2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 /* OSUnserialize.y created by rsulack on Nov 21 1998 */
25 // "classic" parser for unserializing OSContainer objects
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
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
39 // when changing code check in both OSUnserialize.y and OSUnserialize.cpp
44 // DO NOT EDIT OSUnserialize.tab.cpp!
55 #include <libkern/c++/OSMetaClass.h>
56 #include <libkern/c++/OSContainers.h>
57 #include <libkern/c++/OSLib.h>
59 typedef struct object {
65 void *key; // for dictionary
66 long long offset; // for offset
72 static int yyerror(char *s);
75 static object_t * newObject();
76 static void freeObject(object_t *o);
78 static OSObject *buildOSDictionary(object_t *);
79 static OSObject *buildOSArray(object_t *);
80 static OSObject *buildOSSet(object_t *);
81 static OSObject *buildOSString(object_t *);
82 static OSObject *buildOSData(object_t *);
83 static OSObject *buildOSOffset(object_t *);
84 static OSObject *buildOSBoolean(object_t *o);
86 static void rememberObject(int, object_t *);
87 static OSObject *retrieveObject(int);
89 // temp variable to use during parsing
92 // resultant object of parsed text
93 static OSObject *parsedObject;
95 #define YYSTYPE object_t *
98 extern void *kern_os_malloc(size_t size);
99 extern void *kern_os_realloc(void * addr, size_t size);
100 extern void kern_os_free(void * addr);
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)
114 %% /* Grammar rules and actions follow */
116 input: /* empty */ { parsedObject = (OSObject *)NULL; YYACCEPT; }
117 | object { parsedObject = (OSObject *)$1; YYACCEPT; }
118 | SYNTAX_ERROR { yyerror("syntax error"); YYERROR; }
121 object: 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);
130 ((OSObject *)$$)->retain();
132 yyerror("forward reference detected");
137 | object '@' NUMBER { $$ = $1;
138 rememberObject($3->u.offset, $1);
143 //------------------------------------------------------------------------------
145 dict: '{' '}' { $$ = NULL; }
146 | '{' pairs '}' { $$ = $2; }
150 | pairs pair { $2->next = $1; $1->prev = $2; $$ = $2; }
153 pair: object '=' object ';' { $$ = newObject();
161 //------------------------------------------------------------------------------
163 array: '(' ')' { $$ = NULL; }
164 | '(' elements ')' { $$ = $2; }
167 set: '[' ']' { $$ = NULL; }
168 | '[' elements ']' { $$ = $2; }
171 elements: object { $$ = newObject();
176 | elements ',' object { o = newObject();
185 //------------------------------------------------------------------------------
187 offset: NUMBER ':' NUMBER { $$ = $1;
188 $$->size = $3->u.offset;
193 //------------------------------------------------------------------------------
198 //------------------------------------------------------------------------------
203 //------------------------------------------------------------------------------
210 static int lineNumber = 0;
211 static const char *parseBuffer;
212 static int parseBufferIndex;
214 #define currentChar() (parseBuffer[parseBufferIndex])
215 #define nextChar() (parseBuffer[++parseBufferIndex])
216 #define prevChar() (parseBuffer[parseBufferIndex - 1])
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) == '-'))
225 static char yyerror_message[128];
228 yyerror(char *s) /* Called by yyparse on error */
230 sprintf(yyerror_message, "OSUnserialize: %s near line %d\n", s, lineNumber);
239 if (parseBufferIndex == 0) lineNumber = 1;
244 /* skip white space */
245 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
247 /* skip over comments */
248 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
250 /* keep track of line number, don't return \n's */
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;
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;
272 if (nextChar() != '.') return SYNTAX_ERROR;
276 yylval = (object_t *)boolean;
280 /* parse unquoted string */
285 start = parseBufferIndex;
286 /* find end of string */
287 while (isAlphaNumeric(c)) {
290 length = parseBufferIndex - start;
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");
298 bcopy(&parseBuffer[start], tempString, length);
299 tempString[length] = 0;
300 yylval = (object_t *)tempString;
304 /* parse quoted string */
305 if (c == '"' || c == '\'') {
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;
317 length = parseBufferIndex - start;
318 /* skip over trailing quote */
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");
328 for (int from=start; from < parseBufferIndex; from++) {
329 // hack - skip over backslashes
330 if (parseBuffer[from] == '\\') {
334 tempString[to] = parseBuffer[from];
337 tempString[length] = 0;
338 yylval = (object_t *)tempString;
342 /* process numbers */
345 unsigned long long n = 0;
357 n = (n * base + c - '0');
361 while(isHexDigit(c)) {
363 n = (n * base + c - '0');
365 n = (n * base + 0xa + c - 'a');
371 yylval = newObject();
372 yylval->u.offset = n;
377 #define OSDATA_ALLOC_SIZE 4096
381 unsigned char *d, *start, *lastStart;
383 start = lastStart = d = (unsigned char *)malloc(OSDATA_ALLOC_SIZE);
384 c = nextChar(); // skip over '<'
385 while (c != 0 && c != '>') {
387 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
388 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
396 if (!isHexDigit(c)) break;
400 *d = (0xa + (c - 'a')) << 4;
405 if (!isHexDigit(c)) break;
409 *d |= 0xa + (c - 'a');
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;
426 yylval = newObject();
427 yylval->object = start;
428 yylval->size = d - start;
430 (void)nextChar(); // skip over '>'
435 /* return single chars, move pointer to next char */
440 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
441 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
442 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
445 int debugUnserializeAllocCount = 0;
452 debugUnserializeAllocCount++;
454 return (object_t *)malloc(sizeof(object_t));
458 freeObject(object_t *o)
461 debugUnserializeAllocCount--;
466 static OSDictionary *tags;
469 rememberObject(int tag, object_t *o)
472 sprintf(key, "%u", tag);
474 tags->setObject(key, (OSObject *)o);
478 retrieveObject(int tag)
481 sprintf(key, "%u", tag);
483 return tags->getObject(key);
487 buildOSDictionary(object_t *o)
489 object_t *temp, *last = o;
492 // get count and last object
500 OSDictionary *d = OSDictionary::withCapacity(count);
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);
508 // If it isn't a symbol, I hope it's a string!
509 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
512 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
514 ((OSObject *)o->object)->release();
515 ((OSObject *)o->u.key)->release();
524 buildOSArray(object_t *o)
526 object_t *temp, *last = o;
529 // get count and last object
537 OSArray *a = OSArray::withCapacity(count);
540 a->setObject((OSObject *)o->object);
541 ((OSObject *)o->object)->release();
550 buildOSSet(object_t *o)
552 OSArray *a = (OSArray *)buildOSArray(o);
553 OSSet *s = OSSet::withArray(a, a->getCapacity());
560 buildOSString(object_t *o)
562 OSString *s = OSString::withCString((char *)o);
570 buildOSData(object_t *o)
575 d = OSData::withBytes(o->object, o->size);
577 d = OSData::withCapacity(0);
585 buildOSOffset(object_t *o)
587 OSNumber *off = OSNumber::withNumber(o->u.offset, o->size);
593 buildOSBoolean(object_t *o)
595 OSBoolean *b = OSBoolean::withBoolean((bool)o);
600 #include <kern/lock.h>
603 static mutex_t *lock = 0;
606 OSUnserialize(const char *buffer, OSString **errorString)
611 lock = mutex_alloc(ETAP_IO_AHA);
619 debugUnserializeAllocCount = 0;
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;
631 *errorString = OSString::withCString(yyerror_message);
636 if (debugUnserializeAllocCount) {
637 printf("OSUnserialize: allocation check failed, count = %d.\n",
638 debugUnserializeAllocCount);
652 // DO NOT EDIT OSUnserialize.cpp!