]> git.saurik.com Git - apple/xnu.git/blame - libkern/c++/OSUnserialize.y
xnu-792.24.17.tar.gz
[apple/xnu.git] / libkern / c++ / OSUnserialize.y
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
8f6c56a5 11 *
6601e61a
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
21 */
22
23/* OSUnserialize.y created by rsulack on Nov 21 1998 */
24
25// "classic" parser for unserializing OSContainer objects
26//
27// XXX - this code should really be removed!
28// - the XML format is now prefered
29// - this code leaks on syntax errors, the XML doesn't
30// - "classic" looks, reads, ... much better than XML :-(
31// - well except the XML is more efficent on OSData
32//
33//
34// to build :
35// bison -p OSUnserialize OSUnserialize.y
36// head -50 OSUnserialize.y > OSUnserialize.cpp
37// sed -e "s/stdio.h/stddef.h/" < OSUnserialize.tab.c >> OSUnserialize.cpp
38//
39// when changing code check in both OSUnserialize.y and OSUnserialize.cpp
40//
41//
42//
43//
44// DO NOT EDIT OSUnserialize.tab.cpp!
45//
46// this means you!
47//
48//
49//
50//
51//
52
53
54%{
55#include <libkern/c++/OSMetaClass.h>
56#include <libkern/c++/OSContainers.h>
57#include <libkern/c++/OSLib.h>
58
59typedef struct object {
60 struct object *next;
61 struct object *prev;
62 void *object;
63 int size; // for data
64 union {
65 void *key; // for dictionary
66 long long offset; // for offset
67 } u;
68
69} object_t;
70
71static int yyparse();
72static int yyerror(char *s);
73static int yylex();
74
75static object_t * newObject();
76static void freeObject(object_t *o);
77
78static OSObject *buildOSDictionary(object_t *);
79static OSObject *buildOSArray(object_t *);
80static OSObject *buildOSSet(object_t *);
81static OSObject *buildOSString(object_t *);
82static OSObject *buildOSData(object_t *);
83static OSObject *buildOSOffset(object_t *);
84static OSObject *buildOSBoolean(object_t *o);
85
86static void rememberObject(int, object_t *);
87static OSObject *retrieveObject(int);
88
89// temp variable to use during parsing
90static object_t *o;
91
92// resultant object of parsed text
93static OSObject *parsedObject;
94
95#define YYSTYPE object_t *
96
97extern "C" {
98extern void *kern_os_malloc(size_t size);
99extern void *kern_os_realloc(void * addr, size_t size);
100extern void kern_os_free(void * addr);
101} /* extern "C" */
102
103#define malloc(s) kern_os_malloc(s)
104#define realloc(a, s) kern_os_realloc(a, s)
105#define free(a) kern_os_free(a)
106
107%}
108%token NUMBER
109%token STRING
110%token DATA
111%token BOOLEAN
112%token SYNTAX_ERROR
113
114%% /* Grammar rules and actions follow */
115
116input: /* empty */ { parsedObject = (OSObject *)NULL; YYACCEPT; }
117 | object { parsedObject = (OSObject *)$1; YYACCEPT; }
118 | SYNTAX_ERROR { yyerror("syntax error"); YYERROR; }
119 ;
120
121object: dict { $$ = (object_t *)buildOSDictionary($1); }
122 | array { $$ = (object_t *)buildOSArray($1); }
123 | set { $$ = (object_t *)buildOSSet($1); }
124 | string { $$ = (object_t *)buildOSString($1); }
125 | data { $$ = (object_t *)buildOSData($1); }
126 | offset { $$ = (object_t *)buildOSOffset($1); }
127 | boolean { $$ = (object_t *)buildOSBoolean($1); }
128 | '@' NUMBER { $$ = (object_t *)retrieveObject($2->u.offset);
129 if ($$) {
130 ((OSObject *)$$)->retain();
131 } else {
132 yyerror("forward reference detected");
133 YYERROR;
134 }
135 freeObject($2);
136 }
137 | object '@' NUMBER { $$ = $1;
138 rememberObject($3->u.offset, $1);
139 freeObject($3);
140 }
141 ;
142
143//------------------------------------------------------------------------------
144
145dict: '{' '}' { $$ = NULL; }
146 | '{' pairs '}' { $$ = $2; }
147 ;
148
149pairs: pair
150 | pairs pair { $2->next = $1; $1->prev = $2; $$ = $2; }
151 ;
152
153pair: object '=' object ';' { $$ = newObject();
154 $$->next = NULL;
155 $$->prev = NULL;
156 $$->u.key = $1;
157 $$->object = $3;
158 }
159 ;
160
161//------------------------------------------------------------------------------
162
163array: '(' ')' { $$ = NULL; }
164 | '(' elements ')' { $$ = $2; }
165 ;
166
167set: '[' ']' { $$ = NULL; }
168 | '[' elements ']' { $$ = $2; }
169 ;
170
171elements: object { $$ = newObject();
172 $$->object = $1;
173 $$->next = NULL;
174 $$->prev = NULL;
175 }
176 | elements ',' object { o = newObject();
177 o->object = $3;
178 o->next = $1;
179 o->prev = NULL;
180 $1->prev = o;
181 $$ = o;
182 }
183 ;
184
185//------------------------------------------------------------------------------
186
187offset: NUMBER ':' NUMBER { $$ = $1;
188 $$->size = $3->u.offset;
189 freeObject($3);
190 }
191 ;
192
193//------------------------------------------------------------------------------
194
195data: DATA
196 ;
197
198//------------------------------------------------------------------------------
199
200string: STRING
201 ;
202
203//------------------------------------------------------------------------------
204
205boolean: BOOLEAN
206 ;
207
208%%
209
210static int lineNumber = 0;
211static const char *parseBuffer;
212static int parseBufferIndex;
213
214#define currentChar() (parseBuffer[parseBufferIndex])
215#define nextChar() (parseBuffer[++parseBufferIndex])
216#define prevChar() (parseBuffer[parseBufferIndex - 1])
217
218#define isSpace(c) ((c) == ' ' || (c) == '\t')
219#define isAlpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
220#define isDigit(c) ((c) >= '0' && (c) <= '9')
221#define isAlphaDigit(c) ((c) >= 'a' && (c) <= 'f')
222#define isHexDigit(c) (isDigit(c) || isAlphaDigit(c))
223#define isAlphaNumeric(c) (isAlpha(c) || isDigit(c) || ((c) == '-'))
224
225static char yyerror_message[128];
226
227int
228yyerror(char *s) /* Called by yyparse on error */
229{
230 sprintf(yyerror_message, "OSUnserialize: %s near line %d\n", s, lineNumber);
231 return 0;
232}
233
234int
235yylex()
236{
237 int c;
238
239 if (parseBufferIndex == 0) lineNumber = 1;
240
241 top:
242 c = currentChar();
243
244 /* skip white space */
245 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
246
247 /* skip over comments */
248 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
249
250 /* keep track of line number, don't return \n's */
251 if (c == '\n') {
252 lineNumber++;
253 (void)nextChar();
254 goto top;
255 }
256
257 /* parse boolean */
258 if (c == '.') {
259 bool boolean = false;
260 if (nextChar() == 't') {
261 if (nextChar() != 'r') return SYNTAX_ERROR;
262 if (nextChar() != 'u') return SYNTAX_ERROR;
263 if (nextChar() != 'e') return SYNTAX_ERROR;
264 boolean = true;
265 } else {
266 if (currentChar() != 'f') return SYNTAX_ERROR;
267 if (nextChar() != 'a') return SYNTAX_ERROR;
268 if (nextChar() != 'l') return SYNTAX_ERROR;
269 if (nextChar() != 's') return SYNTAX_ERROR;
270 if (nextChar() != 'e') return SYNTAX_ERROR;
271 }
272 if (nextChar() != '.') return SYNTAX_ERROR;
273 /* skip over dot */
274 (void)nextChar();
275
276 yylval = (object_t *)boolean;
277 return BOOLEAN;
278 }
279
280 /* parse unquoted string */
281 if (isAlpha(c)) {
282 int start, length;
283 char * tempString;
284
285 start = parseBufferIndex;
286 /* find end of string */
287 while (isAlphaNumeric(c)) {
288 c = nextChar();
289 }
290 length = parseBufferIndex - start;
291
292 /* copy to null terminated buffer */
293 tempString = (char *)malloc(length + 1);
294 if (tempString == 0) {
295 printf("OSUnserialize: can't alloc temp memory\n");
296 return 0;
297 }
298 bcopy(&parseBuffer[start], tempString, length);
299 tempString[length] = 0;
300 yylval = (object_t *)tempString;
301 return STRING;
302 }
303
304 /* parse quoted string */
305 if (c == '"' || c == '\'') {
306 int start, length;
307 char * tempString;
308 char quoteChar = c;
309
310 start = parseBufferIndex + 1; // skip quote
311 /* find end of string, line, buffer */
312 while ((c = nextChar()) != quoteChar) {
313 if (c == '\\') c = nextChar();
314 if (c == '\n') lineNumber++;
315 if (c == 0) return SYNTAX_ERROR;
316 }
317 length = parseBufferIndex - start;
318 /* skip over trailing quote */
319 (void)nextChar();
320 /* copy to null terminated buffer */
321 tempString = (char *)malloc(length + 1);
322 if (tempString == 0) {
323 printf("OSUnserialize: can't alloc temp memory\n");
324 return 0;
325 }
326
327 int to = 0;
328 for (int from=start; from < parseBufferIndex; from++) {
329 // hack - skip over backslashes
330 if (parseBuffer[from] == '\\') {
331 length--;
332 continue;
333 }
334 tempString[to] = parseBuffer[from];
335 to++;
336 }
337 tempString[length] = 0;
338 yylval = (object_t *)tempString;
339 return STRING;
340 }
341
342 /* process numbers */
343 if (isDigit (c))
344 {
345 unsigned long long n = 0;
346 int base = 10;
347
348 if (c == '0') {
349 c = nextChar();
350 if (c == 'x') {
351 base = 16;
352 c = nextChar();
353 }
354 }
355 if (base == 10) {
356 while(isDigit(c)) {
357 n = (n * base + c - '0');
358 c = nextChar();
359 }
360 } else {
361 while(isHexDigit(c)) {
362 if (isDigit(c)) {
363 n = (n * base + c - '0');
364 } else {
365 n = (n * base + 0xa + c - 'a');
366 }
367 c = nextChar();
368 }
369 }
370
371 yylval = newObject();
372 yylval->u.offset = n;
373
374 return NUMBER;
375 }
376
377#define OSDATA_ALLOC_SIZE 4096
378
379 /* process data */
380 if (c == '<') {
381 unsigned char *d, *start, *lastStart;
382
383 start = lastStart = d = (unsigned char *)malloc(OSDATA_ALLOC_SIZE);
384 c = nextChar(); // skip over '<'
385 while (c != 0 && c != '>') {
386
387 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
388 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
389 if (c == '\n') {
390 lineNumber++;
391 c = nextChar();
392 continue;
393 }
394
395 // get high nibble
396 if (!isHexDigit(c)) break;
397 if (isDigit(c)) {
398 *d = (c - '0') << 4;
399 } else {
400 *d = (0xa + (c - 'a')) << 4;
401 }
402
403 // get low nibble
404 c = nextChar();
405 if (!isHexDigit(c)) break;
406 if (isDigit(c)) {
407 *d |= c - '0';
408 } else {
409 *d |= 0xa + (c - 'a');
410 }
411
412 d++;
413 if ((d - lastStart) >= OSDATA_ALLOC_SIZE) {
414 int oldsize = d - start;
415 start = (unsigned char *)realloc(start, oldsize + OSDATA_ALLOC_SIZE);
416 d = lastStart = start + oldsize;
417 }
418 c = nextChar();
419 }
420 if (c != '>' ) {
421 free(start);
422 return SYNTAX_ERROR;
423 }
424
425 // got it!
426 yylval = newObject();
427 yylval->object = start;
428 yylval->size = d - start;
429
430 (void)nextChar(); // skip over '>'
431 return DATA;
432 }
433
434
435 /* return single chars, move pointer to next char */
436 (void)nextChar();
437 return c;
438}
439
440// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
441// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
442// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
443
444#ifdef DEBUG
445int debugUnserializeAllocCount = 0;
446#endif
447
448object_t *
449newObject()
450{
451#ifdef DEBUG
452 debugUnserializeAllocCount++;
453#endif
454 return (object_t *)malloc(sizeof(object_t));
455}
456
457void
458freeObject(object_t *o)
459{
460#ifdef DEBUG
461 debugUnserializeAllocCount--;
462#endif
463 free(o);
464}
465
466static OSDictionary *tags;
467
468static void
469rememberObject(int tag, object_t *o)
470{
471 char key[16];
472 sprintf(key, "%u", tag);
473
474 tags->setObject(key, (OSObject *)o);
475}
476
477static OSObject *
478retrieveObject(int tag)
479{
480 char key[16];
481 sprintf(key, "%u", tag);
482
483 return tags->getObject(key);
484}
485
486OSObject *
487buildOSDictionary(object_t *o)
488{
489 object_t *temp, *last = o;
490 int count = 0;
491
492 // get count and last object
493 while (o) {
494 count++;
495 last = o;
496 o = o->next;
497 }
498 o = last;
499
500 OSDictionary *d = OSDictionary::withCapacity(count);
501
502 while (o) {
503#ifdef metaclass_stuff_worksXXX
504 if (((OSObject *)o->u.key)->metaCast("OSSymbol")) {
505 // XXX the evil frontdoor
506 d->setObject((OSSymbol *)o->u.key, (OSObject *)o->object);
507 } else {
508 // If it isn't a symbol, I hope it's a string!
509 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
510 }
511#else
512 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
513#endif
514 ((OSObject *)o->object)->release();
515 ((OSObject *)o->u.key)->release();
516 temp = o;
517 o = o->prev;
518 freeObject(temp);
519 }
520 return d;
521};
522
523OSObject *
524buildOSArray(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 OSArray *a = OSArray::withCapacity(count);
538
539 while (o) {
540 a->setObject((OSObject *)o->object);
541 ((OSObject *)o->object)->release();
542 temp = o;
543 o = o->prev;
544 freeObject(temp);
545 }
546 return a;
547};
548
549OSObject *
550buildOSSet(object_t *o)
551{
552 OSArray *a = (OSArray *)buildOSArray(o);
553 OSSet *s = OSSet::withArray(a, a->getCapacity());
554
555 a->release();
556 return s;
557};
558
559OSObject *
560buildOSString(object_t *o)
561{
562 OSString *s = OSString::withCString((char *)o);
563
564 free(o);
565
566 return s;
567};
568
569OSObject *
570buildOSData(object_t *o)
571{
572 OSData *d;
573
574 if (o->size) {
575 d = OSData::withBytes(o->object, o->size);
576 } else {
577 d = OSData::withCapacity(0);
578 }
579 free(o->object);
580 freeObject(o);
581 return d;
582};
583
584OSObject *
585buildOSOffset(object_t *o)
586{
587 OSNumber *off = OSNumber::withNumber(o->u.offset, o->size);
588 freeObject(o);
589 return off;
590};
591
592OSObject *
593buildOSBoolean(object_t *o)
594{
595 OSBoolean *b = OSBoolean::withBoolean((bool)o);
596 return b;
597};
598
599__BEGIN_DECLS
600#include <kern/lock.h>
601__END_DECLS
602
603static mutex_t *lock = 0;
604
605OSObject*
606OSUnserialize(const char *buffer, OSString **errorString)
607{
608 OSObject *object;
609
610 if (!lock) {
611 lock = mutex_alloc(ETAP_IO_AHA);
612 _mutex_lock(lock);
613 } else {
614 _mutex_lock(lock);
615
616 }
617
618#ifdef DEBUG
619 debugUnserializeAllocCount = 0;
620#endif
621 yyerror_message[0] = 0; //just in case
622 parseBuffer = buffer;
623 parseBufferIndex = 0;
624 tags = OSDictionary::withCapacity(128);
625 if (yyparse() == 0) {
626 object = parsedObject;
627 if (errorString) *errorString = 0;
628 } else {
629 object = 0;
630 if (errorString)
631 *errorString = OSString::withCString(yyerror_message);
632 }
633
634 tags->release();
635#ifdef DEBUG
636 if (debugUnserializeAllocCount) {
637 printf("OSUnserialize: allocation check failed, count = %d.\n",
638 debugUnserializeAllocCount);
639 }
640#endif
641 mutex_unlock(lock);
642
643 return object;
644}
645
646
647//
648//
649//
650//
651//
652// DO NOT EDIT OSUnserialize.cpp!
653//
654// this means you!
655//
656//
657//
658//
659//