1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker * Transcoding support for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker *
4*5e7646d2SAndroid Build Coastguard Worker * Copyright 2007-2014 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker * Copyright 1997-2007 by Easy Software Products.
6*5e7646d2SAndroid Build Coastguard Worker *
7*5e7646d2SAndroid Build Coastguard Worker * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8*5e7646d2SAndroid Build Coastguard Worker */
9*5e7646d2SAndroid Build Coastguard Worker
10*5e7646d2SAndroid Build Coastguard Worker /*
11*5e7646d2SAndroid Build Coastguard Worker * Include necessary headers...
12*5e7646d2SAndroid Build Coastguard Worker */
13*5e7646d2SAndroid Build Coastguard Worker
14*5e7646d2SAndroid Build Coastguard Worker #include "cups-private.h"
15*5e7646d2SAndroid Build Coastguard Worker #include "debug-internal.h"
16*5e7646d2SAndroid Build Coastguard Worker #include <limits.h>
17*5e7646d2SAndroid Build Coastguard Worker #include <time.h>
18*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_ICONV_H
19*5e7646d2SAndroid Build Coastguard Worker # include <iconv.h>
20*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_ICONV_H */
21*5e7646d2SAndroid Build Coastguard Worker
22*5e7646d2SAndroid Build Coastguard Worker
23*5e7646d2SAndroid Build Coastguard Worker /*
24*5e7646d2SAndroid Build Coastguard Worker * Local globals...
25*5e7646d2SAndroid Build Coastguard Worker */
26*5e7646d2SAndroid Build Coastguard Worker
27*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_ICONV_H
28*5e7646d2SAndroid Build Coastguard Worker static _cups_mutex_t map_mutex = _CUPS_MUTEX_INITIALIZER;
29*5e7646d2SAndroid Build Coastguard Worker /* Mutex to control access to maps */
30*5e7646d2SAndroid Build Coastguard Worker static iconv_t map_from_utf8 = (iconv_t)-1;
31*5e7646d2SAndroid Build Coastguard Worker /* Convert from UTF-8 to charset */
32*5e7646d2SAndroid Build Coastguard Worker static iconv_t map_to_utf8 = (iconv_t)-1;
33*5e7646d2SAndroid Build Coastguard Worker /* Convert from charset to UTF-8 */
34*5e7646d2SAndroid Build Coastguard Worker static cups_encoding_t map_encoding = CUPS_AUTO_ENCODING;
35*5e7646d2SAndroid Build Coastguard Worker /* Which charset is cached */
36*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_ICONV_H */
37*5e7646d2SAndroid Build Coastguard Worker
38*5e7646d2SAndroid Build Coastguard Worker
39*5e7646d2SAndroid Build Coastguard Worker /*
40*5e7646d2SAndroid Build Coastguard Worker * '_cupsCharmapFlush()' - Flush all character set maps out of cache.
41*5e7646d2SAndroid Build Coastguard Worker */
42*5e7646d2SAndroid Build Coastguard Worker
43*5e7646d2SAndroid Build Coastguard Worker void
_cupsCharmapFlush(void)44*5e7646d2SAndroid Build Coastguard Worker _cupsCharmapFlush(void)
45*5e7646d2SAndroid Build Coastguard Worker {
46*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_ICONV_H
47*5e7646d2SAndroid Build Coastguard Worker if (map_from_utf8 != (iconv_t)-1)
48*5e7646d2SAndroid Build Coastguard Worker {
49*5e7646d2SAndroid Build Coastguard Worker iconv_close(map_from_utf8);
50*5e7646d2SAndroid Build Coastguard Worker map_from_utf8 = (iconv_t)-1;
51*5e7646d2SAndroid Build Coastguard Worker }
52*5e7646d2SAndroid Build Coastguard Worker
53*5e7646d2SAndroid Build Coastguard Worker if (map_to_utf8 != (iconv_t)-1)
54*5e7646d2SAndroid Build Coastguard Worker {
55*5e7646d2SAndroid Build Coastguard Worker iconv_close(map_to_utf8);
56*5e7646d2SAndroid Build Coastguard Worker map_to_utf8 = (iconv_t)-1;
57*5e7646d2SAndroid Build Coastguard Worker }
58*5e7646d2SAndroid Build Coastguard Worker
59*5e7646d2SAndroid Build Coastguard Worker map_encoding = CUPS_AUTO_ENCODING;
60*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_ICONV_H */
61*5e7646d2SAndroid Build Coastguard Worker }
62*5e7646d2SAndroid Build Coastguard Worker
63*5e7646d2SAndroid Build Coastguard Worker
64*5e7646d2SAndroid Build Coastguard Worker /*
65*5e7646d2SAndroid Build Coastguard Worker * 'cupsCharsetToUTF8()' - Convert legacy character set to UTF-8.
66*5e7646d2SAndroid Build Coastguard Worker */
67*5e7646d2SAndroid Build Coastguard Worker
68*5e7646d2SAndroid Build Coastguard Worker int /* O - Count or -1 on error */
cupsCharsetToUTF8(cups_utf8_t * dest,const char * src,const int maxout,const cups_encoding_t encoding)69*5e7646d2SAndroid Build Coastguard Worker cupsCharsetToUTF8(
70*5e7646d2SAndroid Build Coastguard Worker cups_utf8_t *dest, /* O - Target string */
71*5e7646d2SAndroid Build Coastguard Worker const char *src, /* I - Source string */
72*5e7646d2SAndroid Build Coastguard Worker const int maxout, /* I - Max output */
73*5e7646d2SAndroid Build Coastguard Worker const cups_encoding_t encoding) /* I - Encoding */
74*5e7646d2SAndroid Build Coastguard Worker {
75*5e7646d2SAndroid Build Coastguard Worker cups_utf8_t *destptr; /* Pointer into UTF-8 buffer */
76*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_ICONV_H
77*5e7646d2SAndroid Build Coastguard Worker size_t srclen, /* Length of source string */
78*5e7646d2SAndroid Build Coastguard Worker outBytesLeft; /* Bytes remaining in output buffer */
79*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_ICONV_H */
80*5e7646d2SAndroid Build Coastguard Worker
81*5e7646d2SAndroid Build Coastguard Worker
82*5e7646d2SAndroid Build Coastguard Worker /*
83*5e7646d2SAndroid Build Coastguard Worker * Check for valid arguments...
84*5e7646d2SAndroid Build Coastguard Worker */
85*5e7646d2SAndroid Build Coastguard Worker
86*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("2cupsCharsetToUTF8(dest=%p, src=\"%s\", maxout=%d, encoding=%d)", (void *)dest, src, maxout, encoding));
87*5e7646d2SAndroid Build Coastguard Worker
88*5e7646d2SAndroid Build Coastguard Worker if (!dest || !src || maxout < 1)
89*5e7646d2SAndroid Build Coastguard Worker {
90*5e7646d2SAndroid Build Coastguard Worker if (dest)
91*5e7646d2SAndroid Build Coastguard Worker *dest = '\0';
92*5e7646d2SAndroid Build Coastguard Worker
93*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsCharsetToUTF8: Bad arguments, returning -1");
94*5e7646d2SAndroid Build Coastguard Worker return (-1);
95*5e7646d2SAndroid Build Coastguard Worker }
96*5e7646d2SAndroid Build Coastguard Worker
97*5e7646d2SAndroid Build Coastguard Worker /*
98*5e7646d2SAndroid Build Coastguard Worker * Handle identity conversions...
99*5e7646d2SAndroid Build Coastguard Worker */
100*5e7646d2SAndroid Build Coastguard Worker
101*5e7646d2SAndroid Build Coastguard Worker if (encoding == CUPS_UTF8 || encoding <= CUPS_US_ASCII ||
102*5e7646d2SAndroid Build Coastguard Worker encoding >= CUPS_ENCODING_VBCS_END)
103*5e7646d2SAndroid Build Coastguard Worker {
104*5e7646d2SAndroid Build Coastguard Worker strlcpy((char *)dest, src, (size_t)maxout);
105*5e7646d2SAndroid Build Coastguard Worker return ((int)strlen((char *)dest));
106*5e7646d2SAndroid Build Coastguard Worker }
107*5e7646d2SAndroid Build Coastguard Worker
108*5e7646d2SAndroid Build Coastguard Worker /*
109*5e7646d2SAndroid Build Coastguard Worker * Handle ISO-8859-1 to UTF-8 directly...
110*5e7646d2SAndroid Build Coastguard Worker */
111*5e7646d2SAndroid Build Coastguard Worker
112*5e7646d2SAndroid Build Coastguard Worker destptr = dest;
113*5e7646d2SAndroid Build Coastguard Worker
114*5e7646d2SAndroid Build Coastguard Worker if (encoding == CUPS_ISO8859_1)
115*5e7646d2SAndroid Build Coastguard Worker {
116*5e7646d2SAndroid Build Coastguard Worker int ch; /* Character from string */
117*5e7646d2SAndroid Build Coastguard Worker cups_utf8_t *destend; /* End of UTF-8 buffer */
118*5e7646d2SAndroid Build Coastguard Worker
119*5e7646d2SAndroid Build Coastguard Worker
120*5e7646d2SAndroid Build Coastguard Worker destend = dest + maxout - 2;
121*5e7646d2SAndroid Build Coastguard Worker
122*5e7646d2SAndroid Build Coastguard Worker while (*src && destptr < destend)
123*5e7646d2SAndroid Build Coastguard Worker {
124*5e7646d2SAndroid Build Coastguard Worker ch = *src++ & 255;
125*5e7646d2SAndroid Build Coastguard Worker
126*5e7646d2SAndroid Build Coastguard Worker if (ch & 128)
127*5e7646d2SAndroid Build Coastguard Worker {
128*5e7646d2SAndroid Build Coastguard Worker *destptr++ = (cups_utf8_t)(0xc0 | (ch >> 6));
129*5e7646d2SAndroid Build Coastguard Worker *destptr++ = (cups_utf8_t)(0x80 | (ch & 0x3f));
130*5e7646d2SAndroid Build Coastguard Worker }
131*5e7646d2SAndroid Build Coastguard Worker else
132*5e7646d2SAndroid Build Coastguard Worker *destptr++ = (cups_utf8_t)ch;
133*5e7646d2SAndroid Build Coastguard Worker }
134*5e7646d2SAndroid Build Coastguard Worker
135*5e7646d2SAndroid Build Coastguard Worker *destptr = '\0';
136*5e7646d2SAndroid Build Coastguard Worker
137*5e7646d2SAndroid Build Coastguard Worker return ((int)(destptr - dest));
138*5e7646d2SAndroid Build Coastguard Worker }
139*5e7646d2SAndroid Build Coastguard Worker
140*5e7646d2SAndroid Build Coastguard Worker /*
141*5e7646d2SAndroid Build Coastguard Worker * Convert input legacy charset to UTF-8...
142*5e7646d2SAndroid Build Coastguard Worker */
143*5e7646d2SAndroid Build Coastguard Worker
144*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_ICONV_H
145*5e7646d2SAndroid Build Coastguard Worker _cupsMutexLock(&map_mutex);
146*5e7646d2SAndroid Build Coastguard Worker
147*5e7646d2SAndroid Build Coastguard Worker if (map_encoding != encoding)
148*5e7646d2SAndroid Build Coastguard Worker {
149*5e7646d2SAndroid Build Coastguard Worker char toset[1024]; /* Destination character set */
150*5e7646d2SAndroid Build Coastguard Worker
151*5e7646d2SAndroid Build Coastguard Worker _cupsCharmapFlush();
152*5e7646d2SAndroid Build Coastguard Worker
153*5e7646d2SAndroid Build Coastguard Worker snprintf(toset, sizeof(toset), "%s//IGNORE", _cupsEncodingName(encoding));
154*5e7646d2SAndroid Build Coastguard Worker
155*5e7646d2SAndroid Build Coastguard Worker map_encoding = encoding;
156*5e7646d2SAndroid Build Coastguard Worker map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8");
157*5e7646d2SAndroid Build Coastguard Worker map_to_utf8 = iconv_open("UTF-8", toset);
158*5e7646d2SAndroid Build Coastguard Worker }
159*5e7646d2SAndroid Build Coastguard Worker
160*5e7646d2SAndroid Build Coastguard Worker if (map_to_utf8 != (iconv_t)-1)
161*5e7646d2SAndroid Build Coastguard Worker {
162*5e7646d2SAndroid Build Coastguard Worker char *altdestptr = (char *)dest; /* Silence bogus GCC type-punned */
163*5e7646d2SAndroid Build Coastguard Worker
164*5e7646d2SAndroid Build Coastguard Worker srclen = strlen(src);
165*5e7646d2SAndroid Build Coastguard Worker outBytesLeft = (size_t)maxout - 1;
166*5e7646d2SAndroid Build Coastguard Worker
167*5e7646d2SAndroid Build Coastguard Worker iconv(map_to_utf8, (char **)&src, &srclen, &altdestptr, &outBytesLeft);
168*5e7646d2SAndroid Build Coastguard Worker *altdestptr = '\0';
169*5e7646d2SAndroid Build Coastguard Worker
170*5e7646d2SAndroid Build Coastguard Worker _cupsMutexUnlock(&map_mutex);
171*5e7646d2SAndroid Build Coastguard Worker
172*5e7646d2SAndroid Build Coastguard Worker return ((int)(altdestptr - (char *)dest));
173*5e7646d2SAndroid Build Coastguard Worker }
174*5e7646d2SAndroid Build Coastguard Worker
175*5e7646d2SAndroid Build Coastguard Worker _cupsMutexUnlock(&map_mutex);
176*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_ICONV_H */
177*5e7646d2SAndroid Build Coastguard Worker
178*5e7646d2SAndroid Build Coastguard Worker /*
179*5e7646d2SAndroid Build Coastguard Worker * No iconv() support, so error out...
180*5e7646d2SAndroid Build Coastguard Worker */
181*5e7646d2SAndroid Build Coastguard Worker
182*5e7646d2SAndroid Build Coastguard Worker *destptr = '\0';
183*5e7646d2SAndroid Build Coastguard Worker
184*5e7646d2SAndroid Build Coastguard Worker return (-1);
185*5e7646d2SAndroid Build Coastguard Worker }
186*5e7646d2SAndroid Build Coastguard Worker
187*5e7646d2SAndroid Build Coastguard Worker
188*5e7646d2SAndroid Build Coastguard Worker /*
189*5e7646d2SAndroid Build Coastguard Worker * 'cupsUTF8ToCharset()' - Convert UTF-8 to legacy character set.
190*5e7646d2SAndroid Build Coastguard Worker */
191*5e7646d2SAndroid Build Coastguard Worker
192*5e7646d2SAndroid Build Coastguard Worker int /* O - Count or -1 on error */
cupsUTF8ToCharset(char * dest,const cups_utf8_t * src,const int maxout,const cups_encoding_t encoding)193*5e7646d2SAndroid Build Coastguard Worker cupsUTF8ToCharset(
194*5e7646d2SAndroid Build Coastguard Worker char *dest, /* O - Target string */
195*5e7646d2SAndroid Build Coastguard Worker const cups_utf8_t *src, /* I - Source string */
196*5e7646d2SAndroid Build Coastguard Worker const int maxout, /* I - Max output */
197*5e7646d2SAndroid Build Coastguard Worker const cups_encoding_t encoding) /* I - Encoding */
198*5e7646d2SAndroid Build Coastguard Worker {
199*5e7646d2SAndroid Build Coastguard Worker char *destptr; /* Pointer into destination */
200*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_ICONV_H
201*5e7646d2SAndroid Build Coastguard Worker size_t srclen, /* Length of source string */
202*5e7646d2SAndroid Build Coastguard Worker outBytesLeft; /* Bytes remaining in output buffer */
203*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_ICONV_H */
204*5e7646d2SAndroid Build Coastguard Worker
205*5e7646d2SAndroid Build Coastguard Worker
206*5e7646d2SAndroid Build Coastguard Worker /*
207*5e7646d2SAndroid Build Coastguard Worker * Check for valid arguments...
208*5e7646d2SAndroid Build Coastguard Worker */
209*5e7646d2SAndroid Build Coastguard Worker
210*5e7646d2SAndroid Build Coastguard Worker if (!dest || !src || maxout < 1)
211*5e7646d2SAndroid Build Coastguard Worker {
212*5e7646d2SAndroid Build Coastguard Worker if (dest)
213*5e7646d2SAndroid Build Coastguard Worker *dest = '\0';
214*5e7646d2SAndroid Build Coastguard Worker
215*5e7646d2SAndroid Build Coastguard Worker return (-1);
216*5e7646d2SAndroid Build Coastguard Worker }
217*5e7646d2SAndroid Build Coastguard Worker
218*5e7646d2SAndroid Build Coastguard Worker /*
219*5e7646d2SAndroid Build Coastguard Worker * Handle identity conversions...
220*5e7646d2SAndroid Build Coastguard Worker */
221*5e7646d2SAndroid Build Coastguard Worker
222*5e7646d2SAndroid Build Coastguard Worker if (encoding == CUPS_UTF8 ||
223*5e7646d2SAndroid Build Coastguard Worker encoding >= CUPS_ENCODING_VBCS_END)
224*5e7646d2SAndroid Build Coastguard Worker {
225*5e7646d2SAndroid Build Coastguard Worker strlcpy(dest, (char *)src, (size_t)maxout);
226*5e7646d2SAndroid Build Coastguard Worker return ((int)strlen(dest));
227*5e7646d2SAndroid Build Coastguard Worker }
228*5e7646d2SAndroid Build Coastguard Worker
229*5e7646d2SAndroid Build Coastguard Worker /*
230*5e7646d2SAndroid Build Coastguard Worker * Handle UTF-8 to ISO-8859-1 directly...
231*5e7646d2SAndroid Build Coastguard Worker */
232*5e7646d2SAndroid Build Coastguard Worker
233*5e7646d2SAndroid Build Coastguard Worker destptr = dest;
234*5e7646d2SAndroid Build Coastguard Worker
235*5e7646d2SAndroid Build Coastguard Worker if (encoding == CUPS_ISO8859_1 || encoding <= CUPS_US_ASCII)
236*5e7646d2SAndroid Build Coastguard Worker {
237*5e7646d2SAndroid Build Coastguard Worker int ch, /* Character from string */
238*5e7646d2SAndroid Build Coastguard Worker maxch; /* Maximum character for charset */
239*5e7646d2SAndroid Build Coastguard Worker char *destend; /* End of ISO-8859-1 buffer */
240*5e7646d2SAndroid Build Coastguard Worker
241*5e7646d2SAndroid Build Coastguard Worker maxch = encoding == CUPS_ISO8859_1 ? 256 : 128;
242*5e7646d2SAndroid Build Coastguard Worker destend = dest + maxout - 1;
243*5e7646d2SAndroid Build Coastguard Worker
244*5e7646d2SAndroid Build Coastguard Worker while (*src && destptr < destend)
245*5e7646d2SAndroid Build Coastguard Worker {
246*5e7646d2SAndroid Build Coastguard Worker ch = *src++;
247*5e7646d2SAndroid Build Coastguard Worker
248*5e7646d2SAndroid Build Coastguard Worker if ((ch & 0xe0) == 0xc0)
249*5e7646d2SAndroid Build Coastguard Worker {
250*5e7646d2SAndroid Build Coastguard Worker ch = ((ch & 0x1f) << 6) | (*src++ & 0x3f);
251*5e7646d2SAndroid Build Coastguard Worker
252*5e7646d2SAndroid Build Coastguard Worker if (ch < maxch)
253*5e7646d2SAndroid Build Coastguard Worker *destptr++ = (char)ch;
254*5e7646d2SAndroid Build Coastguard Worker else
255*5e7646d2SAndroid Build Coastguard Worker *destptr++ = '?';
256*5e7646d2SAndroid Build Coastguard Worker }
257*5e7646d2SAndroid Build Coastguard Worker else if ((ch & 0xf0) == 0xe0 ||
258*5e7646d2SAndroid Build Coastguard Worker (ch & 0xf8) == 0xf0)
259*5e7646d2SAndroid Build Coastguard Worker *destptr++ = '?';
260*5e7646d2SAndroid Build Coastguard Worker else if (!(ch & 0x80))
261*5e7646d2SAndroid Build Coastguard Worker *destptr++ = (char)ch;
262*5e7646d2SAndroid Build Coastguard Worker }
263*5e7646d2SAndroid Build Coastguard Worker
264*5e7646d2SAndroid Build Coastguard Worker *destptr = '\0';
265*5e7646d2SAndroid Build Coastguard Worker
266*5e7646d2SAndroid Build Coastguard Worker return ((int)(destptr - dest));
267*5e7646d2SAndroid Build Coastguard Worker }
268*5e7646d2SAndroid Build Coastguard Worker
269*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_ICONV_H
270*5e7646d2SAndroid Build Coastguard Worker /*
271*5e7646d2SAndroid Build Coastguard Worker * Convert input UTF-8 to legacy charset...
272*5e7646d2SAndroid Build Coastguard Worker */
273*5e7646d2SAndroid Build Coastguard Worker
274*5e7646d2SAndroid Build Coastguard Worker _cupsMutexLock(&map_mutex);
275*5e7646d2SAndroid Build Coastguard Worker
276*5e7646d2SAndroid Build Coastguard Worker if (map_encoding != encoding)
277*5e7646d2SAndroid Build Coastguard Worker {
278*5e7646d2SAndroid Build Coastguard Worker char toset[1024]; /* Destination character set */
279*5e7646d2SAndroid Build Coastguard Worker
280*5e7646d2SAndroid Build Coastguard Worker _cupsCharmapFlush();
281*5e7646d2SAndroid Build Coastguard Worker
282*5e7646d2SAndroid Build Coastguard Worker snprintf(toset, sizeof(toset), "%s//IGNORE", _cupsEncodingName(encoding));
283*5e7646d2SAndroid Build Coastguard Worker
284*5e7646d2SAndroid Build Coastguard Worker map_encoding = encoding;
285*5e7646d2SAndroid Build Coastguard Worker map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8");
286*5e7646d2SAndroid Build Coastguard Worker map_to_utf8 = iconv_open("UTF-8", toset);
287*5e7646d2SAndroid Build Coastguard Worker }
288*5e7646d2SAndroid Build Coastguard Worker
289*5e7646d2SAndroid Build Coastguard Worker if (map_from_utf8 != (iconv_t)-1)
290*5e7646d2SAndroid Build Coastguard Worker {
291*5e7646d2SAndroid Build Coastguard Worker char *altsrc = (char *)src; /* Silence bogus GCC type-punned */
292*5e7646d2SAndroid Build Coastguard Worker
293*5e7646d2SAndroid Build Coastguard Worker srclen = strlen((char *)src);
294*5e7646d2SAndroid Build Coastguard Worker outBytesLeft = (size_t)maxout - 1;
295*5e7646d2SAndroid Build Coastguard Worker
296*5e7646d2SAndroid Build Coastguard Worker iconv(map_from_utf8, &altsrc, &srclen, &destptr, &outBytesLeft);
297*5e7646d2SAndroid Build Coastguard Worker *destptr = '\0';
298*5e7646d2SAndroid Build Coastguard Worker
299*5e7646d2SAndroid Build Coastguard Worker _cupsMutexUnlock(&map_mutex);
300*5e7646d2SAndroid Build Coastguard Worker
301*5e7646d2SAndroid Build Coastguard Worker return ((int)(destptr - dest));
302*5e7646d2SAndroid Build Coastguard Worker }
303*5e7646d2SAndroid Build Coastguard Worker
304*5e7646d2SAndroid Build Coastguard Worker _cupsMutexUnlock(&map_mutex);
305*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_ICONV_H */
306*5e7646d2SAndroid Build Coastguard Worker
307*5e7646d2SAndroid Build Coastguard Worker /*
308*5e7646d2SAndroid Build Coastguard Worker * No iconv() support, so error out...
309*5e7646d2SAndroid Build Coastguard Worker */
310*5e7646d2SAndroid Build Coastguard Worker
311*5e7646d2SAndroid Build Coastguard Worker *destptr = '\0';
312*5e7646d2SAndroid Build Coastguard Worker
313*5e7646d2SAndroid Build Coastguard Worker return (-1);
314*5e7646d2SAndroid Build Coastguard Worker }
315*5e7646d2SAndroid Build Coastguard Worker
316*5e7646d2SAndroid Build Coastguard Worker
317*5e7646d2SAndroid Build Coastguard Worker /*
318*5e7646d2SAndroid Build Coastguard Worker * 'cupsUTF8ToUTF32()' - Convert UTF-8 to UTF-32.
319*5e7646d2SAndroid Build Coastguard Worker *
320*5e7646d2SAndroid Build Coastguard Worker * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows...
321*5e7646d2SAndroid Build Coastguard Worker *
322*5e7646d2SAndroid Build Coastguard Worker * UTF-32 char UTF-8 char(s)
323*5e7646d2SAndroid Build Coastguard Worker * --------------------------------------------------
324*5e7646d2SAndroid Build Coastguard Worker * 0 to 127 = 0xxxxxxx (US-ASCII)
325*5e7646d2SAndroid Build Coastguard Worker * 128 to 2047 = 110xxxxx 10yyyyyy
326*5e7646d2SAndroid Build Coastguard Worker * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz
327*5e7646d2SAndroid Build Coastguard Worker * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx
328*5e7646d2SAndroid Build Coastguard Worker *
329*5e7646d2SAndroid Build Coastguard Worker * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4,
330*5e7646d2SAndroid Build Coastguard Worker * which would convert to five- or six-octet UTF-8 sequences...
331*5e7646d2SAndroid Build Coastguard Worker */
332*5e7646d2SAndroid Build Coastguard Worker
333*5e7646d2SAndroid Build Coastguard Worker int /* O - Count or -1 on error */
cupsUTF8ToUTF32(cups_utf32_t * dest,const cups_utf8_t * src,const int maxout)334*5e7646d2SAndroid Build Coastguard Worker cupsUTF8ToUTF32(
335*5e7646d2SAndroid Build Coastguard Worker cups_utf32_t *dest, /* O - Target string */
336*5e7646d2SAndroid Build Coastguard Worker const cups_utf8_t *src, /* I - Source string */
337*5e7646d2SAndroid Build Coastguard Worker const int maxout) /* I - Max output */
338*5e7646d2SAndroid Build Coastguard Worker {
339*5e7646d2SAndroid Build Coastguard Worker int i; /* Looping variable */
340*5e7646d2SAndroid Build Coastguard Worker cups_utf8_t ch; /* Character value */
341*5e7646d2SAndroid Build Coastguard Worker cups_utf8_t next; /* Next character value */
342*5e7646d2SAndroid Build Coastguard Worker cups_utf32_t ch32; /* UTF-32 character value */
343*5e7646d2SAndroid Build Coastguard Worker
344*5e7646d2SAndroid Build Coastguard Worker
345*5e7646d2SAndroid Build Coastguard Worker /*
346*5e7646d2SAndroid Build Coastguard Worker * Check for valid arguments and clear output...
347*5e7646d2SAndroid Build Coastguard Worker */
348*5e7646d2SAndroid Build Coastguard Worker
349*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("2cupsUTF8ToUTF32(dest=%p, src=\"%s\", maxout=%d)", (void *)dest, src, maxout));
350*5e7646d2SAndroid Build Coastguard Worker
351*5e7646d2SAndroid Build Coastguard Worker if (dest)
352*5e7646d2SAndroid Build Coastguard Worker *dest = 0;
353*5e7646d2SAndroid Build Coastguard Worker
354*5e7646d2SAndroid Build Coastguard Worker if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING)
355*5e7646d2SAndroid Build Coastguard Worker {
356*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad arguments)");
357*5e7646d2SAndroid Build Coastguard Worker
358*5e7646d2SAndroid Build Coastguard Worker return (-1);
359*5e7646d2SAndroid Build Coastguard Worker }
360*5e7646d2SAndroid Build Coastguard Worker
361*5e7646d2SAndroid Build Coastguard Worker /*
362*5e7646d2SAndroid Build Coastguard Worker * Convert input UTF-8 to output UTF-32...
363*5e7646d2SAndroid Build Coastguard Worker */
364*5e7646d2SAndroid Build Coastguard Worker
365*5e7646d2SAndroid Build Coastguard Worker for (i = maxout - 1; *src && i > 0; i --)
366*5e7646d2SAndroid Build Coastguard Worker {
367*5e7646d2SAndroid Build Coastguard Worker ch = *src++;
368*5e7646d2SAndroid Build Coastguard Worker
369*5e7646d2SAndroid Build Coastguard Worker /*
370*5e7646d2SAndroid Build Coastguard Worker * Convert UTF-8 character(s) to UTF-32 character...
371*5e7646d2SAndroid Build Coastguard Worker */
372*5e7646d2SAndroid Build Coastguard Worker
373*5e7646d2SAndroid Build Coastguard Worker if (!(ch & 0x80))
374*5e7646d2SAndroid Build Coastguard Worker {
375*5e7646d2SAndroid Build Coastguard Worker /*
376*5e7646d2SAndroid Build Coastguard Worker * One-octet UTF-8 <= 127 (US-ASCII)...
377*5e7646d2SAndroid Build Coastguard Worker */
378*5e7646d2SAndroid Build Coastguard Worker
379*5e7646d2SAndroid Build Coastguard Worker *dest++ = ch;
380*5e7646d2SAndroid Build Coastguard Worker
381*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF8ToUTF32: %02x => %08X", src[-1], ch));
382*5e7646d2SAndroid Build Coastguard Worker continue;
383*5e7646d2SAndroid Build Coastguard Worker }
384*5e7646d2SAndroid Build Coastguard Worker else if ((ch & 0xe0) == 0xc0)
385*5e7646d2SAndroid Build Coastguard Worker {
386*5e7646d2SAndroid Build Coastguard Worker /*
387*5e7646d2SAndroid Build Coastguard Worker * Two-octet UTF-8 <= 2047 (Latin-x)...
388*5e7646d2SAndroid Build Coastguard Worker */
389*5e7646d2SAndroid Build Coastguard Worker
390*5e7646d2SAndroid Build Coastguard Worker next = *src++;
391*5e7646d2SAndroid Build Coastguard Worker if ((next & 0xc0) != 0x80)
392*5e7646d2SAndroid Build Coastguard Worker {
393*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
394*5e7646d2SAndroid Build Coastguard Worker
395*5e7646d2SAndroid Build Coastguard Worker return (-1);
396*5e7646d2SAndroid Build Coastguard Worker }
397*5e7646d2SAndroid Build Coastguard Worker
398*5e7646d2SAndroid Build Coastguard Worker ch32 = (cups_utf32_t)((ch & 0x1f) << 6) | (cups_utf32_t)(next & 0x3f);
399*5e7646d2SAndroid Build Coastguard Worker
400*5e7646d2SAndroid Build Coastguard Worker /*
401*5e7646d2SAndroid Build Coastguard Worker * Check for non-shortest form (invalid UTF-8)...
402*5e7646d2SAndroid Build Coastguard Worker */
403*5e7646d2SAndroid Build Coastguard Worker
404*5e7646d2SAndroid Build Coastguard Worker if (ch32 < 0x80)
405*5e7646d2SAndroid Build Coastguard Worker {
406*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
407*5e7646d2SAndroid Build Coastguard Worker
408*5e7646d2SAndroid Build Coastguard Worker return (-1);
409*5e7646d2SAndroid Build Coastguard Worker }
410*5e7646d2SAndroid Build Coastguard Worker
411*5e7646d2SAndroid Build Coastguard Worker *dest++ = ch32;
412*5e7646d2SAndroid Build Coastguard Worker
413*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x => %08X",
414*5e7646d2SAndroid Build Coastguard Worker src[-2], src[-1], (unsigned)ch32));
415*5e7646d2SAndroid Build Coastguard Worker }
416*5e7646d2SAndroid Build Coastguard Worker else if ((ch & 0xf0) == 0xe0)
417*5e7646d2SAndroid Build Coastguard Worker {
418*5e7646d2SAndroid Build Coastguard Worker /*
419*5e7646d2SAndroid Build Coastguard Worker * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)...
420*5e7646d2SAndroid Build Coastguard Worker */
421*5e7646d2SAndroid Build Coastguard Worker
422*5e7646d2SAndroid Build Coastguard Worker next = *src++;
423*5e7646d2SAndroid Build Coastguard Worker if ((next & 0xc0) != 0x80)
424*5e7646d2SAndroid Build Coastguard Worker {
425*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
426*5e7646d2SAndroid Build Coastguard Worker
427*5e7646d2SAndroid Build Coastguard Worker return (-1);
428*5e7646d2SAndroid Build Coastguard Worker }
429*5e7646d2SAndroid Build Coastguard Worker
430*5e7646d2SAndroid Build Coastguard Worker ch32 = (cups_utf32_t)((ch & 0x0f) << 6) | (cups_utf32_t)(next & 0x3f);
431*5e7646d2SAndroid Build Coastguard Worker
432*5e7646d2SAndroid Build Coastguard Worker next = *src++;
433*5e7646d2SAndroid Build Coastguard Worker if ((next & 0xc0) != 0x80)
434*5e7646d2SAndroid Build Coastguard Worker {
435*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
436*5e7646d2SAndroid Build Coastguard Worker
437*5e7646d2SAndroid Build Coastguard Worker return (-1);
438*5e7646d2SAndroid Build Coastguard Worker }
439*5e7646d2SAndroid Build Coastguard Worker
440*5e7646d2SAndroid Build Coastguard Worker ch32 = (ch32 << 6) | (cups_utf32_t)(next & 0x3f);
441*5e7646d2SAndroid Build Coastguard Worker
442*5e7646d2SAndroid Build Coastguard Worker /*
443*5e7646d2SAndroid Build Coastguard Worker * Check for non-shortest form (invalid UTF-8)...
444*5e7646d2SAndroid Build Coastguard Worker */
445*5e7646d2SAndroid Build Coastguard Worker
446*5e7646d2SAndroid Build Coastguard Worker if (ch32 < 0x800)
447*5e7646d2SAndroid Build Coastguard Worker {
448*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
449*5e7646d2SAndroid Build Coastguard Worker
450*5e7646d2SAndroid Build Coastguard Worker return (-1);
451*5e7646d2SAndroid Build Coastguard Worker }
452*5e7646d2SAndroid Build Coastguard Worker
453*5e7646d2SAndroid Build Coastguard Worker *dest++ = ch32;
454*5e7646d2SAndroid Build Coastguard Worker
455*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x %02x => %08X",
456*5e7646d2SAndroid Build Coastguard Worker src[-3], src[-2], src[-1], (unsigned)ch32));
457*5e7646d2SAndroid Build Coastguard Worker }
458*5e7646d2SAndroid Build Coastguard Worker else if ((ch & 0xf8) == 0xf0)
459*5e7646d2SAndroid Build Coastguard Worker {
460*5e7646d2SAndroid Build Coastguard Worker /*
461*5e7646d2SAndroid Build Coastguard Worker * Four-octet UTF-8...
462*5e7646d2SAndroid Build Coastguard Worker */
463*5e7646d2SAndroid Build Coastguard Worker
464*5e7646d2SAndroid Build Coastguard Worker next = *src++;
465*5e7646d2SAndroid Build Coastguard Worker if ((next & 0xc0) != 0x80)
466*5e7646d2SAndroid Build Coastguard Worker {
467*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
468*5e7646d2SAndroid Build Coastguard Worker
469*5e7646d2SAndroid Build Coastguard Worker return (-1);
470*5e7646d2SAndroid Build Coastguard Worker }
471*5e7646d2SAndroid Build Coastguard Worker
472*5e7646d2SAndroid Build Coastguard Worker ch32 = (cups_utf32_t)((ch & 0x07) << 6) | (cups_utf32_t)(next & 0x3f);
473*5e7646d2SAndroid Build Coastguard Worker
474*5e7646d2SAndroid Build Coastguard Worker next = *src++;
475*5e7646d2SAndroid Build Coastguard Worker if ((next & 0xc0) != 0x80)
476*5e7646d2SAndroid Build Coastguard Worker {
477*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
478*5e7646d2SAndroid Build Coastguard Worker
479*5e7646d2SAndroid Build Coastguard Worker return (-1);
480*5e7646d2SAndroid Build Coastguard Worker }
481*5e7646d2SAndroid Build Coastguard Worker
482*5e7646d2SAndroid Build Coastguard Worker ch32 = (ch32 << 6) | (cups_utf32_t)(next & 0x3f);
483*5e7646d2SAndroid Build Coastguard Worker
484*5e7646d2SAndroid Build Coastguard Worker next = *src++;
485*5e7646d2SAndroid Build Coastguard Worker if ((next & 0xc0) != 0x80)
486*5e7646d2SAndroid Build Coastguard Worker {
487*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
488*5e7646d2SAndroid Build Coastguard Worker
489*5e7646d2SAndroid Build Coastguard Worker return (-1);
490*5e7646d2SAndroid Build Coastguard Worker }
491*5e7646d2SAndroid Build Coastguard Worker
492*5e7646d2SAndroid Build Coastguard Worker ch32 = (ch32 << 6) | (cups_utf32_t)(next & 0x3f);
493*5e7646d2SAndroid Build Coastguard Worker
494*5e7646d2SAndroid Build Coastguard Worker /*
495*5e7646d2SAndroid Build Coastguard Worker * Check for non-shortest form (invalid UTF-8)...
496*5e7646d2SAndroid Build Coastguard Worker */
497*5e7646d2SAndroid Build Coastguard Worker
498*5e7646d2SAndroid Build Coastguard Worker if (ch32 < 0x10000)
499*5e7646d2SAndroid Build Coastguard Worker {
500*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
501*5e7646d2SAndroid Build Coastguard Worker
502*5e7646d2SAndroid Build Coastguard Worker return (-1);
503*5e7646d2SAndroid Build Coastguard Worker }
504*5e7646d2SAndroid Build Coastguard Worker
505*5e7646d2SAndroid Build Coastguard Worker *dest++ = ch32;
506*5e7646d2SAndroid Build Coastguard Worker
507*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x %02x %02x => %08X",
508*5e7646d2SAndroid Build Coastguard Worker src[-4], src[-3], src[-2], src[-1], (unsigned)ch32));
509*5e7646d2SAndroid Build Coastguard Worker }
510*5e7646d2SAndroid Build Coastguard Worker else
511*5e7646d2SAndroid Build Coastguard Worker {
512*5e7646d2SAndroid Build Coastguard Worker /*
513*5e7646d2SAndroid Build Coastguard Worker * More than 4-octet (invalid UTF-8 sequence)...
514*5e7646d2SAndroid Build Coastguard Worker */
515*5e7646d2SAndroid Build Coastguard Worker
516*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
517*5e7646d2SAndroid Build Coastguard Worker
518*5e7646d2SAndroid Build Coastguard Worker return (-1);
519*5e7646d2SAndroid Build Coastguard Worker }
520*5e7646d2SAndroid Build Coastguard Worker
521*5e7646d2SAndroid Build Coastguard Worker /*
522*5e7646d2SAndroid Build Coastguard Worker * Check for UTF-16 surrogate (illegal UTF-8)...
523*5e7646d2SAndroid Build Coastguard Worker */
524*5e7646d2SAndroid Build Coastguard Worker
525*5e7646d2SAndroid Build Coastguard Worker if (ch32 >= 0xd800 && ch32 <= 0xdfff)
526*5e7646d2SAndroid Build Coastguard Worker return (-1);
527*5e7646d2SAndroid Build Coastguard Worker }
528*5e7646d2SAndroid Build Coastguard Worker
529*5e7646d2SAndroid Build Coastguard Worker *dest = 0;
530*5e7646d2SAndroid Build Coastguard Worker
531*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("3cupsUTF8ToUTF32: Returning %d characters", maxout - 1 - i));
532*5e7646d2SAndroid Build Coastguard Worker
533*5e7646d2SAndroid Build Coastguard Worker return (maxout - 1 - i);
534*5e7646d2SAndroid Build Coastguard Worker }
535*5e7646d2SAndroid Build Coastguard Worker
536*5e7646d2SAndroid Build Coastguard Worker
537*5e7646d2SAndroid Build Coastguard Worker /*
538*5e7646d2SAndroid Build Coastguard Worker * 'cupsUTF32ToUTF8()' - Convert UTF-32 to UTF-8.
539*5e7646d2SAndroid Build Coastguard Worker *
540*5e7646d2SAndroid Build Coastguard Worker * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows...
541*5e7646d2SAndroid Build Coastguard Worker *
542*5e7646d2SAndroid Build Coastguard Worker * UTF-32 char UTF-8 char(s)
543*5e7646d2SAndroid Build Coastguard Worker * --------------------------------------------------
544*5e7646d2SAndroid Build Coastguard Worker * 0 to 127 = 0xxxxxxx (US-ASCII)
545*5e7646d2SAndroid Build Coastguard Worker * 128 to 2047 = 110xxxxx 10yyyyyy
546*5e7646d2SAndroid Build Coastguard Worker * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz
547*5e7646d2SAndroid Build Coastguard Worker * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx
548*5e7646d2SAndroid Build Coastguard Worker *
549*5e7646d2SAndroid Build Coastguard Worker * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4,
550*5e7646d2SAndroid Build Coastguard Worker * which would convert to five- or six-octet UTF-8 sequences...
551*5e7646d2SAndroid Build Coastguard Worker */
552*5e7646d2SAndroid Build Coastguard Worker
553*5e7646d2SAndroid Build Coastguard Worker int /* O - Count or -1 on error */
cupsUTF32ToUTF8(cups_utf8_t * dest,const cups_utf32_t * src,const int maxout)554*5e7646d2SAndroid Build Coastguard Worker cupsUTF32ToUTF8(
555*5e7646d2SAndroid Build Coastguard Worker cups_utf8_t *dest, /* O - Target string */
556*5e7646d2SAndroid Build Coastguard Worker const cups_utf32_t *src, /* I - Source string */
557*5e7646d2SAndroid Build Coastguard Worker const int maxout) /* I - Max output */
558*5e7646d2SAndroid Build Coastguard Worker {
559*5e7646d2SAndroid Build Coastguard Worker cups_utf8_t *start; /* Start of destination string */
560*5e7646d2SAndroid Build Coastguard Worker int i; /* Looping variable */
561*5e7646d2SAndroid Build Coastguard Worker int swap; /* Byte-swap input to output */
562*5e7646d2SAndroid Build Coastguard Worker cups_utf32_t ch; /* Character value */
563*5e7646d2SAndroid Build Coastguard Worker
564*5e7646d2SAndroid Build Coastguard Worker
565*5e7646d2SAndroid Build Coastguard Worker /*
566*5e7646d2SAndroid Build Coastguard Worker * Check for valid arguments and clear output...
567*5e7646d2SAndroid Build Coastguard Worker */
568*5e7646d2SAndroid Build Coastguard Worker
569*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("2cupsUTF32ToUTF8(dest=%p, src=%p, maxout=%d)", (void *)dest, (void *)src, maxout));
570*5e7646d2SAndroid Build Coastguard Worker
571*5e7646d2SAndroid Build Coastguard Worker if (dest)
572*5e7646d2SAndroid Build Coastguard Worker *dest = '\0';
573*5e7646d2SAndroid Build Coastguard Worker
574*5e7646d2SAndroid Build Coastguard Worker if (!dest || !src || maxout < 1)
575*5e7646d2SAndroid Build Coastguard Worker {
576*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (bad args)");
577*5e7646d2SAndroid Build Coastguard Worker
578*5e7646d2SAndroid Build Coastguard Worker return (-1);
579*5e7646d2SAndroid Build Coastguard Worker }
580*5e7646d2SAndroid Build Coastguard Worker
581*5e7646d2SAndroid Build Coastguard Worker /*
582*5e7646d2SAndroid Build Coastguard Worker * Check for leading BOM in UTF-32 and inverted BOM...
583*5e7646d2SAndroid Build Coastguard Worker */
584*5e7646d2SAndroid Build Coastguard Worker
585*5e7646d2SAndroid Build Coastguard Worker start = dest;
586*5e7646d2SAndroid Build Coastguard Worker swap = *src == 0xfffe0000;
587*5e7646d2SAndroid Build Coastguard Worker
588*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF32ToUTF8: swap=%d", swap));
589*5e7646d2SAndroid Build Coastguard Worker
590*5e7646d2SAndroid Build Coastguard Worker if (*src == 0xfffe0000 || *src == 0xfeff)
591*5e7646d2SAndroid Build Coastguard Worker src ++;
592*5e7646d2SAndroid Build Coastguard Worker
593*5e7646d2SAndroid Build Coastguard Worker /*
594*5e7646d2SAndroid Build Coastguard Worker * Convert input UTF-32 to output UTF-8...
595*5e7646d2SAndroid Build Coastguard Worker */
596*5e7646d2SAndroid Build Coastguard Worker
597*5e7646d2SAndroid Build Coastguard Worker for (i = maxout - 1; *src && i > 0;)
598*5e7646d2SAndroid Build Coastguard Worker {
599*5e7646d2SAndroid Build Coastguard Worker ch = *src++;
600*5e7646d2SAndroid Build Coastguard Worker
601*5e7646d2SAndroid Build Coastguard Worker /*
602*5e7646d2SAndroid Build Coastguard Worker * Byte swap input UTF-32, if necessary...
603*5e7646d2SAndroid Build Coastguard Worker * (only byte-swapping 24 of 32 bits)
604*5e7646d2SAndroid Build Coastguard Worker */
605*5e7646d2SAndroid Build Coastguard Worker
606*5e7646d2SAndroid Build Coastguard Worker if (swap)
607*5e7646d2SAndroid Build Coastguard Worker ch = ((ch >> 24) | ((ch >> 8) & 0xff00) | ((ch << 8) & 0xff0000));
608*5e7646d2SAndroid Build Coastguard Worker
609*5e7646d2SAndroid Build Coastguard Worker /*
610*5e7646d2SAndroid Build Coastguard Worker * Check for beyond Plane 16 (invalid UTF-32)...
611*5e7646d2SAndroid Build Coastguard Worker */
612*5e7646d2SAndroid Build Coastguard Worker
613*5e7646d2SAndroid Build Coastguard Worker if (ch > 0x10ffff)
614*5e7646d2SAndroid Build Coastguard Worker {
615*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (character out of range)");
616*5e7646d2SAndroid Build Coastguard Worker
617*5e7646d2SAndroid Build Coastguard Worker return (-1);
618*5e7646d2SAndroid Build Coastguard Worker }
619*5e7646d2SAndroid Build Coastguard Worker
620*5e7646d2SAndroid Build Coastguard Worker /*
621*5e7646d2SAndroid Build Coastguard Worker * Convert UTF-32 character to UTF-8 character(s)...
622*5e7646d2SAndroid Build Coastguard Worker */
623*5e7646d2SAndroid Build Coastguard Worker
624*5e7646d2SAndroid Build Coastguard Worker if (ch < 0x80)
625*5e7646d2SAndroid Build Coastguard Worker {
626*5e7646d2SAndroid Build Coastguard Worker /*
627*5e7646d2SAndroid Build Coastguard Worker * One-octet UTF-8 <= 127 (US-ASCII)...
628*5e7646d2SAndroid Build Coastguard Worker */
629*5e7646d2SAndroid Build Coastguard Worker
630*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)ch;
631*5e7646d2SAndroid Build Coastguard Worker i --;
632*5e7646d2SAndroid Build Coastguard Worker
633*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x", (unsigned)ch, dest[-1]));
634*5e7646d2SAndroid Build Coastguard Worker }
635*5e7646d2SAndroid Build Coastguard Worker else if (ch < 0x800)
636*5e7646d2SAndroid Build Coastguard Worker {
637*5e7646d2SAndroid Build Coastguard Worker /*
638*5e7646d2SAndroid Build Coastguard Worker * Two-octet UTF-8 <= 2047 (Latin-x)...
639*5e7646d2SAndroid Build Coastguard Worker */
640*5e7646d2SAndroid Build Coastguard Worker
641*5e7646d2SAndroid Build Coastguard Worker if (i < 2)
642*5e7646d2SAndroid Build Coastguard Worker {
643*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 2)");
644*5e7646d2SAndroid Build Coastguard Worker
645*5e7646d2SAndroid Build Coastguard Worker return (-1);
646*5e7646d2SAndroid Build Coastguard Worker }
647*5e7646d2SAndroid Build Coastguard Worker
648*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0xc0 | ((ch >> 6) & 0x1f));
649*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f));
650*5e7646d2SAndroid Build Coastguard Worker i -= 2;
651*5e7646d2SAndroid Build Coastguard Worker
652*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x", (unsigned)ch,
653*5e7646d2SAndroid Build Coastguard Worker dest[-2], dest[-1]));
654*5e7646d2SAndroid Build Coastguard Worker }
655*5e7646d2SAndroid Build Coastguard Worker else if (ch < 0x10000)
656*5e7646d2SAndroid Build Coastguard Worker {
657*5e7646d2SAndroid Build Coastguard Worker /*
658*5e7646d2SAndroid Build Coastguard Worker * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)...
659*5e7646d2SAndroid Build Coastguard Worker */
660*5e7646d2SAndroid Build Coastguard Worker
661*5e7646d2SAndroid Build Coastguard Worker if (i < 3)
662*5e7646d2SAndroid Build Coastguard Worker {
663*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 3)");
664*5e7646d2SAndroid Build Coastguard Worker
665*5e7646d2SAndroid Build Coastguard Worker return (-1);
666*5e7646d2SAndroid Build Coastguard Worker }
667*5e7646d2SAndroid Build Coastguard Worker
668*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0xe0 | ((ch >> 12) & 0x0f));
669*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0x80 | ((ch >> 6) & 0x3f));
670*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f));
671*5e7646d2SAndroid Build Coastguard Worker i -= 3;
672*5e7646d2SAndroid Build Coastguard Worker
673*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x %02x", (unsigned)ch,
674*5e7646d2SAndroid Build Coastguard Worker dest[-3], dest[-2], dest[-1]));
675*5e7646d2SAndroid Build Coastguard Worker }
676*5e7646d2SAndroid Build Coastguard Worker else
677*5e7646d2SAndroid Build Coastguard Worker {
678*5e7646d2SAndroid Build Coastguard Worker /*
679*5e7646d2SAndroid Build Coastguard Worker * Four-octet UTF-8...
680*5e7646d2SAndroid Build Coastguard Worker */
681*5e7646d2SAndroid Build Coastguard Worker
682*5e7646d2SAndroid Build Coastguard Worker if (i < 4)
683*5e7646d2SAndroid Build Coastguard Worker {
684*5e7646d2SAndroid Build Coastguard Worker DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 4)");
685*5e7646d2SAndroid Build Coastguard Worker
686*5e7646d2SAndroid Build Coastguard Worker return (-1);
687*5e7646d2SAndroid Build Coastguard Worker }
688*5e7646d2SAndroid Build Coastguard Worker
689*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0xf0 | ((ch >> 18) & 0x07));
690*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0x80 | ((ch >> 12) & 0x3f));
691*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0x80 | ((ch >> 6) & 0x3f));
692*5e7646d2SAndroid Build Coastguard Worker *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f));
693*5e7646d2SAndroid Build Coastguard Worker i -= 4;
694*5e7646d2SAndroid Build Coastguard Worker
695*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x %02x %02x",
696*5e7646d2SAndroid Build Coastguard Worker (unsigned)ch, dest[-4], dest[-3], dest[-2], dest[-1]));
697*5e7646d2SAndroid Build Coastguard Worker }
698*5e7646d2SAndroid Build Coastguard Worker }
699*5e7646d2SAndroid Build Coastguard Worker
700*5e7646d2SAndroid Build Coastguard Worker *dest = '\0';
701*5e7646d2SAndroid Build Coastguard Worker
702*5e7646d2SAndroid Build Coastguard Worker DEBUG_printf(("3cupsUTF32ToUTF8: Returning %d", (int)(dest - start)));
703*5e7646d2SAndroid Build Coastguard Worker
704*5e7646d2SAndroid Build Coastguard Worker return ((int)(dest - start));
705*5e7646d2SAndroid Build Coastguard Worker }
706