/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Portions Copyright (c) 2003 Apple Computer, Inc. All Rights
* Reserved.
* The contents of this file constitute Original Code as defined in and
* 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. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include "config.h"
#include "bootstruct.h"
#include "libsaio.h"
#include "sl.h"
#include "xml.h"
#if DEBUG_XML
#define DBG(x...) printf(x)
#else
#define DBG(x...)
#endif
string_ref *ref_strings = NULL;
string_ref *ref_integer = NULL;
/// TODO: remove below
static char *buffer_start = NULL;
// TODO: redo the next two functions
void SaveRefString(char *string, int id)
{
//printf("Adding Ref String %d (%s)\n", id, string);
string_ref *tmp = ref_strings;
while(tmp)
{
if(tmp->id == id)
{
tmp->string = malloc(strlen(string)+1);
strncpy(tmp->string, string, strlen(string)+1);
return;
}
tmp = tmp->next;
}
string_ref *new_ref = malloc(sizeof(string_ref));
new_ref->string = malloc(strlen(string)+1);
strncpy(new_ref->string, string, (strlen(string)+1)* sizeof(char));
new_ref->id = id;
new_ref->next = ref_strings;
ref_strings = new_ref;
}
void SaveRefInteger(int integer, int id)
{
//printf("Adding Ref Integer %d (%s)\n", id, integer);
string_ref *tmp = ref_integer;
while(tmp)
{
if(tmp->id == id)
{
tmp->string = (char*)integer;
return;
}
tmp = tmp->next;
}
string_ref *new_ref = malloc(sizeof(string_ref));
new_ref->string = (char*)integer;
new_ref->id = id;
new_ref->next = ref_integer;
ref_integer = new_ref;
}
char *GetRefString(int id)
{
string_ref *tmp = ref_strings;
while(tmp)
{
if(tmp->id == id) return tmp->string;
tmp = tmp->next;
}
//verbose("Unable to locate Ref String %d\n", id);
return "Unknown";
}
int GetRefInteger(int id)
{
string_ref *tmp = ref_integer;
while(tmp)
{
if(tmp->id == id) return (int)tmp->string;
tmp = tmp->next;
}
//verbose("Unable to locate Ref String %d\n", id);
return 0;
}
struct Module {
struct Module *nextModule;
long willLoad;
TagPtr dict;
char *plistAddr;
long plistLength;
char *driverPath;
};
typedef struct Module Module, *ModulePtr;
struct DriverInfo {
char *plistAddr;
long plistLength;
void *moduleAddr;
long moduleLength;
};
typedef struct DriverInfo DriverInfo, *DriverInfoPtr;
#define kDriverPackageSignature1 'MKXT'
#define kDriverPackageSignature2 'MOSX'
struct DriversPackage {
unsigned long signature1;
unsigned long signature2;
unsigned long length;
unsigned long adler32;
unsigned long version;
unsigned long numDrivers;
unsigned long reserved1;
unsigned long reserved2;
};
typedef struct DriversPackage DriversPackage;
enum {
kCFBundleType2,
kCFBundleType3
};
#define DOFREE 1
static long ParseTagList(char *buffer, TagPtr *tag, long type, long empty);
static long ParseTagKey(char *buffer, TagPtr *tag);
static long ParseTagString(char *buffer, TagPtr *tag);
static long ParseTagInteger(char *buffer, TagPtr *tag);
static long ParseTagData(char *buffer, TagPtr *tag);
static long ParseTagDate(char *buffer, TagPtr *tag);
//static long ParseTagBoolean(char *buffer, TagPtr *tag, long type);
static long GetNextTag(char *buffer, char **tag, long *start);
static long FixDataMatchingTag(char *buffer, char *tag);
static TagPtr NewTag(void);
static char *NewSymbol(char *string);
#if DOFREE
static void FreeSymbol(char *string);
#endif
//==========================================================================
// XMLGetProperty
TagPtr XMLGetProperty(TagPtr dict, const char *key)
{
TagPtr tagList, tag;
if (dict->type != kTagTypeDict)
{
return NULL;
}
tag = 0;
tagList = dict->tag;
while (tagList) {
tag = tagList;
tagList = tag->tagNext;
if ((tag->type != kTagTypeKey) || (tag->string == 0))
{
continue;
}
if (!strcmp(tag->string, key))
{
return tag->tag;
}
}
return NULL;
}
//==========================================================================
// XMLGetProperty
TagPtr XMLGetKey( TagPtr dict, int id )
{
TagPtr tagList, tag;
if (dict->type != kTagTypeDict)
{
return 0;
}
tag = 0;
int element = 0;
tagList = dict->tag;
while (tagList && element != id)
{
tag = tagList;
tagList = tag->tagNext;
if ((tag->type != kTagTypeKey) || (tag->string == 0))
{
continue;
}
element++;
if(id == element)
{
return tag;
}
}
return 0;
}
TagPtr XMLGetValueForKey(TagPtr key)
{
if (!key || key->type != kTagTypeKey)
{
return 0;
}
return key->tag;
}
// XMLGetTag(int index)
// XMLTagCount( TagPtr dict )
int XMLTagCount( TagPtr dict )
{
int count = 0;
TagPtr tagList, tag;
if (dict->type != kTagTypeDict && dict->type != kTagTypeArray)
{
return 0;
}
tag = 0;
tagList = dict->tag;
while (tagList)
{
tag = tagList;
tagList = tag->tagNext;
if (((tag->type != kTagTypeKey) && ((tag->string == 0) || (tag->string[0] == 0)))
&& (dict->type != kTagTypeArray) // If we are an array, any element is valid
)
{
continue;
}
//if(tag->type == kTagTypeKey) printf("Located key %s\n", tag->string);
count++;
}
return count;
}
TagPtr XMLGetElement( TagPtr dict, int id )
{
if(dict->type != kTagTypeArray)
{
return 0;
}
int element = 0;
TagPtr tmp = dict->tag;
while(element < id)
{
element++;
tmp = tmp->tagNext;
}
return tmp;
}
typedef const struct XMLEntity {
const char *name;
size_t nameLen;
char value;
} XMLEntity;
/* This is ugly, but better than specifying the lengths by hand */
#define _e(str,c) {str,sizeof(str)-1,c}
const XMLEntity ents[] = {
_e("quot;",'"'), // double quotation mark
_e("apos;",'\''), // apostrophe (apostrophe-quote)
_e("lt;", '<'), // less-than sign
_e("gt;", '>'), // greater-than sign
_e("amp;", '&') // ampersand
};
/* Function for basic XML character entities parsing */
char *XMLDecode(const char *src)
{
size_t len;
const char *s;
char *out, *o;
if ( !src || !(len = strlen(src)) || !(out = malloc(len+1)) )
{
return 0;
}
o = out;
s = src;
while (s <= src+len) /* Make sure the terminator is also copied */
{
if ( *s == '&' )
{
bool entFound = false;
int i;
s++;
for ( i = 0; i < sizeof(ents)/sizeof(ents[0]); i++)
{
if ( strncmp(s, ents[i].name, ents[i].nameLen) == 0 )
{
entFound = true;
break;
}
}
if ( entFound )
{
*o++ = ents[i].value;
s += ents[i].nameLen;
continue;
}
}
*o++ = *s++;
}
return out;
}
//==========================================================================
// XMLParseFile
// Expects to see one dictionary in the XML file, the final pos will be returned
// If the pos is not equal to the strlen, then there are multiple dicts
// Puts the first dictionary it finds in the
// tag pointer and returns the end of the dic, or returns -1 if not found.
//
long XMLParseFile( char * buffer, TagPtr *dict )
{
long length;
long pos = 0;
TagPtr tag;
char *configBuffer;
int strlength = strlen(buffer);
configBuffer = malloc(strlength+1);
bcopy(buffer, configBuffer, strlength);
configBuffer[strlength] = 0;
buffer_start = configBuffer;
while (1)
{
length = XMLParseNextTag(configBuffer + pos, &tag);
if (length == -1) break;
pos += length;
if (tag == 0)
{
continue;
}
if (tag->type == kTagTypeDict)
{
break;
}
XMLFreeTag(tag);
}
free(configBuffer);
if (length < 0)
{
return -1;
}
*dict = tag;
return pos;
}
//==========================================================================
// ParseNextTag
// TODO: cleanup
long XMLParseNextTag( char *buffer, TagPtr *tag )
{
long length = 0;
long pos = 0;
char *tagName = NULL;
length = GetNextTag(buffer, &tagName, 0);
if (length == -1)
{
return -1;
}
pos = length;
if (!strncmp(tagName, kXMLTagPList, 6))
{
length = 0;
// just a header; nothing to parse
// return-via-reference tag should be left alone
}
/***** dict ****/
else if (!strncmp(tagName, kXMLTagDict, sizeof(kXMLTagDict)))
{
length = ParseTagList(buffer + pos, tag, kTagTypeDict, 0);
}
else if (!strncmp(tagName, kXMLTagDict, strlen(kXMLTagDict)) && tagName[strlen(tagName)-1] == '/')
{
length = ParseTagList(buffer + pos, tag, kTagTypeDict, 1);
}
else if (!strncmp(tagName, kXMLTagDict " ", strlen(kXMLTagDict " ")))
{
length = ParseTagList(buffer + pos, tag, kTagTypeDict, 0);
}
/***** key ****/
else if (!strncmp(tagName, kXMLTagKey, sizeof(kXMLTagKey)))
{
length = ParseTagKey(buffer + pos, tag);
}
/***** string ****/
else if (!strncmp(tagName, kXMLTagString, sizeof(kXMLTagString)))
{
length = ParseTagString(buffer + pos, tag);
}
else if (!strncmp(tagName, kXMLTagString " ", strlen(kXMLTagString " ")))
{
// TODO: save tag if if found
if(!strncmp(tagName + strlen(kXMLTagString " "), kXMLStringID, strlen(kXMLStringID)))
{
// ID=
int id = 0;
int cnt = strlen(kXMLTagString " " kXMLStringID "\"") + 1;
while ((tagName[cnt] != '\0') && (tagName[cnt] != '"')) cnt++;
tagName[cnt] = 0;
char* val = tagName + strlen(kXMLTagString " " kXMLStringID "\"");
while(*val)
{
if ((*val >= '0' && *val <= '9')) // 0 - 9
{
id = (id * 10) + (*val++ - '0');
}
else
{
printf("ParseStringID error (0x%x)\n", *val);
getchar();
return -1;
}
}
length = ParseTagString(buffer + pos, tag);
SaveRefString(buffer + pos, id);
}
else if(!strncmp(tagName + strlen(kXMLTagString " "), kXMLStringIDRef, strlen(kXMLStringIDRef)))
{
// IDREF=
int id = 0;
int cnt = strlen(kXMLTagString " " kXMLStringIDRef "\"") + 1;
while ((tagName[cnt] != '\0') && (tagName[cnt] != '"')) cnt++;
tagName[cnt] = 0;
char* val = tagName + strlen(kXMLTagString " " kXMLStringIDRef "\"");
while(*val)
{
if ((*val >= '0' && *val <= '9')) // 0 - 9
{
id = (id * 10) + (*val++ - '0');
}
else
{
printf("ParseStringIDREF error (0x%x)\n", *val);
getchar();
return -1;
}
}
char* str = GetRefString(id);
TagPtr tmpTag = NewTag();
tmpTag->type = kTagTypeString;
tmpTag->string = str;
tmpTag->tag = 0;
tmpTag->tagNext = 0;
tmpTag->offset = buffer_start ? buffer - buffer_start + pos : 0;
*tag = tmpTag;
length = 0;
//printf("Located IDREF, id = %d, string = %s\n", id, str);
}
}
/***** integer ****/
else if (!strncmp(tagName, kXMLTagInteger, sizeof(kXMLTagInteger)))
{
length = ParseTagInteger(buffer + pos, tag);
}
else if (!strncmp(tagName, kXMLTagInteger " ", strlen(kXMLTagInteger " ")))
{
if(!strncmp(tagName + strlen(kXMLTagInteger " "), kXMLStringID, strlen(kXMLStringID)))
{
// ID=
int id = 0;
int cnt = strlen(kXMLTagInteger " " kXMLStringID "\"") + 1;
while ((tagName[cnt] != '\0') && (tagName[cnt] != '"')) cnt++;
tagName[cnt] = 0;
char* val = tagName + strlen(kXMLTagInteger " " kXMLStringID "\"");
while(*val)
{
if ((*val >= '0' && *val <= '9')) // 0 - 9
{
id = (id * 10) + (*val++ - '0');
}
else
{
printf("ParseIntegerID error (0x%x)\n", *val);
getchar();
return -1;
}
}
length = ParseTagInteger(buffer + pos, tag);
SaveRefInteger((int)(*tag)->string, id);
}
else if(!strncmp(tagName + strlen(kXMLTagInteger " "), kXMLStringIDRef, strlen(kXMLStringIDRef)))
{
// IDREF=
int id = 0;
int cnt = strlen(kXMLTagInteger " " kXMLStringIDRef "\"") + 1;
while ((tagName[cnt] != '\0') && (tagName[cnt] != '"')) cnt++;
tagName[cnt] = 0;
char* val = tagName + strlen(kXMLTagInteger " " kXMLStringIDRef "\"");
while(*val)
{
if ((*val >= '0' && *val <= '9')) // 0 - 9
{
id = (id * 10) + (*val++ - '0');
}
else
{
printf("ParseStringIDREF error (0x%x)\n", *val);
getchar();
return -1;
}
}
int integer = GetRefInteger(id);
TagPtr tmpTag = NewTag();
if (tmpTag == 0)
{
return -1;
}
tmpTag->type = kTagTypeInteger;
tmpTag->string = (char*) integer;
tmpTag->tag = 0;
tmpTag->tagNext = 0;
tmpTag->offset = buffer_start ? buffer - buffer_start + pos : 0;
*tag = tmpTag;
length = 0;
//printf("Located IDREF, id = %d, string = %s\n", id, str);
}
else
{
length = ParseTagInteger(buffer + pos, tag);
}
}
/***** data ****/
else if (!strncmp(tagName, kXMLTagData, sizeof(kXMLTagData)))
{
length = ParseTagData(buffer + pos, tag);
}
else if (!strncmp(tagName, kXMLTagData " ", strlen(kXMLTagData " ")))
{
length = ParseTagData(buffer + pos, tag);
}
else if (!strncmp(tagName, kXMLTagDate, sizeof(kXMLTagDate)))
{
length = ParseTagDate(buffer + pos, tag);
}
/***** date ****/
else if (!strncmp(tagName, kXMLTagDate " ", strlen(kXMLTagDate " ")))
{
length = ParseTagDate(buffer + pos, tag);
}
/***** false ****/
else if (!strncmp(tagName, kXMLTagFalse, sizeof(kXMLTagFalse)))
{
length = ParseTagBoolean(buffer + pos, tag, kTagTypeFalse);
}
/***** true ****/
else if (!strncmp(tagName, kXMLTagTrue, sizeof(kXMLTagTrue)))
{
length = ParseTagBoolean(buffer + pos, tag, kTagTypeTrue);
}
/***** array ****/
else if (!strncmp(tagName, kXMLTagArray, sizeof(kXMLTagArray) ))
{
length = ParseTagList(buffer + pos, tag, kTagTypeArray, 0);
}
else if (!strncmp(tagName, kXMLTagArray " ", strlen(kXMLTagArray " ")))
{
length = ParseTagList(buffer + pos, tag, kTagTypeArray, 0);
}
else if (!strncmp(tagName, kXMLTagArray "/", strlen(kXMLTagArray "/")))
{
length = ParseTagList(buffer + pos, tag, kTagTypeArray, 1);
}
/***** unknown ****/
else
{
// it wasn't parsed so we consumed no additional characters
*tag = NULL;
length = 0;
}
if (length == -1)
{
return -1;
}
return pos + length;
}
//==========================================================================
// ParseTagList
static long ParseTagList( char *buffer, TagPtr *tag, long type, long empty )
{
long pos = 0;
long length = 0;
TagPtr tagList = NULL;
TagPtr tmpTag;
if (!empty)
{
while (1)
{
length = XMLParseNextTag(buffer + pos, &tmpTag);
if (length == -1)
{
break;
}
pos += length;
// detect end of list
if (tmpTag == NULL)
{
break;
}
tmpTag->tagNext = tagList;
tagList = tmpTag;
}
if (length == -1)
{
XMLFreeTag(tagList);
return -1;
}
}
tmpTag = NewTag();
if (tmpTag == NULL)
{
XMLFreeTag(tagList);
return -1;
}
tmpTag->type = type;
tmpTag->string = 0;
tmpTag->offset = buffer_start ? buffer - buffer_start : 0;
tmpTag->tag = tagList;
tmpTag->tagNext = 0;
*tag = tmpTag;
return pos;
}
//==========================================================================
// ParseTagKey
static long ParseTagKey( char *buffer, TagPtr *tag )
{
long length = 0;
long length2 = 0;
char *string;
TagPtr tmpTag;
TagPtr subTag;
length = FixDataMatchingTag(buffer, kXMLTagKey);
if (length == -1)
{
return -1;
}
length2 = XMLParseNextTag(buffer + length, &subTag);
if (length2 == -1)
{
return -1;
}
tmpTag = NewTag();
if (tmpTag == NULL)
{
XMLFreeTag(subTag);
return -1;
}
string = NewSymbol(buffer);
if (string == NULL)
{
XMLFreeTag(subTag);
XMLFreeTag(tmpTag);
return -1;
}
tmpTag->type = kTagTypeKey;
tmpTag->string = string;
tmpTag->tag = subTag;
tmpTag->offset = buffer_start ? buffer - buffer_start: 0;
tmpTag->tagNext = 0;
*tag = tmpTag;
return length + length2;
}
//==========================================================================
// ParseTagString
static long ParseTagString( char *buffer, TagPtr *tag )
{
long length = 0;
char *string;
length = FixDataMatchingTag(buffer, kXMLTagString);
if (length == -1)
{
return -1;
}
TagPtr tmpTag = NewTag();
if (tmpTag == NULL)
{
return -1;
}
string = NewSymbol(buffer);
if (string == NULL)
{
XMLFreeTag(tmpTag);
return -1;
}
tmpTag->type = kTagTypeString;
tmpTag->string = string;
tmpTag->tag = NULL;
tmpTag->tagNext = NULL;
tmpTag->offset = buffer_start ? buffer - buffer_start: 0;
*tag = tmpTag;
return length;
}
//==========================================================================
// ParseTagInteger
static long ParseTagInteger( char *buffer, TagPtr *tag )
{
long length, integer;
bool negative = false;
TagPtr tmpTag;
char* val = buffer;
int size;
if(buffer[0] == '<')
{
printf("Warning integer is non existant\n");
getchar();
tmpTag = NewTag();
tmpTag->type = kTagTypeInteger;
tmpTag->string = 0;
tmpTag->tag = 0;
tmpTag->offset = 0;
tmpTag->tagNext = 0;
*tag = tmpTag;
return 0;
}
size = length = FixDataMatchingTag(buffer, kXMLTagInteger);
if (length == -1)
{
return -1;
}
tmpTag = NewTag();
if (tmpTag == 0)
{
return -1;
}
integer = 0;
if(size > 1 && (val[1] == 'x' || val[1] == 'X')) // Hex value
{
val += 2;
while(*val)
{
if ((*val >= '0' && *val <= '9')) // 0 - 9
{
integer = (integer * 16) + (*val++ - '0');
}
else if ((*val >= 'a' && *val <= 'f')) // a - f
{
integer = (integer * 16) + (*val++ - 'a' + 10);
}
else if ((*val >= 'A' && *val <= 'F')) // A - F
{
integer = (integer * 16) + (*val++ - 'A' + 10);
}
else
{
printf("ParseTagInteger hex error (0x%x) in buffer %s\n", *val, buffer);
getchar();
XMLFreeTag(tmpTag);
return -1;
}
}
}
else if ( size ) // Decimal value
{
if (*val == '-')
{
negative = true;
val++;
size--;
}
for (integer = 0; size > 0; size--)
{
if(*val) // UGLY HACK, fix me.
{
if (*val < '0' || *val > '9')
{
printf("ParseTagInteger decimal error (0x%x) in buffer %s\n", *val, buffer);
getchar();
return -1;
}
integer = (integer * 10) + (*val++ - '0');
}
}
if (negative) {
integer = -integer;
}
}
tmpTag->type = kTagTypeInteger;
tmpTag->string = (char *)integer;
tmpTag->tag = NULL;
tmpTag->offset = buffer_start ? buffer - buffer_start: 0;
tmpTag->tagNext = NULL;
*tag = tmpTag;
return length;
}
//==========================================================================
// ParseTagData
static long ParseTagData( char *buffer, TagPtr *tag)
{
//int actuallen = 0;
int len = 0;
long length = 0;
TagPtr tmpTag;
char *tmpString;
length = FixDataMatchingTag(buffer, kXMLTagData);
if (length == -1)
{
return -1;
}
tmpTag = NewTag();
if (tmpTag == NULL)
{
return -1;
}
tmpString = NewSymbol(buffer);
tmpTag->type = kTagTypeData;
tmpTag->string = tmpString;
tmpTag->data = (UInt8 *)BASE64Decode(buffer, strlen(buffer), &len);
tmpTag->dataLen = len;
tmpTag->tag = NULL;
tmpTag->offset = /* actuallen; */ buffer_start ? buffer - buffer_start: 0;
tmpTag->tagNext = NULL;
*tag = tmpTag;
return length;
}
//==========================================================================
// ParseTagDate
static long ParseTagDate( char *buffer, TagPtr *tag )
{
long length = 0;
TagPtr tmpTag;
length = FixDataMatchingTag(buffer, kXMLTagDate);
if (length == -1)
{
return -1;
}
tmpTag = NewTag();
if (tmpTag == NULL)
{
return -1;
}
printf("ParseTagDate unimplimented\n");
getchar();
tmpTag->type = kTagTypeDate;
tmpTag->string = NULL;
tmpTag->tag = NULL;
tmpTag->tagNext = NULL;
tmpTag->offset = buffer_start ? buffer - buffer_start: 0;
*tag = tmpTag;
return length;
}
//==========================================================================
// ParseTagBoolean
long ParseTagBoolean( char *buffer, TagPtr *tag, long type )
{
TagPtr tmpTag;
tmpTag = NewTag();
if (tmpTag == NULL)
{
return -1;
}
tmpTag->type = type;
tmpTag->string = NULL;
tmpTag->tag = NULL;
tmpTag->tagNext = NULL;
tmpTag->offset = buffer_start ? buffer - buffer_start: 0;
*tag = tmpTag;
return 0;
}
//==========================================================================
// GetNextTag
static long GetNextTag( char *buffer, char **tag, long *start )
{
long cnt;
long cnt2;
if (tag == NULL)
{
return -1;
}
// Find the start of the tag.
cnt = 0;
while ((buffer[cnt] != '\0') && (buffer[cnt] != '<'))
{
cnt++;
}
if (buffer[cnt] == '\0')
{
return -1;
}
// Find the end of the tag.
cnt2 = cnt + 1;
while ((buffer[cnt2] != '\0') && (buffer[cnt2] != '>'))
{
cnt2++;
}
if (buffer[cnt2] == '\0')
{
return -1;
}
// Fix the tag data.
*tag = buffer + cnt + 1;
buffer[cnt2] = '\0';
if (start)
{
*start = cnt;
}
return cnt2 + 1;
}
//==========================================================================
// FixDataMatchingTag
// Modifies 'buffer' to add a '\0' at the end of the tag matching 'tag'.
// Returns the length of the data found, counting the end tag,
// or -1 if the end tag was not found.
static long FixDataMatchingTag( char *buffer, char *tag )
{
long length;
long start;
long stop;
char *endTag;
start = 0;
while (1)
{
length = GetNextTag(buffer + start, &endTag, &stop);
if (length == -1)
{
return -1;
}
if ((*endTag == '/') && !strcmp(endTag + 1, tag))
{
break;
}
start += length;
}
buffer[start + stop] = '\0';
return start + length;
}
//==========================================================================
// NewTag
#define kTagsPerBlock (0x1000)
static TagPtr gTagsFree = NULL;
static TagPtr NewTag( void )
{
long cnt;
TagPtr tag;
if (gTagsFree == NULL)
{
tag = (TagPtr)malloc(kTagsPerBlock *sizeof(Tag));
if (tag == NULL)
{
return NULL;
}
// Initalize the new tags.
for (cnt = 0; cnt < kTagsPerBlock; cnt++)
{
tag[cnt].type = kTagTypeNone;
tag[cnt].string = 0;
tag[cnt].data = 0;
tag[cnt].dataLen = 0;
tag[cnt].tag = 0;
tag[cnt].tagNext = tag + cnt + 1;
}
tag[kTagsPerBlock - 1].tagNext = 0;
gTagsFree = tag;
}
tag = gTagsFree;
gTagsFree = tag->tagNext;
return tag;
}
//==========================================================================
// XMLFreeTag
void XMLFreeTag( TagPtr tag )
{
#if DOFREE
if (tag == NULL)
{
return;
}
if (!XMLIsInteger(tag) && tag->string)
{
FreeSymbol(tag->string);
}
XMLFreeTag(tag->tag);
XMLFreeTag(tag->tagNext);
// Clear and free the tag.
tag->type = kTagTypeNone;
tag->string = NULL;
tag->data = NULL;
tag->dataLen = 0;
tag->tag = NULL;
tag->offset = 0;
tag->tagNext = gTagsFree;
gTagsFree = tag;
#else
return;
#endif
}
//==========================================================================
// Symbol object.
struct Symbol
{
long refCount;
struct Symbol *next;
char string[];
};
typedef struct Symbol Symbol, *SymbolPtr;
static SymbolPtr FindSymbol(char *string, SymbolPtr *prevSymbol);
static SymbolPtr gSymbolsHead = NULL;
//==========================================================================
// NewSymbol
static char *NewSymbol( char *string )
{
static SymbolPtr lastGuy = 0;
SymbolPtr symbol;
// Look for string in the list of symbols.
symbol = FindSymbol(string, 0);
// Add the new symbol.
if (symbol == NULL)
{
symbol = (SymbolPtr)malloc(sizeof(Symbol) + 1 + strlen(string));
if (symbol == NULL)
{
stop("NULL symbol!");
return NULL;
}
// Set the symbol's data.
symbol->refCount = 0;
strcpy(symbol->string, string);
// Add the symbol to the list.
symbol->next = gSymbolsHead;
gSymbolsHead = symbol;
}
// Update the refCount and return the string.
symbol->refCount++;
if (lastGuy && lastGuy->next != 0)
{
stop("last guy not last!");
}
return symbol->string;
}
//==========================================================================
// FreeSymbol
#if DOFREE
static void FreeSymbol( char *string )
{
SymbolPtr symbol, prev;
prev = NULL;
// Look for string in the list of symbols.
symbol = FindSymbol(string, &prev);
if (symbol == NULL)
{
return;
}
// Update the refCount.
symbol->refCount--;
if (symbol->refCount != 0)
{
return;
}
// Remove the symbol from the list.
if (prev != NULL)
{
prev->next = symbol->next;
}
else
{
gSymbolsHead = symbol->next;
}
// Free the symbol's memory.
free(symbol);
}
#endif
//==========================================================================
// FindSymbol
static SymbolPtr FindSymbol( char *string, SymbolPtr *prevSymbol )
{
SymbolPtr symbol, prev;
if (string == NULL)
{
return NULL;
}
symbol = gSymbolsHead;
prev = NULL;
while (symbol != NULL)
{
if (!strcmp(symbol->string, string))
{
break;
}
prev = symbol;
symbol = symbol->next;
}
if ((symbol != NULL) && (prevSymbol != NULL))
{
*prevSymbol = prev;
}
return symbol;
}
bool XMLIsType(TagPtr dict, enum xmltype type)
{
if(!dict)
{
return (type == kTagTypeNone);
}
return (dict->type == type);
}
/*** Cast functions ***/
bool XMLIsArray(TagPtr entry)
{
return entry && (entry->type == kTagTypeArray);
}
TagPtr XMLCastArray(TagPtr dict)
{
if(!dict)
{
return NULL;
}
if(dict->type == kTagTypeArray)
{
return dict;
} else {
return NULL;
}
}
bool XMLIsDict(TagPtr entry)
{
return entry && (entry->type == kTagTypeDict);
}
bool XMLIsData(TagPtr entry)
{
return entry && (entry->type == kTagTypeData);
}
TagPtr XMLCastDict(TagPtr dict)
{
if(!dict)
{
return NULL;
}
if(dict->type == kTagTypeDict)
{
return dict;
}
else
{
return NULL;
}
}
bool XMLIsString(TagPtr entry)
{
return entry && ((entry->type == kTagTypeString) || (entry->type == kTagTypeKey));
}
char *XMLCastString(TagPtr dict)
{
if(!dict)
{
return NULL;
}
if((dict->type == kTagTypeString) || (dict->type == kTagTypeKey))
{
return dict->string;
}
return NULL;
}
char *XMLCastData(TagPtr dict, int* length)
{
if(!dict)
{
return NULL;
}
if((dict->type == kTagTypeData) || (dict->type == kTagTypeKey))
{
*length = dict->offset;
return dict->string;
}
*length = 0;
return NULL;
}
long XMLCastStringOffset(TagPtr dict)
{
if(dict && ((dict->type == kTagTypeString) || (dict->type == kTagTypeKey)))
{
return dict->offset;
}
else
{
return -1;
}
}
bool XMLIsBoolean(TagPtr entry)
{
return entry && ((entry->type == kTagTypeTrue) || (entry->type == kTagTypeFalse));
}
bool XMLCastBoolean(TagPtr dict)
{
if(!dict)
{
return false;
}
if(dict->type == kTagTypeTrue)
{
return true;
}
return false;
}
bool XMLIsInteger(TagPtr entry)
{
return entry && (entry->type == kTagTypeInteger);
}
int XMLCastInteger(TagPtr dict)
{
if(!dict)
{
//printf("XMLCastInteger: null dict\n");
return 0;
}
if(dict->type == kTagTypeInteger)
{
return (int)(dict->string);
}
return 0;
}
bool XMLAddTagToDictionary(TagPtr dict, char *key, TagPtr value)
{
if (!dict || dict->type != kTagTypeDict)
{
return false;
}
TagPtr tmpTag;
char* string;
tmpTag = NewTag();
if (tmpTag == 0)
{
return false;
}
string = NewSymbol(key);
if (string == 0)
{
XMLFreeTag(tmpTag);
return false;
}
tmpTag->type = kTagTypeKey;
tmpTag->string = string;
tmpTag->tag = value;
tmpTag->offset = 0;
tmpTag->tagNext = 0;
TagPtr tagList = dict->tag;
if(!tagList)
{
// First tag
dict->tag = tmpTag;
return true;
}
while(tagList && tagList->tagNext) tagList = tagList->tagNext;
if(tagList)
{
tagList->tagNext = tmpTag;
return true;
}
XMLFreeTag(tmpTag);
return false;
}
//==========================================================================
// Micky1979
// XMLConvertTagPtrToXMLString
// convert back a TagPtr to a xml representation
// Here is still w/o header and footer
char *XMLConvertTagPtrToXMLString(TagPtr aDict, long parentType, int indent)
{
indent ++;
// TODO check if we can use a buffer for the booter stuff already reserved somewhere
char *string = "";
char *ind = "";
for (int i = 0; i < indent; i++)
{
char *ind2 = malloc(strlen(ind) + strlen("\t") +1);
strcpy(ind2, ind);
ind2[strlen(ind)] = '\t';
ind2[strlen(ind) +1] = '\0';
ind = ind2;
}
unsigned long length = 0;
int count = XMLTagCount(aDict);
while(count)
{
// parsing only supported tags
char *key = NULL;
TagPtr sub = NULL;
if (!XMLIsArray(aDict))
{
key = XMLCastString(XMLGetKey(aDict, count));
sub = XMLGetProperty(aDict, key);
}
else
{
key = "";
sub = XMLGetElement( aDict, count-1);
}
if(sub)
{
if(XMLIsData(sub))
{
char *temp;
if (parentType == kTagTypeArray)
{
length = (strlen(ind) +
strlen(sub->string ? sub->string : "") +
strlen("") +
strlen("\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n", string, ind, sub->string ? sub->string : "");
} else {
length = (strlen(ind) +
strlen(key) +
strlen("") +
strlen("\n") +
strlen(ind) +
strlen(sub->string ? sub->string : "") +
strlen("") +
strlen("\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n%s%s\n",
string, ind, key, ind, sub->string ? sub->string : "");
}
temp[strlen(string) + length] = '\0';
string = temp;
}
else if(XMLIsString(sub))
{
char *temp;
if (parentType == kTagTypeArray)
{
length = (strlen(ind) +
strlen("") +
strlen(XMLCastString(sub) ? XMLCastString(sub) : "") +
strlen("\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n",
string, ind, XMLCastString(sub) ? XMLCastString(sub) : "");
} else {
length = (strlen(ind) +
strlen(key) +
strlen("") +
strlen("\n") +
strlen(ind) +
strlen("") +
strlen(XMLCastString(sub) ? XMLCastString(sub) : "") +
strlen("\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n%s%s\n",
string, ind, key, ind, XMLCastString(sub) ? XMLCastString(sub) : "");
}
temp[strlen(string) + length] = '\0';
string = temp;
}
else if(XMLIsInteger(sub))
{
// 'real' (float/dowble) cannot be parsed. only integers
int x = XMLCastInteger(sub);
char xBuf[snprintf( NULL, 0, "%d", x )];
snprintf( xBuf, snprintf( NULL, 0, "%d", x ) +1, "%d", x );
char *temp;
if (parentType == kTagTypeArray)
{
length = (strlen(ind) +
strlen("") +
sizeof(xBuf) +
strlen("\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n", string, ind, (char *)xBuf);
} else {
length = (strlen(ind) +
strlen(key) +
strlen("") +
strlen("\n") +
strlen(ind) +
strlen("") +
sizeof(xBuf) +
strlen("\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n%s%s\n",
string, ind, key, ind, (char *)xBuf);
}
temp[strlen(string) + length] = '\0';
string = temp;
}
else if(XMLIsBoolean(sub))
{
char *temp;
int v = XMLCastBoolean(sub);
if (parentType == kTagTypeArray)
{
length = (strlen(ind) +
strlen(v ? "\n" : "\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s", string, ind, v ? "\n" : "\n");
} else {
length = (strlen(ind) +
strlen(key) +
strlen("") +
strlen("\n") +
strlen(ind) +
strlen(v ? "\n" : "\n") +
1);
temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n%s%s",
string, ind, key, ind, v ? "\n" : "\n");
}
temp[strlen(string) + length] = '\0';
string = temp;
}
else if (XMLIsDict(sub) || XMLIsArray(sub)) // its a contenitor..
{
int subCount = XMLTagCount(sub);
char *otag = subCount <=0 ? "" : XMLIsDict(sub) ? "\n" : "\n";
char *ctag = subCount <=0 ? XMLIsDict(sub) ? "\n" :
"\n" : XMLIsDict(sub) ? "\n" : "\n";
char *dict = NULL;
dict = NULL;
dict = XMLConvertTagPtrToXMLString(sub, sub->type, indent);
length = (strlen(ind) +
strlen(key) +
strlen("") +
strlen("\n") +
strlen(ind) +
strlen(otag) +
strlen(dict) +
strlen(ind) +
strlen(ctag) +
1);
char *temp = malloc(strlen(string) + length);
snprintf(temp, length+strlen(string), "%s%s%s\n%s%s%s%s%s\n",
string, ind, key, ind, otag, dict, ind, ctag);
temp[strlen(string) + length] = '\0';
string = temp;
}
}
count--;
}
if(strlen(ind))
{
free(ind);
} // not mallocated if ""
return string;
}
// XMLConvertTagPtrToPropertyList_v1
// convert back a TagPtr to a xml representation
// with header and footer
char *XMLConvertTagPtrToPropertyList_v1(TagPtr aDict)
{
if (!aDict)
{
return NULL;
}
char *s = XMLConvertTagPtrToXMLString(aDict, aDict->type, 1);
if (s == NULL)
{
return NULL;
}
unsigned long length = ((strlen(kXMLv1) -1 /* -1 for %s included */) +
strlen(s) +
1);
char *propertyList = malloc(length);
snprintf(propertyList, length, kXMLv1, s);
if (strlen(s))
{
free(s);
}
return (char *)propertyList;
}
// XMLGenerateKextInjectorFromTag
// generate an full Info.plist to create a kext injector
// sDict should contains all the contents of IOKitPersonalities
// personalityName is a funcy name. Must not be a real kext name
// OSBundleRequired should be the same of the real kext you want to hack (Root, Safe Boot, Network-Root etc.)
// can also be NULL or "" assuming the target kext does not have this key.
char * XMLGenerateKextInjectorFromTag(TagPtr aDict, char *personalityName, char *OSBundleRequired)
{
if (!aDict || personalityName == NULL)
{
return NULL;
}
char *IOKitPersonalities = XMLConvertTagPtrToXMLString(aDict, aDict->type, 1);
if (IOKitPersonalities == NULL)
{
return NULL;
}
char *OBRkey = OSBundleRequired == NULL ? "" : OSBundleRequired;
char *propertyList;
unsigned long length = 0;
if (strlen(OBRkey))
{
length = (strlen("\tOSBundleRequired\n\t") +
strlen(OBRkey) +
strlen("\n") +
1);
char temp[length];
snprintf(temp, length, "\tOSBundleRequired\n\t%s\n", OBRkey);
unsigned long mlength = ((strlen(kFakeInjectorKext) -8 /* %s x 8 */) +
strlen(personalityName) +
strlen(personalityName) +
strlen(IOKitPersonalities) +
length +
1);
propertyList = malloc(mlength);
snprintf(propertyList, mlength, kFakeInjectorKext, personalityName, personalityName, IOKitPersonalities, temp);
}
else
{
unsigned long mlength = ((strlen(kFakeInjectorKext) -8 /* %s x 8 */) +
strlen(personalityName) +
strlen(personalityName) +
strlen(IOKitPersonalities) +
1);
propertyList = malloc(mlength);
snprintf(propertyList, mlength, kFakeInjectorKext, personalityName, personalityName, IOKitPersonalities, "");
}
if (strlen(IOKitPersonalities))
{
free(IOKitPersonalities);
}
return propertyList;
}