xref: /aosp_15_r20/external/mtools/charsetConv.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1*d5c9a868SElliott Hughes /*  Copyright 2008,2009 Alain Knaff.
2*d5c9a868SElliott Hughes  *  This file is part of mtools.
3*d5c9a868SElliott Hughes  *
4*d5c9a868SElliott Hughes  *  Mtools is free software: you can redistribute it and/or modify
5*d5c9a868SElliott Hughes  *  it under the terms of the GNU General Public License as published by
6*d5c9a868SElliott Hughes  *  the Free Software Foundation, either version 3 of the License, or
7*d5c9a868SElliott Hughes  *  (at your option) any later version.
8*d5c9a868SElliott Hughes  *
9*d5c9a868SElliott Hughes  *  Mtools is distributed in the hope that it will be useful,
10*d5c9a868SElliott Hughes  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11*d5c9a868SElliott Hughes  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*d5c9a868SElliott Hughes  *  GNU General Public License for more details.
13*d5c9a868SElliott Hughes  *
14*d5c9a868SElliott Hughes  *  You should have received a copy of the GNU General Public License
15*d5c9a868SElliott Hughes  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16*d5c9a868SElliott Hughes  *
17*d5c9a868SElliott Hughes  * Various character set conversions used by mtools
18*d5c9a868SElliott Hughes  */
19*d5c9a868SElliott Hughes #include "sysincludes.h"
20*d5c9a868SElliott Hughes #include "msdos.h"
21*d5c9a868SElliott Hughes #include "mtools.h"
22*d5c9a868SElliott Hughes 
23*d5c9a868SElliott Hughes #include <stdio.h>
24*d5c9a868SElliott Hughes #include <errno.h>
25*d5c9a868SElliott Hughes #include <stdlib.h>
26*d5c9a868SElliott Hughes #include "file_name.h"
27*d5c9a868SElliott Hughes 
28*d5c9a868SElliott Hughes 
29*d5c9a868SElliott Hughes #ifdef HAVE_ICONV_H
30*d5c9a868SElliott Hughes #include <iconv.h>
31*d5c9a868SElliott Hughes 
32*d5c9a868SElliott Hughes struct doscp_t {
33*d5c9a868SElliott Hughes 	iconv_t from;
34*d5c9a868SElliott Hughes 	iconv_t to;
35*d5c9a868SElliott Hughes };
36*d5c9a868SElliott Hughes 
37*d5c9a868SElliott Hughes static const char *wcharCp=NULL;
38*d5c9a868SElliott Hughes 
39*d5c9a868SElliott Hughes static const char* wcharTries[] = {
40*d5c9a868SElliott Hughes 	"WCHAR_T",
41*d5c9a868SElliott Hughes 	"UTF-32BE", "UTF-32LE",
42*d5c9a868SElliott Hughes 	"UTF-16BE", "UTF-16LE",
43*d5c9a868SElliott Hughes 	"UTF-32", "UTF-16",
44*d5c9a868SElliott Hughes 	"UCS-4BE", "UCS-4LE",
45*d5c9a868SElliott Hughes 	"UCS-2BE", "UCS-2LE",
46*d5c9a868SElliott Hughes 	"UCS-4", "UCS-2"
47*d5c9a868SElliott Hughes };
48*d5c9a868SElliott Hughes 
49*d5c9a868SElliott Hughes static const char *asciiTries[] = {
50*d5c9a868SElliott Hughes 	"ASCII", "ASCII-GR", "ISO8859-1"
51*d5c9a868SElliott Hughes };
52*d5c9a868SElliott Hughes 
53*d5c9a868SElliott Hughes static const wchar_t *testString = L"ab";
54*d5c9a868SElliott Hughes 
try(const char * testCp)55*d5c9a868SElliott Hughes static int try(const char *testCp) {
56*d5c9a868SElliott Hughes 	size_t res;
57*d5c9a868SElliott Hughes 	char *inbuf = (char *)testString;
58*d5c9a868SElliott Hughes 	size_t inbufLen = 2*sizeof(wchar_t);
59*d5c9a868SElliott Hughes 	char outbuf[3];
60*d5c9a868SElliott Hughes 	char *outbufP = outbuf;
61*d5c9a868SElliott Hughes 	size_t outbufLen = 2*sizeof(char);
62*d5c9a868SElliott Hughes 	iconv_t test = 0;
63*d5c9a868SElliott Hughes 	size_t i;
64*d5c9a868SElliott Hughes 
65*d5c9a868SElliott Hughes 	for(i=0; i < sizeof(asciiTries) / sizeof(asciiTries[0]); i++) {
66*d5c9a868SElliott Hughes 		test = iconv_open(asciiTries[i], testCp);
67*d5c9a868SElliott Hughes 		if(test != (iconv_t) -1)
68*d5c9a868SElliott Hughes 			break;
69*d5c9a868SElliott Hughes 	}
70*d5c9a868SElliott Hughes 	if(test == (iconv_t) -1)
71*d5c9a868SElliott Hughes 		goto fail0;
72*d5c9a868SElliott Hughes 	res = iconv(test,
73*d5c9a868SElliott Hughes 		    &inbuf, &inbufLen,
74*d5c9a868SElliott Hughes 		    &outbufP, &outbufLen);
75*d5c9a868SElliott Hughes 	if(res != 0 || outbufLen != 0 || inbufLen != 0)
76*d5c9a868SElliott Hughes 		goto fail;
77*d5c9a868SElliott Hughes 	if(memcmp(outbuf, "ab", 2))
78*d5c9a868SElliott Hughes 		goto fail;
79*d5c9a868SElliott Hughes 	/* fprintf(stderr, "%s ok\n", testCp); */
80*d5c9a868SElliott Hughes 	return 1;
81*d5c9a868SElliott Hughes  fail:
82*d5c9a868SElliott Hughes 	iconv_close(test);
83*d5c9a868SElliott Hughes  fail0:
84*d5c9a868SElliott Hughes 	/*fprintf(stderr, "%s fail\n", testCp);*/
85*d5c9a868SElliott Hughes 	return 0;
86*d5c9a868SElliott Hughes }
87*d5c9a868SElliott Hughes 
getWcharCp(void)88*d5c9a868SElliott Hughes static const char *getWcharCp(void) {
89*d5c9a868SElliott Hughes 	unsigned int i;
90*d5c9a868SElliott Hughes 	if(wcharCp != NULL)
91*d5c9a868SElliott Hughes 		return wcharCp;
92*d5c9a868SElliott Hughes 	for(i=0; i< sizeof(wcharTries) / sizeof(wcharTries[0]); i++) {
93*d5c9a868SElliott Hughes 		if(try(wcharTries[i]))
94*d5c9a868SElliott Hughes 			return (wcharCp=wcharTries[i]);
95*d5c9a868SElliott Hughes 	}
96*d5c9a868SElliott Hughes 	fprintf(stderr, "No codepage found for wchar_t\n");
97*d5c9a868SElliott Hughes 	return NULL;
98*d5c9a868SElliott Hughes }
99*d5c9a868SElliott Hughes 
100*d5c9a868SElliott Hughes 
cp_open(unsigned int codepage)101*d5c9a868SElliott Hughes doscp_t *cp_open(unsigned int codepage)
102*d5c9a868SElliott Hughes {
103*d5c9a868SElliott Hughes 	char dosCp[17];
104*d5c9a868SElliott Hughes 	doscp_t *ret;
105*d5c9a868SElliott Hughes 	iconv_t from;
106*d5c9a868SElliott Hughes 	iconv_t to;
107*d5c9a868SElliott Hughes 
108*d5c9a868SElliott Hughes 	if(codepage == 0)
109*d5c9a868SElliott Hughes 		codepage = mtools_default_codepage;
110*d5c9a868SElliott Hughes 	if(codepage > 9999) {
111*d5c9a868SElliott Hughes 		fprintf(stderr, "Bad codepage %d\n", codepage);
112*d5c9a868SElliott Hughes 		return NULL;
113*d5c9a868SElliott Hughes 	}
114*d5c9a868SElliott Hughes 
115*d5c9a868SElliott Hughes 	if(getWcharCp() == NULL)
116*d5c9a868SElliott Hughes 		return NULL;
117*d5c9a868SElliott Hughes 
118*d5c9a868SElliott Hughes 	sprintf(dosCp, "CP%d", codepage);
119*d5c9a868SElliott Hughes 	from = iconv_open(wcharCp, dosCp);
120*d5c9a868SElliott Hughes 	if(from == (iconv_t)-1) {
121*d5c9a868SElliott Hughes 		fprintf(stderr, "Error converting to codepage %d %s\n",
122*d5c9a868SElliott Hughes 			codepage, strerror(errno));
123*d5c9a868SElliott Hughes 		return NULL;
124*d5c9a868SElliott Hughes 	}
125*d5c9a868SElliott Hughes 
126*d5c9a868SElliott Hughes 	sprintf(dosCp, "CP%d//TRANSLIT", codepage);
127*d5c9a868SElliott Hughes 	to   =  iconv_open(dosCp, wcharCp);
128*d5c9a868SElliott Hughes 	if(to == (iconv_t)-1) {
129*d5c9a868SElliott Hughes 		/* Transliteration not supported? */
130*d5c9a868SElliott Hughes 		sprintf(dosCp, "CP%d", codepage);
131*d5c9a868SElliott Hughes 		to   =  iconv_open(dosCp, wcharCp);
132*d5c9a868SElliott Hughes 	}
133*d5c9a868SElliott Hughes 	if(to == (iconv_t)-1) {
134*d5c9a868SElliott Hughes 		iconv_close(from);
135*d5c9a868SElliott Hughes 		fprintf(stderr, "Error converting to codepage %d %s\n",
136*d5c9a868SElliott Hughes 			codepage, strerror(errno));
137*d5c9a868SElliott Hughes 		return NULL;
138*d5c9a868SElliott Hughes 	}
139*d5c9a868SElliott Hughes 
140*d5c9a868SElliott Hughes 	ret = New(doscp_t);
141*d5c9a868SElliott Hughes 	if(ret == NULL)
142*d5c9a868SElliott Hughes 		return ret;
143*d5c9a868SElliott Hughes 	ret->from = from;
144*d5c9a868SElliott Hughes 	ret->to   = to;
145*d5c9a868SElliott Hughes 	return ret;
146*d5c9a868SElliott Hughes }
147*d5c9a868SElliott Hughes 
cp_close(doscp_t * cp)148*d5c9a868SElliott Hughes void cp_close(doscp_t *cp)
149*d5c9a868SElliott Hughes {
150*d5c9a868SElliott Hughes 	iconv_close(cp->to);
151*d5c9a868SElliott Hughes 	iconv_close(cp->from);
152*d5c9a868SElliott Hughes 	free(cp);
153*d5c9a868SElliott Hughes }
154*d5c9a868SElliott Hughes 
dos_to_wchar(doscp_t * cp,const char * dos,wchar_t * wchar,size_t len)155*d5c9a868SElliott Hughes size_t dos_to_wchar(doscp_t *cp, const char *dos, wchar_t *wchar, size_t len)
156*d5c9a868SElliott Hughes {
157*d5c9a868SElliott Hughes 	size_t r;
158*d5c9a868SElliott Hughes 	size_t in_len=len;
159*d5c9a868SElliott Hughes 	size_t out_len=len*sizeof(wchar_t);
160*d5c9a868SElliott Hughes 	wchar_t *dptr=wchar;
161*d5c9a868SElliott Hughes 	char *dos2 = (char *) dos; /* Magic to be able to call iconv with its
162*d5c9a868SElliott Hughes 				      buggy prototype */
163*d5c9a868SElliott Hughes 	r=iconv(cp->from, &dos2, &in_len, (char **)&dptr, &out_len);
164*d5c9a868SElliott Hughes 	if(r == (size_t) -1)
165*d5c9a868SElliott Hughes 		return r;
166*d5c9a868SElliott Hughes 	*dptr = L'\0';
167*d5c9a868SElliott Hughes 	return (size_t) (dptr-wchar);
168*d5c9a868SElliott Hughes }
169*d5c9a868SElliott Hughes 
170*d5c9a868SElliott Hughes /**
171*d5c9a868SElliott Hughes  * Converts len wide character to destination. Caller's responsibility to
172*d5c9a868SElliott Hughes  * ensure that dest is large enough.
173*d5c9a868SElliott Hughes  * mangled will be set if there has been an untranslatable character.
174*d5c9a868SElliott Hughes  */
safe_iconv(iconv_t conv,const wchar_t * wchar,char * dest,size_t in_len,size_t out_len,int * mangled)175*d5c9a868SElliott Hughes static size_t safe_iconv(iconv_t conv, const wchar_t *wchar, char *dest,
176*d5c9a868SElliott Hughes 		      size_t in_len, size_t out_len, int *mangled)
177*d5c9a868SElliott Hughes {
178*d5c9a868SElliott Hughes 	size_t r;
179*d5c9a868SElliott Hughes 	unsigned int i;
180*d5c9a868SElliott Hughes 	char *dptr = dest;
181*d5c9a868SElliott Hughes 	size_t len;
182*d5c9a868SElliott Hughes 
183*d5c9a868SElliott Hughes 	in_len=in_len*sizeof(wchar_t);
184*d5c9a868SElliott Hughes 
185*d5c9a868SElliott Hughes 	while(in_len > 0 && out_len > 0) {
186*d5c9a868SElliott Hughes 		r=iconv(conv, (char**)&wchar, &in_len, &dptr, &out_len);
187*d5c9a868SElliott Hughes 		if(r == (size_t) -1 || errno != EILSEQ) {
188*d5c9a868SElliott Hughes 			/* everything transformed, or error that is _not_ a bad
189*d5c9a868SElliott Hughes 			 * character */
190*d5c9a868SElliott Hughes 			break;
191*d5c9a868SElliott Hughes 		}
192*d5c9a868SElliott Hughes 		*mangled |= 1;
193*d5c9a868SElliott Hughes 
194*d5c9a868SElliott Hughes 		if(out_len <= 0)
195*d5c9a868SElliott Hughes 			break;
196*d5c9a868SElliott Hughes 		if(dptr)
197*d5c9a868SElliott Hughes 			*dptr++ = '_';
198*d5c9a868SElliott Hughes 		in_len -= sizeof(wchar_t);
199*d5c9a868SElliott Hughes 
200*d5c9a868SElliott Hughes 		wchar++;
201*d5c9a868SElliott Hughes 		out_len--;
202*d5c9a868SElliott Hughes 	}
203*d5c9a868SElliott Hughes 
204*d5c9a868SElliott Hughes 	len = (size_t) (dptr-dest); /* how many dest characters have there been
205*d5c9a868SElliott Hughes 				       generated */
206*d5c9a868SElliott Hughes 
207*d5c9a868SElliott Hughes 	/* eliminate question marks which might have been formed by
208*d5c9a868SElliott Hughes 	   untransliterable characters */
209*d5c9a868SElliott Hughes 	for(i=0; i<len; i++) {
210*d5c9a868SElliott Hughes 		if(dest[i] == '?') {
211*d5c9a868SElliott Hughes 			dest[i] = '_';
212*d5c9a868SElliott Hughes 			*mangled |= 1;
213*d5c9a868SElliott Hughes 		}
214*d5c9a868SElliott Hughes 	}
215*d5c9a868SElliott Hughes 	return len;
216*d5c9a868SElliott Hughes }
217*d5c9a868SElliott Hughes 
wchar_to_dos(doscp_t * cp,wchar_t * wchar,char * dos,size_t len,int * mangled)218*d5c9a868SElliott Hughes void wchar_to_dos(doscp_t *cp,
219*d5c9a868SElliott Hughes 		  wchar_t *wchar, char *dos, size_t len, int *mangled)
220*d5c9a868SElliott Hughes {
221*d5c9a868SElliott Hughes 	safe_iconv(cp->to, wchar, dos, len, len, mangled);
222*d5c9a868SElliott Hughes }
223*d5c9a868SElliott Hughes 
224*d5c9a868SElliott Hughes #else
225*d5c9a868SElliott Hughes 
226*d5c9a868SElliott Hughes #include "codepage.h"
227*d5c9a868SElliott Hughes 
228*d5c9a868SElliott Hughes struct doscp_t {
229*d5c9a868SElliott Hughes 	unsigned char *from_dos;
230*d5c9a868SElliott Hughes 	unsigned char to_dos[0x80];
231*d5c9a868SElliott Hughes };
232*d5c9a868SElliott Hughes 
cp_open(unsigned int codepage)233*d5c9a868SElliott Hughes doscp_t *cp_open(unsigned int codepage)
234*d5c9a868SElliott Hughes {
235*d5c9a868SElliott Hughes 	doscp_t *ret;
236*d5c9a868SElliott Hughes 	int i;
237*d5c9a868SElliott Hughes 	Codepage_t *cp;
238*d5c9a868SElliott Hughes 
239*d5c9a868SElliott Hughes 	if(codepage == 0)
240*d5c9a868SElliott Hughes 		codepage = 850;
241*d5c9a868SElliott Hughes 
242*d5c9a868SElliott Hughes 	ret = New(doscp_t);
243*d5c9a868SElliott Hughes 	if(ret == NULL)
244*d5c9a868SElliott Hughes 		return ret;
245*d5c9a868SElliott Hughes 
246*d5c9a868SElliott Hughes 	for(cp=codepages; cp->nr ; cp++)
247*d5c9a868SElliott Hughes 		if(cp->nr == codepage) {
248*d5c9a868SElliott Hughes 			ret->from_dos = cp->tounix;
249*d5c9a868SElliott Hughes 			break;
250*d5c9a868SElliott Hughes 		}
251*d5c9a868SElliott Hughes 
252*d5c9a868SElliott Hughes 	if(ret->from_dos == NULL) {
253*d5c9a868SElliott Hughes 		fprintf(stderr, "Bad codepage %d\n", codepage);
254*d5c9a868SElliott Hughes 		free(ret);
255*d5c9a868SElliott Hughes 		return NULL;
256*d5c9a868SElliott Hughes 	}
257*d5c9a868SElliott Hughes 
258*d5c9a868SElliott Hughes 	for(i=0; i<0x80; i++) {
259*d5c9a868SElliott Hughes 		char native = ret->from_dos[i];
260*d5c9a868SElliott Hughes 		if(! (native & 0x80))
261*d5c9a868SElliott Hughes 			continue;
262*d5c9a868SElliott Hughes 		ret->to_dos[native & 0x7f] = 0x80 | i;
263*d5c9a868SElliott Hughes 	}
264*d5c9a868SElliott Hughes 	return ret;
265*d5c9a868SElliott Hughes }
266*d5c9a868SElliott Hughes 
cp_close(doscp_t * cp)267*d5c9a868SElliott Hughes void cp_close(doscp_t *cp)
268*d5c9a868SElliott Hughes {
269*d5c9a868SElliott Hughes 	free(cp);
270*d5c9a868SElliott Hughes }
271*d5c9a868SElliott Hughes 
dos_to_wchar(doscp_t * cp,const char * dos,wchar_t * wchar,size_t len)272*d5c9a868SElliott Hughes size_t dos_to_wchar(doscp_t *cp, const char *dos, wchar_t *wchar, size_t len)
273*d5c9a868SElliott Hughes {
274*d5c9a868SElliott Hughes 	int i;
275*d5c9a868SElliott Hughes 
276*d5c9a868SElliott Hughes 	for(i=0; i<len && dos[i]; i++) {
277*d5c9a868SElliott Hughes 		char c = dos[i];
278*d5c9a868SElliott Hughes 		if(c >= ' ' && c <= '~')
279*d5c9a868SElliott Hughes 			wchar[i] = c;
280*d5c9a868SElliott Hughes 		else {
281*d5c9a868SElliott Hughes 			wchar[i] = cp->from_dos[c & 0x7f];
282*d5c9a868SElliott Hughes 		}
283*d5c9a868SElliott Hughes 	}
284*d5c9a868SElliott Hughes 	wchar[i] = '\0';
285*d5c9a868SElliott Hughes 	return i;
286*d5c9a868SElliott Hughes }
287*d5c9a868SElliott Hughes 
288*d5c9a868SElliott Hughes 
wchar_to_dos(doscp_t * cp,wchar_t * wchar,char * dos,size_t len,int * mangled)289*d5c9a868SElliott Hughes void wchar_to_dos(doscp_t *cp,
290*d5c9a868SElliott Hughes 		  wchar_t *wchar, char *dos, size_t len, int *mangled)
291*d5c9a868SElliott Hughes {
292*d5c9a868SElliott Hughes 	int i;
293*d5c9a868SElliott Hughes 	for(i=0; i<len && wchar[i]; i++) {
294*d5c9a868SElliott Hughes 		char c = wchar[i];
295*d5c9a868SElliott Hughes 		if(c >= ' ' && c <= '~')
296*d5c9a868SElliott Hughes 			dos[i] = c;
297*d5c9a868SElliott Hughes 		else {
298*d5c9a868SElliott Hughes 			dos[i] = cp->to_dos[c & 0x7f];
299*d5c9a868SElliott Hughes 			if(dos[i] == '\0') {
300*d5c9a868SElliott Hughes 				dos[i]='_';
301*d5c9a868SElliott Hughes 				*mangled=1;
302*d5c9a868SElliott Hughes 			}
303*d5c9a868SElliott Hughes 		}
304*d5c9a868SElliott Hughes 	}
305*d5c9a868SElliott Hughes }
306*d5c9a868SElliott Hughes 
307*d5c9a868SElliott Hughes #endif
308*d5c9a868SElliott Hughes 
309*d5c9a868SElliott Hughes 
310*d5c9a868SElliott Hughes #ifndef HAVE_WCHAR_H
311*d5c9a868SElliott Hughes 
312*d5c9a868SElliott Hughes typedef int mbstate_t;
313*d5c9a868SElliott Hughes 
wcrtomb(char * s,wchar_t wc,mbstate_t * ps)314*d5c9a868SElliott Hughes static inline size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps)
315*d5c9a868SElliott Hughes {
316*d5c9a868SElliott Hughes 	*s = wc;
317*d5c9a868SElliott Hughes 	return 1;
318*d5c9a868SElliott Hughes }
319*d5c9a868SElliott Hughes 
mbrtowc(wchar_t * pwc,const char * s,size_t n,mbstate_t * ps)320*d5c9a868SElliott Hughes static inline size_t mbrtowc(wchar_t *pwc, const char *s,
321*d5c9a868SElliott Hughes 			     size_t n, mbstate_t *ps)
322*d5c9a868SElliott Hughes {
323*d5c9a868SElliott Hughes 	*pwc = *s;
324*d5c9a868SElliott Hughes 	return 1;
325*d5c9a868SElliott Hughes }
326*d5c9a868SElliott Hughes 
327*d5c9a868SElliott Hughes #endif
328*d5c9a868SElliott Hughes 
329*d5c9a868SElliott Hughes #ifdef HAVE_ICONV_H
330*d5c9a868SElliott Hughes 
331*d5c9a868SElliott Hughes #include <langinfo.h>
332*d5c9a868SElliott Hughes 
333*d5c9a868SElliott Hughes static iconv_t to_native = NULL;
334*d5c9a868SElliott Hughes 
initialize_to_native(void)335*d5c9a868SElliott Hughes static void initialize_to_native(void)
336*d5c9a868SElliott Hughes {
337*d5c9a868SElliott Hughes 	char *li, *cp;
338*d5c9a868SElliott Hughes 	size_t len;
339*d5c9a868SElliott Hughes 	if(to_native != NULL)
340*d5c9a868SElliott Hughes 		return;
341*d5c9a868SElliott Hughes 	li = nl_langinfo(CODESET);
342*d5c9a868SElliott Hughes 	len = strlen(li) + 11;
343*d5c9a868SElliott Hughes 	if(getWcharCp() == NULL)
344*d5c9a868SElliott Hughes 		exit(1);
345*d5c9a868SElliott Hughes 	cp = safe_malloc(len);
346*d5c9a868SElliott Hughes 	strcpy(cp, li);
347*d5c9a868SElliott Hughes 	strcat(cp, "//TRANSLIT");
348*d5c9a868SElliott Hughes 	to_native = iconv_open(cp, wcharCp);
349*d5c9a868SElliott Hughes 	if(to_native == (iconv_t) -1)
350*d5c9a868SElliott Hughes 		to_native = iconv_open(li, wcharCp);
351*d5c9a868SElliott Hughes 	if(to_native == (iconv_t) -1)
352*d5c9a868SElliott Hughes 		fprintf(stderr, "Could not allocate iconv for %s\n", cp);
353*d5c9a868SElliott Hughes 	free(cp);
354*d5c9a868SElliott Hughes 	if(to_native == (iconv_t) -1)
355*d5c9a868SElliott Hughes 		exit(1);
356*d5c9a868SElliott Hughes }
357*d5c9a868SElliott Hughes 
358*d5c9a868SElliott Hughes 
359*d5c9a868SElliott Hughes 
360*d5c9a868SElliott Hughes #endif
361*d5c9a868SElliott Hughes 
362*d5c9a868SElliott Hughes 
363*d5c9a868SElliott Hughes /**
364*d5c9a868SElliott Hughes  * Convert wchar string to native, converting at most len wchar characters
365*d5c9a868SElliott Hughes  * Returns number of generated native characters
366*d5c9a868SElliott Hughes  */
wchar_to_native(const wchar_t * wchar,char * native,size_t len,size_t out_len)367*d5c9a868SElliott Hughes size_t wchar_to_native(const wchar_t *wchar, char *native, size_t len,
368*d5c9a868SElliott Hughes 		       size_t out_len)
369*d5c9a868SElliott Hughes {
370*d5c9a868SElliott Hughes #ifdef HAVE_ICONV_H
371*d5c9a868SElliott Hughes 	int mangled;
372*d5c9a868SElliott Hughes 	size_t r;
373*d5c9a868SElliott Hughes 	initialize_to_native();
374*d5c9a868SElliott Hughes 	len = wcsnlen(wchar,len);
375*d5c9a868SElliott Hughes 	r=safe_iconv(to_native, wchar, native, len, out_len, &mangled);
376*d5c9a868SElliott Hughes 	native[r]='\0';
377*d5c9a868SElliott Hughes 	return r;
378*d5c9a868SElliott Hughes #else
379*d5c9a868SElliott Hughes 	int i;
380*d5c9a868SElliott Hughes 	char *dptr = native;
381*d5c9a868SElliott Hughes 	mbstate_t ps;
382*d5c9a868SElliott Hughes 	memset(&ps, 0, sizeof(ps));
383*d5c9a868SElliott Hughes 	for(i=0; i<len && wchar[i] != 0; i++) {
384*d5c9a868SElliott Hughes 		size_t r = wcrtomb(dptr, wchar[i], &ps);
385*d5c9a868SElliott Hughes 		if(r == (size_t) -1 && errno == EILSEQ) {
386*d5c9a868SElliott Hughes 			r=1;
387*d5c9a868SElliott Hughes 			*dptr='_';
388*d5c9a868SElliott Hughes 		}
389*d5c9a868SElliott Hughes 		dptr+=r;
390*d5c9a868SElliott Hughes 	}
391*d5c9a868SElliott Hughes 	*dptr='\0';
392*d5c9a868SElliott Hughes 	return dptr-native;
393*d5c9a868SElliott Hughes #endif
394*d5c9a868SElliott Hughes }
395*d5c9a868SElliott Hughes 
396*d5c9a868SElliott Hughes /**
397*d5c9a868SElliott Hughes  * Convert native string to wchar string, generating at most len wchar
398*d5c9a868SElliott Hughes  * characters. If end is supplied, stop conversion when source pointer
399*d5c9a868SElliott Hughes  * exceeds end. Returns number of generated wchars
400*d5c9a868SElliott Hughes  */
native_to_wchar(const char * native,wchar_t * wchar,size_t len,const char * end,int * mangled)401*d5c9a868SElliott Hughes size_t native_to_wchar(const char *native, wchar_t *wchar, size_t len,
402*d5c9a868SElliott Hughes 		       const char *end, int *mangled)
403*d5c9a868SElliott Hughes {
404*d5c9a868SElliott Hughes 	mbstate_t ps;
405*d5c9a868SElliott Hughes 	unsigned int i;
406*d5c9a868SElliott Hughes 	memset(&ps, 0, sizeof(ps));
407*d5c9a868SElliott Hughes 
408*d5c9a868SElliott Hughes 	for(i=0; i<len && (native < end || !end); i++) {
409*d5c9a868SElliott Hughes 		size_t r = mbrtowc(wchar+i, native, len, &ps);
410*d5c9a868SElliott Hughes 		if(r == (size_t) -1) {
411*d5c9a868SElliott Hughes 			/* Unconvertible character. Just pretend it's Latin1
412*d5c9a868SElliott Hughes 			   encoded (if valid Latin1 character) or substitute
413*d5c9a868SElliott Hughes 			   with an underscore if not
414*d5c9a868SElliott Hughes 			*/
415*d5c9a868SElliott Hughes 			char c = *native;
416*d5c9a868SElliott Hughes 			if(c >= '\xa0' && c < '\xff')
417*d5c9a868SElliott Hughes 				wchar[i] = c & 0xff;
418*d5c9a868SElliott Hughes 			else
419*d5c9a868SElliott Hughes 				wchar[i] = '_';
420*d5c9a868SElliott Hughes 			memset(&ps, 0, sizeof(ps));
421*d5c9a868SElliott Hughes 			r=1;
422*d5c9a868SElliott Hughes 		}
423*d5c9a868SElliott Hughes 		if(r == 0)
424*d5c9a868SElliott Hughes 			break;
425*d5c9a868SElliott Hughes 		native += r;
426*d5c9a868SElliott Hughes 	}
427*d5c9a868SElliott Hughes 	if(mangled && ((end && native < end) || (!end && *native &&  i == len)))
428*d5c9a868SElliott Hughes 		*mangled |= 3;
429*d5c9a868SElliott Hughes 	wchar[i]='\0';
430*d5c9a868SElliott Hughes 	return i;
431*d5c9a868SElliott Hughes }
432*d5c9a868SElliott Hughes 
433