1/*
2 * Copyright (c) 2000 Apple Computer, 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/*  OSUnserialize.y created by rsulack on Nov 21 1998 */
30
31// 		"classic" parser for unserializing OSContainer objects
32//
33//  XXX - this code should really be removed!
34//	- the XML format is now prefered
35//	- this code leaks on syntax errors, the XML doesn't
36//	- "classic" looks, reads, ... much better than XML :-(
37//	- well except the XML is more efficent on OSData
38//
39//
40// to build :
41//	bison -p OSUnserialize OSUnserialize.y
42//	head -50 OSUnserialize.y > OSUnserialize.cpp
43//	sed -e "s/stdio.h/stddef.h/" < OSUnserialize.tab.c >> OSUnserialize.cpp
44//
45//	when changing code check in both OSUnserialize.y and OSUnserialize.cpp
46//
47//
48//
49//
50//		 DO NOT EDIT OSUnserialize.tab.cpp!
51//
52//			this means you!
53//
54//
55//
56//
57//
58
59
60%{
61#include <libkern/c++/OSMetaClass.h>
62#include <libkern/c++/OSContainers.h>
63#include <libkern/c++/OSLib.h>
64
65typedef	struct object {
66	struct object	*next;
67	struct object	*prev;
68	void		*object;
69	int		size;		// for data
70	union {
71		void	*key;		// for dictionary
72		long long offset;	// for offset
73	} u;
74
75} object_t;
76
77static int yyerror(const char *s);
78static int yylex();
79
80static object_t * newObject();
81static void freeObject(object_t *o);
82
83static OSObject *buildOSDictionary(object_t *);
84static OSObject *buildOSArray(object_t *);
85static OSObject *buildOSSet(object_t *);
86static OSObject *buildOSString(object_t *);
87static OSObject *buildOSData(object_t *);
88static OSObject *buildOSOffset(object_t *);
89static OSObject *buildOSBoolean(object_t *o);
90
91static void rememberObject(int, object_t *);
92static OSObject *retrieveObject(int);
93
94// temp variable to use during parsing
95static object_t *oo;
96
97// resultant object of parsed text
98static OSObject	*parsedObject;
99
100#define YYSTYPE object_t *
101
102extern "C" {
103extern void *kern_os_malloc(size_t size);
104extern void *kern_os_realloc(void * addr, size_t size);
105extern void kern_os_free(void * addr);
106} /* extern "C" */
107
108#define malloc(s) kern_os_malloc(s)
109#define realloc(a, s) kern_os_realloc(a, s)
110#define free(a) kern_os_free(a)
111
112%}
113%token NUMBER
114%token STRING
115%token DATA
116%token BOOLEAN
117%token SYNTAX_ERROR
118
119%% /* Grammar rules and actions follow */
120
121input:	  /* empty */		{ parsedObject = (OSObject *)NULL; YYACCEPT; }
122	| object		{ parsedObject = (OSObject *)$1;   YYACCEPT; }
123	| SYNTAX_ERROR		{ yyerror("syntax error");	   YYERROR; }
124	;
125
126object:	  dict			{ $$ = (object_t *)buildOSDictionary($1); }
127	| array			{ $$ = (object_t *)buildOSArray($1); }
128	| set			{ $$ = (object_t *)buildOSSet($1); }
129	| string		{ $$ = (object_t *)buildOSString($1); }
130	| data			{ $$ = (object_t *)buildOSData($1); }
131	| offset		{ $$ = (object_t *)buildOSOffset($1); }
132	| boolean		{ $$ = (object_t *)buildOSBoolean($1); }
133	| '@' NUMBER		{ $$ = (object_t *)retrieveObject($2->u.offset);
134				  if ($$) {
135				    ((OSObject *)$$)->retain();
136				  } else {
137				    yyerror("forward reference detected");
138				    YYERROR;
139				  }
140				  freeObject($2);
141				}
142	| object '@' NUMBER	{ $$ = $1;
143				  rememberObject($3->u.offset, $1);
144				  freeObject($3);
145				}
146	;
147
148//------------------------------------------------------------------------------
149
150dict:	  '{' '}'		{ $$ = NULL; }
151	| '{' pairs '}'		{ $$ = $2; }
152	;
153
154pairs:	  pair
155	| pairs pair		{ $2->next = $1; $1->prev = $2; $$ = $2; }
156	;
157
158pair:	  object '=' object ';'	{ $$ = newObject();
159				  $$->next = NULL;
160				  $$->prev = NULL;
161				  $$->u.key = $1;
162				  $$->object = $3;
163				}
164	;
165
166//------------------------------------------------------------------------------
167
168array:	  '(' ')'		{ $$ = NULL; }
169	| '(' elements ')'	{ $$ = $2; }
170	;
171
172set:	  '[' ']'		{ $$ = NULL; }
173	| '[' elements ']'	{ $$ = $2; }
174	;
175
176elements: object		{ $$ = newObject();
177				  $$->object = $1;
178				  $$->next = NULL;
179				  $$->prev = NULL;
180				}
181	| elements ',' object	{ oo = newObject();
182				  oo->object = $3;
183				  oo->next = $1;
184				  oo->prev = NULL;
185				  $1->prev = oo;
186				  $$ = oo;
187				}
188	;
189
190//------------------------------------------------------------------------------
191
192offset:	  NUMBER ':' NUMBER	{ $$ = $1;
193				  $$->size = $3->u.offset;
194				  freeObject($3);
195				}
196	;
197
198//------------------------------------------------------------------------------
199
200data:	  DATA
201	;
202
203//------------------------------------------------------------------------------
204
205string:	  STRING
206	;
207
208//------------------------------------------------------------------------------
209
210boolean:  BOOLEAN
211	;
212
213%%
214
215static int		lineNumber = 0;
216static const char	*parseBuffer;
217static int		parseBufferIndex;
218
219#define currentChar()	(parseBuffer[parseBufferIndex])
220#define nextChar()	(parseBuffer[++parseBufferIndex])
221#define prevChar()	(parseBuffer[parseBufferIndex - 1])
222
223#define isSpace(c)	((c) == ' ' || (c) == '\t')
224#define isAlpha(c)	(((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
225#define isDigit(c)	((c) >= '0' && (c) <= '9')
226#define isAlphaDigit(c)	((c) >= 'a' && (c) <= 'f')
227#define isHexDigit(c)	(isDigit(c) || isAlphaDigit(c))
228#define isAlphaNumeric(c) (isAlpha(c) || isDigit(c) || ((c) == '-'))
229
230static char yyerror_message[128];
231
232int
233yyerror(const char *s)  /* Called by yyparse on error */
234{
235	snprintf(yyerror_message, sizeof(yyerror_message), "OSUnserialize: %s near line %d\n", s, lineNumber);
236	return 0;
237}
238
239int
240yylex()
241{
242	int c;
243
244	if (parseBufferIndex == 0) lineNumber = 1;
245
246 top:
247	c = currentChar();
248
249	/* skip white space  */
250	if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
251
252	/* skip over comments */
253	if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
254
255	/* keep track of line number, don't return \n's */
256	if (c == '\n') {
257		lineNumber++;
258		(void)nextChar();
259		goto top;
260	}
261
262	/* parse boolean */
263	if (c == '.') {
264		bool boolean = false;
265		if (nextChar() == 't') {
266			if (nextChar() != 'r') return SYNTAX_ERROR;
267			if (nextChar() != 'u') return SYNTAX_ERROR;
268			if (nextChar() != 'e') return SYNTAX_ERROR;
269			boolean = true;
270		} else {
271			if (currentChar() != 'f') return SYNTAX_ERROR;
272			if (nextChar() != 'a') return SYNTAX_ERROR;
273			if (nextChar() != 'l') return SYNTAX_ERROR;
274			if (nextChar() != 's') return SYNTAX_ERROR;
275			if (nextChar() != 'e') return SYNTAX_ERROR;
276		}
277		if (nextChar() != '.') return SYNTAX_ERROR;
278		/* skip over dot */
279		(void)nextChar();
280
281		yylval = (object_t *)boolean;
282		return BOOLEAN;
283	}
284
285	/* parse unquoted string */
286	if (isAlpha(c)) {
287		int start, length;
288		char * tempString;
289
290		start = parseBufferIndex;
291		/* find end of string */
292		while (isAlphaNumeric(c)) {
293			c = nextChar();
294		}
295		length = parseBufferIndex - start;
296
297		/* copy to null terminated buffer */
298		tempString = (char *)malloc(length + 1);
299		if (tempString == 0) {
300			printf("OSUnserialize: can't alloc temp memory\n");
301			return 0;
302		}
303		bcopy(&parseBuffer[start], tempString, length);
304		tempString[length] = 0;
305		yylval = (object_t *)tempString;
306		return STRING;
307	}
308
309	/* parse quoted string */
310	if (c == '"' || c == '\'') {
311		int start, length;
312		char * tempString;
313		char quoteChar = c;
314
315		start = parseBufferIndex + 1;		// skip quote
316		/* find end of string, line, buffer */
317		while ((c = nextChar()) != quoteChar) {
318			if (c == '\\') c = nextChar();
319			if (c == '\n') lineNumber++;
320			if (c == 0) return SYNTAX_ERROR;
321		}
322		length = parseBufferIndex - start;
323		/* skip over trailing quote */
324		(void)nextChar();
325		/* copy to null terminated buffer */
326		tempString = (char *)malloc(length + 1);
327		if (tempString == 0) {
328			printf("OSUnserialize: can't alloc temp memory\n");
329			return 0;
330		}
331
332		int to = 0;
333		for (int from=start; from < parseBufferIndex; from++) {
334			// hack - skip over backslashes
335			if (parseBuffer[from] == '\\') {
336				length--;
337				continue;
338			}
339			tempString[to] = parseBuffer[from];
340			to++;
341		}
342		tempString[length] = 0;
343		yylval = (object_t *)tempString;
344		return STRING;
345	}
346
347	/* process numbers */
348	if (isDigit (c))
349	{
350		unsigned long long n = 0;
351		int base = 10;
352
353		if (c == '0') {
354			c = nextChar();
355			if (c == 'x') {
356				base = 16;
357				c = nextChar();
358			}
359		}
360		if (base == 10) {
361			while(isDigit(c)) {
362				n = (n * base + c - '0');
363				c = nextChar();
364			}
365		} else {
366			while(isHexDigit(c)) {
367				if (isDigit(c)) {
368					n = (n * base + c - '0');
369				} else {
370					n = (n * base + 0xa + c - 'a');
371				}
372				c = nextChar();
373			}
374		}
375
376		yylval = newObject();
377		yylval->u.offset = n;
378
379		return NUMBER;
380	}
381
382#define OSDATA_ALLOC_SIZE 4096
383
384	/* process data */
385	if (c == '<') {
386		unsigned char *d, *start, *lastStart;
387
388		start = lastStart = d = (unsigned char *)malloc(OSDATA_ALLOC_SIZE);
389		c = nextChar();	// skip over '<'
390		while (c != 0 && c != '>') {
391
392			if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
393			if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
394			if (c == '\n') {
395				lineNumber++;
396				c = nextChar();
397				continue;
398			}
399
400			// get high nibble
401			if (!isHexDigit(c)) break;
402			if (isDigit(c)) {
403				*d = (c - '0') << 4;
404			} else {
405				*d =  (0xa + (c - 'a')) << 4;
406			}
407
408			// get low nibble
409			c = nextChar();
410			if (!isHexDigit(c)) break;
411			if (isDigit(c)) {
412				*d |= c - '0';
413			} else {
414				*d |= 0xa + (c - 'a');
415			}
416
417			d++;
418			if ((d - lastStart) >= OSDATA_ALLOC_SIZE) {
419				int oldsize = d - start;
420				start = (unsigned char *)realloc(start, oldsize + OSDATA_ALLOC_SIZE);
421				d = lastStart = start + oldsize;
422			}
423			c = nextChar();
424		}
425		if (c != '>' ) {
426			free(start);
427			return SYNTAX_ERROR;
428		}
429
430		// got it!
431		yylval = newObject();
432		yylval->object = start;
433		yylval->size = d - start;
434
435		(void)nextChar();	// skip over '>'
436		return DATA;
437	}
438
439
440	/* return single chars, move pointer to next char */
441	(void)nextChar();
442	return c;
443}
444
445// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
446// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
447// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
448
449#if DEBUG
450int debugUnserializeAllocCount = 0;
451#endif
452
453object_t *
454newObject()
455{
456#if DEBUG
457	debugUnserializeAllocCount++;
458#endif
459	return (object_t *)malloc(sizeof(object_t));
460}
461
462void
463freeObject(object_t *o)
464{
465#if DEBUG
466	debugUnserializeAllocCount--;
467#endif
468	free(o);
469}
470
471static OSDictionary *tags;
472
473static void
474rememberObject(int tag, object_t *o)
475{
476	char key[16];
477	snprintf(key, sizeof(key), "%u", tag);
478
479	tags->setObject(key, (OSObject *)o);
480}
481
482static OSObject *
483retrieveObject(int tag)
484{
485	char key[16];
486	snprintf(key, sizeof(key), "%u", tag);
487
488	return tags->getObject(key);
489}
490
491OSObject *
492buildOSDictionary(object_t *o)
493{
494	object_t *temp, *last = o;
495	int count = 0;
496
497	// get count and last object
498	while (o) {
499		count++;
500		last = o;
501		o = o->next;
502	}
503	o = last;
504
505	OSDictionary *d = OSDictionary::withCapacity(count);
506
507	while (o) {
508#ifdef metaclass_stuff_worksXXX
509		if (((OSObject *)o->u.key)->metaCast("OSSymbol")) {
510			// XXX the evil frontdoor
511			d->setObject((OSSymbol *)o->u.key, (OSObject *)o->object);
512		} else {
513                        // If it isn't a symbol, I hope it's a string!
514			d->setObject((OSString *)o->u.key, (OSObject *)o->object);
515		}
516#else
517		d->setObject((OSString *)o->u.key, (OSObject *)o->object);
518#endif
519		((OSObject *)o->object)->release();
520		((OSObject *)o->u.key)->release();
521		temp = o;
522		o = o->prev;
523		freeObject(temp);
524	}
525	return d;
526};
527
528OSObject *
529buildOSArray(object_t *o)
530{
531	object_t *temp, *last = o;
532	int count = 0;
533
534	// get count and last object
535	while (o) {
536		count++;
537		last = o;
538		o = o->next;
539	}
540	o = last;
541
542	OSArray *a = OSArray::withCapacity(count);
543
544	while (o) {
545		a->setObject((OSObject *)o->object);
546		((OSObject *)o->object)->release();
547		temp = o;
548		o = o->prev;
549		freeObject(temp);
550	}
551	return a;
552};
553
554OSObject *
555buildOSSet(object_t *o)
556{
557	OSArray *a = (OSArray *)buildOSArray(o);
558	OSSet *s = OSSet::withArray(a, a->getCapacity());
559
560	a->release();
561	return s;
562};
563
564OSObject *
565buildOSString(object_t *o)
566{
567	OSString *s = OSString::withCString((char *)o);
568
569	free(o);
570
571	return s;
572};
573
574OSObject *
575buildOSData(object_t *o)
576{
577	OSData *d;
578
579	if (o->size) {
580		d = OSData::withBytes(o->object, o->size);
581	} else {
582		d = OSData::withCapacity(0);
583	}
584	free(o->object);
585	freeObject(o);
586	return d;
587};
588
589OSObject *
590buildOSOffset(object_t *o)
591{
592	OSNumber *off = OSNumber::withNumber(o->u.offset, o->size);
593	freeObject(o);
594	return off;
595};
596
597OSObject *
598buildOSBoolean(object_t *o)
599{
600	OSBoolean *b = OSBoolean::withBoolean((bool)o);
601	return b;
602};
603
604__BEGIN_DECLS
605#include <kern/locks.h>
606__END_DECLS
607
608static lck_mtx_t *lock = 0;
609extern lck_grp_t *IOLockGroup;
610
611OSObject*
612OSUnserialize(const char *buffer, OSString **errorString)
613{
614	OSObject *object;
615
616	if (!lock) {
617		lock = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
618		lck_mtx_lock(lock);
619	} else {
620		lck_mtx_lock(lock);
621
622	}
623
624#if DEBUG
625	debugUnserializeAllocCount = 0;
626#endif
627	yyerror_message[0] = 0;	//just in case
628	parseBuffer = buffer;
629	parseBufferIndex = 0;
630	tags = OSDictionary::withCapacity(128);
631	if (yyparse() == 0) {
632		object = parsedObject;
633		if (errorString) *errorString = 0;
634	} else {
635		object = 0;
636		if (errorString)
637			*errorString = OSString::withCString(yyerror_message);
638	}
639
640	tags->release();
641#if DEBUG
642	if (debugUnserializeAllocCount) {
643		printf("OSUnserialize: allocation check failed, count = %d.\n",
644		       debugUnserializeAllocCount);
645	}
646#endif
647	lck_mtx_unlock(lock);
648
649	return object;
650}
651
652
653//
654//
655//
656//
657//
658//		 DO NOT EDIT OSUnserialize.cpp!
659//
660//			this means you!
661//
662//
663//
664//
665//
666