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