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