/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. 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 1.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. * * 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 OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ /* * drivers.c - Driver Loading Functions. * * Copyright (c) 2000 Apple Computer, Inc. * * DRI: Josh de Cesare */ #include "libsaio.h" #include "memory.h" #include "kernBootStruct.h" #include "nbp.h" #include "boot.h" enum { kTagTypeNone = 0, kTagTypeDict, kTagTypeKey, kTagTypeString, kTagTypeInteger, kTagTypeData, kTagTypeDate, kTagTypeFalse, kTagTypeTrue, kTagTypeArray }; #define kXMLTagPList "plist " #define kXMLTagDict "dict" #define kXMLTagKey "key" #define kXMLTagString "string" #define kXMLTagInteger "integer" #define kXMLTagData "data" #define kXMLTagDate "date" #define kXMLTagFalse "false/" #define kXMLTagTrue "true/" #define kXMLTagArray "array" #define kPropCFBundleIdentifier ("CFBundleIdentifier") #define kPropCFBundleExecutable ("CFBundleExecutable") #define kPropOSBundleRequired ("OSBundleRequired") #define kPropOSBundleLibraries ("OSBundleLibraries") #define kPropIOKitPersonalities ("IOKitPersonalities") #define kPropIONameMatch ("IONameMatch") struct Tag { long type; char *string; struct Tag *tag; struct Tag *tagNext; }; typedef struct Tag Tag, *TagPtr; 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 alder32; unsigned long version; unsigned long numDrivers; unsigned long reserved1; unsigned long reserved2; }; typedef struct DriversPackage DriversPackage; static long FileLoadDrivers(char *dirSpec, long plugin); static long NetLoadDrivers(char *dirSpec); static long LoadDriverMKext(char *fileSpec); static long LoadDriverPList(char *dirSpec, char *name); static long LoadMatchedModules(void); static long MatchPersonalities(void); static long MatchLibraries(void); static TagPtr GetProperty(TagPtr dict, char *key); // static ModulePtr FindModule(char *name); static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities); static long ParseNextTag(char *buffer, TagPtr *tag); 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 void FreeTag(TagPtr tag); static char *NewSymbol(char *string); static void FreeSymbol(char *string); // static void DumpTag(TagPtr tag, long depth); static ModulePtr gModuleHead, gModuleTail; static TagPtr gPersonalityHead, gPersonalityTail; static char * gExtensionsSpec; static char * gDriverSpec; static char * gFileSpec; //========================================================================== // BootX shim functions. #include #define kLoadAddr TFTP_ADDR #define kLoadSize TFTP_LEN #define kPageSize 4096 #define RoundPage(x) ((((unsigned)(x)) + kPageSize - 1) & ~(kPageSize - 1)) static long LoadFile( char * fileSpec ) { unsigned long count = TFTP_LEN; unsigned long addr = TFTP_ADDR; if ( gBootDev == kBootDevNetwork ) { if ( nbpTFTPReadFile(fileSpec, &count, addr) != nbpStatusSuccess ) return -1; } else { int fd = open( fileSpec, 0 ); if ( fd < 0 ) return -1; count = read( fd, (char *) addr, count ); close(fd); } return count; } static long gImageFirstBootXAddr; static long gImageLastKernelAddr; static void * AllocateBootXMemory( long size ) { long addr = gImageFirstBootXAddr - size; if ( addr < gImageLastKernelAddr ) return 0; bzero(addr, size); gImageFirstBootXAddr = addr; return (void *)addr; } static long AllocateKernelMemory( long inSize ) { long addr = gImageLastKernelAddr; gImageLastKernelAddr += RoundPage(inSize); if ( gImageLastKernelAddr > gImageFirstBootXAddr ) stop( "AllocateKernelMemory error" ); kernBootStruct->ksize = gImageLastKernelAddr - kernBootStruct->kaddr; return addr; } static long AllocateMemoryRange(char * rangeName, long start, long length, long type) { if ( kernBootStruct->numBootDrivers < NDRIVERS ) { int num = kernBootStruct->numBootDrivers; kernBootStruct->driverConfig[num].address = start; kernBootStruct->driverConfig[num].size = length; kernBootStruct->driverConfig[num].type = type; kernBootStruct->numBootDrivers++; } else { stop( "AllocateMemoryRange error" ); } return 0; } // Map BootX file types to UFS file types defined in ufs/ufs/dir.h. enum { kUnknownFileType = DT_UNKNOWN, kFlatFileType = DT_REG, kDirectoryFileType = DT_DIR, kLinkFileType = DT_LNK }; static long GetFileInfo( char * dirSpec, char * name, long * flags, long * time ) { struct dirstuff * dir; struct direct * entry = 0; dir = opendir(dirSpec); if ( dir ) { while (( entry = readdir(dir) )) { if ( strcmp( entry->d_name, name ) == 0 ) { *flags = entry->d_type; *time = 0; break; } } closedir(dir); } return ( entry ) ? 0 : -1; } // Map BootX types to boot counterparts. #define gBootFileType gBootDev enum { kNetworkDeviceType = kBootDevNetwork, kBlockDeviceType = kBootDevHardDisk }; static struct dirstuff * OpenDir( char * dirSpec ) { return opendir(dirSpec); } static void CloseDir( struct dirstuff * dirStuff ) { closedir(dirStuff); } static long GetDirEntry( struct dirstuff * dir, long * dirIndex, char ** name, long * flags, long * time) { if ( dir ) { struct direct * entry = readdir(dir); if ( entry ) { *name = entry->d_name; *flags = entry->d_type; *time = 0; return 0; } } return (-1); } static long InitDriverSupport() { gExtensionsSpec = (char *) malloc( 4096 ); gDriverSpec = (char *) malloc( 4096 ); gFileSpec = (char *) malloc( 4096 ); if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec ) stop( "InitDriverSupport error" ); gImageLastKernelAddr = RoundPage( kernBootStruct->kaddr + kernBootStruct->ksize ); gImageFirstBootXAddr = ( KERNEL_ADDR + KERNEL_LEN ); return 0; } static unsigned long Alder32( unsigned char * buffer, long length ) { long cnt; unsigned long result, lowHalf, highHalf; lowHalf = 1; highHalf = 0; for ( cnt = 0; cnt < length; cnt++ ) { if ((cnt % 5000) == 0) { lowHalf %= 65521L; highHalf %= 65521L; } lowHalf += buffer[cnt]; highHalf += lowHalf; } lowHalf %= 65521L; highHalf %= 65521L; result = (highHalf << 16) | lowHalf; return result; } //========================================================================== // LoadDrivers long LoadDrivers( char * dirSpec ) { if ( InitDriverSupport() != 0 ) return 0; if ( gBootFileType == kNetworkDeviceType ) { NetLoadDrivers(dirSpec); } else /* if ( gBootFileType == kBlockDeviceType ) */ { strcpy(gExtensionsSpec, dirSpec); strcat(gExtensionsSpec, "System/Library/"); FileLoadDrivers(gExtensionsSpec, 0); } #if 0 else { return 0; } #endif MatchPersonalities(); MatchLibraries(); LoadMatchedModules(); return 0; } //========================================================================== // FileLoadDrivers static long FileLoadDrivers( char * dirSpec, long plugin ) { long ret, length, index, flags, time; char * name; struct dirstuff * dir; if ( !plugin ) { long time2; ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time); if ((ret == 0) && (flags == kFlatFileType)) { ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2); if ((ret != 0) || (flags == kDirectoryFileType) || (time > time2)) { sprintf(gDriverSpec, "%sExtensions.mkext", dirSpec); verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec); if (LoadDriverMKext(gDriverSpec) == 0) return 0; } } strcat(dirSpec, "Extensions"); } verbose("LoadDrivers: Loading from [%s]\n", dirSpec); // INTEL addition dir = OpenDir( dirSpec ); index = 0; while (1) { // INTEL modification ret = GetDirEntry(dir, &index, &name, &flags, &time); if (ret == -1) break; // Make sure this is a directory. if (flags != kDirectoryFileType) continue; // Make sure this is a kext. length = strlen(name); if (strcmp(name + length - 5, ".kext")) continue; if (!plugin) sprintf(gDriverSpec, "%s/%s/Contents/PlugIns", dirSpec, name); ret = LoadDriverPList(dirSpec, name); if (ret != 0) { // printf("LoadDrivers: failed\n"); } if (!plugin) ret = FileLoadDrivers(gDriverSpec, 1); } // INTEL addition if ( dir ) CloseDir( dir ); return 0; } //========================================================================== // static long NetLoadDrivers( char * dirSpec ) { long tries; #if 0 long cnt; // Get the name of the kernel cnt = strlen(gBootFile); while (cnt--) { if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) { cnt++; break; } } #endif // INTEL modification sprintf(gDriverSpec, "%s%s.mkext", dirSpec, kernBootStruct->bootFile); verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec); tries = 3; while (tries--) { if (LoadDriverMKext(gDriverSpec) == 0) break; } if (tries == -1) return -1; return 0; } //========================================================================== // loadDriverMKext static long LoadDriverMKext( char * fileSpec ) { long driversAddr, driversLength; char segName[32]; DriversPackage * package = (DriversPackage *)kLoadAddr; #define GetPackageElement(e) bswap32(package-> ## e) // Load the MKext. if (LoadFile(fileSpec) == -1) return -1; // Verify the MKext. if (( GetPackageElement(signature1) != kDriverPackageSignature1) || ( GetPackageElement(signature2) != kDriverPackageSignature2) || ( GetPackageElement(length) > kLoadSize ) || ( GetPackageElement(alder32) != Alder32((char *)&package->version, GetPackageElement(length) - 0x10) ) ) { return -1; } // Make space for the MKext. driversLength = GetPackageElement(length); driversAddr = AllocateKernelMemory(driversLength); // Copy the MKext. memcpy((void *)driversAddr, (void *)kLoadAddr, driversLength); // Add the MKext to the memory map. sprintf(segName, "DriversPackage-%lx", driversAddr); AllocateMemoryRange(segName, driversAddr, driversLength, kBootDriverTypeMKEXT); return 0; } //========================================================================== // LoadDriverPList static long LoadDriverPList( char * dirSpec, char * name ) { long length, driverPathLength; ModulePtr module; TagPtr personalities; char * buffer = 0; char * tmpDriverPath = 0; long ret = -1; do { // Save the driver path. sprintf(gFileSpec, "%s/%s/Contents/MacOS/", dirSpec, name); driverPathLength = strlen(gFileSpec); tmpDriverPath = malloc(driverPathLength + 1); if (tmpDriverPath == 0) break; strcpy(tmpDriverPath, gFileSpec); // Construct the file spec to the plist, then load it. sprintf(gFileSpec, "%s/%s/Contents/Info.plist", dirSpec, name); length = LoadFile(gFileSpec); if (length == -1) break; buffer = malloc(length + 1); if (buffer == 0) break; strncpy(buffer, (char *)kLoadAddr, length); // Parse the plist. ret = ParseXML(buffer, &module, &personalities); if (ret != 0) break; // Allocate memory for the driver path and the plist. module->driverPath = AllocateBootXMemory(driverPathLength + 1); module->plistAddr = AllocateBootXMemory(length + 1); if ((module->driverPath == 0) || (module->plistAddr == 0)) break; // Save the driver path in the module. strcpy(module->driverPath, tmpDriverPath); // Add the plist to the module. strncpy(module->plistAddr, (char *)kLoadAddr, length); module->plistLength = length + 1; // Add the module to the end of the module list. if (gModuleHead == 0) gModuleHead = module; else gModuleTail->nextModule = module; gModuleTail = module; // Add the persionalities to the personality list. if (personalities) personalities = personalities->tag; while (personalities != 0) { if (gPersonalityHead == 0) gPersonalityHead = personalities->tag; else gPersonalityTail->tagNext = personalities->tag; gPersonalityTail = personalities->tag; personalities = personalities->tagNext; } ret = 0; } while (0); if ( buffer ) free( buffer ); if ( tmpDriverPath ) free( tmpDriverPath ); return ret; } //========================================================================== // LoadMatchedModules static long LoadMatchedModules( void ) { TagPtr prop; ModulePtr module; char *fileName, segName[32]; DriverInfoPtr driver; long length, driverAddr, driverLength; module = gModuleHead; while (module != 0) { if (module->willLoad) { prop = GetProperty(module->dict, kPropCFBundleExecutable); if (prop != 0) { fileName = prop->string; sprintf(gFileSpec, "%s%s", module->driverPath, fileName); length = LoadFile(gFileSpec); } else length = 0; if (length != -1) { // Make make in the image area. driverLength = sizeof(DriverInfo) + module->plistLength + length; driverAddr = AllocateKernelMemory(driverLength); // Set up the DriverInfo. driver = (DriverInfoPtr)driverAddr; driver->plistAddr = (char *)(driverAddr + sizeof(DriverInfo)); driver->plistLength = module->plistLength; if (length != 0) { driver->moduleAddr = (void *)(driverAddr + sizeof(DriverInfo) + module->plistLength); driver->moduleLength = length; } else { driver->moduleAddr = 0; driver->moduleLength = 0; } // Save the plist and module. strcpy(driver->plistAddr, module->plistAddr); if (length != 0) { memcpy(driver->moduleAddr, (void *)kLoadAddr, driver->moduleLength); } // Add an entry to the memory map. sprintf(segName, "Driver-%lx", (unsigned long)driver); AllocateMemoryRange(segName, driverAddr, driverLength, kBootDriverTypeKEXT); } } module = module->nextModule; } return 0; } //========================================================================== // MatchPersonalities static long MatchPersonalities( void ) { #warning IONameMatch support not implemented return 0; } //========================================================================== // MatchLibraries static long MatchLibraries( void ) { TagPtr prop, prop2; ModulePtr module, module2; long done; do { done = 1; module = gModuleHead; while (module != 0) { if (module->willLoad == 1) { prop = GetProperty(module->dict, kPropOSBundleLibraries); if (prop != 0) { prop = prop->tag; while (prop != 0) { module2 = gModuleHead; while (module2 != 0) { prop2 = GetProperty(module2->dict, kPropCFBundleIdentifier); if ((prop2 != 0) && (!strcmp(prop->string, prop2->string))) { if (module2->willLoad == 0) module2->willLoad = 1; break; } module2 = module2->nextModule; } prop = prop->tagNext; } } module->willLoad = 2; done = 0; } module = module->nextModule; } } while (!done); return 0; } //========================================================================== // GetProperty static TagPtr GetProperty( TagPtr dict, char * key ) { TagPtr tagList, tag; if (dict->type != kTagTypeDict) return 0; 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 0; } //========================================================================== // FindModule #if NOTDEF static ModulePtr FindModule( char * name ) { ModulePtr module; TagPtr prop; module = gModuleHead; while (module != 0) { prop = GetProperty(module->dict, kPropCFBundleIdentifier); if ((prop != 0) && !strcmp(name, prop->string)) break; module = module->nextModule; } return module; } #endif /* NOTDEF */ //========================================================================== // ParseXML static long ParseXML( char * buffer, ModulePtr * module, TagPtr * personalities ) { long length, pos; TagPtr moduleDict, required; ModulePtr tmpModule; pos = 0; while (1) { length = ParseNextTag(buffer + pos, &moduleDict); if (length == -1) break; pos += length; if (moduleDict == 0) continue; if (moduleDict->type == kTagTypeDict) break; FreeTag(moduleDict); } if (length == -1) return -1; required = GetProperty(moduleDict, kPropOSBundleRequired); if ( (required == 0) || (required->type != kTagTypeString) || !strcmp(required->string, "Safe Boot")) { FreeTag(moduleDict); return -2; } tmpModule = AllocateBootXMemory(sizeof(Module)); if (tmpModule == 0) { FreeTag(moduleDict); return -1; } tmpModule->dict = moduleDict; // For now, load any module that has OSBundleRequired != "Safe Boot". tmpModule->willLoad = 1; *module = tmpModule; // Get the personalities. *personalities = GetProperty(moduleDict, kPropIOKitPersonalities); return 0; } //========================================================================== // ParseNextTag static long ParseNextTag( char * buffer, TagPtr * tag ) { long length, pos; char * tagName; length = GetNextTag(buffer, &tagName, 0); if (length == -1) return -1; pos = length; if (!strncmp(tagName, kXMLTagPList, 6)) { length = 0; } else if (!strcmp(tagName, kXMLTagDict)) { length = ParseTagList(buffer + pos, tag, kTagTypeDict, 0); } else if (!strcmp(tagName, kXMLTagDict "/")) { length = ParseTagList(buffer + pos, tag, kTagTypeDict, 1); } else if (!strcmp(tagName, kXMLTagKey)) { length = ParseTagKey(buffer + pos, tag); } else if (!strcmp(tagName, kXMLTagString)) { length = ParseTagString(buffer + pos, tag); } else if (!strcmp(tagName, kXMLTagInteger)) { length = ParseTagInteger(buffer + pos, tag); } else if (!strcmp(tagName, kXMLTagData)) { length = ParseTagData(buffer + pos, tag); } else if (!strcmp(tagName, kXMLTagDate)) { length = ParseTagDate(buffer + pos, tag); } else if (!strcmp(tagName, kXMLTagFalse)) { length = ParseTagBoolean(buffer + pos, tag, kTagTypeFalse); } else if (!strcmp(tagName, kXMLTagTrue)) { length = ParseTagBoolean(buffer + pos, tag, kTagTypeTrue); } else if (!strcmp(tagName, kXMLTagArray)) { length = ParseTagList(buffer + pos, tag, kTagTypeArray, 0); } else if (!strcmp(tagName, kXMLTagArray "/")) { length = ParseTagList(buffer + pos, tag, kTagTypeArray, 1); } else { *tag = 0; length = 0; } if (length == -1) return -1; return pos + length; } //========================================================================== // ParseTagList static long ParseTagList( char * buffer, TagPtr * tag, long type, long empty ) { long length, pos; TagPtr tagList, tmpTag; tagList = 0; pos = 0; if (!empty) { while (1) { length = ParseNextTag(buffer + pos, &tmpTag); if (length == -1) break; pos += length; if (tmpTag == 0) break; tmpTag->tagNext = tagList; tagList = tmpTag; } if (length == -1) { FreeTag(tagList); return -1; } } tmpTag = NewTag(); if (tmpTag == 0) { FreeTag(tagList); return -1; } tmpTag->type = type; tmpTag->string = 0; tmpTag->tag = tagList; tmpTag->tagNext = 0; *tag = tmpTag; return pos; } //========================================================================== // ParseTagKey static long ParseTagKey( char * buffer, TagPtr * tag ) { long length, length2; char *string; TagPtr tmpTag, subTag; length = FixDataMatchingTag(buffer, kXMLTagKey); if (length == -1) return -1; length2 = ParseNextTag(buffer + length, &subTag); if (length2 == -1) return -1; tmpTag = NewTag(); if (tmpTag == 0) { FreeTag(subTag); return -1; } string = NewSymbol(buffer); if (string == 0) { FreeTag(subTag); FreeTag(tmpTag); return -1; } tmpTag->type = kTagTypeKey; tmpTag->string = string; tmpTag->tag = subTag; tmpTag->tagNext = 0; *tag = tmpTag; return length + length2; } //========================================================================== // ParseTagString static long ParseTagString( char * buffer, TagPtr * tag ) { long length; char * string; TagPtr tmpTag; length = FixDataMatchingTag(buffer, kXMLTagString); if (length == -1) return -1; tmpTag = NewTag(); if (tmpTag == 0) return -1; string = NewSymbol(buffer); if (string == 0) { FreeTag(tmpTag); return -1; } tmpTag->type = kTagTypeString; tmpTag->string = string; tmpTag->tag = 0; tmpTag->tagNext = 0; *tag = tmpTag; return length; } //========================================================================== // ParseTagInteger static long ParseTagInteger( char * buffer, TagPtr * tag ) { long length, integer; TagPtr tmpTag; length = FixDataMatchingTag(buffer, kXMLTagInteger); if (length == -1) return -1; tmpTag = NewTag(); if (tmpTag == 0) return -1; integer = 0; tmpTag->type = kTagTypeInteger; tmpTag->string = (char *)integer; tmpTag->tag = 0; tmpTag->tagNext = 0; *tag = tmpTag; return length; } //========================================================================== // ParseTagData static long ParseTagData( char * buffer, TagPtr * tag ) { long length; TagPtr tmpTag; length = FixDataMatchingTag(buffer, kXMLTagData); if (length == -1) return -1; tmpTag = NewTag(); if (tmpTag == 0) return -1; tmpTag->type = kTagTypeData; tmpTag->string = 0; tmpTag->tag = 0; tmpTag->tagNext = 0; *tag = tmpTag; return length; } //========================================================================== // ParseTagDate static long ParseTagDate( char * buffer, TagPtr * tag ) { long length; TagPtr tmpTag; length = FixDataMatchingTag(buffer, kXMLTagDate); if (length == -1) return -1; tmpTag = NewTag(); if (tmpTag == 0) return -1; tmpTag->type = kTagTypeDate; tmpTag->string = 0; tmpTag->tag = 0; tmpTag->tagNext = 0; *tag = tmpTag; return length; } //========================================================================== // ParseTagBoolean static long ParseTagBoolean( char * buffer, TagPtr * tag, long type ) { TagPtr tmpTag; tmpTag = NewTag(); if (tmpTag == 0) return -1; tmpTag->type = type; tmpTag->string = 0; tmpTag->tag = 0; tmpTag->tagNext = 0; *tag = tmpTag; return 0; } //========================================================================== // GetNextTag static long GetNextTag( char * buffer, char ** tag, long * start ) { long cnt, cnt2; if (tag == 0) 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 static long FixDataMatchingTag( char * buffer, char * tag ) { long length, start, 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; static TagPtr NewTag( void ) { long cnt; TagPtr tag; if (gTagsFree == 0) { tag = (TagPtr)AllocateBootXMemory(kTagsPerBlock * sizeof(Tag)); if (tag == 0) return 0; // Initalize the new tags. for (cnt = 0; cnt < kTagsPerBlock; cnt++) { tag[cnt].type = kTagTypeNone; tag[cnt].string = 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; } //========================================================================== // FreeTag static void FreeTag( TagPtr tag ) { return; if (tag == 0) return; if (tag->string) FreeSymbol(tag->string); FreeTag(tag->tag); FreeTag(tag->tagNext); // Clear and free the tag. tag->type = kTagTypeNone; tag->string = 0; tag->tag = 0; tag->tagNext = gTagsFree; gTagsFree = tag; } //========================================================================== // Symbol object. struct Symbol { long refCount; struct Symbol *next; char string[1]; }; typedef struct Symbol Symbol, *SymbolPtr; static SymbolPtr FindSymbol(char * string, SymbolPtr * prevSymbol); static SymbolPtr gSymbolsHead; //========================================================================== // NewSymbol static char * NewSymbol( char * string ) { SymbolPtr symbol; // Look for string in the list of symbols. symbol = FindSymbol(string, 0); // Add the new symbol. if (symbol == 0) { symbol = AllocateBootXMemory(sizeof(Symbol) + strlen(string)); if (symbol == 0) return 0; // 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++; return symbol->string; } //========================================================================== // FreeSymbol static void FreeSymbol( char * string ) { #if 0 SymbolPtr symbol, prev; // Look for string in the list of symbols. symbol = FindSymbol(string, &prev); if (symbol == 0) return; // Update the refCount. symbol->refCount--; if (symbol->refCount != 0) return; // Remove the symbol from the list. if (prev != 0) 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; symbol = gSymbolsHead; prev = 0; while (symbol != 0) { if (!strcmp(symbol->string, string)) break; prev = symbol; symbol = symbol->next; } if ((symbol != 0) && (prevSymbol != 0)) *prevSymbol = prev; return symbol; }