xref: /xnu-8792.81.2/libkern/c++/OSUnserializeXML.y (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1 /*
2  * Copyright (c) 1999-2019 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /*
30  * HISTORY
31  *
32  * OSUnserializeXML.y created by rsulack on Tue Oct 12 1999
33  */
34 
35 // parser for unserializing OSContainer objects serialized to XML
36 //
37 // to build :
38 //	bison -p OSUnserializeXML OSUnserializeXML.y
39 //	head -50 OSUnserializeXML.y > ../libkern/c++/OSUnserializeXMLSharedImplementation.h
40 //	sed -e "s/#include <stdio.h>//" < OSUnserializeXML.tab.c >> ../libkern/c++/OSUnserializeXMLSharedImplementation.h
41 //
42 //	when changing code check in both OSUnserializeXML.y and OSUnserializeXMLSharedImplementation.h
43 //
44 //
45 //
46 //
47 //
48 //		 DO NOT EDIT OSUnserializeXMLSharedImplementation.h!
49 //
50 //			this means you!
51 //
52 //
53 //
54 //
55 //
56 //
57 
58 
59 %pure_parser
60 
61 %{
62 #include <string.h>
63 #if KERNEL
64 #include <libkern/c++/OSMetaClass.h>
65 #include <libkern/c++/OSContainers.h>
66 #include <libkern/c++/OSLib.h>
67 #else /* !KERNEL */
68 #include <DriverKit/DriverKit.h>
69 #endif /* KERNEL */
70 
71 
72 #define MAX_OBJECTS              131071
73 #define MAX_REFED_OBJECTS        65535
74 
75 #define YYSTYPE object_t *
76 #define YYPARSE_PARAM   state
77 #define YYLEX_PARAM     (parser_state_t *)state
78 
79 // this is the internal struct used to hold objects on parser stack
80 // it represents objects both before and after they have been created
81 typedef struct object {
82 	struct object   *next;
83 	struct object   *free;
84 	struct object   *elements;
85 	OSObject        *object;
86 	OSSymbol        *key;                   // for dictionary
87 	int             size;
88 	void            *data;                  // for data
89 	char            *string;                // for string & symbol
90 	int             string_alloc_length;
91 	long long       number;                 // for number
92 	int             idref;
93 } object_t;
94 
95 // this code is reentrant, this structure contains all
96 // state information for the parsing of a single buffer
97 typedef struct parser_state {
98 	const char      *parseBuffer;           // start of text to be parsed
99 	int             parseBufferIndex;       // current index into text
100 	int             lineNumber;             // current line number
101 	object_t        *objects;               // internal objects in use
102 	object_t        *freeObjects;           // internal objects that are free
103 	OSDictionary    *tags;                  // used to remember "ID" tags
104 	OSString        **errorString;          // parse error with line
105 	OSObject        *parsedObject;          // resultant object of parsed text
106 	int             parsedObjectCount;
107 	int             retrievedObjectCount;
108 } parser_state_t;
109 
110 #define STATE           ((parser_state_t *)state)
111 
112 #undef yyerror
113 #define yyerror(s)      OSUnserializeerror(STATE, (s))
114 static int              OSUnserializeerror(parser_state_t *state, const char *s);
115 
116 static int              yylex(YYSTYPE *lvalp, parser_state_t *state);
117 
118 static object_t         *newObject(parser_state_t *state);
119 static void             freeObject(parser_state_t *state, object_t *o);
120 static void             rememberObject(parser_state_t *state, int tag, OSObject *o);
121 static object_t         *retrieveObject(parser_state_t *state, int tag);
122 static void             cleanupObjects(parser_state_t *state);
123 
124 static object_t         *buildDictionary(parser_state_t *state, object_t *o);
125 static object_t         *buildArray(parser_state_t *state, object_t *o);
126 static object_t         *buildSet(parser_state_t *state, object_t *o);
127 static object_t         *buildString(parser_state_t *state, object_t *o);
128 static object_t         *buildSymbol(parser_state_t *state, object_t *o);
129 static object_t         *buildData(parser_state_t *state, object_t *o);
130 static object_t         *buildNumber(parser_state_t *state, object_t *o);
131 static object_t         *buildBoolean(parser_state_t *state, object_t *o);
132 
133 #if KERNEL
134 __BEGIN_DECLS
135 #include <kern/kalloc.h>
136 __END_DECLS
137 
138 #define malloc(size)         malloc_impl(size)
139 #define malloc_type(type)    kalloc_type(type, Z_WAITOK)
140 static inline void *
malloc_impl(size_t size)141 malloc_impl(size_t size)
142 {
143 	if (size == 0) {
144 		return NULL;
145 	}
146 	return kheap_alloc_tag_bt(KHEAP_DATA_BUFFERS, size,
147 				(zalloc_flags_t) (Z_WAITOK | Z_ZERO),
148 				VM_KERN_MEMORY_LIBKERN);
149 }
150 
151 #define free(addr)             free_impl(addr)
152 #define free_type(type, addr)  kfree_type(type, addr)
153 static inline void
free_impl(void * addr)154 free_impl(void *addr)
155 {
156 	kheap_free_addr(KHEAP_DATA_BUFFERS, addr);
157 }
158 static inline void
safe_free(void * addr,size_t size)159 safe_free(void *addr, size_t size)
160 {
161   if(addr) {
162 	assert(size != 0);
163 	kheap_free(KHEAP_DATA_BUFFERS, addr, size);
164   }
165 }
166 
167 #define realloc(addr, osize, nsize) realloc_impl(addr, osize, nsize)
168 static inline void *
realloc_impl(void * addr,size_t osize,size_t nsize)169 realloc_impl(void *addr, size_t osize, size_t nsize)
170 {
171 	if (!addr) {
172 		return malloc(nsize);
173 	}
174 	if (nsize == osize) {
175 		return addr;
176 	}
177 	void *nmem = malloc(nsize);
178 	if (!nmem) {
179 		safe_free(addr, osize);
180 		return NULL;
181 	}
182 	(void)memcpy(nmem, addr, (nsize > osize) ? osize : nsize);
183 	safe_free(addr, osize);
184 
185 	return nmem;
186 }
187 #else /* !KERNEL */
188 #define malloc(size)      malloc_impl(size)
189 #define malloc_type(type) (type *) calloc(1, sizeof(type))
190 static inline void *
malloc_impl(size_t size)191 malloc_impl(size_t size)
192 {
193 	if (size == 0) {
194 		return NULL;
195 	}
196 	return calloc(1, size);
197 }
198 #define safe_free(addr, size)       free(addr)
199 #define free_type(type, addr)       safe_free(addr, sizeof(type))
200 #define realloc(addr, osize, nsize) realloc_impl(addr, osize, nsize)
201 static inline void *
realloc_impl(void * addr,size_t osize,size_t nsize)202 realloc_impl(void *addr, size_t osize, size_t nsize)
203 {
204 	void * nmem;
205 
206 	if (!addr) {
207 		return malloc(nsize);
208 	}
209 	if (nsize == osize) {
210 		return addr;
211 	}
212 	nmem = (realloc)(addr, nsize);
213 	if (nmem && nsize > osize) {
214 		bzero((uint8_t *)nmem + osize, nsize - osize);
215 	}
216 
217 	return nmem;
218 }
219 #endif /* KERNEL */
220 
221 %}
222 %token ARRAY
223 %token BOOLEAN
224 %token DATA
225 %token DICTIONARY
226 %token IDREF
227 %token KEY
228 %token NUMBER
229 %token SET
230 %token STRING
231 %token SYNTAX_ERROR
232 %% /* Grammar rules and actions follow */
233 
234 input:	  /* empty */		{ yyerror("unexpected end of buffer");
235 				  YYERROR;
236 				}
237 	| object		{ STATE->parsedObject = $1->object;
238 				  $1->object = 0;
239 				  freeObject(STATE, $1);
240 				  YYACCEPT;
241 				}
242 	| SYNTAX_ERROR		{ yyerror("syntax error");
243 				  YYERROR;
244 				}
245 	;
246 
247 object:	  dict			{ $$ = buildDictionary(STATE, $1);
248 
249 				  if (!yyval->object) {
250 				    yyerror("buildDictionary");
251 				    YYERROR;
252 				  }
253 				  STATE->parsedObjectCount++;
254 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
255 				    yyerror("maximum object count");
256 				    YYERROR;
257 				  }
258 				}
259 	| array			{ $$ = buildArray(STATE, $1);
260 
261 				  if (!yyval->object) {
262 				    yyerror("buildArray");
263 				    YYERROR;
264 				  }
265 				  STATE->parsedObjectCount++;
266 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
267 				    yyerror("maximum object count");
268 				    YYERROR;
269 				  }
270 				}
271 	| set			{ $$ = buildSet(STATE, $1);
272 
273 				  if (!yyval->object) {
274 				    yyerror("buildSet");
275 				    YYERROR;
276 				  }
277 				  STATE->parsedObjectCount++;
278 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
279 				    yyerror("maximum object count");
280 				    YYERROR;
281 				  }
282 				}
283 	| string		{ $$ = buildString(STATE, $1);
284 
285 				  if (!yyval->object) {
286 				    yyerror("buildString");
287 				    YYERROR;
288 				  }
289 				  STATE->parsedObjectCount++;
290 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
291 				    yyerror("maximum object count");
292 				    YYERROR;
293 				  }
294 				}
295 	| data			{ $$ = buildData(STATE, $1);
296 
297 				  if (!yyval->object) {
298 				    yyerror("buildData");
299 				    YYERROR;
300 				  }
301 				  STATE->parsedObjectCount++;
302 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
303 				    yyerror("maximum object count");
304 				    YYERROR;
305 				  }
306 				}
307 	| number		{ $$ = buildNumber(STATE, $1);
308 
309 				  if (!yyval->object) {
310 				    yyerror("buildNumber");
311 				    YYERROR;
312 				  }
313 				  STATE->parsedObjectCount++;
314 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
315 				    yyerror("maximum object count");
316 				    YYERROR;
317 				  }
318 				}
319 	| boolean		{ $$ = buildBoolean(STATE, $1);
320 
321 				  if (!yyval->object) {
322 				    yyerror("buildBoolean");
323 				    YYERROR;
324 				  }
325 				  STATE->parsedObjectCount++;
326 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
327 				    yyerror("maximum object count");
328 				    YYERROR;
329 				  }
330 				}
331 	| idref			{ $$ = retrieveObject(STATE, $1->idref);
332 				  if ($$) {
333 				    STATE->retrievedObjectCount++;
334 				    $$->object->retain();
335 				    if (STATE->retrievedObjectCount > MAX_REFED_OBJECTS) {
336 				      yyerror("maximum object reference count");
337 				      YYERROR;
338 				    }
339 				  } else {
340 				    yyerror("forward reference detected");
341 				    YYERROR;
342 				  }
343 				  freeObject(STATE, $1);
344 
345 				  STATE->parsedObjectCount++;
346 				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
347 				    yyerror("maximum object count");
348 				    YYERROR;
349 				  }
350 				}
351 	;
352 
353 //------------------------------------------------------------------------------
354 
355 dict:	  '{' '}'		{ $$ = $1;
356 				  $$->elements = NULL;
357 				}
358 	| '{' pairs '}'		{ $$ = $1;
359 				  $$->elements = $2;
360 				}
361 	| DICTIONARY
362 	;
363 
364 pairs:	  pair
365 	| pairs pair		{ $$ = $2;
366 				  $$->next = $1;
367 
368 				  object_t *o;
369 				  o = $$->next;
370 				  while (o) {
371 				    if (o->key == $$->key) {
372 				      yyerror("duplicate dictionary key");
373 				      YYERROR;
374 				    }
375 				    o = o->next;
376 				  }
377 				}
378 	;
379 
380 pair:	  key object		{ $$ = $1;
381 				  $$->key = (OSSymbol *)$$->object;
382 				  $$->object = $2->object;
383 				  $$->next = NULL;
384 				  $2->object = 0;
385 				  freeObject(STATE, $2);
386 				}
387 	;
388 
389 key:	  KEY			{ $$ = buildSymbol(STATE, $1);
390 
391 //				  STATE->parsedObjectCount++;
392 //				  if (STATE->parsedObjectCount > MAX_OBJECTS) {
393 //				    yyerror("maximum object count");
394 //				    YYERROR;
395 //				  }
396 				}
397 	;
398 
399 //------------------------------------------------------------------------------
400 
401 array:	  '(' ')'		{ $$ = $1;
402 				  $$->elements = NULL;
403 				}
404 	| '(' elements ')'	{ $$ = $1;
405 				  $$->elements = $2;
406 				}
407 	| ARRAY
408 	;
409 
410 set:	  '[' ']'		{ $$ = $1;
411 				  $$->elements = NULL;
412 				}
413 	| '[' elements ']'	{ $$ = $1;
414 				  $$->elements = $2;
415 				}
416 	| SET
417 	;
418 
419 elements: object		{ $$ = $1;
420 				  $$->next = NULL;
421 				}
422 	| elements object	{ $$ = $2;
423 				  $$->next = $1;
424 				}
425 	;
426 
427 //------------------------------------------------------------------------------
428 
429 boolean:  BOOLEAN
430 	;
431 
432 data:	  DATA
433 	;
434 
435 idref:	  IDREF
436 	;
437 
438 number:	  NUMBER
439 	;
440 
441 string:	  STRING
442 	;
443 
444 %%
445 
446 int
447 OSUnserializeerror(parser_state_t * state, const char *s)  /* Called by yyparse on errors */
448 {
449 	if (state->errorString) {
450 		char tempString[128];
451 		snprintf(tempString, 128, "OSUnserializeXML: %s near line %d\n", s, state->lineNumber);
452 		*(state->errorString) = OSString::withCString(tempString);
453 	}
454 
455 	return 0;
456 }
457 
458 #define TAG_MAX_LENGTH          32
459 #define TAG_MAX_ATTRIBUTES      32
460 #define TAG_BAD                 0
461 #define TAG_START               1
462 #define TAG_END                 2
463 #define TAG_EMPTY               3
464 #define TAG_IGNORE              4
465 
466 #define currentChar()   (state->parseBuffer[state->parseBufferIndex])
467 #define nextChar()      (state->parseBuffer[++state->parseBufferIndex])
468 #define prevChar()      (state->parseBuffer[state->parseBufferIndex - 1])
469 
470 #define isSpace(c)      ((c) == ' ' || (c) == '\t')
471 #define isAlpha(c)      (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
472 #define isDigit(c)      ((c) >= '0' && (c) <= '9')
473 #define isAlphaDigit(c) ((c) >= 'a' && (c) <= 'f')
474 #define isHexDigit(c)   (isDigit(c) || isAlphaDigit(c))
475 #define isAlphaNumeric(c) (isAlpha(c) || isDigit(c) || ((c) == '-'))
476 
477 static int
getTag(parser_state_t * state,char tag[TAG_MAX_LENGTH],int * attributeCount,char attributes[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH],char values[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH])478 getTag(parser_state_t *state,
479     char tag[TAG_MAX_LENGTH],
480     int *attributeCount,
481     char attributes[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH],
482     char values[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH] )
483 {
484 	int length = 0;
485 	int c = currentChar();
486 	int tagType = TAG_START;
487 
488 	*attributeCount = 0;
489 
490 	if (c != '<') {
491 		return TAG_BAD;
492 	}
493 	c = nextChar();         // skip '<'
494 
495 
496 	// <!TAG   declarations     >
497 	// <!--     comments      -->
498 	if (c == '!') {
499 		c = nextChar();
500 		bool isComment = (c == '-') && ((c = nextChar()) != 0) && (c == '-');
501 		if (!isComment && !isAlpha(c)) {
502 			return TAG_BAD;                      // <!1, <!-A, <!eos
503 		}
504 		while (c && (c = nextChar()) != 0) {
505 			if (c == '\n') {
506 				state->lineNumber++;
507 			}
508 			if (isComment) {
509 				if (c != '-') {
510 					continue;
511 				}
512 				c = nextChar();
513 				if (c != '-') {
514 					continue;
515 				}
516 				c = nextChar();
517 			}
518 			if (c == '>') {
519 				(void)nextChar();
520 				return TAG_IGNORE;
521 			}
522 			if (isComment) {
523 				break;
524 			}
525 		}
526 		return TAG_BAD;
527 	} else
528 	// <? Processing Instructions  ?>
529 	if (c == '?') {
530 		while ((c = nextChar()) != 0) {
531 			if (c == '\n') {
532 				state->lineNumber++;
533 			}
534 			if (c != '?') {
535 				continue;
536 			}
537 			c = nextChar();
538 			if (!c) {
539 				return TAG_IGNORE;
540 			}
541 			if (c == '>') {
542 				(void)nextChar();
543 				return TAG_IGNORE;
544 			}
545 		}
546 		return TAG_BAD;
547 	} else
548 	// </ end tag >
549 	if (c == '/') {
550 		c = nextChar();         // skip '/'
551 		tagType = TAG_END;
552 	}
553 	if (!isAlpha(c)) {
554 		return TAG_BAD;
555 	}
556 
557 	/* find end of tag while copying it */
558 	while (isAlphaNumeric(c)) {
559 		tag[length++] = c;
560 		c = nextChar();
561 		if (length >= (TAG_MAX_LENGTH - 1)) {
562 			return TAG_BAD;
563 		}
564 	}
565 
566 	tag[length] = 0;
567 
568 //	printf("tag %s, type %d\n", tag, tagType);
569 
570 	// look for attributes of the form attribute = "value" ...
571 	while ((c != '>') && (c != '/')) {
572 		while (isSpace(c)) {
573 			c = nextChar();
574 		}
575 
576 		length = 0;
577 		while (isAlphaNumeric(c)) {
578 			attributes[*attributeCount][length++] = c;
579 			if (length >= (TAG_MAX_LENGTH - 1)) {
580 				return TAG_BAD;
581 			}
582 			c = nextChar();
583 		}
584 		attributes[*attributeCount][length] = 0;
585 
586 		while (isSpace(c)) {
587 			c = nextChar();
588 		}
589 
590 		if (c != '=') {
591 			return TAG_BAD;
592 		}
593 		c = nextChar();
594 
595 		while (isSpace(c)) {
596 			c = nextChar();
597 		}
598 
599 		if (c != '"') {
600 			return TAG_BAD;
601 		}
602 		c = nextChar();
603 		length = 0;
604 		while (c != '"') {
605 			values[*attributeCount][length++] = c;
606 			if (length >= (TAG_MAX_LENGTH - 1)) {
607 				return TAG_BAD;
608 			}
609 			c = nextChar();
610 			if (!c) {
611 				return TAG_BAD;
612 			}
613 		}
614 		values[*attributeCount][length] = 0;
615 
616 		c = nextChar(); // skip closing quote
617 
618 //		printf("	attribute '%s' = '%s', nextchar = '%c'\n",
619 //		       attributes[*attributeCount], values[*attributeCount], c);
620 
621 		(*attributeCount)++;
622 		if (*attributeCount >= TAG_MAX_ATTRIBUTES) {
623 			return TAG_BAD;
624 		}
625 	}
626 
627 	if (c == '/') {
628 		c = nextChar();         // skip '/'
629 		tagType = TAG_EMPTY;
630 	}
631 	if (c != '>') {
632 		return TAG_BAD;
633 	}
634 	c = nextChar();         // skip '>'
635 
636 	return tagType;
637 }
638 
639 static char *
getString(parser_state_t * state,int * alloc_lengthp)640 getString(parser_state_t *state, int *alloc_lengthp)
641 {
642 	int c = currentChar();
643 	int start, length, i, j;
644 	char * tempString;
645 
646 	start = state->parseBufferIndex;
647 	/* find end of string */
648 
649 	while (c != 0) {
650 		if (c == '\n') {
651 			state->lineNumber++;
652 		}
653 		if (c == '<') {
654 			break;
655 		}
656 		c = nextChar();
657 	}
658 
659 	if (c != '<') {
660 		return 0;
661 	}
662 
663 	length = state->parseBufferIndex - start;
664 
665 	/* copy to null terminated buffer */
666 	tempString = (char *)malloc(length + 1);
667 	if (tempString == NULL) {
668 		printf("OSUnserializeXML: can't alloc temp memory\n");
669 		goto error;
670 	}
671 	if (alloc_lengthp) {
672 		*alloc_lengthp = length + 1;
673 	}
674 
675 	// copy out string in tempString
676 	// "&amp;" -> '&', "&lt;" -> '<', "&gt;" -> '>'
677 
678 	i = j = 0;
679 	while (i < length) {
680 		c = state->parseBuffer[start + i++];
681 		if (c != '&') {
682 			tempString[j++] = c;
683 		} else {
684 			if ((i + 3) > length) {
685 				goto error;
686 			}
687 			c = state->parseBuffer[start + i++];
688 			if (c == 'l') {
689 				if (state->parseBuffer[start + i++] != 't') {
690 					goto error;
691 				}
692 				if (state->parseBuffer[start + i++] != ';') {
693 					goto error;
694 				}
695 				tempString[j++] = '<';
696 				continue;
697 			}
698 			if (c == 'g') {
699 				if (state->parseBuffer[start + i++] != 't') {
700 					goto error;
701 				}
702 				if (state->parseBuffer[start + i++] != ';') {
703 					goto error;
704 				}
705 				tempString[j++] = '>';
706 				continue;
707 			}
708 			if ((i + 3) > length) {
709 				goto error;
710 			}
711 			if (c == 'a') {
712 				if (state->parseBuffer[start + i++] != 'm') {
713 					goto error;
714 				}
715 				if (state->parseBuffer[start + i++] != 'p') {
716 					goto error;
717 				}
718 				if (state->parseBuffer[start + i++] != ';') {
719 					goto error;
720 				}
721 				tempString[j++] = '&';
722 				continue;
723 			}
724 			goto error;
725 		}
726 	}
727 	tempString[j] = 0;
728 
729 //	printf("string %s\n", tempString);
730 
731 	return tempString;
732 
733 error:
734 	if (tempString) {
735 		safe_free(tempString, length + 1);
736 		if (alloc_lengthp) {
737 			*alloc_lengthp = 0;
738 		}
739 	}
740 	return 0;
741 }
742 
743 static long long
getNumber(parser_state_t * state)744 getNumber(parser_state_t *state)
745 {
746 	unsigned long long n = 0;
747 	int base = 10;
748 	bool negate = false;
749 	int c = currentChar();
750 
751 	if (c == '0') {
752 		c = nextChar();
753 		if (c == 'x') {
754 			base = 16;
755 			c = nextChar();
756 		}
757 	}
758 	if (base == 10) {
759 		if (c == '-') {
760 			negate = true;
761 			c = nextChar();
762 		}
763 		while (isDigit(c)) {
764 			n = (n * base + c - '0');
765 			c = nextChar();
766 		}
767 		if (negate) {
768 			n = (unsigned long long)((long long)n * (long long)-1);
769 		}
770 	} else {
771 		while (isHexDigit(c)) {
772 			if (isDigit(c)) {
773 				n = (n * base + c - '0');
774 			} else {
775 				n = (n * base + 0xa + c - 'a');
776 			}
777 			c = nextChar();
778 		}
779 	}
780 //	printf("number 0x%x\n", (unsigned long)n);
781 	return n;
782 }
783 
784 // taken from CFXMLParsing/CFPropertyList.c
785 
786 static const signed char __CFPLDataDecodeTable[128] = {
787 	/* 000 */ -1, -1, -1, -1, -1, -1, -1, -1,
788 	/* 010 */ -1, -1, -1, -1, -1, -1, -1, -1,
789 	/* 020 */ -1, -1, -1, -1, -1, -1, -1, -1,
790 	/* 030 */ -1, -1, -1, -1, -1, -1, -1, -1,
791 	/* ' ' */ -1, -1, -1, -1, -1, -1, -1, -1,
792 	/* '(' */ -1, -1, -1, 62, -1, -1, -1, 63,
793 	/* '0' */ 52, 53, 54, 55, 56, 57, 58, 59,
794 	/* '8' */ 60, 61, -1, -1, -1, 0, -1, -1,
795 	/* '@' */ -1, 0, 1, 2, 3, 4, 5, 6,
796 	/* 'H' */ 7, 8, 9, 10, 11, 12, 13, 14,
797 	/* 'P' */ 15, 16, 17, 18, 19, 20, 21, 22,
798 	/* 'X' */ 23, 24, 25, -1, -1, -1, -1, -1,
799 	/* '`' */ -1, 26, 27, 28, 29, 30, 31, 32,
800 	/* 'h' */ 33, 34, 35, 36, 37, 38, 39, 40,
801 	/* 'p' */ 41, 42, 43, 44, 45, 46, 47, 48,
802 	/* 'x' */ 49, 50, 51, -1, -1, -1, -1, -1
803 };
804 
805 #define DATA_ALLOC_SIZE 4096
806 
807 static void *
getCFEncodedData(parser_state_t * state,unsigned int * size)808 getCFEncodedData(parser_state_t *state, unsigned int *size)
809 {
810 	int numeq = 0, cntr = 0;
811 	unsigned int acc = 0;
812 	int tmpbufpos = 0;
813 	size_t tmpbuflen = DATA_ALLOC_SIZE;
814 	unsigned char *tmpbuf = (unsigned char *)malloc(tmpbuflen);
815 
816 	int c = currentChar();
817 	*size = 0;
818 
819 	while (c != '<') {
820 		c &= 0x7f;
821 		if (c == 0) {
822 			safe_free(tmpbuf, tmpbuflen);
823 			return 0;
824 		}
825 		if (c == '=') {
826 			numeq++;
827 		} else {
828 			numeq = 0;
829 		}
830 		if (c == '\n') {
831 			state->lineNumber++;
832 		}
833 		if (__CFPLDataDecodeTable[c] < 0) {
834 			c = nextChar();
835 			continue;
836 		}
837 		cntr++;
838 		acc <<= 6;
839 		acc += __CFPLDataDecodeTable[c];
840 		if (0 == (cntr & 0x3)) {
841 			if (tmpbuflen <= tmpbufpos + 2) {
842 				size_t oldsize = tmpbuflen;
843 				tmpbuflen *= 2;
844 				tmpbuf = (unsigned char *)realloc(tmpbuf, oldsize, tmpbuflen);
845 			}
846 			tmpbuf[tmpbufpos++] = (acc >> 16) & 0xff;
847 			if (numeq < 2) {
848 				tmpbuf[tmpbufpos++] = (acc >> 8) & 0xff;
849 			}
850 			if (numeq < 1) {
851 				tmpbuf[tmpbufpos++] = acc & 0xff;
852 			}
853 		}
854 		c = nextChar();
855 	}
856 	*size = tmpbufpos;
857 	if (*size == 0) {
858 		safe_free(tmpbuf, tmpbuflen);
859 		return 0;
860 	}
861 	return tmpbuf;
862 }
863 
864 static void *
getHexData(parser_state_t * state,unsigned int * size)865 getHexData(parser_state_t *state, unsigned int *size)
866 {
867 	int c;
868 	unsigned char *d, *start;
869 
870 	size_t buflen = DATA_ALLOC_SIZE; // initial buffer size
871 	start = d = (unsigned char *)malloc(buflen);
872 	c = currentChar();
873 
874 	while (c != '<') {
875 		if (isSpace(c)) {
876 			while ((c = nextChar()) != 0 && isSpace(c)) {
877 			}
878 		}
879 		;
880 		if (c == '\n') {
881 			state->lineNumber++;
882 			c = nextChar();
883 			continue;
884 		}
885 
886 		// get high nibble
887 		if (isDigit(c)) {
888 			*d = (c - '0') << 4;
889 		} else if (isAlphaDigit(c)) {
890 			*d =  (0xa + (c - 'a')) << 4;
891 		} else {
892 			goto error;
893 		}
894 
895 		// get low nibble
896 		c = nextChar();
897 		if (isDigit(c)) {
898 			*d |= c - '0';
899 		} else if (isAlphaDigit(c)) {
900 			*d |= 0xa + (c - 'a');
901 		} else {
902 			goto error;
903 		}
904 
905 		d++;
906 		size_t oldsize = d - start;
907 		if (oldsize >= buflen) {
908 			assert(oldsize == buflen);
909 			buflen *= 2;
910 			start = (unsigned char *)realloc(start, oldsize, buflen);
911 			d = start + oldsize;
912 		}
913 		c = nextChar();
914 	}
915 
916 	*size = d - start;
917 	return start;
918 
919 error:
920 
921 	*size = 0;
922 	safe_free(start, buflen);
923 	return 0;
924 }
925 
926 static int
yylex(YYSTYPE * lvalp,parser_state_t * state)927 yylex(YYSTYPE *lvalp, parser_state_t *state)
928 {
929 	int c, i;
930 	int tagType;
931 	char tag[TAG_MAX_LENGTH];
932 	int attributeCount;
933 	char attributes[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH];
934 	char values[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH];
935 	object_t *object;
936 	int alloc_length;
937 top:
938 	c = currentChar();
939 
940 	/* skip white space  */
941 	if (isSpace(c)) {
942 		while ((c = nextChar()) != 0 && isSpace(c)) {
943 		}
944 	}
945 	;
946 
947 	/* keep track of line number, don't return \n's */
948 	if (c == '\n') {
949 		STATE->lineNumber++;
950 		(void)nextChar();
951 		goto top;
952 	}
953 
954 	// end of the buffer?
955 	if (!c) {
956 		return 0;
957 	}
958 
959 	tagType = getTag(STATE, tag, &attributeCount, attributes, values);
960 	if (tagType == TAG_BAD) {
961 		return SYNTAX_ERROR;
962 	}
963 	if (tagType == TAG_IGNORE) {
964 		goto top;
965 	}
966 
967 	// handle allocation and check for "ID" and "IDREF" tags up front
968 	*lvalp = object = newObject(STATE);
969 	object->idref = -1;
970 	for (i = 0; i < attributeCount; i++) {
971 		if (attributes[i][0] == 'I' && attributes[i][1] == 'D') {
972 			// check for idref's, note: we ignore the tag, for
973 			// this to work correctly, all idrefs must be unique
974 			// across the whole serialization
975 			if (attributes[i][2] == 'R' && attributes[i][3] == 'E' &&
976 			    attributes[i][4] == 'F' && !attributes[i][5]) {
977 				if (tagType != TAG_EMPTY) {
978 					return SYNTAX_ERROR;
979 				}
980 				object->idref = strtol(values[i], NULL, 0);
981 				return IDREF;
982 			}
983 			// check for id's
984 			if (!attributes[i][2]) {
985 				object->idref = strtol(values[i], NULL, 0);
986 			} else {
987 				return SYNTAX_ERROR;
988 			}
989 		}
990 	}
991 
992 	switch (*tag) {
993 	case 'a':
994 		if (!strcmp(tag, "array")) {
995 			if (tagType == TAG_EMPTY) {
996 				object->elements = NULL;
997 				return ARRAY;
998 			}
999 			return (tagType == TAG_START) ? '(' : ')';
1000 		}
1001 		break;
1002 	case 'd':
1003 		if (!strcmp(tag, "dict")) {
1004 			if (tagType == TAG_EMPTY) {
1005 				object->elements = NULL;
1006 				return DICTIONARY;
1007 			}
1008 			return (tagType == TAG_START) ? '{' : '}';
1009 		}
1010 		if (!strcmp(tag, "data")) {
1011 			unsigned int size;
1012 			if (tagType == TAG_EMPTY) {
1013 				object->data = NULL;
1014 				object->size = 0;
1015 				return DATA;
1016 			}
1017 
1018 			bool isHexFormat = false;
1019 			for (i = 0; i < attributeCount; i++) {
1020 				if (!strcmp(attributes[i], "format") && !strcmp(values[i], "hex")) {
1021 					isHexFormat = true;
1022 					break;
1023 				}
1024 			}
1025 			// CF encoded is the default form
1026 			if (isHexFormat) {
1027 				object->data = getHexData(STATE, &size);
1028 			} else {
1029 				object->data = getCFEncodedData(STATE, &size);
1030 			}
1031 			object->size = size;
1032 			if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END) || strcmp(tag, "data")) {
1033 				return SYNTAX_ERROR;
1034 			}
1035 			return DATA;
1036 		}
1037 		break;
1038 	case 'f':
1039 		if (!strcmp(tag, "false")) {
1040 			if (tagType == TAG_EMPTY) {
1041 				object->number = 0;
1042 				return BOOLEAN;
1043 			}
1044 		}
1045 		break;
1046 	case 'i':
1047 		if (!strcmp(tag, "integer")) {
1048 			object->size = 64;      // default
1049 			for (i = 0; i < attributeCount; i++) {
1050 				if (!strcmp(attributes[i], "size")) {
1051 					object->size = strtoul(values[i], NULL, 0);
1052 				}
1053 			}
1054 			if (tagType == TAG_EMPTY) {
1055 				object->number = 0;
1056 				return NUMBER;
1057 			}
1058 			object->number = getNumber(STATE);
1059 			if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END) || strcmp(tag, "integer")) {
1060 				return SYNTAX_ERROR;
1061 			}
1062 			return NUMBER;
1063 		}
1064 		break;
1065 	case 'k':
1066 		if (!strcmp(tag, "key")) {
1067 			if (tagType == TAG_EMPTY) {
1068 				return SYNTAX_ERROR;
1069 			}
1070 			object->string = getString(STATE, &alloc_length);
1071 			if (!object->string) {
1072 				return SYNTAX_ERROR;
1073 			}
1074 			object->string_alloc_length = alloc_length;
1075 			if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END)
1076 			    || strcmp(tag, "key")) {
1077 				return SYNTAX_ERROR;
1078 			}
1079 			return KEY;
1080 		}
1081 		break;
1082 	case 'p':
1083 		if (!strcmp(tag, "plist")) {
1084 			freeObject(STATE, object);
1085 			goto top;
1086 		}
1087 		break;
1088 	case 's':
1089 		if (!strcmp(tag, "string")) {
1090 			if (tagType == TAG_EMPTY) {
1091 				object->string = (char *)malloc(1);
1092 				object->string_alloc_length = 1;
1093 				object->string[0] = 0;
1094 				return STRING;
1095 			}
1096 			object->string = getString(STATE, &alloc_length);
1097 			if (!object->string) {
1098 				return SYNTAX_ERROR;
1099 			}
1100 			object->string_alloc_length = alloc_length;
1101 			if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END)
1102 			    || strcmp(tag, "string")) {
1103 				return SYNTAX_ERROR;
1104 			}
1105 			return STRING;
1106 		}
1107 		if (!strcmp(tag, "set")) {
1108 			if (tagType == TAG_EMPTY) {
1109 				object->elements = NULL;
1110 				return SET;
1111 			}
1112 			if (tagType == TAG_START) {
1113 				return '[';
1114 			} else {
1115 				return ']';
1116 			}
1117 		}
1118 		break;
1119 	case 't':
1120 		if (!strcmp(tag, "true")) {
1121 			if (tagType == TAG_EMPTY) {
1122 				object->number = 1;
1123 				return BOOLEAN;
1124 			}
1125 		}
1126 		break;
1127 	}
1128 
1129 	return SYNTAX_ERROR;
1130 }
1131 
1132 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1133 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1134 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1135 
1136 // "java" like allocation, if this code hits a syntax error in the
1137 // the middle of the parsed string we just bail with pointers hanging
1138 // all over place, this code helps keeps it all together
1139 
1140 //static int object_count = 0;
1141 
1142 object_t *
newObject(parser_state_t * state)1143 newObject(parser_state_t *state)
1144 {
1145 	object_t *o;
1146 
1147 	if (state->freeObjects) {
1148 		o = state->freeObjects;
1149 		state->freeObjects = state->freeObjects->next;
1150 	} else {
1151 		o = malloc_type(object_t);
1152 //		object_count++;
1153 		o->free = state->objects;
1154 		state->objects = o;
1155 	}
1156 
1157 	return o;
1158 }
1159 
1160 void
freeObject(parser_state_t * state,object_t * o)1161 freeObject(parser_state_t * state, object_t *o)
1162 {
1163 	o->next = state->freeObjects;
1164 	state->freeObjects = o;
1165 }
1166 
1167 void
cleanupObjects(parser_state_t * state)1168 cleanupObjects(parser_state_t *state)
1169 {
1170 	object_t *t, *o = state->objects;
1171 
1172 	while (o) {
1173 		if (o->object) {
1174 //			printf("OSUnserializeXML: releasing object o=%x object=%x\n", (int)o, (int)o->object);
1175 			o->object->release();
1176 		}
1177 		if (o->data) {
1178 //			printf("OSUnserializeXML: freeing   object o=%x data=%x\n", (int)o, (int)o->data);
1179 			free(o->data);
1180 		}
1181 		if (o->key) {
1182 //			printf("OSUnserializeXML: releasing object o=%x key=%x\n", (int)o, (int)o->key);
1183 			o->key->release();
1184 		}
1185 		if (o->string) {
1186 //			printf("OSUnserializeXML: freeing   object o=%x string=%x\n", (int)o, (int)o->string);
1187 			free(o->string);
1188 		}
1189 
1190 		t = o;
1191 		o = o->free;
1192 		free_type(object_t, t);
1193 //		object_count--;
1194 	}
1195 //	printf("object_count = %d\n", object_count);
1196 }
1197 
1198 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1199 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1200 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1201 
1202 static void
rememberObject(parser_state_t * state,int tag,OSObject * o)1203 rememberObject(parser_state_t *state, int tag, OSObject *o)
1204 {
1205 	char key[16];
1206 	snprintf(key, 16, "%u", tag);
1207 
1208 //	printf("remember key %s\n", key);
1209 
1210 	state->tags->setObject(key, o);
1211 }
1212 
1213 static object_t *
retrieveObject(parser_state_t * state,int tag)1214 retrieveObject(parser_state_t *state, int tag)
1215 {
1216 	OSObject *ref;
1217 	object_t *o;
1218 	char key[16];
1219 	snprintf(key, 16, "%u", tag);
1220 
1221 //	printf("retrieve key '%s'\n", key);
1222 
1223 	ref = state->tags->getObject(key);
1224 	if (!ref) {
1225 		return 0;
1226 	}
1227 
1228 	o = newObject(state);
1229 	o->object = ref;
1230 	return o;
1231 }
1232 
1233 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1234 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1235 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
1236 
1237 object_t *
buildDictionary(parser_state_t * state,object_t * header)1238 buildDictionary(parser_state_t *state, object_t * header)
1239 {
1240 	object_t *o, *t;
1241 	int count = 0;
1242 	OSDictionary *dict;
1243 
1244 	// get count and reverse order
1245 	o = header->elements;
1246 	header->elements = 0;
1247 	while (o) {
1248 		count++;
1249 		t = o;
1250 		o = o->next;
1251 
1252 		t->next = header->elements;
1253 		header->elements = t;
1254 	}
1255 
1256 	dict = OSDictionary::withCapacity(count);
1257 	if (header->idref >= 0) {
1258 		rememberObject(state, header->idref, dict);
1259 	}
1260 
1261 	o = header->elements;
1262 	while (o) {
1263 		dict->setObject(o->key, o->object);
1264 
1265 		o->key->release();
1266 		o->object->release();
1267 		o->key = 0;
1268 		o->object = 0;
1269 
1270 		t = o;
1271 		o = o->next;
1272 		freeObject(state, t);
1273 	}
1274 	o = header;
1275 	o->object = dict;
1276 	return o;
1277 };
1278 
1279 object_t *
buildArray(parser_state_t * state,object_t * header)1280 buildArray(parser_state_t *state, object_t * header)
1281 {
1282 	object_t *o, *t;
1283 	int count = 0;
1284 	OSArray *array;
1285 
1286 	// get count and reverse order
1287 	o = header->elements;
1288 	header->elements = 0;
1289 	while (o) {
1290 		count++;
1291 		t = o;
1292 		o = o->next;
1293 
1294 		t->next = header->elements;
1295 		header->elements = t;
1296 	}
1297 
1298 	array = OSArray::withCapacity(count);
1299 	if (header->idref >= 0) {
1300 		rememberObject(state, header->idref, array);
1301 	}
1302 
1303 	o = header->elements;
1304 	while (o) {
1305 		array->setObject(o->object);
1306 
1307 		o->object->release();
1308 		o->object = 0;
1309 
1310 		t = o;
1311 		o = o->next;
1312 		freeObject(state, t);
1313 	}
1314 	o = header;
1315 	o->object = array;
1316 	return o;
1317 };
1318 
1319 object_t *
buildSet(parser_state_t * state,object_t * header)1320 buildSet(parser_state_t *state, object_t *header)
1321 {
1322 	object_t *o = buildArray(state, header);
1323 
1324 #if KERNEL
1325 	OSArray *array = (OSArray *)o->object;
1326 	OSSet *set = OSSet::withArray(array, array->getCapacity());
1327 
1328 	// write over the reference created in buildArray
1329 	if (header->idref >= 0) {
1330 		rememberObject(state, header->idref, set);
1331 	}
1332 
1333 	array->release();
1334 	o->object = set;
1335 #endif /* KERNEL */
1336 	return o;
1337 };
1338 
1339 object_t *
buildString(parser_state_t * state,object_t * o)1340 buildString(parser_state_t *state, object_t *o)
1341 {
1342 	OSString *string;
1343 
1344 	string = OSString::withCString(o->string);
1345 	if (o->idref >= 0) {
1346 		rememberObject(state, o->idref, string);
1347 	}
1348 
1349 	free(o->string);
1350 	o->string = 0;
1351 	o->object = string;
1352 
1353 	return o;
1354 };
1355 
1356 object_t *
buildSymbol(parser_state_t * state,object_t * o)1357 buildSymbol(parser_state_t *state, object_t *o)
1358 {
1359 	OSSymbol *symbol;
1360 
1361 	symbol = const_cast < OSSymbol * > (OSSymbol::withCString(o->string));
1362 	if (o->idref >= 0) {
1363 		rememberObject(state, o->idref, symbol);
1364 	}
1365 
1366 	safe_free(o->string, o->string_alloc_length);
1367 	o->string = 0;
1368 	o->object = symbol;
1369 
1370 	return o;
1371 };
1372 
1373 object_t *
buildData(parser_state_t * state,object_t * o)1374 buildData(parser_state_t *state, object_t *o)
1375 {
1376 	OSData *data;
1377 
1378 	if (o->size) {
1379 		data = OSData::withBytes(o->data, o->size);
1380 	} else {
1381 		data = OSData::withCapacity(0);
1382 	}
1383 	if (o->idref >= 0) {
1384 		rememberObject(state, o->idref, data);
1385 	}
1386 
1387 	if (o->size) {
1388 		free(o->data);
1389 	}
1390 	o->data = 0;
1391 	o->object = data;
1392 	return o;
1393 };
1394 
1395 object_t *
buildNumber(parser_state_t * state,object_t * o)1396 buildNumber(parser_state_t *state, object_t *o)
1397 {
1398 	OSNumber *number = OSNumber::withNumber(o->number, o->size);
1399 
1400 	if (o->idref >= 0) {
1401 		rememberObject(state, o->idref, number);
1402 	}
1403 
1404 	o->object = number;
1405 	return o;
1406 };
1407 
1408 object_t *
buildBoolean(parser_state_t * state __unused,object_t * o)1409 buildBoolean(parser_state_t *state __unused, object_t *o)
1410 {
1411 	o->object = ((o->number == 0) ? kOSBooleanFalse : kOSBooleanTrue);
1412 	o->object->retain();
1413 	return o;
1414 };
1415 
1416 OSObject*
OSUnserializeXML(const char * buffer,OSString ** errorString)1417 OSUnserializeXML(const char *buffer, OSString **errorString)
1418 {
1419 	OSObject *object;
1420 
1421 	if (!buffer) {
1422 		return 0;
1423 	}
1424 	parser_state_t *state = (parser_state_t *)malloc_type(parser_state_t);
1425 	if (!state) {
1426 		return 0;
1427 	}
1428 
1429 	// just in case
1430 	if (errorString) {
1431 		*errorString = NULL;
1432 	}
1433 
1434 	state->parseBuffer = buffer;
1435 	state->parseBufferIndex = 0;
1436 	state->lineNumber = 1;
1437 	state->objects = 0;
1438 	state->freeObjects = 0;
1439 	state->tags = OSDictionary::withCapacity(128);
1440 	state->errorString = errorString;
1441 	state->parsedObject = 0;
1442 	state->parsedObjectCount = 0;
1443 	state->retrievedObjectCount = 0;
1444 
1445 	(void)yyparse((void *)state);
1446 
1447 	object = state->parsedObject;
1448 
1449 	cleanupObjects(state);
1450 	state->tags->release();
1451 	free_type(parser_state_t, state);
1452 
1453 	return object;
1454 }
1455 
1456 #if KERNEL
1457 #include <libkern/OSSerializeBinary.h>
1458 
1459 OSObject*
OSUnserializeXML(const char * buffer,size_t bufferSize,OSString ** errorString)1460 OSUnserializeXML(const char *buffer, size_t bufferSize, OSString **errorString)
1461 {
1462 	if (!buffer) {
1463 		return 0;
1464 	}
1465 	if (bufferSize < sizeof(kOSSerializeBinarySignature)) {
1466 		return 0;
1467 	}
1468 
1469 	if (!strcmp(kOSSerializeBinarySignature, buffer)
1470 	    || (kOSSerializeIndexedBinarySignature == (uint8_t)buffer[0])) {
1471 		return OSUnserializeBinary(buffer, bufferSize, errorString);
1472 	}
1473 
1474 	// XML must be null terminated
1475 	if (buffer[bufferSize - 1]) {
1476 		return 0;
1477 	}
1478 
1479 	return OSUnserializeXML(buffer, errorString);
1480 }
1481 
1482 #else /* !KERNEL */
1483 
1484 OSObject*
OSUnserializeXML(const char * buffer,size_t bufferSize,OSString ** errorString)1485 OSUnserializeXML(const char *buffer, size_t bufferSize, OSString **errorString)
1486 {
1487 	if (!buffer) {
1488 		return 0;
1489 	}
1490 
1491 	// XML must be null terminated
1492 	if (buffer[bufferSize - 1]) {
1493 		return 0;
1494 	}
1495 
1496 	return OSUnserializeXML(buffer, errorString);
1497 }
1498 
1499 #endif /* KERNEL */
1500 
1501 
1502 //
1503 //
1504 //
1505 //
1506 //
1507 //		 DO NOT EDIT OSUnserializeXMLSharedImplementation.h!
1508 //
1509 //			this means you!
1510 //
1511 //
1512 //
1513 //
1514 //
1515