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