1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin 
24da2e3ebdSchin /*
25da2e3ebdSchin  * Glenn Fowler
26da2e3ebdSchin  * AT&T Research
27da2e3ebdSchin  *
28da2e3ebdSchin  * iconv intercept
29da2e3ebdSchin  * minimally provides { utf*<=>bin ascii<=>ebcdic* }
30da2e3ebdSchin  */
31da2e3ebdSchin 
32da2e3ebdSchin #include <ast.h>
33da2e3ebdSchin #include <dirent.h>
34da2e3ebdSchin 
35da2e3ebdSchin #define DEBUG_TRACE		0
36da2e3ebdSchin #define _ICONV_LIST_PRIVATE_
37da2e3ebdSchin 
38da2e3ebdSchin #include <ccode.h>
39da2e3ebdSchin #include <ctype.h>
40da2e3ebdSchin #include <iconv.h>
41da2e3ebdSchin 
42da2e3ebdSchin #include "lclib.h"
43da2e3ebdSchin 
44da2e3ebdSchin #if !_lib_iconv_open
45da2e3ebdSchin 
46da2e3ebdSchin #define _ast_iconv_t		iconv_t
47da2e3ebdSchin #define _ast_iconv_f		iconv_f
48da2e3ebdSchin #define _ast_iconv_list_t	iconv_list_t
49da2e3ebdSchin #define _ast_iconv_open		iconv_open
50da2e3ebdSchin #define _ast_iconv		iconv
51da2e3ebdSchin #define _ast_iconv_close	iconv_close
52da2e3ebdSchin #define _ast_iconv_list		iconv_list
53da2e3ebdSchin #define _ast_iconv_move		iconv_move
54da2e3ebdSchin #define _ast_iconv_name		iconv_name
55da2e3ebdSchin #define _ast_iconv_write	iconv_write
56da2e3ebdSchin 
57da2e3ebdSchin #endif
58da2e3ebdSchin 
59da2e3ebdSchin #ifndef E2BIG
60da2e3ebdSchin #define E2BIG			ENOMEM
61da2e3ebdSchin #endif
62da2e3ebdSchin #ifndef EILSEQ
63da2e3ebdSchin #define EILSEQ			EIO
64da2e3ebdSchin #endif
65da2e3ebdSchin 
66da2e3ebdSchin #define RETURN(e,n,fn) \
67da2e3ebdSchin 	if (*fn && !e) e = E2BIG; \
68da2e3ebdSchin 	if (e) { errno = e; return (size_t)(-1); } \
69da2e3ebdSchin 	return n;
70da2e3ebdSchin 
71da2e3ebdSchin typedef struct Map_s
72da2e3ebdSchin {
73da2e3ebdSchin 	char*			name;
74da2e3ebdSchin 	const unsigned char*	map;
75da2e3ebdSchin 	_ast_iconv_f		fun;
76da2e3ebdSchin 	int			index;
77da2e3ebdSchin } Map_t;
78da2e3ebdSchin 
79da2e3ebdSchin typedef struct Conv_s
80da2e3ebdSchin {
81da2e3ebdSchin 	iconv_t			cvt;
82da2e3ebdSchin 	char*			buf;
83da2e3ebdSchin 	size_t			size;
84da2e3ebdSchin 	Map_t			from;
85da2e3ebdSchin 	Map_t			to;
86da2e3ebdSchin } Conv_t;
87da2e3ebdSchin 
88da2e3ebdSchin static Conv_t*			freelist[4];
89da2e3ebdSchin static int			freeindex;
90da2e3ebdSchin 
91da2e3ebdSchin static const char		name_local[] = "local";
92da2e3ebdSchin static const char		name_native[] = "native";
93da2e3ebdSchin 
94da2e3ebdSchin static const _ast_iconv_list_t	codes[] =
95da2e3ebdSchin {
96da2e3ebdSchin 	{
97da2e3ebdSchin 	"utf",
98da2e3ebdSchin 	"un|unicode|utf",
99da2e3ebdSchin 	"multibyte 8-bit unicode",
100da2e3ebdSchin 	"UTF-%s",
101da2e3ebdSchin 	"8",
102da2e3ebdSchin 	CC_UTF,
103da2e3ebdSchin 	},
104da2e3ebdSchin 
105da2e3ebdSchin 	{
106da2e3ebdSchin 	"ume",
107da2e3ebdSchin 	"um|ume|utf?(-)7",
108da2e3ebdSchin 	"multibyte 7-bit unicode",
109da2e3ebdSchin 	"UTF-7",
110da2e3ebdSchin 	0,
111da2e3ebdSchin 	CC_UME,
112da2e3ebdSchin 	},
113da2e3ebdSchin 
114da2e3ebdSchin 	{
115da2e3ebdSchin 	"euc",
116da2e3ebdSchin 	"(big|euc)*",
117da2e3ebdSchin 	"euc family",
118da2e3ebdSchin 	0,
119da2e3ebdSchin 	0,
120da2e3ebdSchin 	CC_ICONV,
121da2e3ebdSchin 	},
122da2e3ebdSchin 
123da2e3ebdSchin 	{
124da2e3ebdSchin 	"dos",
125da2e3ebdSchin 	"dos?(-)?(855)",
126da2e3ebdSchin 	"dos code page",
127da2e3ebdSchin 	"DOS855",
128da2e3ebdSchin 	0,
129da2e3ebdSchin 	CC_ICONV,
130da2e3ebdSchin 	},
131da2e3ebdSchin 
132da2e3ebdSchin 	{
133da2e3ebdSchin 	"ucs",
134da2e3ebdSchin 	"ucs?(-)?(2)?(be)|utf-16?(be)",
135da2e3ebdSchin 	"unicode runes",
136da2e3ebdSchin 	"UCS-%s",
137da2e3ebdSchin 	"2",
138da2e3ebdSchin 	CC_UCS,
139da2e3ebdSchin 	},
140da2e3ebdSchin 
141da2e3ebdSchin 	{
142da2e3ebdSchin 	"ucs-le",
143da2e3ebdSchin 	"ucs?(-)?(2)le|utf-16le",
144da2e3ebdSchin 	"little endian unicode runes",
145da2e3ebdSchin 	"UCS-%sLE",
146da2e3ebdSchin 	"2",
147da2e3ebdSchin 	CC_SCU,
148da2e3ebdSchin 	},
149da2e3ebdSchin 
150da2e3ebdSchin 	{ 0 },
151da2e3ebdSchin };
152da2e3ebdSchin 
153da2e3ebdSchin #if _UWIN
154da2e3ebdSchin 
155da2e3ebdSchin #include <ast_windows.h>
156da2e3ebdSchin 
157da2e3ebdSchin #ifndef CP_UCS2
158da2e3ebdSchin #define CP_UCS2	0x0000
159da2e3ebdSchin #endif
160da2e3ebdSchin 
161da2e3ebdSchin static char	_win_maps[] = "/reg/local_machine/SOFTWARE/Classes/MIME/Database/Charset";
162da2e3ebdSchin 
163da2e3ebdSchin /*
164da2e3ebdSchin  * return the codeset index given its name or alias
165da2e3ebdSchin  * the map is in the what? oh, the registry
166da2e3ebdSchin  */
167da2e3ebdSchin 
168da2e3ebdSchin static int
_win_codeset(const char * name)169da2e3ebdSchin _win_codeset(const char* name)
170da2e3ebdSchin {
171da2e3ebdSchin 	register char*	s;
172da2e3ebdSchin 	char*		e;
173da2e3ebdSchin 	int		n;
174da2e3ebdSchin 	Sfio_t*		sp;
175da2e3ebdSchin 	char		aka[128];
176da2e3ebdSchin 	char		tmp[128];
177da2e3ebdSchin 
178da2e3ebdSchin #if DEBUG_TRACE
179da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d _win_codeset name=%s", __LINE__, name);
180da2e3ebdSchin #endif
181da2e3ebdSchin 	if (name == name_native)
182da2e3ebdSchin 		return CP_ACP;
183da2e3ebdSchin 	if (!strcasecmp(name, "utf") || !strcasecmp(name, "utf8") || !strcasecmp(name, "utf-8"))
184da2e3ebdSchin 		return CP_UTF8;
185da2e3ebdSchin 	if (!strcasecmp(name, "ucs") || !strcasecmp(name, "ucs2") || !strcasecmp(name, "ucs-2"))
186da2e3ebdSchin 		return CP_UCS2;
187da2e3ebdSchin 	if (name[0] == '0' && name[1] == 'x' && (n = strtol(name, &e, 0)) > 0 && !*e)
188da2e3ebdSchin 		return n;
189da2e3ebdSchin 	for (;;)
190da2e3ebdSchin 	{
191da2e3ebdSchin 		sfsprintf(tmp, sizeof(tmp), "%s/%s", _win_maps, name);
192da2e3ebdSchin 		if (!(sp = sfopen(0, tmp, "r")))
193da2e3ebdSchin 		{
194da2e3ebdSchin 			s = (char*)name;
195da2e3ebdSchin 			if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'p' || s[1] == 'P'))
196da2e3ebdSchin 				s += 2;
197da2e3ebdSchin 			if (!isdigit(s[0]))
198da2e3ebdSchin 				break;
199da2e3ebdSchin 			sfsprintf(tmp, sizeof(tmp), "%s/windows-%s", _win_maps, s);
200da2e3ebdSchin 			if (!(sp = sfopen(0, tmp, "r")))
201da2e3ebdSchin 				break;
202da2e3ebdSchin 		}
203da2e3ebdSchin 		for (;;)
204da2e3ebdSchin 		{
205da2e3ebdSchin 			if (!(s = sfgetr(sp, '\n', 0)))
206da2e3ebdSchin 			{
207da2e3ebdSchin 				sfclose(sp);
208da2e3ebdSchin 				return -1;
209da2e3ebdSchin 			}
210da2e3ebdSchin 			if (!strncasecmp(s, "AliasForCharSet=", 16))
211da2e3ebdSchin 			{
212da2e3ebdSchin 				n = sfvalue(sp) - 17;
213da2e3ebdSchin 				s += 16;
214da2e3ebdSchin 				if (n >= sizeof(aka))
215da2e3ebdSchin 					n = sizeof(aka) - 1;
216da2e3ebdSchin 				memcpy(aka, s, n);
217da2e3ebdSchin 				aka[n] = 0;
218da2e3ebdSchin 				sfclose(sp);
219da2e3ebdSchin 				name = (const char*)aka;
220da2e3ebdSchin 				break;
221da2e3ebdSchin 			}
222da2e3ebdSchin 			if (!strncasecmp(s, "CodePage=", 9))
223da2e3ebdSchin 			{
224da2e3ebdSchin 				s += 9;
225da2e3ebdSchin 				n = strtol(s, 0, 0);
226da2e3ebdSchin 				sfclose(sp);
227da2e3ebdSchin 				return n;
228da2e3ebdSchin 			}
229da2e3ebdSchin 		}
230da2e3ebdSchin 	}
231da2e3ebdSchin 	return -1;
232da2e3ebdSchin }
233da2e3ebdSchin 
234da2e3ebdSchin /*
235da2e3ebdSchin  * get and check the codeset indices
236da2e3ebdSchin  */
237da2e3ebdSchin 
238da2e3ebdSchin static _ast_iconv_t
_win_iconv_open(register Conv_t * cc,const char * t,const char * f)239da2e3ebdSchin _win_iconv_open(register Conv_t* cc, const char* t, const char* f)
240da2e3ebdSchin {
241da2e3ebdSchin #if DEBUG_TRACE
242da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d _win_iconv_open f=%s t=%s\n", __LINE__, f, t);
243da2e3ebdSchin #endif
244da2e3ebdSchin 	if ((cc->from.index = _win_codeset(f)) < 0)
245da2e3ebdSchin 		return (_ast_iconv_t)(-1);
246da2e3ebdSchin 	if ((cc->to.index = _win_codeset(t)) < 0)
247da2e3ebdSchin 		return (_ast_iconv_t)(-1);
248da2e3ebdSchin #if DEBUG_TRACE
249da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d _win_iconv_open f=0x%04x t=0x%04x\n", __LINE__, cc->from.index, cc->to.index);
250da2e3ebdSchin #endif
251da2e3ebdSchin 	return (_ast_iconv_t)cc;
252da2e3ebdSchin }
253da2e3ebdSchin 
254da2e3ebdSchin /*
255da2e3ebdSchin  * even though the indices already check out
256da2e3ebdSchin  * they could still be rejected
257da2e3ebdSchin  */
258da2e3ebdSchin 
259da2e3ebdSchin static size_t
_win_iconv(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)260da2e3ebdSchin _win_iconv(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
261da2e3ebdSchin {
262da2e3ebdSchin 	Conv_t*	cc = (Conv_t*)cd;
263da2e3ebdSchin 	size_t	un;
264da2e3ebdSchin 	size_t	tz;
265da2e3ebdSchin 	size_t	fz;
266da2e3ebdSchin 	size_t	bz;
267da2e3ebdSchin 	size_t	pz;
268da2e3ebdSchin 	size_t	oz;
269da2e3ebdSchin 	LPWSTR	ub;
270da2e3ebdSchin 
271da2e3ebdSchin #if DEBUG_TRACE
272da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d _win_iconv from=0x%04x to=0x%04x\n", __LINE__, cc->from.index, cc->to.index);
273da2e3ebdSchin #endif
274*b30d1939SAndy Fiddaman 	if (cc->from.index == cc->to.index || cc->from.index != CP_UCS2 && cc->to.index == 0)
275da2e3ebdSchin 	{
276da2e3ebdSchin 		/*
277da2e3ebdSchin 		 * easy
278da2e3ebdSchin 		 */
279da2e3ebdSchin 
280da2e3ebdSchin 		fz = tz = (*fn < *tn) ? *fn : *tn;
281da2e3ebdSchin 		memcpy(*tb, *fb, fz);
282da2e3ebdSchin 	}
283da2e3ebdSchin 	else
284da2e3ebdSchin 	{
285da2e3ebdSchin 		ub = 0;
286da2e3ebdSchin 		un = *fn;
287da2e3ebdSchin 
288da2e3ebdSchin 		/*
289da2e3ebdSchin 		 * from => ucs-2
290da2e3ebdSchin 		 */
291da2e3ebdSchin 
292da2e3ebdSchin 		if (cc->to.index == CP_UCS2)
293da2e3ebdSchin 		{
294da2e3ebdSchin 			if ((tz = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)*fn, (LPWSTR)*tb, *tn)) && tz <= *tn)
295da2e3ebdSchin 			{
296da2e3ebdSchin 				fz = *fn;
297da2e3ebdSchin 				tz *= sizeof(WCHAR);
298da2e3ebdSchin 			}
299da2e3ebdSchin 			else
300da2e3ebdSchin 			{
301da2e3ebdSchin 				/*
302da2e3ebdSchin 				 * target too small
303da2e3ebdSchin 				 * binary search on input size to make it fit
304da2e3ebdSchin 				 */
305da2e3ebdSchin 
306da2e3ebdSchin 				oz = 0;
307da2e3ebdSchin 				pz = *fn / 2;
308da2e3ebdSchin 				fz = *fn - pz;
309da2e3ebdSchin 				for (;;)
310da2e3ebdSchin 				{
311da2e3ebdSchin 					while (!(tz = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)fz, (LPWSTR)*tb, 0)))
312da2e3ebdSchin 						if (++fz >= *fn)
313da2e3ebdSchin 							goto nope;
314da2e3ebdSchin 					tz *= sizeof(WCHAR);
315da2e3ebdSchin 					if (tz == *tn)
316da2e3ebdSchin 						break;
317da2e3ebdSchin 					if (!(pz /= 2))
318da2e3ebdSchin 					{
319da2e3ebdSchin 						if (!(fz = oz))
320da2e3ebdSchin 							goto nope;
321da2e3ebdSchin 						break;
322da2e3ebdSchin 					}
323da2e3ebdSchin 					if (tz > *tn)
324da2e3ebdSchin 						fz -= pz;
325da2e3ebdSchin 					else
326da2e3ebdSchin 					{
327da2e3ebdSchin 						oz = fz;
328da2e3ebdSchin 						fz += pz;
329da2e3ebdSchin 					}
330da2e3ebdSchin 				}
331da2e3ebdSchin 			}
332da2e3ebdSchin 		}
333da2e3ebdSchin 		else
334da2e3ebdSchin 		{
335da2e3ebdSchin 			if (cc->from.index == CP_UCS2)
336da2e3ebdSchin 			{
337da2e3ebdSchin 				un = *fn / sizeof(WCHAR);
338da2e3ebdSchin 				ub = (LPWSTR)*fb;
339da2e3ebdSchin 			}
340da2e3ebdSchin 			else if (!(un = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)*fn, (LPWSTR)*tb, 0)))
341da2e3ebdSchin 				goto nope;
342da2e3ebdSchin 			else if (!(ub = (LPWSTR)malloc(un * sizeof(WCHAR))))
343da2e3ebdSchin 				goto nope;
344da2e3ebdSchin 			else if (!(un = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)*fn, (LPWSTR)ub, un)))
345da2e3ebdSchin 				goto nope;
346da2e3ebdSchin 
347da2e3ebdSchin 			/*
348da2e3ebdSchin 			 * ucs-2 => to
349da2e3ebdSchin 			 */
350da2e3ebdSchin 
351da2e3ebdSchin 			if (tz = WideCharToMultiByte(cc->to.index, 0, (LPCWSTR)ub, un, *tb, *tn, 0, 0))
352da2e3ebdSchin 				fz = *fn;
353da2e3ebdSchin 			else
354da2e3ebdSchin 			{
355da2e3ebdSchin 				/*
356da2e3ebdSchin 				 * target too small
357da2e3ebdSchin 				 * binary search on input size to make it fit
358da2e3ebdSchin 				 */
359da2e3ebdSchin 
360da2e3ebdSchin 				oz = 0;
361da2e3ebdSchin 				pz = *fn / 2;
362da2e3ebdSchin 				bz = *fn - pz;
363da2e3ebdSchin 				for (;;)
364da2e3ebdSchin 				{
365da2e3ebdSchin 					while (!(fz = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)bz, (LPWSTR)ub, un)))
366da2e3ebdSchin 						if (++bz > *fn)
367da2e3ebdSchin 							goto nope;
368da2e3ebdSchin 					if (!(tz = WideCharToMultiByte(cc->to.index, 0, (LPCWSTR)ub, fz, *tb, 0, 0, 0)))
369da2e3ebdSchin 						goto nope;
370da2e3ebdSchin 					if (tz == *tn)
371da2e3ebdSchin 						break;
372da2e3ebdSchin 					if (!(pz /= 2))
373da2e3ebdSchin 					{
374da2e3ebdSchin 						if (!(fz = oz))
375da2e3ebdSchin 							goto nope;
376da2e3ebdSchin 						break;
377da2e3ebdSchin 					}
378da2e3ebdSchin 					if (tz > *tn)
379da2e3ebdSchin 						bz -= pz;
380da2e3ebdSchin 					else
381da2e3ebdSchin 					{
382da2e3ebdSchin 						oz = bz;
383da2e3ebdSchin 						bz += pz;
384da2e3ebdSchin 					}
385da2e3ebdSchin 				}
386da2e3ebdSchin 				if (!(tz = WideCharToMultiByte(cc->to.index, 0, (LPCWSTR)ub, fz, *tb, tz, 0, 0)))
387da2e3ebdSchin 					goto nope;
388da2e3ebdSchin #if DEBUG_TRACE
389da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d _win_iconv *fn=%u fz=%u[%u] *tn=%u tz=%u\n", __LINE__, *fn, fz, fz * sizeof(WCHAR), *tn, tz);
390da2e3ebdSchin #endif
391da2e3ebdSchin #if 0
392da2e3ebdSchin 				fz *= sizeof(WCHAR);
393da2e3ebdSchin #endif
394da2e3ebdSchin 			}
395da2e3ebdSchin 			if (ub != (LPWSTR)*fb)
396da2e3ebdSchin 				free(ub);
397da2e3ebdSchin 		}
398da2e3ebdSchin 	}
399da2e3ebdSchin 	*fb += fz;
400da2e3ebdSchin 	*fn -= fz;
401da2e3ebdSchin 	*tb += tz;
402da2e3ebdSchin 	*tn -= tz;
403da2e3ebdSchin 	return fz;
404da2e3ebdSchin  nope:
405da2e3ebdSchin 	if (ub && ub != (LPWSTR)*fb)
406da2e3ebdSchin 		free(ub);
407da2e3ebdSchin 	errno = EINVAL;
408da2e3ebdSchin 	return (size_t)(-1);
409da2e3ebdSchin }
410da2e3ebdSchin 
411da2e3ebdSchin #endif
412da2e3ebdSchin 
413da2e3ebdSchin /*
414da2e3ebdSchin  * return canonical character code set name for m
415da2e3ebdSchin  * if b!=0 then canonical name placed in b of size n
416da2e3ebdSchin  * <ccode.h> index returned
417da2e3ebdSchin  */
418da2e3ebdSchin 
419da2e3ebdSchin int
_ast_iconv_name(register const char * m,register char * b,size_t n)420da2e3ebdSchin _ast_iconv_name(register const char* m, register char* b, size_t n)
421da2e3ebdSchin {
422da2e3ebdSchin 	register const _ast_iconv_list_t*	cp;
423da2e3ebdSchin 	const _ast_iconv_list_t*		bp;
424da2e3ebdSchin 	register int				c;
425da2e3ebdSchin 	register char*				e;
426*b30d1939SAndy Fiddaman 	ssize_t					sub[2];
427da2e3ebdSchin 	char					buf[16];
428da2e3ebdSchin #if DEBUG_TRACE
429da2e3ebdSchin 	char*					o;
430da2e3ebdSchin #endif
431da2e3ebdSchin 
432da2e3ebdSchin 	if (!b)
433da2e3ebdSchin 	{
434da2e3ebdSchin 		b = buf;
435da2e3ebdSchin 		n = sizeof(buf);
436da2e3ebdSchin 	}
437da2e3ebdSchin #if DEBUG_TRACE
438da2e3ebdSchin 	o = b;
439da2e3ebdSchin #endif
440da2e3ebdSchin 	e = b + n - 1;
441da2e3ebdSchin 	bp = 0;
442da2e3ebdSchin 	n = 0;
443da2e3ebdSchin 	cp = ccmaplist(NiL);
444da2e3ebdSchin #if DEBUG_TRACE
445da2e3ebdSchin if (error_info.trace < DEBUG_TRACE) sfprintf(sfstderr, "%s: debug-%d: AHA%d _ast_iconv_name m=\"%s\"\n", error_info.id, error_info.trace, __LINE__, m);
446da2e3ebdSchin #endif
447da2e3ebdSchin 	for (;;)
448da2e3ebdSchin 	{
449da2e3ebdSchin #if DEBUG_TRACE
450da2e3ebdSchin if (error_info.trace < DEBUG_TRACE) sfprintf(sfstderr, "%s: debug-%d: AHA%d _ast_iconv_name n=%d bp=%p cp=%p ccode=%d name=\"%s\"\n", error_info.id, error_info.trace, __LINE__, n, bp, cp, cp->ccode, cp->name);
451da2e3ebdSchin #endif
452da2e3ebdSchin 		if (strgrpmatch(m, cp->match, sub, elementsof(sub) / 2, STR_MAXIMAL|STR_LEFT|STR_ICASE))
453da2e3ebdSchin 		{
454da2e3ebdSchin 			if (!(c = m[sub[1]]))
455da2e3ebdSchin 			{
456da2e3ebdSchin 				bp = cp;
457da2e3ebdSchin 				break;
458da2e3ebdSchin 			}
459da2e3ebdSchin 			if (sub[1] > n && !isalpha(c))
460da2e3ebdSchin 			{
461da2e3ebdSchin 				bp = cp;
462da2e3ebdSchin 				n = sub[1];
463da2e3ebdSchin 			}
464da2e3ebdSchin 		}
465da2e3ebdSchin 		if (cp->ccode < 0)
466da2e3ebdSchin 		{
467da2e3ebdSchin 			if (!(++cp)->name)
468da2e3ebdSchin 				break;
469da2e3ebdSchin 		}
470da2e3ebdSchin 		else if (!(cp = (const _ast_iconv_list_t*)ccmaplist((_ast_iconv_list_t*)cp)))
471da2e3ebdSchin 			cp = codes;
472da2e3ebdSchin 	}
473da2e3ebdSchin 	if (cp = bp)
474da2e3ebdSchin 	{
475da2e3ebdSchin 		if (cp->canon)
476da2e3ebdSchin 		{
477da2e3ebdSchin 			if (cp->index)
478da2e3ebdSchin 			{
479da2e3ebdSchin 				for (m += sub[1]; *m && !isalnum(*m); m++);
480da2e3ebdSchin 				if (!isdigit(*m))
481da2e3ebdSchin 					m = cp->index;
482da2e3ebdSchin 			}
483da2e3ebdSchin 			else
484da2e3ebdSchin 				m = "1";
485da2e3ebdSchin 			b += sfsprintf(b, e - b, cp->canon, m);
486da2e3ebdSchin 		}
487da2e3ebdSchin 		else if (cp->ccode == CC_NATIVE)
488da2e3ebdSchin 		{
489da2e3ebdSchin 			if ((locales[AST_LC_CTYPE]->flags & LC_default) || !locales[AST_LC_CTYPE]->charset || !(m = locales[AST_LC_CTYPE]->charset->code) || streq(m, "iso8859-1"))
490da2e3ebdSchin 				switch (CC_NATIVE)
491da2e3ebdSchin 				{
492da2e3ebdSchin 				case CC_EBCDIC:
493da2e3ebdSchin 					m = (const char*)"EBCDIC";
494da2e3ebdSchin 					break;
495da2e3ebdSchin 				case CC_EBCDIC_I:
496da2e3ebdSchin 					m = (const char*)"EBCDIC-I";
497da2e3ebdSchin 					break;
498da2e3ebdSchin 				case CC_EBCDIC_O:
499da2e3ebdSchin 					m = (const char*)"EBCDIC-O";
500da2e3ebdSchin 					break;
501da2e3ebdSchin 				default:
502da2e3ebdSchin 					m = (const char*)"ISO-8859-1";
503da2e3ebdSchin 					break;
504da2e3ebdSchin 				}
505da2e3ebdSchin 			b += sfsprintf(b, e - b, "%s", m);
506da2e3ebdSchin 		}
507da2e3ebdSchin 		*b = 0;
508da2e3ebdSchin #if DEBUG_TRACE
509da2e3ebdSchin if (error_info.trace < DEBUG_TRACE) sfprintf(sfstderr, "%s: debug-%d: AHA%d _ast_iconv_name ccode=%d canon=\"%s\"\n", error_info.id, error_info.trace, __LINE__, cp->ccode, o);
510da2e3ebdSchin #endif
511da2e3ebdSchin 		return cp->ccode;
512da2e3ebdSchin 	}
513da2e3ebdSchin 	while (b < e && (c = *m++))
514da2e3ebdSchin 	{
515da2e3ebdSchin 		if (islower(c))
516da2e3ebdSchin 			c = toupper(c);
517da2e3ebdSchin 		*b++ = c;
518da2e3ebdSchin 	}
519da2e3ebdSchin 	*b = 0;
520da2e3ebdSchin #if DEBUG_TRACE
521da2e3ebdSchin if (error_info.trace < DEBUG_TRACE) sfprintf(sfstderr, "%s: debug-%d: AHA%d _ast_iconv_name ccode=%d canon=\"%s\"\n", error_info.id, error_info.trace, __LINE__, CC_ICONV, o);
522da2e3ebdSchin #endif
523da2e3ebdSchin 	return CC_ICONV;
524da2e3ebdSchin }
525da2e3ebdSchin 
526da2e3ebdSchin /*
527da2e3ebdSchin  * convert utf-8 to bin
528da2e3ebdSchin  */
529da2e3ebdSchin 
530da2e3ebdSchin static size_t
utf2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)531da2e3ebdSchin utf2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
532da2e3ebdSchin {
533da2e3ebdSchin 	register unsigned char*		f;
534da2e3ebdSchin 	register unsigned char*		fe;
535da2e3ebdSchin 	register unsigned char*		t;
536da2e3ebdSchin 	register unsigned char*		te;
537da2e3ebdSchin 	register unsigned char*		p;
538da2e3ebdSchin 	register int			c;
539da2e3ebdSchin 	register int			w;
540da2e3ebdSchin 	size_t				n;
541da2e3ebdSchin 	int				e;
542da2e3ebdSchin 
543da2e3ebdSchin 	e = 0;
544da2e3ebdSchin 	f = (unsigned char*)(*fb);
545da2e3ebdSchin 	fe = f + (*fn);
546da2e3ebdSchin 	t = (unsigned char*)(*tb);
547da2e3ebdSchin 	te = t + (*tn);
548da2e3ebdSchin 	while (t < te && f < fe)
549da2e3ebdSchin 	{
550da2e3ebdSchin 		p = f;
551da2e3ebdSchin 		c = *f++;
552da2e3ebdSchin 		if (c & 0x80)
553da2e3ebdSchin 		{
554da2e3ebdSchin 			if (!(c & 0x40))
555da2e3ebdSchin 			{
556da2e3ebdSchin 				f = p;
557da2e3ebdSchin 				e = EILSEQ;
558da2e3ebdSchin 				break;
559da2e3ebdSchin 			}
560da2e3ebdSchin 			if (c & 0x20)
561da2e3ebdSchin 			{
562da2e3ebdSchin 				w = (c & 0x0F) << 12;
563da2e3ebdSchin 				if (f >= fe)
564da2e3ebdSchin 				{
565da2e3ebdSchin 					f = p;
566da2e3ebdSchin 					e = EINVAL;
567da2e3ebdSchin 					break;
568da2e3ebdSchin 				}
569da2e3ebdSchin 				c = *f++;
570da2e3ebdSchin 				if (c & 0x40)
571da2e3ebdSchin 				{
572da2e3ebdSchin 					f = p;
573da2e3ebdSchin 					e = EILSEQ;
574da2e3ebdSchin 					break;
575da2e3ebdSchin 				}
576da2e3ebdSchin 				w |= (c & 0x3F) << 6;
577da2e3ebdSchin 			}
578da2e3ebdSchin 			else
579da2e3ebdSchin 				w = (c & 0x1F) << 6;
580da2e3ebdSchin 			if (f >= fe)
581da2e3ebdSchin 			{
582da2e3ebdSchin 				f = p;
583da2e3ebdSchin 				e = EINVAL;
584da2e3ebdSchin 				break;
585da2e3ebdSchin 			}
586da2e3ebdSchin 			c = *f++;
587da2e3ebdSchin 			w |= (c & 0x3F);
588da2e3ebdSchin 		}
589da2e3ebdSchin 		else
590da2e3ebdSchin 			w = c;
591da2e3ebdSchin 		*t++ = w;
592da2e3ebdSchin 	}
593da2e3ebdSchin 	*fn -= (char*)f - (*fb);
594da2e3ebdSchin 	*fb = (char*)f;
595da2e3ebdSchin 	*tn -= (n = (char*)t - (*tb));
596da2e3ebdSchin 	*tb = (char*)t;
597da2e3ebdSchin 	RETURN(e, n, fn);
598da2e3ebdSchin }
599da2e3ebdSchin 
600da2e3ebdSchin /*
601da2e3ebdSchin  * convert bin to utf-8
602da2e3ebdSchin  */
603da2e3ebdSchin 
604da2e3ebdSchin static size_t
bin2utf(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)605da2e3ebdSchin bin2utf(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
606da2e3ebdSchin {
607da2e3ebdSchin 	register unsigned char*		f;
608da2e3ebdSchin 	register unsigned char*		fe;
609da2e3ebdSchin 	register unsigned char*		t;
610da2e3ebdSchin 	register unsigned char*		te;
611da2e3ebdSchin 	register int			c;
612da2e3ebdSchin 	wchar_t				w;
613da2e3ebdSchin 	size_t				n;
614da2e3ebdSchin 	int				e;
615da2e3ebdSchin 
616da2e3ebdSchin 	e = 0;
617da2e3ebdSchin 	f = (unsigned char*)(*fb);
618da2e3ebdSchin 	fe = f + (*fn);
619da2e3ebdSchin 	t = (unsigned char*)(*tb);
620da2e3ebdSchin 	te = t + (*tn);
621da2e3ebdSchin 	while (f < fe && t < te)
622da2e3ebdSchin 	{
623da2e3ebdSchin 		if (!mbwide())
624da2e3ebdSchin 		{
625da2e3ebdSchin 			c = 1;
626da2e3ebdSchin 			w = *f;
627da2e3ebdSchin 		}
628da2e3ebdSchin 		else if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
629da2e3ebdSchin 		{
630da2e3ebdSchin 			e = EINVAL;
631da2e3ebdSchin 			break;
632da2e3ebdSchin 		}
633da2e3ebdSchin 		else if (!c)
634da2e3ebdSchin 			c = 1;
635da2e3ebdSchin 		if (!(w & ~0x7F))
636da2e3ebdSchin 			*t++ = w;
637da2e3ebdSchin 		else
638da2e3ebdSchin 		{
639da2e3ebdSchin 			if (!(w & ~0x7FF))
640da2e3ebdSchin 			{
641da2e3ebdSchin 				if (t >= (te - 2))
642da2e3ebdSchin 				{
643da2e3ebdSchin 					e = E2BIG;
644da2e3ebdSchin 					break;
645da2e3ebdSchin 				}
646da2e3ebdSchin 				*t++ = 0xC0 + (w >> 6);
647da2e3ebdSchin 			}
648da2e3ebdSchin 			else if (!(w & ~0xffff))
649da2e3ebdSchin 			{
650da2e3ebdSchin 				if (t >= (te - 3))
651da2e3ebdSchin 				{
652da2e3ebdSchin 					e = E2BIG;
653da2e3ebdSchin 					break;
654da2e3ebdSchin 				}
655da2e3ebdSchin 				*t++ = 0xE0 + (w >> 12);
656da2e3ebdSchin 				*t++ = 0x80 + ((w >> 6 ) & 0x3F);
657da2e3ebdSchin 			}
658da2e3ebdSchin 			else
659da2e3ebdSchin 			{
660da2e3ebdSchin 				e = EILSEQ;
661da2e3ebdSchin 				break;
662da2e3ebdSchin 			}
663da2e3ebdSchin 			*t++ = 0x80 + (w & 0x3F);
664da2e3ebdSchin 		}
665da2e3ebdSchin 		f += c;
666da2e3ebdSchin 	}
667da2e3ebdSchin 	*fn -= (n = (char*)f - (*fb));
668da2e3ebdSchin 	*fb = (char*)f;
669da2e3ebdSchin 	*tn -= (char*)t - (*tb);
670da2e3ebdSchin 	*tb = (char*)t;
671da2e3ebdSchin 	RETURN(e, n, fn);
672da2e3ebdSchin }
673da2e3ebdSchin 
674da2e3ebdSchin static const unsigned char	ume_D[] =
675da2e3ebdSchin "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?!\"#$%&*;<=>@[]^_`{|} \t\n";
676da2e3ebdSchin 
677da2e3ebdSchin static const unsigned char	ume_M[] =
678da2e3ebdSchin "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
679da2e3ebdSchin 
680da2e3ebdSchin static unsigned char		ume_d[UCHAR_MAX+1];
681da2e3ebdSchin 
682da2e3ebdSchin static unsigned char		ume_m[UCHAR_MAX+1];
683da2e3ebdSchin 
684da2e3ebdSchin #define NOE			0xFF
685da2e3ebdSchin #define UMEINIT()		(ume_d[ume_D[0]]?0:umeinit())
686da2e3ebdSchin 
687da2e3ebdSchin /*
688da2e3ebdSchin  * initialize the ume tables
689da2e3ebdSchin  */
690da2e3ebdSchin 
691da2e3ebdSchin static int
umeinit(void)692da2e3ebdSchin umeinit(void)
693da2e3ebdSchin {
694da2e3ebdSchin 	register const unsigned char*	s;
695da2e3ebdSchin 	register int			i;
696da2e3ebdSchin 	register int			c;
697da2e3ebdSchin 
698da2e3ebdSchin 	if (!ume_d[ume_D[0]])
699da2e3ebdSchin 	{
700da2e3ebdSchin 		s = ume_D;
701da2e3ebdSchin 		while (c = *s++)
702da2e3ebdSchin 			ume_d[c] = 1;
703da2e3ebdSchin 		memset(ume_m, NOE, sizeof(ume_m));
704da2e3ebdSchin 		for (i = 0; c = ume_M[i]; i++)
705da2e3ebdSchin 			ume_m[c] = i;
706da2e3ebdSchin 	}
707da2e3ebdSchin 	return 0;
708da2e3ebdSchin }
709da2e3ebdSchin 
710da2e3ebdSchin /*
711da2e3ebdSchin  * convert utf-7 to bin
712da2e3ebdSchin  */
713da2e3ebdSchin 
714da2e3ebdSchin static size_t
ume2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)715da2e3ebdSchin ume2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
716da2e3ebdSchin {
717da2e3ebdSchin 	register unsigned char*		f;
718da2e3ebdSchin 	register unsigned char*		fe;
719da2e3ebdSchin 	register unsigned char*		t;
720da2e3ebdSchin 	register unsigned char*		te;
721da2e3ebdSchin 	register unsigned char*		p;
722da2e3ebdSchin 	register int			s;
723da2e3ebdSchin 	register int			c;
724da2e3ebdSchin 	register int			w;
725da2e3ebdSchin 	size_t				n;
726da2e3ebdSchin 	int				e;
727da2e3ebdSchin 
728da2e3ebdSchin 	e = 0;
729da2e3ebdSchin 	UMEINIT();
730da2e3ebdSchin 	f = (unsigned char*)(*fb);
731da2e3ebdSchin 	fe = f + (*fn);
732da2e3ebdSchin 	t = (unsigned char*)(*tb);
733da2e3ebdSchin 	te = t + (*tn);
734da2e3ebdSchin 	s = 0;
735da2e3ebdSchin 	while (f < fe && t < te)
736da2e3ebdSchin 	{
737da2e3ebdSchin 		p = f;
738da2e3ebdSchin 		c = *f++;
739da2e3ebdSchin 		if (s)
740da2e3ebdSchin 		{
741da2e3ebdSchin 			if (c == '-' && s > 1)
742da2e3ebdSchin 				s = 0;
743da2e3ebdSchin 			else if ((w = ume_m[c]) == NOE)
744da2e3ebdSchin 			{
745da2e3ebdSchin 				s = 0;
746da2e3ebdSchin 				*t++ = c;
747da2e3ebdSchin 			}
748da2e3ebdSchin 			else if (f >= (fe - 2))
749da2e3ebdSchin 			{
750da2e3ebdSchin 				f = p;
751da2e3ebdSchin 				e = EINVAL;
752da2e3ebdSchin 				break;
753da2e3ebdSchin 			}
754da2e3ebdSchin 			else
755da2e3ebdSchin 			{
756da2e3ebdSchin 				s = 2;
757da2e3ebdSchin 				w = (w << 6) | ume_m[*f++];
758da2e3ebdSchin 				w = (w << 6) | ume_m[*f++];
759da2e3ebdSchin 				if (!(w & ~0xFF))
760da2e3ebdSchin 					*t++ = w;
761da2e3ebdSchin 				else if (t >= (te - 1))
762da2e3ebdSchin 				{
763da2e3ebdSchin 					f = p;
764da2e3ebdSchin 					e = E2BIG;
765da2e3ebdSchin 					break;
766da2e3ebdSchin 				}
767da2e3ebdSchin 				else
768da2e3ebdSchin 				{
769da2e3ebdSchin 					*t++ = (w >> 8) & 0xFF;
770da2e3ebdSchin 					*t++ = w & 0xFF;
771da2e3ebdSchin 				}
772da2e3ebdSchin 			}
773da2e3ebdSchin 		}
774da2e3ebdSchin 		else if (c == '+')
775da2e3ebdSchin 			s = 1;
776da2e3ebdSchin 		else
777da2e3ebdSchin 			*t++ = c;
778da2e3ebdSchin 	}
779da2e3ebdSchin 	*fn -= (char*)f - (*fb);
780da2e3ebdSchin 	*fb = (char*)f;
781da2e3ebdSchin 	*tn -= (n = (char*)t - (*tb));
782da2e3ebdSchin 	*tb = (char*)t;
783da2e3ebdSchin 	RETURN(e, n, fn);
784da2e3ebdSchin }
785da2e3ebdSchin 
786da2e3ebdSchin /*
787da2e3ebdSchin  * convert bin to utf-7
788da2e3ebdSchin  */
789da2e3ebdSchin 
790da2e3ebdSchin static size_t
bin2ume(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)791da2e3ebdSchin bin2ume(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
792da2e3ebdSchin {
793da2e3ebdSchin 	register unsigned char*		f;
794da2e3ebdSchin 	register unsigned char*		fe;
795da2e3ebdSchin 	register unsigned char*		t;
796da2e3ebdSchin 	register unsigned char*		te;
797da2e3ebdSchin 	register int			c;
798da2e3ebdSchin 	register int			s;
799da2e3ebdSchin 	wchar_t				w;
800da2e3ebdSchin 	size_t				n;
801da2e3ebdSchin 	int				e;
802da2e3ebdSchin 
803da2e3ebdSchin 	e = 0;
804da2e3ebdSchin 	UMEINIT();
805da2e3ebdSchin 	f = (unsigned char*)(*fb);
806da2e3ebdSchin 	fe = f + (*fn);
807da2e3ebdSchin 	t = (unsigned char*)(*tb);
808da2e3ebdSchin 	te = t + (*tn);
809da2e3ebdSchin 	s = 0;
810da2e3ebdSchin 	while (f < fe && t < (te - s))
811da2e3ebdSchin 	{
812da2e3ebdSchin 		if (!mbwide())
813da2e3ebdSchin 		{
814da2e3ebdSchin 			c = 1;
815da2e3ebdSchin 			w = *f;
816da2e3ebdSchin 		}
817da2e3ebdSchin 		else if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
818da2e3ebdSchin 		{
819da2e3ebdSchin 			e = EINVAL;
820da2e3ebdSchin 			break;
821da2e3ebdSchin 		}
822da2e3ebdSchin 		else if (!c)
823da2e3ebdSchin 			c = 1;
824da2e3ebdSchin 		if (!(w & ~0x7F) && ume_d[w])
825da2e3ebdSchin 		{
826da2e3ebdSchin 			if (s)
827da2e3ebdSchin 			{
828da2e3ebdSchin 				s = 0;
829da2e3ebdSchin 				*t++ = '-';
830da2e3ebdSchin 			}
831da2e3ebdSchin 			*t++ = w;
832da2e3ebdSchin 		}
833da2e3ebdSchin 		else if (t >= (te - (4 + s)))
834da2e3ebdSchin 		{
835da2e3ebdSchin 			e = E2BIG;
836da2e3ebdSchin 			break;
837da2e3ebdSchin 		}
838da2e3ebdSchin 		else
839da2e3ebdSchin 		{
840da2e3ebdSchin 			if (!s)
841da2e3ebdSchin 			{
842da2e3ebdSchin 				s = 1;
843da2e3ebdSchin 				*t++ = '+';
844da2e3ebdSchin 			}
845da2e3ebdSchin 			*t++ = ume_M[(w >> 12) & 0x3F];
846da2e3ebdSchin 			*t++ = ume_M[(w >> 6) & 0x3F];
847da2e3ebdSchin 			*t++ = ume_M[w & 0x3F];
848da2e3ebdSchin 		}
849da2e3ebdSchin 		f += c;
850da2e3ebdSchin 	}
851da2e3ebdSchin 	if (s)
852da2e3ebdSchin 		*t++ = '-';
853da2e3ebdSchin 	*fn -= (n = (char*)f - (*fb));
854da2e3ebdSchin 	*fb = (char*)f;
855da2e3ebdSchin 	*tn -= (char*)t - (*tb);
856da2e3ebdSchin 	*tb = (char*)t;
857da2e3ebdSchin 	RETURN(e, n, fn);
858da2e3ebdSchin }
859da2e3ebdSchin 
860da2e3ebdSchin /*
861da2e3ebdSchin  * convert ucs-2 to bin with no byte swap
862da2e3ebdSchin  */
863da2e3ebdSchin 
864da2e3ebdSchin static size_t
ucs2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)865da2e3ebdSchin ucs2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
866da2e3ebdSchin {
867da2e3ebdSchin 	register unsigned char*		f;
868da2e3ebdSchin 	register unsigned char*		fe;
869da2e3ebdSchin 	register unsigned char*		t;
870da2e3ebdSchin 	register unsigned char*		te;
871da2e3ebdSchin 	register int			w;
872da2e3ebdSchin 	size_t				n;
873da2e3ebdSchin 	int				e;
874da2e3ebdSchin 
875da2e3ebdSchin 	e = 0;
876da2e3ebdSchin 	f = (unsigned char*)(*fb);
877da2e3ebdSchin 	fe = f + (*fn);
878da2e3ebdSchin 	t = (unsigned char*)(*tb);
879da2e3ebdSchin 	te = t + (*tn);
880da2e3ebdSchin 	while (f < (fe - 1) && t < te)
881da2e3ebdSchin 	{
882da2e3ebdSchin 		w = *f++;
883da2e3ebdSchin 		w = (w << 8) | *f++;
884da2e3ebdSchin 		if (!(w & ~0xFF))
885da2e3ebdSchin 			*t++ = w;
886da2e3ebdSchin 		else if (t >= (te - 1))
887da2e3ebdSchin 		{
888da2e3ebdSchin 			f -= 2;
889da2e3ebdSchin 			e = E2BIG;
890da2e3ebdSchin 			break;
891da2e3ebdSchin 		}
892da2e3ebdSchin 		else
893da2e3ebdSchin 		{
894da2e3ebdSchin 			*t++ = (w >> 8) & 0xFF;
895da2e3ebdSchin 			*t++ = w & 0xFF;
896da2e3ebdSchin 		}
897da2e3ebdSchin 	}
898da2e3ebdSchin 	*fn -= (char*)f - (*fb);
899da2e3ebdSchin 	*fb = (char*)f;
900da2e3ebdSchin 	*tn -= (n = (char*)t - (*tb));
901da2e3ebdSchin 	*tb = (char*)t;
902da2e3ebdSchin 	RETURN(e, n, fn);
903da2e3ebdSchin }
904da2e3ebdSchin 
905da2e3ebdSchin /*
906da2e3ebdSchin  * convert bin to ucs-2 with no byte swap
907da2e3ebdSchin  */
908da2e3ebdSchin 
909da2e3ebdSchin static size_t
bin2ucs(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)910da2e3ebdSchin bin2ucs(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
911da2e3ebdSchin {
912da2e3ebdSchin 	register unsigned char*		f;
913da2e3ebdSchin 	register unsigned char*		fe;
914da2e3ebdSchin 	register unsigned char*		t;
915da2e3ebdSchin 	register unsigned char*		te;
916da2e3ebdSchin 	register int			c;
917da2e3ebdSchin 	wchar_t				w;
918da2e3ebdSchin 	size_t				n;
919da2e3ebdSchin 	int				e;
920da2e3ebdSchin 
921da2e3ebdSchin 	e = 0;
922da2e3ebdSchin 	f = (unsigned char*)(*fb);
923da2e3ebdSchin 	fe = f + (*fn);
924da2e3ebdSchin 	t = (unsigned char*)(*tb);
925da2e3ebdSchin 	te = t + (*tn);
926da2e3ebdSchin 	while (f < fe && t < (te - 1))
927da2e3ebdSchin 	{
928da2e3ebdSchin 		if (!mbwide())
929da2e3ebdSchin 		{
930da2e3ebdSchin 			c = 1;
931da2e3ebdSchin 			w = *f;
932da2e3ebdSchin 		}
933da2e3ebdSchin 		if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
934da2e3ebdSchin 		{
935da2e3ebdSchin 			e = EINVAL;
936da2e3ebdSchin 			break;
937da2e3ebdSchin 		}
938da2e3ebdSchin 		else if (!c)
939da2e3ebdSchin 			c = 1;
940da2e3ebdSchin 		*t++ = (w >> 8) & 0xFF;
941da2e3ebdSchin 		*t++ = w & 0xFF;
942da2e3ebdSchin 		f += c;
943da2e3ebdSchin 	}
944da2e3ebdSchin 	*fn -= (n = (char*)f - (*fb));
945da2e3ebdSchin 	*fb = (char*)f;
946da2e3ebdSchin 	*tn -= (char*)t - (*tb);
947da2e3ebdSchin 	*tb = (char*)t;
948da2e3ebdSchin 	RETURN(e, n, fn);
949da2e3ebdSchin }
950da2e3ebdSchin 
951da2e3ebdSchin /*
952da2e3ebdSchin  * convert ucs-2 to bin with byte swap
953da2e3ebdSchin  */
954da2e3ebdSchin 
955da2e3ebdSchin static size_t
scu2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)956da2e3ebdSchin scu2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
957da2e3ebdSchin {
958da2e3ebdSchin 	register unsigned char*		f;
959da2e3ebdSchin 	register unsigned char*		fe;
960da2e3ebdSchin 	register unsigned char*		t;
961da2e3ebdSchin 	register unsigned char*		te;
962da2e3ebdSchin 	register int			w;
963da2e3ebdSchin 	size_t				n;
964da2e3ebdSchin 	int				e;
965da2e3ebdSchin 
966da2e3ebdSchin 	e = 0;
967da2e3ebdSchin 	f = (unsigned char*)(*fb);
968da2e3ebdSchin 	fe = f + (*fn);
969da2e3ebdSchin 	t = (unsigned char*)(*tb);
970da2e3ebdSchin 	te = t + (*tn);
971da2e3ebdSchin 	while (f < (fe - 1) && t < te)
972da2e3ebdSchin 	{
973da2e3ebdSchin 		w = *f++;
974da2e3ebdSchin 		w = w | (*f++ << 8);
975da2e3ebdSchin 		if (!(w & ~0xFF))
976da2e3ebdSchin 			*t++ = w;
977da2e3ebdSchin 		else if (t >= (te - 1))
978da2e3ebdSchin 		{
979da2e3ebdSchin 			f -= 2;
980da2e3ebdSchin 			e = E2BIG;
981da2e3ebdSchin 			break;
982da2e3ebdSchin 		}
983da2e3ebdSchin 		else
984da2e3ebdSchin 		{
985da2e3ebdSchin 			*t++ = (w >> 8) & 0xFF;
986da2e3ebdSchin 			*t++ = w & 0xFF;
987da2e3ebdSchin 		}
988da2e3ebdSchin 	}
989da2e3ebdSchin 	*fn -= (char*)f - (*fb);
990da2e3ebdSchin 	*fb = (char*)f;
991da2e3ebdSchin 	*tn -= (n = (char*)t - (*tb));
992da2e3ebdSchin 	*tb = (char*)t;
993da2e3ebdSchin 	RETURN(e, n, fn);
994da2e3ebdSchin }
995da2e3ebdSchin 
996da2e3ebdSchin /*
997da2e3ebdSchin  * convert bin to ucs-2 with byte swap
998da2e3ebdSchin  */
999da2e3ebdSchin 
1000da2e3ebdSchin static size_t
bin2scu(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)1001da2e3ebdSchin bin2scu(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
1002da2e3ebdSchin {
1003da2e3ebdSchin 	register unsigned char*		f;
1004da2e3ebdSchin 	register unsigned char*		fe;
1005da2e3ebdSchin 	register unsigned char*		t;
1006da2e3ebdSchin 	register unsigned char*		te;
1007da2e3ebdSchin 	register int			c;
1008da2e3ebdSchin 	wchar_t				w;
1009da2e3ebdSchin 	size_t				n;
1010da2e3ebdSchin 	int				e;
1011da2e3ebdSchin 
1012da2e3ebdSchin 	e = 0;
1013da2e3ebdSchin 	f = (unsigned char*)(*fb);
1014da2e3ebdSchin 	fe = f + (*fn);
1015da2e3ebdSchin 	t = (unsigned char*)(*tb);
1016da2e3ebdSchin 	te = t + (*tn);
1017da2e3ebdSchin 	while (f < fe && t < (te - 1))
1018da2e3ebdSchin 	{
1019da2e3ebdSchin 		if (!mbwide())
1020da2e3ebdSchin 		{
1021da2e3ebdSchin 			c = 1;
1022da2e3ebdSchin 			w = *f;
1023da2e3ebdSchin 		}
1024da2e3ebdSchin 		else if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
1025da2e3ebdSchin 		{
1026da2e3ebdSchin 			e = EINVAL;
1027da2e3ebdSchin 			break;
1028da2e3ebdSchin 		}
1029da2e3ebdSchin 		else if (!c)
1030da2e3ebdSchin 			c = 1;
1031da2e3ebdSchin 		*t++ = w & 0xFF;
1032da2e3ebdSchin 		*t++ = (w >> 8) & 0xFF;
1033da2e3ebdSchin 		f += c;
1034da2e3ebdSchin 	}
1035da2e3ebdSchin 	*fn -= (n = (char*)f - (*fb));
1036da2e3ebdSchin 	*fb = (char*)f;
1037da2e3ebdSchin 	*tn -= (char*)t - (*tb);
1038da2e3ebdSchin 	*tb = (char*)t;
1039da2e3ebdSchin 	RETURN(e, n, fn);
1040da2e3ebdSchin }
1041da2e3ebdSchin 
1042da2e3ebdSchin /*
1043da2e3ebdSchin  * open a character code conversion map from f to t
1044da2e3ebdSchin  */
1045da2e3ebdSchin 
1046da2e3ebdSchin _ast_iconv_t
_ast_iconv_open(const char * t,const char * f)1047da2e3ebdSchin _ast_iconv_open(const char* t, const char* f)
1048da2e3ebdSchin {
1049da2e3ebdSchin 	register Conv_t*	cc;
1050da2e3ebdSchin 	int			fc;
1051da2e3ebdSchin 	int			tc;
1052da2e3ebdSchin 	int			i;
1053da2e3ebdSchin 
1054da2e3ebdSchin 	char			fr[64];
1055da2e3ebdSchin 	char			to[64];
1056da2e3ebdSchin 
1057da2e3ebdSchin #if DEBUG_TRACE
1058da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d _ast_iconv_open f=%s t=%s\n", __LINE__, f, t);
1059da2e3ebdSchin #endif
1060da2e3ebdSchin 	if (!t || !*t || *t == '-' && !*(t + 1) || !strcasecmp(t, name_local) || !strcasecmp(t, name_native))
1061da2e3ebdSchin 		t = name_native;
1062da2e3ebdSchin 	if (!f || !*f || *f == '-' && !*(f + 1) || !strcasecmp(t, name_local) || !strcasecmp(f, name_native))
1063da2e3ebdSchin 		f = name_native;
1064da2e3ebdSchin 
1065da2e3ebdSchin 	/*
1066da2e3ebdSchin 	 * the ast identify is always (iconv_t)(0)
1067da2e3ebdSchin 	 */
1068da2e3ebdSchin 
1069da2e3ebdSchin 	if (t == f)
1070da2e3ebdSchin 		return (iconv_t)(0);
1071da2e3ebdSchin 	fc = _ast_iconv_name(f, fr, sizeof(fr));
1072da2e3ebdSchin 	tc = _ast_iconv_name(t, to, sizeof(to));
1073da2e3ebdSchin #if DEBUG_TRACE
1074da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d _ast_iconv_open f=%s:%s:%d t=%s:%s:%d\n", __LINE__, f, fr, fc, t, to, tc);
1075da2e3ebdSchin #endif
1076da2e3ebdSchin 	if (fc != CC_ICONV && fc == tc || streq(fr, to))
1077da2e3ebdSchin 		return (iconv_t)(0);
1078da2e3ebdSchin 
1079da2e3ebdSchin 	/*
1080da2e3ebdSchin 	 * first check the free list
1081da2e3ebdSchin 	 */
1082da2e3ebdSchin 
1083da2e3ebdSchin 	for (i = 0; i < elementsof(freelist); i++)
1084da2e3ebdSchin 		if ((cc = freelist[i]) && streq(to, cc->to.name) && streq(fr, cc->from.name))
1085da2e3ebdSchin 		{
1086da2e3ebdSchin 			freelist[i] = 0;
1087da2e3ebdSchin #if _lib_iconv_open
1088da2e3ebdSchin 			/*
1089da2e3ebdSchin 			 * reset the shift state if any
1090da2e3ebdSchin 			 */
1091da2e3ebdSchin 
1092da2e3ebdSchin 			if (cc->cvt != (iconv_t)(-1))
1093da2e3ebdSchin 				iconv(cc->cvt, NiL, NiL, NiL, NiL);
1094da2e3ebdSchin #endif
1095da2e3ebdSchin 			return cc;
1096da2e3ebdSchin 		}
1097da2e3ebdSchin 
1098da2e3ebdSchin 	/*
1099da2e3ebdSchin 	 * allocate a new one
1100da2e3ebdSchin 	 */
1101da2e3ebdSchin 
1102da2e3ebdSchin 	if (!(cc = newof(0, Conv_t, 1, strlen(to) + strlen(fr) + 2)))
1103da2e3ebdSchin 		return (iconv_t)(-1);
1104da2e3ebdSchin 	cc->to.name = (char*)(cc + 1);
1105da2e3ebdSchin 	cc->from.name = strcopy(cc->to.name, to) + 1;
1106da2e3ebdSchin 	strcpy(cc->from.name, fr);
1107da2e3ebdSchin 	cc->cvt = (iconv_t)(-1);
1108da2e3ebdSchin 
1109da2e3ebdSchin 	/*
1110da2e3ebdSchin 	 * 8 bit maps are the easiest
1111da2e3ebdSchin 	 */
1112da2e3ebdSchin 
1113da2e3ebdSchin 	if (fc >= 0 && tc >= 0)
1114da2e3ebdSchin 		cc->from.map = ccmap(fc, tc);
1115da2e3ebdSchin #if _lib_iconv_open
1116*b30d1939SAndy Fiddaman 	else if ((cc->cvt = iconv_open(t, f)) != (iconv_t)(-1) || (cc->cvt = iconv_open(to, fr)) != (iconv_t)(-1))
1117da2e3ebdSchin 		cc->from.fun = (_ast_iconv_f)iconv;
1118da2e3ebdSchin #endif
1119da2e3ebdSchin #if _UWIN
1120*b30d1939SAndy Fiddaman 	else if ((cc->cvt = _win_iconv_open(cc, t, f)) != (_ast_iconv_t)(-1) || (cc->cvt = _win_iconv_open(cc, to, fr)) != (_ast_iconv_t)(-1))
1121da2e3ebdSchin 		cc->from.fun = (_ast_iconv_f)_win_iconv;
1122da2e3ebdSchin #endif
1123da2e3ebdSchin 	else
1124da2e3ebdSchin 	{
1125da2e3ebdSchin 		switch (fc)
1126da2e3ebdSchin 		{
1127da2e3ebdSchin 		case CC_UTF:
1128da2e3ebdSchin 			cc->from.fun = utf2bin;
1129da2e3ebdSchin 			break;
1130da2e3ebdSchin 		case CC_UME:
1131da2e3ebdSchin 			cc->from.fun = ume2bin;
1132da2e3ebdSchin 			break;
1133da2e3ebdSchin 		case CC_UCS:
1134da2e3ebdSchin 			cc->from.fun = ucs2bin;
1135da2e3ebdSchin 			break;
1136da2e3ebdSchin 		case CC_SCU:
1137da2e3ebdSchin 			cc->from.fun = scu2bin;
1138da2e3ebdSchin 			break;
1139da2e3ebdSchin 		case CC_ASCII:
1140da2e3ebdSchin 			break;
1141da2e3ebdSchin 		default:
1142da2e3ebdSchin 			if (fc < 0)
1143da2e3ebdSchin 				goto nope;
1144da2e3ebdSchin 			cc->from.map = ccmap(fc, CC_ASCII);
1145da2e3ebdSchin 			break;
1146da2e3ebdSchin 		}
1147da2e3ebdSchin 		switch (tc)
1148da2e3ebdSchin 		{
1149da2e3ebdSchin 		case CC_UTF:
1150da2e3ebdSchin 			cc->to.fun = bin2utf;
1151da2e3ebdSchin 			break;
1152da2e3ebdSchin 		case CC_UME:
1153da2e3ebdSchin 			cc->to.fun = bin2ume;
1154da2e3ebdSchin 			break;
1155da2e3ebdSchin 		case CC_UCS:
1156da2e3ebdSchin 			cc->to.fun = bin2ucs;
1157da2e3ebdSchin 			break;
1158da2e3ebdSchin 		case CC_SCU:
1159da2e3ebdSchin 			cc->to.fun = bin2scu;
1160da2e3ebdSchin 			break;
1161da2e3ebdSchin 		case CC_ASCII:
1162da2e3ebdSchin 			break;
1163da2e3ebdSchin 		default:
1164da2e3ebdSchin 			if (tc < 0)
1165da2e3ebdSchin 				goto nope;
1166da2e3ebdSchin 			cc->to.map = ccmap(CC_ASCII, tc);
1167da2e3ebdSchin 			break;
1168da2e3ebdSchin 		}
1169da2e3ebdSchin 	}
1170da2e3ebdSchin 	return (iconv_t)cc;
1171da2e3ebdSchin  nope:
1172da2e3ebdSchin 	return (iconv_t)(-1);
1173da2e3ebdSchin }
1174da2e3ebdSchin 
1175da2e3ebdSchin /*
1176da2e3ebdSchin  * close a character code conversion map
1177da2e3ebdSchin  */
1178da2e3ebdSchin 
1179da2e3ebdSchin int
_ast_iconv_close(_ast_iconv_t cd)1180da2e3ebdSchin _ast_iconv_close(_ast_iconv_t cd)
1181da2e3ebdSchin {
1182da2e3ebdSchin 	Conv_t*	cc;
1183da2e3ebdSchin 	Conv_t*	oc;
1184da2e3ebdSchin 	int	i;
1185da2e3ebdSchin 	int	r = 0;
1186da2e3ebdSchin 
1187da2e3ebdSchin 	if (cd == (_ast_iconv_t)(-1))
1188da2e3ebdSchin 		return -1;
1189da2e3ebdSchin 	if (!(cc = (Conv_t*)cd))
1190da2e3ebdSchin 		return 0;
1191da2e3ebdSchin 
1192da2e3ebdSchin 	/*
1193da2e3ebdSchin 	 * add to the free list
1194da2e3ebdSchin 	 */
1195da2e3ebdSchin 
1196da2e3ebdSchin 	i = freeindex;
1197da2e3ebdSchin 	for (;;)
1198da2e3ebdSchin 	{
1199da2e3ebdSchin 		if (++ i >= elementsof(freelist))
1200da2e3ebdSchin 			i = 0;
1201da2e3ebdSchin 		if (!freelist[i])
1202da2e3ebdSchin 			break;
1203da2e3ebdSchin 		if (i == freeindex)
1204da2e3ebdSchin 		{
1205da2e3ebdSchin 			if (++ i >= elementsof(freelist))
1206da2e3ebdSchin 				i = 0;
1207da2e3ebdSchin 
1208da2e3ebdSchin 			/*
1209da2e3ebdSchin 			 * close the oldest
1210da2e3ebdSchin 			 */
1211da2e3ebdSchin 
1212da2e3ebdSchin 			if (oc = freelist[i])
1213da2e3ebdSchin 			{
1214da2e3ebdSchin #if _lib_iconv_open
1215da2e3ebdSchin 				if (oc->cvt != (iconv_t)(-1))
1216da2e3ebdSchin 					r = iconv_close(oc->cvt);
1217da2e3ebdSchin #endif
1218da2e3ebdSchin 				if (oc->buf)
1219da2e3ebdSchin 					free(oc->buf);
1220da2e3ebdSchin 				free(oc);
1221da2e3ebdSchin 			}
1222da2e3ebdSchin 			break;
1223da2e3ebdSchin 		}
1224da2e3ebdSchin 	}
1225da2e3ebdSchin 	freelist[freeindex = i] = cc;
1226da2e3ebdSchin 	return r;
1227da2e3ebdSchin }
1228da2e3ebdSchin 
1229da2e3ebdSchin /*
1230da2e3ebdSchin  * copy *fb size *fn to *tb size *tn
1231da2e3ebdSchin  * fb,fn tb,tn updated on return
1232da2e3ebdSchin  */
1233da2e3ebdSchin 
1234da2e3ebdSchin size_t
_ast_iconv(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)1235da2e3ebdSchin _ast_iconv(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
1236da2e3ebdSchin {
1237da2e3ebdSchin 	Conv_t*				cc = (Conv_t*)cd;
1238da2e3ebdSchin 	register unsigned char*		f;
1239da2e3ebdSchin 	register unsigned char*		t;
1240da2e3ebdSchin 	register unsigned char*		e;
1241da2e3ebdSchin 	register const unsigned char*	m;
1242da2e3ebdSchin 	register size_t			n;
1243da2e3ebdSchin 	char*				b;
1244da2e3ebdSchin 	char*				tfb;
1245da2e3ebdSchin 	size_t				tfn;
1246da2e3ebdSchin 	size_t				i;
1247da2e3ebdSchin 
1248da2e3ebdSchin 	if (!fb || !*fb)
1249da2e3ebdSchin 	{
1250da2e3ebdSchin 		/* TODO: reset to the initial state */
1251da2e3ebdSchin 		if (!tb || !*tb)
1252da2e3ebdSchin 			return 0;
1253da2e3ebdSchin 		/* TODO: write the initial state shift sequence */
1254da2e3ebdSchin 		return 0;
1255da2e3ebdSchin 	}
1256da2e3ebdSchin 	n = *tn;
1257da2e3ebdSchin 	if (cc)
1258da2e3ebdSchin 	{
1259da2e3ebdSchin 		if (cc->from.fun)
1260da2e3ebdSchin 		{
1261da2e3ebdSchin 			if (cc->to.fun)
1262da2e3ebdSchin 			{
1263da2e3ebdSchin 				if (!cc->buf && !(cc->buf = oldof(0, char, cc->size = SF_BUFSIZE, 0)))
1264da2e3ebdSchin 				{
1265da2e3ebdSchin 					errno = ENOMEM;
1266da2e3ebdSchin 					return -1;
1267da2e3ebdSchin 				}
1268da2e3ebdSchin 				b = cc->buf;
1269da2e3ebdSchin 				i = cc->size;
1270da2e3ebdSchin 				tfb = *fb;
1271da2e3ebdSchin 				tfn = *fn;
1272da2e3ebdSchin 				if ((*cc->from.fun)(cc->cvt, &tfb, &tfn, &b, &i) == (size_t)(-1))
1273da2e3ebdSchin 					return -1;
1274da2e3ebdSchin 				tfn = b - cc->buf;
1275da2e3ebdSchin 				tfb = cc->buf;
1276da2e3ebdSchin 				n = (*cc->to.fun)(cc->cvt, &tfb, &tfn, tb, tn);
1277da2e3ebdSchin 				i = tfb - cc->buf;
1278da2e3ebdSchin 				*fb += i;
1279da2e3ebdSchin 				*fn -= i;
1280da2e3ebdSchin 				return n;
1281da2e3ebdSchin 			}
1282da2e3ebdSchin 			if ((*cc->from.fun)(cc->cvt, fb, fn, tb, tn) == (size_t)(-1))
1283da2e3ebdSchin 				return -1;
1284da2e3ebdSchin 			n -= *tn;
1285da2e3ebdSchin 			if (m = cc->to.map)
1286da2e3ebdSchin 			{
1287da2e3ebdSchin 				e = (unsigned char*)(*tb);
1288da2e3ebdSchin 				for (t = e - n; t < e; t++)
1289da2e3ebdSchin 					*t = m[*t];
1290da2e3ebdSchin 			}
1291da2e3ebdSchin 			return n;
1292da2e3ebdSchin 		}
1293da2e3ebdSchin 		else if (cc->to.fun)
1294da2e3ebdSchin 		{
1295da2e3ebdSchin 			if (!(m = cc->from.map))
1296da2e3ebdSchin 				return (*cc->to.fun)(cc->cvt, fb, fn, tb, tn);
1297da2e3ebdSchin 			if (!cc->buf && !(cc->buf = oldof(0, char, cc->size = SF_BUFSIZE, 0)))
1298da2e3ebdSchin 			{
1299da2e3ebdSchin 				errno = ENOMEM;
1300da2e3ebdSchin 				return -1;
1301da2e3ebdSchin 			}
1302da2e3ebdSchin 			if ((n = *fn) > cc->size)
1303da2e3ebdSchin 				n = cc->size;
1304da2e3ebdSchin 			f = (unsigned char*)(*fb);
1305da2e3ebdSchin 			e = f + n;
1306da2e3ebdSchin 			t = (unsigned char*)(b = cc->buf);
1307da2e3ebdSchin 			while (f < e)
1308da2e3ebdSchin 				*t++ = m[*f++];
1309da2e3ebdSchin 			n = (*cc->to.fun)(cc->cvt, &b, fn, tb, tn);
1310da2e3ebdSchin 			*fb += b - cc->buf;
1311da2e3ebdSchin 			return n;
1312da2e3ebdSchin 		}
1313da2e3ebdSchin 	}
1314da2e3ebdSchin 	if (n > *fn)
1315da2e3ebdSchin 		n = *fn;
1316da2e3ebdSchin 	if (cc && (m = cc->from.map))
1317da2e3ebdSchin 	{
1318da2e3ebdSchin 		f = (unsigned char*)(*fb);
1319da2e3ebdSchin 		e = f + n;
1320da2e3ebdSchin 		t = (unsigned char*)(*tb);
1321da2e3ebdSchin 		while (f < e)
1322da2e3ebdSchin 			*t++ = m[*f++];
1323da2e3ebdSchin 	}
1324da2e3ebdSchin 	else
1325da2e3ebdSchin 		memcpy(*tb, *fb, n);
1326da2e3ebdSchin 	*fb += n;
1327da2e3ebdSchin 	*fn -= n;
1328da2e3ebdSchin 	*tb += n;
1329da2e3ebdSchin 	*tn -= n;
1330da2e3ebdSchin 	return n;
1331da2e3ebdSchin }
1332da2e3ebdSchin 
1333*b30d1939SAndy Fiddaman #define OK		((size_t)-1)
1334*b30d1939SAndy Fiddaman 
1335da2e3ebdSchin /*
1336da2e3ebdSchin  * write *fb size *fn to op
1337da2e3ebdSchin  * fb,fn updated on return
1338da2e3ebdSchin  * total bytes written to op returned
1339da2e3ebdSchin  */
1340da2e3ebdSchin 
1341da2e3ebdSchin ssize_t
_ast_iconv_write(_ast_iconv_t cd,Sfio_t * op,char ** fb,size_t * fn,Iconv_disc_t * disc)1342*b30d1939SAndy Fiddaman _ast_iconv_write(_ast_iconv_t cd, Sfio_t* op, char** fb, size_t* fn, Iconv_disc_t* disc)
1343da2e3ebdSchin {
1344*b30d1939SAndy Fiddaman 	char*		fo = *fb;
1345da2e3ebdSchin 	char*		tb;
1346da2e3ebdSchin 	char*		ts;
1347*b30d1939SAndy Fiddaman 	size_t*		e;
1348da2e3ebdSchin 	size_t		tn;
1349da2e3ebdSchin 	size_t		r;
1350*b30d1939SAndy Fiddaman 	int		ok;
1351*b30d1939SAndy Fiddaman 	Iconv_disc_t	compat;
1352*b30d1939SAndy Fiddaman 
1353*b30d1939SAndy Fiddaman 	/*
1354*b30d1939SAndy Fiddaman 	 * the old api had optional size_t* instead of Iconv_disc_t*
1355*b30d1939SAndy Fiddaman 	 */
1356da2e3ebdSchin 
1357*b30d1939SAndy Fiddaman 	if (!disc || disc->version < 20110101L || disc->version >= 30000101L)
1358*b30d1939SAndy Fiddaman 	{
1359*b30d1939SAndy Fiddaman 		e = (size_t*)disc;
1360*b30d1939SAndy Fiddaman 		disc = &compat;
1361*b30d1939SAndy Fiddaman 		iconv_init(disc, 0);
1362*b30d1939SAndy Fiddaman 	}
1363*b30d1939SAndy Fiddaman 	else
1364*b30d1939SAndy Fiddaman 		e = 0;
1365da2e3ebdSchin 	r = 0;
1366da2e3ebdSchin 	tn = 0;
1367*b30d1939SAndy Fiddaman 	ok = 1;
1368*b30d1939SAndy Fiddaman 	while (ok && *fn > 0)
1369da2e3ebdSchin 	{
1370*b30d1939SAndy Fiddaman 		if (!(tb = (char*)sfreserve(op, -(tn + 1), SF_WRITE|SF_LOCKR)) || !(tn = sfvalue(op)))
1371*b30d1939SAndy Fiddaman 		{
1372*b30d1939SAndy Fiddaman 			if (!r)
1373*b30d1939SAndy Fiddaman 				r = -1;
1374*b30d1939SAndy Fiddaman 			break;
1375*b30d1939SAndy Fiddaman 		}
1376da2e3ebdSchin 		ts = tb;
1377da2e3ebdSchin #if DEBUG_TRACE
1378da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d iconv_write ts=%p tn=%d", __LINE__, ts, tn);
1379da2e3ebdSchin 		for (;;)
1380da2e3ebdSchin #else
1381*b30d1939SAndy Fiddaman 		while (*fn > 0 && _ast_iconv(cd, fb, fn, &ts, &tn) == (size_t)(-1))
1382da2e3ebdSchin #endif
1383da2e3ebdSchin 		{
1384da2e3ebdSchin #if DEBUG_TRACE
1385da2e3ebdSchin 			ssize_t	_r;
1386da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d iconv_write %d => %d `%-.*s'", __LINE__, *fn, tn, *fn, *fb);
1387da2e3ebdSchin 			_r = _ast_iconv(cd, fb, fn, &ts, &tn);
1388da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d iconv_write %d => %d [%d]", __LINE__, *fn, tn, _r);
1389*b30d1939SAndy Fiddaman 			if (_r != (size_t)(-1) || !fn)
1390da2e3ebdSchin 				break;
1391da2e3ebdSchin #endif
1392*b30d1939SAndy Fiddaman 			switch (errno)
1393*b30d1939SAndy Fiddaman 			{
1394*b30d1939SAndy Fiddaman 			case E2BIG:
1395da2e3ebdSchin 				break;
1396*b30d1939SAndy Fiddaman 			case EINVAL:
1397*b30d1939SAndy Fiddaman 				if (disc->errorf)
1398*b30d1939SAndy Fiddaman 					(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "incomplete multibyte sequence at offset %I*u", sizeof(fo), *fb - fo);
1399*b30d1939SAndy Fiddaman 				goto bad;
1400*b30d1939SAndy Fiddaman 			default:
1401*b30d1939SAndy Fiddaman 				if (disc->errorf)
1402*b30d1939SAndy Fiddaman 					(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "invalid multibyte sequence at offset %I*u", sizeof(fo), *fb - fo);
1403*b30d1939SAndy Fiddaman 			bad:
1404*b30d1939SAndy Fiddaman 				disc->errors++;
1405*b30d1939SAndy Fiddaman 				if (!(disc->flags & ICONV_FATAL))
1406*b30d1939SAndy Fiddaman 				{
1407*b30d1939SAndy Fiddaman 					if (!(disc->flags & ICONV_OMIT) && tn > 0)
1408*b30d1939SAndy Fiddaman 					{
1409*b30d1939SAndy Fiddaman 						*ts++ = (disc->fill >= 0) ? disc->fill : **fb;
1410*b30d1939SAndy Fiddaman 						tn--;
1411*b30d1939SAndy Fiddaman 					}
1412*b30d1939SAndy Fiddaman 					(*fb)++;
1413*b30d1939SAndy Fiddaman 					(*fn)--;
1414*b30d1939SAndy Fiddaman 					continue;
1415*b30d1939SAndy Fiddaman 				}
1416*b30d1939SAndy Fiddaman 				ok = 0;
1417da2e3ebdSchin 				break;
1418*b30d1939SAndy Fiddaman 			}
1419*b30d1939SAndy Fiddaman 			break;
1420da2e3ebdSchin 		}
1421da2e3ebdSchin #if DEBUG_TRACE
1422da2e3ebdSchin error(DEBUG_TRACE, "AHA#%d iconv_write %d", __LINE__, ts - tb);
1423da2e3ebdSchin #endif
1424da2e3ebdSchin 		sfwrite(op, tb, ts - tb);
1425da2e3ebdSchin 		r += ts - tb;
1426da2e3ebdSchin 	}
1427*b30d1939SAndy Fiddaman 	if (e)
1428*b30d1939SAndy Fiddaman 		*e = disc->errors;
1429da2e3ebdSchin 	return r;
1430da2e3ebdSchin }
1431da2e3ebdSchin 
1432da2e3ebdSchin /*
1433da2e3ebdSchin  * move n bytes from ip to op
1434da2e3ebdSchin  */
1435da2e3ebdSchin 
1436da2e3ebdSchin ssize_t
_ast_iconv_move(_ast_iconv_t cd,Sfio_t * ip,Sfio_t * op,size_t n,Iconv_disc_t * disc)1437*b30d1939SAndy Fiddaman _ast_iconv_move(_ast_iconv_t cd, Sfio_t* ip, Sfio_t* op, size_t n, Iconv_disc_t* disc)
1438da2e3ebdSchin {
1439da2e3ebdSchin 	char*		fb;
1440da2e3ebdSchin 	char*		fs;
1441da2e3ebdSchin 	char*		tb;
1442da2e3ebdSchin 	char*		ts;
1443*b30d1939SAndy Fiddaman 	size_t*		e;
1444*b30d1939SAndy Fiddaman 	size_t		fe;
1445da2e3ebdSchin 	size_t		fn;
1446da2e3ebdSchin 	size_t		fo;
1447*b30d1939SAndy Fiddaman 	size_t		ft;
1448da2e3ebdSchin 	size_t		tn;
1449da2e3ebdSchin 	size_t		i;
1450da2e3ebdSchin 	ssize_t		r = 0;
1451*b30d1939SAndy Fiddaman 	int		ok = 1;
1452da2e3ebdSchin 	int		locked;
1453*b30d1939SAndy Fiddaman 	Iconv_disc_t	compat;
1454*b30d1939SAndy Fiddaman 
1455*b30d1939SAndy Fiddaman 	/*
1456*b30d1939SAndy Fiddaman 	 * the old api had optional size_t* instead of Iconv_disc_t*
1457*b30d1939SAndy Fiddaman 	 */
1458da2e3ebdSchin 
1459*b30d1939SAndy Fiddaman 	if (!disc || disc->version < 20110101L || disc->version >= 30000101L)
1460*b30d1939SAndy Fiddaman 	{
1461*b30d1939SAndy Fiddaman 		e = (size_t*)disc;
1462*b30d1939SAndy Fiddaman 		disc = &compat;
1463*b30d1939SAndy Fiddaman 		iconv_init(disc, 0);
1464*b30d1939SAndy Fiddaman 	}
1465*b30d1939SAndy Fiddaman 	else
1466*b30d1939SAndy Fiddaman 		e = 0;
1467*b30d1939SAndy Fiddaman 	tb = 0;
1468*b30d1939SAndy Fiddaman 	fe = OK;
1469*b30d1939SAndy Fiddaman 	ft = 0;
1470da2e3ebdSchin 	fn = n;
1471*b30d1939SAndy Fiddaman 	do
1472da2e3ebdSchin 	{
1473*b30d1939SAndy Fiddaman 		if (n != SF_UNBOUND)
1474*b30d1939SAndy Fiddaman 			n = -((ssize_t)(n & (((size_t)(~0))>>1)));
1475*b30d1939SAndy Fiddaman 		if ((!(fb = (char*)sfreserve(ip, n, locked = SF_LOCKR)) || !(fo = sfvalue(ip))) &&
1476*b30d1939SAndy Fiddaman 		    (!(fb = (char*)sfreserve(ip, n, locked = 0)) || !(fo = sfvalue(ip))))
1477da2e3ebdSchin 			break;
1478da2e3ebdSchin 		fs = fb;
1479*b30d1939SAndy Fiddaman 		fn = fo;
1480da2e3ebdSchin 		if (!(tb = (char*)sfreserve(op, SF_UNBOUND, SF_WRITE|SF_LOCKR)))
1481da2e3ebdSchin 		{
1482*b30d1939SAndy Fiddaman 			if (!r)
1483*b30d1939SAndy Fiddaman 				r = -1;
1484*b30d1939SAndy Fiddaman 			break;
1485da2e3ebdSchin 		}
1486da2e3ebdSchin 		ts = tb;
1487da2e3ebdSchin 		tn = sfvalue(op);
1488*b30d1939SAndy Fiddaman 		while (fn > 0 && _ast_iconv(cd, &fs, &fn, &ts, &tn) == (size_t)(-1))
1489da2e3ebdSchin 		{
1490*b30d1939SAndy Fiddaman 			switch (errno)
1491da2e3ebdSchin 			{
1492*b30d1939SAndy Fiddaman 			case E2BIG:
1493*b30d1939SAndy Fiddaman 				break;
1494*b30d1939SAndy Fiddaman 			case EINVAL:
1495*b30d1939SAndy Fiddaman 				if (fe == ft + (fo - fn))
1496*b30d1939SAndy Fiddaman 				{
1497*b30d1939SAndy Fiddaman 					fe = OK;
1498*b30d1939SAndy Fiddaman 					if (disc->errorf)
1499*b30d1939SAndy Fiddaman 						(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "incomplete multibyte sequence at offset %I*u", sizeof(ft), ft + (fo - fn));
1500*b30d1939SAndy Fiddaman 					goto bad;
1501*b30d1939SAndy Fiddaman 				}
1502*b30d1939SAndy Fiddaman 				fe = ft;
1503*b30d1939SAndy Fiddaman 				break;
1504*b30d1939SAndy Fiddaman 			default:
1505*b30d1939SAndy Fiddaman 				if (disc->errorf)
1506*b30d1939SAndy Fiddaman 					(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "invalid multibyte sequence at offset %I*u", sizeof(ft), ft + (fo - fn));
1507*b30d1939SAndy Fiddaman 			bad:
1508*b30d1939SAndy Fiddaman 				disc->errors++;
1509*b30d1939SAndy Fiddaman 				if (!(disc->flags & ICONV_FATAL))
1510*b30d1939SAndy Fiddaman 				{
1511*b30d1939SAndy Fiddaman 					if (!(disc->flags & ICONV_OMIT) && tn > 0)
1512*b30d1939SAndy Fiddaman 					{
1513*b30d1939SAndy Fiddaman 						*ts++ = (disc->fill >= 0) ? disc->fill : *fs;
1514*b30d1939SAndy Fiddaman 						tn--;
1515*b30d1939SAndy Fiddaman 					}
1516*b30d1939SAndy Fiddaman 					fs++;
1517*b30d1939SAndy Fiddaman 					fn--;
1518*b30d1939SAndy Fiddaman 					continue;
1519*b30d1939SAndy Fiddaman 				}
1520*b30d1939SAndy Fiddaman 				ok = 0;
1521*b30d1939SAndy Fiddaman 				break;
1522da2e3ebdSchin 			}
1523*b30d1939SAndy Fiddaman 			break;
1524da2e3ebdSchin 		}
1525da2e3ebdSchin 		sfwrite(op, tb, ts - tb);
1526da2e3ebdSchin 		r += ts - tb;
1527*b30d1939SAndy Fiddaman 		ts = tb;
1528da2e3ebdSchin 		if (locked)
1529da2e3ebdSchin 			sfread(ip, fb, fs - fb);
1530da2e3ebdSchin 		else
1531da2e3ebdSchin 			for (i = fn; --i >= (fs - fb);)
1532da2e3ebdSchin 				sfungetc(ip, fb[i]);
1533da2e3ebdSchin 		if (n != SF_UNBOUND)
1534da2e3ebdSchin 		{
1535da2e3ebdSchin 			if (n <= (fs - fb))
1536da2e3ebdSchin 				break;
1537da2e3ebdSchin 			n -= fs - fb;
1538da2e3ebdSchin 		}
1539*b30d1939SAndy Fiddaman 		ft += (fs - fb);
1540da2e3ebdSchin 		if (fn == fo)
1541da2e3ebdSchin 			fn++;
1542*b30d1939SAndy Fiddaman 	} while (ok);
1543*b30d1939SAndy Fiddaman 	if (fb && locked)
1544*b30d1939SAndy Fiddaman 		sfread(ip, fb, 0);
1545*b30d1939SAndy Fiddaman 	if (tb)
1546*b30d1939SAndy Fiddaman 	{
1547*b30d1939SAndy Fiddaman 		sfwrite(op, tb, 0);
1548*b30d1939SAndy Fiddaman 		if (ts > tb)
1549*b30d1939SAndy Fiddaman 		{
1550*b30d1939SAndy Fiddaman 			sfwrite(op, tb, ts - tb);
1551*b30d1939SAndy Fiddaman 			r += ts - tb;
1552*b30d1939SAndy Fiddaman 		}
1553da2e3ebdSchin 	}
1554*b30d1939SAndy Fiddaman 	if (e)
1555*b30d1939SAndy Fiddaman 		*e = disc->errors;
1556da2e3ebdSchin 	return r;
1557da2e3ebdSchin }
1558da2e3ebdSchin 
1559da2e3ebdSchin /*
1560da2e3ebdSchin  * iconv_list_t iterator
1561da2e3ebdSchin  * call with arg 0 to start
1562da2e3ebdSchin  * prev return value is current arg
1563da2e3ebdSchin  */
1564da2e3ebdSchin 
1565da2e3ebdSchin _ast_iconv_list_t*
_ast_iconv_list(_ast_iconv_list_t * cp)1566da2e3ebdSchin _ast_iconv_list(_ast_iconv_list_t* cp)
1567da2e3ebdSchin {
1568da2e3ebdSchin #if _UWIN
1569da2e3ebdSchin 	struct dirent*	ent;
1570da2e3ebdSchin 
1571da2e3ebdSchin 	if (!cp)
1572da2e3ebdSchin 	{
1573da2e3ebdSchin 		if (!(cp = newof(0, _ast_iconv_list_t, 1, 0)))
1574da2e3ebdSchin 			return ccmaplist(NiL);
1575da2e3ebdSchin 		if (!(cp->data = opendir(_win_maps)))
1576da2e3ebdSchin 		{
1577da2e3ebdSchin 			free(cp);
1578da2e3ebdSchin 			return ccmaplist(NiL);
1579da2e3ebdSchin 		}
1580da2e3ebdSchin 	}
1581da2e3ebdSchin 	if (cp->data)
1582da2e3ebdSchin 	{
1583da2e3ebdSchin 		if (ent = readdir((DIR*)cp->data))
1584da2e3ebdSchin 		{
1585da2e3ebdSchin 			cp->name = cp->match = cp->desc = (const char*)ent->d_name;
1586da2e3ebdSchin 			return cp;
1587da2e3ebdSchin 		}
1588da2e3ebdSchin 		closedir((DIR*)cp->data);
1589da2e3ebdSchin 		free(cp);
1590da2e3ebdSchin 		return ccmaplist(NiL);
1591da2e3ebdSchin 	}
1592da2e3ebdSchin #else
1593da2e3ebdSchin 	if (!cp)
1594da2e3ebdSchin 		return ccmaplist(NiL);
1595da2e3ebdSchin #endif
1596da2e3ebdSchin 	if (cp->ccode >= 0)
1597da2e3ebdSchin 		return (cp = ccmaplist(cp)) ? cp : (_ast_iconv_list_t*)codes;
1598da2e3ebdSchin 	return (++cp)->name ? cp : (_ast_iconv_list_t*)0;
1599da2e3ebdSchin }
1600