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