14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin
244887Schin /*
254887Schin * Glenn Fowler
264887Schin * AT&T Research
274887Schin *
284887Schin * iconv intercept
294887Schin * minimally provides { utf*<=>bin ascii<=>ebcdic* }
304887Schin */
314887Schin
324887Schin #include <ast.h>
334887Schin #include <dirent.h>
344887Schin
354887Schin #define DEBUG_TRACE 0
364887Schin #define _ICONV_LIST_PRIVATE_
374887Schin
384887Schin #include <ccode.h>
394887Schin #include <ctype.h>
404887Schin #include <iconv.h>
414887Schin
424887Schin #include "lclib.h"
434887Schin
444887Schin #if !_lib_iconv_open
454887Schin
464887Schin #define _ast_iconv_t iconv_t
474887Schin #define _ast_iconv_f iconv_f
484887Schin #define _ast_iconv_list_t iconv_list_t
494887Schin #define _ast_iconv_open iconv_open
504887Schin #define _ast_iconv iconv
514887Schin #define _ast_iconv_close iconv_close
524887Schin #define _ast_iconv_list iconv_list
534887Schin #define _ast_iconv_move iconv_move
544887Schin #define _ast_iconv_name iconv_name
554887Schin #define _ast_iconv_write iconv_write
564887Schin
574887Schin #endif
584887Schin
594887Schin #ifndef E2BIG
604887Schin #define E2BIG ENOMEM
614887Schin #endif
624887Schin #ifndef EILSEQ
634887Schin #define EILSEQ EIO
644887Schin #endif
654887Schin
664887Schin #define RETURN(e,n,fn) \
674887Schin if (*fn && !e) e = E2BIG; \
684887Schin if (e) { errno = e; return (size_t)(-1); } \
694887Schin return n;
704887Schin
714887Schin typedef struct Map_s
724887Schin {
734887Schin char* name;
744887Schin const unsigned char* map;
754887Schin _ast_iconv_f fun;
764887Schin int index;
774887Schin } Map_t;
784887Schin
794887Schin typedef struct Conv_s
804887Schin {
814887Schin iconv_t cvt;
824887Schin char* buf;
834887Schin size_t size;
844887Schin Map_t from;
854887Schin Map_t to;
864887Schin } Conv_t;
874887Schin
884887Schin static Conv_t* freelist[4];
894887Schin static int freeindex;
904887Schin
914887Schin static const char name_local[] = "local";
924887Schin static const char name_native[] = "native";
934887Schin
944887Schin static const _ast_iconv_list_t codes[] =
954887Schin {
964887Schin {
974887Schin "utf",
984887Schin "un|unicode|utf",
994887Schin "multibyte 8-bit unicode",
1004887Schin "UTF-%s",
1014887Schin "8",
1024887Schin CC_UTF,
1034887Schin },
1044887Schin
1054887Schin {
1064887Schin "ume",
1074887Schin "um|ume|utf?(-)7",
1084887Schin "multibyte 7-bit unicode",
1094887Schin "UTF-7",
1104887Schin 0,
1114887Schin CC_UME,
1124887Schin },
1134887Schin
1144887Schin {
1154887Schin "euc",
1164887Schin "(big|euc)*",
1174887Schin "euc family",
1184887Schin 0,
1194887Schin 0,
1204887Schin CC_ICONV,
1214887Schin },
1224887Schin
1234887Schin {
1244887Schin "dos",
1254887Schin "dos?(-)?(855)",
1264887Schin "dos code page",
1274887Schin "DOS855",
1284887Schin 0,
1294887Schin CC_ICONV,
1304887Schin },
1314887Schin
1324887Schin {
1334887Schin "ucs",
1344887Schin "ucs?(-)?(2)?(be)|utf-16?(be)",
1354887Schin "unicode runes",
1364887Schin "UCS-%s",
1374887Schin "2",
1384887Schin CC_UCS,
1394887Schin },
1404887Schin
1414887Schin {
1424887Schin "ucs-le",
1434887Schin "ucs?(-)?(2)le|utf-16le",
1444887Schin "little endian unicode runes",
1454887Schin "UCS-%sLE",
1464887Schin "2",
1474887Schin CC_SCU,
1484887Schin },
1494887Schin
1504887Schin { 0 },
1514887Schin };
1524887Schin
1534887Schin #if _UWIN
1544887Schin
1554887Schin #include <ast_windows.h>
1564887Schin
1574887Schin #ifndef CP_UCS2
1584887Schin #define CP_UCS2 0x0000
1594887Schin #endif
1604887Schin
1614887Schin static char _win_maps[] = "/reg/local_machine/SOFTWARE/Classes/MIME/Database/Charset";
1624887Schin
1634887Schin /*
1644887Schin * return the codeset index given its name or alias
1654887Schin * the map is in the what? oh, the registry
1664887Schin */
1674887Schin
1684887Schin static int
_win_codeset(const char * name)1694887Schin _win_codeset(const char* name)
1704887Schin {
1714887Schin register char* s;
1724887Schin char* e;
1734887Schin int n;
1744887Schin Sfio_t* sp;
1754887Schin char aka[128];
1764887Schin char tmp[128];
1774887Schin
1784887Schin #if DEBUG_TRACE
1794887Schin error(DEBUG_TRACE, "AHA#%d _win_codeset name=%s", __LINE__, name);
1804887Schin #endif
1814887Schin if (name == name_native)
1824887Schin return CP_ACP;
1834887Schin if (!strcasecmp(name, "utf") || !strcasecmp(name, "utf8") || !strcasecmp(name, "utf-8"))
1844887Schin return CP_UTF8;
1854887Schin if (!strcasecmp(name, "ucs") || !strcasecmp(name, "ucs2") || !strcasecmp(name, "ucs-2"))
1864887Schin return CP_UCS2;
1874887Schin if (name[0] == '0' && name[1] == 'x' && (n = strtol(name, &e, 0)) > 0 && !*e)
1884887Schin return n;
1894887Schin for (;;)
1904887Schin {
1914887Schin sfsprintf(tmp, sizeof(tmp), "%s/%s", _win_maps, name);
1924887Schin if (!(sp = sfopen(0, tmp, "r")))
1934887Schin {
1944887Schin s = (char*)name;
1954887Schin if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'p' || s[1] == 'P'))
1964887Schin s += 2;
1974887Schin if (!isdigit(s[0]))
1984887Schin break;
1994887Schin sfsprintf(tmp, sizeof(tmp), "%s/windows-%s", _win_maps, s);
2004887Schin if (!(sp = sfopen(0, tmp, "r")))
2014887Schin break;
2024887Schin }
2034887Schin for (;;)
2044887Schin {
2054887Schin if (!(s = sfgetr(sp, '\n', 0)))
2064887Schin {
2074887Schin sfclose(sp);
2084887Schin return -1;
2094887Schin }
2104887Schin if (!strncasecmp(s, "AliasForCharSet=", 16))
2114887Schin {
2124887Schin n = sfvalue(sp) - 17;
2134887Schin s += 16;
2144887Schin if (n >= sizeof(aka))
2154887Schin n = sizeof(aka) - 1;
2164887Schin memcpy(aka, s, n);
2174887Schin aka[n] = 0;
2184887Schin sfclose(sp);
2194887Schin name = (const char*)aka;
2204887Schin break;
2214887Schin }
2224887Schin if (!strncasecmp(s, "CodePage=", 9))
2234887Schin {
2244887Schin s += 9;
2254887Schin n = strtol(s, 0, 0);
2264887Schin sfclose(sp);
2274887Schin return n;
2284887Schin }
2294887Schin }
2304887Schin }
2314887Schin return -1;
2324887Schin }
2334887Schin
2344887Schin /*
2354887Schin * get and check the codeset indices
2364887Schin */
2374887Schin
2384887Schin static _ast_iconv_t
_win_iconv_open(register Conv_t * cc,const char * t,const char * f)2394887Schin _win_iconv_open(register Conv_t* cc, const char* t, const char* f)
2404887Schin {
2414887Schin #if DEBUG_TRACE
2424887Schin error(DEBUG_TRACE, "AHA#%d _win_iconv_open f=%s t=%s\n", __LINE__, f, t);
2434887Schin #endif
2444887Schin if ((cc->from.index = _win_codeset(f)) < 0)
2454887Schin return (_ast_iconv_t)(-1);
2464887Schin if ((cc->to.index = _win_codeset(t)) < 0)
2474887Schin return (_ast_iconv_t)(-1);
2484887Schin #if DEBUG_TRACE
2494887Schin error(DEBUG_TRACE, "AHA#%d _win_iconv_open f=0x%04x t=0x%04x\n", __LINE__, cc->from.index, cc->to.index);
2504887Schin #endif
2514887Schin return (_ast_iconv_t)cc;
2524887Schin }
2534887Schin
2544887Schin /*
2554887Schin * even though the indices already check out
2564887Schin * they could still be rejected
2574887Schin */
2584887Schin
2594887Schin static size_t
_win_iconv(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)2604887Schin _win_iconv(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
2614887Schin {
2624887Schin Conv_t* cc = (Conv_t*)cd;
2634887Schin size_t un;
2644887Schin size_t tz;
2654887Schin size_t fz;
2664887Schin size_t bz;
2674887Schin size_t pz;
2684887Schin size_t oz;
2694887Schin LPWSTR ub;
2704887Schin
2714887Schin #if DEBUG_TRACE
2724887Schin error(DEBUG_TRACE, "AHA#%d _win_iconv from=0x%04x to=0x%04x\n", __LINE__, cc->from.index, cc->to.index);
2734887Schin #endif
2744887Schin if (cc->from.index == cc->to.index)
2754887Schin {
2764887Schin /*
2774887Schin * easy
2784887Schin */
2794887Schin
2804887Schin fz = tz = (*fn < *tn) ? *fn : *tn;
2814887Schin memcpy(*tb, *fb, fz);
2824887Schin }
2834887Schin else
2844887Schin {
2854887Schin ub = 0;
2864887Schin un = *fn;
2874887Schin
2884887Schin /*
2894887Schin * from => ucs-2
2904887Schin */
2914887Schin
2924887Schin if (cc->to.index == CP_UCS2)
2934887Schin {
2944887Schin if ((tz = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)*fn, (LPWSTR)*tb, *tn)) && tz <= *tn)
2954887Schin {
2964887Schin fz = *fn;
2974887Schin tz *= sizeof(WCHAR);
2984887Schin }
2994887Schin else
3004887Schin {
3014887Schin /*
3024887Schin * target too small
3034887Schin * binary search on input size to make it fit
3044887Schin */
3054887Schin
3064887Schin oz = 0;
3074887Schin pz = *fn / 2;
3084887Schin fz = *fn - pz;
3094887Schin for (;;)
3104887Schin {
3114887Schin while (!(tz = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)fz, (LPWSTR)*tb, 0)))
3124887Schin if (++fz >= *fn)
3134887Schin goto nope;
3144887Schin tz *= sizeof(WCHAR);
3154887Schin if (tz == *tn)
3164887Schin break;
3174887Schin if (!(pz /= 2))
3184887Schin {
3194887Schin if (!(fz = oz))
3204887Schin goto nope;
3214887Schin break;
3224887Schin }
3234887Schin if (tz > *tn)
3244887Schin fz -= pz;
3254887Schin else
3264887Schin {
3274887Schin oz = fz;
3284887Schin fz += pz;
3294887Schin }
3304887Schin }
3314887Schin }
3324887Schin }
3334887Schin else
3344887Schin {
3354887Schin if (cc->from.index == CP_UCS2)
3364887Schin {
3374887Schin un = *fn / sizeof(WCHAR);
3384887Schin ub = (LPWSTR)*fb;
3394887Schin }
3404887Schin else if (!(un = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)*fn, (LPWSTR)*tb, 0)))
3414887Schin goto nope;
3424887Schin else if (!(ub = (LPWSTR)malloc(un * sizeof(WCHAR))))
3434887Schin goto nope;
3444887Schin else if (!(un = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)*fn, (LPWSTR)ub, un)))
3454887Schin goto nope;
3464887Schin
3474887Schin /*
3484887Schin * ucs-2 => to
3494887Schin */
3504887Schin
3514887Schin if (tz = WideCharToMultiByte(cc->to.index, 0, (LPCWSTR)ub, un, *tb, *tn, 0, 0))
3524887Schin fz = *fn;
3534887Schin else
3544887Schin {
3554887Schin /*
3564887Schin * target too small
3574887Schin * binary search on input size to make it fit
3584887Schin */
3594887Schin
3604887Schin oz = 0;
3614887Schin pz = *fn / 2;
3624887Schin bz = *fn - pz;
3634887Schin for (;;)
3644887Schin {
3654887Schin while (!(fz = MultiByteToWideChar(cc->from.index, 0, (LPCSTR)*fb, (int)bz, (LPWSTR)ub, un)))
3664887Schin if (++bz > *fn)
3674887Schin goto nope;
3684887Schin if (!(tz = WideCharToMultiByte(cc->to.index, 0, (LPCWSTR)ub, fz, *tb, 0, 0, 0)))
3694887Schin goto nope;
3704887Schin if (tz == *tn)
3714887Schin break;
3724887Schin if (!(pz /= 2))
3734887Schin {
3744887Schin if (!(fz = oz))
3754887Schin goto nope;
3764887Schin break;
3774887Schin }
3784887Schin if (tz > *tn)
3794887Schin bz -= pz;
3804887Schin else
3814887Schin {
3824887Schin oz = bz;
3834887Schin bz += pz;
3844887Schin }
3854887Schin }
3864887Schin if (!(tz = WideCharToMultiByte(cc->to.index, 0, (LPCWSTR)ub, fz, *tb, tz, 0, 0)))
3874887Schin goto nope;
3884887Schin #if DEBUG_TRACE
3894887Schin 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);
3904887Schin #endif
3914887Schin #if 0
3924887Schin fz *= sizeof(WCHAR);
3934887Schin #endif
3944887Schin }
3954887Schin if (ub != (LPWSTR)*fb)
3964887Schin free(ub);
3974887Schin }
3984887Schin }
3994887Schin *fb += fz;
4004887Schin *fn -= fz;
4014887Schin *tb += tz;
4024887Schin *tn -= tz;
4034887Schin return fz;
4044887Schin nope:
4054887Schin if (ub && ub != (LPWSTR)*fb)
4064887Schin free(ub);
4074887Schin errno = EINVAL;
4084887Schin return (size_t)(-1);
4094887Schin }
4104887Schin
4114887Schin #endif
4124887Schin
4134887Schin /*
4144887Schin * return canonical character code set name for m
4154887Schin * if b!=0 then canonical name placed in b of size n
4164887Schin * <ccode.h> index returned
4174887Schin */
4184887Schin
4194887Schin int
_ast_iconv_name(register const char * m,register char * b,size_t n)4204887Schin _ast_iconv_name(register const char* m, register char* b, size_t n)
4214887Schin {
4224887Schin register const _ast_iconv_list_t* cp;
4234887Schin const _ast_iconv_list_t* bp;
4244887Schin register int c;
4254887Schin register char* e;
4264887Schin int sub[2];
4274887Schin char buf[16];
4284887Schin #if DEBUG_TRACE
4294887Schin char* o;
4304887Schin #endif
4314887Schin
4324887Schin if (!b)
4334887Schin {
4344887Schin b = buf;
4354887Schin n = sizeof(buf);
4364887Schin }
4374887Schin #if DEBUG_TRACE
4384887Schin o = b;
4394887Schin #endif
4404887Schin e = b + n - 1;
4414887Schin bp = 0;
4424887Schin n = 0;
4434887Schin cp = ccmaplist(NiL);
4444887Schin #if DEBUG_TRACE
4454887Schin 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);
4464887Schin #endif
4474887Schin for (;;)
4484887Schin {
4494887Schin #if DEBUG_TRACE
4504887Schin 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);
4514887Schin #endif
4524887Schin if (strgrpmatch(m, cp->match, sub, elementsof(sub) / 2, STR_MAXIMAL|STR_LEFT|STR_ICASE))
4534887Schin {
4544887Schin if (!(c = m[sub[1]]))
4554887Schin {
4564887Schin bp = cp;
4574887Schin break;
4584887Schin }
4594887Schin if (sub[1] > n && !isalpha(c))
4604887Schin {
4614887Schin bp = cp;
4624887Schin n = sub[1];
4634887Schin }
4644887Schin }
4654887Schin if (cp->ccode < 0)
4664887Schin {
4674887Schin if (!(++cp)->name)
4684887Schin break;
4694887Schin }
4704887Schin else if (!(cp = (const _ast_iconv_list_t*)ccmaplist((_ast_iconv_list_t*)cp)))
4714887Schin cp = codes;
4724887Schin }
4734887Schin if (cp = bp)
4744887Schin {
4754887Schin if (cp->canon)
4764887Schin {
4774887Schin if (cp->index)
4784887Schin {
4794887Schin for (m += sub[1]; *m && !isalnum(*m); m++);
4804887Schin if (!isdigit(*m))
4814887Schin m = cp->index;
4824887Schin }
4834887Schin else
4844887Schin m = "1";
4854887Schin b += sfsprintf(b, e - b, cp->canon, m);
4864887Schin }
4874887Schin else if (cp->ccode == CC_NATIVE)
4884887Schin {
4894887Schin if ((locales[AST_LC_CTYPE]->flags & LC_default) || !locales[AST_LC_CTYPE]->charset || !(m = locales[AST_LC_CTYPE]->charset->code) || streq(m, "iso8859-1"))
4904887Schin switch (CC_NATIVE)
4914887Schin {
4924887Schin case CC_EBCDIC:
4934887Schin m = (const char*)"EBCDIC";
4944887Schin break;
4954887Schin case CC_EBCDIC_I:
4964887Schin m = (const char*)"EBCDIC-I";
4974887Schin break;
4984887Schin case CC_EBCDIC_O:
4994887Schin m = (const char*)"EBCDIC-O";
5004887Schin break;
5014887Schin default:
5024887Schin m = (const char*)"ISO-8859-1";
5034887Schin break;
5044887Schin }
5054887Schin b += sfsprintf(b, e - b, "%s", m);
5064887Schin }
5074887Schin *b = 0;
5084887Schin #if DEBUG_TRACE
5094887Schin 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);
5104887Schin #endif
5114887Schin return cp->ccode;
5124887Schin }
5134887Schin while (b < e && (c = *m++))
5144887Schin {
5154887Schin if (islower(c))
5164887Schin c = toupper(c);
5174887Schin *b++ = c;
5184887Schin }
5194887Schin *b = 0;
5204887Schin #if DEBUG_TRACE
5214887Schin 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);
5224887Schin #endif
5234887Schin return CC_ICONV;
5244887Schin }
5254887Schin
5264887Schin /*
5274887Schin * convert utf-8 to bin
5284887Schin */
5294887Schin
5304887Schin static size_t
utf2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)5314887Schin utf2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
5324887Schin {
5334887Schin register unsigned char* f;
5344887Schin register unsigned char* fe;
5354887Schin register unsigned char* t;
5364887Schin register unsigned char* te;
5374887Schin register unsigned char* p;
5384887Schin register int c;
5394887Schin register int w;
5404887Schin size_t n;
5414887Schin int e;
5424887Schin
5434887Schin e = 0;
5444887Schin f = (unsigned char*)(*fb);
5454887Schin fe = f + (*fn);
5464887Schin t = (unsigned char*)(*tb);
5474887Schin te = t + (*tn);
5484887Schin while (t < te && f < fe)
5494887Schin {
5504887Schin p = f;
5514887Schin c = *f++;
5524887Schin if (c & 0x80)
5534887Schin {
5544887Schin if (!(c & 0x40))
5554887Schin {
5564887Schin f = p;
5574887Schin e = EILSEQ;
5584887Schin break;
5594887Schin }
5604887Schin if (c & 0x20)
5614887Schin {
5624887Schin w = (c & 0x0F) << 12;
5634887Schin if (f >= fe)
5644887Schin {
5654887Schin f = p;
5664887Schin e = EINVAL;
5674887Schin break;
5684887Schin }
5694887Schin c = *f++;
5704887Schin if (c & 0x40)
5714887Schin {
5724887Schin f = p;
5734887Schin e = EILSEQ;
5744887Schin break;
5754887Schin }
5764887Schin w |= (c & 0x3F) << 6;
5774887Schin }
5784887Schin else
5794887Schin w = (c & 0x1F) << 6;
5804887Schin if (f >= fe)
5814887Schin {
5824887Schin f = p;
5834887Schin e = EINVAL;
5844887Schin break;
5854887Schin }
5864887Schin c = *f++;
5874887Schin w |= (c & 0x3F);
5884887Schin }
5894887Schin else
5904887Schin w = c;
5914887Schin *t++ = w;
5924887Schin }
5934887Schin *fn -= (char*)f - (*fb);
5944887Schin *fb = (char*)f;
5954887Schin *tn -= (n = (char*)t - (*tb));
5964887Schin *tb = (char*)t;
5974887Schin RETURN(e, n, fn);
5984887Schin }
5994887Schin
6004887Schin /*
6014887Schin * convert bin to utf-8
6024887Schin */
6034887Schin
6044887Schin static size_t
bin2utf(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)6054887Schin bin2utf(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
6064887Schin {
6074887Schin register unsigned char* f;
6084887Schin register unsigned char* fe;
6094887Schin register unsigned char* t;
6104887Schin register unsigned char* te;
6114887Schin register int c;
6124887Schin wchar_t w;
6134887Schin size_t n;
6144887Schin int e;
6154887Schin
6164887Schin e = 0;
6174887Schin f = (unsigned char*)(*fb);
6184887Schin fe = f + (*fn);
6194887Schin t = (unsigned char*)(*tb);
6204887Schin te = t + (*tn);
6214887Schin while (f < fe && t < te)
6224887Schin {
6234887Schin if (!mbwide())
6244887Schin {
6254887Schin c = 1;
6264887Schin w = *f;
6274887Schin }
6284887Schin else if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
6294887Schin {
6304887Schin e = EINVAL;
6314887Schin break;
6324887Schin }
6334887Schin else if (!c)
6344887Schin c = 1;
6354887Schin if (!(w & ~0x7F))
6364887Schin *t++ = w;
6374887Schin else
6384887Schin {
6394887Schin if (!(w & ~0x7FF))
6404887Schin {
6414887Schin if (t >= (te - 2))
6424887Schin {
6434887Schin e = E2BIG;
6444887Schin break;
6454887Schin }
6464887Schin *t++ = 0xC0 + (w >> 6);
6474887Schin }
6484887Schin else if (!(w & ~0xffff))
6494887Schin {
6504887Schin if (t >= (te - 3))
6514887Schin {
6524887Schin e = E2BIG;
6534887Schin break;
6544887Schin }
6554887Schin *t++ = 0xE0 + (w >> 12);
6564887Schin *t++ = 0x80 + ((w >> 6 ) & 0x3F);
6574887Schin }
6584887Schin else
6594887Schin {
6604887Schin e = EILSEQ;
6614887Schin break;
6624887Schin }
6634887Schin *t++ = 0x80 + (w & 0x3F);
6644887Schin }
6654887Schin f += c;
6664887Schin }
6674887Schin *fn -= (n = (char*)f - (*fb));
6684887Schin *fb = (char*)f;
6694887Schin *tn -= (char*)t - (*tb);
6704887Schin *tb = (char*)t;
6714887Schin RETURN(e, n, fn);
6724887Schin }
6734887Schin
6744887Schin static const unsigned char ume_D[] =
6754887Schin "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?!\"#$%&*;<=>@[]^_`{|} \t\n";
6764887Schin
6774887Schin static const unsigned char ume_M[] =
6784887Schin "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6794887Schin
6804887Schin static unsigned char ume_d[UCHAR_MAX+1];
6814887Schin
6824887Schin static unsigned char ume_m[UCHAR_MAX+1];
6834887Schin
6844887Schin #define NOE 0xFF
6854887Schin #define UMEINIT() (ume_d[ume_D[0]]?0:umeinit())
6864887Schin
6874887Schin /*
6884887Schin * initialize the ume tables
6894887Schin */
6904887Schin
6914887Schin static int
umeinit(void)6924887Schin umeinit(void)
6934887Schin {
6944887Schin register const unsigned char* s;
6954887Schin register int i;
6964887Schin register int c;
6974887Schin
6984887Schin if (!ume_d[ume_D[0]])
6994887Schin {
7004887Schin s = ume_D;
7014887Schin while (c = *s++)
7024887Schin ume_d[c] = 1;
7034887Schin memset(ume_m, NOE, sizeof(ume_m));
7044887Schin for (i = 0; c = ume_M[i]; i++)
7054887Schin ume_m[c] = i;
7064887Schin }
7074887Schin return 0;
7084887Schin }
7094887Schin
7104887Schin /*
7114887Schin * convert utf-7 to bin
7124887Schin */
7134887Schin
7144887Schin static size_t
ume2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)7154887Schin ume2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
7164887Schin {
7174887Schin register unsigned char* f;
7184887Schin register unsigned char* fe;
7194887Schin register unsigned char* t;
7204887Schin register unsigned char* te;
7214887Schin register unsigned char* p;
7224887Schin register int s;
7234887Schin register int c;
7244887Schin register int w;
7254887Schin size_t n;
7264887Schin int e;
7274887Schin
7284887Schin e = 0;
7294887Schin UMEINIT();
7304887Schin f = (unsigned char*)(*fb);
7314887Schin fe = f + (*fn);
7324887Schin t = (unsigned char*)(*tb);
7334887Schin te = t + (*tn);
7344887Schin s = 0;
7354887Schin while (f < fe && t < te)
7364887Schin {
7374887Schin p = f;
7384887Schin c = *f++;
7394887Schin if (s)
7404887Schin {
7414887Schin if (c == '-' && s > 1)
7424887Schin s = 0;
7434887Schin else if ((w = ume_m[c]) == NOE)
7444887Schin {
7454887Schin s = 0;
7464887Schin *t++ = c;
7474887Schin }
7484887Schin else if (f >= (fe - 2))
7494887Schin {
7504887Schin f = p;
7514887Schin e = EINVAL;
7524887Schin break;
7534887Schin }
7544887Schin else
7554887Schin {
7564887Schin s = 2;
7574887Schin w = (w << 6) | ume_m[*f++];
7584887Schin w = (w << 6) | ume_m[*f++];
7594887Schin if (!(w & ~0xFF))
7604887Schin *t++ = w;
7614887Schin else if (t >= (te - 1))
7624887Schin {
7634887Schin f = p;
7644887Schin e = E2BIG;
7654887Schin break;
7664887Schin }
7674887Schin else
7684887Schin {
7694887Schin *t++ = (w >> 8) & 0xFF;
7704887Schin *t++ = w & 0xFF;
7714887Schin }
7724887Schin }
7734887Schin }
7744887Schin else if (c == '+')
7754887Schin s = 1;
7764887Schin else
7774887Schin *t++ = c;
7784887Schin }
7794887Schin *fn -= (char*)f - (*fb);
7804887Schin *fb = (char*)f;
7814887Schin *tn -= (n = (char*)t - (*tb));
7824887Schin *tb = (char*)t;
7834887Schin RETURN(e, n, fn);
7844887Schin }
7854887Schin
7864887Schin /*
7874887Schin * convert bin to utf-7
7884887Schin */
7894887Schin
7904887Schin static size_t
bin2ume(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)7914887Schin bin2ume(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
7924887Schin {
7934887Schin register unsigned char* f;
7944887Schin register unsigned char* fe;
7954887Schin register unsigned char* t;
7964887Schin register unsigned char* te;
7974887Schin register int c;
7984887Schin register int s;
7994887Schin wchar_t w;
8004887Schin size_t n;
8014887Schin int e;
8024887Schin
8034887Schin e = 0;
8044887Schin UMEINIT();
8054887Schin f = (unsigned char*)(*fb);
8064887Schin fe = f + (*fn);
8074887Schin t = (unsigned char*)(*tb);
8084887Schin te = t + (*tn);
8094887Schin s = 0;
8104887Schin while (f < fe && t < (te - s))
8114887Schin {
8124887Schin if (!mbwide())
8134887Schin {
8144887Schin c = 1;
8154887Schin w = *f;
8164887Schin }
8174887Schin else if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
8184887Schin {
8194887Schin e = EINVAL;
8204887Schin break;
8214887Schin }
8224887Schin else if (!c)
8234887Schin c = 1;
8244887Schin if (!(w & ~0x7F) && ume_d[w])
8254887Schin {
8264887Schin if (s)
8274887Schin {
8284887Schin s = 0;
8294887Schin *t++ = '-';
8304887Schin }
8314887Schin *t++ = w;
8324887Schin }
8334887Schin else if (t >= (te - (4 + s)))
8344887Schin {
8354887Schin e = E2BIG;
8364887Schin break;
8374887Schin }
8384887Schin else
8394887Schin {
8404887Schin if (!s)
8414887Schin {
8424887Schin s = 1;
8434887Schin *t++ = '+';
8444887Schin }
8454887Schin *t++ = ume_M[(w >> 12) & 0x3F];
8464887Schin *t++ = ume_M[(w >> 6) & 0x3F];
8474887Schin *t++ = ume_M[w & 0x3F];
8484887Schin }
8494887Schin f += c;
8504887Schin }
8514887Schin if (s)
8524887Schin *t++ = '-';
8534887Schin *fn -= (n = (char*)f - (*fb));
8544887Schin *fb = (char*)f;
8554887Schin *tn -= (char*)t - (*tb);
8564887Schin *tb = (char*)t;
8574887Schin RETURN(e, n, fn);
8584887Schin }
8594887Schin
8604887Schin /*
8614887Schin * convert ucs-2 to bin with no byte swap
8624887Schin */
8634887Schin
8644887Schin static size_t
ucs2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)8654887Schin ucs2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
8664887Schin {
8674887Schin register unsigned char* f;
8684887Schin register unsigned char* fe;
8694887Schin register unsigned char* t;
8704887Schin register unsigned char* te;
8714887Schin register int w;
8724887Schin size_t n;
8734887Schin int e;
8744887Schin
8754887Schin e = 0;
8764887Schin f = (unsigned char*)(*fb);
8774887Schin fe = f + (*fn);
8784887Schin t = (unsigned char*)(*tb);
8794887Schin te = t + (*tn);
8804887Schin while (f < (fe - 1) && t < te)
8814887Schin {
8824887Schin w = *f++;
8834887Schin w = (w << 8) | *f++;
8844887Schin if (!(w & ~0xFF))
8854887Schin *t++ = w;
8864887Schin else if (t >= (te - 1))
8874887Schin {
8884887Schin f -= 2;
8894887Schin e = E2BIG;
8904887Schin break;
8914887Schin }
8924887Schin else
8934887Schin {
8944887Schin *t++ = (w >> 8) & 0xFF;
8954887Schin *t++ = w & 0xFF;
8964887Schin }
8974887Schin }
8984887Schin *fn -= (char*)f - (*fb);
8994887Schin *fb = (char*)f;
9004887Schin *tn -= (n = (char*)t - (*tb));
9014887Schin *tb = (char*)t;
9024887Schin RETURN(e, n, fn);
9034887Schin }
9044887Schin
9054887Schin /*
9064887Schin * convert bin to ucs-2 with no byte swap
9074887Schin */
9084887Schin
9094887Schin static size_t
bin2ucs(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)9104887Schin bin2ucs(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
9114887Schin {
9124887Schin register unsigned char* f;
9134887Schin register unsigned char* fe;
9144887Schin register unsigned char* t;
9154887Schin register unsigned char* te;
9164887Schin register int c;
9174887Schin wchar_t w;
9184887Schin size_t n;
9194887Schin int e;
9204887Schin
9214887Schin e = 0;
9224887Schin f = (unsigned char*)(*fb);
9234887Schin fe = f + (*fn);
9244887Schin t = (unsigned char*)(*tb);
9254887Schin te = t + (*tn);
9264887Schin while (f < fe && t < (te - 1))
9274887Schin {
9284887Schin if (!mbwide())
9294887Schin {
9304887Schin c = 1;
9314887Schin w = *f;
9324887Schin }
9334887Schin if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
9344887Schin {
9354887Schin e = EINVAL;
9364887Schin break;
9374887Schin }
9384887Schin else if (!c)
9394887Schin c = 1;
9404887Schin *t++ = (w >> 8) & 0xFF;
9414887Schin *t++ = w & 0xFF;
9424887Schin f += c;
9434887Schin }
9444887Schin *fn -= (n = (char*)f - (*fb));
9454887Schin *fb = (char*)f;
9464887Schin *tn -= (char*)t - (*tb);
9474887Schin *tb = (char*)t;
9484887Schin RETURN(e, n, fn);
9494887Schin }
9504887Schin
9514887Schin /*
9524887Schin * convert ucs-2 to bin with byte swap
9534887Schin */
9544887Schin
9554887Schin static size_t
scu2bin(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)9564887Schin scu2bin(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
9574887Schin {
9584887Schin register unsigned char* f;
9594887Schin register unsigned char* fe;
9604887Schin register unsigned char* t;
9614887Schin register unsigned char* te;
9624887Schin register int w;
9634887Schin size_t n;
9644887Schin int e;
9654887Schin
9664887Schin e = 0;
9674887Schin f = (unsigned char*)(*fb);
9684887Schin fe = f + (*fn);
9694887Schin t = (unsigned char*)(*tb);
9704887Schin te = t + (*tn);
9714887Schin while (f < (fe - 1) && t < te)
9724887Schin {
9734887Schin w = *f++;
9744887Schin w = w | (*f++ << 8);
9754887Schin if (!(w & ~0xFF))
9764887Schin *t++ = w;
9774887Schin else if (t >= (te - 1))
9784887Schin {
9794887Schin f -= 2;
9804887Schin e = E2BIG;
9814887Schin break;
9824887Schin }
9834887Schin else
9844887Schin {
9854887Schin *t++ = (w >> 8) & 0xFF;
9864887Schin *t++ = w & 0xFF;
9874887Schin }
9884887Schin }
9894887Schin *fn -= (char*)f - (*fb);
9904887Schin *fb = (char*)f;
9914887Schin *tn -= (n = (char*)t - (*tb));
9924887Schin *tb = (char*)t;
9934887Schin RETURN(e, n, fn);
9944887Schin }
9954887Schin
9964887Schin /*
9974887Schin * convert bin to ucs-2 with byte swap
9984887Schin */
9994887Schin
10004887Schin static size_t
bin2scu(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)10014887Schin bin2scu(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
10024887Schin {
10034887Schin register unsigned char* f;
10044887Schin register unsigned char* fe;
10054887Schin register unsigned char* t;
10064887Schin register unsigned char* te;
10074887Schin register int c;
10084887Schin wchar_t w;
10094887Schin size_t n;
10104887Schin int e;
10114887Schin
10124887Schin e = 0;
10134887Schin f = (unsigned char*)(*fb);
10144887Schin fe = f + (*fn);
10154887Schin t = (unsigned char*)(*tb);
10164887Schin te = t + (*tn);
10174887Schin while (f < fe && t < (te - 1))
10184887Schin {
10194887Schin if (!mbwide())
10204887Schin {
10214887Schin c = 1;
10224887Schin w = *f;
10234887Schin }
10244887Schin else if ((c = (*_ast_info.mb_towc)(&w, (char*)f, fe - f)) < 0)
10254887Schin {
10264887Schin e = EINVAL;
10274887Schin break;
10284887Schin }
10294887Schin else if (!c)
10304887Schin c = 1;
10314887Schin *t++ = w & 0xFF;
10324887Schin *t++ = (w >> 8) & 0xFF;
10334887Schin f += c;
10344887Schin }
10354887Schin *fn -= (n = (char*)f - (*fb));
10364887Schin *fb = (char*)f;
10374887Schin *tn -= (char*)t - (*tb);
10384887Schin *tb = (char*)t;
10394887Schin RETURN(e, n, fn);
10404887Schin }
10414887Schin
10424887Schin /*
10434887Schin * open a character code conversion map from f to t
10444887Schin */
10454887Schin
10464887Schin _ast_iconv_t
_ast_iconv_open(const char * t,const char * f)10474887Schin _ast_iconv_open(const char* t, const char* f)
10484887Schin {
10494887Schin register Conv_t* cc;
10504887Schin int fc;
10514887Schin int tc;
10524887Schin int i;
10534887Schin
10544887Schin char fr[64];
10554887Schin char to[64];
10564887Schin
10574887Schin #if DEBUG_TRACE
10584887Schin error(DEBUG_TRACE, "AHA#%d _ast_iconv_open f=%s t=%s\n", __LINE__, f, t);
10594887Schin #endif
10604887Schin if (!t || !*t || *t == '-' && !*(t + 1) || !strcasecmp(t, name_local) || !strcasecmp(t, name_native))
10614887Schin t = name_native;
10624887Schin if (!f || !*f || *f == '-' && !*(f + 1) || !strcasecmp(t, name_local) || !strcasecmp(f, name_native))
10634887Schin f = name_native;
10644887Schin
10654887Schin /*
10664887Schin * the ast identify is always (iconv_t)(0)
10674887Schin */
10684887Schin
10694887Schin if (t == f)
10704887Schin return (iconv_t)(0);
10714887Schin fc = _ast_iconv_name(f, fr, sizeof(fr));
10724887Schin tc = _ast_iconv_name(t, to, sizeof(to));
10734887Schin #if DEBUG_TRACE
10744887Schin error(DEBUG_TRACE, "AHA#%d _ast_iconv_open f=%s:%s:%d t=%s:%s:%d\n", __LINE__, f, fr, fc, t, to, tc);
10754887Schin #endif
10764887Schin if (fc != CC_ICONV && fc == tc || streq(fr, to))
10774887Schin return (iconv_t)(0);
10784887Schin
10794887Schin /*
10804887Schin * first check the free list
10814887Schin */
10824887Schin
10834887Schin for (i = 0; i < elementsof(freelist); i++)
10844887Schin if ((cc = freelist[i]) && streq(to, cc->to.name) && streq(fr, cc->from.name))
10854887Schin {
10864887Schin freelist[i] = 0;
10874887Schin #if _lib_iconv_open
10884887Schin /*
10894887Schin * reset the shift state if any
10904887Schin */
10914887Schin
10924887Schin if (cc->cvt != (iconv_t)(-1))
10934887Schin iconv(cc->cvt, NiL, NiL, NiL, NiL);
10944887Schin #endif
10954887Schin return cc;
10964887Schin }
10974887Schin
10984887Schin /*
10994887Schin * allocate a new one
11004887Schin */
11014887Schin
11024887Schin if (!(cc = newof(0, Conv_t, 1, strlen(to) + strlen(fr) + 2)))
11034887Schin return (iconv_t)(-1);
11044887Schin cc->to.name = (char*)(cc + 1);
11054887Schin cc->from.name = strcopy(cc->to.name, to) + 1;
11064887Schin strcpy(cc->from.name, fr);
11074887Schin cc->cvt = (iconv_t)(-1);
11084887Schin
11094887Schin /*
11104887Schin * 8 bit maps are the easiest
11114887Schin */
11124887Schin
11134887Schin if (fc >= 0 && tc >= 0)
11144887Schin cc->from.map = ccmap(fc, tc);
11154887Schin #if _lib_iconv_open
11164887Schin else if ((cc->cvt = iconv_open(to, fr)) != (iconv_t)(-1))
11174887Schin cc->from.fun = (_ast_iconv_f)iconv;
11184887Schin #endif
11194887Schin #if _UWIN
11204887Schin else if ((cc->cvt = _win_iconv_open(cc, to, fr)) != (_ast_iconv_t)(-1))
11214887Schin cc->from.fun = (_ast_iconv_f)_win_iconv;
11224887Schin #endif
11234887Schin else
11244887Schin {
11254887Schin switch (fc)
11264887Schin {
11274887Schin case CC_UTF:
11284887Schin cc->from.fun = utf2bin;
11294887Schin break;
11304887Schin case CC_UME:
11314887Schin cc->from.fun = ume2bin;
11324887Schin break;
11334887Schin case CC_UCS:
11344887Schin cc->from.fun = ucs2bin;
11354887Schin break;
11364887Schin case CC_SCU:
11374887Schin cc->from.fun = scu2bin;
11384887Schin break;
11394887Schin case CC_ASCII:
11404887Schin break;
11414887Schin default:
11424887Schin if (fc < 0)
11434887Schin goto nope;
11444887Schin cc->from.map = ccmap(fc, CC_ASCII);
11454887Schin break;
11464887Schin }
11474887Schin switch (tc)
11484887Schin {
11494887Schin case CC_UTF:
11504887Schin cc->to.fun = bin2utf;
11514887Schin break;
11524887Schin case CC_UME:
11534887Schin cc->to.fun = bin2ume;
11544887Schin break;
11554887Schin case CC_UCS:
11564887Schin cc->to.fun = bin2ucs;
11574887Schin break;
11584887Schin case CC_SCU:
11594887Schin cc->to.fun = bin2scu;
11604887Schin break;
11614887Schin case CC_ASCII:
11624887Schin break;
11634887Schin default:
11644887Schin if (tc < 0)
11654887Schin goto nope;
11664887Schin cc->to.map = ccmap(CC_ASCII, tc);
11674887Schin break;
11684887Schin }
11694887Schin }
11704887Schin return (iconv_t)cc;
11714887Schin nope:
11724887Schin return (iconv_t)(-1);
11734887Schin }
11744887Schin
11754887Schin /*
11764887Schin * close a character code conversion map
11774887Schin */
11784887Schin
11794887Schin int
_ast_iconv_close(_ast_iconv_t cd)11804887Schin _ast_iconv_close(_ast_iconv_t cd)
11814887Schin {
11824887Schin Conv_t* cc;
11834887Schin Conv_t* oc;
11844887Schin int i;
11854887Schin int r = 0;
11864887Schin
11874887Schin if (cd == (_ast_iconv_t)(-1))
11884887Schin return -1;
11894887Schin if (!(cc = (Conv_t*)cd))
11904887Schin return 0;
11914887Schin
11924887Schin /*
11934887Schin * add to the free list
11944887Schin */
11954887Schin
11964887Schin i = freeindex;
11974887Schin for (;;)
11984887Schin {
11994887Schin if (++ i >= elementsof(freelist))
12004887Schin i = 0;
12014887Schin if (!freelist[i])
12024887Schin break;
12034887Schin if (i == freeindex)
12044887Schin {
12054887Schin if (++ i >= elementsof(freelist))
12064887Schin i = 0;
12074887Schin
12084887Schin /*
12094887Schin * close the oldest
12104887Schin */
12114887Schin
12124887Schin if (oc = freelist[i])
12134887Schin {
12144887Schin #if _lib_iconv_open
12154887Schin if (oc->cvt != (iconv_t)(-1))
12164887Schin r = iconv_close(oc->cvt);
12174887Schin #endif
12184887Schin if (oc->buf)
12194887Schin free(oc->buf);
12204887Schin free(oc);
12214887Schin }
12224887Schin break;
12234887Schin }
12244887Schin }
12254887Schin freelist[freeindex = i] = cc;
12264887Schin return r;
12274887Schin }
12284887Schin
12294887Schin /*
12304887Schin * copy *fb size *fn to *tb size *tn
12314887Schin * fb,fn tb,tn updated on return
12324887Schin */
12334887Schin
12344887Schin size_t
_ast_iconv(_ast_iconv_t cd,char ** fb,size_t * fn,char ** tb,size_t * tn)12354887Schin _ast_iconv(_ast_iconv_t cd, char** fb, size_t* fn, char** tb, size_t* tn)
12364887Schin {
12374887Schin Conv_t* cc = (Conv_t*)cd;
12384887Schin register unsigned char* f;
12394887Schin register unsigned char* t;
12404887Schin register unsigned char* e;
12414887Schin register const unsigned char* m;
12424887Schin register size_t n;
12434887Schin char* b;
12444887Schin char* tfb;
12454887Schin size_t tfn;
12464887Schin size_t i;
12474887Schin
12484887Schin if (!fb || !*fb)
12494887Schin {
12504887Schin /* TODO: reset to the initial state */
12514887Schin if (!tb || !*tb)
12524887Schin return 0;
12534887Schin /* TODO: write the initial state shift sequence */
12544887Schin return 0;
12554887Schin }
12564887Schin n = *tn;
12574887Schin if (cc)
12584887Schin {
12594887Schin if (cc->from.fun)
12604887Schin {
12614887Schin if (cc->to.fun)
12624887Schin {
12634887Schin if (!cc->buf && !(cc->buf = oldof(0, char, cc->size = SF_BUFSIZE, 0)))
12644887Schin {
12654887Schin errno = ENOMEM;
12664887Schin return -1;
12674887Schin }
12684887Schin b = cc->buf;
12694887Schin i = cc->size;
12704887Schin tfb = *fb;
12714887Schin tfn = *fn;
12724887Schin if ((*cc->from.fun)(cc->cvt, &tfb, &tfn, &b, &i) == (size_t)(-1))
12734887Schin return -1;
12744887Schin tfn = b - cc->buf;
12754887Schin tfb = cc->buf;
12764887Schin n = (*cc->to.fun)(cc->cvt, &tfb, &tfn, tb, tn);
12774887Schin i = tfb - cc->buf;
12784887Schin *fb += i;
12794887Schin *fn -= i;
12804887Schin return n;
12814887Schin }
12824887Schin if ((*cc->from.fun)(cc->cvt, fb, fn, tb, tn) == (size_t)(-1))
12834887Schin return -1;
12844887Schin n -= *tn;
12854887Schin if (m = cc->to.map)
12864887Schin {
12874887Schin e = (unsigned char*)(*tb);
12884887Schin for (t = e - n; t < e; t++)
12894887Schin *t = m[*t];
12904887Schin }
12914887Schin return n;
12924887Schin }
12934887Schin else if (cc->to.fun)
12944887Schin {
12954887Schin if (!(m = cc->from.map))
12964887Schin return (*cc->to.fun)(cc->cvt, fb, fn, tb, tn);
12974887Schin if (!cc->buf && !(cc->buf = oldof(0, char, cc->size = SF_BUFSIZE, 0)))
12984887Schin {
12994887Schin errno = ENOMEM;
13004887Schin return -1;
13014887Schin }
13024887Schin if ((n = *fn) > cc->size)
13034887Schin n = cc->size;
13044887Schin f = (unsigned char*)(*fb);
13054887Schin e = f + n;
13064887Schin t = (unsigned char*)(b = cc->buf);
13074887Schin while (f < e)
13084887Schin *t++ = m[*f++];
13094887Schin n = (*cc->to.fun)(cc->cvt, &b, fn, tb, tn);
13104887Schin *fb += b - cc->buf;
13114887Schin return n;
13124887Schin }
13134887Schin }
13144887Schin if (n > *fn)
13154887Schin n = *fn;
13164887Schin if (cc && (m = cc->from.map))
13174887Schin {
13184887Schin f = (unsigned char*)(*fb);
13194887Schin e = f + n;
13204887Schin t = (unsigned char*)(*tb);
13214887Schin while (f < e)
13224887Schin *t++ = m[*f++];
13234887Schin }
13244887Schin else
13254887Schin memcpy(*tb, *fb, n);
13264887Schin *fb += n;
13274887Schin *fn -= n;
13284887Schin *tb += n;
13294887Schin *tn -= n;
13304887Schin return n;
13314887Schin }
13324887Schin
13334887Schin /*
13344887Schin * write *fb size *fn to op
13354887Schin * fb,fn updated on return
13364887Schin * total bytes written to op returned
13374887Schin */
13384887Schin
13394887Schin ssize_t
_ast_iconv_write(_ast_iconv_t cd,Sfio_t * op,char ** fb,size_t * fn,size_t * e)13404887Schin _ast_iconv_write(_ast_iconv_t cd, Sfio_t* op, char** fb, size_t* fn, size_t* e)
13414887Schin {
13424887Schin char* tb;
13434887Schin char* ts;
13444887Schin size_t tn;
13454887Schin size_t r;
13464887Schin
13474887Schin r = 0;
13484887Schin tn = 0;
13494887Schin while (*fn > 0)
13504887Schin {
13514887Schin if (!(tb = (char*)sfreserve(op, -(tn + 1), SF_WRITE|SF_LOCKR)))
13524887Schin return r ? r : -1;
13534887Schin ts = tb;
13544887Schin tn = sfvalue(op);
13554887Schin #if DEBUG_TRACE
13564887Schin error(DEBUG_TRACE, "AHA#%d iconv_write ts=%p tn=%d", __LINE__, ts, tn);
13574887Schin for (;;)
13584887Schin #else
13594887Schin while (_ast_iconv(cd, fb, fn, &ts, &tn) == (size_t)(-1))
13604887Schin #endif
13614887Schin {
13624887Schin #if DEBUG_TRACE
13634887Schin ssize_t _r;
13644887Schin error(DEBUG_TRACE, "AHA#%d iconv_write %d => %d `%-.*s'", __LINE__, *fn, tn, *fn, *fb);
13654887Schin _r = _ast_iconv(cd, fb, fn, &ts, &tn);
13664887Schin error(DEBUG_TRACE, "AHA#%d iconv_write %d => %d [%d]", __LINE__, *fn, tn, _r);
13674887Schin if (_r != (size_t)(-1))
13684887Schin break;
13694887Schin #endif
13704887Schin if (errno == E2BIG)
13714887Schin break;
13724887Schin if (e)
13734887Schin (*e)++;
13744887Schin if (!tn)
13754887Schin break;
13764887Schin *ts++ = *(*fb)++;
13774887Schin tn--;
13784887Schin (*fn)--;
13794887Schin }
13804887Schin #if DEBUG_TRACE
13814887Schin error(DEBUG_TRACE, "AHA#%d iconv_write %d", __LINE__, ts - tb);
13824887Schin #endif
13834887Schin
13844887Schin sfwrite(op, tb, ts - tb);
13854887Schin r += ts - tb;
13864887Schin }
13874887Schin return r;
13884887Schin }
13894887Schin
13904887Schin /*
13914887Schin * move n bytes from ip to op
13924887Schin */
13934887Schin
13944887Schin ssize_t
_ast_iconv_move(_ast_iconv_t cd,Sfio_t * ip,Sfio_t * op,size_t n,size_t * e)13954887Schin _ast_iconv_move(_ast_iconv_t cd, Sfio_t* ip, Sfio_t* op, size_t n, size_t* e)
13964887Schin {
13974887Schin char* fb;
13984887Schin char* fs;
13994887Schin char* tb;
14004887Schin char* ts;
14014887Schin size_t fn;
14024887Schin size_t fo;
14034887Schin size_t tn;
14044887Schin size_t i;
14054887Schin ssize_t r = 0;
14064887Schin int locked;
14074887Schin
14084887Schin fn = n;
14094887Schin for (;;)
14104887Schin {
14114887Schin if (fn != SF_UNBOUND)
14124887Schin fn = -((ssize_t)(fn & (((size_t)(~0))>>1)));
14134887Schin if (!(fb = (char*)sfreserve(ip, fn, locked = SF_LOCKR)) &&
14144887Schin !(fb = (char*)sfreserve(ip, fn, locked = 0)))
14154887Schin break;
14164887Schin fs = fb;
14174887Schin fn = fo = sfvalue(ip);
14184887Schin if (!(tb = (char*)sfreserve(op, SF_UNBOUND, SF_WRITE|SF_LOCKR)))
14194887Schin {
14204887Schin sfread(ip, fb, 0);
14214887Schin return r ? r : -1;
14224887Schin }
14234887Schin ts = tb;
14244887Schin tn = sfvalue(op);
14254887Schin while (_ast_iconv(cd, &fs, &fn, &ts, &tn) != (size_t)(-1) && fn > 0)
14264887Schin {
14274887Schin if (tn > 0)
14284887Schin {
14294887Schin *ts++ = '_';
14304887Schin tn--;
14314887Schin }
14324887Schin if (e)
14334887Schin (*e)++;
14344887Schin fs++;
14354887Schin fn--;
14364887Schin }
14374887Schin sfwrite(op, tb, ts - tb);
14384887Schin r += ts - tb;
14394887Schin if (locked)
14404887Schin sfread(ip, fb, fs - fb);
14414887Schin else
14424887Schin for (i = fn; --i >= (fs - fb);)
14434887Schin sfungetc(ip, fb[i]);
14444887Schin if (n != SF_UNBOUND)
14454887Schin {
14464887Schin if (n <= (fs - fb))
14474887Schin break;
14484887Schin n -= fs - fb;
14494887Schin }
14504887Schin if (fn == fo)
14514887Schin fn++;
14524887Schin }
14534887Schin return r;
14544887Schin }
14554887Schin
14564887Schin /*
14574887Schin * iconv_list_t iterator
14584887Schin * call with arg 0 to start
14594887Schin * prev return value is current arg
14604887Schin */
14614887Schin
14624887Schin _ast_iconv_list_t*
_ast_iconv_list(_ast_iconv_list_t * cp)14634887Schin _ast_iconv_list(_ast_iconv_list_t* cp)
14644887Schin {
14654887Schin #if _UWIN
14664887Schin struct dirent* ent;
14674887Schin
14684887Schin if (!cp)
14694887Schin {
14704887Schin if (!(cp = newof(0, _ast_iconv_list_t, 1, 0)))
14714887Schin return ccmaplist(NiL);
14724887Schin if (!(cp->data = opendir(_win_maps)))
14734887Schin {
14744887Schin free(cp);
14754887Schin return ccmaplist(NiL);
14764887Schin }
14774887Schin }
14784887Schin if (cp->data)
14794887Schin {
14804887Schin if (ent = readdir((DIR*)cp->data))
14814887Schin {
14824887Schin cp->name = cp->match = cp->desc = (const char*)ent->d_name;
14834887Schin return cp;
14844887Schin }
14854887Schin closedir((DIR*)cp->data);
14864887Schin free(cp);
14874887Schin return ccmaplist(NiL);
14884887Schin }
14894887Schin #else
14904887Schin if (!cp)
14914887Schin return ccmaplist(NiL);
14924887Schin #endif
14934887Schin if (cp->ccode >= 0)
14944887Schin return (cp = ccmaplist(cp)) ? cp : (_ast_iconv_list_t*)codes;
14954887Schin return (++cp)->name ? cp : (_ast_iconv_list_t*)0;
14964887Schin }
1497