mirror of
https://github.com/darlinghq/darling-xnu.git
synced 2024-11-23 04:29:53 +00:00
710 lines
15 KiB
Plaintext
710 lines
15 KiB
Plaintext
/*
|
|
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
|
|
*
|
|
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. The rights granted to you under the License
|
|
* may not be used to create, or enable the creation or redistribution of,
|
|
* unlawful or unlicensed copies of an Apple operating system, or to
|
|
* circumvent, violate, or enable the circumvention or violation of, any
|
|
* terms of an Apple operating system software license agreement.
|
|
*
|
|
* Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
|
|
*/
|
|
|
|
/* OSUnserialize.y created by rsulack on Nov 21 1998 */
|
|
|
|
// "classic" parser for unserializing OSContainer objects
|
|
//
|
|
// XXX - this code should really be removed!
|
|
// - the XML format is now prefered
|
|
// - this code leaks on syntax errors, the XML doesn't
|
|
// - "classic" looks, reads, ... much better than XML :-(
|
|
// - well except the XML is more efficent on OSData
|
|
//
|
|
//
|
|
// to build :
|
|
// bison -p OSUnserialize OSUnserialize.y
|
|
// head -50 OSUnserialize.y > OSUnserialize.cpp
|
|
// sed -e "s/stdio.h/stddef.h/" < OSUnserialize.tab.c >> OSUnserialize.cpp
|
|
//
|
|
// when changing code check in both OSUnserialize.y and OSUnserialize.cpp
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// DO NOT EDIT OSUnserialize.tab.cpp!
|
|
//
|
|
// this means you!
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
%{
|
|
#include <libkern/c++/OSMetaClass.h>
|
|
#include <libkern/c++/OSContainers.h>
|
|
#include <libkern/c++/OSLib.h>
|
|
|
|
typedef struct object {
|
|
struct object *next;
|
|
struct object *prev;
|
|
void *object;
|
|
int size; // for data
|
|
union {
|
|
void *key; // for dictionary
|
|
long long offset; // for offset
|
|
} u;
|
|
|
|
} object_t;
|
|
|
|
static int yyerror(const char *s);
|
|
static int yylex();
|
|
|
|
static object_t * newObject();
|
|
static void freeObject(object_t *o);
|
|
|
|
static OSObject *buildOSDictionary(object_t *);
|
|
static OSObject *buildOSArray(object_t *);
|
|
static OSObject *buildOSSet(object_t *);
|
|
static OSObject *buildOSString(object_t *);
|
|
static OSObject *buildOSData(object_t *);
|
|
static OSObject *buildOSOffset(object_t *);
|
|
static OSObject *buildOSBoolean(object_t *o);
|
|
|
|
static void rememberObject(int, object_t *);
|
|
static OSObject *retrieveObject(int);
|
|
|
|
// temp variable to use during parsing
|
|
static object_t *oo;
|
|
|
|
// resultant object of parsed text
|
|
static OSObject *parsedObject;
|
|
|
|
#define YYSTYPE object_t *
|
|
|
|
__BEGIN_DECLS
|
|
#include <kern/kalloc.h>
|
|
__END_DECLS
|
|
|
|
#define malloc(size) malloc_impl(size)
|
|
static inline void *
|
|
malloc_impl(size_t size)
|
|
{
|
|
if (size == 0) {
|
|
return NULL;
|
|
}
|
|
return kheap_alloc_tag_bt(KHEAP_DEFAULT, size,
|
|
(zalloc_flags_t) (Z_WAITOK | Z_ZERO),
|
|
VM_KERN_MEMORY_LIBKERN);
|
|
}
|
|
|
|
#define free(addr) free_impl(addr)
|
|
static inline void
|
|
free_impl(void *addr)
|
|
{
|
|
kheap_free_addr(KHEAP_DEFAULT, addr);
|
|
}
|
|
static inline void
|
|
safe_free(void *addr, size_t size)
|
|
{
|
|
if(addr) {
|
|
assert(size != 0);
|
|
kheap_free(KHEAP_DEFAULT, addr, size);
|
|
}
|
|
}
|
|
|
|
#define realloc(addr, osize, nsize) realloc_impl(addr, osize, nsize)
|
|
static inline void *
|
|
realloc_impl(void *addr, size_t osize, size_t nsize)
|
|
{
|
|
if (!addr) {
|
|
return malloc(nsize);
|
|
}
|
|
if (nsize == osize) {
|
|
return addr;
|
|
}
|
|
void *nmem = malloc(nsize);
|
|
if (!nmem) {
|
|
safe_free(addr, osize);
|
|
return NULL;
|
|
}
|
|
(void)memcpy(nmem, addr, (nsize > osize) ? osize : nsize);
|
|
safe_free(addr, osize);
|
|
|
|
return nmem;
|
|
}
|
|
|
|
%}
|
|
%token NUMBER
|
|
%token STRING
|
|
%token DATA
|
|
%token BOOLEAN
|
|
%token SYNTAX_ERROR
|
|
|
|
%% /* Grammar rules and actions follow */
|
|
|
|
input: /* empty */ { parsedObject = (OSObject *)NULL; YYACCEPT; }
|
|
| object { parsedObject = (OSObject *)$1; YYACCEPT; }
|
|
| SYNTAX_ERROR { yyerror("syntax error"); YYERROR; }
|
|
;
|
|
|
|
object: dict { $$ = (object_t *)buildOSDictionary($1); }
|
|
| array { $$ = (object_t *)buildOSArray($1); }
|
|
| set { $$ = (object_t *)buildOSSet($1); }
|
|
| string { $$ = (object_t *)buildOSString($1); }
|
|
| data { $$ = (object_t *)buildOSData($1); }
|
|
| offset { $$ = (object_t *)buildOSOffset($1); }
|
|
| boolean { $$ = (object_t *)buildOSBoolean($1); }
|
|
| '@' NUMBER { $$ = (object_t *)retrieveObject($2->u.offset);
|
|
if ($$) {
|
|
((OSObject *)$$)->retain();
|
|
} else {
|
|
yyerror("forward reference detected");
|
|
YYERROR;
|
|
}
|
|
freeObject($2);
|
|
}
|
|
| object '@' NUMBER { $$ = $1;
|
|
rememberObject($3->u.offset, $1);
|
|
freeObject($3);
|
|
}
|
|
;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
dict: '{' '}' { $$ = NULL; }
|
|
| '{' pairs '}' { $$ = $2; }
|
|
;
|
|
|
|
pairs: pair
|
|
| pairs pair { $2->next = $1; $1->prev = $2; $$ = $2; }
|
|
;
|
|
|
|
pair: object '=' object ';' { $$ = newObject();
|
|
$$->next = NULL;
|
|
$$->prev = NULL;
|
|
$$->u.key = $1;
|
|
$$->object = $3;
|
|
}
|
|
;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
array: '(' ')' { $$ = NULL; }
|
|
| '(' elements ')' { $$ = $2; }
|
|
;
|
|
|
|
set: '[' ']' { $$ = NULL; }
|
|
| '[' elements ']' { $$ = $2; }
|
|
;
|
|
|
|
elements: object { $$ = newObject();
|
|
$$->object = $1;
|
|
$$->next = NULL;
|
|
$$->prev = NULL;
|
|
}
|
|
| elements ',' object { oo = newObject();
|
|
oo->object = $3;
|
|
oo->next = $1;
|
|
oo->prev = NULL;
|
|
$1->prev = oo;
|
|
$$ = oo;
|
|
}
|
|
;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
offset: NUMBER ':' NUMBER { $$ = $1;
|
|
$$->size = $3->u.offset;
|
|
freeObject($3);
|
|
}
|
|
;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
data: DATA
|
|
;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
string: STRING
|
|
;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
boolean: BOOLEAN
|
|
;
|
|
|
|
%%
|
|
|
|
static int lineNumber = 0;
|
|
static const char *parseBuffer;
|
|
static int parseBufferIndex;
|
|
|
|
#define currentChar() (parseBuffer[parseBufferIndex])
|
|
#define nextChar() (parseBuffer[++parseBufferIndex])
|
|
#define prevChar() (parseBuffer[parseBufferIndex - 1])
|
|
|
|
#define isSpace(c) ((c) == ' ' || (c) == '\t')
|
|
#define isAlpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
|
|
#define isDigit(c) ((c) >= '0' && (c) <= '9')
|
|
#define isAlphaDigit(c) ((c) >= 'a' && (c) <= 'f')
|
|
#define isHexDigit(c) (isDigit(c) || isAlphaDigit(c))
|
|
#define isAlphaNumeric(c) (isAlpha(c) || isDigit(c) || ((c) == '-'))
|
|
|
|
static char yyerror_message[128];
|
|
|
|
int
|
|
yyerror(const char *s) /* Called by yyparse on error */
|
|
{
|
|
snprintf(yyerror_message, sizeof(yyerror_message), "OSUnserialize: %s near line %d\n", s, lineNumber);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yylex()
|
|
{
|
|
int c;
|
|
|
|
if (parseBufferIndex == 0) lineNumber = 1;
|
|
|
|
top:
|
|
c = currentChar();
|
|
|
|
/* skip white space */
|
|
if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
|
|
|
|
/* skip over comments */
|
|
if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
|
|
|
|
/* keep track of line number, don't return \n's */
|
|
if (c == '\n') {
|
|
lineNumber++;
|
|
(void)nextChar();
|
|
goto top;
|
|
}
|
|
|
|
/* parse boolean */
|
|
if (c == '.') {
|
|
bool boolean = false;
|
|
if (nextChar() == 't') {
|
|
if (nextChar() != 'r') return SYNTAX_ERROR;
|
|
if (nextChar() != 'u') return SYNTAX_ERROR;
|
|
if (nextChar() != 'e') return SYNTAX_ERROR;
|
|
boolean = true;
|
|
} else {
|
|
if (currentChar() != 'f') return SYNTAX_ERROR;
|
|
if (nextChar() != 'a') return SYNTAX_ERROR;
|
|
if (nextChar() != 'l') return SYNTAX_ERROR;
|
|
if (nextChar() != 's') return SYNTAX_ERROR;
|
|
if (nextChar() != 'e') return SYNTAX_ERROR;
|
|
}
|
|
if (nextChar() != '.') return SYNTAX_ERROR;
|
|
/* skip over dot */
|
|
(void)nextChar();
|
|
|
|
yylval = (object_t *)boolean;
|
|
return BOOLEAN;
|
|
}
|
|
|
|
/* parse unquoted string */
|
|
if (isAlpha(c)) {
|
|
int start, length;
|
|
char * tempString;
|
|
|
|
start = parseBufferIndex;
|
|
/* find end of string */
|
|
while (isAlphaNumeric(c)) {
|
|
c = nextChar();
|
|
}
|
|
length = parseBufferIndex - start;
|
|
|
|
/* copy to null terminated buffer */
|
|
tempString = (char *)malloc(length + 1);
|
|
if (tempString == NULL) {
|
|
printf("OSUnserialize: can't alloc temp memory\n");
|
|
return 0;
|
|
}
|
|
bcopy(&parseBuffer[start], tempString, length);
|
|
tempString[length] = 0;
|
|
yylval = (object_t *)tempString;
|
|
return STRING;
|
|
}
|
|
|
|
/* parse quoted string */
|
|
if (c == '"' || c == '\'') {
|
|
int start, length;
|
|
char * tempString;
|
|
char quoteChar = c;
|
|
|
|
start = parseBufferIndex + 1; // skip quote
|
|
/* find end of string, line, buffer */
|
|
while ((c = nextChar()) != quoteChar) {
|
|
if (c == '\\') c = nextChar();
|
|
if (c == '\n') lineNumber++;
|
|
if (c == 0) return SYNTAX_ERROR;
|
|
}
|
|
length = parseBufferIndex - start;
|
|
/* skip over trailing quote */
|
|
(void)nextChar();
|
|
/* copy to null terminated buffer */
|
|
tempString = (char *)malloc(length + 1);
|
|
if (tempString == NULL) {
|
|
printf("OSUnserialize: can't alloc temp memory\n");
|
|
return 0;
|
|
}
|
|
|
|
int to = 0;
|
|
for (int from=start; from < parseBufferIndex; from++) {
|
|
// hack - skip over backslashes
|
|
if (parseBuffer[from] == '\\') {
|
|
length--;
|
|
continue;
|
|
}
|
|
tempString[to] = parseBuffer[from];
|
|
to++;
|
|
}
|
|
tempString[length] = 0;
|
|
yylval = (object_t *)tempString;
|
|
return STRING;
|
|
}
|
|
|
|
/* process numbers */
|
|
if (isDigit (c))
|
|
{
|
|
unsigned long long n = 0;
|
|
int base = 10;
|
|
|
|
if (c == '0') {
|
|
c = nextChar();
|
|
if (c == 'x') {
|
|
base = 16;
|
|
c = nextChar();
|
|
}
|
|
}
|
|
if (base == 10) {
|
|
while(isDigit(c)) {
|
|
n = (n * base + c - '0');
|
|
c = nextChar();
|
|
}
|
|
} else {
|
|
while(isHexDigit(c)) {
|
|
if (isDigit(c)) {
|
|
n = (n * base + c - '0');
|
|
} else {
|
|
n = (n * base + 0xa + c - 'a');
|
|
}
|
|
c = nextChar();
|
|
}
|
|
}
|
|
|
|
yylval = newObject();
|
|
yylval->u.offset = n;
|
|
|
|
return NUMBER;
|
|
}
|
|
|
|
#define OSDATA_ALLOC_SIZE 4096
|
|
|
|
/* process data */
|
|
if (c == '<') {
|
|
unsigned char *d, *start, *lastStart;
|
|
|
|
size_t buflen = OSDATA_ALLOC_SIZE;
|
|
start = lastStart = d = (unsigned char *)malloc(buflen);
|
|
c = nextChar(); // skip over '<'
|
|
while (c != 0 && c != '>') {
|
|
|
|
if (isSpace(c)) while ((c = nextChar()) != 0 && isSpace(c)) {};
|
|
if (c == '#') while ((c = nextChar()) != 0 && c != '\n') {};
|
|
if (c == '\n') {
|
|
lineNumber++;
|
|
c = nextChar();
|
|
continue;
|
|
}
|
|
|
|
// get high nibble
|
|
if (!isHexDigit(c)) break;
|
|
if (isDigit(c)) {
|
|
*d = (c - '0') << 4;
|
|
} else {
|
|
*d = (0xa + (c - 'a')) << 4;
|
|
}
|
|
|
|
// get low nibble
|
|
c = nextChar();
|
|
if (!isHexDigit(c)) break;
|
|
if (isDigit(c)) {
|
|
*d |= c - '0';
|
|
} else {
|
|
*d |= 0xa + (c - 'a');
|
|
}
|
|
|
|
d++;
|
|
if ((d - lastStart) >= OSDATA_ALLOC_SIZE) {
|
|
int oldsize = d - start;
|
|
assert(buflen == oldsize);
|
|
start = (unsigned char *)realloc(start, oldsize, buflen);
|
|
d = lastStart = start + oldsize;
|
|
}
|
|
c = nextChar();
|
|
}
|
|
if (c != '>' ) {
|
|
safe_free(start, buflen);
|
|
return SYNTAX_ERROR;
|
|
}
|
|
|
|
// got it!
|
|
yylval = newObject();
|
|
yylval->object = start;
|
|
yylval->size = d - start;
|
|
|
|
(void)nextChar(); // skip over '>'
|
|
return DATA;
|
|
}
|
|
|
|
|
|
/* return single chars, move pointer to next char */
|
|
(void)nextChar();
|
|
return c;
|
|
}
|
|
|
|
// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
|
|
// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
|
|
// !@$&)(^Q$&*^!$(*!@$_(^%_(*Q#$(_*&!$_(*&!$_(*&!#$(*!@&^!@#%!_!#
|
|
|
|
#if DEBUG
|
|
int debugUnserializeAllocCount = 0;
|
|
#endif
|
|
|
|
object_t *
|
|
newObject()
|
|
{
|
|
#if DEBUG
|
|
debugUnserializeAllocCount++;
|
|
#endif
|
|
return (object_t *)malloc(sizeof(object_t));
|
|
}
|
|
|
|
void
|
|
freeObject(object_t *o)
|
|
{
|
|
#if DEBUG
|
|
debugUnserializeAllocCount--;
|
|
#endif
|
|
safe_free(o, sizeof(object_t));
|
|
}
|
|
|
|
static OSDictionary *tags;
|
|
|
|
static void
|
|
rememberObject(int tag, object_t *o)
|
|
{
|
|
char key[16];
|
|
snprintf(key, sizeof(key), "%u", tag);
|
|
|
|
tags->setObject(key, (OSObject *)o);
|
|
}
|
|
|
|
static OSObject *
|
|
retrieveObject(int tag)
|
|
{
|
|
char key[16];
|
|
snprintf(key, sizeof(key), "%u", tag);
|
|
|
|
return tags->getObject(key);
|
|
}
|
|
|
|
OSObject *
|
|
buildOSDictionary(object_t *o)
|
|
{
|
|
object_t *temp, *last = o;
|
|
int count = 0;
|
|
|
|
// get count and last object
|
|
while (o) {
|
|
count++;
|
|
last = o;
|
|
o = o->next;
|
|
}
|
|
o = last;
|
|
|
|
OSDictionary *d = OSDictionary::withCapacity(count);
|
|
|
|
while (o) {
|
|
#ifdef metaclass_stuff_worksXXX
|
|
if (((OSObject *)o->u.key)->metaCast("OSSymbol")) {
|
|
// XXX the evil frontdoor
|
|
d->setObject((OSSymbol *)o->u.key, (OSObject *)o->object);
|
|
} else {
|
|
// If it isn't a symbol, I hope it's a string!
|
|
d->setObject((OSString *)o->u.key, (OSObject *)o->object);
|
|
}
|
|
#else
|
|
d->setObject((OSString *)o->u.key, (OSObject *)o->object);
|
|
#endif
|
|
((OSObject *)o->object)->release();
|
|
((OSObject *)o->u.key)->release();
|
|
temp = o;
|
|
o = o->prev;
|
|
freeObject(temp);
|
|
}
|
|
return d;
|
|
};
|
|
|
|
OSObject *
|
|
buildOSArray(object_t *o)
|
|
{
|
|
object_t *temp, *last = o;
|
|
int count = 0;
|
|
|
|
// get count and last object
|
|
while (o) {
|
|
count++;
|
|
last = o;
|
|
o = o->next;
|
|
}
|
|
o = last;
|
|
|
|
OSArray *a = OSArray::withCapacity(count);
|
|
|
|
while (o) {
|
|
a->setObject((OSObject *)o->object);
|
|
((OSObject *)o->object)->release();
|
|
temp = o;
|
|
o = o->prev;
|
|
freeObject(temp);
|
|
}
|
|
return a;
|
|
};
|
|
|
|
OSObject *
|
|
buildOSSet(object_t *o)
|
|
{
|
|
OSArray *a = (OSArray *)buildOSArray(o);
|
|
OSSet *s = OSSet::withArray(a, a->getCapacity());
|
|
|
|
a->release();
|
|
return s;
|
|
};
|
|
|
|
OSObject *
|
|
buildOSString(object_t *o)
|
|
{
|
|
OSString *s = OSString::withCString((char *)o);
|
|
|
|
safe_free(o, strlen((char *)o) + 1);
|
|
|
|
return s;
|
|
};
|
|
|
|
OSObject *
|
|
buildOSData(object_t *o)
|
|
{
|
|
OSData *d;
|
|
|
|
if (o->size) {
|
|
d = OSData::withBytes(o->object, o->size);
|
|
} else {
|
|
d = OSData::withCapacity(0);
|
|
}
|
|
safe_free(o->object, o->size);
|
|
freeObject(o);
|
|
return d;
|
|
};
|
|
|
|
OSObject *
|
|
buildOSOffset(object_t *o)
|
|
{
|
|
OSNumber *off = OSNumber::withNumber(o->u.offset, o->size);
|
|
freeObject(o);
|
|
return off;
|
|
};
|
|
|
|
OSObject *
|
|
buildOSBoolean(object_t *o)
|
|
{
|
|
OSBoolean *b = OSBoolean::withBoolean((bool)o);
|
|
return b;
|
|
};
|
|
|
|
__BEGIN_DECLS
|
|
#include <kern/locks.h>
|
|
__END_DECLS
|
|
|
|
static lck_mtx_t *lock = 0;
|
|
extern lck_grp_t *IOLockGroup;
|
|
|
|
OSObject*
|
|
OSUnserialize(const char *buffer, OSString **errorString)
|
|
{
|
|
OSObject *object;
|
|
|
|
if (!lock) {
|
|
lock = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
|
|
lck_mtx_lock(lock);
|
|
} else {
|
|
lck_mtx_lock(lock);
|
|
|
|
}
|
|
|
|
#if DEBUG
|
|
debugUnserializeAllocCount = 0;
|
|
#endif
|
|
yyerror_message[0] = 0; //just in case
|
|
parseBuffer = buffer;
|
|
parseBufferIndex = 0;
|
|
tags = OSDictionary::withCapacity(128);
|
|
if (yyparse() == 0) {
|
|
object = parsedObject;
|
|
if (errorString) *errorString = NULL;
|
|
} else {
|
|
object = NULL;
|
|
if (errorString)
|
|
*errorString = OSString::withCString(yyerror_message);
|
|
}
|
|
|
|
tags->release();
|
|
#if DEBUG
|
|
if (debugUnserializeAllocCount) {
|
|
printf("OSUnserialize: allocation check failed, count = %d.\n",
|
|
debugUnserializeAllocCount);
|
|
}
|
|
#endif
|
|
lck_mtx_unlock(lock);
|
|
|
|
return object;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// DO NOT EDIT OSUnserialize.cpp!
|
|
//
|
|
// this means you!
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|