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_SET_NOTSHARED)
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