2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
26 * drivers.c - Driver Loading Functions.
28 * Copyright (c) 2000 Apple Computer, Inc.
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"
59 #define kPropCFBundleIdentifier ("CFBundleIdentifier")
60 #define kPropCFBundleExecutable ("CFBundleExecutable")
61 #define kPropOSBundleRequired ("OSBundleRequired")
62 #define kPropOSBundleLibraries ("OSBundleLibraries")
63 #define kPropIOKitPersonalities ("IOKitPersonalities")
64 #define kPropIONameMatch ("IONameMatch")
72 typedef struct Tag Tag
, *TagPtr
;
75 struct Module
*nextModule
;
82 typedef struct Module Module
, *ModulePtr
;
90 typedef struct DriverInfo DriverInfo
, *DriverInfoPtr
;
92 #define kDriverPackageSignature1 'MKXT'
93 #define kDriverPackageSignature2 'MOSX'
95 struct DriversPackage
{
96 unsigned long signature1
;
97 unsigned long signature2
;
99 unsigned long alder32
;
100 unsigned long version
;
101 unsigned long numDrivers
;
102 unsigned long reserved1
;
103 unsigned long reserved2
;
105 typedef struct DriversPackage DriversPackage
;
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
);
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];
148 long LoadDrivers(char *dirSpec
)
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);
160 MatchPersonalities();
164 LoadMatchedModules();
171 static long FileLoadDrivers(char *dirSpec
, long plugin
)
173 long ret
, length
, index
, flags
, time
, time2
, bundleType
;
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;
188 strcat(dirSpec
, "Extensions");
191 printf("LoadDrivers: Loading from [%s]\n", dirSpec
);
195 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
196 if (ret
== -1) break;
198 // Make sure this is a directory.
199 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
201 // Make sure this is a kext.
202 length
= strlen(name
);
203 if (strcmp(name
+ length
- 5, ".kext")) continue;
205 // Save the file name.
206 strcpy(gFileName
, name
);
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
;
215 sprintf(gDriverSpec
, "%s\\%s\\%sPlugIns", dirSpec
, gFileName
,
216 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
219 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
221 printf("LoadDrivers: failed\n");
225 ret
= FileLoadDrivers(gDriverSpec
, 1);
233 static long NetLoadDrivers(char *dirSpec
)
237 // Get the name of the kernel
238 cnt
= strlen(gBootFile
);
240 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
246 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, gBootFile
+ cnt
);
248 printf("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
252 if (LoadDriverMKext(gDriverSpec
) == 0) break;
254 if (tries
== -1) return -1;
260 static long LoadDriverMKext(char *fileSpec
)
262 long driversAddr
, driversLength
;
264 DriversPackage
*package
= (DriversPackage
*)kLoadAddr
;
267 if (LoadFile(fileSpec
) == -1) return -1;
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;
276 // Make space for the MKext.
277 driversLength
= package
->length
;
278 driversAddr
= AllocateKernelMemory(driversLength
);
281 memcpy((void *)driversAddr
, (void *)kLoadAddr
, driversLength
);
283 // Add the MKext to the memory map.
284 sprintf(segName
, "DriversPackage-%x", driversAddr
);
285 AllocateMemoryRange(segName
, driversAddr
, driversLength
);
291 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
)
293 long length
, ret
, driverPathLength
;
296 TagPtr personalities
;
299 // Reset the malloc zone.
300 malloc_init((char *)kMallocAddr
, kMallocSize
);
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
);
310 // Construct the file spec.
311 sprintf(gFileSpec
, "%s\\%s\\%sInfo.plist", dirSpec
, name
,
312 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
314 length
= LoadFile(gFileSpec
);
320 buffer
= malloc(length
+ 1);
325 strncpy(buffer
, (char *)kLoadAddr
, length
);
327 ret
= ParseXML(buffer
, &module, &personalities
);
334 // Allocate memory for the driver path and the plist.
335 module->driverPath
= AllocateBootXMemory(driverPathLength
+ 1);
336 module->plistAddr
= AllocateBootXMemory(length
+ 1);
338 if ((module->driverPath
== 0) | (module->plistAddr
== 0)) {
343 // Save the driver path in the module.
344 strcpy(module->driverPath
, tmpDriverPath
);
347 // Add the origin plist to the module.
348 strncpy(module->plistAddr
, (char *)kLoadAddr
, length
);
349 module->plistLength
= length
+ 1;
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;
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
;
363 personalities
= personalities
->tagNext
;
370 static long LoadMatchedModules(void)
374 char *fileName
, segName
[32];
375 DriverInfoPtr driver
;
376 long length
, driverAddr
, driverLength
;
378 module = gModuleHead
;
379 while (module != 0) {
380 if (module->willLoad
) {
381 prop
= GetProperty(module->dict
, kPropCFBundleExecutable
);
383 fileName
= prop
->string
;
384 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
385 length
= LoadFile(gFileSpec
);
388 // Make make in the image area.
389 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
390 driverAddr
= AllocateKernelMemory(driverLength
);
392 // Set up the DriverInfo.
393 driver
= (DriverInfoPtr
)driverAddr
;
394 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
395 driver
->plistLength
= module->plistLength
;
397 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
398 module->plistLength
);
399 driver
->moduleLength
= length
;
401 driver
->moduleAddr
= 0;
402 driver
->moduleLength
= 0;
405 // Save the plist and module.
406 strcpy(driver
->plistAddr
, module->plistAddr
);
408 memcpy(driver
->moduleAddr
, (void *)kLoadAddr
, driver
->moduleLength
);
411 // Add an entry to the memory map.
412 sprintf(segName
, "Driver-%x", driver
);
413 AllocateMemoryRange(segName
, driverAddr
, driverLength
);
417 module = module->nextModule
;
424 static long MatchPersonalities(void)
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;
442 // Look for the exact match property.
443 // Try to match with it.
445 // Look for the old match property.
446 // Try to match with it.
448 prop
= GetProperty(persionality
, kPropIONameMatch
);
449 if ((prop
!= 0) && (prop
->tag
!= 0)) prop
= prop
->tag
;
451 ph
= SearchForNodeMatching(0, 1, prop
->string
);
454 prop
= prop
->tagNext
;
457 // If a node was found mark the module to be loaded.
459 module->willLoad
= 1;
467 static long MatchLibraries(void)
470 ModulePtr
module, module2
;
475 module = gModuleHead
;
476 while (module != 0) {
477 if (module->willLoad
== 1) {
478 prop
= GetProperty(module->dict
, kPropOSBundleLibraries
);
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;
489 module2
= module2
->nextModule
;
491 prop
= prop
->tagNext
;
494 module->willLoad
= 2;
497 module = module->nextModule
;
505 static TagPtr
GetProperty(TagPtr dict
, char *key
)
509 if (dict
->type
!= kTagTypeDict
) return 0;
515 tagList
= tag
->tagNext
;
517 if ((tag
->type
!= kTagTypeKey
) || (tag
->string
== 0)) continue;
519 if (!strcmp(tag
->string
, key
)) return tag
->tag
;
526 static ModulePtr
FindModule(char *name
)
531 module = gModuleHead
;
533 while (module != 0) {
534 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
535 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
536 module = module->nextModule
;
543 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
)
546 TagPtr moduleDict
, required
;
551 length
= ParseNextTag(buffer
+ pos
, &moduleDict
);
552 if (length
== -1) break;
555 if (moduleDict
== 0) continue;
557 if (moduleDict
->type
== kTagTypeDict
) break;
562 if (length
== -1) return -1;
564 required
= GetProperty(moduleDict
, kPropOSBundleRequired
);
565 if ((required
== 0) || (required
->type
!= kTagTypeString
) ||
566 !strcmp(required
->string
, "Safe Boot")) {
571 tmpModule
= AllocateBootXMemory(sizeof(Module
));
572 if (tmpModule
== 0) {
576 tmpModule
->dict
= moduleDict
;
578 // For now, load any module that has OSBundleRequired != "Safe Boot".
579 tmpModule
->willLoad
= 1;
583 // Get the personalities.
584 *personalities
= GetProperty(moduleDict
, kPropIOKitPersonalities
);
590 static long ParseNextTag(char *buffer
, TagPtr
*tag
)
595 length
= GetNextTag(buffer
, &tagName
, 0);
596 if (length
== -1) return -1;
599 if (!strncmp(tagName
, kXMLTagPList
, 6)) {
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);
628 if (length
== -1) return -1;
634 static long ParseTagList(char *buffer
, TagPtr
*tag
, long type
, long empty
)
637 TagPtr tagList
, tmpTag
;
644 length
= ParseNextTag(buffer
+ pos
, &tmpTag
);
645 if (length
== -1) break;
648 if (tmpTag
== 0) break;
649 tmpTag
->tagNext
= tagList
;
667 tmpTag
->tag
= tagList
;
676 static long ParseTagKey(char *buffer
, TagPtr
*tag
)
678 long length
, length2
;
680 TagPtr tmpTag
, subTag
;
682 length
= FixDataMatchingTag(buffer
, kXMLTagKey
);
683 if (length
== -1) return -1;
685 length2
= ParseNextTag(buffer
+ length
, &subTag
);
686 if (length2
== -1) return -1;
694 string
= NewSymbol(buffer
);
701 tmpTag
->type
= kTagTypeKey
;
702 tmpTag
->string
= string
;
703 tmpTag
->tag
= subTag
;
708 return length
+ length2
;
712 static long ParseTagString(char *buffer
, TagPtr
*tag
)
718 length
= FixDataMatchingTag(buffer
, kXMLTagString
);
719 if (length
== -1) return -1;
722 if (tmpTag
== 0) return -1;
724 string
= NewSymbol(buffer
);
730 tmpTag
->type
= kTagTypeString
;
731 tmpTag
->string
= string
;
741 static long ParseTagInteger(char *buffer
, TagPtr
*tag
)
743 long length
, integer
;
746 length
= FixDataMatchingTag(buffer
, kXMLTagInteger
);
747 if (length
== -1) return -1;
750 if (tmpTag
== 0) return -1;
754 tmpTag
->type
= kTagTypeInteger
;
755 tmpTag
->string
= (char *)integer
;
765 static long ParseTagData(char *buffer
, TagPtr
*tag
)
770 length
= FixDataMatchingTag(buffer
, kXMLTagData
);
771 if (length
== -1) return -1;
774 if (tmpTag
== 0) return -1;
776 tmpTag
->type
= kTagTypeData
;
787 static long ParseTagDate(char *buffer
, TagPtr
*tag
)
792 length
= FixDataMatchingTag(buffer
, kXMLTagDate
);
793 if (length
== -1) return -1;
796 if (tmpTag
== 0) return -1;
798 tmpTag
->type
= kTagTypeDate
;
809 static long ParseTagBoolean(char *buffer
, TagPtr
*tag
, long type
)
814 if (tmpTag
== 0) return -1;
827 static long GetNextTag(char *buffer
, char **tag
, long *start
)
831 if (tag
== 0) return -1;
833 // Find the start of the tag.
835 while ((buffer
[cnt
] != '\0') && (buffer
[cnt
] != '<')) cnt
++;
836 if (buffer
[cnt
] == '\0') return -1;
838 // Find the end of the tag.
840 while ((buffer
[cnt2
] != '\0') && (buffer
[cnt2
] != '>')) cnt2
++;
841 if (buffer
[cnt2
] == '\0') return -1;
844 *tag
= buffer
+ cnt
+ 1;
846 if (start
) *start
= cnt
;
852 static long FixDataMatchingTag(char *buffer
, char *tag
)
854 long length
, start
, stop
;
859 length
= GetNextTag(buffer
+ start
, &endTag
, &stop
);
860 if (length
== -1) return -1;
862 if ((*endTag
== '/') && !strcmp(endTag
+ 1, tag
)) break;
866 buffer
[start
+ stop
] = '\0';
868 return start
+ length
;
872 #define kTagsPerBlock (0x1000)
874 static TagPtr gTagsFree
;
876 static TagPtr
NewTag(void)
881 if (gTagsFree
== 0) {
882 tag
= (TagPtr
)AllocateBootXMemory(kTagsPerBlock
* sizeof(Tag
));
883 if (tag
== 0) return 0;
885 // Initalize the new tags.
886 for (cnt
= 0; cnt
< kTagsPerBlock
; cnt
++) {
887 tag
[cnt
].type
= kTagTypeNone
;
890 tag
[cnt
].tagNext
= tag
+ cnt
+ 1;
892 tag
[kTagsPerBlock
- 1].tagNext
= 0;
898 gTagsFree
= tag
->tagNext
;
904 static void FreeTag(TagPtr tag
)
907 if (tag
== 0) return;
909 if (tag
->string
) FreeSymbol(tag
->string
);
912 FreeTag(tag
->tagNext
);
914 // Clear and free the tag.
915 tag
->type
= kTagTypeNone
;
918 tag
->tagNext
= gTagsFree
;
928 typedef struct Symbol Symbol
, *SymbolPtr
;
930 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
);
932 static SymbolPtr gSymbolsHead
;
935 static char *NewSymbol(char *string
)
939 // Look for string in the list of symbols.
940 symbol
= FindSymbol(string
, 0);
942 // Add the new symbol.
944 symbol
= AllocateBootXMemory(sizeof(Symbol
) + strlen(string
));
945 if (symbol
== 0) return 0;
947 // Set the symbol's data.
948 symbol
->refCount
= 0;
949 strcpy(symbol
->string
, string
);
951 // Add the symbol to the list.
952 symbol
->next
= gSymbolsHead
;
953 gSymbolsHead
= symbol
;
956 // Update the refCount and return the string.
958 return symbol
->string
;
962 static void FreeSymbol(char *string
)
965 SymbolPtr symbol
, prev
;
967 // Look for string in the list of symbols.
968 symbol
= FindSymbol(string
, &prev
);
969 if (symbol
== 0) return;
971 // Update the refCount.
974 if (symbol
->refCount
!= 0) return;
976 // Remove the symbol from the list.
977 if (prev
!= 0) prev
->next
= symbol
->next
;
978 else gSymbolsHead
= symbol
->next
;
980 // Free the symbol's memory.
986 static SymbolPtr
FindSymbol(char *string
, SymbolPtr
*prevSymbol
)
988 SymbolPtr symbol
, prev
;
990 symbol
= gSymbolsHead
;
993 while (symbol
!= 0) {
994 if (!strcmp(symbol
->string
, string
)) break;
997 symbol
= symbol
->next
;
1000 if ((symbol
!= 0) && (prevSymbol
!= 0)) *prevSymbol
= prev
;
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
);
1016 static void DumpTag(TagPtr tag
, long depth
)
1018 if (tag
== 0) return;
1020 switch (tag
->type
) {
1022 DumpTagDict(tag
, depth
);
1026 DumpTagKey(tag
, depth
);
1029 case kTagTypeString
:
1030 DumpTagString(tag
, depth
);
1033 case kTagTypeInteger
:
1034 DumpTagInteger(tag
, depth
);
1038 DumpTagData(tag
, depth
);
1042 DumpTagDate(tag
, depth
);
1045 case kTagTypeFalse
:
1047 DumpTagBoolean(tag
, depth
);
1050 case kTagTypeArray
:
1051 DumpTagArray(tag
, depth
);
1060 static void DumpTagDict(TagPtr tag
, long depth
)
1064 if (tag
->tag
== 0) {
1066 printf("<%s/>\n", kXMLTagDict
);
1069 printf("<%s>\n", kXMLTagDict
);
1073 DumpTag(tagList
, depth
+ 1);
1074 tagList
= tagList
->tagNext
;
1078 printf("</%s>\n", kXMLTagDict
);
1083 static void DumpTagKey(TagPtr tag
, long depth
)
1086 printf("<%s>%s</%s>\n", kXMLTagKey
, tag
->string
, kXMLTagKey
);
1088 DumpTag(tag
->tag
, depth
);
1092 static void DumpTagString(TagPtr tag
, long depth
)
1095 printf("<%s>%s</%s>\n", kXMLTagString
, tag
->string
, kXMLTagString
);
1099 static void DumpTagInteger(TagPtr tag
, long depth
)
1102 printf("<%s>%x</%s>\n", kXMLTagInteger
, tag
->string
, kXMLTagInteger
);
1106 static void DumpTagData(TagPtr tag
, long depth
)
1109 printf("<%s>%x</%s>\n", kXMLTagData
, tag
->string
, kXMLTagData
);
1113 static void DumpTagDate(TagPtr tag
, long depth
)
1116 printf("<%s>%x</%s>\n", kXMLTagDate
, tag
->string
, kXMLTagDate
);
1120 static void DumpTagBoolean(TagPtr tag
, long depth
)
1123 printf("<%s>\n", (tag
->type
== kTagTypeTrue
) ? kXMLTagTrue
: kXMLTagFalse
);
1127 static void DumpTagArray(TagPtr tag
, long depth
)
1131 if (tag
->tag
== 0) {
1133 printf("<%s/>\n", kXMLTagArray
);
1136 printf("<%s>\n", kXMLTagArray
);
1140 DumpTag(tagList
, depth
+ 1);
1141 tagList
= tagList
->tagNext
;
1145 printf("</%s>\n", kXMLTagArray
);
1150 static void DumpSpaces(long depth
)
1154 for (cnt
= 0; cnt
< (depth
* 4); cnt
++) putchar(' ');