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