1219019Sgabor/* $FreeBSD$ */
2219019Sgabor/*	$NetBSD: citrus_utf7.c,v 1.5 2006/08/23 12:57:24 tnozaki Exp $	*/
3219019Sgabor
4219019Sgabor/*-
5219019Sgabor * Copyright (c)2004, 2005 Citrus Project,
6219019Sgabor * All rights reserved.
7219019Sgabor *
8219019Sgabor * Redistribution and use in source and binary forms, with or without
9219019Sgabor * modification, are permitted provided that the following conditions
10219019Sgabor * are met:
11219019Sgabor * 1. Redistributions of source code must retain the above copyright
12219019Sgabor *    notice, this list of conditions and the following disclaimer.
13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright
14219019Sgabor *    notice, this list of conditions and the following disclaimer in the
15219019Sgabor *    documentation and/or other materials provided with the distribution.
16219019Sgabor *
17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20219019Sgabor * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27219019Sgabor * SUCH DAMAGE.
28219019Sgabor *
29219019Sgabor */
30219019Sgabor
31219019Sgabor#include <sys/cdefs.h>
32219019Sgabor
33219019Sgabor#include <assert.h>
34219019Sgabor#include <errno.h>
35219019Sgabor#include <limits.h>
36219019Sgabor#include <stdio.h>
37219019Sgabor#include <stdint.h>
38219019Sgabor#include <stdlib.h>
39219019Sgabor#include <string.h>
40219019Sgabor#include <wchar.h>
41219019Sgabor
42219019Sgabor#include "citrus_namespace.h"
43219019Sgabor#include "citrus_types.h"
44219019Sgabor#include "citrus_module.h"
45219019Sgabor#include "citrus_stdenc.h"
46219019Sgabor#include "citrus_utf7.h"
47219019Sgabor
48219019Sgabor/* ----------------------------------------------------------------------
49219019Sgabor * private stuffs used by templates
50219019Sgabor */
51219019Sgabor
52219019Sgabor#define EI_MASK		UINT16_C(0xff)
53219019Sgabor#define EI_DIRECT	UINT16_C(0x100)
54219019Sgabor#define EI_OPTION	UINT16_C(0x200)
55219019Sgabor#define EI_SPACE	UINT16_C(0x400)
56219019Sgabor
57219019Sgabortypedef struct {
58219019Sgabor	uint16_t	 cell[0x80];
59219019Sgabor} _UTF7EncodingInfo;
60219019Sgabor
61219019Sgabortypedef struct {
62219019Sgabor	unsigned int
63219019Sgabor		mode: 1,	/* whether base64 mode */
64219019Sgabor		bits: 4,	/* need to hold 0 - 15 */
65283908Stijl		cache: 22;	/* 22 = BASE64_BIT + UTF16_BIT */
66219019Sgabor	int chlen;
67219019Sgabor	char ch[4]; /* BASE64_IN, 3 * 6 = 18, most closed to UTF16_BIT */
68219019Sgabor} _UTF7State;
69219019Sgabor
70219019Sgabor#define	_CEI_TO_EI(_cei_)		(&(_cei_)->ei)
71219019Sgabor#define	_CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
72219019Sgabor
73219019Sgabor#define	_FUNCNAME(m)			_citrus_UTF7_##m
74219019Sgabor#define	_ENCODING_INFO			_UTF7EncodingInfo
75219019Sgabor#define	_ENCODING_STATE			_UTF7State
76219019Sgabor#define	_ENCODING_MB_CUR_MAX(_ei_)		4
77219019Sgabor#define	_ENCODING_IS_STATE_DEPENDENT		1
78219019Sgabor#define	_STATE_NEEDS_EXPLICIT_INIT(_ps_)	0
79219019Sgabor
80219019Sgaborstatic __inline void
81219019Sgabor/*ARGSUSED*/
82219019Sgabor_citrus_UTF7_init_state(_UTF7EncodingInfo * __restrict ei __unused,
83219019Sgabor    _UTF7State * __restrict s)
84219019Sgabor{
85219019Sgabor
86219019Sgabor	memset((void *)s, 0, sizeof(*s));
87219019Sgabor}
88219019Sgabor
89260264Sdim#if 0
90219019Sgaborstatic __inline void
91219019Sgabor/*ARGSUSED*/
92219019Sgabor_citrus_UTF7_pack_state(_UTF7EncodingInfo * __restrict ei __unused,
93219019Sgabor    void *__restrict pspriv, const _UTF7State * __restrict s)
94219019Sgabor{
95219019Sgabor
96219019Sgabor	memcpy(pspriv, (const void *)s, sizeof(*s));
97219019Sgabor}
98219019Sgabor
99219019Sgaborstatic __inline void
100219019Sgabor/*ARGSUSED*/
101219019Sgabor_citrus_UTF7_unpack_state(_UTF7EncodingInfo * __restrict ei __unused,
102219019Sgabor    _UTF7State * __restrict s, const void * __restrict pspriv)
103219019Sgabor{
104219019Sgabor
105219019Sgabor	memcpy((void *)s, pspriv, sizeof(*s));
106219019Sgabor}
107260264Sdim#endif
108219019Sgabor
109219019Sgaborstatic const char base64[] =
110219019Sgabor	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
111219019Sgabor	"abcdefghijklmnopqrstuvwxyz"
112219019Sgabor	"0123456789+/";
113219019Sgabor
114219019Sgaborstatic const char direct[] =
115219019Sgabor	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
116219019Sgabor	"abcdefghijklmnopqrstuvwxyz"
117258496Stijl	"0123456789'(),-./:?";
118219019Sgabor
119258496Stijlstatic const char option[] = "!\"#$%&*;<=>@[]^_`{|}";
120219019Sgaborstatic const char spaces[] = " \t\r\n";
121219019Sgabor
122219019Sgabor#define	BASE64_BIT	6
123219019Sgabor#define	UTF16_BIT	16
124219019Sgabor
125219019Sgabor#define	BASE64_MAX	0x3f
126219019Sgabor#define	UTF16_MAX	UINT16_C(0xffff)
127219019Sgabor#define	UTF32_MAX	UINT32_C(0x10ffff)
128219019Sgabor
129219019Sgabor#define	BASE64_IN	'+'
130219019Sgabor#define	BASE64_OUT	'-'
131219019Sgabor
132219019Sgabor#define	SHIFT7BIT(c)	((c) >> 7)
133219019Sgabor#define	ISSPECIAL(c)	((c) == '\0' || (c) == BASE64_IN)
134219019Sgabor
135219019Sgabor#define	FINDLEN(ei, c) \
136219019Sgabor	(SHIFT7BIT((c)) ? -1 : (((ei)->cell[(c)] & EI_MASK) - 1))
137219019Sgabor
138219019Sgabor#define	ISDIRECT(ei, c)	(!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
139219019Sgabor	ei->cell[(c)] & (EI_DIRECT | EI_OPTION | EI_SPACE)))
140219019Sgabor
141219019Sgabor#define	ISSAFE(ei, c)	(!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
142219019Sgabor	(c < 0x80 && ei->cell[(c)] & (EI_DIRECT | EI_SPACE))))
143219019Sgabor
144219019Sgabor/* surrogate pair */
145219019Sgabor#define	SRG_BASE	UINT32_C(0x10000)
146219019Sgabor#define	HISRG_MIN	UINT16_C(0xd800)
147219019Sgabor#define	HISRG_MAX	UINT16_C(0xdbff)
148219019Sgabor#define	LOSRG_MIN	UINT16_C(0xdc00)
149219019Sgabor#define	LOSRG_MAX	UINT16_C(0xdfff)
150219019Sgabor
151219019Sgaborstatic int
152219019Sgabor_citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,
153282275Stijl    uint16_t * __restrict u16, char ** __restrict s, size_t n,
154219019Sgabor    _UTF7State * __restrict psenc, size_t * __restrict nresult)
155219019Sgabor{
156282275Stijl	char *s0;
157219019Sgabor	int done, i, len;
158219019Sgabor
159283908Stijl	*nresult = 0;
160219019Sgabor	s0 = *s;
161219019Sgabor
162219019Sgabor	for (i = 0, done = 0; done == 0; i++) {
163219019Sgabor		if (i == psenc->chlen) {
164219019Sgabor			if (n-- < 1) {
165219019Sgabor				*nresult = (size_t)-2;
166219019Sgabor				*s = s0;
167219019Sgabor				return (0);
168219019Sgabor			}
169219019Sgabor			psenc->ch[psenc->chlen++] = *s0++;
170219019Sgabor		}
171219019Sgabor		if (SHIFT7BIT((int)psenc->ch[i]))
172219019Sgabor			goto ilseq;
173219019Sgabor		if (!psenc->mode) {
174219019Sgabor			if (psenc->bits > 0 || psenc->cache > 0)
175219019Sgabor				return (EINVAL);
176219019Sgabor			if (psenc->ch[i] == BASE64_IN)
177219019Sgabor				psenc->mode = 1;
178219019Sgabor			else {
179219019Sgabor				if (!ISDIRECT(ei, (int)psenc->ch[i]))
180219019Sgabor					goto ilseq;
181219019Sgabor				*u16 = (uint16_t)psenc->ch[i];
182219019Sgabor				done = 1;
183219019Sgabor				continue;
184219019Sgabor			}
185219019Sgabor		} else {
186219019Sgabor			if (psenc->ch[i] == BASE64_OUT && psenc->cache == 0) {
187219019Sgabor				psenc->mode = 0;
188219019Sgabor				*u16 = (uint16_t)BASE64_IN;
189219019Sgabor				done = 1;
190219019Sgabor				continue;
191219019Sgabor			}
192219019Sgabor			len = FINDLEN(ei, (int)psenc->ch[i]);
193219019Sgabor			if (len < 0) {
194219019Sgabor				if (psenc->bits >= BASE64_BIT)
195219019Sgabor					return (EINVAL);
196219019Sgabor				psenc->mode = 0;
197219019Sgabor				psenc->bits = psenc->cache = 0;
198219019Sgabor				if (psenc->ch[i] != BASE64_OUT) {
199219019Sgabor					if (!ISDIRECT(ei, (int)psenc->ch[i]))
200219019Sgabor						goto ilseq;
201219019Sgabor					*u16 = (uint16_t)psenc->ch[i];
202219019Sgabor					done = 1;
203258496Stijl				} else {
204258496Stijl					psenc->chlen--;
205258496Stijl					i--;
206219019Sgabor				}
207219019Sgabor			} else {
208219019Sgabor				psenc->cache =
209219019Sgabor				    (psenc->cache << BASE64_BIT) | len;
210219019Sgabor				switch (psenc->bits) {
211219019Sgabor				case 0: case 2: case 4: case 6: case 8:
212219019Sgabor					psenc->bits += BASE64_BIT;
213219019Sgabor					break;
214219019Sgabor				case 10: case 12: case 14:
215219019Sgabor					psenc->bits -= (UTF16_BIT - BASE64_BIT);
216219019Sgabor					*u16 = (psenc->cache >> psenc->bits) &
217219019Sgabor					    UTF16_MAX;
218219019Sgabor					done = 1;
219219019Sgabor					break;
220219019Sgabor				default:
221219019Sgabor					return (EINVAL);
222219019Sgabor				}
223219019Sgabor			}
224219019Sgabor		}
225219019Sgabor	}
226219019Sgabor
227219019Sgabor	if (psenc->chlen > i)
228219019Sgabor		return (EINVAL);
229219019Sgabor	psenc->chlen = 0;
230219019Sgabor	*nresult = (size_t)((*u16 == 0) ? 0 : s0 - *s);
231219019Sgabor	*s = s0;
232219019Sgabor
233219019Sgabor	return (0);
234219019Sgabor
235219019Sgaborilseq:
236219019Sgabor	*nresult = (size_t)-1;
237219019Sgabor	return (EILSEQ);
238219019Sgabor}
239219019Sgabor
240219019Sgaborstatic int
241219019Sgabor_citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,
242282275Stijl    wchar_t * __restrict pwc, char ** __restrict s, size_t n,
243219019Sgabor    _UTF7State * __restrict psenc, size_t * __restrict nresult)
244219019Sgabor{
245219019Sgabor	uint32_t u32;
246219019Sgabor	uint16_t hi, lo;
247219019Sgabor	size_t nr, siz;
248219019Sgabor	int err;
249219019Sgabor
250219019Sgabor	if (*s == NULL) {
251219019Sgabor		_citrus_UTF7_init_state(ei, psenc);
252219019Sgabor		*nresult = (size_t)_ENCODING_IS_STATE_DEPENDENT;
253219019Sgabor		return (0);
254219019Sgabor	}
255283908Stijl	err = _citrus_UTF7_mbtoutf16(ei, &hi, s, n, psenc, &nr);
256283908Stijl	if (nr == (size_t)-1 || nr == (size_t)-2) {
257283908Stijl		*nresult = nr;
258283908Stijl		return (err);
259219019Sgabor	}
260283908Stijl	if (err != 0)
261283908Stijl		return (err);
262283908Stijl	n -= nr;
263283908Stijl	siz = nr;
264283908Stijl	if (hi < HISRG_MIN || hi > HISRG_MAX) {
265283908Stijl		u32 = (uint32_t)hi;
266283908Stijl		goto done;
267283908Stijl	}
268258496Stijl	err = _citrus_UTF7_mbtoutf16(ei, &lo, s, n, psenc, &nr);
269219019Sgabor	if (nr == (size_t)-1 || nr == (size_t)-2) {
270283908Stijl		psenc->chlen = 1; /* make get_state_desc return incomplete */
271219019Sgabor		*nresult = nr;
272219019Sgabor		return (err);
273219019Sgabor	}
274219019Sgabor	if (err != 0)
275219019Sgabor		return (err);
276283908Stijl	if (lo < LOSRG_MIN || lo > LOSRG_MAX) {
277283908Stijl		*nresult = (size_t)-1;
278283908Stijl		return (EILSEQ);
279283908Stijl	}
280219019Sgabor	hi -= HISRG_MIN;
281219019Sgabor	lo -= LOSRG_MIN;
282219019Sgabor	u32 = (hi << 10 | lo) + SRG_BASE;
283219019Sgabor	siz += nr;
284219019Sgabordone:
285219019Sgabor	if (pwc != NULL)
286219019Sgabor		*pwc = (wchar_t)u32;
287219019Sgabor	if (u32 == (uint32_t)0) {
288219019Sgabor		*nresult = (size_t)0;
289219019Sgabor		_citrus_UTF7_init_state(ei, psenc);
290219019Sgabor	} else {
291219019Sgabor		*nresult = siz;
292219019Sgabor	}
293219019Sgabor	return (err);
294219019Sgabor}
295219019Sgabor
296219019Sgaborstatic int
297219019Sgabor_citrus_UTF7_utf16tomb(_UTF7EncodingInfo * __restrict ei,
298219019Sgabor    char * __restrict s, size_t n __unused, uint16_t u16,
299219019Sgabor    _UTF7State * __restrict psenc, size_t * __restrict nresult)
300219019Sgabor{
301219019Sgabor	int bits, i;
302219019Sgabor
303219019Sgabor	if (psenc->chlen != 0 || psenc->bits > BASE64_BIT)
304219019Sgabor		return (EINVAL);
305219019Sgabor
306219019Sgabor	if (ISSAFE(ei, u16)) {
307219019Sgabor		if (psenc->mode) {
308219019Sgabor			if (psenc->bits > 0) {
309219019Sgabor				bits = BASE64_BIT - psenc->bits;
310219019Sgabor				i = (psenc->cache << bits) & BASE64_MAX;
311219019Sgabor				psenc->ch[psenc->chlen++] = base64[i];
312219019Sgabor				psenc->bits = psenc->cache = 0;
313219019Sgabor			}
314219019Sgabor			if (u16 == BASE64_OUT || FINDLEN(ei, u16) >= 0)
315219019Sgabor				psenc->ch[psenc->chlen++] = BASE64_OUT;
316219019Sgabor			psenc->mode = 0;
317219019Sgabor		}
318219019Sgabor		if (psenc->bits != 0)
319219019Sgabor			return (EINVAL);
320219019Sgabor		psenc->ch[psenc->chlen++] = (char)u16;
321219019Sgabor		if (u16 == BASE64_IN)
322219019Sgabor			psenc->ch[psenc->chlen++] = BASE64_OUT;
323219019Sgabor	} else {
324219019Sgabor		if (!psenc->mode) {
325219019Sgabor			if (psenc->bits > 0)
326219019Sgabor				return (EINVAL);
327219019Sgabor			psenc->ch[psenc->chlen++] = BASE64_IN;
328219019Sgabor			psenc->mode = 1;
329219019Sgabor		}
330219019Sgabor		psenc->cache = (psenc->cache << UTF16_BIT) | u16;
331219019Sgabor		bits = UTF16_BIT + psenc->bits;
332219019Sgabor		psenc->bits = bits % BASE64_BIT;
333219019Sgabor		while ((bits -= BASE64_BIT) >= 0) {
334219019Sgabor			i = (psenc->cache >> bits) & BASE64_MAX;
335219019Sgabor			psenc->ch[psenc->chlen++] = base64[i];
336219019Sgabor		}
337219019Sgabor	}
338219019Sgabor	memcpy(s, psenc->ch, psenc->chlen);
339219019Sgabor	*nresult = psenc->chlen;
340219019Sgabor	psenc->chlen = 0;
341219019Sgabor
342219019Sgabor	return (0);
343219019Sgabor}
344219019Sgabor
345219019Sgaborstatic int
346219019Sgabor_citrus_UTF7_wcrtomb_priv(_UTF7EncodingInfo * __restrict ei,
347219019Sgabor    char * __restrict s, size_t n, wchar_t wchar,
348219019Sgabor    _UTF7State * __restrict psenc, size_t * __restrict nresult)
349219019Sgabor{
350219019Sgabor	uint32_t u32;
351219019Sgabor	uint16_t u16[2];
352219019Sgabor	int err, i, len;
353219019Sgabor	size_t nr, siz;
354219019Sgabor
355219019Sgabor	u32 = (uint32_t)wchar;
356219019Sgabor	if (u32 <= UTF16_MAX) {
357219019Sgabor		u16[0] = (uint16_t)u32;
358219019Sgabor		len = 1;
359219019Sgabor	} else if (u32 <= UTF32_MAX) {
360219019Sgabor		u32 -= SRG_BASE;
361219019Sgabor		u16[0] = (u32 >> 10) + HISRG_MIN;
362219019Sgabor		u16[1] = ((uint16_t)(u32 & UINT32_C(0x3ff))) + LOSRG_MIN;
363219019Sgabor		len = 2;
364219019Sgabor	} else {
365219019Sgabor		*nresult = (size_t)-1;
366219019Sgabor		return (EILSEQ);
367219019Sgabor	}
368219019Sgabor	siz = 0;
369219019Sgabor	for (i = 0; i < len; ++i) {
370219019Sgabor		err = _citrus_UTF7_utf16tomb(ei, s, n, u16[i], psenc, &nr);
371219019Sgabor		if (err != 0)
372219019Sgabor			return (err); /* XXX: state has been modified */
373219019Sgabor		s += nr;
374219019Sgabor		n -= nr;
375219019Sgabor		siz += nr;
376219019Sgabor	}
377219019Sgabor	*nresult = siz;
378219019Sgabor
379219019Sgabor	return (0);
380219019Sgabor}
381219019Sgabor
382219019Sgaborstatic int
383219019Sgabor/* ARGSUSED */
384219019Sgabor_citrus_UTF7_put_state_reset(_UTF7EncodingInfo * __restrict ei __unused,
385219019Sgabor    char * __restrict s, size_t n, _UTF7State * __restrict psenc,
386219019Sgabor    size_t * __restrict nresult)
387219019Sgabor{
388219019Sgabor	int bits, pos;
389219019Sgabor
390283908Stijl	if (psenc->chlen != 0 || psenc->bits > BASE64_BIT)
391219019Sgabor		return (EINVAL);
392219019Sgabor
393219019Sgabor	if (psenc->mode) {
394219019Sgabor		if (psenc->bits > 0) {
395219019Sgabor			if (n-- < 1)
396219019Sgabor				return (E2BIG);
397219019Sgabor			bits = BASE64_BIT - psenc->bits;
398219019Sgabor			pos = (psenc->cache << bits) & BASE64_MAX;
399219019Sgabor			psenc->ch[psenc->chlen++] = base64[pos];
400219019Sgabor			psenc->ch[psenc->chlen++] = BASE64_OUT;
401219019Sgabor			psenc->bits = psenc->cache = 0;
402219019Sgabor		}
403219019Sgabor		psenc->mode = 0;
404219019Sgabor	}
405219019Sgabor	if (psenc->bits != 0)
406219019Sgabor		return (EINVAL);
407219019Sgabor	if (n-- < 1)
408219019Sgabor		return (E2BIG);
409219019Sgabor
410219019Sgabor	*nresult = (size_t)psenc->chlen;
411219019Sgabor	if (psenc->chlen > 0) {
412219019Sgabor		memcpy(s, psenc->ch, psenc->chlen);
413219019Sgabor		psenc->chlen = 0;
414219019Sgabor	}
415219019Sgabor
416219019Sgabor	return (0);
417219019Sgabor}
418219019Sgabor
419219019Sgaborstatic __inline int
420219019Sgabor/*ARGSUSED*/
421219019Sgabor_citrus_UTF7_stdenc_wctocs(_UTF7EncodingInfo * __restrict ei __unused,
422219019Sgabor    _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
423219019Sgabor{
424219019Sgabor
425219019Sgabor	*csid = 0;
426219019Sgabor	*idx = (_index_t)wc;
427219019Sgabor
428219019Sgabor	return (0);
429219019Sgabor}
430219019Sgabor
431219019Sgaborstatic __inline int
432219019Sgabor/*ARGSUSED*/
433219019Sgabor_citrus_UTF7_stdenc_cstowc(_UTF7EncodingInfo * __restrict ei __unused,
434219019Sgabor    wchar_t * __restrict wc, _csid_t csid, _index_t idx)
435219019Sgabor{
436219019Sgabor
437219019Sgabor	if (csid != 0)
438219019Sgabor		return (EILSEQ);
439219019Sgabor	*wc = (wchar_t)idx;
440219019Sgabor
441219019Sgabor	return (0);
442219019Sgabor}
443219019Sgabor
444219019Sgaborstatic __inline int
445219019Sgabor/*ARGSUSED*/
446219019Sgabor_citrus_UTF7_stdenc_get_state_desc_generic(_UTF7EncodingInfo * __restrict ei __unused,
447219019Sgabor    _UTF7State * __restrict psenc, int * __restrict rstate)
448219019Sgabor{
449219019Sgabor
450219019Sgabor	*rstate = (psenc->chlen == 0) ? _STDENC_SDGEN_INITIAL :
451219019Sgabor	    _STDENC_SDGEN_INCOMPLETE_CHAR;
452219019Sgabor	return (0);
453219019Sgabor}
454219019Sgabor
455219019Sgaborstatic void
456219019Sgabor/*ARGSUSED*/
457219019Sgabor_citrus_UTF7_encoding_module_uninit(_UTF7EncodingInfo *ei __unused)
458219019Sgabor{
459219019Sgabor
460219019Sgabor	/* ei seems to be unused */
461219019Sgabor}
462219019Sgabor
463219019Sgaborstatic int
464219019Sgabor/*ARGSUSED*/
465219019Sgabor_citrus_UTF7_encoding_module_init(_UTF7EncodingInfo * __restrict ei,
466219019Sgabor    const void * __restrict var __unused, size_t lenvar __unused)
467219019Sgabor{
468219019Sgabor	const char *s;
469219019Sgabor
470219019Sgabor	memset(ei, 0, sizeof(*ei));
471219019Sgabor
472219019Sgabor#define FILL(str, flag)				\
473219019Sgabordo {						\
474219019Sgabor	for (s = str; *s != '\0'; s++)		\
475219019Sgabor		ei->cell[*s & 0x7f] |= flag;	\
476219019Sgabor} while (/*CONSTCOND*/0)
477219019Sgabor
478219019Sgabor	FILL(base64, (s - base64) + 1);
479219019Sgabor	FILL(direct, EI_DIRECT);
480219019Sgabor	FILL(option, EI_OPTION);
481219019Sgabor	FILL(spaces, EI_SPACE);
482219019Sgabor
483219019Sgabor	return (0);
484219019Sgabor}
485219019Sgabor
486219019Sgabor/* ----------------------------------------------------------------------
487219019Sgabor * public interface for stdenc
488219019Sgabor */
489219019Sgabor
490219019Sgabor_CITRUS_STDENC_DECLS(UTF7);
491219019Sgabor_CITRUS_STDENC_DEF_OPS(UTF7);
492219019Sgabor
493219019Sgabor#include "citrus_stdenc_template.h"
494