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