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