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