1*388550b0Srillig /* $NetBSD: citrus_utf7.c,v 1.7 2022/04/19 20:32:14 rillig Exp $ */
2fe05f588Stnozaki
3fe05f588Stnozaki /*-
4fe05f588Stnozaki * Copyright (c)2004, 2005 Citrus Project,
5fe05f588Stnozaki * All rights reserved.
6fe05f588Stnozaki *
7fe05f588Stnozaki * Redistribution and use in source and binary forms, with or without
8fe05f588Stnozaki * modification, are permitted provided that the following conditions
9fe05f588Stnozaki * are met:
10fe05f588Stnozaki * 1. Redistributions of source code must retain the above copyright
11fe05f588Stnozaki * notice, this list of conditions and the following disclaimer.
12fe05f588Stnozaki * 2. Redistributions in binary form must reproduce the above copyright
13fe05f588Stnozaki * notice, this list of conditions and the following disclaimer in the
14fe05f588Stnozaki * documentation and/or other materials provided with the distribution.
15fe05f588Stnozaki *
16fe05f588Stnozaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17fe05f588Stnozaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18fe05f588Stnozaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19fe05f588Stnozaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20fe05f588Stnozaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21fe05f588Stnozaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22fe05f588Stnozaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23fe05f588Stnozaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24fe05f588Stnozaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25fe05f588Stnozaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26fe05f588Stnozaki * SUCH DAMAGE.
27fe05f588Stnozaki *
28fe05f588Stnozaki */
29fe05f588Stnozaki
30fe05f588Stnozaki #include <sys/cdefs.h>
31fe05f588Stnozaki #if defined(LIB_SCCS) && !defined(lint)
32*388550b0Srillig __RCSID("$NetBSD: citrus_utf7.c,v 1.7 2022/04/19 20:32:14 rillig Exp $");
33fe05f588Stnozaki #endif /* LIB_SCCS and not lint */
34fe05f588Stnozaki
35fe05f588Stnozaki #include <assert.h>
36fe05f588Stnozaki #include <errno.h>
37fe05f588Stnozaki #include <string.h>
38fe05f588Stnozaki #include <stdio.h>
39fe05f588Stnozaki #include <stdint.h>
40fe05f588Stnozaki #include <stdlib.h>
41fe05f588Stnozaki #include <limits.h>
42fe05f588Stnozaki #include <wchar.h>
43fe05f588Stnozaki
44fe05f588Stnozaki #include "citrus_namespace.h"
45fe05f588Stnozaki #include "citrus_types.h"
46fe05f588Stnozaki #include "citrus_module.h"
47fe05f588Stnozaki #include "citrus_ctype.h"
48fe05f588Stnozaki #include "citrus_stdenc.h"
49fe05f588Stnozaki #include "citrus_utf7.h"
50fe05f588Stnozaki
51fe05f588Stnozaki /* ----------------------------------------------------------------------
52fe05f588Stnozaki * private stuffs used by templates
53fe05f588Stnozaki */
54fe05f588Stnozaki
55fe05f588Stnozaki typedef struct {
56fe05f588Stnozaki uint16_t cell[0x80];
57fe05f588Stnozaki #define EI_MASK UINT16_C(0xff)
58fe05f588Stnozaki #define EI_DIRECT UINT16_C(0x100)
59fe05f588Stnozaki #define EI_OPTION UINT16_C(0x200)
60fe05f588Stnozaki #define EI_SPACE UINT16_C(0x400)
61fe05f588Stnozaki } _UTF7EncodingInfo;
62fe05f588Stnozaki
63fe05f588Stnozaki typedef struct {
64fe05f588Stnozaki unsigned int
65fe05f588Stnozaki mode: 1, /* whether base64 mode */
66fe05f588Stnozaki bits: 4, /* need to hold 0 - 15 */
67fe05f588Stnozaki cache: 22, /* 22 = BASE64_BIT + UTF16_BIT */
686e2609d6Stnozaki surrogate: 1; /* whether surrogate pair or not */
696e2609d6Stnozaki int chlen;
70fe05f588Stnozaki char ch[4]; /* BASE64_IN, 3 * 6 = 18, most closed to UTF16_BIT */
71fe05f588Stnozaki } _UTF7State;
72fe05f588Stnozaki
73fe05f588Stnozaki typedef struct {
74fe05f588Stnozaki _UTF7EncodingInfo ei;
75fe05f588Stnozaki struct {
76fe05f588Stnozaki /* for future multi-locale facility */
77fe05f588Stnozaki _UTF7State s_mblen;
78fe05f588Stnozaki _UTF7State s_mbrlen;
79fe05f588Stnozaki _UTF7State s_mbrtowc;
80fe05f588Stnozaki _UTF7State s_mbtowc;
81fe05f588Stnozaki _UTF7State s_mbsrtowcs;
8285a67e61Sjoerg _UTF7State s_mbsnrtowcs;
83fe05f588Stnozaki _UTF7State s_wcrtomb;
84fe05f588Stnozaki _UTF7State s_wcsrtombs;
8585a67e61Sjoerg _UTF7State s_wcsnrtombs;
86fe05f588Stnozaki _UTF7State s_wctomb;
87fe05f588Stnozaki } states;
88fe05f588Stnozaki } _UTF7CTypeInfo;
89fe05f588Stnozaki
90fe05f588Stnozaki #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
91fe05f588Stnozaki #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
92fe05f588Stnozaki
93fe05f588Stnozaki #define _FUNCNAME(m) _citrus_UTF7_##m
94fe05f588Stnozaki #define _ENCODING_INFO _UTF7EncodingInfo
95fe05f588Stnozaki #define _CTYPE_INFO _UTF7CTypeInfo
96fe05f588Stnozaki #define _ENCODING_STATE _UTF7State
97fe05f588Stnozaki #define _ENCODING_MB_CUR_MAX(_ei_) 4
98fe05f588Stnozaki #define _ENCODING_IS_STATE_DEPENDENT 1
99fe05f588Stnozaki #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) 0
100fe05f588Stnozaki
101fe05f588Stnozaki static __inline void
102fe05f588Stnozaki /*ARGSUSED*/
_citrus_UTF7_init_state(_UTF7EncodingInfo * __restrict ei,_UTF7State * __restrict s)103fe05f588Stnozaki _citrus_UTF7_init_state(_UTF7EncodingInfo * __restrict ei,
104fe05f588Stnozaki _UTF7State * __restrict s)
105fe05f588Stnozaki {
106fe05f588Stnozaki /* ei appears to be unused */
107fe05f588Stnozaki _DIAGASSERT(s != NULL);
108fe05f588Stnozaki
109fe05f588Stnozaki memset((void *)s, 0, sizeof(*s));
110fe05f588Stnozaki }
111fe05f588Stnozaki
112fe05f588Stnozaki static __inline void
113fe05f588Stnozaki /*ARGSUSED*/
_citrus_UTF7_pack_state(_UTF7EncodingInfo * __restrict ei,void * __restrict pspriv,const _UTF7State * __restrict s)114fe05f588Stnozaki _citrus_UTF7_pack_state(_UTF7EncodingInfo * __restrict ei,
115fe05f588Stnozaki void *__restrict pspriv, const _UTF7State * __restrict s)
116fe05f588Stnozaki {
117fe05f588Stnozaki /* ei seem to be unused */
118fe05f588Stnozaki _DIAGASSERT(pspriv != NULL);
119fe05f588Stnozaki _DIAGASSERT(s != NULL);
120fe05f588Stnozaki
121fe05f588Stnozaki memcpy(pspriv, (const void *)s, sizeof(*s));
122fe05f588Stnozaki }
123fe05f588Stnozaki
124fe05f588Stnozaki static __inline void
125fe05f588Stnozaki /*ARGSUSED*/
_citrus_UTF7_unpack_state(_UTF7EncodingInfo * __restrict ei,_UTF7State * __restrict s,const void * __restrict pspriv)126fe05f588Stnozaki _citrus_UTF7_unpack_state(_UTF7EncodingInfo * __restrict ei,
127fe05f588Stnozaki _UTF7State * __restrict s, const void * __restrict pspriv)
128fe05f588Stnozaki {
129fe05f588Stnozaki /* ei seem to be unused */
130fe05f588Stnozaki _DIAGASSERT(s != NULL);
131fe05f588Stnozaki _DIAGASSERT(pspriv != NULL);
132fe05f588Stnozaki
133fe05f588Stnozaki memcpy((void *)s, pspriv, sizeof(*s));
134fe05f588Stnozaki }
135fe05f588Stnozaki
136fe05f588Stnozaki static const char base64[] =
137fe05f588Stnozaki "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
138fe05f588Stnozaki "abcdefghijklmnopqrstuvwxyz"
139fe05f588Stnozaki "0123456789+/";
140fe05f588Stnozaki
141fe05f588Stnozaki static const char direct[] =
142fe05f588Stnozaki "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
143fe05f588Stnozaki "abcdefghijklmnopqrstuvwxyz"
144fe05f588Stnozaki "0123456789(),-./:?";
145fe05f588Stnozaki
146fe05f588Stnozaki static const char option[] = "!\"#$%&';<=>@[]^_`{|}";
147fe05f588Stnozaki static const char spaces[] = " \t\r\n";
148fe05f588Stnozaki
149fe05f588Stnozaki #define BASE64_BIT 6
150fe05f588Stnozaki #define UTF16_BIT 16
151fe05f588Stnozaki
152fe05f588Stnozaki #define BASE64_MAX 0x3f
153fe05f588Stnozaki #define UTF16_MAX UINT16_C(0xffff)
154fe05f588Stnozaki #define UTF32_MAX UINT32_C(0x10ffff)
155fe05f588Stnozaki
156fe05f588Stnozaki #define BASE64_IN '+'
157fe05f588Stnozaki #define BASE64_OUT '-'
158fe05f588Stnozaki
159fe05f588Stnozaki #define SHIFT7BIT(c) ((c) >> 7)
160fe05f588Stnozaki #define ISSPECIAL(c) ((c) == '\0' || (c) == BASE64_IN)
161fe05f588Stnozaki
162fe05f588Stnozaki #define FINDLEN(ei, c) \
163fe05f588Stnozaki (SHIFT7BIT((c)) ? -1 : (((ei)->cell[(c)] & EI_MASK) - 1))
164fe05f588Stnozaki
165fe05f588Stnozaki #define ISDIRECT(ei, c) (!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
166fe05f588Stnozaki ei->cell[(c)] & (EI_DIRECT | EI_OPTION | EI_SPACE)))
167fe05f588Stnozaki
168fe05f588Stnozaki #define ISSAFE(ei, c) (!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
16915cc8e46Schristos (c < 0x80 && ei->cell[(c)] & (EI_DIRECT | EI_SPACE))))
170fe05f588Stnozaki
171fe05f588Stnozaki /* surrogate pair */
172fe05f588Stnozaki #define SRG_BASE UINT32_C(0x10000)
173fe05f588Stnozaki #define HISRG_MIN UINT16_C(0xd800)
174fe05f588Stnozaki #define HISRG_MAX UINT16_C(0xdbff)
175fe05f588Stnozaki #define LOSRG_MIN UINT16_C(0xdc00)
176fe05f588Stnozaki #define LOSRG_MAX UINT16_C(0xdfff)
177fe05f588Stnozaki
178fe05f588Stnozaki static int
_citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,uint16_t * __restrict u16,const char ** __restrict s,size_t n,_UTF7State * __restrict psenc,size_t * __restrict nresult)179f264ea3aStnozaki _citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,
180fe05f588Stnozaki uint16_t * __restrict u16, const char ** __restrict s, size_t n,
181fe05f588Stnozaki _UTF7State * __restrict psenc, size_t * __restrict nresult)
182fe05f588Stnozaki {
1836e2609d6Stnozaki _UTF7State sv;
184fe05f588Stnozaki const char *s0;
185fe05f588Stnozaki int i, done, len;
186fe05f588Stnozaki
187fe05f588Stnozaki _DIAGASSERT(ei != NULL);
188fe05f588Stnozaki _DIAGASSERT(s != NULL && *s != NULL);
189fe05f588Stnozaki _DIAGASSERT(psenc != NULL);
190fe05f588Stnozaki
191fe05f588Stnozaki s0 = *s;
1926e2609d6Stnozaki sv = *psenc;
193fe05f588Stnozaki
194fe05f588Stnozaki for (i = 0, done = 0; done == 0; i++) {
1956e2609d6Stnozaki _DIAGASSERT(i <= psenc->chlen);
1966e2609d6Stnozaki if (i == psenc->chlen) {
197fe05f588Stnozaki if (n-- < 1) {
198fe05f588Stnozaki *nresult = (size_t)-2;
199fe05f588Stnozaki *s = s0;
2006e2609d6Stnozaki sv.chlen = psenc->chlen;
2016e2609d6Stnozaki *psenc = sv;
202f264ea3aStnozaki return 0;
203fe05f588Stnozaki }
2046e2609d6Stnozaki psenc->ch[psenc->chlen++] = *s0++;
205fe05f588Stnozaki }
206fe05f588Stnozaki if (SHIFT7BIT((int)psenc->ch[i]))
207fe05f588Stnozaki goto ilseq;
2086e2609d6Stnozaki if (!psenc->mode) {
2096e2609d6Stnozaki if (psenc->bits > 0 || psenc->cache > 0)
210f264ea3aStnozaki return EINVAL;
211fe05f588Stnozaki if (psenc->ch[i] == BASE64_IN) {
2126e2609d6Stnozaki psenc->mode = 1;
213fe05f588Stnozaki } else {
214fe05f588Stnozaki if (!ISDIRECT(ei, (int)psenc->ch[i]))
215fe05f588Stnozaki goto ilseq;
216fe05f588Stnozaki *u16 = (uint16_t)psenc->ch[i];
217fe05f588Stnozaki done = 1;
218fe05f588Stnozaki continue;
219fe05f588Stnozaki }
220fe05f588Stnozaki } else {
2216e2609d6Stnozaki if (psenc->ch[i] == BASE64_OUT && psenc->cache == 0) {
2226e2609d6Stnozaki psenc->mode = 0;
223fe05f588Stnozaki *u16 = (uint16_t)BASE64_IN;
224fe05f588Stnozaki done = 1;
225fe05f588Stnozaki continue;
226fe05f588Stnozaki }
227fe05f588Stnozaki len = FINDLEN(ei, (int)psenc->ch[i]);
228fe05f588Stnozaki if (len < 0) {
2296e2609d6Stnozaki if (psenc->bits >= BASE64_BIT)
230f264ea3aStnozaki return EINVAL;
2316e2609d6Stnozaki psenc->mode = 0;
2326e2609d6Stnozaki psenc->bits = psenc->cache = 0;
233fe05f588Stnozaki if (psenc->ch[i] != BASE64_OUT) {
234fe05f588Stnozaki if (!ISDIRECT(ei, (int)psenc->ch[i]))
235fe05f588Stnozaki goto ilseq;
236fe05f588Stnozaki *u16 = (uint16_t)psenc->ch[i];
237fe05f588Stnozaki done = 1;
238fe05f588Stnozaki }
239fe05f588Stnozaki } else {
240f264ea3aStnozaki psenc->cache =
241f264ea3aStnozaki (psenc->cache << BASE64_BIT) | len;
2426e2609d6Stnozaki switch (psenc->bits) {
243fe05f588Stnozaki case 0: case 2: case 4: case 6: case 8:
2446e2609d6Stnozaki psenc->bits += BASE64_BIT;
245fe05f588Stnozaki break;
246fe05f588Stnozaki case 10: case 12: case 14:
2476e2609d6Stnozaki psenc->bits -= (UTF16_BIT - BASE64_BIT);
2486e2609d6Stnozaki *u16 = (psenc->cache >> psenc->bits)
249fe05f588Stnozaki & UTF16_MAX;
250fe05f588Stnozaki done = 1;
251fe05f588Stnozaki break;
252fe05f588Stnozaki default:
253f264ea3aStnozaki return EINVAL;
254fe05f588Stnozaki }
255fe05f588Stnozaki }
256fe05f588Stnozaki }
257fe05f588Stnozaki }
258fe05f588Stnozaki
2596e2609d6Stnozaki if (psenc->chlen > i)
260f264ea3aStnozaki return EINVAL;
2616e2609d6Stnozaki psenc->chlen = 0;
262fe05f588Stnozaki *nresult = (size_t)((*u16 == 0) ? 0 : s0 - *s);
263fe05f588Stnozaki *s = s0;
264fe05f588Stnozaki
265f264ea3aStnozaki return 0;
266fe05f588Stnozaki
267fe05f588Stnozaki ilseq:
268fe05f588Stnozaki *nresult = (size_t)-1;
269f264ea3aStnozaki return EILSEQ;
270fe05f588Stnozaki }
271fe05f588Stnozaki
272fe05f588Stnozaki static int
_citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,wchar_t * __restrict pwc,const char ** __restrict s,size_t n,_UTF7State * __restrict psenc,size_t * __restrict nresult)273fe05f588Stnozaki _citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,
274fe05f588Stnozaki wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
275fe05f588Stnozaki _UTF7State * __restrict psenc, size_t * __restrict nresult)
276fe05f588Stnozaki {
277f264ea3aStnozaki const char *s0;
278fe05f588Stnozaki uint32_t u32;
279fe05f588Stnozaki uint16_t hi, lo;
280f264ea3aStnozaki size_t siz, nr;
281fe05f588Stnozaki int err;
282fe05f588Stnozaki
283fe05f588Stnozaki _DIAGASSERT(ei != NULL);
284fe05f588Stnozaki /* pwc may be null */
285fe05f588Stnozaki _DIAGASSERT(s != NULL);
286fe05f588Stnozaki _DIAGASSERT(psenc != NULL);
287fe05f588Stnozaki
288fe05f588Stnozaki if (*s == NULL) {
289fe05f588Stnozaki _citrus_UTF7_init_state(ei, psenc);
290fe05f588Stnozaki *nresult = (size_t)_ENCODING_IS_STATE_DEPENDENT;
291f264ea3aStnozaki return 0;
292fe05f588Stnozaki }
293f264ea3aStnozaki s0 = *s;
2946e2609d6Stnozaki if (psenc->surrogate) {
2956e2609d6Stnozaki hi = (psenc->cache >> 2) & UTF16_MAX;
296f264ea3aStnozaki if (hi < HISRG_MIN || hi > HISRG_MAX)
297f264ea3aStnozaki return EINVAL;
298fe05f588Stnozaki siz = 0;
299fe05f588Stnozaki } else {
300f264ea3aStnozaki err = _citrus_UTF7_mbtoutf16(ei, &hi, &s0, n, psenc, &nr);
301f264ea3aStnozaki if (nr == (size_t)-1 || nr == (size_t)-2) {
302f264ea3aStnozaki *nresult = nr;
303f264ea3aStnozaki return err;
304fe05f588Stnozaki }
305f264ea3aStnozaki if (err != 0)
306f264ea3aStnozaki return err;
307f264ea3aStnozaki n -= nr;
308f264ea3aStnozaki siz = nr;
309f264ea3aStnozaki if (hi < HISRG_MIN || hi > HISRG_MAX) {
310fe05f588Stnozaki u32 = (uint32_t)hi;
311f264ea3aStnozaki goto done;
312f264ea3aStnozaki }
313f264ea3aStnozaki psenc->surrogate = 1;
314f264ea3aStnozaki }
315f264ea3aStnozaki err = _citrus_UTF7_mbtoutf16(ei, &lo, &s0, n, psenc, &nr);
316f264ea3aStnozaki if (nr == (size_t)-1 || nr == (size_t)-2) {
317f264ea3aStnozaki *nresult = nr;
318f264ea3aStnozaki return err;
319f264ea3aStnozaki }
320f264ea3aStnozaki if (err != 0)
321f264ea3aStnozaki return err;
322fe05f588Stnozaki hi -= HISRG_MIN;
323fe05f588Stnozaki lo -= LOSRG_MIN;
324fe05f588Stnozaki u32 = (hi << 10 | lo) + SRG_BASE;
325f264ea3aStnozaki siz += nr;
326f264ea3aStnozaki done:
327f264ea3aStnozaki *s = s0;
328fe05f588Stnozaki if (pwc != NULL)
329fe05f588Stnozaki *pwc = (wchar_t)u32;
330f264ea3aStnozaki if (u32 == (uint32_t)0) {
331f264ea3aStnozaki *nresult = (size_t)0;
332f264ea3aStnozaki _citrus_UTF7_init_state(ei, psenc);
333f264ea3aStnozaki } else {
334f264ea3aStnozaki *nresult = siz;
335f264ea3aStnozaki psenc->surrogate = 0;
336f264ea3aStnozaki }
337f264ea3aStnozaki return err;
338fe05f588Stnozaki }
339fe05f588Stnozaki
340f264ea3aStnozaki static int
_citrus_UTF7_utf16tomb(_UTF7EncodingInfo * __restrict ei,char * __restrict s,size_t n,uint16_t u16,_UTF7State * __restrict psenc,size_t * __restrict nresult)341f264ea3aStnozaki _citrus_UTF7_utf16tomb(_UTF7EncodingInfo * __restrict ei,
342f264ea3aStnozaki char * __restrict s, size_t n, uint16_t u16,
343f264ea3aStnozaki _UTF7State * __restrict psenc, size_t * __restrict nresult)
344fe05f588Stnozaki {
345fe05f588Stnozaki int bits, i;
346fe05f588Stnozaki
347fe05f588Stnozaki _DIAGASSERT(ei != NULL);
348fe05f588Stnozaki _DIAGASSERT(psenc != NULL);
349fe05f588Stnozaki
3506e2609d6Stnozaki if (psenc->chlen != 0 || psenc->bits > BASE64_BIT)
351f264ea3aStnozaki return EINVAL;
352fe05f588Stnozaki
353fe05f588Stnozaki if (ISSAFE(ei, u16)) {
3546e2609d6Stnozaki if (psenc->mode) {
3556e2609d6Stnozaki if (psenc->bits > 0) {
3566e2609d6Stnozaki bits = BASE64_BIT - psenc->bits;
3576e2609d6Stnozaki i = (psenc->cache << bits) & BASE64_MAX;
3586e2609d6Stnozaki psenc->ch[psenc->chlen++] = base64[i];
3596e2609d6Stnozaki psenc->bits = psenc->cache = 0;
360fe05f588Stnozaki }
361fe05f588Stnozaki if (u16 == BASE64_OUT || FINDLEN(ei, u16) >= 0)
3626e2609d6Stnozaki psenc->ch[psenc->chlen++] = BASE64_OUT;
3636e2609d6Stnozaki psenc->mode = 0;
364fe05f588Stnozaki }
3656e2609d6Stnozaki if (psenc->bits != 0)
366f264ea3aStnozaki return EINVAL;
3676e2609d6Stnozaki psenc->ch[psenc->chlen++] = (char)u16;
368fe05f588Stnozaki if (u16 == BASE64_IN)
3696e2609d6Stnozaki psenc->ch[psenc->chlen++] = BASE64_OUT;
370fe05f588Stnozaki } else {
3716e2609d6Stnozaki if (!psenc->mode) {
3726e2609d6Stnozaki if (psenc->bits > 0)
373f264ea3aStnozaki return EINVAL;
3746e2609d6Stnozaki psenc->ch[psenc->chlen++] = BASE64_IN;
3756e2609d6Stnozaki psenc->mode = 1;
376fe05f588Stnozaki }
3776e2609d6Stnozaki psenc->cache = (psenc->cache << UTF16_BIT) | u16;
3786e2609d6Stnozaki bits = UTF16_BIT + psenc->bits;
3796e2609d6Stnozaki psenc->bits = bits % BASE64_BIT;
380fe05f588Stnozaki while ((bits -= BASE64_BIT) >= 0) {
3816e2609d6Stnozaki i = (psenc->cache >> bits) & BASE64_MAX;
3826e2609d6Stnozaki psenc->ch[psenc->chlen++] = base64[i];
383fe05f588Stnozaki }
384fe05f588Stnozaki }
385f264ea3aStnozaki memcpy(s, psenc->ch, psenc->chlen);
386f264ea3aStnozaki *nresult = psenc->chlen;
387f264ea3aStnozaki psenc->chlen = 0;
388fe05f588Stnozaki
389f264ea3aStnozaki return 0;
390fe05f588Stnozaki }
391fe05f588Stnozaki
392fe05f588Stnozaki static int
_citrus_UTF7_wcrtomb_priv(_UTF7EncodingInfo * __restrict ei,char * __restrict s,size_t n,wchar_t wchar,_UTF7State * __restrict psenc,size_t * __restrict nresult)393fe05f588Stnozaki _citrus_UTF7_wcrtomb_priv(_UTF7EncodingInfo * __restrict ei,
394fe05f588Stnozaki char * __restrict s, size_t n, wchar_t wchar,
395fe05f588Stnozaki _UTF7State * __restrict psenc, size_t * __restrict nresult)
396fe05f588Stnozaki {
397fe05f588Stnozaki uint32_t u32;
398fe05f588Stnozaki uint16_t u16[2];
399fe05f588Stnozaki int err, len, i;
400f264ea3aStnozaki size_t siz, nr;
401fe05f588Stnozaki
402fe05f588Stnozaki _DIAGASSERT(ei != NULL);
403fe05f588Stnozaki _DIAGASSERT(s != NULL);
404fe05f588Stnozaki _DIAGASSERT(psenc != NULL);
405f264ea3aStnozaki _DIAGASSERT(nresult != NULL);
406fe05f588Stnozaki
407fe05f588Stnozaki u32 = (uint32_t)wchar;
408fe05f588Stnozaki if (u32 <= UTF16_MAX) {
409fe05f588Stnozaki u16[0] = (uint16_t)u32;
410fe05f588Stnozaki len = 1;
411fe05f588Stnozaki } else if (u32 <= UTF32_MAX) {
412fe05f588Stnozaki u32 -= SRG_BASE;
413fe05f588Stnozaki u16[0] = (u32 >> 10) + HISRG_MIN;
414fe05f588Stnozaki u16[1] = ((uint16_t)(u32 & UINT32_C(0x3ff))) + LOSRG_MIN;
415fe05f588Stnozaki len = 2;
416fe05f588Stnozaki } else {
417fe05f588Stnozaki *nresult = (size_t)-1;
418f264ea3aStnozaki return EILSEQ;
419fe05f588Stnozaki }
420f264ea3aStnozaki siz = 0;
421f264ea3aStnozaki for (i = 0; i < len; ++i) {
422f264ea3aStnozaki err = _citrus_UTF7_utf16tomb(ei, s, n, u16[i], psenc, &nr);
423f264ea3aStnozaki if (err != 0)
424f264ea3aStnozaki return err; /* XXX: state has been modified */
425f264ea3aStnozaki s += nr;
426f264ea3aStnozaki n -= nr;
427f264ea3aStnozaki siz += nr;
428f264ea3aStnozaki }
429f264ea3aStnozaki *nresult = siz;
430fe05f588Stnozaki
431f264ea3aStnozaki return 0;
432fe05f588Stnozaki }
433fe05f588Stnozaki
434fe05f588Stnozaki static int
435fe05f588Stnozaki /* ARGSUSED */
_citrus_UTF7_put_state_reset(_UTF7EncodingInfo * __restrict ei,char * __restrict s,size_t n,_UTF7State * __restrict psenc,size_t * __restrict nresult)436fe05f588Stnozaki _citrus_UTF7_put_state_reset(_UTF7EncodingInfo * __restrict ei,
437fe05f588Stnozaki char * __restrict s, size_t n, _UTF7State * __restrict psenc,
438fe05f588Stnozaki size_t * __restrict nresult)
439fe05f588Stnozaki {
440fe05f588Stnozaki int bits, pos;
441fe05f588Stnozaki
442fe05f588Stnozaki _DIAGASSERT(ei != NULL);
443fe05f588Stnozaki _DIAGASSERT(s != NULL);
444fe05f588Stnozaki _DIAGASSERT(psenc != NULL);
445fe05f588Stnozaki _DIAGASSERT(nresult != NULL);
446fe05f588Stnozaki
4476e2609d6Stnozaki if (psenc->chlen != 0 || psenc->bits > BASE64_BIT || psenc->surrogate)
448f264ea3aStnozaki return EINVAL;
449fe05f588Stnozaki
4506e2609d6Stnozaki if (psenc->mode) {
4516e2609d6Stnozaki if (psenc->bits > 0) {
452fe05f588Stnozaki if (n-- < 1)
453f264ea3aStnozaki return E2BIG;
4546e2609d6Stnozaki bits = BASE64_BIT - psenc->bits;
4556e2609d6Stnozaki pos = (psenc->cache << bits) & BASE64_MAX;
4566e2609d6Stnozaki psenc->ch[psenc->chlen++] = base64[pos];
4576e2609d6Stnozaki psenc->ch[psenc->chlen++] = BASE64_OUT;
4586e2609d6Stnozaki psenc->bits = psenc->cache = 0;
459fe05f588Stnozaki }
4606e2609d6Stnozaki psenc->mode = 0;
461fe05f588Stnozaki }
4626e2609d6Stnozaki if (psenc->bits != 0)
463f264ea3aStnozaki return EINVAL;
464fe05f588Stnozaki if (n-- < 1)
465f264ea3aStnozaki return E2BIG;
466fe05f588Stnozaki
4676e2609d6Stnozaki _DIAGASSERT(n >= psenc->chlen);
4686e2609d6Stnozaki *nresult = (size_t)psenc->chlen;
4696e2609d6Stnozaki if (psenc->chlen > 0) {
4706e2609d6Stnozaki memcpy(s, psenc->ch, psenc->chlen);
4716e2609d6Stnozaki psenc->chlen = 0;
472fe05f588Stnozaki }
473fe05f588Stnozaki
474f264ea3aStnozaki return 0;
475fe05f588Stnozaki }
476fe05f588Stnozaki
477fe05f588Stnozaki static __inline int
478fe05f588Stnozaki /*ARGSUSED*/
_citrus_UTF7_stdenc_wctocs(_UTF7EncodingInfo * __restrict ei,_csid_t * __restrict csid,_index_t * __restrict idx,wchar_t wc)479fe05f588Stnozaki _citrus_UTF7_stdenc_wctocs(_UTF7EncodingInfo * __restrict ei,
480fe05f588Stnozaki _csid_t * __restrict csid,
481fe05f588Stnozaki _index_t * __restrict idx, wchar_t wc)
482fe05f588Stnozaki {
483fe05f588Stnozaki /* ei seem to be unused */
484fe05f588Stnozaki _DIAGASSERT(csid != NULL);
485fe05f588Stnozaki _DIAGASSERT(idx != NULL);
486fe05f588Stnozaki
487fe05f588Stnozaki *csid = 0;
488fe05f588Stnozaki *idx = (_index_t)wc;
489fe05f588Stnozaki
490f264ea3aStnozaki return 0;
491fe05f588Stnozaki }
492fe05f588Stnozaki
493fe05f588Stnozaki static __inline int
494fe05f588Stnozaki /*ARGSUSED*/
_citrus_UTF7_stdenc_cstowc(_UTF7EncodingInfo * __restrict ei,wchar_t * __restrict wc,_csid_t csid,_index_t idx)495fe05f588Stnozaki _citrus_UTF7_stdenc_cstowc(_UTF7EncodingInfo * __restrict ei,
496fe05f588Stnozaki wchar_t * __restrict wc,
497fe05f588Stnozaki _csid_t csid, _index_t idx)
498fe05f588Stnozaki {
499fe05f588Stnozaki /* ei seem to be unused */
500fe05f588Stnozaki _DIAGASSERT(wc != NULL);
501fe05f588Stnozaki
502fe05f588Stnozaki if (csid != 0)
503f264ea3aStnozaki return EILSEQ;
504fe05f588Stnozaki *wc = (wchar_t)idx;
505fe05f588Stnozaki
506f264ea3aStnozaki return 0;
507fe05f588Stnozaki }
508fe05f588Stnozaki
5091beef8feStshiozak static __inline int
5101beef8feStshiozak /*ARGSUSED*/
_citrus_UTF7_stdenc_get_state_desc_generic(_UTF7EncodingInfo * __restrict ei,_UTF7State * __restrict psenc,int * __restrict rstate)5111beef8feStshiozak _citrus_UTF7_stdenc_get_state_desc_generic(_UTF7EncodingInfo * __restrict ei,
5121beef8feStshiozak _UTF7State * __restrict psenc,
5131beef8feStshiozak int * __restrict rstate)
5141beef8feStshiozak {
5151beef8feStshiozak
5161beef8feStshiozak if (psenc->chlen == 0)
5171beef8feStshiozak *rstate = _STDENC_SDGEN_INITIAL;
5181beef8feStshiozak else
5191beef8feStshiozak *rstate = _STDENC_SDGEN_INCOMPLETE_CHAR;
5201beef8feStshiozak
5211beef8feStshiozak return 0;
5221beef8feStshiozak }
5231beef8feStshiozak
524fe05f588Stnozaki static void
525fe05f588Stnozaki /*ARGSUSED*/
_citrus_UTF7_encoding_module_uninit(_UTF7EncodingInfo * ei)526fe05f588Stnozaki _citrus_UTF7_encoding_module_uninit(_UTF7EncodingInfo *ei)
527fe05f588Stnozaki {
528fe05f588Stnozaki /* ei seems to be unused */
529fe05f588Stnozaki }
530fe05f588Stnozaki
531fe05f588Stnozaki static int
532fe05f588Stnozaki /*ARGSUSED*/
_citrus_UTF7_encoding_module_init(_UTF7EncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)533fe05f588Stnozaki _citrus_UTF7_encoding_module_init(_UTF7EncodingInfo * __restrict ei,
534fe05f588Stnozaki const void * __restrict var, size_t lenvar)
535fe05f588Stnozaki {
536fe05f588Stnozaki const char *s;
537fe05f588Stnozaki
538fe05f588Stnozaki _DIAGASSERT(ei != NULL);
539fe05f588Stnozaki /* var may be null */
540fe05f588Stnozaki
541fe05f588Stnozaki memset(ei, 0, sizeof(*ei));
542fe05f588Stnozaki
543fe05f588Stnozaki #define FILL(str, flag) \
544fe05f588Stnozaki do { \
545fe05f588Stnozaki for (s = str; *s != '\0'; s++) \
546fe05f588Stnozaki ei->cell[*s & 0x7f] |= flag; \
547*388550b0Srillig } while (0)
548fe05f588Stnozaki
549fe05f588Stnozaki FILL(base64, (s - base64) + 1);
550fe05f588Stnozaki FILL(direct, EI_DIRECT);
551fe05f588Stnozaki FILL(option, EI_OPTION);
552fe05f588Stnozaki FILL(spaces, EI_SPACE);
553fe05f588Stnozaki
554f264ea3aStnozaki return 0;
555fe05f588Stnozaki }
556fe05f588Stnozaki
557fe05f588Stnozaki /* ----------------------------------------------------------------------
558fe05f588Stnozaki * public interface for ctype
559fe05f588Stnozaki */
560fe05f588Stnozaki
561fe05f588Stnozaki _CITRUS_CTYPE_DECLS(UTF7);
562fe05f588Stnozaki _CITRUS_CTYPE_DEF_OPS(UTF7);
563fe05f588Stnozaki
564fe05f588Stnozaki #include "citrus_ctype_template.h"
565fe05f588Stnozaki
566fe05f588Stnozaki /* ----------------------------------------------------------------------
567fe05f588Stnozaki * public interface for stdenc
568fe05f588Stnozaki */
569fe05f588Stnozaki
570fe05f588Stnozaki _CITRUS_STDENC_DECLS(UTF7);
571fe05f588Stnozaki _CITRUS_STDENC_DEF_OPS(UTF7);
572fe05f588Stnozaki
573fe05f588Stnozaki #include "citrus_stdenc_template.h"
574