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