2 * string.c : an XML string utilities module
4 * This module provides various utility functions for manipulating
5 * the xmlChar* type. All functions named xmlStr* have been moved here
6 * from the parser.c file (their original home).
8 * See Copyright for the status of this software.
10 * UTF8 string routines from:
11 * William Brack <wbrack@mmm.com.hk>
22 #include <libxml/xmlmemory.h>
23 #include <libxml/parserInternals.h>
24 #include <libxml/xmlstring.h>
26 #include "private/parser.h"
27 #include "private/string.h"
29 /************************************************************************
31 * Commodity functions to handle xmlChars *
33 ************************************************************************/
37 * @cur: the input xmlChar *
38 * @len: the len of @cur
40 * a strndup for array of xmlChar's
42 * Returns a new xmlChar * or NULL
45 xmlStrndup(const xmlChar
*cur
, int len
) {
48 if ((cur
== NULL
) || (len
< 0)) return(NULL
);
49 ret
= (xmlChar
*) xmlMallocAtomic((size_t) len
+ 1);
53 memcpy(ret
, cur
, len
);
60 * @cur: the input xmlChar *
62 * a strdup for array of xmlChar's. Since they are supposed to be
63 * encoded in UTF-8 or an encoding with 8bit based chars, we assume
64 * a termination mark of '0'.
66 * Returns a new xmlChar * or NULL
69 xmlStrdup(const xmlChar
*cur
) {
70 const xmlChar
*p
= cur
;
72 if (cur
== NULL
) return(NULL
);
73 while (*p
!= 0) p
++; /* non input consuming */
74 return(xmlStrndup(cur
, p
- cur
));
79 * @cur: the input char *
80 * @len: the len of @cur
82 * a strndup for char's to xmlChar's
84 * Returns a new xmlChar * or NULL
88 xmlCharStrndup(const char *cur
, int len
) {
92 if ((cur
== NULL
) || (len
< 0)) return(NULL
);
93 ret
= (xmlChar
*) xmlMallocAtomic((size_t) len
+ 1);
97 for (i
= 0;i
< len
;i
++) {
98 /* Explicit sign change */
99 ret
[i
] = (xmlChar
) cur
[i
];
100 if (ret
[i
] == 0) return(ret
);
108 * @cur: the input char *
110 * a strdup for char's to xmlChar's
112 * Returns a new xmlChar * or NULL
116 xmlCharStrdup(const char *cur
) {
119 if (cur
== NULL
) return(NULL
);
120 while (*p
!= '\0') p
++; /* non input consuming */
121 return(xmlCharStrndup(cur
, p
- cur
));
126 * @str1: the first xmlChar *
127 * @str2: the second xmlChar *
129 * a strcmp for xmlChar's
131 * Returns the integer result of the comparison
135 xmlStrcmp(const xmlChar
*str1
, const xmlChar
*str2
) {
136 if (str1
== str2
) return(0);
137 if (str1
== NULL
) return(-1);
138 if (str2
== NULL
) return(1);
139 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
140 return(strcmp((const char *)str1
, (const char *)str2
));
143 int tmp
= *str1
++ - *str2
;
144 if (tmp
!= 0) return(tmp
);
145 } while (*str2
++ != 0);
152 * @str1: the first xmlChar *
153 * @str2: the second xmlChar *
155 * Check if both strings are equal of have same content.
156 * Should be a bit more readable and faster than xmlStrcmp()
158 * Returns 1 if they are equal, 0 if they are different
162 xmlStrEqual(const xmlChar
*str1
, const xmlChar
*str2
) {
163 if (str1
== str2
) return(1);
164 if (str1
== NULL
) return(0);
165 if (str2
== NULL
) return(0);
166 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
167 return(strcmp((const char *)str1
, (const char *)str2
) == 0);
170 if (*str1
++ != *str2
) return(0);
178 * @pref: the prefix of the QName
179 * @name: the localname of the QName
180 * @str: the second xmlChar *
182 * Check if a QName is Equal to a given string
184 * Returns 1 if they are equal, 0 if they are different
188 xmlStrQEqual(const xmlChar
*pref
, const xmlChar
*name
, const xmlChar
*str
) {
189 if (pref
== NULL
) return(xmlStrEqual(name
, str
));
190 if (name
== NULL
) return(0);
191 if (str
== NULL
) return(0);
194 if (*pref
++ != *str
) return(0);
195 } while ((*str
++) && (*pref
));
196 if (*str
++ != ':') return(0);
198 if (*name
++ != *str
) return(0);
205 * @str1: the first xmlChar *
206 * @str2: the second xmlChar *
207 * @len: the max comparison length
209 * a strncmp for xmlChar's
211 * Returns the integer result of the comparison
215 xmlStrncmp(const xmlChar
*str1
, const xmlChar
*str2
, int len
) {
216 if (len
<= 0) return(0);
217 if (str1
== str2
) return(0);
218 if (str1
== NULL
) return(-1);
219 if (str2
== NULL
) return(1);
220 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
221 return(strncmp((const char *)str1
, (const char *)str2
, len
));
224 int tmp
= *str1
++ - *str2
;
225 if (tmp
!= 0 || --len
== 0) return(tmp
);
226 } while (*str2
++ != 0);
231 static const xmlChar casemap
[256] = {
232 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
233 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
234 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
235 0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
236 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
237 0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
238 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
239 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
240 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
241 0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
242 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
243 0x78,0x79,0x7A,0x7B,0x5C,0x5D,0x5E,0x5F,
244 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
245 0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
246 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
247 0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
248 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
249 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
250 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
251 0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
252 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
253 0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
254 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
255 0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
256 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
257 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
258 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
259 0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
260 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
261 0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
262 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
263 0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
268 * @str1: the first xmlChar *
269 * @str2: the second xmlChar *
271 * a strcasecmp for xmlChar's
273 * Returns the integer result of the comparison
277 xmlStrcasecmp(const xmlChar
*str1
, const xmlChar
*str2
) {
280 if (str1
== str2
) return(0);
281 if (str1
== NULL
) return(-1);
282 if (str2
== NULL
) return(1);
284 tmp
= casemap
[*str1
++] - casemap
[*str2
];
285 if (tmp
!= 0) return(tmp
);
286 } while (*str2
++ != 0);
292 * @str1: the first xmlChar *
293 * @str2: the second xmlChar *
294 * @len: the max comparison length
296 * a strncasecmp for xmlChar's
298 * Returns the integer result of the comparison
302 xmlStrncasecmp(const xmlChar
*str1
, const xmlChar
*str2
, int len
) {
305 if (len
<= 0) return(0);
306 if (str1
== str2
) return(0);
307 if (str1
== NULL
) return(-1);
308 if (str2
== NULL
) return(1);
310 tmp
= casemap
[*str1
++] - casemap
[*str2
];
311 if (tmp
!= 0 || --len
== 0) return(tmp
);
312 } while (*str2
++ != 0);
318 * @str: the xmlChar * array
319 * @val: the xmlChar to search
321 * a strchr for xmlChar's
323 * Returns the xmlChar * for the first occurrence or NULL.
327 xmlStrchr(const xmlChar
*str
, xmlChar val
) {
328 if (str
== NULL
) return(NULL
);
329 while (*str
!= 0) { /* non input consuming */
330 if (*str
== val
) return((xmlChar
*) str
);
338 * @str: the xmlChar * array (haystack)
339 * @val: the xmlChar to search (needle)
341 * a strstr for xmlChar's
343 * Returns the xmlChar * for the first occurrence or NULL.
347 xmlStrstr(const xmlChar
*str
, const xmlChar
*val
) {
350 if (str
== NULL
) return(NULL
);
351 if (val
== NULL
) return(NULL
);
354 if (n
== 0) return(str
);
355 while (*str
!= 0) { /* non input consuming */
357 if (!xmlStrncmp(str
, val
, n
)) return((const xmlChar
*) str
);
366 * @str: the xmlChar * array (haystack)
367 * @val: the xmlChar to search (needle)
369 * a case-ignoring strstr for xmlChar's
371 * Returns the xmlChar * for the first occurrence or NULL.
375 xmlStrcasestr(const xmlChar
*str
, const xmlChar
*val
) {
378 if (str
== NULL
) return(NULL
);
379 if (val
== NULL
) return(NULL
);
382 if (n
== 0) return(str
);
383 while (*str
!= 0) { /* non input consuming */
384 if (casemap
[*str
] == casemap
[*val
])
385 if (!xmlStrncasecmp(str
, val
, n
)) return(str
);
393 * @str: the xmlChar * array (haystack)
394 * @start: the index of the first char (zero based)
395 * @len: the length of the substring
397 * Extract a substring of a given string
399 * Returns the xmlChar * for the first occurrence or NULL.
403 xmlStrsub(const xmlChar
*str
, int start
, int len
) {
406 if (str
== NULL
) return(NULL
);
407 if (start
< 0) return(NULL
);
408 if (len
< 0) return(NULL
);
410 for (i
= 0;i
< start
;i
++) {
411 if (*str
== 0) return(NULL
);
414 if (*str
== 0) return(NULL
);
415 return(xmlStrndup(str
, len
));
420 * @str: the xmlChar * array
422 * length of a xmlChar's string
424 * Returns the number of xmlChar contained in the ARRAY.
428 xmlStrlen(const xmlChar
*str
) {
429 size_t len
= str
? strlen((const char *)str
) : 0;
430 return(len
> INT_MAX
? 0 : len
);
435 * @cur: the original xmlChar * array
436 * @add: the xmlChar * array added
437 * @len: the length of @add
439 * a strncat for array of xmlChar's, it will extend @cur with the len
440 * first bytes of @add. Note that if @len < 0 then this is an API error
441 * and NULL will be returned.
443 * Returns a new xmlChar *, the original @cur is reallocated and should
448 xmlStrncat(xmlChar
*cur
, const xmlChar
*add
, int len
) {
452 if ((add
== NULL
) || (len
== 0))
457 return(xmlStrndup(add
, len
));
459 size
= xmlStrlen(cur
);
460 if ((size
< 0) || (size
> INT_MAX
- len
))
462 ret
= (xmlChar
*) xmlRealloc(cur
, (size_t) size
+ len
+ 1);
466 memcpy(&ret
[size
], add
, len
);
473 * @str1: first xmlChar string
474 * @str2: second xmlChar string
475 * @len: the len of @str2 or < 0
477 * same as xmlStrncat, but creates a new string. The original
478 * two strings are not freed. If @len is < 0 then the length
479 * will be calculated automatically.
481 * Returns a new xmlChar * or NULL
484 xmlStrncatNew(const xmlChar
*str1
, const xmlChar
*str2
, int len
) {
489 len
= xmlStrlen(str2
);
493 if ((str2
== NULL
) || (len
== 0))
494 return(xmlStrdup(str1
));
496 return(xmlStrndup(str2
, len
));
498 size
= xmlStrlen(str1
);
499 if ((size
< 0) || (size
> INT_MAX
- len
))
501 ret
= (xmlChar
*) xmlMalloc((size_t) size
+ len
+ 1);
503 return(xmlStrndup(str1
, size
));
505 memcpy(ret
, str1
, size
);
506 memcpy(&ret
[size
], str2
, len
);
513 * @cur: the original xmlChar * array
514 * @add: the xmlChar * array added
516 * a strcat for array of xmlChar's. Since they are supposed to be
517 * encoded in UTF-8 or an encoding with 8bit based chars, we assume
518 * a termination mark of '0'.
520 * Returns a new xmlChar * containing the concatenated string. The original
521 * @cur is reallocated and should not be freed.
524 xmlStrcat(xmlChar
*cur
, const xmlChar
*add
) {
525 const xmlChar
*p
= add
;
527 if (add
== NULL
) return(cur
);
529 return(xmlStrdup(add
));
531 while (*p
!= 0) p
++; /* non input consuming */
532 return(xmlStrncat(cur
, add
, p
- add
));
537 * @buf: the result buffer.
538 * @len: the result buffer length.
539 * @msg: the message with printf formatting.
540 * @...: extra parameters for the message.
542 * Formats @msg and places result into @buf.
544 * Returns the number of characters written to @buf or -1 if an error occurs.
547 xmlStrPrintf(xmlChar
*buf
, int len
, const char *msg
, ...) {
551 if((buf
== NULL
) || (msg
== NULL
)) {
556 ret
= vsnprintf((char *) buf
, len
, (const char *) msg
, args
);
558 buf
[len
- 1] = 0; /* be safe ! */
565 * @buf: the result buffer.
566 * @len: the result buffer length.
567 * @msg: the message with printf formatting.
568 * @ap: extra parameters for the message.
570 * Formats @msg and places result into @buf.
572 * Returns the number of characters written to @buf or -1 if an error occurs.
575 xmlStrVPrintf(xmlChar
*buf
, int len
, const char *msg
, va_list ap
) {
578 if((buf
== NULL
) || (msg
== NULL
)) {
582 ret
= vsnprintf((char *) buf
, len
, (const char *) msg
, ap
);
583 buf
[len
- 1] = 0; /* be safe ! */
588 /************************************************************************
590 * Generic UTF8 handling routines *
592 * From rfc2044: encoding of the Unicode values on UTF-8: *
594 * UCS-4 range (hex.) UTF-8 octet sequence (binary) *
595 * 0000 0000-0000 007F 0xxxxxxx *
596 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx *
597 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx *
599 * I hope we won't use values > 0xFFFF anytime soon ! *
601 ************************************************************************/
606 * @utf: pointer to the UTF8 character
608 * calculates the internal size of a UTF8 character
610 * returns the numbers of bytes in the character, -1 on format error
613 xmlUTF8Size(const xmlChar
*utf
) {
621 /* check valid UTF8 character */
624 /* determine number of bytes in char */
626 for (mask
=0x20; mask
!= 0; mask
>>=1) {
636 * @utf1: pointer to first UTF8 char
637 * @utf2: pointer to second UTF8 char
639 * compares the two UCS4 values
641 * returns result of the compare as with xmlStrncmp
644 xmlUTF8Charcmp(const xmlChar
*utf1
, const xmlChar
*utf2
) {
651 return xmlStrncmp(utf1
, utf2
, xmlUTF8Size(utf1
));
656 * @utf: a sequence of UTF-8 encoded bytes
658 * compute the length of an UTF8 string, it doesn't do a full UTF8
659 * checking of the content of the string.
661 * Returns the number of characters in the string or -1 in case of error
664 xmlUTF8Strlen(const xmlChar
*utf
) {
672 if ((utf
[1] & 0xc0) != 0x80)
674 if ((utf
[0] & 0xe0) == 0xe0) {
675 if ((utf
[2] & 0xc0) != 0x80)
677 if ((utf
[0] & 0xf0) == 0xf0) {
678 if ((utf
[0] & 0xf8) != 0xf0 || (utf
[3] & 0xc0) != 0x80)
692 return(ret
> INT_MAX
? 0 : ret
);
697 * @utf: a sequence of UTF-8 encoded bytes
698 * @len: a pointer to the minimum number of bytes present in
699 * the sequence. This is used to assure the next character
700 * is completely contained within the sequence.
702 * Read the first UTF8 character from @utf
704 * Returns the char value or -1 in case of error, and sets *len to
705 * the actual number of bytes consumed (0 in case of error)
708 xmlGetUTF8Char(const unsigned char *utf
, int *len
) {
722 if ((utf
[1] & 0xc0) != 0x80)
724 if ((c
& 0xe0) == 0xe0) {
727 if ((utf
[2] & 0xc0) != 0x80)
729 if ((c
& 0xf0) == 0xf0) {
732 if ((c
& 0xf8) != 0xf0 || (utf
[3] & 0xc0) != 0x80)
736 c
= (utf
[0] & 0x7) << 18;
737 c
|= (utf
[1] & 0x3f) << 12;
738 c
|= (utf
[2] & 0x3f) << 6;
743 c
= (utf
[0] & 0xf) << 12;
744 c
|= (utf
[1] & 0x3f) << 6;
750 c
= (utf
[0] & 0x1f) << 6;
767 * @utf: Pointer to putative UTF-8 encoded string.
769 * Checks @utf for being valid UTF-8. @utf is assumed to be
770 * null-terminated. This function is not super-strict, as it will
771 * allow longer UTF-8 sequences than necessary. Note that Java is
772 * capable of producing these sequences if provoked. Also note, this
773 * routine checks for the 4-byte maximum size, but does not check for
774 * 0x10ffff maximum value.
776 * Return value: true if @utf is valid.
779 xmlCheckUTF8(const unsigned char *utf
)
787 * utf is a string of 1, 2, 3 or 4 bytes. The valid strings
788 * are as follows (in "bit format"):
789 * 0xxxxxxx valid 1-byte
790 * 110xxxxx 10xxxxxx valid 2-byte
791 * 1110xxxx 10xxxxxx 10xxxxxx valid 3-byte
792 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx valid 4-byte
794 while ((c
= utf
[0])) { /* string is 0-terminated */
796 if ((c
& 0x80) == 0x00) { /* 1-byte code, starts with 10 */
798 } else if ((c
& 0xe0) == 0xc0) {/* 2-byte code, starts with 110 */
799 if ((utf
[1] & 0xc0 ) != 0x80)
802 } else if ((c
& 0xf0) == 0xe0) {/* 3-byte code, starts with 1110 */
803 if (((utf
[1] & 0xc0) != 0x80) ||
804 ((utf
[2] & 0xc0) != 0x80))
807 } else if ((c
& 0xf8) == 0xf0) {/* 4-byte code, starts with 11110 */
808 if (((utf
[1] & 0xc0) != 0x80) ||
809 ((utf
[2] & 0xc0) != 0x80) ||
810 ((utf
[3] & 0xc0) != 0x80))
813 } else /* unknown encoding */
822 * @utf: a sequence of UTF-8 encoded bytes
823 * @len: the number of characters in the array
825 * storage size of an UTF8 string
826 * the behaviour is not guaranteed if the input string is not UTF-8
828 * Returns the storage size of
829 * the first 'len' characters of ARRAY
833 xmlUTF8Strsize(const xmlChar
*utf
, int len
) {
834 const xmlChar
*ptr
=utf
;
847 if ( (ch
= *ptr
++) & 0x80)
848 while ((ch
<<=1) & 0x80 ) {
849 if (*ptr
== 0) break;
854 return (ret
> INT_MAX
? 0 : ret
);
860 * @utf: the input UTF8 *
861 * @len: the len of @utf (in chars)
863 * a strndup for array of UTF8's
865 * Returns a new UTF8 * or NULL
868 xmlUTF8Strndup(const xmlChar
*utf
, int len
) {
872 if ((utf
== NULL
) || (len
< 0)) return(NULL
);
873 i
= xmlUTF8Strsize(utf
, len
);
874 ret
= (xmlChar
*) xmlMallocAtomic((size_t) i
+ 1);
885 * @utf: the input UTF8 *
886 * @pos: the position of the desired UTF8 char (in chars)
888 * a function to provide the equivalent of fetching a
889 * character from a string array
891 * Returns a pointer to the UTF8 character or NULL
894 xmlUTF8Strpos(const xmlChar
*utf
, int pos
) {
897 if (utf
== NULL
) return(NULL
);
901 if ((ch
=*utf
++) == 0) return(NULL
);
903 /* if not simple ascii, verify proper format */
904 if ( (ch
& 0xc0) != 0xc0 )
906 /* then skip over remaining bytes for this char */
907 while ( (ch
<<= 1) & 0x80 )
908 if ( (*utf
++ & 0xc0) != 0x80 )
912 return((xmlChar
*)utf
);
917 * @utf: the input UTF8 *
918 * @utfchar: the UTF8 character to be found
920 * a function to provide the relative location of a UTF8 char
922 * Returns the relative character position of the desired char
926 xmlUTF8Strloc(const xmlChar
*utf
, const xmlChar
*utfchar
) {
931 if (utf
==NULL
|| utfchar
==NULL
) return -1;
932 size
= xmlUTF8Strsize(utfchar
, 1);
933 for(i
=0; (ch
=*utf
) != 0; i
++) {
934 if (xmlStrncmp(utf
, utfchar
, size
)==0)
935 return(i
> INT_MAX
? 0 : i
);
938 /* if not simple ascii, verify proper format */
939 if ( (ch
& 0xc0) != 0xc0 )
941 /* then skip over remaining bytes for this char */
942 while ( (ch
<<= 1) & 0x80 )
943 if ( (*utf
++ & 0xc0) != 0x80 )
952 * @utf: a sequence of UTF-8 encoded bytes
953 * @start: relative pos of first char
954 * @len: total number to copy
956 * Create a substring from a given UTF-8 string
957 * Note: positions are given in units of UTF-8 chars
959 * Returns a pointer to a newly created string
960 * or NULL if any problem
964 xmlUTF8Strsub(const xmlChar
*utf
, int start
, int len
) {
968 if (utf
== NULL
) return(NULL
);
969 if (start
< 0) return(NULL
);
970 if (len
< 0) return(NULL
);
973 * Skip over any leading chars
975 for (i
= 0;i
< start
;i
++) {
976 if ((ch
=*utf
++) == 0) return(NULL
);
978 /* if not simple ascii, verify proper format */
979 if ( (ch
& 0xc0) != 0xc0 )
981 /* then skip over remaining bytes for this char */
982 while ( (ch
<<= 1) & 0x80 )
983 if ( (*utf
++ & 0xc0) != 0x80 )
988 return(xmlUTF8Strndup(utf
, len
));
992 * xmlEscapeFormatString:
993 * @msg: a pointer to the string in which to escape '%' characters.
994 * Must be a heap-allocated buffer created by libxml2 that may be
995 * returned, or that may be freed and replaced.
997 * Replaces the string pointed to by 'msg' with an escaped string.
998 * Returns the same string with all '%' characters escaped.
1001 xmlEscapeFormatString(xmlChar
**msg
)
1003 xmlChar
*msgPtr
= NULL
;
1004 xmlChar
*result
= NULL
;
1005 xmlChar
*resultPtr
= NULL
;
1008 size_t resultLen
= 0;
1013 for (msgPtr
= *msg
; *msgPtr
!= '\0'; ++msgPtr
) {
1022 if ((count
> INT_MAX
) || (msgLen
> INT_MAX
- count
))
1024 resultLen
= msgLen
+ count
+ 1;
1025 result
= (xmlChar
*) xmlMallocAtomic(resultLen
);
1026 if (result
== NULL
) {
1027 /* Clear *msg to prevent format string vulnerabilities in
1028 out-of-memory situations. */
1034 for (msgPtr
= *msg
, resultPtr
= result
; *msgPtr
!= '\0'; ++msgPtr
, ++resultPtr
) {
1035 *resultPtr
= *msgPtr
;
1037 *(++resultPtr
) = '%';
1039 result
[resultLen
- 1] = '\0';