2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* OSUnserialize.y created by rsulack on Nov 21 1998 */
31 // "classic" parser for unserializing OSContainer objects
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
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
45 // when changing code check in both OSUnserialize.y and OSUnserialize.cpp
50 // DO NOT EDIT OSUnserialize.tab.cpp!
61 #include <libkern/c++/OSMetaClass.h>
62 #include <libkern/c++/OSContainers.h>
63 #include <libkern/c++/OSLib.h>
65 typedef struct object {
71 void *key; // for dictionary
72 long long offset; // for offset
77 static int yyerror(const char *s);
80 static object_t * newObject();
81 static void freeObject(object_t *o);
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);
91 static void rememberObject(int, object_t *);
92 static OSObject *retrieveObject(int);
94 // temp variable to use during parsing
97 // resultant object of parsed text
98 static OSObject *parsedObject;
100 #define YYSTYPE object_t *
102 #include <libkern/OSRuntime.h>
104 #define malloc(s) kern_os_malloc(s)
105 #define realloc(a, s) kern_os_realloc(a, s)
106 #define free(a) kern_os_free(a)
115 %% /* Grammar rules and actions follow */
117 input: /* empty */ { parsedObject = (OSObject *)NULL; YYACCEPT; }
118 | object { parsedObject = (OSObject *)$1; YYACCEPT; }
119 | SYNTAX_ERROR { yyerror("syntax error"); YYERROR; }
122 object: dict { $$ = (object_t *)buildOSDictionary($1); }
123 | array { $$ = (object_t *)buildOSArray($1); }
124 | set { $$ = (object_t *)buildOSSet($1); }
125 | string { $$ = (object_t *)buildOSString($1); }
126 | data { $$ = (object_t *)buildOSData($1); }
127 | offset { $$ = (object_t *)buildOSOffset($1); }
128 | boolean { $$ = (object_t *)buildOSBoolean($1); }
129 | '@' NUMBER { $$ = (object_t *)retrieveObject($2->u.offset);
131 ((OSObject *)$$)->retain();
133 yyerror("forward reference detected");
138 | object '@' NUMBER { $$ = $1;
139 rememberObject($3->u.offset, $1);
144 //------------------------------------------------------------------------------
146 dict: '{' '}' { $$ = NULL; }
147 | '{' pairs '}' { $$ = $2; }
151 | pairs pair { $2->next = $1; $1->prev = $2; $$ = $2; }
154 pair: object '=' object ';' { $$ = newObject();
162 //------------------------------------------------------------------------------
164 array: '(' ')' { $$ = NULL; }
165 | '(' elements ')' { $$ = $2; }
168 set: '[' ']' { $$ = NULL; }
169 | '[' elements ']' { $$ = $2; }
172 elements: object { $$ = newObject();
177 | elements ',' object { oo = newObject();
186 //------------------------------------------------------------------------------
188 offset: NUMBER ':' NUMBER { $$ = $1;
189 $$->size = $3->u.offset;
194 //------------------------------------------------------------------------------
199 //------------------------------------------------------------------------------
204 //------------------------------------------------------------------------------
211 static int lineNumber = 0;
212 static const char *parseBuffer;
213 static int parseBufferIndex;
215 #define currentChar() (parseBuffer[parseBufferIndex])
216 #define nextChar() (parseBuffer[++parseBufferIndex])
217 #define prevChar() (parseBuffer[parseBufferIndex - 1])
219 #define isSpace(c) ((c) == ' ' || (c) == '\t')
220 #define isAlpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
221 #define isDigit(c) ((c) >= '0' && (c) <= '9')
222 #define isAlphaDigit(c) ((c) >= 'a' && (c) <= 'f')
223 #define isHexDigit(c) (isDigit(c) || isAlphaDigit(c))
224 #define isAlphaNumeric(c) (isAlpha(c) || isDigit(c) || ((c) == '-'))
226 static char yyerror_message[128];
229 yyerror(const char *s) /* Called by yyparse on error */
231 snprintf(yyerror_message, sizeof(yyerror_message), "OSUnserialize: %s near line %d\n", s, lineNumber);
240 if (parseBufferIndex == 0) lineNumber = 1;
245 /* skip white space */
246 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
248 /* skip over comments */
249 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
251 /* keep track of line number, don't return \n's */
260 bool boolean = false;
261 if (nextChar() == 't') {
262 if (nextChar() != 'r') return SYNTAX_ERROR;
263 if (nextChar() != 'u') return SYNTAX_ERROR;
264 if (nextChar() != 'e') return SYNTAX_ERROR;
267 if (currentChar() != 'f') return SYNTAX_ERROR;
268 if (nextChar() != 'a') return SYNTAX_ERROR;
269 if (nextChar() != 'l') return SYNTAX_ERROR;
270 if (nextChar() != 's') return SYNTAX_ERROR;
271 if (nextChar() != 'e') return SYNTAX_ERROR;
273 if (nextChar() != '.') return SYNTAX_ERROR;
277 yylval = (object_t *)boolean;
281 /* parse unquoted string */
286 start = parseBufferIndex;
287 /* find end of string */
288 while (isAlphaNumeric(c)) {
291 length = parseBufferIndex - start;
293 /* copy to null terminated buffer */
294 tempString = (char *)malloc(length + 1);
295 if (tempString == 0) {
296 printf("OSUnserialize: can't alloc temp memory\n");
299 bcopy(&parseBuffer[start], tempString, length);
300 tempString[length] = 0;
301 yylval = (object_t *)tempString;
305 /* parse quoted string */
306 if (c == '"' || c == '\'') {
311 start = parseBufferIndex + 1; // skip quote
312 /* find end of string, line, buffer */
313 while ((c = nextChar()) != quoteChar) {
314 if (c == '\\') c = nextChar();
315 if (c == '\n') lineNumber++;
316 if (c == 0) return SYNTAX_ERROR;
318 length = parseBufferIndex - start;
319 /* skip over trailing quote */
321 /* copy to null terminated buffer */
322 tempString = (char *)malloc(length + 1);
323 if (tempString == 0) {
324 printf("OSUnserialize: can't alloc temp memory\n");
329 for (int from=start; from < parseBufferIndex; from++) {
330 // hack - skip over backslashes
331 if (parseBuffer[from] == '\\') {
335 tempString[to] = parseBuffer[from];
338 tempString[length] = 0;
339 yylval = (object_t *)tempString;
343 /* process numbers */
346 unsigned long long n = 0;
358 n = (n * base + c - '0');
362 while(isHexDigit(c)) {
364 n = (n * base + c - '0');
366 n = (n * base + 0xa + c - 'a');
372 yylval = newObject();
373 yylval->u.offset = n;
378 #define OSDATA_ALLOC_SIZE 4096
382 unsigned char *d, *start, *lastStart;
384 start = lastStart = d = (unsigned char *)malloc(OSDATA_ALLOC_SIZE);
385 c = nextChar(); // skip over '<'
386 while (c != 0 && c != '>') {
388 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
389 if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
397 if (!isHexDigit(c)) break;
401 *d = (0xa + (c - 'a')) << 4;
406 if (!isHexDigit(c)) break;
410 *d |= 0xa + (c - 'a');
414 if ((d - lastStart) >= OSDATA_ALLOC_SIZE) {
415 int oldsize = d - start;
416 start = (unsigned char *)realloc(start, oldsize + OSDATA_ALLOC_SIZE);
417 d = lastStart = start + oldsize;
427 yylval = newObject();
428 yylval->object = start;
429 yylval->size = d - start;
431 (void)nextChar(); // skip over '>'
436 /* return single chars, move pointer to next char */
441 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
442 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
443 // !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
446 int debugUnserializeAllocCount = 0;
453 debugUnserializeAllocCount++;
455 return (object_t *)malloc(sizeof(object_t));
459 freeObject(object_t *o)
462 debugUnserializeAllocCount--;
467 static OSDictionary *tags;
470 rememberObject(int tag, object_t *o)
473 snprintf(key, sizeof(key), "%u", tag);
475 tags->setObject(key, (OSObject *)o);
479 retrieveObject(int tag)
482 snprintf(key, sizeof(key), "%u", tag);
484 return tags->getObject(key);
488 buildOSDictionary(object_t *o)
490 object_t *temp, *last = o;
493 // get count and last object
501 OSDictionary *d = OSDictionary::withCapacity(count);
504 #ifdef metaclass_stuff_worksXXX
505 if (((OSObject *)o->u.key)->metaCast("OSSymbol")) {
506 // XXX the evil frontdoor
507 d->setObject((OSSymbol *)o->u.key, (OSObject *)o->object);
509 // If it isn't a symbol, I hope it's a string!
510 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
513 d->setObject((OSString *)o->u.key, (OSObject *)o->object);
515 ((OSObject *)o->object)->release();
516 ((OSObject *)o->u.key)->release();
525 buildOSArray(object_t *o)
527 object_t *temp, *last = o;
530 // get count and last object
538 OSArray *a = OSArray::withCapacity(count);
541 a->setObject((OSObject *)o->object);
542 ((OSObject *)o->object)->release();
551 buildOSSet(object_t *o)
553 OSArray *a = (OSArray *)buildOSArray(o);
554 OSSet *s = OSSet::withArray(a, a->getCapacity());
561 buildOSString(object_t *o)
563 OSString *s = OSString::withCString((char *)o);
571 buildOSData(object_t *o)
576 d = OSData::withBytes(o->object, o->size);
578 d = OSData::withCapacity(0);
586 buildOSOffset(object_t *o)
588 OSNumber *off = OSNumber::withNumber(o->u.offset, o->size);
594 buildOSBoolean(object_t *o)
596 OSBoolean *b = OSBoolean::withBoolean((bool)o);
601 #include <kern/locks.h>
604 static lck_mtx_t *lock = 0;
605 extern lck_grp_t *IOLockGroup;
608 OSUnserialize(const char *buffer, OSString **errorString)
613 lock = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
621 debugUnserializeAllocCount = 0;
623 yyerror_message[0] = 0; //just in case
624 parseBuffer = buffer;
625 parseBufferIndex = 0;
626 tags = OSDictionary::withCapacity(128);
627 if (yyparse() == 0) {
628 object = parsedObject;
629 if (errorString) *errorString = 0;
633 *errorString = OSString::withCString(yyerror_message);
638 if (debugUnserializeAllocCount) {
639 printf("OSUnserialize: allocation check failed, count = %d.\n",
640 debugUnserializeAllocCount);
643 lck_mtx_unlock(lock);
654 // DO NOT EDIT OSUnserialize.cpp!