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