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