]> git.saurik.com Git - apple/boot.git/blob - i386/boot2/drivers.c
boot-83.2.tar.gz
[apple/boot.git] / i386 / boot2 / drivers.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * drivers.c - Driver Loading Functions.
26 *
27 * Copyright (c) 2000 Apple Computer, Inc.
28 *
29 * DRI: Josh de Cesare
30 */
31
32 #include "libsaio.h"
33 #include "memory.h"
34 #include "kernBootStruct.h"
35 #include "nbp.h"
36 #include "boot.h"
37
38 enum {
39 kTagTypeNone = 0,
40 kTagTypeDict,
41 kTagTypeKey,
42 kTagTypeString,
43 kTagTypeInteger,
44 kTagTypeData,
45 kTagTypeDate,
46 kTagTypeFalse,
47 kTagTypeTrue,
48 kTagTypeArray
49 };
50
51 #define kXMLTagPList "plist "
52 #define kXMLTagDict "dict"
53 #define kXMLTagKey "key"
54 #define kXMLTagString "string"
55 #define kXMLTagInteger "integer"
56 #define kXMLTagData "data"
57 #define kXMLTagDate "date"
58 #define kXMLTagFalse "false/"
59 #define kXMLTagTrue "true/"
60 #define kXMLTagArray "array"
61
62 #define kPropCFBundleIdentifier ("CFBundleIdentifier")
63 #define kPropCFBundleExecutable ("CFBundleExecutable")
64 #define kPropOSBundleRequired ("OSBundleRequired")
65 #define kPropOSBundleLibraries ("OSBundleLibraries")
66 #define kPropIOKitPersonalities ("IOKitPersonalities")
67 #define kPropIONameMatch ("IONameMatch")
68
69 struct Tag {
70 long type;
71 char *string;
72 struct Tag *tag;
73 struct Tag *tagNext;
74 };
75 typedef struct Tag Tag, *TagPtr;
76
77 struct Module {
78 struct Module *nextModule;
79 long willLoad;
80 TagPtr dict;
81 char *plistAddr;
82 long plistLength;
83 char *driverPath;
84 };
85 typedef struct Module Module, *ModulePtr;
86
87 struct DriverInfo {
88 char *plistAddr;
89 long plistLength;
90 void *moduleAddr;
91 long moduleLength;
92 };
93 typedef struct DriverInfo DriverInfo, *DriverInfoPtr;
94
95 #define kDriverPackageSignature1 'MKXT'
96 #define kDriverPackageSignature2 'MOSX'
97
98 struct DriversPackage {
99 unsigned long signature1;
100 unsigned long signature2;
101 unsigned long length;
102 unsigned long alder32;
103 unsigned long version;
104 unsigned long numDrivers;
105 unsigned long reserved1;
106 unsigned long reserved2;
107 };
108 typedef struct DriversPackage DriversPackage;
109
110 static long FileLoadDrivers(char *dirSpec, long plugin);
111 static long NetLoadDrivers(char *dirSpec);
112 static long LoadDriverMKext(char *fileSpec);
113 static long LoadDriverPList(char *dirSpec, char *name);
114 static long LoadMatchedModules(void);
115 static long MatchPersonalities(void);
116 static long MatchLibraries(void);
117 static TagPtr GetProperty(TagPtr dict, char *key);
118 // static ModulePtr FindModule(char *name);
119 static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities);
120 static long ParseNextTag(char *buffer, TagPtr *tag);
121 static long ParseTagList(char *buffer, TagPtr *tag, long type, long empty);
122 static long ParseTagKey(char *buffer, TagPtr *tag);
123 static long ParseTagString(char *buffer, TagPtr *tag);
124 static long ParseTagInteger(char *buffer, TagPtr *tag);
125 static long ParseTagData(char *buffer, TagPtr *tag);
126 static long ParseTagDate(char *buffer, TagPtr *tag);
127 static long ParseTagBoolean(char *buffer, TagPtr *tag, long type);
128 static long GetNextTag(char *buffer, char **tag, long *start);
129 static long FixDataMatchingTag(char *buffer, char *tag);
130 static TagPtr NewTag(void);
131 static void FreeTag(TagPtr tag);
132 static char *NewSymbol(char *string);
133 static void FreeSymbol(char *string);
134 // static void DumpTag(TagPtr tag, long depth);
135
136 static ModulePtr gModuleHead, gModuleTail;
137 static TagPtr gPersonalityHead, gPersonalityTail;
138 static char * gExtensionsSpec;
139 static char * gDriverSpec;
140 static char * gFileSpec;
141
142 //==========================================================================
143 // BootX shim functions.
144
145 #include <ufs/ufs/dir.h>
146
147 #define kLoadAddr TFTP_ADDR
148 #define kLoadSize TFTP_LEN
149
150 #define kPageSize 4096
151 #define RoundPage(x) ((((unsigned)(x)) + kPageSize - 1) & ~(kPageSize - 1))
152
153 static long
154 LoadFile( char * fileSpec )
155 {
156 unsigned long count = TFTP_LEN;
157 unsigned long addr = TFTP_ADDR;
158
159 if ( gBootDev == kBootDevNetwork )
160 {
161 if ( nbpTFTPReadFile(fileSpec, &count, addr) != nbpStatusSuccess )
162 return -1;
163 }
164 else
165 {
166 int fd = open( fileSpec, 0 );
167 if ( fd < 0 )
168 return -1;
169
170 count = read( fd, (char *) addr, count );
171 close(fd);
172 }
173 return count;
174 }
175
176 static long gImageFirstBootXAddr;
177 static long gImageLastKernelAddr;
178
179 static void *
180 AllocateBootXMemory( long size )
181 {
182 long addr = gImageFirstBootXAddr - size;
183
184 if ( addr < gImageLastKernelAddr ) return 0;
185
186 bzero(addr, size);
187
188 gImageFirstBootXAddr = addr;
189
190 return (void *)addr;
191 }
192
193 static long
194 AllocateKernelMemory( long inSize )
195 {
196 long addr = gImageLastKernelAddr;
197
198 gImageLastKernelAddr += RoundPage(inSize);
199
200 if ( gImageLastKernelAddr > gImageFirstBootXAddr )
201 stop( "AllocateKernelMemory error" );
202
203 kernBootStruct->ksize = gImageLastKernelAddr - kernBootStruct->kaddr;
204
205 return addr;
206 }
207
208 static long
209 AllocateMemoryRange(char * rangeName, long start, long length, long type)
210 {
211 if ( kernBootStruct->numBootDrivers < NDRIVERS )
212 {
213 int num = kernBootStruct->numBootDrivers;
214
215 kernBootStruct->driverConfig[num].address = start;
216 kernBootStruct->driverConfig[num].size = length;
217 kernBootStruct->driverConfig[num].type = type;
218 kernBootStruct->numBootDrivers++;
219 }
220 else
221 {
222 stop( "AllocateMemoryRange error" );
223 }
224 return 0;
225 }
226
227 // Map BootX file types to UFS file types defined in ufs/ufs/dir.h.
228
229 enum {
230 kUnknownFileType = DT_UNKNOWN,
231 kFlatFileType = DT_REG,
232 kDirectoryFileType = DT_DIR,
233 kLinkFileType = DT_LNK
234 };
235
236 static long
237 GetFileInfo( char * dirSpec, char * name, long * flags, long * time )
238 {
239 struct dirstuff * dir;
240 struct direct * entry = 0;
241
242 dir = opendir(dirSpec);
243 if ( dir )
244 {
245 while (( entry = readdir(dir) ))
246 {
247 if ( strcmp( entry->d_name, name ) == 0 )
248 {
249 *flags = entry->d_type;
250 *time = 0;
251 break;
252 }
253 }
254 closedir(dir);
255 }
256 return ( entry ) ? 0 : -1;
257 }
258
259 // Map BootX types to boot counterparts.
260
261 #define gBootFileType gBootDev
262 enum {
263 kNetworkDeviceType = kBootDevNetwork,
264 kBlockDeviceType = kBootDevHardDisk
265 };
266
267 static struct dirstuff *
268 OpenDir( char * dirSpec )
269 {
270 return opendir(dirSpec);
271 }
272
273 static void
274 CloseDir( struct dirstuff * dirStuff )
275 {
276 closedir(dirStuff);
277 }
278
279 static long
280 GetDirEntry( struct dirstuff * dir, long * dirIndex, char ** name,
281 long * flags, long * time)
282 {
283 if ( dir )
284 {
285 struct direct * entry = readdir(dir);
286
287 if ( entry )
288 {
289 *name = entry->d_name;
290 *flags = entry->d_type;
291 *time = 0;
292 return 0;
293 }
294 }
295 return (-1);
296 }
297
298 static long
299 InitDriverSupport()
300 {
301 gExtensionsSpec = (char *) malloc( 4096 );
302 gDriverSpec = (char *) malloc( 4096 );
303 gFileSpec = (char *) malloc( 4096 );
304
305 if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec )
306 stop( "InitDriverSupport error" );
307
308 gImageLastKernelAddr = RoundPage( kernBootStruct->kaddr +
309 kernBootStruct->ksize );
310
311 gImageFirstBootXAddr = ( KERNEL_ADDR + KERNEL_LEN );
312
313 return 0;
314 }
315
316 static unsigned long
317 Alder32( unsigned char * buffer, long length )
318 {
319 long cnt;
320 unsigned long result, lowHalf, highHalf;
321
322 lowHalf = 1;
323 highHalf = 0;
324
325 for ( cnt = 0; cnt < length; cnt++ )
326 {
327 if ((cnt % 5000) == 0)
328 {
329 lowHalf %= 65521L;
330 highHalf %= 65521L;
331 }
332
333 lowHalf += buffer[cnt];
334 highHalf += lowHalf;
335 }
336
337 lowHalf %= 65521L;
338 highHalf %= 65521L;
339
340 result = (highHalf << 16) | lowHalf;
341
342 return result;
343 }
344
345 //==========================================================================
346 // LoadDrivers
347
348 long LoadDrivers( char * dirSpec )
349 {
350 if ( InitDriverSupport() != 0 )
351 return 0;
352
353 if ( gBootFileType == kNetworkDeviceType )
354 {
355 NetLoadDrivers(dirSpec);
356 }
357 else /* if ( gBootFileType == kBlockDeviceType ) */
358 {
359 strcpy(gExtensionsSpec, dirSpec);
360 strcat(gExtensionsSpec, "System/Library/");
361 FileLoadDrivers(gExtensionsSpec, 0);
362 }
363 #if 0
364 else
365 {
366 return 0;
367 }
368 #endif
369
370 MatchPersonalities();
371
372 MatchLibraries();
373
374 LoadMatchedModules();
375
376 return 0;
377 }
378
379 //==========================================================================
380 // FileLoadDrivers
381
382 static long
383 FileLoadDrivers( char * dirSpec, long plugin )
384 {
385 long ret, length, index, flags, time;
386 char * name;
387 struct dirstuff * dir;
388
389 if ( !plugin )
390 {
391 long time2;
392
393 ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time);
394 if ((ret == 0) && (flags == kFlatFileType))
395 {
396 ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
397 if ((ret != 0) || (flags == kDirectoryFileType) || (time > time2))
398 {
399 sprintf(gDriverSpec, "%sExtensions.mkext", dirSpec);
400 verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec);
401 if (LoadDriverMKext(gDriverSpec) == 0) return 0;
402 }
403 }
404
405 strcat(dirSpec, "Extensions");
406 }
407
408 verbose("LoadDrivers: Loading from [%s]\n", dirSpec);
409
410 // INTEL addition
411 dir = OpenDir( dirSpec );
412
413 index = 0;
414 while (1) {
415 // INTEL modification
416 ret = GetDirEntry(dir, &index, &name, &flags, &time);
417 if (ret == -1) break;
418
419 // Make sure this is a directory.
420 if (flags != kDirectoryFileType) continue;
421
422 // Make sure this is a kext.
423 length = strlen(name);
424 if (strcmp(name + length - 5, ".kext")) continue;
425
426 if (!plugin)
427 sprintf(gDriverSpec, "%s/%s/Contents/PlugIns", dirSpec, name);
428
429 ret = LoadDriverPList(dirSpec, name);
430 if (ret != 0)
431 {
432 // printf("LoadDrivers: failed\n");
433 }
434
435 if (!plugin)
436 ret = FileLoadDrivers(gDriverSpec, 1);
437 }
438
439 // INTEL addition
440 if ( dir ) CloseDir( dir );
441
442 return 0;
443 }
444
445 //==========================================================================
446 //
447
448 static long
449 NetLoadDrivers( char * dirSpec )
450 {
451 long tries;
452
453 #if 0
454 long cnt;
455
456 // Get the name of the kernel
457 cnt = strlen(gBootFile);
458 while (cnt--) {
459 if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) {
460 cnt++;
461 break;
462 }
463 }
464 #endif
465
466 // INTEL modification
467 sprintf(gDriverSpec, "%s%s.mkext", dirSpec, kernBootStruct->bootFile);
468
469 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec);
470
471 tries = 3;
472 while (tries--)
473 {
474 if (LoadDriverMKext(gDriverSpec) == 0) break;
475 }
476 if (tries == -1) return -1;
477
478 return 0;
479 }
480
481 //==========================================================================
482 // loadDriverMKext
483
484 static long
485 LoadDriverMKext( char * fileSpec )
486 {
487 long driversAddr, driversLength;
488 char segName[32];
489 DriversPackage * package = (DriversPackage *)kLoadAddr;
490
491 #define GetPackageElement(e) bswap32(package-> ## e)
492
493 // Load the MKext.
494 if (LoadFile(fileSpec) == -1) return -1;
495
496 // Verify the MKext.
497 if (( GetPackageElement(signature1) != kDriverPackageSignature1) ||
498 ( GetPackageElement(signature2) != kDriverPackageSignature2) ||
499 ( GetPackageElement(length) > kLoadSize ) ||
500 ( GetPackageElement(alder32) !=
501 Alder32((char *)&package->version, GetPackageElement(length) - 0x10) ) )
502 {
503 return -1;
504 }
505
506 // Make space for the MKext.
507 driversLength = GetPackageElement(length);
508 driversAddr = AllocateKernelMemory(driversLength);
509
510 // Copy the MKext.
511 memcpy((void *)driversAddr, (void *)kLoadAddr, driversLength);
512
513 // Add the MKext to the memory map.
514 sprintf(segName, "DriversPackage-%lx", driversAddr);
515 AllocateMemoryRange(segName, driversAddr, driversLength,
516 kBootDriverTypeMKEXT);
517
518 return 0;
519 }
520
521 //==========================================================================
522 // LoadDriverPList
523
524 static long
525 LoadDriverPList( char * dirSpec, char * name )
526 {
527 long length, driverPathLength;
528 ModulePtr module;
529 TagPtr personalities;
530 char * buffer = 0;
531 char * tmpDriverPath = 0;
532 long ret = -1;
533
534 do {
535 // Save the driver path.
536
537 sprintf(gFileSpec, "%s/%s/Contents/MacOS/", dirSpec, name);
538 driverPathLength = strlen(gFileSpec);
539
540 tmpDriverPath = malloc(driverPathLength + 1);
541 if (tmpDriverPath == 0) break;
542
543 strcpy(tmpDriverPath, gFileSpec);
544
545 // Construct the file spec to the plist, then load it.
546
547 sprintf(gFileSpec, "%s/%s/Contents/Info.plist", dirSpec, name);
548
549 length = LoadFile(gFileSpec);
550 if (length == -1) break;
551
552 buffer = malloc(length + 1);
553 if (buffer == 0) break;
554
555 strncpy(buffer, (char *)kLoadAddr, length);
556
557 // Parse the plist.
558
559 ret = ParseXML(buffer, &module, &personalities);
560 if (ret != 0) break;
561
562 // Allocate memory for the driver path and the plist.
563
564 module->driverPath = AllocateBootXMemory(driverPathLength + 1);
565 module->plistAddr = AllocateBootXMemory(length + 1);
566
567 if ((module->driverPath == 0) || (module->plistAddr == 0))
568 break;
569
570 // Save the driver path in the module.
571
572 strcpy(module->driverPath, tmpDriverPath);
573
574 // Add the plist to the module.
575
576 strncpy(module->plistAddr, (char *)kLoadAddr, length);
577 module->plistLength = length + 1;
578
579 // Add the module to the end of the module list.
580
581 if (gModuleHead == 0)
582 gModuleHead = module;
583 else
584 gModuleTail->nextModule = module;
585 gModuleTail = module;
586
587 // Add the persionalities to the personality list.
588
589 if (personalities) personalities = personalities->tag;
590 while (personalities != 0)
591 {
592 if (gPersonalityHead == 0)
593 gPersonalityHead = personalities->tag;
594 else
595 gPersonalityTail->tagNext = personalities->tag;
596
597 gPersonalityTail = personalities->tag;
598 personalities = personalities->tagNext;
599 }
600
601 ret = 0;
602 }
603 while (0);
604
605 if ( buffer ) free( buffer );
606 if ( tmpDriverPath ) free( tmpDriverPath );
607
608 return ret;
609 }
610
611 //==========================================================================
612 // LoadMatchedModules
613
614 static long
615 LoadMatchedModules( void )
616 {
617 TagPtr prop;
618 ModulePtr module;
619 char *fileName, segName[32];
620 DriverInfoPtr driver;
621 long length, driverAddr, driverLength;
622
623 module = gModuleHead;
624
625 while (module != 0)
626 {
627 if (module->willLoad)
628 {
629 prop = GetProperty(module->dict, kPropCFBundleExecutable);
630 if (prop != 0)
631 {
632 fileName = prop->string;
633 sprintf(gFileSpec, "%s%s", module->driverPath, fileName);
634 length = LoadFile(gFileSpec);
635 }
636 else
637 length = 0;
638
639 if (length != -1)
640 {
641 // Make make in the image area.
642 driverLength = sizeof(DriverInfo) + module->plistLength + length;
643 driverAddr = AllocateKernelMemory(driverLength);
644
645 // Set up the DriverInfo.
646 driver = (DriverInfoPtr)driverAddr;
647 driver->plistAddr = (char *)(driverAddr + sizeof(DriverInfo));
648 driver->plistLength = module->plistLength;
649 if (length != 0)
650 {
651 driver->moduleAddr = (void *)(driverAddr + sizeof(DriverInfo) +
652 module->plistLength);
653 driver->moduleLength = length;
654 }
655 else
656 {
657 driver->moduleAddr = 0;
658 driver->moduleLength = 0;
659 }
660
661 // Save the plist and module.
662 strcpy(driver->plistAddr, module->plistAddr);
663 if (length != 0)
664 {
665 memcpy(driver->moduleAddr, (void *)kLoadAddr, driver->moduleLength);
666 }
667
668 // Add an entry to the memory map.
669 sprintf(segName, "Driver-%lx", (unsigned long)driver);
670 AllocateMemoryRange(segName, driverAddr, driverLength,
671 kBootDriverTypeKEXT);
672 }
673 }
674 module = module->nextModule;
675 }
676
677 return 0;
678 }
679
680 //==========================================================================
681 // MatchPersonalities
682
683 static long
684 MatchPersonalities( void )
685 {
686 #warning IONameMatch support not implemented
687 return 0;
688 }
689
690 //==========================================================================
691 // MatchLibraries
692
693 static long
694 MatchLibraries( void )
695 {
696 TagPtr prop, prop2;
697 ModulePtr module, module2;
698 long done;
699
700 do {
701 done = 1;
702 module = gModuleHead;
703
704 while (module != 0)
705 {
706 if (module->willLoad == 1)
707 {
708 prop = GetProperty(module->dict, kPropOSBundleLibraries);
709 if (prop != 0)
710 {
711 prop = prop->tag;
712 while (prop != 0)
713 {
714 module2 = gModuleHead;
715 while (module2 != 0)
716 {
717 prop2 = GetProperty(module2->dict, kPropCFBundleIdentifier);
718 if ((prop2 != 0) && (!strcmp(prop->string, prop2->string)))
719 {
720 if (module2->willLoad == 0) module2->willLoad = 1;
721 break;
722 }
723 module2 = module2->nextModule;
724 }
725 prop = prop->tagNext;
726 }
727 }
728 module->willLoad = 2;
729 done = 0;
730 }
731 module = module->nextModule;
732 }
733 }
734 while (!done);
735
736 return 0;
737 }
738
739 //==========================================================================
740 // GetProperty
741
742 static TagPtr
743 GetProperty( TagPtr dict, char * key )
744 {
745 TagPtr tagList, tag;
746
747 if (dict->type != kTagTypeDict) return 0;
748
749 tag = 0;
750 tagList = dict->tag;
751 while (tagList)
752 {
753 tag = tagList;
754 tagList = tag->tagNext;
755
756 if ((tag->type != kTagTypeKey) || (tag->string == 0)) continue;
757
758 if (!strcmp(tag->string, key)) return tag->tag;
759 }
760
761 return 0;
762 }
763
764 //==========================================================================
765 // FindModule
766
767 #if NOTDEF
768 static ModulePtr
769 FindModule( char * name )
770 {
771 ModulePtr module;
772 TagPtr prop;
773
774 module = gModuleHead;
775
776 while (module != 0)
777 {
778 prop = GetProperty(module->dict, kPropCFBundleIdentifier);
779 if ((prop != 0) && !strcmp(name, prop->string)) break;
780 module = module->nextModule;
781 }
782
783 return module;
784 }
785 #endif /* NOTDEF */
786
787 //==========================================================================
788 // ParseXML
789
790 static long
791 ParseXML( char * buffer, ModulePtr * module, TagPtr * personalities )
792 {
793 long length, pos;
794 TagPtr moduleDict, required;
795 ModulePtr tmpModule;
796
797 pos = 0;
798
799 while (1)
800 {
801 length = ParseNextTag(buffer + pos, &moduleDict);
802 if (length == -1) break;
803
804 pos += length;
805
806 if (moduleDict == 0) continue;
807 if (moduleDict->type == kTagTypeDict) break;
808
809 FreeTag(moduleDict);
810 }
811
812 if (length == -1) return -1;
813
814 required = GetProperty(moduleDict, kPropOSBundleRequired);
815 if ( (required == 0) ||
816 (required->type != kTagTypeString) ||
817 !strcmp(required->string, "Safe Boot"))
818 {
819 FreeTag(moduleDict);
820 return -2;
821 }
822
823 tmpModule = AllocateBootXMemory(sizeof(Module));
824 if (tmpModule == 0)
825 {
826 FreeTag(moduleDict);
827 return -1;
828 }
829 tmpModule->dict = moduleDict;
830
831 // For now, load any module that has OSBundleRequired != "Safe Boot".
832
833 tmpModule->willLoad = 1;
834
835 *module = tmpModule;
836
837 // Get the personalities.
838
839 *personalities = GetProperty(moduleDict, kPropIOKitPersonalities);
840
841 return 0;
842 }
843
844 //==========================================================================
845 // ParseNextTag
846
847 static long
848 ParseNextTag( char * buffer, TagPtr * tag )
849 {
850 long length, pos;
851 char * tagName;
852
853 length = GetNextTag(buffer, &tagName, 0);
854 if (length == -1) return -1;
855
856 pos = length;
857 if (!strncmp(tagName, kXMLTagPList, 6))
858 {
859 length = 0;
860 }
861 else if (!strcmp(tagName, kXMLTagDict))
862 {
863 length = ParseTagList(buffer + pos, tag, kTagTypeDict, 0);
864 }
865 else if (!strcmp(tagName, kXMLTagDict "/"))
866 {
867 length = ParseTagList(buffer + pos, tag, kTagTypeDict, 1);
868 }
869 else if (!strcmp(tagName, kXMLTagKey))
870 {
871 length = ParseTagKey(buffer + pos, tag);
872 }
873 else if (!strcmp(tagName, kXMLTagString))
874 {
875 length = ParseTagString(buffer + pos, tag);
876 }
877 else if (!strcmp(tagName, kXMLTagInteger))
878 {
879 length = ParseTagInteger(buffer + pos, tag);
880 }
881 else if (!strcmp(tagName, kXMLTagData))
882 {
883 length = ParseTagData(buffer + pos, tag);
884 }
885 else if (!strcmp(tagName, kXMLTagDate))
886 {
887 length = ParseTagDate(buffer + pos, tag);
888 }
889 else if (!strcmp(tagName, kXMLTagFalse))
890 {
891 length = ParseTagBoolean(buffer + pos, tag, kTagTypeFalse);
892 }
893 else if (!strcmp(tagName, kXMLTagTrue))
894 {
895 length = ParseTagBoolean(buffer + pos, tag, kTagTypeTrue);
896 }
897 else if (!strcmp(tagName, kXMLTagArray))
898 {
899 length = ParseTagList(buffer + pos, tag, kTagTypeArray, 0);
900 }
901 else if (!strcmp(tagName, kXMLTagArray "/"))
902 {
903 length = ParseTagList(buffer + pos, tag, kTagTypeArray, 1);
904 }
905 else
906 {
907 *tag = 0;
908 length = 0;
909 }
910
911 if (length == -1) return -1;
912
913 return pos + length;
914 }
915
916 //==========================================================================
917 // ParseTagList
918
919 static long
920 ParseTagList( char * buffer, TagPtr * tag, long type, long empty )
921 {
922 long length, pos;
923 TagPtr tagList, tmpTag;
924
925 tagList = 0;
926 pos = 0;
927
928 if (!empty)
929 {
930 while (1)
931 {
932 length = ParseNextTag(buffer + pos, &tmpTag);
933 if (length == -1) break;
934
935 pos += length;
936
937 if (tmpTag == 0) break;
938 tmpTag->tagNext = tagList;
939 tagList = tmpTag;
940 }
941
942 if (length == -1)
943 {
944 FreeTag(tagList);
945 return -1;
946 }
947 }
948
949 tmpTag = NewTag();
950 if (tmpTag == 0)
951 {
952 FreeTag(tagList);
953 return -1;
954 }
955
956 tmpTag->type = type;
957 tmpTag->string = 0;
958 tmpTag->tag = tagList;
959 tmpTag->tagNext = 0;
960
961 *tag = tmpTag;
962
963 return pos;
964 }
965
966 //==========================================================================
967 // ParseTagKey
968
969 static long
970 ParseTagKey( char * buffer, TagPtr * tag )
971 {
972 long length, length2;
973 char *string;
974 TagPtr tmpTag, subTag;
975
976 length = FixDataMatchingTag(buffer, kXMLTagKey);
977 if (length == -1) return -1;
978
979 length2 = ParseNextTag(buffer + length, &subTag);
980 if (length2 == -1) return -1;
981
982 tmpTag = NewTag();
983 if (tmpTag == 0)
984 {
985 FreeTag(subTag);
986 return -1;
987 }
988
989 string = NewSymbol(buffer);
990 if (string == 0)
991 {
992 FreeTag(subTag);
993 FreeTag(tmpTag);
994 return -1;
995 }
996
997 tmpTag->type = kTagTypeKey;
998 tmpTag->string = string;
999 tmpTag->tag = subTag;
1000 tmpTag->tagNext = 0;
1001
1002 *tag = tmpTag;
1003
1004 return length + length2;
1005 }
1006
1007 //==========================================================================
1008 // ParseTagString
1009
1010 static long
1011 ParseTagString( char * buffer, TagPtr * tag )
1012 {
1013 long length;
1014 char * string;
1015 TagPtr tmpTag;
1016
1017 length = FixDataMatchingTag(buffer, kXMLTagString);
1018 if (length == -1) return -1;
1019
1020 tmpTag = NewTag();
1021 if (tmpTag == 0) return -1;
1022
1023 string = NewSymbol(buffer);
1024 if (string == 0)
1025 {
1026 FreeTag(tmpTag);
1027 return -1;
1028 }
1029
1030 tmpTag->type = kTagTypeString;
1031 tmpTag->string = string;
1032 tmpTag->tag = 0;
1033 tmpTag->tagNext = 0;
1034
1035 *tag = tmpTag;
1036
1037 return length;
1038 }
1039
1040 //==========================================================================
1041 // ParseTagInteger
1042
1043 static long
1044 ParseTagInteger( char * buffer, TagPtr * tag )
1045 {
1046 long length, integer;
1047 TagPtr tmpTag;
1048
1049 length = FixDataMatchingTag(buffer, kXMLTagInteger);
1050 if (length == -1) return -1;
1051
1052 tmpTag = NewTag();
1053 if (tmpTag == 0) return -1;
1054
1055 integer = 0;
1056
1057 tmpTag->type = kTagTypeInteger;
1058 tmpTag->string = (char *)integer;
1059 tmpTag->tag = 0;
1060 tmpTag->tagNext = 0;
1061
1062 *tag = tmpTag;
1063
1064 return length;
1065 }
1066
1067 //==========================================================================
1068 // ParseTagData
1069
1070 static long
1071 ParseTagData( char * buffer, TagPtr * tag )
1072 {
1073 long length;
1074 TagPtr tmpTag;
1075
1076 length = FixDataMatchingTag(buffer, kXMLTagData);
1077 if (length == -1) return -1;
1078
1079 tmpTag = NewTag();
1080 if (tmpTag == 0) return -1;
1081
1082 tmpTag->type = kTagTypeData;
1083 tmpTag->string = 0;
1084 tmpTag->tag = 0;
1085 tmpTag->tagNext = 0;
1086
1087 *tag = tmpTag;
1088
1089 return length;
1090 }
1091
1092 //==========================================================================
1093 // ParseTagDate
1094
1095 static long
1096 ParseTagDate( char * buffer, TagPtr * tag )
1097 {
1098 long length;
1099 TagPtr tmpTag;
1100
1101 length = FixDataMatchingTag(buffer, kXMLTagDate);
1102 if (length == -1) return -1;
1103
1104 tmpTag = NewTag();
1105 if (tmpTag == 0) return -1;
1106
1107 tmpTag->type = kTagTypeDate;
1108 tmpTag->string = 0;
1109 tmpTag->tag = 0;
1110 tmpTag->tagNext = 0;
1111
1112 *tag = tmpTag;
1113
1114 return length;
1115 }
1116
1117 //==========================================================================
1118 // ParseTagBoolean
1119
1120 static long
1121 ParseTagBoolean( char * buffer, TagPtr * tag, long type )
1122 {
1123 TagPtr tmpTag;
1124
1125 tmpTag = NewTag();
1126 if (tmpTag == 0) return -1;
1127
1128 tmpTag->type = type;
1129 tmpTag->string = 0;
1130 tmpTag->tag = 0;
1131 tmpTag->tagNext = 0;
1132
1133 *tag = tmpTag;
1134
1135 return 0;
1136 }
1137
1138 //==========================================================================
1139 // GetNextTag
1140
1141 static long
1142 GetNextTag( char * buffer, char ** tag, long * start )
1143 {
1144 long cnt, cnt2;
1145
1146 if (tag == 0) return -1;
1147
1148 // Find the start of the tag.
1149 cnt = 0;
1150 while ((buffer[cnt] != '\0') && (buffer[cnt] != '<')) cnt++;
1151 if (buffer[cnt] == '\0') return -1;
1152
1153 // Find the end of the tag.
1154 cnt2 = cnt + 1;
1155 while ((buffer[cnt2] != '\0') && (buffer[cnt2] != '>')) cnt2++;
1156 if (buffer[cnt2] == '\0') return -1;
1157
1158 // Fix the tag data.
1159 *tag = buffer + cnt + 1;
1160 buffer[cnt2] = '\0';
1161 if (start) *start = cnt;
1162
1163 return cnt2 + 1;
1164 }
1165
1166 //==========================================================================
1167 // FixDataMatchingTag
1168
1169 static long
1170 FixDataMatchingTag( char * buffer, char * tag )
1171 {
1172 long length, start, stop;
1173 char * endTag;
1174
1175 start = 0;
1176 while (1)
1177 {
1178 length = GetNextTag(buffer + start, &endTag, &stop);
1179 if (length == -1) return -1;
1180
1181 if ((*endTag == '/') && !strcmp(endTag + 1, tag)) break;
1182 start += length;
1183 }
1184
1185 buffer[start + stop] = '\0';
1186
1187 return start + length;
1188 }
1189
1190 //==========================================================================
1191 // NewTag
1192
1193 #define kTagsPerBlock (0x1000)
1194
1195 static TagPtr gTagsFree;
1196
1197 static TagPtr
1198 NewTag( void )
1199 {
1200 long cnt;
1201 TagPtr tag;
1202
1203 if (gTagsFree == 0)
1204 {
1205 tag = (TagPtr)AllocateBootXMemory(kTagsPerBlock * sizeof(Tag));
1206 if (tag == 0) return 0;
1207
1208 // Initalize the new tags.
1209 for (cnt = 0; cnt < kTagsPerBlock; cnt++)
1210 {
1211 tag[cnt].type = kTagTypeNone;
1212 tag[cnt].string = 0;
1213 tag[cnt].tag = 0;
1214 tag[cnt].tagNext = tag + cnt + 1;
1215 }
1216 tag[kTagsPerBlock - 1].tagNext = 0;
1217
1218 gTagsFree = tag;
1219 }
1220
1221 tag = gTagsFree;
1222 gTagsFree = tag->tagNext;
1223
1224 return tag;
1225 }
1226
1227 //==========================================================================
1228 // FreeTag
1229
1230 static void
1231 FreeTag( TagPtr tag )
1232 {
1233 return;
1234 if (tag == 0) return;
1235
1236 if (tag->string) FreeSymbol(tag->string);
1237
1238 FreeTag(tag->tag);
1239 FreeTag(tag->tagNext);
1240
1241 // Clear and free the tag.
1242 tag->type = kTagTypeNone;
1243 tag->string = 0;
1244 tag->tag = 0;
1245 tag->tagNext = gTagsFree;
1246 gTagsFree = tag;
1247 }
1248
1249 //==========================================================================
1250 // Symbol object.
1251
1252 struct Symbol
1253 {
1254 long refCount;
1255 struct Symbol *next;
1256 char string[1];
1257 };
1258 typedef struct Symbol Symbol, *SymbolPtr;
1259
1260 static SymbolPtr FindSymbol(char * string, SymbolPtr * prevSymbol);
1261
1262 static SymbolPtr gSymbolsHead;
1263
1264 //==========================================================================
1265 // NewSymbol
1266
1267 static char *
1268 NewSymbol( char * string )
1269 {
1270 SymbolPtr symbol;
1271
1272 // Look for string in the list of symbols.
1273 symbol = FindSymbol(string, 0);
1274
1275 // Add the new symbol.
1276 if (symbol == 0)
1277 {
1278 symbol = AllocateBootXMemory(sizeof(Symbol) + strlen(string));
1279 if (symbol == 0) return 0;
1280
1281 // Set the symbol's data.
1282 symbol->refCount = 0;
1283 strcpy(symbol->string, string);
1284
1285 // Add the symbol to the list.
1286 symbol->next = gSymbolsHead;
1287 gSymbolsHead = symbol;
1288 }
1289
1290 // Update the refCount and return the string.
1291 symbol->refCount++;
1292 return symbol->string;
1293 }
1294
1295 //==========================================================================
1296 // FreeSymbol
1297
1298 static void
1299 FreeSymbol( char * string )
1300 {
1301 #if 0
1302 SymbolPtr symbol, prev;
1303
1304 // Look for string in the list of symbols.
1305 symbol = FindSymbol(string, &prev);
1306 if (symbol == 0) return;
1307
1308 // Update the refCount.
1309 symbol->refCount--;
1310
1311 if (symbol->refCount != 0) return;
1312
1313 // Remove the symbol from the list.
1314 if (prev != 0) prev->next = symbol->next;
1315 else gSymbolsHead = symbol->next;
1316
1317 // Free the symbol's memory.
1318 free(symbol);
1319 #endif
1320 }
1321
1322 //==========================================================================
1323 // FindSymbol
1324
1325 static SymbolPtr
1326 FindSymbol( char * string, SymbolPtr * prevSymbol )
1327 {
1328 SymbolPtr symbol, prev;
1329
1330 symbol = gSymbolsHead;
1331 prev = 0;
1332
1333 while (symbol != 0)
1334 {
1335 if (!strcmp(symbol->string, string)) break;
1336
1337 prev = symbol;
1338 symbol = symbol->next;
1339 }
1340
1341 if ((symbol != 0) && (prevSymbol != 0)) *prevSymbol = prev;
1342
1343 return symbol;
1344 }