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