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