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