Remove building with NOCRYPTO option
[minix3.git] / lib / libc / citrus / modules / citrus_utf7.c
blobeae0ee3eb66b226edb11f9f1453be26c79f64d3f
1 /* $NetBSD: citrus_utf7.c,v 1.6 2013/05/28 16:57:56 joerg Exp $ */
3 /*-
4 * Copyright (c)2004, 2005 Citrus Project,
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 #if defined(LIB_SCCS) && !defined(lint)
32 __RCSID("$NetBSD: citrus_utf7.c,v 1.6 2013/05/28 16:57:56 joerg Exp $");
33 #endif /* LIB_SCCS and not lint */
35 #include <assert.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdint.h>
40 #include <stdlib.h>
41 #include <limits.h>
42 #include <wchar.h>
44 #include "citrus_namespace.h"
45 #include "citrus_types.h"
46 #include "citrus_module.h"
47 #include "citrus_ctype.h"
48 #include "citrus_stdenc.h"
49 #include "citrus_utf7.h"
51 /* ----------------------------------------------------------------------
52 * private stuffs used by templates
55 typedef struct {
56 uint16_t cell[0x80];
57 #define EI_MASK UINT16_C(0xff)
58 #define EI_DIRECT UINT16_C(0x100)
59 #define EI_OPTION UINT16_C(0x200)
60 #define EI_SPACE UINT16_C(0x400)
61 } _UTF7EncodingInfo;
63 typedef struct {
64 unsigned int
65 mode: 1, /* whether base64 mode */
66 bits: 4, /* need to hold 0 - 15 */
67 cache: 22, /* 22 = BASE64_BIT + UTF16_BIT */
68 surrogate: 1; /* whether surrogate pair or not */
69 int chlen;
70 char ch[4]; /* BASE64_IN, 3 * 6 = 18, most closed to UTF16_BIT */
71 } _UTF7State;
73 typedef struct {
74 _UTF7EncodingInfo ei;
75 struct {
76 /* for future multi-locale facility */
77 _UTF7State s_mblen;
78 _UTF7State s_mbrlen;
79 _UTF7State s_mbrtowc;
80 _UTF7State s_mbtowc;
81 _UTF7State s_mbsrtowcs;
82 _UTF7State s_mbsnrtowcs;
83 _UTF7State s_wcrtomb;
84 _UTF7State s_wcsrtombs;
85 _UTF7State s_wcsnrtombs;
86 _UTF7State s_wctomb;
87 } states;
88 } _UTF7CTypeInfo;
90 #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
91 #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
93 #define _FUNCNAME(m) _citrus_UTF7_##m
94 #define _ENCODING_INFO _UTF7EncodingInfo
95 #define _CTYPE_INFO _UTF7CTypeInfo
96 #define _ENCODING_STATE _UTF7State
97 #define _ENCODING_MB_CUR_MAX(_ei_) 4
98 #define _ENCODING_IS_STATE_DEPENDENT 1
99 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) 0
101 static __inline void
102 /*ARGSUSED*/
103 _citrus_UTF7_init_state(_UTF7EncodingInfo * __restrict ei,
104 _UTF7State * __restrict s)
106 /* ei appears to be unused */
107 _DIAGASSERT(s != NULL);
109 memset((void *)s, 0, sizeof(*s));
112 static __inline void
113 /*ARGSUSED*/
114 _citrus_UTF7_pack_state(_UTF7EncodingInfo * __restrict ei,
115 void *__restrict pspriv, const _UTF7State * __restrict s)
117 /* ei seem to be unused */
118 _DIAGASSERT(pspriv != NULL);
119 _DIAGASSERT(s != NULL);
121 memcpy(pspriv, (const void *)s, sizeof(*s));
124 static __inline void
125 /*ARGSUSED*/
126 _citrus_UTF7_unpack_state(_UTF7EncodingInfo * __restrict ei,
127 _UTF7State * __restrict s, const void * __restrict pspriv)
129 /* ei seem to be unused */
130 _DIAGASSERT(s != NULL);
131 _DIAGASSERT(pspriv != NULL);
133 memcpy((void *)s, pspriv, sizeof(*s));
136 static const char base64[] =
137 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
138 "abcdefghijklmnopqrstuvwxyz"
139 "0123456789+/";
141 static const char direct[] =
142 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
143 "abcdefghijklmnopqrstuvwxyz"
144 "0123456789(),-./:?";
146 static const char option[] = "!\"#$%&';<=>@[]^_`{|}";
147 static const char spaces[] = " \t\r\n";
149 #define BASE64_BIT 6
150 #define UTF16_BIT 16
152 #define BASE64_MAX 0x3f
153 #define UTF16_MAX UINT16_C(0xffff)
154 #define UTF32_MAX UINT32_C(0x10ffff)
156 #define BASE64_IN '+'
157 #define BASE64_OUT '-'
159 #define SHIFT7BIT(c) ((c) >> 7)
160 #define ISSPECIAL(c) ((c) == '\0' || (c) == BASE64_IN)
162 #define FINDLEN(ei, c) \
163 (SHIFT7BIT((c)) ? -1 : (((ei)->cell[(c)] & EI_MASK) - 1))
165 #define ISDIRECT(ei, c) (!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
166 ei->cell[(c)] & (EI_DIRECT | EI_OPTION | EI_SPACE)))
168 #define ISSAFE(ei, c) (!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
169 (c < 0x80 && ei->cell[(c)] & (EI_DIRECT | EI_SPACE))))
171 /* surrogate pair */
172 #define SRG_BASE UINT32_C(0x10000)
173 #define HISRG_MIN UINT16_C(0xd800)
174 #define HISRG_MAX UINT16_C(0xdbff)
175 #define LOSRG_MIN UINT16_C(0xdc00)
176 #define LOSRG_MAX UINT16_C(0xdfff)
178 static int
179 _citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,
180 uint16_t * __restrict u16, const char ** __restrict s, size_t n,
181 _UTF7State * __restrict psenc, size_t * __restrict nresult)
183 _UTF7State sv;
184 const char *s0;
185 int i, done, len;
187 _DIAGASSERT(ei != NULL);
188 _DIAGASSERT(s != NULL && *s != NULL);
189 _DIAGASSERT(psenc != NULL);
191 s0 = *s;
192 sv = *psenc;
194 for (i = 0, done = 0; done == 0; i++) {
195 _DIAGASSERT(i <= psenc->chlen);
196 if (i == psenc->chlen) {
197 if (n-- < 1) {
198 *nresult = (size_t)-2;
199 *s = s0;
200 sv.chlen = psenc->chlen;
201 *psenc = sv;
202 return 0;
204 psenc->ch[psenc->chlen++] = *s0++;
206 if (SHIFT7BIT((int)psenc->ch[i]))
207 goto ilseq;
208 if (!psenc->mode) {
209 if (psenc->bits > 0 || psenc->cache > 0)
210 return EINVAL;
211 if (psenc->ch[i] == BASE64_IN) {
212 psenc->mode = 1;
213 } else {
214 if (!ISDIRECT(ei, (int)psenc->ch[i]))
215 goto ilseq;
216 *u16 = (uint16_t)psenc->ch[i];
217 done = 1;
218 continue;
220 } else {
221 if (psenc->ch[i] == BASE64_OUT && psenc->cache == 0) {
222 psenc->mode = 0;
223 *u16 = (uint16_t)BASE64_IN;
224 done = 1;
225 continue;
227 len = FINDLEN(ei, (int)psenc->ch[i]);
228 if (len < 0) {
229 if (psenc->bits >= BASE64_BIT)
230 return EINVAL;
231 psenc->mode = 0;
232 psenc->bits = psenc->cache = 0;
233 if (psenc->ch[i] != BASE64_OUT) {
234 if (!ISDIRECT(ei, (int)psenc->ch[i]))
235 goto ilseq;
236 *u16 = (uint16_t)psenc->ch[i];
237 done = 1;
239 } else {
240 psenc->cache =
241 (psenc->cache << BASE64_BIT) | len;
242 switch (psenc->bits) {
243 case 0: case 2: case 4: case 6: case 8:
244 psenc->bits += BASE64_BIT;
245 break;
246 case 10: case 12: case 14:
247 psenc->bits -= (UTF16_BIT - BASE64_BIT);
248 *u16 = (psenc->cache >> psenc->bits)
249 & UTF16_MAX;
250 done = 1;
251 break;
252 default:
253 return EINVAL;
259 if (psenc->chlen > i)
260 return EINVAL;
261 psenc->chlen = 0;
262 *nresult = (size_t)((*u16 == 0) ? 0 : s0 - *s);
263 *s = s0;
265 return 0;
267 ilseq:
268 *nresult = (size_t)-1;
269 return EILSEQ;
272 static int
273 _citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,
274 wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
275 _UTF7State * __restrict psenc, size_t * __restrict nresult)
277 const char *s0;
278 uint32_t u32;
279 uint16_t hi, lo;
280 size_t siz, nr;
281 int err;
283 _DIAGASSERT(ei != NULL);
284 /* pwc may be null */
285 _DIAGASSERT(s != NULL);
286 _DIAGASSERT(psenc != NULL);
288 if (*s == NULL) {
289 _citrus_UTF7_init_state(ei, psenc);
290 *nresult = (size_t)_ENCODING_IS_STATE_DEPENDENT;
291 return 0;
293 s0 = *s;
294 if (psenc->surrogate) {
295 hi = (psenc->cache >> 2) & UTF16_MAX;
296 if (hi < HISRG_MIN || hi > HISRG_MAX)
297 return EINVAL;
298 siz = 0;
299 } else {
300 err = _citrus_UTF7_mbtoutf16(ei, &hi, &s0, n, psenc, &nr);
301 if (nr == (size_t)-1 || nr == (size_t)-2) {
302 *nresult = nr;
303 return err;
305 if (err != 0)
306 return err;
307 n -= nr;
308 siz = nr;
309 if (hi < HISRG_MIN || hi > HISRG_MAX) {
310 u32 = (uint32_t)hi;
311 goto done;
313 psenc->surrogate = 1;
315 err = _citrus_UTF7_mbtoutf16(ei, &lo, &s0, n, psenc, &nr);
316 if (nr == (size_t)-1 || nr == (size_t)-2) {
317 *nresult = nr;
318 return err;
320 if (err != 0)
321 return err;
322 hi -= HISRG_MIN;
323 lo -= LOSRG_MIN;
324 u32 = (hi << 10 | lo) + SRG_BASE;
325 siz += nr;
326 done:
327 *s = s0;
328 if (pwc != NULL)
329 *pwc = (wchar_t)u32;
330 if (u32 == (uint32_t)0) {
331 *nresult = (size_t)0;
332 _citrus_UTF7_init_state(ei, psenc);
333 } else {
334 *nresult = siz;
335 psenc->surrogate = 0;
337 return err;
340 static int
341 _citrus_UTF7_utf16tomb(_UTF7EncodingInfo * __restrict ei,
342 char * __restrict s, size_t n, uint16_t u16,
343 _UTF7State * __restrict psenc, size_t * __restrict nresult)
345 int bits, i;
347 _DIAGASSERT(ei != NULL);
348 _DIAGASSERT(psenc != NULL);
350 if (psenc->chlen != 0 || psenc->bits > BASE64_BIT)
351 return EINVAL;
353 if (ISSAFE(ei, u16)) {
354 if (psenc->mode) {
355 if (psenc->bits > 0) {
356 bits = BASE64_BIT - psenc->bits;
357 i = (psenc->cache << bits) & BASE64_MAX;
358 psenc->ch[psenc->chlen++] = base64[i];
359 psenc->bits = psenc->cache = 0;
361 if (u16 == BASE64_OUT || FINDLEN(ei, u16) >= 0)
362 psenc->ch[psenc->chlen++] = BASE64_OUT;
363 psenc->mode = 0;
365 if (psenc->bits != 0)
366 return EINVAL;
367 psenc->ch[psenc->chlen++] = (char)u16;
368 if (u16 == BASE64_IN)
369 psenc->ch[psenc->chlen++] = BASE64_OUT;
370 } else {
371 if (!psenc->mode) {
372 if (psenc->bits > 0)
373 return EINVAL;
374 psenc->ch[psenc->chlen++] = BASE64_IN;
375 psenc->mode = 1;
377 psenc->cache = (psenc->cache << UTF16_BIT) | u16;
378 bits = UTF16_BIT + psenc->bits;
379 psenc->bits = bits % BASE64_BIT;
380 while ((bits -= BASE64_BIT) >= 0) {
381 i = (psenc->cache >> bits) & BASE64_MAX;
382 psenc->ch[psenc->chlen++] = base64[i];
385 memcpy(s, psenc->ch, psenc->chlen);
386 *nresult = psenc->chlen;
387 psenc->chlen = 0;
389 return 0;
392 static int
393 _citrus_UTF7_wcrtomb_priv(_UTF7EncodingInfo * __restrict ei,
394 char * __restrict s, size_t n, wchar_t wchar,
395 _UTF7State * __restrict psenc, size_t * __restrict nresult)
397 uint32_t u32;
398 uint16_t u16[2];
399 int err, len, i;
400 size_t siz, nr;
402 _DIAGASSERT(ei != NULL);
403 _DIAGASSERT(s != NULL);
404 _DIAGASSERT(psenc != NULL);
405 _DIAGASSERT(nresult != NULL);
407 u32 = (uint32_t)wchar;
408 if (u32 <= UTF16_MAX) {
409 u16[0] = (uint16_t)u32;
410 len = 1;
411 } else if (u32 <= UTF32_MAX) {
412 u32 -= SRG_BASE;
413 u16[0] = (u32 >> 10) + HISRG_MIN;
414 u16[1] = ((uint16_t)(u32 & UINT32_C(0x3ff))) + LOSRG_MIN;
415 len = 2;
416 } else {
417 *nresult = (size_t)-1;
418 return EILSEQ;
420 siz = 0;
421 for (i = 0; i < len; ++i) {
422 err = _citrus_UTF7_utf16tomb(ei, s, n, u16[i], psenc, &nr);
423 if (err != 0)
424 return err; /* XXX: state has been modified */
425 s += nr;
426 n -= nr;
427 siz += nr;
429 *nresult = siz;
431 return 0;
434 static int
435 /* ARGSUSED */
436 _citrus_UTF7_put_state_reset(_UTF7EncodingInfo * __restrict ei,
437 char * __restrict s, size_t n, _UTF7State * __restrict psenc,
438 size_t * __restrict nresult)
440 int bits, pos;
442 _DIAGASSERT(ei != NULL);
443 _DIAGASSERT(s != NULL);
444 _DIAGASSERT(psenc != NULL);
445 _DIAGASSERT(nresult != NULL);
447 if (psenc->chlen != 0 || psenc->bits > BASE64_BIT || psenc->surrogate)
448 return EINVAL;
450 if (psenc->mode) {
451 if (psenc->bits > 0) {
452 if (n-- < 1)
453 return E2BIG;
454 bits = BASE64_BIT - psenc->bits;
455 pos = (psenc->cache << bits) & BASE64_MAX;
456 psenc->ch[psenc->chlen++] = base64[pos];
457 psenc->ch[psenc->chlen++] = BASE64_OUT;
458 psenc->bits = psenc->cache = 0;
460 psenc->mode = 0;
462 if (psenc->bits != 0)
463 return EINVAL;
464 if (n-- < 1)
465 return E2BIG;
467 _DIAGASSERT(n >= psenc->chlen);
468 *nresult = (size_t)psenc->chlen;
469 if (psenc->chlen > 0) {
470 memcpy(s, psenc->ch, psenc->chlen);
471 psenc->chlen = 0;
474 return 0;
477 static __inline int
478 /*ARGSUSED*/
479 _citrus_UTF7_stdenc_wctocs(_UTF7EncodingInfo * __restrict ei,
480 _csid_t * __restrict csid,
481 _index_t * __restrict idx, wchar_t wc)
483 /* ei seem to be unused */
484 _DIAGASSERT(csid != NULL);
485 _DIAGASSERT(idx != NULL);
487 *csid = 0;
488 *idx = (_index_t)wc;
490 return 0;
493 static __inline int
494 /*ARGSUSED*/
495 _citrus_UTF7_stdenc_cstowc(_UTF7EncodingInfo * __restrict ei,
496 wchar_t * __restrict wc,
497 _csid_t csid, _index_t idx)
499 /* ei seem to be unused */
500 _DIAGASSERT(wc != NULL);
502 if (csid != 0)
503 return EILSEQ;
504 *wc = (wchar_t)idx;
506 return 0;
509 static __inline int
510 /*ARGSUSED*/
511 _citrus_UTF7_stdenc_get_state_desc_generic(_UTF7EncodingInfo * __restrict ei,
512 _UTF7State * __restrict psenc,
513 int * __restrict rstate)
516 if (psenc->chlen == 0)
517 *rstate = _STDENC_SDGEN_INITIAL;
518 else
519 *rstate = _STDENC_SDGEN_INCOMPLETE_CHAR;
521 return 0;
524 static void
525 /*ARGSUSED*/
526 _citrus_UTF7_encoding_module_uninit(_UTF7EncodingInfo *ei)
528 /* ei seems to be unused */
531 static int
532 /*ARGSUSED*/
533 _citrus_UTF7_encoding_module_init(_UTF7EncodingInfo * __restrict ei,
534 const void * __restrict var, size_t lenvar)
536 const char *s;
538 _DIAGASSERT(ei != NULL);
539 /* var may be null */
541 memset(ei, 0, sizeof(*ei));
543 #define FILL(str, flag) \
544 do { \
545 for (s = str; *s != '\0'; s++) \
546 ei->cell[*s & 0x7f] |= flag; \
547 } while (/*CONSTCOND*/0)
549 FILL(base64, (s - base64) + 1);
550 FILL(direct, EI_DIRECT);
551 FILL(option, EI_OPTION);
552 FILL(spaces, EI_SPACE);
554 return 0;
557 /* ----------------------------------------------------------------------
558 * public interface for ctype
561 _CITRUS_CTYPE_DECLS(UTF7);
562 _CITRUS_CTYPE_DEF_OPS(UTF7);
564 #include "citrus_ctype_template.h"
566 /* ----------------------------------------------------------------------
567 * public interface for stdenc
570 _CITRUS_STDENC_DECLS(UTF7);
571 _CITRUS_STDENC_DEF_OPS(UTF7);
573 #include "citrus_stdenc_template.h"