xref: /aosp_15_r20/external/libcups/ppdc/ppdc-catalog.cxx (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker //
2*5e7646d2SAndroid Build Coastguard Worker // Shared message catalog class for the CUPS PPD Compiler.
3*5e7646d2SAndroid Build Coastguard Worker //
4*5e7646d2SAndroid Build Coastguard Worker // Copyright 2007-2017 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker // Copyright 2002-2006 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 "ppdc-private.h"
15*5e7646d2SAndroid Build Coastguard Worker 
16*5e7646d2SAndroid Build Coastguard Worker 
17*5e7646d2SAndroid Build Coastguard Worker //
18*5e7646d2SAndroid Build Coastguard Worker // Character encodings...
19*5e7646d2SAndroid Build Coastguard Worker //
20*5e7646d2SAndroid Build Coastguard Worker 
21*5e7646d2SAndroid Build Coastguard Worker typedef enum
22*5e7646d2SAndroid Build Coastguard Worker {
23*5e7646d2SAndroid Build Coastguard Worker   PPDC_CS_AUTO,
24*5e7646d2SAndroid Build Coastguard Worker   PPDC_CS_UTF8,
25*5e7646d2SAndroid Build Coastguard Worker   PPDC_CS_UTF16BE,
26*5e7646d2SAndroid Build Coastguard Worker   PPDC_CS_UTF16LE
27*5e7646d2SAndroid Build Coastguard Worker } ppdc_cs_t;
28*5e7646d2SAndroid Build Coastguard Worker 
29*5e7646d2SAndroid Build Coastguard Worker 
30*5e7646d2SAndroid Build Coastguard Worker //
31*5e7646d2SAndroid Build Coastguard Worker // Local functions...
32*5e7646d2SAndroid Build Coastguard Worker //
33*5e7646d2SAndroid Build Coastguard Worker 
34*5e7646d2SAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
35*5e7646d2SAndroid Build Coastguard Worker static void	apple_add_message(CFStringRef key, CFStringRef val, ppdcCatalog *c);
36*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ && CUPS_BUNDLEDIR */
37*5e7646d2SAndroid Build Coastguard Worker static int	get_utf8(char *&ptr);
38*5e7646d2SAndroid Build Coastguard Worker static int	get_utf16(cups_file_t *fp, ppdc_cs_t &cs);
39*5e7646d2SAndroid Build Coastguard Worker static int	put_utf8(int ch, char *&ptr, char *end);
40*5e7646d2SAndroid Build Coastguard Worker static int	put_utf16(cups_file_t *fp, int ch);
41*5e7646d2SAndroid Build Coastguard Worker 
42*5e7646d2SAndroid Build Coastguard Worker 
43*5e7646d2SAndroid Build Coastguard Worker //
44*5e7646d2SAndroid Build Coastguard Worker // 'ppdcCatalog::ppdcCatalog()' - Create a shared message catalog.
45*5e7646d2SAndroid Build Coastguard Worker //
46*5e7646d2SAndroid Build Coastguard Worker 
ppdcCatalog(const char * l,const char * f)47*5e7646d2SAndroid Build Coastguard Worker ppdcCatalog::ppdcCatalog(const char *l,	// I - Locale
48*5e7646d2SAndroid Build Coastguard Worker                          const char *f)	// I - Message catalog file
49*5e7646d2SAndroid Build Coastguard Worker   : ppdcShared()
50*5e7646d2SAndroid Build Coastguard Worker {
51*5e7646d2SAndroid Build Coastguard Worker   PPDC_NEW;
52*5e7646d2SAndroid Build Coastguard Worker 
53*5e7646d2SAndroid Build Coastguard Worker   locale   = new ppdcString(l);
54*5e7646d2SAndroid Build Coastguard Worker   filename = new ppdcString(f);
55*5e7646d2SAndroid Build Coastguard Worker   messages = new ppdcArray();
56*5e7646d2SAndroid Build Coastguard Worker 
57*5e7646d2SAndroid Build Coastguard Worker   if (l && strcmp(l, "en"))
58*5e7646d2SAndroid Build Coastguard Worker   {
59*5e7646d2SAndroid Build Coastguard Worker     // Try loading the base messages for this locale...
60*5e7646d2SAndroid Build Coastguard Worker     char	pofile[1024];		// Message catalog file
61*5e7646d2SAndroid Build Coastguard Worker 
62*5e7646d2SAndroid Build Coastguard Worker 
63*5e7646d2SAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
64*5e7646d2SAndroid Build Coastguard Worker     char		applelang[256];	// Apple language ID
65*5e7646d2SAndroid Build Coastguard Worker     CFURLRef		url;		// URL to cups.strings file
66*5e7646d2SAndroid Build Coastguard Worker     CFReadStreamRef	stream = NULL;	// File stream
67*5e7646d2SAndroid Build Coastguard Worker     CFPropertyListRef	plist = NULL;	// Localization file
68*5e7646d2SAndroid Build Coastguard Worker 
69*5e7646d2SAndroid Build Coastguard Worker     snprintf(pofile, sizeof(pofile), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", _cupsAppleLanguage(l, applelang, sizeof(applelang)));
70*5e7646d2SAndroid Build Coastguard Worker     if (access(pofile, 0))
71*5e7646d2SAndroid Build Coastguard Worker     {
72*5e7646d2SAndroid Build Coastguard Worker       // Try alternate lproj directory names...
73*5e7646d2SAndroid Build Coastguard Worker       const char *tl = l;		// Temporary locale string
74*5e7646d2SAndroid Build Coastguard Worker 
75*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(l, "en", 2))
76*5e7646d2SAndroid Build Coastguard Worker 	tl = "English";
77*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(l, "nb", 2))
78*5e7646d2SAndroid Build Coastguard Worker         tl = "no";
79*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(l, "nl", 2))
80*5e7646d2SAndroid Build Coastguard Worker 	tl = "Dutch";
81*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(l, "fr", 2))
82*5e7646d2SAndroid Build Coastguard Worker 	tl = "French";
83*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(l, "de", 2))
84*5e7646d2SAndroid Build Coastguard Worker 	tl = "German";
85*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(l, "it", 2))
86*5e7646d2SAndroid Build Coastguard Worker 	tl = "Italian";
87*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(l, "ja", 2))
88*5e7646d2SAndroid Build Coastguard Worker 	tl = "Japanese";
89*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(l, "es", 2))
90*5e7646d2SAndroid Build Coastguard Worker 	tl = "Spanish";
91*5e7646d2SAndroid Build Coastguard Worker 
92*5e7646d2SAndroid Build Coastguard Worker       snprintf(pofile, sizeof(pofile), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", tl);
93*5e7646d2SAndroid Build Coastguard Worker     }
94*5e7646d2SAndroid Build Coastguard Worker 
95*5e7646d2SAndroid Build Coastguard Worker     url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)pofile, (CFIndex)strlen(pofile), false);
96*5e7646d2SAndroid Build Coastguard Worker     if (url)
97*5e7646d2SAndroid Build Coastguard Worker     {
98*5e7646d2SAndroid Build Coastguard Worker       stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
99*5e7646d2SAndroid Build Coastguard Worker 
100*5e7646d2SAndroid Build Coastguard Worker       if (stream)
101*5e7646d2SAndroid Build Coastguard Worker       {
102*5e7646d2SAndroid Build Coastguard Worker        /*
103*5e7646d2SAndroid Build Coastguard Worker 	* Read the property list containing the localization data.
104*5e7646d2SAndroid Build Coastguard Worker 	*/
105*5e7646d2SAndroid Build Coastguard Worker 
106*5e7646d2SAndroid Build Coastguard Worker 	CFReadStreamOpen(stream);
107*5e7646d2SAndroid Build Coastguard Worker 
108*5e7646d2SAndroid Build Coastguard Worker 	plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
109*5e7646d2SAndroid Build Coastguard Worker 
110*5e7646d2SAndroid Build Coastguard Worker 	if (plist && CFGetTypeID(plist) == CFDictionaryGetTypeID())
111*5e7646d2SAndroid Build Coastguard Worker 	  CFDictionaryApplyFunction((CFDictionaryRef)plist, (CFDictionaryApplierFunction)apple_add_message, this);
112*5e7646d2SAndroid Build Coastguard Worker 
113*5e7646d2SAndroid Build Coastguard Worker 	if (plist)
114*5e7646d2SAndroid Build Coastguard Worker 	  CFRelease(plist);
115*5e7646d2SAndroid Build Coastguard Worker 
116*5e7646d2SAndroid Build Coastguard Worker 	CFRelease(stream);
117*5e7646d2SAndroid Build Coastguard Worker       }
118*5e7646d2SAndroid Build Coastguard Worker 
119*5e7646d2SAndroid Build Coastguard Worker       CFRelease(url);
120*5e7646d2SAndroid Build Coastguard Worker     }
121*5e7646d2SAndroid Build Coastguard Worker 
122*5e7646d2SAndroid Build Coastguard Worker #else
123*5e7646d2SAndroid Build Coastguard Worker     _cups_globals_t	*cg = _cupsGlobals();
124*5e7646d2SAndroid Build Coastguard Worker 					// Global information
125*5e7646d2SAndroid Build Coastguard Worker 
126*5e7646d2SAndroid Build Coastguard Worker     snprintf(pofile, sizeof(pofile), "%s/%s/cups_%s.po", cg->localedir, l, l);
127*5e7646d2SAndroid Build Coastguard Worker 
128*5e7646d2SAndroid Build Coastguard Worker     if (load_messages(pofile) && strchr(l, '_'))
129*5e7646d2SAndroid Build Coastguard Worker     {
130*5e7646d2SAndroid Build Coastguard Worker       // Try the base locale...
131*5e7646d2SAndroid Build Coastguard Worker       char	baseloc[3];		// Base locale...
132*5e7646d2SAndroid Build Coastguard Worker 
133*5e7646d2SAndroid Build Coastguard Worker 
134*5e7646d2SAndroid Build Coastguard Worker       strlcpy(baseloc, l, sizeof(baseloc));
135*5e7646d2SAndroid Build Coastguard Worker       snprintf(pofile, sizeof(pofile), "%s/%s/cups_%s.po", cg->localedir,
136*5e7646d2SAndroid Build Coastguard Worker                baseloc, baseloc);
137*5e7646d2SAndroid Build Coastguard Worker 
138*5e7646d2SAndroid Build Coastguard Worker       load_messages(pofile);
139*5e7646d2SAndroid Build Coastguard Worker     }
140*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ && CUPS_BUNDLEDIR */
141*5e7646d2SAndroid Build Coastguard Worker   }
142*5e7646d2SAndroid Build Coastguard Worker 
143*5e7646d2SAndroid Build Coastguard Worker   if (f && *f)
144*5e7646d2SAndroid Build Coastguard Worker     load_messages(f);
145*5e7646d2SAndroid Build Coastguard Worker }
146*5e7646d2SAndroid Build Coastguard Worker 
147*5e7646d2SAndroid Build Coastguard Worker 
148*5e7646d2SAndroid Build Coastguard Worker //
149*5e7646d2SAndroid Build Coastguard Worker // 'ppdcCatalog::~ppdcCatalog()' - Destroy a shared message catalog.
150*5e7646d2SAndroid Build Coastguard Worker //
151*5e7646d2SAndroid Build Coastguard Worker 
~ppdcCatalog()152*5e7646d2SAndroid Build Coastguard Worker ppdcCatalog::~ppdcCatalog()
153*5e7646d2SAndroid Build Coastguard Worker {
154*5e7646d2SAndroid Build Coastguard Worker   PPDC_DELETE;
155*5e7646d2SAndroid Build Coastguard Worker 
156*5e7646d2SAndroid Build Coastguard Worker   locale->release();
157*5e7646d2SAndroid Build Coastguard Worker   filename->release();
158*5e7646d2SAndroid Build Coastguard Worker   messages->release();
159*5e7646d2SAndroid Build Coastguard Worker }
160*5e7646d2SAndroid Build Coastguard Worker 
161*5e7646d2SAndroid Build Coastguard Worker 
162*5e7646d2SAndroid Build Coastguard Worker //
163*5e7646d2SAndroid Build Coastguard Worker // 'ppdcCatalog::add_message()' - Add a new message.
164*5e7646d2SAndroid Build Coastguard Worker //
165*5e7646d2SAndroid Build Coastguard Worker 
166*5e7646d2SAndroid Build Coastguard Worker void
add_message(const char * id,const char * string)167*5e7646d2SAndroid Build Coastguard Worker ppdcCatalog::add_message(
168*5e7646d2SAndroid Build Coastguard Worker     const char *id,			// I - Message ID to add
169*5e7646d2SAndroid Build Coastguard Worker     const char *string)			// I - Translation string
170*5e7646d2SAndroid Build Coastguard Worker {
171*5e7646d2SAndroid Build Coastguard Worker   ppdcMessage	*m;			// Current message
172*5e7646d2SAndroid Build Coastguard Worker   char		text[1024];		// Text to translate
173*5e7646d2SAndroid Build Coastguard Worker 
174*5e7646d2SAndroid Build Coastguard Worker 
175*5e7646d2SAndroid Build Coastguard Worker   // Range check input...
176*5e7646d2SAndroid Build Coastguard Worker   if (!id)
177*5e7646d2SAndroid Build Coastguard Worker     return;
178*5e7646d2SAndroid Build Coastguard Worker 
179*5e7646d2SAndroid Build Coastguard Worker   // Verify that we don't already have the message ID...
180*5e7646d2SAndroid Build Coastguard Worker   for (m = (ppdcMessage *)messages->first();
181*5e7646d2SAndroid Build Coastguard Worker        m;
182*5e7646d2SAndroid Build Coastguard Worker        m = (ppdcMessage *)messages->next())
183*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(m->id->value, id))
184*5e7646d2SAndroid Build Coastguard Worker     {
185*5e7646d2SAndroid Build Coastguard Worker       if (string)
186*5e7646d2SAndroid Build Coastguard Worker       {
187*5e7646d2SAndroid Build Coastguard Worker         m->string->release();
188*5e7646d2SAndroid Build Coastguard Worker 	m->string = new ppdcString(string);
189*5e7646d2SAndroid Build Coastguard Worker       }
190*5e7646d2SAndroid Build Coastguard Worker       return;
191*5e7646d2SAndroid Build Coastguard Worker     }
192*5e7646d2SAndroid Build Coastguard Worker 
193*5e7646d2SAndroid Build Coastguard Worker   // Add the message...
194*5e7646d2SAndroid Build Coastguard Worker   if (!string)
195*5e7646d2SAndroid Build Coastguard Worker   {
196*5e7646d2SAndroid Build Coastguard Worker     snprintf(text, sizeof(text), "TRANSLATE %s", id);
197*5e7646d2SAndroid Build Coastguard Worker     string = text;
198*5e7646d2SAndroid Build Coastguard Worker   }
199*5e7646d2SAndroid Build Coastguard Worker 
200*5e7646d2SAndroid Build Coastguard Worker   messages->add(new ppdcMessage(id, string));
201*5e7646d2SAndroid Build Coastguard Worker }
202*5e7646d2SAndroid Build Coastguard Worker 
203*5e7646d2SAndroid Build Coastguard Worker 
204*5e7646d2SAndroid Build Coastguard Worker //
205*5e7646d2SAndroid Build Coastguard Worker // 'ppdcCatalog::find_message()' - Find a message in a catalog...
206*5e7646d2SAndroid Build Coastguard Worker //
207*5e7646d2SAndroid Build Coastguard Worker 
208*5e7646d2SAndroid Build Coastguard Worker const char *				// O - Message text
find_message(const char * id)209*5e7646d2SAndroid Build Coastguard Worker ppdcCatalog::find_message(
210*5e7646d2SAndroid Build Coastguard Worker     const char *id)			// I - Message ID
211*5e7646d2SAndroid Build Coastguard Worker {
212*5e7646d2SAndroid Build Coastguard Worker   ppdcMessage	*m;			// Current message
213*5e7646d2SAndroid Build Coastguard Worker 
214*5e7646d2SAndroid Build Coastguard Worker 
215*5e7646d2SAndroid Build Coastguard Worker   if (!*id)
216*5e7646d2SAndroid Build Coastguard Worker     return (id);
217*5e7646d2SAndroid Build Coastguard Worker 
218*5e7646d2SAndroid Build Coastguard Worker   for (m = (ppdcMessage *)messages->first();
219*5e7646d2SAndroid Build Coastguard Worker        m;
220*5e7646d2SAndroid Build Coastguard Worker        m = (ppdcMessage *)messages->next())
221*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(m->id->value, id))
222*5e7646d2SAndroid Build Coastguard Worker       return (m->string->value);
223*5e7646d2SAndroid Build Coastguard Worker 
224*5e7646d2SAndroid Build Coastguard Worker   return (id);
225*5e7646d2SAndroid Build Coastguard Worker }
226*5e7646d2SAndroid Build Coastguard Worker 
227*5e7646d2SAndroid Build Coastguard Worker 
228*5e7646d2SAndroid Build Coastguard Worker //
229*5e7646d2SAndroid Build Coastguard Worker // 'ppdcCatalog::load_messages()' - Load messages from a .po file.
230*5e7646d2SAndroid Build Coastguard Worker //
231*5e7646d2SAndroid Build Coastguard Worker 
232*5e7646d2SAndroid Build Coastguard Worker int					// O - 0 on success, -1 on failure
load_messages(const char * f)233*5e7646d2SAndroid Build Coastguard Worker ppdcCatalog::load_messages(
234*5e7646d2SAndroid Build Coastguard Worker     const char *f)			// I - Message catalog file
235*5e7646d2SAndroid Build Coastguard Worker {
236*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*fp;			// Message file
237*5e7646d2SAndroid Build Coastguard Worker   char		line[4096],		// Line buffer
238*5e7646d2SAndroid Build Coastguard Worker 		*ptr,			// Pointer into buffer
239*5e7646d2SAndroid Build Coastguard Worker 		id[4096],		// Translation ID
240*5e7646d2SAndroid Build Coastguard Worker 		str[4096];		// Translation string
241*5e7646d2SAndroid Build Coastguard Worker   int		linenum;		// Line number
242*5e7646d2SAndroid Build Coastguard Worker 
243*5e7646d2SAndroid Build Coastguard Worker 
244*5e7646d2SAndroid Build Coastguard Worker   // Open the message catalog file...
245*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsFileOpen(f, "r")) == NULL)
246*5e7646d2SAndroid Build Coastguard Worker     return (-1);
247*5e7646d2SAndroid Build Coastguard Worker 
248*5e7646d2SAndroid Build Coastguard Worker   if ((ptr = (char *)strrchr(f, '.')) == NULL)
249*5e7646d2SAndroid Build Coastguard Worker     goto unknown_load_format;
250*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(ptr, ".strings"))
251*5e7646d2SAndroid Build Coastguard Worker   {
252*5e7646d2SAndroid Build Coastguard Worker    /*
253*5e7646d2SAndroid Build Coastguard Worker     * Read messages in macOS ".strings" format, which are either UTF-8/UTF-16
254*5e7646d2SAndroid Build Coastguard Worker     * text files of the format:
255*5e7646d2SAndroid Build Coastguard Worker     *
256*5e7646d2SAndroid Build Coastguard Worker     *     "id" = "str";
257*5e7646d2SAndroid Build Coastguard Worker     *
258*5e7646d2SAndroid Build Coastguard Worker     * Strings files can also contain C-style comments.
259*5e7646d2SAndroid Build Coastguard Worker     */
260*5e7646d2SAndroid Build Coastguard Worker 
261*5e7646d2SAndroid Build Coastguard Worker     ppdc_cs_t	cs = PPDC_CS_AUTO;	// Character set for file
262*5e7646d2SAndroid Build Coastguard Worker     int		ch;			// Current character from file
263*5e7646d2SAndroid Build Coastguard Worker     char	*end;			// End of buffer
264*5e7646d2SAndroid Build Coastguard Worker 
265*5e7646d2SAndroid Build Coastguard Worker 
266*5e7646d2SAndroid Build Coastguard Worker     id[0]  = '\0';
267*5e7646d2SAndroid Build Coastguard Worker     str[0] = '\0';
268*5e7646d2SAndroid Build Coastguard Worker     ptr    = NULL;
269*5e7646d2SAndroid Build Coastguard Worker     end    = NULL;
270*5e7646d2SAndroid Build Coastguard Worker 
271*5e7646d2SAndroid Build Coastguard Worker     while ((ch = get_utf16(fp, cs)) != 0)
272*5e7646d2SAndroid Build Coastguard Worker     {
273*5e7646d2SAndroid Build Coastguard Worker       if (ptr)
274*5e7646d2SAndroid Build Coastguard Worker       {
275*5e7646d2SAndroid Build Coastguard Worker         if (ch == '\\')
276*5e7646d2SAndroid Build Coastguard Worker 	{
277*5e7646d2SAndroid Build Coastguard Worker 	  if ((ch = get_utf16(fp, cs)) == 0)
278*5e7646d2SAndroid Build Coastguard Worker 	    break;
279*5e7646d2SAndroid Build Coastguard Worker 
280*5e7646d2SAndroid Build Coastguard Worker 	  if (ch == 'n')
281*5e7646d2SAndroid Build Coastguard Worker 	    ch = '\n';
282*5e7646d2SAndroid Build Coastguard Worker 	  else if (ch == 't')
283*5e7646d2SAndroid Build Coastguard Worker 	    ch = '\t';
284*5e7646d2SAndroid Build Coastguard Worker         }
285*5e7646d2SAndroid Build Coastguard Worker 	else if (ch == '\"')
286*5e7646d2SAndroid Build Coastguard Worker 	{
287*5e7646d2SAndroid Build Coastguard Worker 	  *ptr = '\0';
288*5e7646d2SAndroid Build Coastguard Worker 	  ptr  = NULL;
289*5e7646d2SAndroid Build Coastguard Worker 	}
290*5e7646d2SAndroid Build Coastguard Worker 
291*5e7646d2SAndroid Build Coastguard Worker         if (ptr)
292*5e7646d2SAndroid Build Coastguard Worker 	  put_utf8(ch, ptr, end);
293*5e7646d2SAndroid Build Coastguard Worker       }
294*5e7646d2SAndroid Build Coastguard Worker       else if (ch == '/')
295*5e7646d2SAndroid Build Coastguard Worker       {
296*5e7646d2SAndroid Build Coastguard Worker         // Start of a comment?
297*5e7646d2SAndroid Build Coastguard Worker 	if ((ch = get_utf16(fp, cs)) == 0)
298*5e7646d2SAndroid Build Coastguard Worker 	  break;
299*5e7646d2SAndroid Build Coastguard Worker 
300*5e7646d2SAndroid Build Coastguard Worker         if (ch == '*')
301*5e7646d2SAndroid Build Coastguard Worker 	{
302*5e7646d2SAndroid Build Coastguard Worker 	  // Skip C comment...
303*5e7646d2SAndroid Build Coastguard Worker 	  int lastch = 0;
304*5e7646d2SAndroid Build Coastguard Worker 
305*5e7646d2SAndroid Build Coastguard Worker           while ((ch = get_utf16(fp, cs)) != 0)
306*5e7646d2SAndroid Build Coastguard Worker 	  {
307*5e7646d2SAndroid Build Coastguard Worker 	    if (ch == '/' && lastch == '*')
308*5e7646d2SAndroid Build Coastguard Worker 	      break;
309*5e7646d2SAndroid Build Coastguard Worker 
310*5e7646d2SAndroid Build Coastguard Worker 	    lastch = ch;
311*5e7646d2SAndroid Build Coastguard Worker 	  }
312*5e7646d2SAndroid Build Coastguard Worker 	}
313*5e7646d2SAndroid Build Coastguard Worker 	else if (ch == '/')
314*5e7646d2SAndroid Build Coastguard Worker 	{
315*5e7646d2SAndroid Build Coastguard Worker 	  // Skip C++ comment...
316*5e7646d2SAndroid Build Coastguard Worker 	  while ((ch = get_utf16(fp, cs)) != 0)
317*5e7646d2SAndroid Build Coastguard Worker 	    if (ch == '\n')
318*5e7646d2SAndroid Build Coastguard Worker 	      break;
319*5e7646d2SAndroid Build Coastguard Worker 	}
320*5e7646d2SAndroid Build Coastguard Worker       }
321*5e7646d2SAndroid Build Coastguard Worker       else if (ch == '\"')
322*5e7646d2SAndroid Build Coastguard Worker       {
323*5e7646d2SAndroid Build Coastguard Worker         // Start quoted string...
324*5e7646d2SAndroid Build Coastguard Worker 	if (id[0])
325*5e7646d2SAndroid Build Coastguard Worker 	{
326*5e7646d2SAndroid Build Coastguard Worker 	  ptr = str;
327*5e7646d2SAndroid Build Coastguard Worker 	  end = str + sizeof(str) - 1;
328*5e7646d2SAndroid Build Coastguard Worker 	}
329*5e7646d2SAndroid Build Coastguard Worker 	else
330*5e7646d2SAndroid Build Coastguard Worker 	{
331*5e7646d2SAndroid Build Coastguard Worker 	  ptr = id;
332*5e7646d2SAndroid Build Coastguard Worker 	  end = id + sizeof(id) - 1;
333*5e7646d2SAndroid Build Coastguard Worker 	}
334*5e7646d2SAndroid Build Coastguard Worker       }
335*5e7646d2SAndroid Build Coastguard Worker       else if (ch == ';')
336*5e7646d2SAndroid Build Coastguard Worker       {
337*5e7646d2SAndroid Build Coastguard Worker         // Add string...
338*5e7646d2SAndroid Build Coastguard Worker 	add_message(id, str);
339*5e7646d2SAndroid Build Coastguard Worker 	id[0] = '\0';
340*5e7646d2SAndroid Build Coastguard Worker       }
341*5e7646d2SAndroid Build Coastguard Worker     }
342*5e7646d2SAndroid Build Coastguard Worker   }
343*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(ptr, ".po") || !strcmp(ptr, ".gz"))
344*5e7646d2SAndroid Build Coastguard Worker   {
345*5e7646d2SAndroid Build Coastguard Worker    /*
346*5e7646d2SAndroid Build Coastguard Worker     * Read messages from the catalog file until EOF...
347*5e7646d2SAndroid Build Coastguard Worker     *
348*5e7646d2SAndroid Build Coastguard Worker     * The format is the GNU gettext .po format, which is fairly simple:
349*5e7646d2SAndroid Build Coastguard Worker     *
350*5e7646d2SAndroid Build Coastguard Worker     *     msgid "some text"
351*5e7646d2SAndroid Build Coastguard Worker     *     msgstr "localized text"
352*5e7646d2SAndroid Build Coastguard Worker     *
353*5e7646d2SAndroid Build Coastguard Worker     * The ID and localized text can span multiple lines using the form:
354*5e7646d2SAndroid Build Coastguard Worker     *
355*5e7646d2SAndroid Build Coastguard Worker     *     msgid ""
356*5e7646d2SAndroid Build Coastguard Worker     *     "some long text"
357*5e7646d2SAndroid Build Coastguard Worker     *     msgstr ""
358*5e7646d2SAndroid Build Coastguard Worker     *     "localized text spanning "
359*5e7646d2SAndroid Build Coastguard Worker     *     "multiple lines"
360*5e7646d2SAndroid Build Coastguard Worker     */
361*5e7646d2SAndroid Build Coastguard Worker 
362*5e7646d2SAndroid Build Coastguard Worker     int	which,				// In msgid?
363*5e7646d2SAndroid Build Coastguard Worker 	haveid,				// Did we get a msgid string?
364*5e7646d2SAndroid Build Coastguard Worker 	havestr;			// Did we get a msgstr string?
365*5e7646d2SAndroid Build Coastguard Worker 
366*5e7646d2SAndroid Build Coastguard Worker     linenum = 0;
367*5e7646d2SAndroid Build Coastguard Worker     id[0]   = '\0';
368*5e7646d2SAndroid Build Coastguard Worker     str[0]  = '\0';
369*5e7646d2SAndroid Build Coastguard Worker     haveid  = 0;
370*5e7646d2SAndroid Build Coastguard Worker     havestr = 0;
371*5e7646d2SAndroid Build Coastguard Worker     which   = 0;
372*5e7646d2SAndroid Build Coastguard Worker 
373*5e7646d2SAndroid Build Coastguard Worker     while (cupsFileGets(fp, line, sizeof(line)))
374*5e7646d2SAndroid Build Coastguard Worker     {
375*5e7646d2SAndroid Build Coastguard Worker       linenum ++;
376*5e7646d2SAndroid Build Coastguard Worker 
377*5e7646d2SAndroid Build Coastguard Worker       // Skip blank and comment lines...
378*5e7646d2SAndroid Build Coastguard Worker       if (line[0] == '#' || !line[0])
379*5e7646d2SAndroid Build Coastguard Worker 	continue;
380*5e7646d2SAndroid Build Coastguard Worker 
381*5e7646d2SAndroid Build Coastguard Worker       // Strip the trailing quote...
382*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = (char *)strrchr(line, '\"')) == NULL)
383*5e7646d2SAndroid Build Coastguard Worker       {
384*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintf(stderr,
385*5e7646d2SAndroid Build Coastguard Worker 	                _("ppdc: Expected quoted string on line %d of %s."),
386*5e7646d2SAndroid Build Coastguard Worker 			linenum, f);
387*5e7646d2SAndroid Build Coastguard Worker 	cupsFileClose(fp);
388*5e7646d2SAndroid Build Coastguard Worker 	return (-1);
389*5e7646d2SAndroid Build Coastguard Worker       }
390*5e7646d2SAndroid Build Coastguard Worker 
391*5e7646d2SAndroid Build Coastguard Worker       *ptr = '\0';
392*5e7646d2SAndroid Build Coastguard Worker 
393*5e7646d2SAndroid Build Coastguard Worker       // Find start of value...
394*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strchr(line, '\"')) == NULL)
395*5e7646d2SAndroid Build Coastguard Worker       {
396*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintf(stderr,
397*5e7646d2SAndroid Build Coastguard Worker 	                _("ppdc: Expected quoted string on line %d of %s."),
398*5e7646d2SAndroid Build Coastguard Worker 			linenum, f);
399*5e7646d2SAndroid Build Coastguard Worker 	cupsFileClose(fp);
400*5e7646d2SAndroid Build Coastguard Worker 	return (-1);
401*5e7646d2SAndroid Build Coastguard Worker       }
402*5e7646d2SAndroid Build Coastguard Worker 
403*5e7646d2SAndroid Build Coastguard Worker       ptr ++;
404*5e7646d2SAndroid Build Coastguard Worker 
405*5e7646d2SAndroid Build Coastguard Worker       // Unquote the text...
406*5e7646d2SAndroid Build Coastguard Worker       char *sptr, *dptr;			// Source/destination pointers
407*5e7646d2SAndroid Build Coastguard Worker 
408*5e7646d2SAndroid Build Coastguard Worker       for (sptr = ptr, dptr = ptr; *sptr;)
409*5e7646d2SAndroid Build Coastguard Worker       {
410*5e7646d2SAndroid Build Coastguard Worker 	if (*sptr == '\\')
411*5e7646d2SAndroid Build Coastguard Worker 	{
412*5e7646d2SAndroid Build Coastguard Worker 	  sptr ++;
413*5e7646d2SAndroid Build Coastguard Worker 	  if (isdigit(*sptr))
414*5e7646d2SAndroid Build Coastguard Worker 	  {
415*5e7646d2SAndroid Build Coastguard Worker 	    *dptr = 0;
416*5e7646d2SAndroid Build Coastguard Worker 
417*5e7646d2SAndroid Build Coastguard Worker 	    while (isdigit(*sptr))
418*5e7646d2SAndroid Build Coastguard Worker 	    {
419*5e7646d2SAndroid Build Coastguard Worker 	      *dptr = *dptr * 8 + *sptr - '0';
420*5e7646d2SAndroid Build Coastguard Worker 	      sptr ++;
421*5e7646d2SAndroid Build Coastguard Worker 	    }
422*5e7646d2SAndroid Build Coastguard Worker 
423*5e7646d2SAndroid Build Coastguard Worker 	    dptr ++;
424*5e7646d2SAndroid Build Coastguard Worker 	  }
425*5e7646d2SAndroid Build Coastguard Worker 	  else
426*5e7646d2SAndroid Build Coastguard Worker 	  {
427*5e7646d2SAndroid Build Coastguard Worker 	    if (*sptr == 'n')
428*5e7646d2SAndroid Build Coastguard Worker 	      *dptr++ = '\n';
429*5e7646d2SAndroid Build Coastguard Worker 	    else if (*sptr == 'r')
430*5e7646d2SAndroid Build Coastguard Worker 	      *dptr++ = '\r';
431*5e7646d2SAndroid Build Coastguard Worker 	    else if (*sptr == 't')
432*5e7646d2SAndroid Build Coastguard Worker 	      *dptr++ = '\t';
433*5e7646d2SAndroid Build Coastguard Worker 	    else
434*5e7646d2SAndroid Build Coastguard Worker 	      *dptr++ = *sptr;
435*5e7646d2SAndroid Build Coastguard Worker 
436*5e7646d2SAndroid Build Coastguard Worker 	    sptr ++;
437*5e7646d2SAndroid Build Coastguard Worker 	  }
438*5e7646d2SAndroid Build Coastguard Worker 	}
439*5e7646d2SAndroid Build Coastguard Worker 	else
440*5e7646d2SAndroid Build Coastguard Worker 	  *dptr++ = *sptr++;
441*5e7646d2SAndroid Build Coastguard Worker       }
442*5e7646d2SAndroid Build Coastguard Worker 
443*5e7646d2SAndroid Build Coastguard Worker       *dptr = '\0';
444*5e7646d2SAndroid Build Coastguard Worker 
445*5e7646d2SAndroid Build Coastguard Worker       // Create or add to a message...
446*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(line, "msgid", 5))
447*5e7646d2SAndroid Build Coastguard Worker       {
448*5e7646d2SAndroid Build Coastguard Worker 	if (haveid && havestr)
449*5e7646d2SAndroid Build Coastguard Worker 	  add_message(id, str);
450*5e7646d2SAndroid Build Coastguard Worker 
451*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(id, ptr, sizeof(id));
452*5e7646d2SAndroid Build Coastguard Worker 	str[0] = '\0';
453*5e7646d2SAndroid Build Coastguard Worker 	haveid  = 1;
454*5e7646d2SAndroid Build Coastguard Worker 	havestr = 0;
455*5e7646d2SAndroid Build Coastguard Worker 	which   = 1;
456*5e7646d2SAndroid Build Coastguard Worker       }
457*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(line, "msgstr", 6))
458*5e7646d2SAndroid Build Coastguard Worker       {
459*5e7646d2SAndroid Build Coastguard Worker 	if (!haveid)
460*5e7646d2SAndroid Build Coastguard Worker 	{
461*5e7646d2SAndroid Build Coastguard Worker 	  _cupsLangPrintf(stderr,
462*5e7646d2SAndroid Build Coastguard Worker 	                  _("ppdc: Need a msgid line before any "
463*5e7646d2SAndroid Build Coastguard Worker 			    "translation strings on line %d of %s."),
464*5e7646d2SAndroid Build Coastguard Worker 			  linenum, f);
465*5e7646d2SAndroid Build Coastguard Worker 	  cupsFileClose(fp);
466*5e7646d2SAndroid Build Coastguard Worker 	  return (-1);
467*5e7646d2SAndroid Build Coastguard Worker 	}
468*5e7646d2SAndroid Build Coastguard Worker 
469*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(str, ptr, sizeof(str));
470*5e7646d2SAndroid Build Coastguard Worker 	havestr = 1;
471*5e7646d2SAndroid Build Coastguard Worker 	which   = 2;
472*5e7646d2SAndroid Build Coastguard Worker       }
473*5e7646d2SAndroid Build Coastguard Worker       else if (line[0] == '\"' && which == 2)
474*5e7646d2SAndroid Build Coastguard Worker 	strlcat(str, ptr, sizeof(str));
475*5e7646d2SAndroid Build Coastguard Worker       else if (line[0] == '\"' && which == 1)
476*5e7646d2SAndroid Build Coastguard Worker 	strlcat(id, ptr, sizeof(id));
477*5e7646d2SAndroid Build Coastguard Worker       else
478*5e7646d2SAndroid Build Coastguard Worker       {
479*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintf(stderr, _("ppdc: Unexpected text on line %d of %s."),
480*5e7646d2SAndroid Build Coastguard Worker 			linenum, f);
481*5e7646d2SAndroid Build Coastguard Worker 	cupsFileClose(fp);
482*5e7646d2SAndroid Build Coastguard Worker 	return (-1);
483*5e7646d2SAndroid Build Coastguard Worker       }
484*5e7646d2SAndroid Build Coastguard Worker     }
485*5e7646d2SAndroid Build Coastguard Worker 
486*5e7646d2SAndroid Build Coastguard Worker     if (haveid && havestr)
487*5e7646d2SAndroid Build Coastguard Worker       add_message(id, str);
488*5e7646d2SAndroid Build Coastguard Worker   }
489*5e7646d2SAndroid Build Coastguard Worker   else
490*5e7646d2SAndroid Build Coastguard Worker     goto unknown_load_format;
491*5e7646d2SAndroid Build Coastguard Worker 
492*5e7646d2SAndroid Build Coastguard Worker  /*
493*5e7646d2SAndroid Build Coastguard Worker   * Close the file and return...
494*5e7646d2SAndroid Build Coastguard Worker   */
495*5e7646d2SAndroid Build Coastguard Worker 
496*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
497*5e7646d2SAndroid Build Coastguard Worker 
498*5e7646d2SAndroid Build Coastguard Worker   return (0);
499*5e7646d2SAndroid Build Coastguard Worker 
500*5e7646d2SAndroid Build Coastguard Worker  /*
501*5e7646d2SAndroid Build Coastguard Worker   * Unknown format error...
502*5e7646d2SAndroid Build Coastguard Worker   */
503*5e7646d2SAndroid Build Coastguard Worker 
504*5e7646d2SAndroid Build Coastguard Worker   unknown_load_format:
505*5e7646d2SAndroid Build Coastguard Worker 
506*5e7646d2SAndroid Build Coastguard Worker   _cupsLangPrintf(stderr,
507*5e7646d2SAndroid Build Coastguard Worker                   _("ppdc: Unknown message catalog format for \"%s\"."), f);
508*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
509*5e7646d2SAndroid Build Coastguard Worker   return (-1);
510*5e7646d2SAndroid Build Coastguard Worker }
511*5e7646d2SAndroid Build Coastguard Worker 
512*5e7646d2SAndroid Build Coastguard Worker 
513*5e7646d2SAndroid Build Coastguard Worker //
514*5e7646d2SAndroid Build Coastguard Worker // 'ppdcCatalog::save_messages()' - Save the messages to a .po file.
515*5e7646d2SAndroid Build Coastguard Worker //
516*5e7646d2SAndroid Build Coastguard Worker 
517*5e7646d2SAndroid Build Coastguard Worker int					// O - 0 on success, -1 on error
save_messages(const char * f)518*5e7646d2SAndroid Build Coastguard Worker ppdcCatalog::save_messages(
519*5e7646d2SAndroid Build Coastguard Worker     const char *f)			// I - File to save to
520*5e7646d2SAndroid Build Coastguard Worker {
521*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*fp;			// Message file
522*5e7646d2SAndroid Build Coastguard Worker   ppdcMessage	*m;			// Current message
523*5e7646d2SAndroid Build Coastguard Worker   char		*ptr;			// Pointer into string
524*5e7646d2SAndroid Build Coastguard Worker   int		utf16;			// Output UTF-16 .strings file?
525*5e7646d2SAndroid Build Coastguard Worker   int		ch;			// Current character
526*5e7646d2SAndroid Build Coastguard Worker 
527*5e7646d2SAndroid Build Coastguard Worker 
528*5e7646d2SAndroid Build Coastguard Worker   // Open the file...
529*5e7646d2SAndroid Build Coastguard Worker   if ((ptr = (char *)strrchr(f, '.')) == NULL)
530*5e7646d2SAndroid Build Coastguard Worker     return (-1);
531*5e7646d2SAndroid Build Coastguard Worker 
532*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(ptr, ".gz"))
533*5e7646d2SAndroid Build Coastguard Worker     fp = cupsFileOpen(f, "w9");
534*5e7646d2SAndroid Build Coastguard Worker   else
535*5e7646d2SAndroid Build Coastguard Worker     fp = cupsFileOpen(f, "w");
536*5e7646d2SAndroid Build Coastguard Worker 
537*5e7646d2SAndroid Build Coastguard Worker   if (!fp)
538*5e7646d2SAndroid Build Coastguard Worker     return (-1);
539*5e7646d2SAndroid Build Coastguard Worker 
540*5e7646d2SAndroid Build Coastguard Worker   // For .strings files, write a BOM for big-endian output...
541*5e7646d2SAndroid Build Coastguard Worker   utf16 = !strcmp(ptr, ".strings");
542*5e7646d2SAndroid Build Coastguard Worker 
543*5e7646d2SAndroid Build Coastguard Worker   if (utf16)
544*5e7646d2SAndroid Build Coastguard Worker     put_utf16(fp, 0xfeff);
545*5e7646d2SAndroid Build Coastguard Worker 
546*5e7646d2SAndroid Build Coastguard Worker   // Loop through all of the messages...
547*5e7646d2SAndroid Build Coastguard Worker   for (m = (ppdcMessage *)messages->first();
548*5e7646d2SAndroid Build Coastguard Worker        m;
549*5e7646d2SAndroid Build Coastguard Worker        m = (ppdcMessage *)messages->next())
550*5e7646d2SAndroid Build Coastguard Worker   {
551*5e7646d2SAndroid Build Coastguard Worker     if (utf16)
552*5e7646d2SAndroid Build Coastguard Worker     {
553*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, '\"');
554*5e7646d2SAndroid Build Coastguard Worker 
555*5e7646d2SAndroid Build Coastguard Worker       ptr = m->id->value;
556*5e7646d2SAndroid Build Coastguard Worker       while ((ch = get_utf8(ptr)) != 0)
557*5e7646d2SAndroid Build Coastguard Worker 	switch (ch)
558*5e7646d2SAndroid Build Coastguard Worker 	{
559*5e7646d2SAndroid Build Coastguard Worker 	  case '\n' :
560*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
561*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, 'n');
562*5e7646d2SAndroid Build Coastguard Worker 	      break;
563*5e7646d2SAndroid Build Coastguard Worker 	  case '\\' :
564*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
565*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
566*5e7646d2SAndroid Build Coastguard Worker 	      break;
567*5e7646d2SAndroid Build Coastguard Worker 	  case '\"' :
568*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
569*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\"');
570*5e7646d2SAndroid Build Coastguard Worker 	      break;
571*5e7646d2SAndroid Build Coastguard Worker 	  default :
572*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, ch);
573*5e7646d2SAndroid Build Coastguard Worker 	      break;
574*5e7646d2SAndroid Build Coastguard Worker 	}
575*5e7646d2SAndroid Build Coastguard Worker 
576*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, '\"');
577*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, ' ');
578*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, '=');
579*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, ' ');
580*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, '\"');
581*5e7646d2SAndroid Build Coastguard Worker 
582*5e7646d2SAndroid Build Coastguard Worker       ptr = m->string->value;
583*5e7646d2SAndroid Build Coastguard Worker       while ((ch = get_utf8(ptr)) != 0)
584*5e7646d2SAndroid Build Coastguard Worker 	switch (ch)
585*5e7646d2SAndroid Build Coastguard Worker 	{
586*5e7646d2SAndroid Build Coastguard Worker 	  case '\n' :
587*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
588*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, 'n');
589*5e7646d2SAndroid Build Coastguard Worker 	      break;
590*5e7646d2SAndroid Build Coastguard Worker 	  case '\\' :
591*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
592*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
593*5e7646d2SAndroid Build Coastguard Worker 	      break;
594*5e7646d2SAndroid Build Coastguard Worker 	  case '\"' :
595*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\\');
596*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, '\"');
597*5e7646d2SAndroid Build Coastguard Worker 	      break;
598*5e7646d2SAndroid Build Coastguard Worker 	  default :
599*5e7646d2SAndroid Build Coastguard Worker 	      put_utf16(fp, ch);
600*5e7646d2SAndroid Build Coastguard Worker 	      break;
601*5e7646d2SAndroid Build Coastguard Worker 	}
602*5e7646d2SAndroid Build Coastguard Worker 
603*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, '\"');
604*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, ';');
605*5e7646d2SAndroid Build Coastguard Worker       put_utf16(fp, '\n');
606*5e7646d2SAndroid Build Coastguard Worker     }
607*5e7646d2SAndroid Build Coastguard Worker     else
608*5e7646d2SAndroid Build Coastguard Worker     {
609*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "msgid \"");
610*5e7646d2SAndroid Build Coastguard Worker       for (ptr = m->id->value; *ptr; ptr ++)
611*5e7646d2SAndroid Build Coastguard Worker 	switch (*ptr)
612*5e7646d2SAndroid Build Coastguard Worker 	{
613*5e7646d2SAndroid Build Coastguard Worker 	  case '\n' :
614*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePuts(fp, "\\n");
615*5e7646d2SAndroid Build Coastguard Worker 	      break;
616*5e7646d2SAndroid Build Coastguard Worker 	  case '\\' :
617*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePuts(fp, "\\\\");
618*5e7646d2SAndroid Build Coastguard Worker 	      break;
619*5e7646d2SAndroid Build Coastguard Worker 	  case '\"' :
620*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePuts(fp, "\\\"");
621*5e7646d2SAndroid Build Coastguard Worker 	      break;
622*5e7646d2SAndroid Build Coastguard Worker 	  default :
623*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePutChar(fp, *ptr);
624*5e7646d2SAndroid Build Coastguard Worker 	      break;
625*5e7646d2SAndroid Build Coastguard Worker 	}
626*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "\"\n");
627*5e7646d2SAndroid Build Coastguard Worker 
628*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "msgstr \"");
629*5e7646d2SAndroid Build Coastguard Worker       for (ptr = m->string->value; *ptr; ptr ++)
630*5e7646d2SAndroid Build Coastguard Worker 	switch (*ptr)
631*5e7646d2SAndroid Build Coastguard Worker 	{
632*5e7646d2SAndroid Build Coastguard Worker 	  case '\n' :
633*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePuts(fp, "\\n");
634*5e7646d2SAndroid Build Coastguard Worker 	      break;
635*5e7646d2SAndroid Build Coastguard Worker 	  case '\\' :
636*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePuts(fp, "\\\\");
637*5e7646d2SAndroid Build Coastguard Worker 	      break;
638*5e7646d2SAndroid Build Coastguard Worker 	  case '\"' :
639*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePuts(fp, "\\\"");
640*5e7646d2SAndroid Build Coastguard Worker 	      break;
641*5e7646d2SAndroid Build Coastguard Worker 	  default :
642*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePutChar(fp, *ptr);
643*5e7646d2SAndroid Build Coastguard Worker 	      break;
644*5e7646d2SAndroid Build Coastguard Worker 	}
645*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "\"\n");
646*5e7646d2SAndroid Build Coastguard Worker 
647*5e7646d2SAndroid Build Coastguard Worker       cupsFilePutChar(fp, '\n');
648*5e7646d2SAndroid Build Coastguard Worker     }
649*5e7646d2SAndroid Build Coastguard Worker   }
650*5e7646d2SAndroid Build Coastguard Worker 
651*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
652*5e7646d2SAndroid Build Coastguard Worker 
653*5e7646d2SAndroid Build Coastguard Worker   return (0);
654*5e7646d2SAndroid Build Coastguard Worker }
655*5e7646d2SAndroid Build Coastguard Worker 
656*5e7646d2SAndroid Build Coastguard Worker 
657*5e7646d2SAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
658*5e7646d2SAndroid Build Coastguard Worker //
659*5e7646d2SAndroid Build Coastguard Worker // 'apple_add_message()' - Add a message from a localization dictionary.
660*5e7646d2SAndroid Build Coastguard Worker //
661*5e7646d2SAndroid Build Coastguard Worker 
662*5e7646d2SAndroid Build Coastguard Worker static void
apple_add_message(CFStringRef key,CFStringRef val,ppdcCatalog * c)663*5e7646d2SAndroid Build Coastguard Worker apple_add_message(CFStringRef key,	// I - Localization key
664*5e7646d2SAndroid Build Coastguard Worker                   CFStringRef val,	// I - Localized value
665*5e7646d2SAndroid Build Coastguard Worker                   ppdcCatalog *c)	// I - Message catalog
666*5e7646d2SAndroid Build Coastguard Worker {
667*5e7646d2SAndroid Build Coastguard Worker   char	id[1024],			// Message id
668*5e7646d2SAndroid Build Coastguard Worker 	str[1024];			// Localized message
669*5e7646d2SAndroid Build Coastguard Worker 
670*5e7646d2SAndroid Build Coastguard Worker 
671*5e7646d2SAndroid Build Coastguard Worker   if (CFStringGetCString(key, id, sizeof(id), kCFStringEncodingUTF8) &&
672*5e7646d2SAndroid Build Coastguard Worker       CFStringGetCString(val, str, sizeof(str), kCFStringEncodingUTF8))
673*5e7646d2SAndroid Build Coastguard Worker     c->add_message(id, str);
674*5e7646d2SAndroid Build Coastguard Worker }
675*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ && CUPS_BUNDLEDIR */
676*5e7646d2SAndroid Build Coastguard Worker 
677*5e7646d2SAndroid Build Coastguard Worker 
678*5e7646d2SAndroid Build Coastguard Worker //
679*5e7646d2SAndroid Build Coastguard Worker // 'get_utf8()' - Get a UTF-8 character.
680*5e7646d2SAndroid Build Coastguard Worker //
681*5e7646d2SAndroid Build Coastguard Worker 
682*5e7646d2SAndroid Build Coastguard Worker static int				// O  - Unicode character or 0 on EOF
get_utf8(char * & ptr)683*5e7646d2SAndroid Build Coastguard Worker get_utf8(char *&ptr)			// IO - Pointer to character
684*5e7646d2SAndroid Build Coastguard Worker {
685*5e7646d2SAndroid Build Coastguard Worker   int	ch;				// Current character
686*5e7646d2SAndroid Build Coastguard Worker 
687*5e7646d2SAndroid Build Coastguard Worker 
688*5e7646d2SAndroid Build Coastguard Worker   if ((ch = *ptr++ & 255) < 0xc0)
689*5e7646d2SAndroid Build Coastguard Worker     return (ch);
690*5e7646d2SAndroid Build Coastguard Worker 
691*5e7646d2SAndroid Build Coastguard Worker   if ((ch & 0xe0) == 0xc0)
692*5e7646d2SAndroid Build Coastguard Worker   {
693*5e7646d2SAndroid Build Coastguard Worker     // Two-byte UTF-8...
694*5e7646d2SAndroid Build Coastguard Worker     if ((*ptr & 0xc0) != 0x80)
695*5e7646d2SAndroid Build Coastguard Worker       return (0);
696*5e7646d2SAndroid Build Coastguard Worker 
697*5e7646d2SAndroid Build Coastguard Worker     ch = ((ch & 0x1f) << 6) | (*ptr++ & 0x3f);
698*5e7646d2SAndroid Build Coastguard Worker   }
699*5e7646d2SAndroid Build Coastguard Worker   else if ((ch & 0xf0) == 0xe0)
700*5e7646d2SAndroid Build Coastguard Worker   {
701*5e7646d2SAndroid Build Coastguard Worker     // Three-byte UTF-8...
702*5e7646d2SAndroid Build Coastguard Worker     if ((*ptr & 0xc0) != 0x80)
703*5e7646d2SAndroid Build Coastguard Worker       return (0);
704*5e7646d2SAndroid Build Coastguard Worker 
705*5e7646d2SAndroid Build Coastguard Worker     ch = ((ch & 0x0f) << 6) | (*ptr++ & 0x3f);
706*5e7646d2SAndroid Build Coastguard Worker 
707*5e7646d2SAndroid Build Coastguard Worker     if ((*ptr & 0xc0) != 0x80)
708*5e7646d2SAndroid Build Coastguard Worker       return (0);
709*5e7646d2SAndroid Build Coastguard Worker 
710*5e7646d2SAndroid Build Coastguard Worker     ch = (ch << 6) | (*ptr++ & 0x3f);
711*5e7646d2SAndroid Build Coastguard Worker   }
712*5e7646d2SAndroid Build Coastguard Worker   else if ((ch & 0xf8) == 0xf0)
713*5e7646d2SAndroid Build Coastguard Worker   {
714*5e7646d2SAndroid Build Coastguard Worker     // Four-byte UTF-8...
715*5e7646d2SAndroid Build Coastguard Worker     if ((*ptr & 0xc0) != 0x80)
716*5e7646d2SAndroid Build Coastguard Worker       return (0);
717*5e7646d2SAndroid Build Coastguard Worker 
718*5e7646d2SAndroid Build Coastguard Worker     ch = ((ch & 0x07) << 6) | (*ptr++ & 0x3f);
719*5e7646d2SAndroid Build Coastguard Worker 
720*5e7646d2SAndroid Build Coastguard Worker     if ((*ptr & 0xc0) != 0x80)
721*5e7646d2SAndroid Build Coastguard Worker       return (0);
722*5e7646d2SAndroid Build Coastguard Worker 
723*5e7646d2SAndroid Build Coastguard Worker     ch = (ch << 6) | (*ptr++ & 0x3f);
724*5e7646d2SAndroid Build Coastguard Worker 
725*5e7646d2SAndroid Build Coastguard Worker     if ((*ptr & 0xc0) != 0x80)
726*5e7646d2SAndroid Build Coastguard Worker       return (0);
727*5e7646d2SAndroid Build Coastguard Worker 
728*5e7646d2SAndroid Build Coastguard Worker     ch = (ch << 6) | (*ptr++ & 0x3f);
729*5e7646d2SAndroid Build Coastguard Worker   }
730*5e7646d2SAndroid Build Coastguard Worker 
731*5e7646d2SAndroid Build Coastguard Worker   return (ch);
732*5e7646d2SAndroid Build Coastguard Worker }
733*5e7646d2SAndroid Build Coastguard Worker 
734*5e7646d2SAndroid Build Coastguard Worker 
735*5e7646d2SAndroid Build Coastguard Worker //
736*5e7646d2SAndroid Build Coastguard Worker // 'get_utf16()' - Get a UTF-16 character...
737*5e7646d2SAndroid Build Coastguard Worker //
738*5e7646d2SAndroid Build Coastguard Worker 
739*5e7646d2SAndroid Build Coastguard Worker static int				// O  - Unicode character or 0 on EOF
get_utf16(cups_file_t * fp,ppdc_cs_t & cs)740*5e7646d2SAndroid Build Coastguard Worker get_utf16(cups_file_t *fp,		// I  - File to read from
741*5e7646d2SAndroid Build Coastguard Worker           ppdc_cs_t   &cs)		// IO - Character set of file
742*5e7646d2SAndroid Build Coastguard Worker {
743*5e7646d2SAndroid Build Coastguard Worker   int		ch;			// Current character
744*5e7646d2SAndroid Build Coastguard Worker   unsigned char	buffer[3];		// Bytes
745*5e7646d2SAndroid Build Coastguard Worker 
746*5e7646d2SAndroid Build Coastguard Worker 
747*5e7646d2SAndroid Build Coastguard Worker   if (cs == PPDC_CS_AUTO)
748*5e7646d2SAndroid Build Coastguard Worker   {
749*5e7646d2SAndroid Build Coastguard Worker     // Get byte-order-mark, if present...
750*5e7646d2SAndroid Build Coastguard Worker     if (cupsFileRead(fp, (char *)buffer, 2) != 2)
751*5e7646d2SAndroid Build Coastguard Worker       return (0);
752*5e7646d2SAndroid Build Coastguard Worker 
753*5e7646d2SAndroid Build Coastguard Worker     if (buffer[0] == 0xfe && buffer[1] == 0xff)
754*5e7646d2SAndroid Build Coastguard Worker     {
755*5e7646d2SAndroid Build Coastguard Worker       // Big-endian UTF-16...
756*5e7646d2SAndroid Build Coastguard Worker       cs = PPDC_CS_UTF16BE;
757*5e7646d2SAndroid Build Coastguard Worker 
758*5e7646d2SAndroid Build Coastguard Worker       if (cupsFileRead(fp, (char *)buffer, 2) != 2)
759*5e7646d2SAndroid Build Coastguard Worker 	return (0);
760*5e7646d2SAndroid Build Coastguard Worker     }
761*5e7646d2SAndroid Build Coastguard Worker     else if (buffer[0] == 0xff && buffer[1] == 0xfe)
762*5e7646d2SAndroid Build Coastguard Worker     {
763*5e7646d2SAndroid Build Coastguard Worker       // Little-endian UTF-16...
764*5e7646d2SAndroid Build Coastguard Worker       cs = PPDC_CS_UTF16LE;
765*5e7646d2SAndroid Build Coastguard Worker 
766*5e7646d2SAndroid Build Coastguard Worker       if (cupsFileRead(fp, (char *)buffer, 2) != 2)
767*5e7646d2SAndroid Build Coastguard Worker 	return (0);
768*5e7646d2SAndroid Build Coastguard Worker     }
769*5e7646d2SAndroid Build Coastguard Worker     else if (buffer[0] == 0x00 && buffer[1] != 0x00)
770*5e7646d2SAndroid Build Coastguard Worker     {
771*5e7646d2SAndroid Build Coastguard Worker       // No BOM, assume big-endian UTF-16...
772*5e7646d2SAndroid Build Coastguard Worker       cs = PPDC_CS_UTF16BE;
773*5e7646d2SAndroid Build Coastguard Worker     }
774*5e7646d2SAndroid Build Coastguard Worker     else if (buffer[0] != 0x00 && buffer[1] == 0x00)
775*5e7646d2SAndroid Build Coastguard Worker     {
776*5e7646d2SAndroid Build Coastguard Worker       // No BOM, assume little-endian UTF-16...
777*5e7646d2SAndroid Build Coastguard Worker       cs = PPDC_CS_UTF16LE;
778*5e7646d2SAndroid Build Coastguard Worker     }
779*5e7646d2SAndroid Build Coastguard Worker     else
780*5e7646d2SAndroid Build Coastguard Worker     {
781*5e7646d2SAndroid Build Coastguard Worker       // No BOM, assume UTF-8...
782*5e7646d2SAndroid Build Coastguard Worker       cs = PPDC_CS_UTF8;
783*5e7646d2SAndroid Build Coastguard Worker 
784*5e7646d2SAndroid Build Coastguard Worker       cupsFileRewind(fp);
785*5e7646d2SAndroid Build Coastguard Worker     }
786*5e7646d2SAndroid Build Coastguard Worker   }
787*5e7646d2SAndroid Build Coastguard Worker   else if (cs != PPDC_CS_UTF8)
788*5e7646d2SAndroid Build Coastguard Worker   {
789*5e7646d2SAndroid Build Coastguard Worker     if (cupsFileRead(fp, (char *)buffer, 2) != 2)
790*5e7646d2SAndroid Build Coastguard Worker       return (0);
791*5e7646d2SAndroid Build Coastguard Worker   }
792*5e7646d2SAndroid Build Coastguard Worker 
793*5e7646d2SAndroid Build Coastguard Worker   if (cs == PPDC_CS_UTF8)
794*5e7646d2SAndroid Build Coastguard Worker   {
795*5e7646d2SAndroid Build Coastguard Worker     // UTF-8 character...
796*5e7646d2SAndroid Build Coastguard Worker     if ((ch = cupsFileGetChar(fp)) < 0)
797*5e7646d2SAndroid Build Coastguard Worker       return (0);
798*5e7646d2SAndroid Build Coastguard Worker 
799*5e7646d2SAndroid Build Coastguard Worker     if ((ch & 0xe0) == 0xc0)
800*5e7646d2SAndroid Build Coastguard Worker     {
801*5e7646d2SAndroid Build Coastguard Worker       // Two-byte UTF-8...
802*5e7646d2SAndroid Build Coastguard Worker       if (cupsFileRead(fp, (char *)buffer, 1) != 1)
803*5e7646d2SAndroid Build Coastguard Worker         return (0);
804*5e7646d2SAndroid Build Coastguard Worker 
805*5e7646d2SAndroid Build Coastguard Worker       if ((buffer[0] & 0xc0) != 0x80)
806*5e7646d2SAndroid Build Coastguard Worker         return (0);
807*5e7646d2SAndroid Build Coastguard Worker 
808*5e7646d2SAndroid Build Coastguard Worker       ch = ((ch & 0x1f) << 6) | (buffer[0] & 0x3f);
809*5e7646d2SAndroid Build Coastguard Worker     }
810*5e7646d2SAndroid Build Coastguard Worker     else if ((ch & 0xf0) == 0xe0)
811*5e7646d2SAndroid Build Coastguard Worker     {
812*5e7646d2SAndroid Build Coastguard Worker       // Three-byte UTF-8...
813*5e7646d2SAndroid Build Coastguard Worker       if (cupsFileRead(fp, (char *)buffer, 2) != 2)
814*5e7646d2SAndroid Build Coastguard Worker         return (0);
815*5e7646d2SAndroid Build Coastguard Worker 
816*5e7646d2SAndroid Build Coastguard Worker       if ((buffer[0] & 0xc0) != 0x80 ||
817*5e7646d2SAndroid Build Coastguard Worker           (buffer[1] & 0xc0) != 0x80)
818*5e7646d2SAndroid Build Coastguard Worker         return (0);
819*5e7646d2SAndroid Build Coastguard Worker 
820*5e7646d2SAndroid Build Coastguard Worker       ch = ((((ch & 0x0f) << 6) | (buffer[0] & 0x3f)) << 6) |
821*5e7646d2SAndroid Build Coastguard Worker            (buffer[1] & 0x3f);
822*5e7646d2SAndroid Build Coastguard Worker     }
823*5e7646d2SAndroid Build Coastguard Worker     else if ((ch & 0xf8) == 0xf0)
824*5e7646d2SAndroid Build Coastguard Worker     {
825*5e7646d2SAndroid Build Coastguard Worker       // Four-byte UTF-8...
826*5e7646d2SAndroid Build Coastguard Worker       if (cupsFileRead(fp, (char *)buffer, 3) != 3)
827*5e7646d2SAndroid Build Coastguard Worker         return (0);
828*5e7646d2SAndroid Build Coastguard Worker 
829*5e7646d2SAndroid Build Coastguard Worker       if ((buffer[0] & 0xc0) != 0x80 ||
830*5e7646d2SAndroid Build Coastguard Worker           (buffer[1] & 0xc0) != 0x80 ||
831*5e7646d2SAndroid Build Coastguard Worker           (buffer[2] & 0xc0) != 0x80)
832*5e7646d2SAndroid Build Coastguard Worker         return (0);
833*5e7646d2SAndroid Build Coastguard Worker 
834*5e7646d2SAndroid Build Coastguard Worker       ch = ((((((ch & 0x07) << 6) | (buffer[0] & 0x3f)) << 6) |
835*5e7646d2SAndroid Build Coastguard Worker              (buffer[1] & 0x3f)) << 6) | (buffer[2] & 0x3f);
836*5e7646d2SAndroid Build Coastguard Worker     }
837*5e7646d2SAndroid Build Coastguard Worker   }
838*5e7646d2SAndroid Build Coastguard Worker   else
839*5e7646d2SAndroid Build Coastguard Worker   {
840*5e7646d2SAndroid Build Coastguard Worker     // UTF-16 character...
841*5e7646d2SAndroid Build Coastguard Worker     if (cs == PPDC_CS_UTF16BE)
842*5e7646d2SAndroid Build Coastguard Worker       ch = (buffer[0] << 8) | buffer[1];
843*5e7646d2SAndroid Build Coastguard Worker     else
844*5e7646d2SAndroid Build Coastguard Worker       ch = (buffer[1] << 8) | buffer[0];
845*5e7646d2SAndroid Build Coastguard Worker 
846*5e7646d2SAndroid Build Coastguard Worker     if (ch >= 0xd800 && ch <= 0xdbff)
847*5e7646d2SAndroid Build Coastguard Worker     {
848*5e7646d2SAndroid Build Coastguard Worker       // Handle multi-word encoding...
849*5e7646d2SAndroid Build Coastguard Worker       int lch;
850*5e7646d2SAndroid Build Coastguard Worker 
851*5e7646d2SAndroid Build Coastguard Worker       if (cupsFileRead(fp, (char *)buffer, 2) != 2)
852*5e7646d2SAndroid Build Coastguard Worker         return (0);
853*5e7646d2SAndroid Build Coastguard Worker 
854*5e7646d2SAndroid Build Coastguard Worker       if (cs == PPDC_CS_UTF16BE)
855*5e7646d2SAndroid Build Coastguard Worker 	lch = (buffer[0] << 8) | buffer[1];
856*5e7646d2SAndroid Build Coastguard Worker       else
857*5e7646d2SAndroid Build Coastguard Worker 	lch = (buffer[1] << 8) | buffer[0];
858*5e7646d2SAndroid Build Coastguard Worker 
859*5e7646d2SAndroid Build Coastguard Worker       if (lch < 0xdc00 || lch >= 0xdfff)
860*5e7646d2SAndroid Build Coastguard Worker         return (0);
861*5e7646d2SAndroid Build Coastguard Worker 
862*5e7646d2SAndroid Build Coastguard Worker       ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
863*5e7646d2SAndroid Build Coastguard Worker     }
864*5e7646d2SAndroid Build Coastguard Worker   }
865*5e7646d2SAndroid Build Coastguard Worker 
866*5e7646d2SAndroid Build Coastguard Worker   return (ch);
867*5e7646d2SAndroid Build Coastguard Worker }
868*5e7646d2SAndroid Build Coastguard Worker 
869*5e7646d2SAndroid Build Coastguard Worker 
870*5e7646d2SAndroid Build Coastguard Worker //
871*5e7646d2SAndroid Build Coastguard Worker // 'put_utf8()' - Add a UTF-8 character to a string.
872*5e7646d2SAndroid Build Coastguard Worker //
873*5e7646d2SAndroid Build Coastguard Worker 
874*5e7646d2SAndroid Build Coastguard Worker static int				// O  - 0 on success, -1 on failure
put_utf8(int ch,char * & ptr,char * end)875*5e7646d2SAndroid Build Coastguard Worker put_utf8(int  ch,			// I  - Unicode character
876*5e7646d2SAndroid Build Coastguard Worker          char *&ptr,			// IO - String pointer
877*5e7646d2SAndroid Build Coastguard Worker 	 char *end)			// I  - End of buffer
878*5e7646d2SAndroid Build Coastguard Worker {
879*5e7646d2SAndroid Build Coastguard Worker   if (ch < 0x80)
880*5e7646d2SAndroid Build Coastguard Worker   {
881*5e7646d2SAndroid Build Coastguard Worker     // One-byte ASCII...
882*5e7646d2SAndroid Build Coastguard Worker     if (ptr >= end)
883*5e7646d2SAndroid Build Coastguard Worker       return (-1);
884*5e7646d2SAndroid Build Coastguard Worker 
885*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)ch;
886*5e7646d2SAndroid Build Coastguard Worker   }
887*5e7646d2SAndroid Build Coastguard Worker   else if (ch < 0x800)
888*5e7646d2SAndroid Build Coastguard Worker   {
889*5e7646d2SAndroid Build Coastguard Worker     // Two-byte UTF-8...
890*5e7646d2SAndroid Build Coastguard Worker     if ((ptr + 1) >= end)
891*5e7646d2SAndroid Build Coastguard Worker       return (-1);
892*5e7646d2SAndroid Build Coastguard Worker 
893*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0xc0 | (ch >> 6));
894*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0x80 | (ch & 0x3f));
895*5e7646d2SAndroid Build Coastguard Worker   }
896*5e7646d2SAndroid Build Coastguard Worker   else if (ch < 0x10000)
897*5e7646d2SAndroid Build Coastguard Worker   {
898*5e7646d2SAndroid Build Coastguard Worker     // Three-byte UTF-8...
899*5e7646d2SAndroid Build Coastguard Worker     if ((ptr + 2) >= end)
900*5e7646d2SAndroid Build Coastguard Worker       return (-1);
901*5e7646d2SAndroid Build Coastguard Worker 
902*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0xe0 | (ch >> 12));
903*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
904*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0x80 | (ch & 0x3f));
905*5e7646d2SAndroid Build Coastguard Worker   }
906*5e7646d2SAndroid Build Coastguard Worker   else
907*5e7646d2SAndroid Build Coastguard Worker   {
908*5e7646d2SAndroid Build Coastguard Worker     // Four-byte UTF-8...
909*5e7646d2SAndroid Build Coastguard Worker     if ((ptr + 3) >= end)
910*5e7646d2SAndroid Build Coastguard Worker       return (-1);
911*5e7646d2SAndroid Build Coastguard Worker 
912*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0xf0 | (ch >> 18));
913*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0x80 | ((ch >> 12) & 0x3f));
914*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
915*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = (char)(0x80 | (ch & 0x3f));
916*5e7646d2SAndroid Build Coastguard Worker   }
917*5e7646d2SAndroid Build Coastguard Worker 
918*5e7646d2SAndroid Build Coastguard Worker   return (0);
919*5e7646d2SAndroid Build Coastguard Worker }
920*5e7646d2SAndroid Build Coastguard Worker 
921*5e7646d2SAndroid Build Coastguard Worker 
922*5e7646d2SAndroid Build Coastguard Worker //
923*5e7646d2SAndroid Build Coastguard Worker // 'put_utf16()' - Write a UTF-16 character to a file.
924*5e7646d2SAndroid Build Coastguard Worker //
925*5e7646d2SAndroid Build Coastguard Worker 
926*5e7646d2SAndroid Build Coastguard Worker static int				// O - 0 on success, -1 on failure
put_utf16(cups_file_t * fp,int ch)927*5e7646d2SAndroid Build Coastguard Worker put_utf16(cups_file_t *fp,		// I - File to write to
928*5e7646d2SAndroid Build Coastguard Worker           int         ch)		// I - Unicode character
929*5e7646d2SAndroid Build Coastguard Worker {
930*5e7646d2SAndroid Build Coastguard Worker   unsigned char	buffer[4];		// Output buffer
931*5e7646d2SAndroid Build Coastguard Worker 
932*5e7646d2SAndroid Build Coastguard Worker 
933*5e7646d2SAndroid Build Coastguard Worker   if (ch < 0x10000)
934*5e7646d2SAndroid Build Coastguard Worker   {
935*5e7646d2SAndroid Build Coastguard Worker     // One-word UTF-16 big-endian...
936*5e7646d2SAndroid Build Coastguard Worker     buffer[0] = (unsigned char)(ch >> 8);
937*5e7646d2SAndroid Build Coastguard Worker     buffer[1] = (unsigned char)ch;
938*5e7646d2SAndroid Build Coastguard Worker 
939*5e7646d2SAndroid Build Coastguard Worker     if (cupsFileWrite(fp, (char *)buffer, 2) == 2)
940*5e7646d2SAndroid Build Coastguard Worker       return (0);
941*5e7646d2SAndroid Build Coastguard Worker   }
942*5e7646d2SAndroid Build Coastguard Worker   else
943*5e7646d2SAndroid Build Coastguard Worker   {
944*5e7646d2SAndroid Build Coastguard Worker     // Two-word UTF-16 big-endian...
945*5e7646d2SAndroid Build Coastguard Worker     ch -= 0x10000;
946*5e7646d2SAndroid Build Coastguard Worker 
947*5e7646d2SAndroid Build Coastguard Worker     buffer[0] = (unsigned char)(0xd8 | (ch >> 18));
948*5e7646d2SAndroid Build Coastguard Worker     buffer[1] = (unsigned char)(ch >> 10);
949*5e7646d2SAndroid Build Coastguard Worker     buffer[2] = (unsigned char)(0xdc | ((ch >> 8) & 0x03));
950*5e7646d2SAndroid Build Coastguard Worker     buffer[3] = (unsigned char)ch;
951*5e7646d2SAndroid Build Coastguard Worker 
952*5e7646d2SAndroid Build Coastguard Worker     if (cupsFileWrite(fp, (char *)buffer, 4) == 4)
953*5e7646d2SAndroid Build Coastguard Worker       return (0);
954*5e7646d2SAndroid Build Coastguard Worker   }
955*5e7646d2SAndroid Build Coastguard Worker 
956*5e7646d2SAndroid Build Coastguard Worker   return (-1);
957*5e7646d2SAndroid Build Coastguard Worker }
958