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