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