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