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