]> git.saurik.com Git - apple/cf.git/blob - Parsing.subproj/CFXMLNode.c
CF-299.35.tar.gz
[apple/cf.git] / Parsing.subproj / CFXMLNode.c
1 /*
2 * Copyright (c) 2003 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 /* CFXMLNode.c
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Chris Parker
28 */
29
30 #include <CoreFoundation/CFXMLNode.h>
31 #include <CoreFoundation/CFPropertyList.h>
32 #include "CFInternal.h"
33 #include "CFXMLInputStream.h"
34
35 CF_INLINE Boolean _nullSafeCFEqual(CFTypeRef cf1, CFTypeRef cf2) {
36 if (cf1 && !cf2) return false;
37 if (cf2 && !cf1) return false;
38 if (cf1) return CFEqual(cf1, cf2);
39 return true;
40 }
41
42 static Boolean externalIDEqual(CFXMLExternalID *ext1, CFXMLExternalID *ext2) {
43 return _nullSafeCFEqual(ext1->systemID, ext2->systemID) && _nullSafeCFEqual(ext1->publicID, ext2->publicID);
44 }
45
46 static Boolean __CFXMLNodeEqual(CFTypeRef cf1, CFTypeRef cf2) {
47 CFXMLNodeRef desc1 = (CFXMLNodeRef)cf1, desc2 = (CFXMLNodeRef)cf2;
48 if (desc1 == desc2) return true;
49 if (!desc1 || !desc2) return false;
50 if (desc1->dataTypeID != desc2->dataTypeID) return false;
51 if ((desc1->dataString && !desc2->dataString) || (!desc1->dataString && desc2->dataString)) return false;
52 if (desc1->dataString && !CFEqual(desc1->dataString, desc2->dataString)) return false;
53 if ((desc1->additionalData && !desc2->additionalData) || (!desc1->additionalData && desc2->additionalData)) return false;
54 if (!desc1->additionalData) return true;
55 switch (desc1->dataTypeID) {
56 case kCFXMLNodeTypeDocument:{
57 CFURLRef url1, url2;
58 url1 = ((CFXMLDocumentInfo *)desc1->additionalData)->sourceURL;
59 url2 = ((CFXMLDocumentInfo *)desc2->additionalData)->sourceURL;
60 return _nullSafeCFEqual(url1, url2);
61 }
62 case kCFXMLNodeTypeElement: {
63 CFXMLElementInfo *elt1, *elt2;
64 elt1 = (CFXMLElementInfo *)desc1->additionalData;
65 elt2 = (CFXMLElementInfo *)desc2->additionalData;
66 if (elt1->isEmpty != elt2->isEmpty) return false;
67 if (elt1->attributes == elt2->attributes) return true;
68 if (!elt1->attributes) return (CFDictionaryGetCount(elt2->attributes) == 0);
69 if (!elt2->attributes) return (CFDictionaryGetCount(elt1->attributes) == 0);
70 return CFEqual(elt1->attributes, elt2->attributes);
71 }
72 case kCFXMLNodeTypeProcessingInstruction: {
73 CFStringRef str1, str2;
74 str1 = ((CFXMLProcessingInstructionInfo *)desc1->additionalData)->dataString;
75 str2 = ((CFXMLProcessingInstructionInfo *)desc2->additionalData)->dataString;
76 return _nullSafeCFEqual(str1, str2);
77 }
78 case kCFXMLNodeTypeEntity: {
79 CFXMLEntityInfo *data1, *data2;
80 data1 = (CFXMLEntityInfo *)desc1->additionalData;
81 data2 = (CFXMLEntityInfo *)desc2->additionalData;
82 if (data1->entityType != data2->entityType) return false;
83 if (!_nullSafeCFEqual(data1->replacementText, data2->replacementText)) return false;
84 if (!_nullSafeCFEqual(data1->notationName, data2->notationName)) return false;
85 return externalIDEqual(&data1->entityID, &data2->entityID);
86 }
87 case kCFXMLNodeTypeEntityReference: {
88 return ((CFXMLEntityReferenceInfo *)(desc1->additionalData))->entityType == ((CFXMLEntityReferenceInfo *)(desc2->additionalData))->entityType;
89 }
90 case kCFXMLNodeTypeNotation: {
91 CFXMLNotationInfo *data1, *data2;
92 data1 = (CFXMLNotationInfo *)desc1->additionalData;
93 data2 = (CFXMLNotationInfo *)desc2->additionalData;
94 return externalIDEqual(&(data1->externalID), &(data2->externalID));
95 }
96 case kCFXMLNodeTypeDocumentType: {
97 CFXMLDocumentTypeInfo *data1, *data2;
98 data1 = (CFXMLDocumentTypeInfo *)desc1->additionalData;
99 data2 = (CFXMLDocumentTypeInfo *)desc2->additionalData;
100 return externalIDEqual(&(data1->externalID), &(data2->externalID));
101 }
102 case kCFXMLNodeTypeElementTypeDeclaration: {
103 CFXMLElementTypeDeclarationInfo *d1 = (CFXMLElementTypeDeclarationInfo *)desc1->additionalData;
104 CFXMLElementTypeDeclarationInfo *d2 = (CFXMLElementTypeDeclarationInfo *)desc2->additionalData;
105 return _nullSafeCFEqual(d1->contentDescription, d2->contentDescription);
106 }
107 case kCFXMLNodeTypeAttributeListDeclaration: {
108 CFXMLAttributeListDeclarationInfo *attList1 = (CFXMLAttributeListDeclarationInfo *)desc1->additionalData;
109 CFXMLAttributeListDeclarationInfo *attList2 = (CFXMLAttributeListDeclarationInfo *)desc2->additionalData;
110 CFIndex idx;
111 if (attList1->numberOfAttributes != attList2->numberOfAttributes) return false;
112 for (idx = 0; idx < attList1->numberOfAttributes; idx ++) {
113 CFXMLAttributeDeclarationInfo *attr1 = &(attList1->attributes[idx]);
114 CFXMLAttributeDeclarationInfo *attr2 = &(attList2->attributes[idx]);
115 if (!_nullSafeCFEqual(attr1->attributeName, attr2->attributeName)) return false;
116 if (!_nullSafeCFEqual(attr1->typeString, attr2->typeString)) return false;
117 if (!_nullSafeCFEqual(attr1->defaultString, attr2->defaultString)) return false;
118 }
119 return true;
120 }
121 default:
122 return false;
123 }
124 return true;
125 }
126
127 static UInt32 __CFXMLNodeHash(CFTypeRef cf) {
128 CFXMLNodeRef node = (CFXMLNodeRef)cf;
129 if (node->dataString) {
130 return CFHash(node->dataString);
131 }
132 if (node->dataTypeID == kCFXMLNodeTypeDocument) {
133 CFURLRef url = ((CFXMLDocumentInfo *)node->additionalData)->sourceURL;
134 return url ? CFHash(url) : (UInt32)cf;
135 } else {
136 CFAssert2(false, __kCFLogAssertion, "%s(): Saw unexpected XML type code %d", __PRETTY_FUNCTION__, node->dataTypeID);
137 return (UInt32)cf;
138 }
139 }
140
141 static CFStringRef __CFXMLNodeCopyDescription(CFTypeRef cf) {
142 struct __CFXMLNode *node = (struct __CFXMLNode *)cf;
143 return CFStringCreateWithFormat(NULL, NULL, CFSTR("CFXMLNode 0x%x>{typeID = %d, string = %@}"), (UInt32)cf, node->dataTypeID, node->dataString);
144 }
145
146 static void __CFXMLNodeDeallocate(CFTypeRef cf) {
147 struct __CFXMLNode *node = (struct __CFXMLNode *)cf;
148 if (node->dataString) CFRelease(node->dataString);
149 if (node->additionalData) {
150 switch (node->dataTypeID) {
151 case kCFXMLNodeTypeDocument:
152 if (((CFXMLDocumentInfo *)node->additionalData)->sourceURL) {
153 CFRelease(((CFXMLDocumentInfo *)node->additionalData)->sourceURL);
154 }
155 break;
156 case kCFXMLNodeTypeElement:
157 if (((CFXMLElementInfo *)node->additionalData)->attributes) {
158 CFRelease(((CFXMLElementInfo *)node->additionalData)->attributes);
159 CFRelease(((CFXMLElementInfo *)node->additionalData)->attributeOrder);
160 }
161 break;
162 case kCFXMLNodeTypeProcessingInstruction:
163 if (((CFXMLProcessingInstructionInfo *)node->additionalData)->dataString) {
164 CFRelease(((CFXMLProcessingInstructionInfo *)node->additionalData)->dataString);
165 }
166 break;
167 case kCFXMLNodeTypeEntity:
168 {
169 CFXMLEntityInfo *data = (CFXMLEntityInfo *)node->additionalData;
170 if (data->replacementText) CFRelease(data->replacementText);
171 if (data->entityID.systemID) CFRelease(data->entityID.systemID);
172 if (data->entityID.publicID) CFRelease(data->entityID.publicID);
173 if (data->notationName) CFRelease(data->notationName);
174 break;
175 }
176 case kCFXMLNodeTypeEntityReference:
177 {
178 // Do nothing; additionalData has no structure of its own, with dependent pieces to release. -- REW, 2/11/2000
179 break;
180 }
181 case kCFXMLNodeTypeDocumentType:
182 case kCFXMLNodeTypeNotation:
183 // We get away with this because CFXMLNotationInfo and CFXMLDocumentTypeInfo have identical formats
184 {
185 CFXMLNotationInfo *data = (CFXMLNotationInfo *)node->additionalData;
186 if (data->externalID.systemID) CFRelease(data->externalID.systemID);
187 if (data->externalID.publicID) CFRelease(data->externalID.publicID);
188 break;
189 }
190 case kCFXMLNodeTypeElementTypeDeclaration:
191 if (((CFXMLElementTypeDeclarationInfo *)node->additionalData)->contentDescription) {
192 CFRelease(((CFXMLElementTypeDeclarationInfo *)node->additionalData)->contentDescription);
193 }
194 break;
195 case kCFXMLNodeTypeAttributeListDeclaration:
196 {
197 CFXMLAttributeListDeclarationInfo *data = (CFXMLAttributeListDeclarationInfo *)node->additionalData;
198 CFIndex idx;
199 for (idx = 0; idx < data->numberOfAttributes; idx ++) {
200 CFRelease(data->attributes[idx].attributeName);
201 CFRelease(data->attributes[idx].typeString);
202 CFRelease(data->attributes[idx].defaultString);
203 }
204 CFAllocatorDeallocate(CFGetAllocator(node), data->attributes);
205 break;
206 }
207 default:
208 CFAssert1(false, __kCFLogAssertion, "%s(): Encountered unexpected typeID %d (additionalData should be empty)", node->dataTypeID);
209 }
210 }
211 }
212
213 static CFTypeID __kCFXMLNodeTypeID = _kCFRuntimeNotATypeID;
214
215 static const CFRuntimeClass __CFXMLNodeClass = {
216 0,
217 "CFXMLNode",
218 NULL, // init
219 NULL, // copy
220 __CFXMLNodeDeallocate,
221 __CFXMLNodeEqual,
222 __CFXMLNodeHash,
223 NULL, //
224 __CFXMLNodeCopyDescription
225 };
226
227 __private_extern__ void __CFXMLNodeInitialize(void) {
228 __kCFXMLNodeTypeID = _CFRuntimeRegisterClass(&__CFXMLNodeClass);
229 }
230
231 CFTypeID CFXMLNodeGetTypeID(void) {
232 return __kCFXMLNodeTypeID;
233 }
234
235 CFXMLNodeRef CFXMLNodeCreateCopy(CFAllocatorRef alloc, CFXMLNodeRef origNode) {
236 return CFXMLNodeCreate(alloc, origNode->dataTypeID, origNode->dataString, origNode->additionalData, origNode->version);
237 }
238
239 static void _copyAddlDataForType(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType, const void *src, void *dest) {
240 switch(xmlType) {
241 case kCFXMLNodeTypeDocument: {
242 CFXMLDocumentInfo *srcData = (CFXMLDocumentInfo *)src;
243 CFXMLDocumentInfo *destData = (CFXMLDocumentInfo *)dest;
244 destData->sourceURL = srcData->sourceURL ? CFRetain(srcData->sourceURL) : NULL;
245 destData->encoding = srcData->encoding;
246 break;
247 }
248 case kCFXMLNodeTypeElement: {
249 CFXMLElementInfo *srcData = (CFXMLElementInfo *)src;
250 CFXMLElementInfo *destData = (CFXMLElementInfo *)dest;
251 if (srcData->attributes && CFDictionaryGetCount(srcData->attributes) != 0) {
252 destData->attributes = CFPropertyListCreateDeepCopy(alloc, srcData->attributes, kCFPropertyListImmutable);
253 destData->attributeOrder = CFPropertyListCreateDeepCopy(alloc, srcData->attributeOrder, kCFPropertyListImmutable);
254 } else {
255 destData->attributes = NULL;
256 destData->attributeOrder = NULL;
257 }
258 destData->isEmpty = srcData->isEmpty;
259 break;
260 }
261 case kCFXMLNodeTypeProcessingInstruction: {
262 CFXMLProcessingInstructionInfo *srcData = (CFXMLProcessingInstructionInfo *)src;
263 CFXMLProcessingInstructionInfo *destData = (CFXMLProcessingInstructionInfo *)dest;
264 destData->dataString = srcData->dataString ? CFStringCreateCopy(alloc, srcData->dataString) : NULL;
265 break;
266 }
267 case kCFXMLNodeTypeEntity:
268 {
269 CFXMLEntityInfo *sourceData = (CFXMLEntityInfo *)src;
270 CFXMLEntityInfo *destData = (CFXMLEntityInfo *)dest;
271 destData->entityType = sourceData->entityType;
272 destData->replacementText = sourceData->replacementText ? CFStringCreateCopy(alloc, sourceData->replacementText) : NULL;
273 destData->entityID.systemID = sourceData->entityID.systemID ? CFRetain(sourceData->entityID.systemID) : NULL;
274 destData->entityID.publicID = sourceData->entityID.publicID ? CFStringCreateCopy(alloc, sourceData->entityID.publicID) : NULL;
275 destData->notationName = sourceData->notationName ? CFStringCreateCopy(alloc, sourceData->notationName) : NULL;
276 break;
277 }
278 case kCFXMLNodeTypeEntityReference:
279 {
280 CFXMLEntityReferenceInfo *srcData = (CFXMLEntityReferenceInfo *)src;
281 CFXMLEntityReferenceInfo *destData = (CFXMLEntityReferenceInfo *)dest;
282 destData->entityType = srcData->entityType;
283 break;
284 }
285 case kCFXMLNodeTypeDocumentType:
286 case kCFXMLNodeTypeNotation:
287 {
288 // We can get away with this because the structures of CFXMLNotationInfo and CFXMLDocumentTypeInfo match. -- REW, 3/8/2000
289 CFXMLNotationInfo *srcData = (CFXMLNotationInfo *)src;
290 CFXMLNotationInfo *destData = (CFXMLNotationInfo *)dest;
291 destData->externalID.systemID = srcData->externalID.systemID ? CFRetain(srcData->externalID.systemID) : NULL;
292 destData->externalID.publicID = srcData->externalID.publicID ? CFStringCreateCopy(alloc, srcData->externalID.publicID) : NULL;
293 break;
294 }
295 case kCFXMLNodeTypeElementTypeDeclaration: {
296 CFXMLElementTypeDeclarationInfo *srcData = (CFXMLElementTypeDeclarationInfo *)src;
297 CFXMLElementTypeDeclarationInfo *destData = (CFXMLElementTypeDeclarationInfo *)dest;
298 destData->contentDescription = srcData->contentDescription ? CFStringCreateCopy(alloc, srcData->contentDescription) : NULL;
299 break;
300 }
301 case kCFXMLNodeTypeAttributeListDeclaration:
302 {
303 CFXMLAttributeListDeclarationInfo *sourceData = (CFXMLAttributeListDeclarationInfo *)src;
304 CFXMLAttributeListDeclarationInfo *destData = (CFXMLAttributeListDeclarationInfo *)dest;
305 CFIndex idx;
306 destData->numberOfAttributes = sourceData->numberOfAttributes;
307 destData->attributes = sourceData->numberOfAttributes ? CFAllocatorAllocate(alloc, sizeof(CFXMLAttributeDeclarationInfo)*sourceData->numberOfAttributes, 0) : NULL;
308 for (idx = 0; idx < sourceData->numberOfAttributes; idx ++) {
309 CFXMLAttributeDeclarationInfo sourceAttr = sourceData->attributes[idx];
310 CFXMLAttributeDeclarationInfo *destAttr = &(destData->attributes[idx]);
311 destAttr->attributeName = CFStringCreateCopy(alloc, sourceAttr.attributeName);
312 destAttr->typeString = CFStringCreateCopy(alloc, sourceAttr.typeString);
313 destAttr->defaultString = CFStringCreateCopy(alloc, sourceAttr.defaultString);
314 }
315 break;
316 }
317 default:
318 CFAssert2(false, __kCFLogAssertion, "%s(): Encountered unexpected typeID %d (additionalData should be empty)", __PRETTY_FUNCTION__, xmlType);
319 }
320 }
321
322 // Designated initializer; all node creation (except the wonky one created by the parser) should happen here.
323 CFXMLNodeRef CFXMLNodeCreate(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType, CFStringRef dataString, const void *additionalData, CFIndex version) {
324 struct __CFXMLNode *node;
325 UInt32 extraSize;
326 // Add assertions checking xmlType against the presence/absence of additionalData & dataString
327 switch (xmlType) {
328 case kCFXMLNodeTypeDocument: extraSize = sizeof(CFXMLDocumentInfo); break;
329 case kCFXMLNodeTypeElement: extraSize = sizeof(CFXMLElementInfo); break;
330 case kCFXMLNodeTypeProcessingInstruction: extraSize = sizeof(CFXMLProcessingInstructionInfo); break;
331 case kCFXMLNodeTypeEntity: extraSize = sizeof(CFXMLEntityInfo); break;
332 case kCFXMLNodeTypeEntityReference: extraSize = sizeof(CFXMLEntityReferenceInfo); break;
333 case kCFXMLNodeTypeDocumentType: extraSize = sizeof(CFXMLDocumentTypeInfo); break;
334 case kCFXMLNodeTypeNotation: extraSize = sizeof(CFXMLNotationInfo); break;
335 case kCFXMLNodeTypeElementTypeDeclaration: extraSize = sizeof(CFXMLElementTypeDeclarationInfo); break;
336 case kCFXMLNodeTypeAttributeListDeclaration: extraSize = sizeof(CFXMLAttributeListDeclarationInfo); break;
337 default: extraSize = 0;
338 }
339
340 node = (struct __CFXMLNode *)_CFRuntimeCreateInstance(alloc, __kCFXMLNodeTypeID, sizeof(struct __CFXMLNode) + extraSize - sizeof(CFRuntimeBase), NULL);
341 if (node) {
342 alloc = CFGetAllocator(node);
343 node->version = version;
344 node->dataTypeID = xmlType;
345 node->dataString = dataString ? CFStringCreateCopy(alloc, dataString) : NULL;
346 if (extraSize != 0) {
347 node->additionalData = (void *)((uint8_t *)node + sizeof(struct __CFXMLNode));
348 _copyAddlDataForType(alloc, xmlType, additionalData, node->additionalData);
349 } else {
350 node->additionalData = NULL;
351 }
352 }
353 return node;
354 }
355
356 CFXMLNodeTypeCode CFXMLNodeGetTypeCode(CFXMLNodeRef node) {
357 return node->dataTypeID;
358 }
359
360 CFStringRef CFXMLNodeGetString(CFXMLNodeRef node) {
361 return node->dataString;
362 }
363
364 const void *CFXMLNodeGetInfoPtr(CFXMLNodeRef node) {
365 return node->additionalData;
366 }
367
368 CFIndex CFXMLNodeGetVersion(CFXMLNodeRef node) {
369 return node->version;
370 }