1/* 2 * Copyright (c) 1999-2009 Apple 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/* 30 * HISTORY 31 * 32 * OSUnserializeXML.y created by rsulack on Tue Oct 12 1999 33 */ 34 35// parser for unserializing OSContainer objects serialized to XML 36// 37// to build : 38// bison -p OSUnserializeXML OSUnserializeXML.y 39// head -50 OSUnserializeXML.y > OSUnserializeXML.cpp 40// sed -e "s/#include <stdio.h>//" < OSUnserializeXML.tab.c >> OSUnserializeXML.cpp 41// 42// when changing code check in both OSUnserializeXML.y and OSUnserializeXML.cpp 43// 44// 45// 46// 47// 48// DO NOT EDIT OSUnserializeXML.cpp! 49// 50// this means you! 51// 52// 53// 54// 55// 56// 57 58 59%pure_parser 60 61%{ 62#include <string.h> 63#include <libkern/c++/OSMetaClass.h> 64#include <libkern/c++/OSContainers.h> 65#include <libkern/c++/OSLib.h> 66 67#define YYSTYPE object_t * 68#define YYPARSE_PARAM state 69#define YYLEX_PARAM (parser_state_t *)state 70 71// this is the internal struct used to hold objects on parser stack 72// it represents objects both before and after they have been created 73typedef struct object { 74 struct object *next; 75 struct object *free; 76 struct object *elements; 77 OSObject *object; 78 OSString *key; // for dictionary 79 int size; 80 void *data; // for data 81 char *string; // for string & symbol 82 long long number; // for number 83 int idref; 84} object_t; 85 86// this code is reentrant, this structure contains all 87// state information for the parsing of a single buffer 88typedef struct parser_state { 89 const char *parseBuffer; // start of text to be parsed 90 int parseBufferIndex; // current index into text 91 int lineNumber; // current line number 92 object_t *objects; // internal objects in use 93 object_t *freeObjects; // internal objects that are free 94 OSDictionary *tags; // used to remember "ID" tags 95 OSString **errorString; // parse error with line 96 OSObject *parsedObject; // resultant object of parsed text 97} parser_state_t; 98 99#define STATE ((parser_state_t *)state) 100 101#undef yyerror 102#define yyerror(s) OSUnserializeerror(STATE, (s)) 103static int OSUnserializeerror(parser_state_t *state, const char *s); 104 105static int yylex(YYSTYPE *lvalp, parser_state_t *state); 106 107static object_t *newObject(parser_state_t *state); 108static void freeObject(parser_state_t *state, object_t *o); 109static void rememberObject(parser_state_t *state, int tag, OSObject *o); 110static object_t *retrieveObject(parser_state_t *state, int tag); 111static void cleanupObjects(parser_state_t *state); 112 113static object_t *buildDictionary(parser_state_t *state, object_t *o); 114static object_t *buildArray(parser_state_t *state, object_t *o); 115static object_t *buildSet(parser_state_t *state, object_t *o); 116static object_t *buildString(parser_state_t *state, object_t *o); 117static object_t *buildData(parser_state_t *state, object_t *o); 118static object_t *buildNumber(parser_state_t *state, object_t *o); 119static object_t *buildBoolean(parser_state_t *state, object_t *o); 120 121extern "C" { 122extern void *kern_os_malloc(size_t size); 123extern void *kern_os_realloc(void * addr, size_t size); 124extern void kern_os_free(void * addr); 125 126} /* extern "C" */ 127 128#define malloc(s) kern_os_malloc(s) 129#define realloc(a, s) kern_os_realloc(a, s) 130#define free(a) kern_os_free((void *)a) 131 132%} 133%token ARRAY 134%token BOOLEAN 135%token DATA 136%token DICTIONARY 137%token IDREF 138%token KEY 139%token NUMBER 140%token SET 141%token STRING 142%token SYNTAX_ERROR 143%% /* Grammar rules and actions follow */ 144 145input: /* empty */ { yyerror("unexpected end of buffer"); 146 YYERROR; 147 } 148 | object { STATE->parsedObject = $1->object; 149 $1->object = 0; 150 freeObject(STATE, $1); 151 YYACCEPT; 152 } 153 | SYNTAX_ERROR { yyerror("syntax error"); 154 YYERROR; 155 } 156 ; 157 158object: dict { $$ = buildDictionary(STATE, $1); } 159 | array { $$ = buildArray(STATE, $1); } 160 | set { $$ = buildSet(STATE, $1); } 161 | string { $$ = buildString(STATE, $1); } 162 | data { $$ = buildData(STATE, $1); } 163 | number { $$ = buildNumber(STATE, $1); } 164 | boolean { $$ = buildBoolean(STATE, $1); } 165 | idref { $$ = retrieveObject(STATE, $1->idref); 166 if ($$) { 167 $$->object->retain(); 168 } else { 169 yyerror("forward reference detected"); 170 YYERROR; 171 } 172 freeObject(STATE, $1); 173 } 174 ; 175 176//------------------------------------------------------------------------------ 177 178dict: '{' '}' { $$ = $1; 179 $$->elements = NULL; 180 } 181 | '{' pairs '}' { $$ = $1; 182 $$->elements = $2; 183 } 184 | DICTIONARY 185 ; 186 187pairs: pair 188 | pairs pair { $$ = $2; 189 $$->next = $1; 190 } 191 ; 192 193pair: key object { $$ = $1; 194 $$->key = (OSString *)$$->object; 195 $$->object = $2->object; 196 $$->next = NULL; 197 $2->object = 0; 198 freeObject(STATE, $2); 199 } 200 ; 201 202key: KEY { $$ = buildString(STATE, $1); } 203 ; 204 205//------------------------------------------------------------------------------ 206 207array: '(' ')' { $$ = $1; 208 $$->elements = NULL; 209 } 210 | '(' elements ')' { $$ = $1; 211 $$->elements = $2; 212 } 213 | ARRAY 214 ; 215 216set: '[' ']' { $$ = $1; 217 $$->elements = NULL; 218 } 219 | '[' elements ']' { $$ = $1; 220 $$->elements = $2; 221 } 222 | SET 223 ; 224 225elements: object { $$ = $1; 226 $$->next = NULL; 227 } 228 | elements object { $$ = $2; 229 $$->next = $1; 230 } 231 ; 232 233//------------------------------------------------------------------------------ 234 235boolean: BOOLEAN 236 ; 237 238data: DATA 239 ; 240 241idref: IDREF 242 ; 243 244number: NUMBER 245 ; 246 247string: STRING 248 ; 249 250%% 251 252int 253OSUnserializeerror(parser_state_t * state, const char *s) /* Called by yyparse on errors */ 254{ 255 if (state->errorString) { 256 char tempString[128]; 257 snprintf(tempString, 128, "OSUnserializeXML: %s near line %d\n", s, state->lineNumber); 258 *(state->errorString) = OSString::withCString(tempString); 259 } 260 261 return 0; 262} 263 264#define TAG_MAX_LENGTH 32 265#define TAG_MAX_ATTRIBUTES 32 266#define TAG_BAD 0 267#define TAG_START 1 268#define TAG_END 2 269#define TAG_EMPTY 3 270#define TAG_IGNORE 4 271 272#define currentChar() (state->parseBuffer[state->parseBufferIndex]) 273#define nextChar() (state->parseBuffer[++state->parseBufferIndex]) 274#define prevChar() (state->parseBuffer[state->parseBufferIndex - 1]) 275 276#define isSpace(c) ((c) == ' ' || (c) == '\t') 277#define isAlpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) 278#define isDigit(c) ((c) >= '0' && (c) <= '9') 279#define isAlphaDigit(c) ((c) >= 'a' && (c) <= 'f') 280#define isHexDigit(c) (isDigit(c) || isAlphaDigit(c)) 281#define isAlphaNumeric(c) (isAlpha(c) || isDigit(c) || ((c) == '-')) 282 283static int 284getTag(parser_state_t *state, 285 char tag[TAG_MAX_LENGTH], 286 int *attributeCount, 287 char attributes[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH], 288 char values[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH] ) 289{ 290 int length = 0; 291 int c = currentChar(); 292 int tagType = TAG_START; 293 294 *attributeCount = 0; 295 296 if (c != '<') return TAG_BAD; 297 c = nextChar(); // skip '<' 298 299 300 // <!TAG declarations > 301 // <!-- comments --> 302 if (c == '!') { 303 c = nextChar(); 304 bool isComment = (c == '-') && ((c = nextChar()) != 0) && (c == '-'); 305 if (!isComment && !isAlpha(c)) return TAG_BAD; // <!1, <!-A, <!eos 306 307 while (c && (c = nextChar()) != 0) { 308 if (c == '\n') state->lineNumber++; 309 if (isComment) { 310 if (c != '-') continue; 311 c = nextChar(); 312 if (c != '-') continue; 313 c = nextChar(); 314 } 315 if (c == '>') { 316 (void)nextChar(); 317 return TAG_IGNORE; 318 } 319 if (isComment) break; 320 } 321 return TAG_BAD; 322 } 323 324 else 325 326 // <? Processing Instructions ?> 327 if (c == '?') { 328 while ((c = nextChar()) != 0) { 329 if (c == '\n') state->lineNumber++; 330 if (c != '?') continue; 331 c = nextChar(); 332 if (c == '>') { 333 (void)nextChar(); 334 return TAG_IGNORE; 335 } 336 } 337 return TAG_BAD; 338 } 339 340 else 341 342 // </ end tag > 343 if (c == '/') { 344 c = nextChar(); // skip '/' 345 tagType = TAG_END; 346 } 347 if (!isAlpha(c)) return TAG_BAD; 348 349 /* find end of tag while copying it */ 350 while (isAlphaNumeric(c)) { 351 tag[length++] = c; 352 c = nextChar(); 353 if (length >= (TAG_MAX_LENGTH - 1)) return TAG_BAD; 354 } 355 356 tag[length] = 0; 357 358// printf("tag %s, type %d\n", tag, tagType); 359 360 // look for attributes of the form attribute = "value" ... 361 while ((c != '>') && (c != '/')) { 362 while (isSpace(c)) c = nextChar(); 363 364 length = 0; 365 while (isAlphaNumeric(c)) { 366 attributes[*attributeCount][length++] = c; 367 if (length >= (TAG_MAX_LENGTH - 1)) return TAG_BAD; 368 c = nextChar(); 369 } 370 attributes[*attributeCount][length] = 0; 371 372 while (isSpace(c)) c = nextChar(); 373 374 if (c != '=') return TAG_BAD; 375 c = nextChar(); 376 377 while (isSpace(c)) c = nextChar(); 378 379 if (c != '"') return TAG_BAD; 380 c = nextChar(); 381 length = 0; 382 while (c != '"') { 383 values[*attributeCount][length++] = c; 384 if (length >= (TAG_MAX_LENGTH - 1)) return TAG_BAD; 385 c = nextChar(); 386 } 387 values[*attributeCount][length] = 0; 388 389 c = nextChar(); // skip closing quote 390 391// printf(" attribute '%s' = '%s', nextchar = '%c'\n", 392// attributes[*attributeCount], values[*attributeCount], c); 393 394 (*attributeCount)++; 395 if (*attributeCount >= TAG_MAX_ATTRIBUTES) return TAG_BAD; 396 } 397 398 if (c == '/') { 399 c = nextChar(); // skip '/' 400 tagType = TAG_EMPTY; 401 } 402 if (c != '>') return TAG_BAD; 403 c = nextChar(); // skip '>' 404 405 return tagType; 406} 407 408static char * 409getString(parser_state_t *state) 410{ 411 int c = currentChar(); 412 int start, length, i, j; 413 char * tempString; 414 415 start = state->parseBufferIndex; 416 /* find end of string */ 417 418 while (c != 0) { 419 if (c == '\n') state->lineNumber++; 420 if (c == '<') { 421 break; 422 } 423 c = nextChar(); 424 } 425 426 if (c != '<') return 0; 427 428 length = state->parseBufferIndex - start; 429 430 /* copy to null terminated buffer */ 431 tempString = (char *)malloc(length + 1); 432 if (tempString == 0) { 433 printf("OSUnserializeXML: can't alloc temp memory\n"); 434 goto error; 435 } 436 437 // copy out string in tempString 438 // "&" -> '&', "<" -> '<', ">" -> '>' 439 440 i = j = 0; 441 while (i < length) { 442 c = state->parseBuffer[start + i++]; 443 if (c != '&') { 444 tempString[j++] = c; 445 } else { 446 if ((i+3) > length) goto error; 447 c = state->parseBuffer[start + i++]; 448 if (c == 'l') { 449 if (state->parseBuffer[start + i++] != 't') goto error; 450 if (state->parseBuffer[start + i++] != ';') goto error; 451 tempString[j++] = '<'; 452 continue; 453 } 454 if (c == 'g') { 455 if (state->parseBuffer[start + i++] != 't') goto error; 456 if (state->parseBuffer[start + i++] != ';') goto error; 457 tempString[j++] = '>'; 458 continue; 459 } 460 if ((i+3) > length) goto error; 461 if (c == 'a') { 462 if (state->parseBuffer[start + i++] != 'm') goto error; 463 if (state->parseBuffer[start + i++] != 'p') goto error; 464 if (state->parseBuffer[start + i++] != ';') goto error; 465 tempString[j++] = '&'; 466 continue; 467 } 468 goto error; 469 } 470 } 471 tempString[j] = 0; 472 473// printf("string %s\n", tempString); 474 475 return tempString; 476 477error: 478 if (tempString) free(tempString); 479 return 0; 480} 481 482static long long 483getNumber(parser_state_t *state) 484{ 485 unsigned long long n = 0; 486 int base = 10; 487 bool negate = false; 488 int c = currentChar(); 489 490 if (c == '0') { 491 c = nextChar(); 492 if (c == 'x') { 493 base = 16; 494 c = nextChar(); 495 } 496 } 497 if (base == 10) { 498 if (c == '-') { 499 negate = true; 500 c = nextChar(); 501 } 502 while(isDigit(c)) { 503 n = (n * base + c - '0'); 504 c = nextChar(); 505 } 506 if (negate) { 507 n = (unsigned long long)((long long)n * (long long)-1); 508 } 509 } else { 510 while(isHexDigit(c)) { 511 if (isDigit(c)) { 512 n = (n * base + c - '0'); 513 } else { 514 n = (n * base + 0xa + c - 'a'); 515 } 516 c = nextChar(); 517 } 518 } 519// printf("number 0x%x\n", (unsigned long)n); 520 return n; 521} 522 523// taken from CFXMLParsing/CFPropertyList.c 524 525static const signed char __CFPLDataDecodeTable[128] = { 526 /* 000 */ -1, -1, -1, -1, -1, -1, -1, -1, 527 /* 010 */ -1, -1, -1, -1, -1, -1, -1, -1, 528 /* 020 */ -1, -1, -1, -1, -1, -1, -1, -1, 529 /* 030 */ -1, -1, -1, -1, -1, -1, -1, -1, 530 /* ' ' */ -1, -1, -1, -1, -1, -1, -1, -1, 531 /* '(' */ -1, -1, -1, 62, -1, -1, -1, 63, 532 /* '0' */ 52, 53, 54, 55, 56, 57, 58, 59, 533 /* '8' */ 60, 61, -1, -1, -1, 0, -1, -1, 534 /* '@' */ -1, 0, 1, 2, 3, 4, 5, 6, 535 /* 'H' */ 7, 8, 9, 10, 11, 12, 13, 14, 536 /* 'P' */ 15, 16, 17, 18, 19, 20, 21, 22, 537 /* 'X' */ 23, 24, 25, -1, -1, -1, -1, -1, 538 /* '`' */ -1, 26, 27, 28, 29, 30, 31, 32, 539 /* 'h' */ 33, 34, 35, 36, 37, 38, 39, 40, 540 /* 'p' */ 41, 42, 43, 44, 45, 46, 47, 48, 541 /* 'x' */ 49, 50, 51, -1, -1, -1, -1, -1 542}; 543 544#define DATA_ALLOC_SIZE 4096 545 546static void * 547getCFEncodedData(parser_state_t *state, unsigned int *size) 548{ 549 int numeq = 0, acc = 0, cntr = 0; 550 int tmpbufpos = 0, tmpbuflen = 0; 551 unsigned char *tmpbuf = (unsigned char *)malloc(DATA_ALLOC_SIZE); 552 553 int c = currentChar(); 554 *size = 0; 555 556 while (c != '<') { 557 c &= 0x7f; 558 if (c == 0) { 559 free(tmpbuf); 560 return 0; 561 } 562 if (c == '=') numeq++; else numeq = 0; 563 if (c == '\n') state->lineNumber++; 564 if (__CFPLDataDecodeTable[c] < 0) { 565 c = nextChar(); 566 continue; 567 } 568 cntr++; 569 acc <<= 6; 570 acc += __CFPLDataDecodeTable[c]; 571 if (0 == (cntr & 0x3)) { 572 if (tmpbuflen <= tmpbufpos + 2) { 573 tmpbuflen += DATA_ALLOC_SIZE; 574 tmpbuf = (unsigned char *)realloc(tmpbuf, tmpbuflen); 575 } 576 tmpbuf[tmpbufpos++] = (acc >> 16) & 0xff; 577 if (numeq < 2) 578 tmpbuf[tmpbufpos++] = (acc >> 8) & 0xff; 579 if (numeq < 1) 580 tmpbuf[tmpbufpos++] = acc & 0xff; 581 } 582 c = nextChar(); 583 } 584 *size = tmpbufpos; 585 if (*size == 0) { 586 free(tmpbuf); 587 return 0; 588 } 589 return tmpbuf; 590} 591 592static void * 593getHexData(parser_state_t *state, unsigned int *size) 594{ 595 int c; 596 unsigned char *d, *start, *lastStart; 597 598 start = lastStart = d = (unsigned char *)malloc(DATA_ALLOC_SIZE); 599 c = currentChar(); 600 601 while (c != '<') { 602 603 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {}; 604 if (c == '\n') { 605 state->lineNumber++; 606 c = nextChar(); 607 continue; 608 } 609 610 // get high nibble 611 if (isDigit(c)) { 612 *d = (c - '0') << 4; 613 } else if (isAlphaDigit(c)) { 614 *d = (0xa + (c - 'a')) << 4; 615 } else { 616 goto error; 617 } 618 619 // get low nibble 620 c = nextChar(); 621 if (isDigit(c)) { 622 *d |= c - '0'; 623 } else if (isAlphaDigit(c)) { 624 *d |= 0xa + (c - 'a'); 625 } else { 626 goto error; 627 } 628 629 d++; 630 if ((d - lastStart) >= DATA_ALLOC_SIZE) { 631 int oldsize = d - start; 632 start = (unsigned char *)realloc(start, oldsize + DATA_ALLOC_SIZE); 633 d = lastStart = start + oldsize; 634 } 635 c = nextChar(); 636 } 637 638 *size = d - start; 639 return start; 640 641 error: 642 643 *size = 0; 644 free(start); 645 return 0; 646} 647 648static int 649yylex(YYSTYPE *lvalp, parser_state_t *state) 650{ 651 int c, i; 652 int tagType; 653 char tag[TAG_MAX_LENGTH]; 654 int attributeCount; 655 char attributes[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH]; 656 char values[TAG_MAX_ATTRIBUTES][TAG_MAX_LENGTH]; 657 object_t *object; 658 659 top: 660 c = currentChar(); 661 662 /* skip white space */ 663 if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {}; 664 665 /* keep track of line number, don't return \n's */ 666 if (c == '\n') { 667 STATE->lineNumber++; 668 (void)nextChar(); 669 goto top; 670 } 671 672 // end of the buffer? 673 if (!c) return 0; 674 675 tagType = getTag(STATE, tag, &attributeCount, attributes, values); 676 if (tagType == TAG_BAD) return SYNTAX_ERROR; 677 if (tagType == TAG_IGNORE) goto top; 678 679 // handle allocation and check for "ID" and "IDREF" tags up front 680 *lvalp = object = newObject(STATE); 681 object->idref = -1; 682 for (i=0; i < attributeCount; i++) { 683 if (attributes[i][0] == 'I' && attributes[i][1] == 'D') { 684 // check for idref's, note: we ignore the tag, for 685 // this to work correctly, all idrefs must be unique 686 // across the whole serialization 687 if (attributes[i][2] == 'R' && attributes[i][3] == 'E' && 688 attributes[i][4] == 'F' && !attributes[i][5]) { 689 if (tagType != TAG_EMPTY) return SYNTAX_ERROR; 690 object->idref = strtol(values[i], NULL, 0); 691 return IDREF; 692 } 693 // check for id's 694 if (!attributes[i][2]) { 695 object->idref = strtol(values[i], NULL, 0); 696 } else { 697 return SYNTAX_ERROR; 698 } 699 } 700 } 701 702 switch (*tag) { 703 case 'a': 704 if (!strcmp(tag, "array")) { 705 if (tagType == TAG_EMPTY) { 706 object->elements = NULL; 707 return ARRAY; 708 } 709 return (tagType == TAG_START) ? '(' : ')'; 710 } 711 break; 712 case 'd': 713 if (!strcmp(tag, "dict")) { 714 if (tagType == TAG_EMPTY) { 715 object->elements = NULL; 716 return DICTIONARY; 717 } 718 return (tagType == TAG_START) ? '{' : '}'; 719 } 720 if (!strcmp(tag, "data")) { 721 unsigned int size; 722 if (tagType == TAG_EMPTY) { 723 object->data = NULL; 724 object->size = 0; 725 return DATA; 726 } 727 728 bool isHexFormat = false; 729 for (i=0; i < attributeCount; i++) { 730 if (!strcmp(attributes[i], "format") && !strcmp(values[i], "hex")) { 731 isHexFormat = true; 732 break; 733 } 734 } 735 // CF encoded is the default form 736 if (isHexFormat) { 737 object->data = getHexData(STATE, &size); 738 } else { 739 object->data = getCFEncodedData(STATE, &size); 740 } 741 object->size = size; 742 if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END) || strcmp(tag, "data")) { 743 return SYNTAX_ERROR; 744 } 745 return DATA; 746 } 747 break; 748 case 'f': 749 if (!strcmp(tag, "false")) { 750 if (tagType == TAG_EMPTY) { 751 object->number = 0; 752 return BOOLEAN; 753 } 754 } 755 break; 756 case 'i': 757 if (!strcmp(tag, "integer")) { 758 object->size = 64; // default 759 for (i=0; i < attributeCount; i++) { 760 if (!strcmp(attributes[i], "size")) { 761 object->size = strtoul(values[i], NULL, 0); 762 } 763 } 764 if (tagType == TAG_EMPTY) { 765 object->number = 0; 766 return NUMBER; 767 } 768 object->number = getNumber(STATE); 769 if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END) || strcmp(tag, "integer")) { 770 return SYNTAX_ERROR; 771 } 772 return NUMBER; 773 } 774 break; 775 case 'k': 776 if (!strcmp(tag, "key")) { 777 if (tagType == TAG_EMPTY) return SYNTAX_ERROR; 778 object->string = getString(STATE); 779 if (!object->string) { 780 return SYNTAX_ERROR; 781 } 782 if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END) 783 || strcmp(tag, "key")) { 784 return SYNTAX_ERROR; 785 } 786 return KEY; 787 } 788 break; 789 case 'p': 790 if (!strcmp(tag, "plist")) { 791 freeObject(STATE, object); 792 goto top; 793 } 794 break; 795 case 's': 796 if (!strcmp(tag, "string")) { 797 if (tagType == TAG_EMPTY) { 798 object->string = (char *)malloc(1); 799 object->string[0] = 0; 800 return STRING; 801 } 802 object->string = getString(STATE); 803 if (!object->string) { 804 return SYNTAX_ERROR; 805 } 806 if ((getTag(STATE, tag, &attributeCount, attributes, values) != TAG_END) 807 || strcmp(tag, "string")) { 808 return SYNTAX_ERROR; 809 } 810 return STRING; 811 } 812 if (!strcmp(tag, "set")) { 813 if (tagType == TAG_EMPTY) { 814 object->elements = NULL; 815 return SET;; 816 } 817 if (tagType == TAG_START) { 818 return '['; 819 } else { 820 return ']'; 821 } 822 } 823 break; 824 case 't': 825 if (!strcmp(tag, "true")) { 826 if (tagType == TAG_EMPTY) { 827 object->number = 1; 828 return BOOLEAN; 829 } 830 } 831 break; 832 } 833 834 return SYNTAX_ERROR; 835} 836 837// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 838// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 839// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 840 841// "java" like allocation, if this code hits a syntax error in the 842// the middle of the parsed string we just bail with pointers hanging 843// all over place, this code helps keeps it all together 844 845//static int object_count = 0; 846 847object_t * 848newObject(parser_state_t *state) 849{ 850 object_t *o; 851 852 if (state->freeObjects) { 853 o = state->freeObjects; 854 state->freeObjects = state->freeObjects->next; 855 } else { 856 o = (object_t *)malloc(sizeof(object_t)); 857// object_count++; 858 bzero(o, sizeof(object_t)); 859 o->free = state->objects; 860 state->objects = o; 861 } 862 863 return o; 864} 865 866void 867freeObject(parser_state_t * state, object_t *o) 868{ 869 o->next = state->freeObjects; 870 state->freeObjects = o; 871} 872 873void 874cleanupObjects(parser_state_t *state) 875{ 876 object_t *t, *o = state->objects; 877 878 while (o) { 879 if (o->object) { 880// printf("OSUnserializeXML: releasing object o=%x object=%x\n", (int)o, (int)o->object); 881 o->object->release(); 882 } 883 if (o->data) { 884// printf("OSUnserializeXML: freeing object o=%x data=%x\n", (int)o, (int)o->data); 885 free(o->data); 886 } 887 if (o->key) { 888// printf("OSUnserializeXML: releasing object o=%x key=%x\n", (int)o, (int)o->key); 889 o->key->release(); 890 } 891 if (o->string) { 892// printf("OSUnserializeXML: freeing object o=%x string=%x\n", (int)o, (int)o->string); 893 free(o->string); 894 } 895 896 t = o; 897 o = o->free; 898 free(t); 899// object_count--; 900 } 901// printf("object_count = %d\n", object_count); 902} 903 904// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 905// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 906// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 907 908static void 909rememberObject(parser_state_t *state, int tag, OSObject *o) 910{ 911 char key[16]; 912 snprintf(key, 16, "%u", tag); 913 914// printf("remember key %s\n", key); 915 916 state->tags->setObject(key, o); 917} 918 919static object_t * 920retrieveObject(parser_state_t *state, int tag) 921{ 922 OSObject *ref; 923 object_t *o; 924 char key[16]; 925 snprintf(key, 16, "%u", tag); 926 927// printf("retrieve key '%s'\n", key); 928 929 ref = state->tags->getObject(key); 930 if (!ref) return 0; 931 932 o = newObject(state); 933 o->object = ref; 934 return o; 935} 936 937// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 938// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 939// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!# 940 941object_t * 942buildDictionary(parser_state_t *state, object_t * header) 943{ 944 object_t *o, *t; 945 int count = 0; 946 OSDictionary *dict; 947 948 // get count and reverse order 949 o = header->elements; 950 header->elements = 0; 951 while (o) { 952 count++; 953 t = o; 954 o = o->next; 955 956 t->next = header->elements; 957 header->elements = t; 958 } 959 960 dict = OSDictionary::withCapacity(count); 961 if (header->idref >= 0) rememberObject(state, header->idref, dict); 962 963 o = header->elements; 964 while (o) { 965 dict->setObject(o->key, o->object); 966 967 o->key->release(); 968 o->object->release(); 969 o->key = 0; 970 o->object = 0; 971 972 t = o; 973 o = o->next; 974 freeObject(state, t); 975 } 976 o = header; 977 o->object = dict; 978 return o; 979}; 980 981object_t * 982buildArray(parser_state_t *state, object_t * header) 983{ 984 object_t *o, *t; 985 int count = 0; 986 OSArray *array; 987 988 // get count and reverse order 989 o = header->elements; 990 header->elements = 0; 991 while (o) { 992 count++; 993 t = o; 994 o = o->next; 995 996 t->next = header->elements; 997 header->elements = t; 998 } 999 1000 array = OSArray::withCapacity(count); 1001 if (header->idref >= 0) rememberObject(state, header->idref, array); 1002 1003 o = header->elements; 1004 while (o) { 1005 array->setObject(o->object); 1006 1007 o->object->release(); 1008 o->object = 0; 1009 1010 t = o; 1011 o = o->next; 1012 freeObject(state, t); 1013 } 1014 o = header; 1015 o->object = array; 1016 return o; 1017}; 1018 1019object_t * 1020buildSet(parser_state_t *state, object_t *header) 1021{ 1022 object_t *o = buildArray(state, header); 1023 1024 OSArray *array = (OSArray *)o->object; 1025 OSSet *set = OSSet::withArray(array, array->getCapacity()); 1026 1027 // write over the reference created in buildArray 1028 if (header->idref >= 0) rememberObject(state, header->idref, set); 1029 1030 array->release(); 1031 o->object = set; 1032 return o; 1033}; 1034 1035object_t * 1036buildString(parser_state_t *state, object_t *o) 1037{ 1038 OSString *string; 1039 1040 string = OSString::withCString(o->string); 1041 if (o->idref >= 0) rememberObject(state, o->idref, string); 1042 1043 free(o->string); 1044 o->string = 0; 1045 o->object = string; 1046 1047 return o; 1048}; 1049 1050object_t * 1051buildData(parser_state_t *state, object_t *o) 1052{ 1053 OSData *data; 1054 1055 if (o->size) { 1056 data = OSData::withBytes(o->data, o->size); 1057 } else { 1058 data = OSData::withCapacity(0); 1059 } 1060 if (o->idref >= 0) rememberObject(state, o->idref, data); 1061 1062 if (o->size) free(o->data); 1063 o->data = 0; 1064 o->object = data; 1065 return o; 1066}; 1067 1068object_t * 1069buildNumber(parser_state_t *state, object_t *o) 1070{ 1071 OSNumber *number = OSNumber::withNumber(o->number, o->size); 1072 1073 if (o->idref >= 0) rememberObject(state, o->idref, number); 1074 1075 o->object = number; 1076 return o; 1077}; 1078 1079object_t * 1080buildBoolean(parser_state_t *state __unused, object_t *o) 1081{ 1082 o->object = ((o->number == 0) ? kOSBooleanFalse : kOSBooleanTrue); 1083 o->object->retain(); 1084 return o; 1085}; 1086 1087OSObject* 1088OSUnserializeXML(const char *buffer, OSString **errorString) 1089{ 1090 OSObject *object; 1091 parser_state_t *state = (parser_state_t *)malloc(sizeof(parser_state_t)); 1092 1093 if ((!state) || (!buffer)) return 0; 1094 1095 // just in case 1096 if (errorString) *errorString = NULL; 1097 1098 state->parseBuffer = buffer; 1099 state->parseBufferIndex = 0; 1100 state->lineNumber = 1; 1101 state->objects = 0; 1102 state->freeObjects = 0; 1103 state->tags = OSDictionary::withCapacity(128); 1104 state->errorString = errorString; 1105 state->parsedObject = 0; 1106 1107 (void)yyparse((void *)state); 1108 1109 object = state->parsedObject; 1110 1111 cleanupObjects(state); 1112 state->tags->release(); 1113 free(state); 1114 1115 return object; 1116} 1117 1118 1119// 1120// 1121// 1122// 1123// 1124// DO NOT EDIT OSUnserializeXML.cpp! 1125// 1126// this means you! 1127// 1128// 1129// 1130// 1131// 1132