xref: /aosp_15_r20/external/libcups/cups/transcode.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
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