2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 /* OSUnserialize.y created by rsulack on Nov 21 1998 */
33 // "classic" parser for unserializing OSContainer objects
35 // XXX - this code should really be removed!
36 // - the XML format is now prefered
37 // - this code leaks on syntax errors, the XML doesn't
38 // - "classic" looks, reads, ... much better than XML :-(
39 // - well except the XML is more efficent on OSData
43 // bison -p OSUnserialize OSUnserialize.y
44 // head -50 OSUnserialize.y > OSUnserialize.cpp
45 // sed -e "s/stdio.h/stddef.h/" < OSUnserialize.tab.c >> OSUnserialize.cpp
47 // when changing code check in both OSUnserialize.y and OSUnserialize.cpp
52 // DO NOT EDIT OSUnserialize.tab.cpp!
63 #include <libkern/c++/OSMetaClass.h>
64 #include <libkern/c++/OSContainers.h>
65 #include <libkern/c++/OSLib.h>
67 typedef struct object {
73 void *key; // for dictionary
74 long long offset; // for offset
80 static int yyerror(char *s);
83 static object_t * newObject();
84 static void freeObject(object_t *o);
86 static OSObject *buildOSDictionary(object_t *);
87 static OSObject *buildOSArray(object_t *);
88 static OSObject *buildOSSet(object_t *);
89 static OSObject *buildOSString(object_t *);
90 static OSObject *buildOSData(object_t *);
91 static OSObject *buildOSOffset(object_t *);
92 static OSObject *buildOSBoolean(object_t *o);
94 static void rememberObject(int, object_t *);
95 static OSObject *retrieveObject(int);
97 // temp variable to use during parsing
100 // resultant object of parsed text
101 static OSObject *parsedObject;
103 #define YYSTYPE object_t *
106 extern void *kern_os_malloc(size_t size);
107 extern void *kern_os_realloc(void * addr, size_t size);
108 extern void kern_os_free(void * addr);
111 #define malloc(s) kern_os_malloc(s)
112 #define realloc(a, s) kern_os_realloc(a, s)
113 #define free(a) kern_os_free(a)
122 %% /* Grammar rules and actions follow */
124 input: /* empty */ { parsedObject = (OSObject *)NULL; YYACCEPT; }
125 | object { parsedObject = (OSObject *)$1; YYACCEPT; }
126 | SYNTAX_ERROR { yyerror("syntax error"); YYERROR; }
129 object: dict { $$ = (object_t *)buildOSDictionary($1); }
130 | array { $$ = (object_t *)buildOSArray($1); }
131 | set { $$ = (object_t *)buildOSSet($1); }
132 | string { $$ = (object_t *)buildOSString($1); }
133 | data { $$ = (object_t *)buildOSData($1); }
134 | offset { $$ = (object_t *)buildOSOffset($1); }
135 | boolean { $$ = (object_t *)buildOSBoolean($1); }
136 | '@' NUMBER { $$ = (object_t *)retrieveObject($2->u.offset);
138 ((OSObject *)$$)->retain();
140 yyerror("forward reference detected");
145 | object '@' NUMBER { $$ = $1;
146 rememberObject($3->u.offset, $1);
151 //------------------------------------------------------------------------------
153 dict: '{' '}' { $$ = NULL; }
154 | '{' pairs '}' { $$ = $2; }
158 | pairs pair { $2->next = $1; $1->prev = $2; $$ = $2; }
161 pair: object '=' object ';' { $$ = newObject();
169 //------------------------------------------------------------------------------
171 array: '(' ')' { $$ = NULL; }
172 | '(' elements ')' { $$ = $2; }
175 set: '[' ']' { $$ = NULL; }
176 | '[' elements ']' { $$ = $2; }
179 elements: object { $$ = newObject();
184 | elements ',' object { o = newObject();
193 //------------------------------------------------------------------------------
195 offset: NUMBER ':' NUMBER { $$ = $1;
196 $$->size = $3->u.offset;
201 //------------------------------------------------------------------------------
206 //------------------------------------------------------------------------------
211 //------------------------------------------------------------------------------
218 static int lineNumber = 0;
219 static const char *parseBuffer;
220 static int parseBufferIndex;
222 #define currentChar() (parseBuffer[parseBufferIndex])
223 #define nextChar() (parseBuffer[++parseBufferIndex])
224 #define prevChar() (parseBuffer[parseBufferIndex - 1])
226 #define isSpace(c) ((c) == ' ' || (c) == '\t')
227 #define isAlpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
228 #define isDigit(c) ((c) >= '0' && (c) <= '9')
229 #define isAlphaDigit(c) ((c) >= 'a' && (c) <= 'f')
230 #define isHexDigit(c) (isDigit(c) || isAlphaDigit(c))
231 #define isAlphaNumeric(c) (isAlpha(c) || isDigit(c) || ((c) == '-'))
233 static char yyerror_message[128];
236 yyerror(char *s) /* Called by yyparse on error */
238 sprintf(yyerror_message, "OSUnserialize: %s near line %d\n", s, lineNumber);
247 if (parseBufferIndex == 0) lineNumber = 1;
252 /* skip white space */
253 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
255 /* skip over comments */
256 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
258 /* keep track of line number, don't return \n's */
267 bool boolean = false;
268 if (nextChar() == 't') {
269 if (nextChar() != 'r') return SYNTAX_ERROR;
270 if (nextChar() != 'u') return SYNTAX_ERROR;
271 if (nextChar() != 'e') return SYNTAX_ERROR;
274 if (currentChar() != 'f') return SYNTAX_ERROR;
275 if (nextChar() != 'a') return SYNTAX_ERROR;
276 if (nextChar() != 'l') return SYNTAX_ERROR;
277 if (nextChar() != 's') return SYNTAX_ERROR;
278 if (nextChar() != 'e') return SYNTAX_ERROR;
280 if (nextChar() != '.') return SYNTAX_ERROR;
284 yylval = (object_t *)boolean;
288 /* parse unquoted string */
293 start = parseBufferIndex;
294 /* find end of string */
295 while (isAlphaNumeric(c)) {
298 length = parseBufferIndex - start;
300 /* copy to null terminated buffer */
301 tempString = (char *)malloc(length + 1);
302 if (tempString == 0) {
303 printf("OSUnserialize: can't alloc temp memory\n");
306 bcopy(&parseBuffer[start], tempString, length);
307 tempString[length] = 0;
308 yylval = (object_t *)tempString;
312 /* parse quoted string */
313 if (c == '"' || c == '\'') {
318 start = parseBufferIndex + 1; // skip quote
319 /* find end of string, line, buffer */
320 while ((c = nextChar()) != quoteChar) {
321 if (c == '\\') c = nextChar();
322 if (c == '\n') lineNumber++;
323 if (c == 0) return SYNTAX_ERROR;
325 length = parseBufferIndex - start;
326 /* skip over trailing quote */
328 /* copy to null terminated buffer */
329 tempString = (char *)malloc(length + 1);
330 if (tempString == 0) {
331 printf("OSUnserialize: can't alloc temp memory\n");
336 for (int from=start; from < parseBufferIndex; from++) {
337 // hack - skip over backslashes
338 if (parseBuffer[from] == '\\') {
342 tempString[to] = parseBuffer[from];
345 tempString[length] = 0;
346 yylval = (object_t *)tempString;
350 /* process numbers */
353 unsigned long long n = 0;
365 n = (n * base + c - '0');
369 while(isHexDigit(c)) {
371 n = (n * base + c - '0');
373 n = (n * base + 0xa + c - 'a');
379 yylval = newObject();
380 yylval->u.offset = n;
385 #define OSDATA_ALLOC_SIZE 4096
389 unsigned char *d, *start, *lastStart;
391 start = lastStart = d = (unsigned char *)malloc(OSDATA_ALLOC_SIZE);
392 c = nextChar(); // skip over '<'
393 while (c != 0 && c != '>') {
395 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
396 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
404 if (!isHexDigit(c)) break;
408 *d = (0xa + (c - 'a')) << 4;
413 if (!isHexDigit(c)) break;
417 *d |= 0xa + (c - 'a');
421 if ((d - lastStart) >= OSDATA_ALLOC_SIZE) {
422 int oldsize = d - start;
423 start = (unsigned char *)realloc(start, oldsize + OSDATA_ALLOC_SIZE);
424 d = lastStart = start + oldsize;
434 yylval = newObject();
435 yylval->object = start;
436 yylval->size = d - start;
438 (void)nextChar(); // skip over '>'
443 /* return single chars, move pointer to next char */
448 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
449 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
450 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
453 int debugUnserializeAllocCount = 0;
460 debugUnserializeAllocCount++;
462 return (object_t *)malloc(sizeof(object_t));
466 freeObject(object_t *o)
469 debugUnserializeAllocCount--;
474 static OSDictionary *tags;
477 rememberObject(int tag, object_t *o)
480 sprintf(key, "%u", tag);
482 tags->setObject(key, (OSObject *)o);
486 retrieveObject(int tag)
489 sprintf(key, "%u", tag);
491 return tags->getObject(key);
495 buildOSDictionary(object_t *o)
497 object_t *temp, *last = o;
500 // get count and last object
508 OSDictionary *d = OSDictionary::withCapacity(count);
511 #ifdef metaclass_stuff_worksXXX
512 if (((OSObject *)o->u.key)->metaCast("OSSymbol")) {
513 // XXX the evil frontdoor
514 d->setObject((OSSymbol *)o->u.key, (OSObject *)o->object);
516 // If it isn't a symbol, I hope it's a string!
517 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
520 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
522 ((OSObject *)o->object)->release();
523 ((OSObject *)o->u.key)->release();
532 buildOSArray(object_t *o)
534 object_t *temp, *last = o;
537 // get count and last object
545 OSArray *a = OSArray::withCapacity(count);
548 a->setObject((OSObject *)o->object);
549 ((OSObject *)o->object)->release();
558 buildOSSet(object_t *o)
560 OSArray *a = (OSArray *)buildOSArray(o);
561 OSSet *s = OSSet::withArray(a, a->getCapacity());
568 buildOSString(object_t *o)
570 OSString *s = OSString::withCString((char *)o);
578 buildOSData(object_t *o)
583 d = OSData::withBytes(o->object, o->size);
585 d = OSData::withCapacity(0);
593 buildOSOffset(object_t *o)
595 OSNumber *off = OSNumber::withNumber(o->u.offset, o->size);
601 buildOSBoolean(object_t *o)
603 OSBoolean *b = OSBoolean::withBoolean((bool)o);
608 #include <kern/lock.h>
611 static mutex_t *lock = 0;
614 OSUnserialize(const char *buffer, OSString **errorString)
619 lock = mutex_alloc(ETAP_IO_AHA);
627 debugUnserializeAllocCount = 0;
629 yyerror_message[0] = 0; //just in case
630 parseBuffer = buffer;
631 parseBufferIndex = 0;
632 tags = OSDictionary::withCapacity(128);
633 if (yyparse() == 0) {
634 object = parsedObject;
635 if (errorString) *errorString = 0;
639 *errorString = OSString::withCString(yyerror_message);
644 if (debugUnserializeAllocCount) {
645 printf("OSUnserialize: allocation check failed, count = %d.\n",
646 debugUnserializeAllocCount);
660 // DO NOT EDIT OSUnserialize.cpp!