xref: /aosp_15_r20/external/libxml2/xmlstring.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
1*7c568831SAndroid Build Coastguard Worker /*
2*7c568831SAndroid Build Coastguard Worker  * string.c : an XML string utilities module
3*7c568831SAndroid Build Coastguard Worker  *
4*7c568831SAndroid Build Coastguard Worker  * This module provides various utility functions for manipulating
5*7c568831SAndroid Build Coastguard Worker  * the xmlChar* type. All functions named xmlStr* have been moved here
6*7c568831SAndroid Build Coastguard Worker  * from the parser.c file (their original home).
7*7c568831SAndroid Build Coastguard Worker  *
8*7c568831SAndroid Build Coastguard Worker  * See Copyright for the status of this software.
9*7c568831SAndroid Build Coastguard Worker  *
10*7c568831SAndroid Build Coastguard Worker  * UTF8 string routines from:
11*7c568831SAndroid Build Coastguard Worker  * William Brack <[email protected]>
12*7c568831SAndroid Build Coastguard Worker  *
13*7c568831SAndroid Build Coastguard Worker  * [email protected]
14*7c568831SAndroid Build Coastguard Worker  */
15*7c568831SAndroid Build Coastguard Worker 
16*7c568831SAndroid Build Coastguard Worker #define IN_LIBXML
17*7c568831SAndroid Build Coastguard Worker #include "libxml.h"
18*7c568831SAndroid Build Coastguard Worker 
19*7c568831SAndroid Build Coastguard Worker #include <stdlib.h>
20*7c568831SAndroid Build Coastguard Worker #include <string.h>
21*7c568831SAndroid Build Coastguard Worker #include <limits.h>
22*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlmemory.h>
23*7c568831SAndroid Build Coastguard Worker #include <libxml/parserInternals.h>
24*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlstring.h>
25*7c568831SAndroid Build Coastguard Worker 
26*7c568831SAndroid Build Coastguard Worker #include "private/parser.h"
27*7c568831SAndroid Build Coastguard Worker #include "private/string.h"
28*7c568831SAndroid Build Coastguard Worker 
29*7c568831SAndroid Build Coastguard Worker #ifndef va_copy
30*7c568831SAndroid Build Coastguard Worker   #ifdef __va_copy
31*7c568831SAndroid Build Coastguard Worker     #define va_copy(dest, src) __va_copy(dest, src)
32*7c568831SAndroid Build Coastguard Worker   #else
33*7c568831SAndroid Build Coastguard Worker     #define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list))
34*7c568831SAndroid Build Coastguard Worker   #endif
35*7c568831SAndroid Build Coastguard Worker #endif
36*7c568831SAndroid Build Coastguard Worker 
37*7c568831SAndroid Build Coastguard Worker /************************************************************************
38*7c568831SAndroid Build Coastguard Worker  *                                                                      *
39*7c568831SAndroid Build Coastguard Worker  *                Commodity functions to handle xmlChars                *
40*7c568831SAndroid Build Coastguard Worker  *                                                                      *
41*7c568831SAndroid Build Coastguard Worker  ************************************************************************/
42*7c568831SAndroid Build Coastguard Worker 
43*7c568831SAndroid Build Coastguard Worker /**
44*7c568831SAndroid Build Coastguard Worker  * xmlStrndup:
45*7c568831SAndroid Build Coastguard Worker  * @cur:  the input xmlChar *
46*7c568831SAndroid Build Coastguard Worker  * @len:  the len of @cur
47*7c568831SAndroid Build Coastguard Worker  *
48*7c568831SAndroid Build Coastguard Worker  * a strndup for array of xmlChar's
49*7c568831SAndroid Build Coastguard Worker  *
50*7c568831SAndroid Build Coastguard Worker  * Returns a new xmlChar * or NULL
51*7c568831SAndroid Build Coastguard Worker  */
52*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlStrndup(const xmlChar * cur,int len)53*7c568831SAndroid Build Coastguard Worker xmlStrndup(const xmlChar *cur, int len) {
54*7c568831SAndroid Build Coastguard Worker     xmlChar *ret;
55*7c568831SAndroid Build Coastguard Worker 
56*7c568831SAndroid Build Coastguard Worker     if ((cur == NULL) || (len < 0)) return(NULL);
57*7c568831SAndroid Build Coastguard Worker     ret = xmlMalloc((size_t) len + 1);
58*7c568831SAndroid Build Coastguard Worker     if (ret == NULL) {
59*7c568831SAndroid Build Coastguard Worker         return(NULL);
60*7c568831SAndroid Build Coastguard Worker     }
61*7c568831SAndroid Build Coastguard Worker     memcpy(ret, cur, len);
62*7c568831SAndroid Build Coastguard Worker     ret[len] = 0;
63*7c568831SAndroid Build Coastguard Worker     return(ret);
64*7c568831SAndroid Build Coastguard Worker }
65*7c568831SAndroid Build Coastguard Worker 
66*7c568831SAndroid Build Coastguard Worker /**
67*7c568831SAndroid Build Coastguard Worker  * xmlStrdup:
68*7c568831SAndroid Build Coastguard Worker  * @cur:  the input xmlChar *
69*7c568831SAndroid Build Coastguard Worker  *
70*7c568831SAndroid Build Coastguard Worker  * a strdup for array of xmlChar's. Since they are supposed to be
71*7c568831SAndroid Build Coastguard Worker  * encoded in UTF-8 or an encoding with 8bit based chars, we assume
72*7c568831SAndroid Build Coastguard Worker  * a termination mark of '0'.
73*7c568831SAndroid Build Coastguard Worker  *
74*7c568831SAndroid Build Coastguard Worker  * Returns a new xmlChar * or NULL
75*7c568831SAndroid Build Coastguard Worker  */
76*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlStrdup(const xmlChar * cur)77*7c568831SAndroid Build Coastguard Worker xmlStrdup(const xmlChar *cur) {
78*7c568831SAndroid Build Coastguard Worker     const xmlChar *p = cur;
79*7c568831SAndroid Build Coastguard Worker 
80*7c568831SAndroid Build Coastguard Worker     if (cur == NULL) return(NULL);
81*7c568831SAndroid Build Coastguard Worker     while (*p != 0) p++; /* non input consuming */
82*7c568831SAndroid Build Coastguard Worker     return(xmlStrndup(cur, p - cur));
83*7c568831SAndroid Build Coastguard Worker }
84*7c568831SAndroid Build Coastguard Worker 
85*7c568831SAndroid Build Coastguard Worker /**
86*7c568831SAndroid Build Coastguard Worker  * xmlCharStrndup:
87*7c568831SAndroid Build Coastguard Worker  * @cur:  the input char *
88*7c568831SAndroid Build Coastguard Worker  * @len:  the len of @cur
89*7c568831SAndroid Build Coastguard Worker  *
90*7c568831SAndroid Build Coastguard Worker  * a strndup for char's to xmlChar's
91*7c568831SAndroid Build Coastguard Worker  *
92*7c568831SAndroid Build Coastguard Worker  * Returns a new xmlChar * or NULL
93*7c568831SAndroid Build Coastguard Worker  */
94*7c568831SAndroid Build Coastguard Worker 
95*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlCharStrndup(const char * cur,int len)96*7c568831SAndroid Build Coastguard Worker xmlCharStrndup(const char *cur, int len) {
97*7c568831SAndroid Build Coastguard Worker     int i;
98*7c568831SAndroid Build Coastguard Worker     xmlChar *ret;
99*7c568831SAndroid Build Coastguard Worker 
100*7c568831SAndroid Build Coastguard Worker     if ((cur == NULL) || (len < 0)) return(NULL);
101*7c568831SAndroid Build Coastguard Worker     ret = xmlMalloc((size_t) len + 1);
102*7c568831SAndroid Build Coastguard Worker     if (ret == NULL) {
103*7c568831SAndroid Build Coastguard Worker         return(NULL);
104*7c568831SAndroid Build Coastguard Worker     }
105*7c568831SAndroid Build Coastguard Worker     for (i = 0;i < len;i++) {
106*7c568831SAndroid Build Coastguard Worker         /* Explicit sign change */
107*7c568831SAndroid Build Coastguard Worker         ret[i] = (xmlChar) cur[i];
108*7c568831SAndroid Build Coastguard Worker         if (ret[i] == 0) return(ret);
109*7c568831SAndroid Build Coastguard Worker     }
110*7c568831SAndroid Build Coastguard Worker     ret[len] = 0;
111*7c568831SAndroid Build Coastguard Worker     return(ret);
112*7c568831SAndroid Build Coastguard Worker }
113*7c568831SAndroid Build Coastguard Worker 
114*7c568831SAndroid Build Coastguard Worker /**
115*7c568831SAndroid Build Coastguard Worker  * xmlCharStrdup:
116*7c568831SAndroid Build Coastguard Worker  * @cur:  the input char *
117*7c568831SAndroid Build Coastguard Worker  *
118*7c568831SAndroid Build Coastguard Worker  * a strdup for char's to xmlChar's
119*7c568831SAndroid Build Coastguard Worker  *
120*7c568831SAndroid Build Coastguard Worker  * Returns a new xmlChar * or NULL
121*7c568831SAndroid Build Coastguard Worker  */
122*7c568831SAndroid Build Coastguard Worker 
123*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlCharStrdup(const char * cur)124*7c568831SAndroid Build Coastguard Worker xmlCharStrdup(const char *cur) {
125*7c568831SAndroid Build Coastguard Worker     const char *p = cur;
126*7c568831SAndroid Build Coastguard Worker 
127*7c568831SAndroid Build Coastguard Worker     if (cur == NULL) return(NULL);
128*7c568831SAndroid Build Coastguard Worker     while (*p != '\0') p++; /* non input consuming */
129*7c568831SAndroid Build Coastguard Worker     return(xmlCharStrndup(cur, p - cur));
130*7c568831SAndroid Build Coastguard Worker }
131*7c568831SAndroid Build Coastguard Worker 
132*7c568831SAndroid Build Coastguard Worker /**
133*7c568831SAndroid Build Coastguard Worker  * xmlStrcmp:
134*7c568831SAndroid Build Coastguard Worker  * @str1:  the first xmlChar *
135*7c568831SAndroid Build Coastguard Worker  * @str2:  the second xmlChar *
136*7c568831SAndroid Build Coastguard Worker  *
137*7c568831SAndroid Build Coastguard Worker  * a strcmp for xmlChar's
138*7c568831SAndroid Build Coastguard Worker  *
139*7c568831SAndroid Build Coastguard Worker  * Returns the integer result of the comparison
140*7c568831SAndroid Build Coastguard Worker  */
141*7c568831SAndroid Build Coastguard Worker 
142*7c568831SAndroid Build Coastguard Worker int
xmlStrcmp(const xmlChar * str1,const xmlChar * str2)143*7c568831SAndroid Build Coastguard Worker xmlStrcmp(const xmlChar *str1, const xmlChar *str2) {
144*7c568831SAndroid Build Coastguard Worker     if (str1 == str2) return(0);
145*7c568831SAndroid Build Coastguard Worker     if (str1 == NULL) return(-1);
146*7c568831SAndroid Build Coastguard Worker     if (str2 == NULL) return(1);
147*7c568831SAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
148*7c568831SAndroid Build Coastguard Worker     return(strcmp((const char *)str1, (const char *)str2));
149*7c568831SAndroid Build Coastguard Worker #else
150*7c568831SAndroid Build Coastguard Worker     do {
151*7c568831SAndroid Build Coastguard Worker         int tmp = *str1++ - *str2;
152*7c568831SAndroid Build Coastguard Worker         if (tmp != 0) return(tmp);
153*7c568831SAndroid Build Coastguard Worker     } while (*str2++ != 0);
154*7c568831SAndroid Build Coastguard Worker     return 0;
155*7c568831SAndroid Build Coastguard Worker #endif
156*7c568831SAndroid Build Coastguard Worker }
157*7c568831SAndroid Build Coastguard Worker 
158*7c568831SAndroid Build Coastguard Worker /**
159*7c568831SAndroid Build Coastguard Worker  * xmlStrEqual:
160*7c568831SAndroid Build Coastguard Worker  * @str1:  the first xmlChar *
161*7c568831SAndroid Build Coastguard Worker  * @str2:  the second xmlChar *
162*7c568831SAndroid Build Coastguard Worker  *
163*7c568831SAndroid Build Coastguard Worker  * Check if both strings are equal of have same content.
164*7c568831SAndroid Build Coastguard Worker  * Should be a bit more readable and faster than xmlStrcmp()
165*7c568831SAndroid Build Coastguard Worker  *
166*7c568831SAndroid Build Coastguard Worker  * Returns 1 if they are equal, 0 if they are different
167*7c568831SAndroid Build Coastguard Worker  */
168*7c568831SAndroid Build Coastguard Worker 
169*7c568831SAndroid Build Coastguard Worker int
xmlStrEqual(const xmlChar * str1,const xmlChar * str2)170*7c568831SAndroid Build Coastguard Worker xmlStrEqual(const xmlChar *str1, const xmlChar *str2) {
171*7c568831SAndroid Build Coastguard Worker     if (str1 == str2) return(1);
172*7c568831SAndroid Build Coastguard Worker     if (str1 == NULL) return(0);
173*7c568831SAndroid Build Coastguard Worker     if (str2 == NULL) return(0);
174*7c568831SAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
175*7c568831SAndroid Build Coastguard Worker     return(strcmp((const char *)str1, (const char *)str2) == 0);
176*7c568831SAndroid Build Coastguard Worker #else
177*7c568831SAndroid Build Coastguard Worker     do {
178*7c568831SAndroid Build Coastguard Worker         if (*str1++ != *str2) return(0);
179*7c568831SAndroid Build Coastguard Worker     } while (*str2++);
180*7c568831SAndroid Build Coastguard Worker     return(1);
181*7c568831SAndroid Build Coastguard Worker #endif
182*7c568831SAndroid Build Coastguard Worker }
183*7c568831SAndroid Build Coastguard Worker 
184*7c568831SAndroid Build Coastguard Worker /**
185*7c568831SAndroid Build Coastguard Worker  * xmlStrQEqual:
186*7c568831SAndroid Build Coastguard Worker  * @pref:  the prefix of the QName
187*7c568831SAndroid Build Coastguard Worker  * @name:  the localname of the QName
188*7c568831SAndroid Build Coastguard Worker  * @str:  the second xmlChar *
189*7c568831SAndroid Build Coastguard Worker  *
190*7c568831SAndroid Build Coastguard Worker  * Check if a QName is Equal to a given string
191*7c568831SAndroid Build Coastguard Worker  *
192*7c568831SAndroid Build Coastguard Worker  * Returns 1 if they are equal, 0 if they are different
193*7c568831SAndroid Build Coastguard Worker  */
194*7c568831SAndroid Build Coastguard Worker 
195*7c568831SAndroid Build Coastguard Worker int
xmlStrQEqual(const xmlChar * pref,const xmlChar * name,const xmlChar * str)196*7c568831SAndroid Build Coastguard Worker xmlStrQEqual(const xmlChar *pref, const xmlChar *name, const xmlChar *str) {
197*7c568831SAndroid Build Coastguard Worker     if (pref == NULL) return(xmlStrEqual(name, str));
198*7c568831SAndroid Build Coastguard Worker     if (name == NULL) return(0);
199*7c568831SAndroid Build Coastguard Worker     if (str == NULL) return(0);
200*7c568831SAndroid Build Coastguard Worker 
201*7c568831SAndroid Build Coastguard Worker     do {
202*7c568831SAndroid Build Coastguard Worker         if (*pref++ != *str) return(0);
203*7c568831SAndroid Build Coastguard Worker     } while ((*str++) && (*pref));
204*7c568831SAndroid Build Coastguard Worker     if (*str++ != ':') return(0);
205*7c568831SAndroid Build Coastguard Worker     do {
206*7c568831SAndroid Build Coastguard Worker         if (*name++ != *str) return(0);
207*7c568831SAndroid Build Coastguard Worker     } while (*str++);
208*7c568831SAndroid Build Coastguard Worker     return(1);
209*7c568831SAndroid Build Coastguard Worker }
210*7c568831SAndroid Build Coastguard Worker 
211*7c568831SAndroid Build Coastguard Worker /**
212*7c568831SAndroid Build Coastguard Worker  * xmlStrncmp:
213*7c568831SAndroid Build Coastguard Worker  * @str1:  the first xmlChar *
214*7c568831SAndroid Build Coastguard Worker  * @str2:  the second xmlChar *
215*7c568831SAndroid Build Coastguard Worker  * @len:  the max comparison length
216*7c568831SAndroid Build Coastguard Worker  *
217*7c568831SAndroid Build Coastguard Worker  * a strncmp for xmlChar's
218*7c568831SAndroid Build Coastguard Worker  *
219*7c568831SAndroid Build Coastguard Worker  * Returns the integer result of the comparison
220*7c568831SAndroid Build Coastguard Worker  */
221*7c568831SAndroid Build Coastguard Worker 
222*7c568831SAndroid Build Coastguard Worker int
xmlStrncmp(const xmlChar * str1,const xmlChar * str2,int len)223*7c568831SAndroid Build Coastguard Worker xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) {
224*7c568831SAndroid Build Coastguard Worker     if (len <= 0) return(0);
225*7c568831SAndroid Build Coastguard Worker     if (str1 == str2) return(0);
226*7c568831SAndroid Build Coastguard Worker     if (str1 == NULL) return(-1);
227*7c568831SAndroid Build Coastguard Worker     if (str2 == NULL) return(1);
228*7c568831SAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
229*7c568831SAndroid Build Coastguard Worker     return(strncmp((const char *)str1, (const char *)str2, len));
230*7c568831SAndroid Build Coastguard Worker #else
231*7c568831SAndroid Build Coastguard Worker     do {
232*7c568831SAndroid Build Coastguard Worker         int tmp = *str1++ - *str2;
233*7c568831SAndroid Build Coastguard Worker         if (tmp != 0 || --len == 0) return(tmp);
234*7c568831SAndroid Build Coastguard Worker     } while (*str2++ != 0);
235*7c568831SAndroid Build Coastguard Worker     return 0;
236*7c568831SAndroid Build Coastguard Worker #endif
237*7c568831SAndroid Build Coastguard Worker }
238*7c568831SAndroid Build Coastguard Worker 
239*7c568831SAndroid Build Coastguard Worker static const xmlChar casemap[256] = {
240*7c568831SAndroid Build Coastguard Worker     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
241*7c568831SAndroid Build Coastguard Worker     0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
242*7c568831SAndroid Build Coastguard Worker     0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
243*7c568831SAndroid Build Coastguard Worker     0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
244*7c568831SAndroid Build Coastguard Worker     0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
245*7c568831SAndroid Build Coastguard Worker     0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
246*7c568831SAndroid Build Coastguard Worker     0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
247*7c568831SAndroid Build Coastguard Worker     0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
248*7c568831SAndroid Build Coastguard Worker     0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
249*7c568831SAndroid Build Coastguard Worker     0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
250*7c568831SAndroid Build Coastguard Worker     0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
251*7c568831SAndroid Build Coastguard Worker     0x78,0x79,0x7A,0x7B,0x5C,0x5D,0x5E,0x5F,
252*7c568831SAndroid Build Coastguard Worker     0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
253*7c568831SAndroid Build Coastguard Worker     0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
254*7c568831SAndroid Build Coastguard Worker     0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
255*7c568831SAndroid Build Coastguard Worker     0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
256*7c568831SAndroid Build Coastguard Worker     0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
257*7c568831SAndroid Build Coastguard Worker     0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
258*7c568831SAndroid Build Coastguard Worker     0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
259*7c568831SAndroid Build Coastguard Worker     0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
260*7c568831SAndroid Build Coastguard Worker     0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
261*7c568831SAndroid Build Coastguard Worker     0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
262*7c568831SAndroid Build Coastguard Worker     0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
263*7c568831SAndroid Build Coastguard Worker     0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
264*7c568831SAndroid Build Coastguard Worker     0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
265*7c568831SAndroid Build Coastguard Worker     0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
266*7c568831SAndroid Build Coastguard Worker     0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
267*7c568831SAndroid Build Coastguard Worker     0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
268*7c568831SAndroid Build Coastguard Worker     0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
269*7c568831SAndroid Build Coastguard Worker     0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
270*7c568831SAndroid Build Coastguard Worker     0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
271*7c568831SAndroid Build Coastguard Worker     0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
272*7c568831SAndroid Build Coastguard Worker };
273*7c568831SAndroid Build Coastguard Worker 
274*7c568831SAndroid Build Coastguard Worker /**
275*7c568831SAndroid Build Coastguard Worker  * xmlStrcasecmp:
276*7c568831SAndroid Build Coastguard Worker  * @str1:  the first xmlChar *
277*7c568831SAndroid Build Coastguard Worker  * @str2:  the second xmlChar *
278*7c568831SAndroid Build Coastguard Worker  *
279*7c568831SAndroid Build Coastguard Worker  * a strcasecmp for xmlChar's
280*7c568831SAndroid Build Coastguard Worker  *
281*7c568831SAndroid Build Coastguard Worker  * Returns the integer result of the comparison
282*7c568831SAndroid Build Coastguard Worker  */
283*7c568831SAndroid Build Coastguard Worker 
284*7c568831SAndroid Build Coastguard Worker int
xmlStrcasecmp(const xmlChar * str1,const xmlChar * str2)285*7c568831SAndroid Build Coastguard Worker xmlStrcasecmp(const xmlChar *str1, const xmlChar *str2) {
286*7c568831SAndroid Build Coastguard Worker     register int tmp;
287*7c568831SAndroid Build Coastguard Worker 
288*7c568831SAndroid Build Coastguard Worker     if (str1 == str2) return(0);
289*7c568831SAndroid Build Coastguard Worker     if (str1 == NULL) return(-1);
290*7c568831SAndroid Build Coastguard Worker     if (str2 == NULL) return(1);
291*7c568831SAndroid Build Coastguard Worker     do {
292*7c568831SAndroid Build Coastguard Worker         tmp = casemap[*str1++] - casemap[*str2];
293*7c568831SAndroid Build Coastguard Worker         if (tmp != 0) return(tmp);
294*7c568831SAndroid Build Coastguard Worker     } while (*str2++ != 0);
295*7c568831SAndroid Build Coastguard Worker     return 0;
296*7c568831SAndroid Build Coastguard Worker }
297*7c568831SAndroid Build Coastguard Worker 
298*7c568831SAndroid Build Coastguard Worker /**
299*7c568831SAndroid Build Coastguard Worker  * xmlStrncasecmp:
300*7c568831SAndroid Build Coastguard Worker  * @str1:  the first xmlChar *
301*7c568831SAndroid Build Coastguard Worker  * @str2:  the second xmlChar *
302*7c568831SAndroid Build Coastguard Worker  * @len:  the max comparison length
303*7c568831SAndroid Build Coastguard Worker  *
304*7c568831SAndroid Build Coastguard Worker  * a strncasecmp for xmlChar's
305*7c568831SAndroid Build Coastguard Worker  *
306*7c568831SAndroid Build Coastguard Worker  * Returns the integer result of the comparison
307*7c568831SAndroid Build Coastguard Worker  */
308*7c568831SAndroid Build Coastguard Worker 
309*7c568831SAndroid Build Coastguard Worker int
xmlStrncasecmp(const xmlChar * str1,const xmlChar * str2,int len)310*7c568831SAndroid Build Coastguard Worker xmlStrncasecmp(const xmlChar *str1, const xmlChar *str2, int len) {
311*7c568831SAndroid Build Coastguard Worker     register int tmp;
312*7c568831SAndroid Build Coastguard Worker 
313*7c568831SAndroid Build Coastguard Worker     if (len <= 0) return(0);
314*7c568831SAndroid Build Coastguard Worker     if (str1 == str2) return(0);
315*7c568831SAndroid Build Coastguard Worker     if (str1 == NULL) return(-1);
316*7c568831SAndroid Build Coastguard Worker     if (str2 == NULL) return(1);
317*7c568831SAndroid Build Coastguard Worker     do {
318*7c568831SAndroid Build Coastguard Worker         tmp = casemap[*str1++] - casemap[*str2];
319*7c568831SAndroid Build Coastguard Worker         if (tmp != 0 || --len == 0) return(tmp);
320*7c568831SAndroid Build Coastguard Worker     } while (*str2++ != 0);
321*7c568831SAndroid Build Coastguard Worker     return 0;
322*7c568831SAndroid Build Coastguard Worker }
323*7c568831SAndroid Build Coastguard Worker 
324*7c568831SAndroid Build Coastguard Worker /**
325*7c568831SAndroid Build Coastguard Worker  * xmlStrchr:
326*7c568831SAndroid Build Coastguard Worker  * @str:  the xmlChar * array
327*7c568831SAndroid Build Coastguard Worker  * @val:  the xmlChar to search
328*7c568831SAndroid Build Coastguard Worker  *
329*7c568831SAndroid Build Coastguard Worker  * a strchr for xmlChar's
330*7c568831SAndroid Build Coastguard Worker  *
331*7c568831SAndroid Build Coastguard Worker  * Returns the xmlChar * for the first occurrence or NULL.
332*7c568831SAndroid Build Coastguard Worker  */
333*7c568831SAndroid Build Coastguard Worker 
334*7c568831SAndroid Build Coastguard Worker const xmlChar *
xmlStrchr(const xmlChar * str,xmlChar val)335*7c568831SAndroid Build Coastguard Worker xmlStrchr(const xmlChar *str, xmlChar val) {
336*7c568831SAndroid Build Coastguard Worker     if (str == NULL) return(NULL);
337*7c568831SAndroid Build Coastguard Worker     while (*str != 0) { /* non input consuming */
338*7c568831SAndroid Build Coastguard Worker         if (*str == val) return((xmlChar *) str);
339*7c568831SAndroid Build Coastguard Worker         str++;
340*7c568831SAndroid Build Coastguard Worker     }
341*7c568831SAndroid Build Coastguard Worker     return(NULL);
342*7c568831SAndroid Build Coastguard Worker }
343*7c568831SAndroid Build Coastguard Worker 
344*7c568831SAndroid Build Coastguard Worker /**
345*7c568831SAndroid Build Coastguard Worker  * xmlStrstr:
346*7c568831SAndroid Build Coastguard Worker  * @str:  the xmlChar * array (haystack)
347*7c568831SAndroid Build Coastguard Worker  * @val:  the xmlChar to search (needle)
348*7c568831SAndroid Build Coastguard Worker  *
349*7c568831SAndroid Build Coastguard Worker  * a strstr for xmlChar's
350*7c568831SAndroid Build Coastguard Worker  *
351*7c568831SAndroid Build Coastguard Worker  * Returns the xmlChar * for the first occurrence or NULL.
352*7c568831SAndroid Build Coastguard Worker  */
353*7c568831SAndroid Build Coastguard Worker 
354*7c568831SAndroid Build Coastguard Worker const xmlChar *
xmlStrstr(const xmlChar * str,const xmlChar * val)355*7c568831SAndroid Build Coastguard Worker xmlStrstr(const xmlChar *str, const xmlChar *val) {
356*7c568831SAndroid Build Coastguard Worker     int n;
357*7c568831SAndroid Build Coastguard Worker 
358*7c568831SAndroid Build Coastguard Worker     if (str == NULL) return(NULL);
359*7c568831SAndroid Build Coastguard Worker     if (val == NULL) return(NULL);
360*7c568831SAndroid Build Coastguard Worker     n = xmlStrlen(val);
361*7c568831SAndroid Build Coastguard Worker 
362*7c568831SAndroid Build Coastguard Worker     if (n == 0) return(str);
363*7c568831SAndroid Build Coastguard Worker     while (*str != 0) { /* non input consuming */
364*7c568831SAndroid Build Coastguard Worker         if (*str == *val) {
365*7c568831SAndroid Build Coastguard Worker             if (!xmlStrncmp(str, val, n)) return((const xmlChar *) str);
366*7c568831SAndroid Build Coastguard Worker         }
367*7c568831SAndroid Build Coastguard Worker         str++;
368*7c568831SAndroid Build Coastguard Worker     }
369*7c568831SAndroid Build Coastguard Worker     return(NULL);
370*7c568831SAndroid Build Coastguard Worker }
371*7c568831SAndroid Build Coastguard Worker 
372*7c568831SAndroid Build Coastguard Worker /**
373*7c568831SAndroid Build Coastguard Worker  * xmlStrcasestr:
374*7c568831SAndroid Build Coastguard Worker  * @str:  the xmlChar * array (haystack)
375*7c568831SAndroid Build Coastguard Worker  * @val:  the xmlChar to search (needle)
376*7c568831SAndroid Build Coastguard Worker  *
377*7c568831SAndroid Build Coastguard Worker  * a case-ignoring strstr for xmlChar's
378*7c568831SAndroid Build Coastguard Worker  *
379*7c568831SAndroid Build Coastguard Worker  * Returns the xmlChar * for the first occurrence or NULL.
380*7c568831SAndroid Build Coastguard Worker  */
381*7c568831SAndroid Build Coastguard Worker 
382*7c568831SAndroid Build Coastguard Worker const xmlChar *
xmlStrcasestr(const xmlChar * str,const xmlChar * val)383*7c568831SAndroid Build Coastguard Worker xmlStrcasestr(const xmlChar *str, const xmlChar *val) {
384*7c568831SAndroid Build Coastguard Worker     int n;
385*7c568831SAndroid Build Coastguard Worker 
386*7c568831SAndroid Build Coastguard Worker     if (str == NULL) return(NULL);
387*7c568831SAndroid Build Coastguard Worker     if (val == NULL) return(NULL);
388*7c568831SAndroid Build Coastguard Worker     n = xmlStrlen(val);
389*7c568831SAndroid Build Coastguard Worker 
390*7c568831SAndroid Build Coastguard Worker     if (n == 0) return(str);
391*7c568831SAndroid Build Coastguard Worker     while (*str != 0) { /* non input consuming */
392*7c568831SAndroid Build Coastguard Worker         if (casemap[*str] == casemap[*val])
393*7c568831SAndroid Build Coastguard Worker             if (!xmlStrncasecmp(str, val, n)) return(str);
394*7c568831SAndroid Build Coastguard Worker         str++;
395*7c568831SAndroid Build Coastguard Worker     }
396*7c568831SAndroid Build Coastguard Worker     return(NULL);
397*7c568831SAndroid Build Coastguard Worker }
398*7c568831SAndroid Build Coastguard Worker 
399*7c568831SAndroid Build Coastguard Worker /**
400*7c568831SAndroid Build Coastguard Worker  * xmlStrsub:
401*7c568831SAndroid Build Coastguard Worker  * @str:  the xmlChar * array (haystack)
402*7c568831SAndroid Build Coastguard Worker  * @start:  the index of the first char (zero based)
403*7c568831SAndroid Build Coastguard Worker  * @len:  the length of the substring
404*7c568831SAndroid Build Coastguard Worker  *
405*7c568831SAndroid Build Coastguard Worker  * Extract a substring of a given string
406*7c568831SAndroid Build Coastguard Worker  *
407*7c568831SAndroid Build Coastguard Worker  * Returns the xmlChar * for the first occurrence or NULL.
408*7c568831SAndroid Build Coastguard Worker  */
409*7c568831SAndroid Build Coastguard Worker 
410*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlStrsub(const xmlChar * str,int start,int len)411*7c568831SAndroid Build Coastguard Worker xmlStrsub(const xmlChar *str, int start, int len) {
412*7c568831SAndroid Build Coastguard Worker     int i;
413*7c568831SAndroid Build Coastguard Worker 
414*7c568831SAndroid Build Coastguard Worker     if (str == NULL) return(NULL);
415*7c568831SAndroid Build Coastguard Worker     if (start < 0) return(NULL);
416*7c568831SAndroid Build Coastguard Worker     if (len < 0) return(NULL);
417*7c568831SAndroid Build Coastguard Worker 
418*7c568831SAndroid Build Coastguard Worker     for (i = 0;i < start;i++) {
419*7c568831SAndroid Build Coastguard Worker         if (*str == 0) return(NULL);
420*7c568831SAndroid Build Coastguard Worker         str++;
421*7c568831SAndroid Build Coastguard Worker     }
422*7c568831SAndroid Build Coastguard Worker     if (*str == 0) return(NULL);
423*7c568831SAndroid Build Coastguard Worker     return(xmlStrndup(str, len));
424*7c568831SAndroid Build Coastguard Worker }
425*7c568831SAndroid Build Coastguard Worker 
426*7c568831SAndroid Build Coastguard Worker /**
427*7c568831SAndroid Build Coastguard Worker  * xmlStrlen:
428*7c568831SAndroid Build Coastguard Worker  * @str:  the xmlChar * array
429*7c568831SAndroid Build Coastguard Worker  *
430*7c568831SAndroid Build Coastguard Worker  * length of a xmlChar's string
431*7c568831SAndroid Build Coastguard Worker  *
432*7c568831SAndroid Build Coastguard Worker  * Returns the number of xmlChar contained in the ARRAY.
433*7c568831SAndroid Build Coastguard Worker  */
434*7c568831SAndroid Build Coastguard Worker 
435*7c568831SAndroid Build Coastguard Worker int
xmlStrlen(const xmlChar * str)436*7c568831SAndroid Build Coastguard Worker xmlStrlen(const xmlChar *str) {
437*7c568831SAndroid Build Coastguard Worker     size_t len = str ? strlen((const char *)str) : 0;
438*7c568831SAndroid Build Coastguard Worker     return(len > INT_MAX ? 0 : len);
439*7c568831SAndroid Build Coastguard Worker }
440*7c568831SAndroid Build Coastguard Worker 
441*7c568831SAndroid Build Coastguard Worker /**
442*7c568831SAndroid Build Coastguard Worker  * xmlStrncat:
443*7c568831SAndroid Build Coastguard Worker  * @cur:  the original xmlChar * array
444*7c568831SAndroid Build Coastguard Worker  * @add:  the xmlChar * array added
445*7c568831SAndroid Build Coastguard Worker  * @len:  the length of @add
446*7c568831SAndroid Build Coastguard Worker  *
447*7c568831SAndroid Build Coastguard Worker  * a strncat for array of xmlChar's, it will extend @cur with the len
448*7c568831SAndroid Build Coastguard Worker  * first bytes of @add. Note that if @len < 0 then this is an API error
449*7c568831SAndroid Build Coastguard Worker  * and NULL will be returned.
450*7c568831SAndroid Build Coastguard Worker  *
451*7c568831SAndroid Build Coastguard Worker  * Returns a new xmlChar *, the original @cur is reallocated and should
452*7c568831SAndroid Build Coastguard Worker  * not be freed.
453*7c568831SAndroid Build Coastguard Worker  */
454*7c568831SAndroid Build Coastguard Worker 
455*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlStrncat(xmlChar * cur,const xmlChar * add,int len)456*7c568831SAndroid Build Coastguard Worker xmlStrncat(xmlChar *cur, const xmlChar *add, int len) {
457*7c568831SAndroid Build Coastguard Worker     int size;
458*7c568831SAndroid Build Coastguard Worker     xmlChar *ret;
459*7c568831SAndroid Build Coastguard Worker 
460*7c568831SAndroid Build Coastguard Worker     if ((add == NULL) || (len == 0))
461*7c568831SAndroid Build Coastguard Worker         return(cur);
462*7c568831SAndroid Build Coastguard Worker     if (len < 0)
463*7c568831SAndroid Build Coastguard Worker 	return(NULL);
464*7c568831SAndroid Build Coastguard Worker     if (cur == NULL)
465*7c568831SAndroid Build Coastguard Worker         return(xmlStrndup(add, len));
466*7c568831SAndroid Build Coastguard Worker 
467*7c568831SAndroid Build Coastguard Worker     size = xmlStrlen(cur);
468*7c568831SAndroid Build Coastguard Worker     if ((size < 0) || (size > INT_MAX - len))
469*7c568831SAndroid Build Coastguard Worker         return(NULL);
470*7c568831SAndroid Build Coastguard Worker     ret = (xmlChar *) xmlRealloc(cur, (size_t) size + len + 1);
471*7c568831SAndroid Build Coastguard Worker     if (ret == NULL) {
472*7c568831SAndroid Build Coastguard Worker         xmlFree(cur);
473*7c568831SAndroid Build Coastguard Worker         return(NULL);
474*7c568831SAndroid Build Coastguard Worker     }
475*7c568831SAndroid Build Coastguard Worker     memcpy(&ret[size], add, len);
476*7c568831SAndroid Build Coastguard Worker     ret[size + len] = 0;
477*7c568831SAndroid Build Coastguard Worker     return(ret);
478*7c568831SAndroid Build Coastguard Worker }
479*7c568831SAndroid Build Coastguard Worker 
480*7c568831SAndroid Build Coastguard Worker /**
481*7c568831SAndroid Build Coastguard Worker  * xmlStrncatNew:
482*7c568831SAndroid Build Coastguard Worker  * @str1:  first xmlChar string
483*7c568831SAndroid Build Coastguard Worker  * @str2:  second xmlChar string
484*7c568831SAndroid Build Coastguard Worker  * @len:  the len of @str2 or < 0
485*7c568831SAndroid Build Coastguard Worker  *
486*7c568831SAndroid Build Coastguard Worker  * same as xmlStrncat, but creates a new string.  The original
487*7c568831SAndroid Build Coastguard Worker  * two strings are not freed. If @len is < 0 then the length
488*7c568831SAndroid Build Coastguard Worker  * will be calculated automatically.
489*7c568831SAndroid Build Coastguard Worker  *
490*7c568831SAndroid Build Coastguard Worker  * Returns a new xmlChar * or NULL
491*7c568831SAndroid Build Coastguard Worker  */
492*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlStrncatNew(const xmlChar * str1,const xmlChar * str2,int len)493*7c568831SAndroid Build Coastguard Worker xmlStrncatNew(const xmlChar *str1, const xmlChar *str2, int len) {
494*7c568831SAndroid Build Coastguard Worker     int size;
495*7c568831SAndroid Build Coastguard Worker     xmlChar *ret;
496*7c568831SAndroid Build Coastguard Worker 
497*7c568831SAndroid Build Coastguard Worker     if (len < 0) {
498*7c568831SAndroid Build Coastguard Worker         len = xmlStrlen(str2);
499*7c568831SAndroid Build Coastguard Worker         if (len < 0)
500*7c568831SAndroid Build Coastguard Worker             return(NULL);
501*7c568831SAndroid Build Coastguard Worker     }
502*7c568831SAndroid Build Coastguard Worker     if (str1 == NULL)
503*7c568831SAndroid Build Coastguard Worker         return(xmlStrndup(str2, len));
504*7c568831SAndroid Build Coastguard Worker     if ((str2 == NULL) || (len == 0))
505*7c568831SAndroid Build Coastguard Worker         return(xmlStrdup(str1));
506*7c568831SAndroid Build Coastguard Worker 
507*7c568831SAndroid Build Coastguard Worker     size = xmlStrlen(str1);
508*7c568831SAndroid Build Coastguard Worker     if ((size < 0) || (size > INT_MAX - len))
509*7c568831SAndroid Build Coastguard Worker         return(NULL);
510*7c568831SAndroid Build Coastguard Worker     ret = (xmlChar *) xmlMalloc((size_t) size + len + 1);
511*7c568831SAndroid Build Coastguard Worker     if (ret == NULL)
512*7c568831SAndroid Build Coastguard Worker         return(NULL);
513*7c568831SAndroid Build Coastguard Worker     memcpy(ret, str1, size);
514*7c568831SAndroid Build Coastguard Worker     memcpy(&ret[size], str2, len);
515*7c568831SAndroid Build Coastguard Worker     ret[size + len] = 0;
516*7c568831SAndroid Build Coastguard Worker     return(ret);
517*7c568831SAndroid Build Coastguard Worker }
518*7c568831SAndroid Build Coastguard Worker 
519*7c568831SAndroid Build Coastguard Worker /**
520*7c568831SAndroid Build Coastguard Worker  * xmlStrcat:
521*7c568831SAndroid Build Coastguard Worker  * @cur:  the original xmlChar * array
522*7c568831SAndroid Build Coastguard Worker  * @add:  the xmlChar * array added
523*7c568831SAndroid Build Coastguard Worker  *
524*7c568831SAndroid Build Coastguard Worker  * a strcat for array of xmlChar's. Since they are supposed to be
525*7c568831SAndroid Build Coastguard Worker  * encoded in UTF-8 or an encoding with 8bit based chars, we assume
526*7c568831SAndroid Build Coastguard Worker  * a termination mark of '0'.
527*7c568831SAndroid Build Coastguard Worker  *
528*7c568831SAndroid Build Coastguard Worker  * Returns a new xmlChar * containing the concatenated string. The original
529*7c568831SAndroid Build Coastguard Worker  * @cur is reallocated and should not be freed.
530*7c568831SAndroid Build Coastguard Worker  */
531*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlStrcat(xmlChar * cur,const xmlChar * add)532*7c568831SAndroid Build Coastguard Worker xmlStrcat(xmlChar *cur, const xmlChar *add) {
533*7c568831SAndroid Build Coastguard Worker     const xmlChar *p = add;
534*7c568831SAndroid Build Coastguard Worker 
535*7c568831SAndroid Build Coastguard Worker     if (add == NULL) return(cur);
536*7c568831SAndroid Build Coastguard Worker     if (cur == NULL)
537*7c568831SAndroid Build Coastguard Worker         return(xmlStrdup(add));
538*7c568831SAndroid Build Coastguard Worker 
539*7c568831SAndroid Build Coastguard Worker     while (*p != 0) p++; /* non input consuming */
540*7c568831SAndroid Build Coastguard Worker     return(xmlStrncat(cur, add, p - add));
541*7c568831SAndroid Build Coastguard Worker }
542*7c568831SAndroid Build Coastguard Worker 
543*7c568831SAndroid Build Coastguard Worker /**
544*7c568831SAndroid Build Coastguard Worker  * xmlStrPrintf:
545*7c568831SAndroid Build Coastguard Worker  * @buf:   the result buffer.
546*7c568831SAndroid Build Coastguard Worker  * @len:   the result buffer length.
547*7c568831SAndroid Build Coastguard Worker  * @msg:   the message with printf formatting.
548*7c568831SAndroid Build Coastguard Worker  * @...:   extra parameters for the message.
549*7c568831SAndroid Build Coastguard Worker  *
550*7c568831SAndroid Build Coastguard Worker  * Formats @msg and places result into @buf.
551*7c568831SAndroid Build Coastguard Worker  *
552*7c568831SAndroid Build Coastguard Worker  * Returns the number of characters written to @buf or -1 if an error occurs.
553*7c568831SAndroid Build Coastguard Worker  */
554*7c568831SAndroid Build Coastguard Worker int
xmlStrPrintf(xmlChar * buf,int len,const char * msg,...)555*7c568831SAndroid Build Coastguard Worker xmlStrPrintf(xmlChar *buf, int len, const char *msg, ...) {
556*7c568831SAndroid Build Coastguard Worker     va_list args;
557*7c568831SAndroid Build Coastguard Worker     int ret;
558*7c568831SAndroid Build Coastguard Worker 
559*7c568831SAndroid Build Coastguard Worker     if((buf == NULL) || (msg == NULL)) {
560*7c568831SAndroid Build Coastguard Worker         return(-1);
561*7c568831SAndroid Build Coastguard Worker     }
562*7c568831SAndroid Build Coastguard Worker 
563*7c568831SAndroid Build Coastguard Worker     va_start(args, msg);
564*7c568831SAndroid Build Coastguard Worker     ret = vsnprintf((char *) buf, len, (const char *) msg, args);
565*7c568831SAndroid Build Coastguard Worker     va_end(args);
566*7c568831SAndroid Build Coastguard Worker     buf[len - 1] = 0; /* be safe ! */
567*7c568831SAndroid Build Coastguard Worker 
568*7c568831SAndroid Build Coastguard Worker     return(ret);
569*7c568831SAndroid Build Coastguard Worker }
570*7c568831SAndroid Build Coastguard Worker 
571*7c568831SAndroid Build Coastguard Worker /**
572*7c568831SAndroid Build Coastguard Worker  * xmlStrVPrintf:
573*7c568831SAndroid Build Coastguard Worker  * @buf:   the result buffer.
574*7c568831SAndroid Build Coastguard Worker  * @len:   the result buffer length.
575*7c568831SAndroid Build Coastguard Worker  * @msg:   the message with printf formatting.
576*7c568831SAndroid Build Coastguard Worker  * @ap:    extra parameters for the message.
577*7c568831SAndroid Build Coastguard Worker  *
578*7c568831SAndroid Build Coastguard Worker  * Formats @msg and places result into @buf.
579*7c568831SAndroid Build Coastguard Worker  *
580*7c568831SAndroid Build Coastguard Worker  * Returns the number of characters written to @buf or -1 if an error occurs.
581*7c568831SAndroid Build Coastguard Worker  */
582*7c568831SAndroid Build Coastguard Worker int
xmlStrVPrintf(xmlChar * buf,int len,const char * msg,va_list ap)583*7c568831SAndroid Build Coastguard Worker xmlStrVPrintf(xmlChar *buf, int len, const char *msg, va_list ap) {
584*7c568831SAndroid Build Coastguard Worker     int ret;
585*7c568831SAndroid Build Coastguard Worker 
586*7c568831SAndroid Build Coastguard Worker     if((buf == NULL) || (msg == NULL)) {
587*7c568831SAndroid Build Coastguard Worker         return(-1);
588*7c568831SAndroid Build Coastguard Worker     }
589*7c568831SAndroid Build Coastguard Worker 
590*7c568831SAndroid Build Coastguard Worker     ret = vsnprintf((char *) buf, len, (const char *) msg, ap);
591*7c568831SAndroid Build Coastguard Worker     buf[len - 1] = 0; /* be safe ! */
592*7c568831SAndroid Build Coastguard Worker 
593*7c568831SAndroid Build Coastguard Worker     return(ret);
594*7c568831SAndroid Build Coastguard Worker }
595*7c568831SAndroid Build Coastguard Worker 
596*7c568831SAndroid Build Coastguard Worker /**
597*7c568831SAndroid Build Coastguard Worker  * xmlStrVASPrintf:
598*7c568831SAndroid Build Coastguard Worker  * @out:  pointer to the resulting string
599*7c568831SAndroid Build Coastguard Worker  * @maxSize:  maximum size of the output buffer
600*7c568831SAndroid Build Coastguard Worker  * @msg:  printf format string
601*7c568831SAndroid Build Coastguard Worker  * @ap:  arguments for format string
602*7c568831SAndroid Build Coastguard Worker  *
603*7c568831SAndroid Build Coastguard Worker  * Creates a newly allocated string according to format.
604*7c568831SAndroid Build Coastguard Worker  *
605*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success, 1 if the result was truncated or on other
606*7c568831SAndroid Build Coastguard Worker  * errors, -1 if a memory allocation failed.
607*7c568831SAndroid Build Coastguard Worker  */
608*7c568831SAndroid Build Coastguard Worker int
xmlStrVASPrintf(xmlChar ** out,int maxSize,const char * msg,va_list ap)609*7c568831SAndroid Build Coastguard Worker xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap) {
610*7c568831SAndroid Build Coastguard Worker     char empty[1];
611*7c568831SAndroid Build Coastguard Worker     va_list copy;
612*7c568831SAndroid Build Coastguard Worker     xmlChar *buf;
613*7c568831SAndroid Build Coastguard Worker     int res, size;
614*7c568831SAndroid Build Coastguard Worker     int truncated = 0;
615*7c568831SAndroid Build Coastguard Worker 
616*7c568831SAndroid Build Coastguard Worker     if (out == NULL)
617*7c568831SAndroid Build Coastguard Worker         return(1);
618*7c568831SAndroid Build Coastguard Worker     *out = NULL;
619*7c568831SAndroid Build Coastguard Worker     if (msg == NULL)
620*7c568831SAndroid Build Coastguard Worker         return(1);
621*7c568831SAndroid Build Coastguard Worker     if (maxSize < 32)
622*7c568831SAndroid Build Coastguard Worker         maxSize = 32;
623*7c568831SAndroid Build Coastguard Worker 
624*7c568831SAndroid Build Coastguard Worker     va_copy(copy, ap);
625*7c568831SAndroid Build Coastguard Worker     res = vsnprintf(empty, 1, msg, copy);
626*7c568831SAndroid Build Coastguard Worker     va_end(copy);
627*7c568831SAndroid Build Coastguard Worker 
628*7c568831SAndroid Build Coastguard Worker     if (res > 0) {
629*7c568831SAndroid Build Coastguard Worker         /* snprintf seems to work according to C99. */
630*7c568831SAndroid Build Coastguard Worker 
631*7c568831SAndroid Build Coastguard Worker         if (res < maxSize) {
632*7c568831SAndroid Build Coastguard Worker             size = res + 1;
633*7c568831SAndroid Build Coastguard Worker         } else {
634*7c568831SAndroid Build Coastguard Worker             size = maxSize;
635*7c568831SAndroid Build Coastguard Worker             truncated = 1;
636*7c568831SAndroid Build Coastguard Worker         }
637*7c568831SAndroid Build Coastguard Worker         buf = xmlMalloc(size);
638*7c568831SAndroid Build Coastguard Worker         if (buf == NULL)
639*7c568831SAndroid Build Coastguard Worker             return(-1);
640*7c568831SAndroid Build Coastguard Worker         if (vsnprintf((char *) buf, size, msg, ap) < 0) {
641*7c568831SAndroid Build Coastguard Worker             xmlFree(buf);
642*7c568831SAndroid Build Coastguard Worker             return(1);
643*7c568831SAndroid Build Coastguard Worker         }
644*7c568831SAndroid Build Coastguard Worker     } else {
645*7c568831SAndroid Build Coastguard Worker         /*
646*7c568831SAndroid Build Coastguard Worker          * Unfortunately, older snprintf implementations don't follow the
647*7c568831SAndroid Build Coastguard Worker          * C99 spec. If the output exceeds the size of the buffer, they can
648*7c568831SAndroid Build Coastguard Worker          * return -1, 0 or the number of characters written instead of the
649*7c568831SAndroid Build Coastguard Worker          * needed size. Older MSCVRT also won't write a terminating null
650*7c568831SAndroid Build Coastguard Worker          * byte if the buffer is too small.
651*7c568831SAndroid Build Coastguard Worker          *
652*7c568831SAndroid Build Coastguard Worker          * If the value returned is non-negative and strictly less than
653*7c568831SAndroid Build Coastguard Worker          * the buffer size (without terminating null), the result should
654*7c568831SAndroid Build Coastguard Worker          * have been written completely, so we double the buffer size
655*7c568831SAndroid Build Coastguard Worker          * until this condition is true. This assumes that snprintf will
656*7c568831SAndroid Build Coastguard Worker          * eventually return a non-negative value. Otherwise, we will
657*7c568831SAndroid Build Coastguard Worker          * allocate more and more memory until we run out.
658*7c568831SAndroid Build Coastguard Worker          *
659*7c568831SAndroid Build Coastguard Worker          * Note that this code path is also executed on conforming
660*7c568831SAndroid Build Coastguard Worker          * platforms if the output is the empty string.
661*7c568831SAndroid Build Coastguard Worker          */
662*7c568831SAndroid Build Coastguard Worker 
663*7c568831SAndroid Build Coastguard Worker         buf = NULL;
664*7c568831SAndroid Build Coastguard Worker         size = 32;
665*7c568831SAndroid Build Coastguard Worker         while (1) {
666*7c568831SAndroid Build Coastguard Worker             buf = xmlMalloc(size);
667*7c568831SAndroid Build Coastguard Worker             if (buf == NULL)
668*7c568831SAndroid Build Coastguard Worker                 return(-1);
669*7c568831SAndroid Build Coastguard Worker 
670*7c568831SAndroid Build Coastguard Worker             va_copy(copy, ap);
671*7c568831SAndroid Build Coastguard Worker             res = vsnprintf((char *) buf, size, msg, copy);
672*7c568831SAndroid Build Coastguard Worker             va_end(copy);
673*7c568831SAndroid Build Coastguard Worker             if ((res >= 0) && (res < size - 1))
674*7c568831SAndroid Build Coastguard Worker                 break;
675*7c568831SAndroid Build Coastguard Worker 
676*7c568831SAndroid Build Coastguard Worker             if (size >= maxSize) {
677*7c568831SAndroid Build Coastguard Worker                 truncated = 1;
678*7c568831SAndroid Build Coastguard Worker                 break;
679*7c568831SAndroid Build Coastguard Worker             }
680*7c568831SAndroid Build Coastguard Worker 
681*7c568831SAndroid Build Coastguard Worker             xmlFree(buf);
682*7c568831SAndroid Build Coastguard Worker 
683*7c568831SAndroid Build Coastguard Worker             if (size > maxSize / 2)
684*7c568831SAndroid Build Coastguard Worker                 size = maxSize;
685*7c568831SAndroid Build Coastguard Worker             else
686*7c568831SAndroid Build Coastguard Worker                 size *= 2;
687*7c568831SAndroid Build Coastguard Worker         }
688*7c568831SAndroid Build Coastguard Worker     }
689*7c568831SAndroid Build Coastguard Worker 
690*7c568831SAndroid Build Coastguard Worker     /*
691*7c568831SAndroid Build Coastguard Worker      * If the output was truncated, make sure that the buffer doesn't
692*7c568831SAndroid Build Coastguard Worker      * end with a truncated UTF-8 sequence.
693*7c568831SAndroid Build Coastguard Worker      */
694*7c568831SAndroid Build Coastguard Worker     if (truncated != 0) {
695*7c568831SAndroid Build Coastguard Worker         int i = size - 1;
696*7c568831SAndroid Build Coastguard Worker 
697*7c568831SAndroid Build Coastguard Worker         while (i > 0) {
698*7c568831SAndroid Build Coastguard Worker             /* Break after ASCII */
699*7c568831SAndroid Build Coastguard Worker             if (buf[i-1] < 0x80)
700*7c568831SAndroid Build Coastguard Worker                 break;
701*7c568831SAndroid Build Coastguard Worker             i -= 1;
702*7c568831SAndroid Build Coastguard Worker             /* Break before non-ASCII */
703*7c568831SAndroid Build Coastguard Worker             if (buf[i] >= 0xc0)
704*7c568831SAndroid Build Coastguard Worker                 break;
705*7c568831SAndroid Build Coastguard Worker         }
706*7c568831SAndroid Build Coastguard Worker 
707*7c568831SAndroid Build Coastguard Worker         buf[i] = 0;
708*7c568831SAndroid Build Coastguard Worker     }
709*7c568831SAndroid Build Coastguard Worker 
710*7c568831SAndroid Build Coastguard Worker     *out = (xmlChar *) buf;
711*7c568831SAndroid Build Coastguard Worker     return(truncated);
712*7c568831SAndroid Build Coastguard Worker }
713*7c568831SAndroid Build Coastguard Worker 
714*7c568831SAndroid Build Coastguard Worker /**
715*7c568831SAndroid Build Coastguard Worker  * xmlStrASPrintf:
716*7c568831SAndroid Build Coastguard Worker  * @out:  pointer to the resulting string
717*7c568831SAndroid Build Coastguard Worker  * @maxSize:  maximum size of the output buffer
718*7c568831SAndroid Build Coastguard Worker  * @msg:  printf format string
719*7c568831SAndroid Build Coastguard Worker  * @...:  arguments for format string
720*7c568831SAndroid Build Coastguard Worker  *
721*7c568831SAndroid Build Coastguard Worker  * See xmlStrVASPrintf.
722*7c568831SAndroid Build Coastguard Worker  *
723*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success, 1 if the result was truncated or on other
724*7c568831SAndroid Build Coastguard Worker  * errors, -1 if a memory allocation failed.
725*7c568831SAndroid Build Coastguard Worker  */
726*7c568831SAndroid Build Coastguard Worker int
xmlStrASPrintf(xmlChar ** out,int maxSize,const char * msg,...)727*7c568831SAndroid Build Coastguard Worker xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...) {
728*7c568831SAndroid Build Coastguard Worker     va_list ap;
729*7c568831SAndroid Build Coastguard Worker     int ret;
730*7c568831SAndroid Build Coastguard Worker 
731*7c568831SAndroid Build Coastguard Worker     va_start(ap, msg);
732*7c568831SAndroid Build Coastguard Worker     ret = xmlStrVASPrintf(out, maxSize, msg, ap);
733*7c568831SAndroid Build Coastguard Worker     va_end(ap);
734*7c568831SAndroid Build Coastguard Worker 
735*7c568831SAndroid Build Coastguard Worker     return(ret);
736*7c568831SAndroid Build Coastguard Worker }
737*7c568831SAndroid Build Coastguard Worker 
738*7c568831SAndroid Build Coastguard Worker /************************************************************************
739*7c568831SAndroid Build Coastguard Worker  *                                                                      *
740*7c568831SAndroid Build Coastguard Worker  *              Generic UTF8 handling routines                          *
741*7c568831SAndroid Build Coastguard Worker  *                                                                      *
742*7c568831SAndroid Build Coastguard Worker  * From rfc2044: encoding of the Unicode values on UTF-8:               *
743*7c568831SAndroid Build Coastguard Worker  *                                                                      *
744*7c568831SAndroid Build Coastguard Worker  * UCS-4 range (hex.)           UTF-8 octet sequence (binary)           *
745*7c568831SAndroid Build Coastguard Worker  * 0000 0000-0000 007F   0xxxxxxx                                       *
746*7c568831SAndroid Build Coastguard Worker  * 0000 0080-0000 07FF   110xxxxx 10xxxxxx                              *
747*7c568831SAndroid Build Coastguard Worker  * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx                     *
748*7c568831SAndroid Build Coastguard Worker  *                                                                      *
749*7c568831SAndroid Build Coastguard Worker  * I hope we won't use values > 0xFFFF anytime soon !                   *
750*7c568831SAndroid Build Coastguard Worker  *                                                                      *
751*7c568831SAndroid Build Coastguard Worker  ************************************************************************/
752*7c568831SAndroid Build Coastguard Worker 
753*7c568831SAndroid Build Coastguard Worker 
754*7c568831SAndroid Build Coastguard Worker /**
755*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Size:
756*7c568831SAndroid Build Coastguard Worker  * @utf: pointer to the UTF8 character
757*7c568831SAndroid Build Coastguard Worker  *
758*7c568831SAndroid Build Coastguard Worker  * calculates the internal size of a UTF8 character
759*7c568831SAndroid Build Coastguard Worker  *
760*7c568831SAndroid Build Coastguard Worker  * returns the numbers of bytes in the character, -1 on format error
761*7c568831SAndroid Build Coastguard Worker  */
762*7c568831SAndroid Build Coastguard Worker int
xmlUTF8Size(const xmlChar * utf)763*7c568831SAndroid Build Coastguard Worker xmlUTF8Size(const xmlChar *utf) {
764*7c568831SAndroid Build Coastguard Worker     xmlChar mask;
765*7c568831SAndroid Build Coastguard Worker     int len;
766*7c568831SAndroid Build Coastguard Worker 
767*7c568831SAndroid Build Coastguard Worker     if (utf == NULL)
768*7c568831SAndroid Build Coastguard Worker         return -1;
769*7c568831SAndroid Build Coastguard Worker     if (*utf < 0x80)
770*7c568831SAndroid Build Coastguard Worker         return 1;
771*7c568831SAndroid Build Coastguard Worker     /* check valid UTF8 character */
772*7c568831SAndroid Build Coastguard Worker     if (!(*utf & 0x40))
773*7c568831SAndroid Build Coastguard Worker         return -1;
774*7c568831SAndroid Build Coastguard Worker     /* determine number of bytes in char */
775*7c568831SAndroid Build Coastguard Worker     len = 2;
776*7c568831SAndroid Build Coastguard Worker     for (mask=0x20; mask != 0; mask>>=1) {
777*7c568831SAndroid Build Coastguard Worker         if (!(*utf & mask))
778*7c568831SAndroid Build Coastguard Worker             return len;
779*7c568831SAndroid Build Coastguard Worker         len++;
780*7c568831SAndroid Build Coastguard Worker     }
781*7c568831SAndroid Build Coastguard Worker     return -1;
782*7c568831SAndroid Build Coastguard Worker }
783*7c568831SAndroid Build Coastguard Worker 
784*7c568831SAndroid Build Coastguard Worker /**
785*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Charcmp:
786*7c568831SAndroid Build Coastguard Worker  * @utf1: pointer to first UTF8 char
787*7c568831SAndroid Build Coastguard Worker  * @utf2: pointer to second UTF8 char
788*7c568831SAndroid Build Coastguard Worker  *
789*7c568831SAndroid Build Coastguard Worker  * compares the two UCS4 values
790*7c568831SAndroid Build Coastguard Worker  *
791*7c568831SAndroid Build Coastguard Worker  * returns result of the compare as with xmlStrncmp
792*7c568831SAndroid Build Coastguard Worker  */
793*7c568831SAndroid Build Coastguard Worker int
xmlUTF8Charcmp(const xmlChar * utf1,const xmlChar * utf2)794*7c568831SAndroid Build Coastguard Worker xmlUTF8Charcmp(const xmlChar *utf1, const xmlChar *utf2) {
795*7c568831SAndroid Build Coastguard Worker 
796*7c568831SAndroid Build Coastguard Worker     if (utf1 == NULL ) {
797*7c568831SAndroid Build Coastguard Worker         if (utf2 == NULL)
798*7c568831SAndroid Build Coastguard Worker             return 0;
799*7c568831SAndroid Build Coastguard Worker         return -1;
800*7c568831SAndroid Build Coastguard Worker     }
801*7c568831SAndroid Build Coastguard Worker     return xmlStrncmp(utf1, utf2, xmlUTF8Size(utf1));
802*7c568831SAndroid Build Coastguard Worker }
803*7c568831SAndroid Build Coastguard Worker 
804*7c568831SAndroid Build Coastguard Worker /**
805*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Strlen:
806*7c568831SAndroid Build Coastguard Worker  * @utf:  a sequence of UTF-8 encoded bytes
807*7c568831SAndroid Build Coastguard Worker  *
808*7c568831SAndroid Build Coastguard Worker  * compute the length of an UTF8 string, it doesn't do a full UTF8
809*7c568831SAndroid Build Coastguard Worker  * checking of the content of the string.
810*7c568831SAndroid Build Coastguard Worker  *
811*7c568831SAndroid Build Coastguard Worker  * Returns the number of characters in the string or -1 in case of error
812*7c568831SAndroid Build Coastguard Worker  */
813*7c568831SAndroid Build Coastguard Worker int
xmlUTF8Strlen(const xmlChar * utf)814*7c568831SAndroid Build Coastguard Worker xmlUTF8Strlen(const xmlChar *utf) {
815*7c568831SAndroid Build Coastguard Worker     size_t ret = 0;
816*7c568831SAndroid Build Coastguard Worker 
817*7c568831SAndroid Build Coastguard Worker     if (utf == NULL)
818*7c568831SAndroid Build Coastguard Worker         return(-1);
819*7c568831SAndroid Build Coastguard Worker 
820*7c568831SAndroid Build Coastguard Worker     while (*utf != 0) {
821*7c568831SAndroid Build Coastguard Worker         if (utf[0] & 0x80) {
822*7c568831SAndroid Build Coastguard Worker             if ((utf[1] & 0xc0) != 0x80)
823*7c568831SAndroid Build Coastguard Worker                 return(-1);
824*7c568831SAndroid Build Coastguard Worker             if ((utf[0] & 0xe0) == 0xe0) {
825*7c568831SAndroid Build Coastguard Worker                 if ((utf[2] & 0xc0) != 0x80)
826*7c568831SAndroid Build Coastguard Worker                     return(-1);
827*7c568831SAndroid Build Coastguard Worker                 if ((utf[0] & 0xf0) == 0xf0) {
828*7c568831SAndroid Build Coastguard Worker                     if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
829*7c568831SAndroid Build Coastguard Worker                         return(-1);
830*7c568831SAndroid Build Coastguard Worker                     utf += 4;
831*7c568831SAndroid Build Coastguard Worker                 } else {
832*7c568831SAndroid Build Coastguard Worker                     utf += 3;
833*7c568831SAndroid Build Coastguard Worker                 }
834*7c568831SAndroid Build Coastguard Worker             } else {
835*7c568831SAndroid Build Coastguard Worker                 utf += 2;
836*7c568831SAndroid Build Coastguard Worker             }
837*7c568831SAndroid Build Coastguard Worker         } else {
838*7c568831SAndroid Build Coastguard Worker             utf++;
839*7c568831SAndroid Build Coastguard Worker         }
840*7c568831SAndroid Build Coastguard Worker         ret++;
841*7c568831SAndroid Build Coastguard Worker     }
842*7c568831SAndroid Build Coastguard Worker     return(ret > INT_MAX ? 0 : ret);
843*7c568831SAndroid Build Coastguard Worker }
844*7c568831SAndroid Build Coastguard Worker 
845*7c568831SAndroid Build Coastguard Worker /**
846*7c568831SAndroid Build Coastguard Worker  * xmlGetUTF8Char:
847*7c568831SAndroid Build Coastguard Worker  * @utf:  a sequence of UTF-8 encoded bytes
848*7c568831SAndroid Build Coastguard Worker  * @len:  a pointer to the minimum number of bytes present in
849*7c568831SAndroid Build Coastguard Worker  *        the sequence.  This is used to assure the next character
850*7c568831SAndroid Build Coastguard Worker  *        is completely contained within the sequence.
851*7c568831SAndroid Build Coastguard Worker  *
852*7c568831SAndroid Build Coastguard Worker  * Read the first UTF8 character from @utf
853*7c568831SAndroid Build Coastguard Worker  *
854*7c568831SAndroid Build Coastguard Worker  * Returns the char value or -1 in case of error, and sets *len to
855*7c568831SAndroid Build Coastguard Worker  *        the actual number of bytes consumed (0 in case of error)
856*7c568831SAndroid Build Coastguard Worker  */
857*7c568831SAndroid Build Coastguard Worker int
xmlGetUTF8Char(const unsigned char * utf,int * len)858*7c568831SAndroid Build Coastguard Worker xmlGetUTF8Char(const unsigned char *utf, int *len) {
859*7c568831SAndroid Build Coastguard Worker     unsigned int c;
860*7c568831SAndroid Build Coastguard Worker 
861*7c568831SAndroid Build Coastguard Worker     if (utf == NULL)
862*7c568831SAndroid Build Coastguard Worker         goto error;
863*7c568831SAndroid Build Coastguard Worker     if (len == NULL)
864*7c568831SAndroid Build Coastguard Worker         goto error;
865*7c568831SAndroid Build Coastguard Worker 
866*7c568831SAndroid Build Coastguard Worker     c = utf[0];
867*7c568831SAndroid Build Coastguard Worker     if (c < 0x80) {
868*7c568831SAndroid Build Coastguard Worker         if (*len < 1)
869*7c568831SAndroid Build Coastguard Worker             goto error;
870*7c568831SAndroid Build Coastguard Worker         /* 1-byte code */
871*7c568831SAndroid Build Coastguard Worker         *len = 1;
872*7c568831SAndroid Build Coastguard Worker     } else {
873*7c568831SAndroid Build Coastguard Worker         if ((*len < 2) || ((utf[1] & 0xc0) != 0x80))
874*7c568831SAndroid Build Coastguard Worker             goto error;
875*7c568831SAndroid Build Coastguard Worker         if (c < 0xe0) {
876*7c568831SAndroid Build Coastguard Worker             if (c < 0xc2)
877*7c568831SAndroid Build Coastguard Worker                 goto error;
878*7c568831SAndroid Build Coastguard Worker             /* 2-byte code */
879*7c568831SAndroid Build Coastguard Worker             *len = 2;
880*7c568831SAndroid Build Coastguard Worker             c = (c & 0x1f) << 6;
881*7c568831SAndroid Build Coastguard Worker             c |= utf[1] & 0x3f;
882*7c568831SAndroid Build Coastguard Worker         } else {
883*7c568831SAndroid Build Coastguard Worker             if ((*len < 3) || ((utf[2] & 0xc0) != 0x80))
884*7c568831SAndroid Build Coastguard Worker                 goto error;
885*7c568831SAndroid Build Coastguard Worker             if (c < 0xf0) {
886*7c568831SAndroid Build Coastguard Worker                 /* 3-byte code */
887*7c568831SAndroid Build Coastguard Worker                 *len = 3;
888*7c568831SAndroid Build Coastguard Worker                 c = (c & 0xf) << 12;
889*7c568831SAndroid Build Coastguard Worker                 c |= (utf[1] & 0x3f) << 6;
890*7c568831SAndroid Build Coastguard Worker                 c |= utf[2] & 0x3f;
891*7c568831SAndroid Build Coastguard Worker                 if ((c < 0x800) || ((c >= 0xd800) && (c < 0xe000)))
892*7c568831SAndroid Build Coastguard Worker                     goto error;
893*7c568831SAndroid Build Coastguard Worker             } else {
894*7c568831SAndroid Build Coastguard Worker                 if ((*len < 4) || ((utf[3] & 0xc0) != 0x80))
895*7c568831SAndroid Build Coastguard Worker                     goto error;
896*7c568831SAndroid Build Coastguard Worker                 *len = 4;
897*7c568831SAndroid Build Coastguard Worker                 /* 4-byte code */
898*7c568831SAndroid Build Coastguard Worker                 c = (c & 0x7) << 18;
899*7c568831SAndroid Build Coastguard Worker                 c |= (utf[1] & 0x3f) << 12;
900*7c568831SAndroid Build Coastguard Worker                 c |= (utf[2] & 0x3f) << 6;
901*7c568831SAndroid Build Coastguard Worker                 c |= utf[3] & 0x3f;
902*7c568831SAndroid Build Coastguard Worker                 if ((c < 0x10000) || (c >= 0x110000))
903*7c568831SAndroid Build Coastguard Worker                     goto error;
904*7c568831SAndroid Build Coastguard Worker             }
905*7c568831SAndroid Build Coastguard Worker         }
906*7c568831SAndroid Build Coastguard Worker     }
907*7c568831SAndroid Build Coastguard Worker     return(c);
908*7c568831SAndroid Build Coastguard Worker 
909*7c568831SAndroid Build Coastguard Worker error:
910*7c568831SAndroid Build Coastguard Worker     if (len != NULL)
911*7c568831SAndroid Build Coastguard Worker 	*len = 0;
912*7c568831SAndroid Build Coastguard Worker     return(-1);
913*7c568831SAndroid Build Coastguard Worker }
914*7c568831SAndroid Build Coastguard Worker 
915*7c568831SAndroid Build Coastguard Worker /**
916*7c568831SAndroid Build Coastguard Worker  * xmlCheckUTF8:
917*7c568831SAndroid Build Coastguard Worker  * @utf: Pointer to putative UTF-8 encoded string.
918*7c568831SAndroid Build Coastguard Worker  *
919*7c568831SAndroid Build Coastguard Worker  * Checks @utf for being valid UTF-8. @utf is assumed to be
920*7c568831SAndroid Build Coastguard Worker  * null-terminated. This function is not super-strict, as it will
921*7c568831SAndroid Build Coastguard Worker  * allow longer UTF-8 sequences than necessary. Note that Java is
922*7c568831SAndroid Build Coastguard Worker  * capable of producing these sequences if provoked. Also note, this
923*7c568831SAndroid Build Coastguard Worker  * routine checks for the 4-byte maximum size, but does not check for
924*7c568831SAndroid Build Coastguard Worker  * 0x10ffff maximum value.
925*7c568831SAndroid Build Coastguard Worker  *
926*7c568831SAndroid Build Coastguard Worker  * Return value: true if @utf is valid.
927*7c568831SAndroid Build Coastguard Worker  **/
928*7c568831SAndroid Build Coastguard Worker int
xmlCheckUTF8(const unsigned char * utf)929*7c568831SAndroid Build Coastguard Worker xmlCheckUTF8(const unsigned char *utf)
930*7c568831SAndroid Build Coastguard Worker {
931*7c568831SAndroid Build Coastguard Worker     int ix;
932*7c568831SAndroid Build Coastguard Worker     unsigned char c;
933*7c568831SAndroid Build Coastguard Worker 
934*7c568831SAndroid Build Coastguard Worker     if (utf == NULL)
935*7c568831SAndroid Build Coastguard Worker         return(0);
936*7c568831SAndroid Build Coastguard Worker     /*
937*7c568831SAndroid Build Coastguard Worker      * utf is a string of 1, 2, 3 or 4 bytes.  The valid strings
938*7c568831SAndroid Build Coastguard Worker      * are as follows (in "bit format"):
939*7c568831SAndroid Build Coastguard Worker      *    0xxxxxxx                                      valid 1-byte
940*7c568831SAndroid Build Coastguard Worker      *    110xxxxx 10xxxxxx                             valid 2-byte
941*7c568831SAndroid Build Coastguard Worker      *    1110xxxx 10xxxxxx 10xxxxxx                    valid 3-byte
942*7c568831SAndroid Build Coastguard Worker      *    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx           valid 4-byte
943*7c568831SAndroid Build Coastguard Worker      */
944*7c568831SAndroid Build Coastguard Worker     while ((c = utf[0])) {      /* string is 0-terminated */
945*7c568831SAndroid Build Coastguard Worker         ix = 0;
946*7c568831SAndroid Build Coastguard Worker         if ((c & 0x80) == 0x00) {	/* 1-byte code, starts with 10 */
947*7c568831SAndroid Build Coastguard Worker             ix = 1;
948*7c568831SAndroid Build Coastguard Worker 	} else if ((c & 0xe0) == 0xc0) {/* 2-byte code, starts with 110 */
949*7c568831SAndroid Build Coastguard Worker 	    if ((utf[1] & 0xc0 ) != 0x80)
950*7c568831SAndroid Build Coastguard Worker 	        return 0;
951*7c568831SAndroid Build Coastguard Worker 	    ix = 2;
952*7c568831SAndroid Build Coastguard Worker 	} else if ((c & 0xf0) == 0xe0) {/* 3-byte code, starts with 1110 */
953*7c568831SAndroid Build Coastguard Worker 	    if (((utf[1] & 0xc0) != 0x80) ||
954*7c568831SAndroid Build Coastguard Worker 	        ((utf[2] & 0xc0) != 0x80))
955*7c568831SAndroid Build Coastguard Worker 		    return 0;
956*7c568831SAndroid Build Coastguard Worker 	    ix = 3;
957*7c568831SAndroid Build Coastguard Worker 	} else if ((c & 0xf8) == 0xf0) {/* 4-byte code, starts with 11110 */
958*7c568831SAndroid Build Coastguard Worker 	    if (((utf[1] & 0xc0) != 0x80) ||
959*7c568831SAndroid Build Coastguard Worker 	        ((utf[2] & 0xc0) != 0x80) ||
960*7c568831SAndroid Build Coastguard Worker 		((utf[3] & 0xc0) != 0x80))
961*7c568831SAndroid Build Coastguard Worker 		    return 0;
962*7c568831SAndroid Build Coastguard Worker 	    ix = 4;
963*7c568831SAndroid Build Coastguard Worker 	} else				/* unknown encoding */
964*7c568831SAndroid Build Coastguard Worker 	    return 0;
965*7c568831SAndroid Build Coastguard Worker         utf += ix;
966*7c568831SAndroid Build Coastguard Worker       }
967*7c568831SAndroid Build Coastguard Worker       return(1);
968*7c568831SAndroid Build Coastguard Worker }
969*7c568831SAndroid Build Coastguard Worker 
970*7c568831SAndroid Build Coastguard Worker /**
971*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Strsize:
972*7c568831SAndroid Build Coastguard Worker  * @utf:  a sequence of UTF-8 encoded bytes
973*7c568831SAndroid Build Coastguard Worker  * @len:  the number of characters in the array
974*7c568831SAndroid Build Coastguard Worker  *
975*7c568831SAndroid Build Coastguard Worker  * storage size of an UTF8 string
976*7c568831SAndroid Build Coastguard Worker  * the behaviour is not guaranteed if the input string is not UTF-8
977*7c568831SAndroid Build Coastguard Worker  *
978*7c568831SAndroid Build Coastguard Worker  * Returns the storage size of
979*7c568831SAndroid Build Coastguard Worker  * the first 'len' characters of ARRAY
980*7c568831SAndroid Build Coastguard Worker  */
981*7c568831SAndroid Build Coastguard Worker 
982*7c568831SAndroid Build Coastguard Worker int
xmlUTF8Strsize(const xmlChar * utf,int len)983*7c568831SAndroid Build Coastguard Worker xmlUTF8Strsize(const xmlChar *utf, int len) {
984*7c568831SAndroid Build Coastguard Worker     const xmlChar *ptr=utf;
985*7c568831SAndroid Build Coastguard Worker     int ch;
986*7c568831SAndroid Build Coastguard Worker     size_t ret;
987*7c568831SAndroid Build Coastguard Worker 
988*7c568831SAndroid Build Coastguard Worker     if (utf == NULL)
989*7c568831SAndroid Build Coastguard Worker         return(0);
990*7c568831SAndroid Build Coastguard Worker 
991*7c568831SAndroid Build Coastguard Worker     if (len <= 0)
992*7c568831SAndroid Build Coastguard Worker         return(0);
993*7c568831SAndroid Build Coastguard Worker 
994*7c568831SAndroid Build Coastguard Worker     while ( len-- > 0) {
995*7c568831SAndroid Build Coastguard Worker         if ( !*ptr )
996*7c568831SAndroid Build Coastguard Worker             break;
997*7c568831SAndroid Build Coastguard Worker         ch = *ptr++;
998*7c568831SAndroid Build Coastguard Worker         if ((ch & 0x80))
999*7c568831SAndroid Build Coastguard Worker             while ((ch<<=1) & 0x80 ) {
1000*7c568831SAndroid Build Coastguard Worker 		if (*ptr == 0) break;
1001*7c568831SAndroid Build Coastguard Worker                 ptr++;
1002*7c568831SAndroid Build Coastguard Worker 	    }
1003*7c568831SAndroid Build Coastguard Worker     }
1004*7c568831SAndroid Build Coastguard Worker     ret = ptr - utf;
1005*7c568831SAndroid Build Coastguard Worker     return (ret > INT_MAX ? 0 : ret);
1006*7c568831SAndroid Build Coastguard Worker }
1007*7c568831SAndroid Build Coastguard Worker 
1008*7c568831SAndroid Build Coastguard Worker 
1009*7c568831SAndroid Build Coastguard Worker /**
1010*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Strndup:
1011*7c568831SAndroid Build Coastguard Worker  * @utf:  the input UTF8 *
1012*7c568831SAndroid Build Coastguard Worker  * @len:  the len of @utf (in chars)
1013*7c568831SAndroid Build Coastguard Worker  *
1014*7c568831SAndroid Build Coastguard Worker  * a strndup for array of UTF8's
1015*7c568831SAndroid Build Coastguard Worker  *
1016*7c568831SAndroid Build Coastguard Worker  * Returns a new UTF8 * or NULL
1017*7c568831SAndroid Build Coastguard Worker  */
1018*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlUTF8Strndup(const xmlChar * utf,int len)1019*7c568831SAndroid Build Coastguard Worker xmlUTF8Strndup(const xmlChar *utf, int len) {
1020*7c568831SAndroid Build Coastguard Worker     xmlChar *ret;
1021*7c568831SAndroid Build Coastguard Worker     int i;
1022*7c568831SAndroid Build Coastguard Worker 
1023*7c568831SAndroid Build Coastguard Worker     if ((utf == NULL) || (len < 0)) return(NULL);
1024*7c568831SAndroid Build Coastguard Worker     i = xmlUTF8Strsize(utf, len);
1025*7c568831SAndroid Build Coastguard Worker     ret = xmlMalloc((size_t) i + 1);
1026*7c568831SAndroid Build Coastguard Worker     if (ret == NULL) {
1027*7c568831SAndroid Build Coastguard Worker         return(NULL);
1028*7c568831SAndroid Build Coastguard Worker     }
1029*7c568831SAndroid Build Coastguard Worker     memcpy(ret, utf, i);
1030*7c568831SAndroid Build Coastguard Worker     ret[i] = 0;
1031*7c568831SAndroid Build Coastguard Worker     return(ret);
1032*7c568831SAndroid Build Coastguard Worker }
1033*7c568831SAndroid Build Coastguard Worker 
1034*7c568831SAndroid Build Coastguard Worker /**
1035*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Strpos:
1036*7c568831SAndroid Build Coastguard Worker  * @utf:  the input UTF8 *
1037*7c568831SAndroid Build Coastguard Worker  * @pos:  the position of the desired UTF8 char (in chars)
1038*7c568831SAndroid Build Coastguard Worker  *
1039*7c568831SAndroid Build Coastguard Worker  * a function to provide the equivalent of fetching a
1040*7c568831SAndroid Build Coastguard Worker  * character from a string array
1041*7c568831SAndroid Build Coastguard Worker  *
1042*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to the UTF8 character or NULL
1043*7c568831SAndroid Build Coastguard Worker  */
1044*7c568831SAndroid Build Coastguard Worker const xmlChar *
xmlUTF8Strpos(const xmlChar * utf,int pos)1045*7c568831SAndroid Build Coastguard Worker xmlUTF8Strpos(const xmlChar *utf, int pos) {
1046*7c568831SAndroid Build Coastguard Worker     int ch;
1047*7c568831SAndroid Build Coastguard Worker 
1048*7c568831SAndroid Build Coastguard Worker     if (utf == NULL) return(NULL);
1049*7c568831SAndroid Build Coastguard Worker     if (pos < 0)
1050*7c568831SAndroid Build Coastguard Worker         return(NULL);
1051*7c568831SAndroid Build Coastguard Worker     while (pos--) {
1052*7c568831SAndroid Build Coastguard Worker         ch = *utf++;
1053*7c568831SAndroid Build Coastguard Worker         if (ch == 0)
1054*7c568831SAndroid Build Coastguard Worker             return(NULL);
1055*7c568831SAndroid Build Coastguard Worker         if ( ch & 0x80 ) {
1056*7c568831SAndroid Build Coastguard Worker             /* if not simple ascii, verify proper format */
1057*7c568831SAndroid Build Coastguard Worker             if ( (ch & 0xc0) != 0xc0 )
1058*7c568831SAndroid Build Coastguard Worker                 return(NULL);
1059*7c568831SAndroid Build Coastguard Worker             /* then skip over remaining bytes for this char */
1060*7c568831SAndroid Build Coastguard Worker             while ( (ch <<= 1) & 0x80 )
1061*7c568831SAndroid Build Coastguard Worker                 if ( (*utf++ & 0xc0) != 0x80 )
1062*7c568831SAndroid Build Coastguard Worker                     return(NULL);
1063*7c568831SAndroid Build Coastguard Worker         }
1064*7c568831SAndroid Build Coastguard Worker     }
1065*7c568831SAndroid Build Coastguard Worker     return((xmlChar *)utf);
1066*7c568831SAndroid Build Coastguard Worker }
1067*7c568831SAndroid Build Coastguard Worker 
1068*7c568831SAndroid Build Coastguard Worker /**
1069*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Strloc:
1070*7c568831SAndroid Build Coastguard Worker  * @utf:  the input UTF8 *
1071*7c568831SAndroid Build Coastguard Worker  * @utfchar:  the UTF8 character to be found
1072*7c568831SAndroid Build Coastguard Worker  *
1073*7c568831SAndroid Build Coastguard Worker  * a function to provide the relative location of a UTF8 char
1074*7c568831SAndroid Build Coastguard Worker  *
1075*7c568831SAndroid Build Coastguard Worker  * Returns the relative character position of the desired char
1076*7c568831SAndroid Build Coastguard Worker  * or -1 if not found
1077*7c568831SAndroid Build Coastguard Worker  */
1078*7c568831SAndroid Build Coastguard Worker int
xmlUTF8Strloc(const xmlChar * utf,const xmlChar * utfchar)1079*7c568831SAndroid Build Coastguard Worker xmlUTF8Strloc(const xmlChar *utf, const xmlChar *utfchar) {
1080*7c568831SAndroid Build Coastguard Worker     size_t i;
1081*7c568831SAndroid Build Coastguard Worker     int size;
1082*7c568831SAndroid Build Coastguard Worker     int ch;
1083*7c568831SAndroid Build Coastguard Worker 
1084*7c568831SAndroid Build Coastguard Worker     if (utf==NULL || utfchar==NULL) return -1;
1085*7c568831SAndroid Build Coastguard Worker     size = xmlUTF8Strsize(utfchar, 1);
1086*7c568831SAndroid Build Coastguard Worker         for(i=0; (ch=*utf) != 0; i++) {
1087*7c568831SAndroid Build Coastguard Worker             if (xmlStrncmp(utf, utfchar, size)==0)
1088*7c568831SAndroid Build Coastguard Worker                 return(i > INT_MAX ? 0 : i);
1089*7c568831SAndroid Build Coastguard Worker             utf++;
1090*7c568831SAndroid Build Coastguard Worker             if ( ch & 0x80 ) {
1091*7c568831SAndroid Build Coastguard Worker                 /* if not simple ascii, verify proper format */
1092*7c568831SAndroid Build Coastguard Worker                 if ( (ch & 0xc0) != 0xc0 )
1093*7c568831SAndroid Build Coastguard Worker                     return(-1);
1094*7c568831SAndroid Build Coastguard Worker                 /* then skip over remaining bytes for this char */
1095*7c568831SAndroid Build Coastguard Worker                 while ( (ch <<= 1) & 0x80 )
1096*7c568831SAndroid Build Coastguard Worker                     if ( (*utf++ & 0xc0) != 0x80 )
1097*7c568831SAndroid Build Coastguard Worker                         return(-1);
1098*7c568831SAndroid Build Coastguard Worker             }
1099*7c568831SAndroid Build Coastguard Worker         }
1100*7c568831SAndroid Build Coastguard Worker 
1101*7c568831SAndroid Build Coastguard Worker     return(-1);
1102*7c568831SAndroid Build Coastguard Worker }
1103*7c568831SAndroid Build Coastguard Worker /**
1104*7c568831SAndroid Build Coastguard Worker  * xmlUTF8Strsub:
1105*7c568831SAndroid Build Coastguard Worker  * @utf:  a sequence of UTF-8 encoded bytes
1106*7c568831SAndroid Build Coastguard Worker  * @start: relative pos of first char
1107*7c568831SAndroid Build Coastguard Worker  * @len:   total number to copy
1108*7c568831SAndroid Build Coastguard Worker  *
1109*7c568831SAndroid Build Coastguard Worker  * Create a substring from a given UTF-8 string
1110*7c568831SAndroid Build Coastguard Worker  * Note:  positions are given in units of UTF-8 chars
1111*7c568831SAndroid Build Coastguard Worker  *
1112*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to a newly created string or NULL if the
1113*7c568831SAndroid Build Coastguard Worker  * start index is out of bounds or a memory allocation failed.
1114*7c568831SAndroid Build Coastguard Worker  * If len is too large, the result is truncated.
1115*7c568831SAndroid Build Coastguard Worker  */
1116*7c568831SAndroid Build Coastguard Worker 
1117*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlUTF8Strsub(const xmlChar * utf,int start,int len)1118*7c568831SAndroid Build Coastguard Worker xmlUTF8Strsub(const xmlChar *utf, int start, int len) {
1119*7c568831SAndroid Build Coastguard Worker     int i;
1120*7c568831SAndroid Build Coastguard Worker     int ch;
1121*7c568831SAndroid Build Coastguard Worker 
1122*7c568831SAndroid Build Coastguard Worker     if (utf == NULL) return(NULL);
1123*7c568831SAndroid Build Coastguard Worker     if (start < 0) return(NULL);
1124*7c568831SAndroid Build Coastguard Worker     if (len < 0) return(NULL);
1125*7c568831SAndroid Build Coastguard Worker 
1126*7c568831SAndroid Build Coastguard Worker     /*
1127*7c568831SAndroid Build Coastguard Worker      * Skip over any leading chars
1128*7c568831SAndroid Build Coastguard Worker      */
1129*7c568831SAndroid Build Coastguard Worker     for (i = 0; i < start; i++) {
1130*7c568831SAndroid Build Coastguard Worker         ch = *utf++;
1131*7c568831SAndroid Build Coastguard Worker         if (ch == 0)
1132*7c568831SAndroid Build Coastguard Worker             return(NULL);
1133*7c568831SAndroid Build Coastguard Worker         /* skip over remaining bytes for this char */
1134*7c568831SAndroid Build Coastguard Worker         if (ch & 0x80) {
1135*7c568831SAndroid Build Coastguard Worker             ch <<= 1;
1136*7c568831SAndroid Build Coastguard Worker             while (ch & 0x80) {
1137*7c568831SAndroid Build Coastguard Worker                 if (*utf++ == 0)
1138*7c568831SAndroid Build Coastguard Worker                     return(NULL);
1139*7c568831SAndroid Build Coastguard Worker                 ch <<= 1;
1140*7c568831SAndroid Build Coastguard Worker             }
1141*7c568831SAndroid Build Coastguard Worker         }
1142*7c568831SAndroid Build Coastguard Worker     }
1143*7c568831SAndroid Build Coastguard Worker 
1144*7c568831SAndroid Build Coastguard Worker     return(xmlUTF8Strndup(utf, len));
1145*7c568831SAndroid Build Coastguard Worker }
1146*7c568831SAndroid Build Coastguard Worker 
1147*7c568831SAndroid Build Coastguard Worker /**
1148*7c568831SAndroid Build Coastguard Worker  * xmlEscapeFormatString:
1149*7c568831SAndroid Build Coastguard Worker  * @msg:  a pointer to the string in which to escape '%' characters.
1150*7c568831SAndroid Build Coastguard Worker  * Must be a heap-allocated buffer created by libxml2 that may be
1151*7c568831SAndroid Build Coastguard Worker  * returned, or that may be freed and replaced.
1152*7c568831SAndroid Build Coastguard Worker  *
1153*7c568831SAndroid Build Coastguard Worker  * Replaces the string pointed to by 'msg' with an escaped string.
1154*7c568831SAndroid Build Coastguard Worker  * Returns the same string with all '%' characters escaped.
1155*7c568831SAndroid Build Coastguard Worker  */
1156*7c568831SAndroid Build Coastguard Worker xmlChar *
xmlEscapeFormatString(xmlChar ** msg)1157*7c568831SAndroid Build Coastguard Worker xmlEscapeFormatString(xmlChar **msg)
1158*7c568831SAndroid Build Coastguard Worker {
1159*7c568831SAndroid Build Coastguard Worker     xmlChar *msgPtr = NULL;
1160*7c568831SAndroid Build Coastguard Worker     xmlChar *result = NULL;
1161*7c568831SAndroid Build Coastguard Worker     xmlChar *resultPtr = NULL;
1162*7c568831SAndroid Build Coastguard Worker     size_t count = 0;
1163*7c568831SAndroid Build Coastguard Worker     size_t msgLen = 0;
1164*7c568831SAndroid Build Coastguard Worker     size_t resultLen = 0;
1165*7c568831SAndroid Build Coastguard Worker 
1166*7c568831SAndroid Build Coastguard Worker     if (!msg || !*msg)
1167*7c568831SAndroid Build Coastguard Worker         return(NULL);
1168*7c568831SAndroid Build Coastguard Worker 
1169*7c568831SAndroid Build Coastguard Worker     for (msgPtr = *msg; *msgPtr != '\0'; ++msgPtr) {
1170*7c568831SAndroid Build Coastguard Worker         ++msgLen;
1171*7c568831SAndroid Build Coastguard Worker         if (*msgPtr == '%')
1172*7c568831SAndroid Build Coastguard Worker             ++count;
1173*7c568831SAndroid Build Coastguard Worker     }
1174*7c568831SAndroid Build Coastguard Worker 
1175*7c568831SAndroid Build Coastguard Worker     if (count == 0)
1176*7c568831SAndroid Build Coastguard Worker         return(*msg);
1177*7c568831SAndroid Build Coastguard Worker 
1178*7c568831SAndroid Build Coastguard Worker     if ((count > INT_MAX) || (msgLen > INT_MAX - count))
1179*7c568831SAndroid Build Coastguard Worker         return(NULL);
1180*7c568831SAndroid Build Coastguard Worker     resultLen = msgLen + count + 1;
1181*7c568831SAndroid Build Coastguard Worker     result = xmlMalloc(resultLen);
1182*7c568831SAndroid Build Coastguard Worker     if (result == NULL) {
1183*7c568831SAndroid Build Coastguard Worker         /* Clear *msg to prevent format string vulnerabilities in
1184*7c568831SAndroid Build Coastguard Worker            out-of-memory situations. */
1185*7c568831SAndroid Build Coastguard Worker         xmlFree(*msg);
1186*7c568831SAndroid Build Coastguard Worker         *msg = NULL;
1187*7c568831SAndroid Build Coastguard Worker         return(NULL);
1188*7c568831SAndroid Build Coastguard Worker     }
1189*7c568831SAndroid Build Coastguard Worker 
1190*7c568831SAndroid Build Coastguard Worker     for (msgPtr = *msg, resultPtr = result; *msgPtr != '\0'; ++msgPtr, ++resultPtr) {
1191*7c568831SAndroid Build Coastguard Worker         *resultPtr = *msgPtr;
1192*7c568831SAndroid Build Coastguard Worker         if (*msgPtr == '%')
1193*7c568831SAndroid Build Coastguard Worker             *(++resultPtr) = '%';
1194*7c568831SAndroid Build Coastguard Worker     }
1195*7c568831SAndroid Build Coastguard Worker     result[resultLen - 1] = '\0';
1196*7c568831SAndroid Build Coastguard Worker 
1197*7c568831SAndroid Build Coastguard Worker     xmlFree(*msg);
1198*7c568831SAndroid Build Coastguard Worker     *msg = result;
1199*7c568831SAndroid Build Coastguard Worker 
1200*7c568831SAndroid Build Coastguard Worker     return *msg;
1201*7c568831SAndroid Build Coastguard Worker }
1202*7c568831SAndroid Build Coastguard Worker 
1203