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