1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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. 11 * 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 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 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// 660

