2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Chris Parker
28 #include <CoreFoundation/CFXMLNode.h>
29 #include <CoreFoundation/CFPropertyList.h>
30 #include "CFInternal.h"
31 #include "CFXMLInputStream.h"
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
);
40 static Boolean
externalIDEqual(CFXMLExternalID
*ext1
, CFXMLExternalID
*ext2
) {
41 return _nullSafeCFEqual(ext1
->systemID
, ext2
->systemID
) && _nullSafeCFEqual(ext1
->publicID
, ext2
->publicID
);
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
:{
56 url1
= ((CFXMLDocumentInfo
*)desc1
->additionalData
)->sourceURL
;
57 url2
= ((CFXMLDocumentInfo
*)desc2
->additionalData
)->sourceURL
;
58 return _nullSafeCFEqual(url1
, url2
);
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
);
70 case kCFXMLNodeTypeProcessingInstruction
: {
71 CFStringRef str1
, str2
;
72 str1
= ((CFXMLProcessingInstructionInfo
*)desc1
->additionalData
)->dataString
;
73 str2
= ((CFXMLProcessingInstructionInfo
*)desc2
->additionalData
)->dataString
;
74 return _nullSafeCFEqual(str1
, str2
);
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
);
85 case kCFXMLNodeTypeEntityReference
: {
86 return ((CFXMLEntityReferenceInfo
*)(desc1
->additionalData
))->entityType
== ((CFXMLEntityReferenceInfo
*)(desc2
->additionalData
))->entityType
;
88 case kCFXMLNodeTypeNotation
: {
89 CFXMLNotationInfo
*data1
, *data2
;
90 data1
= (CFXMLNotationInfo
*)desc1
->additionalData
;
91 data2
= (CFXMLNotationInfo
*)desc2
->additionalData
;
92 return externalIDEqual(&(data1
->externalID
), &(data2
->externalID
));
94 case kCFXMLNodeTypeDocumentType
: {
95 CFXMLDocumentTypeInfo
*data1
, *data2
;
96 data1
= (CFXMLDocumentTypeInfo
*)desc1
->additionalData
;
97 data2
= (CFXMLDocumentTypeInfo
*)desc2
->additionalData
;
98 return externalIDEqual(&(data1
->externalID
), &(data2
->externalID
));
100 case kCFXMLNodeTypeElementTypeDeclaration
: {
101 CFXMLElementTypeDeclarationInfo
*d1
= (CFXMLElementTypeDeclarationInfo
*)desc1
->additionalData
;
102 CFXMLElementTypeDeclarationInfo
*d2
= (CFXMLElementTypeDeclarationInfo
*)desc2
->additionalData
;
103 return _nullSafeCFEqual(d1
->contentDescription
, d2
->contentDescription
);
105 case kCFXMLNodeTypeAttributeListDeclaration
: {
106 CFXMLAttributeListDeclarationInfo
*attList1
= (CFXMLAttributeListDeclarationInfo
*)desc1
->additionalData
;
107 CFXMLAttributeListDeclarationInfo
*attList2
= (CFXMLAttributeListDeclarationInfo
*)desc2
->additionalData
;
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;
125 static UInt32
__CFXMLNodeHash(CFTypeRef cf
) {
126 CFXMLNodeRef node
= (CFXMLNodeRef
)cf
;
127 if (node
->dataString
) {
128 return CFHash(node
->dataString
);
130 if (node
->dataTypeID
== kCFXMLNodeTypeDocument
) {
131 CFURLRef url
= ((CFXMLDocumentInfo
*)node
->additionalData
)->sourceURL
;
132 return url
? CFHash(url
) : (UInt32
)cf
;
134 CFAssert2(false, __kCFLogAssertion
, "%s(): Saw unexpected XML type code %d", __PRETTY_FUNCTION__
, node
->dataTypeID
);
139 static CFStringRef
__CFXMLNodeCopyDescription(CFTypeRef cf
) {
140 struct __CFXMLNode
*node
= (struct __CFXMLNode
*)cf
;
141 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFXMLNode 0x%x>{typeID = %d, string = %@}"), (UInt32
)cf
, node
->dataTypeID
, node
->dataString
);
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
);
154 case kCFXMLNodeTypeElement
:
155 if (((CFXMLElementInfo
*)node
->additionalData
)->attributes
) {
156 CFRelease(((CFXMLElementInfo
*)node
->additionalData
)->attributes
);
157 CFRelease(((CFXMLElementInfo
*)node
->additionalData
)->attributeOrder
);
160 case kCFXMLNodeTypeProcessingInstruction
:
161 if (((CFXMLProcessingInstructionInfo
*)node
->additionalData
)->dataString
) {
162 CFRelease(((CFXMLProcessingInstructionInfo
*)node
->additionalData
)->dataString
);
165 case kCFXMLNodeTypeEntity
:
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
);
174 case kCFXMLNodeTypeEntityReference
:
176 // Do nothing; additionalData has no structure of its own, with dependent pieces to release. -- REW, 2/11/2000
179 case kCFXMLNodeTypeDocumentType
:
180 case kCFXMLNodeTypeNotation
:
181 // We get away with this because CFXMLNotationInfo and CFXMLDocumentTypeInfo have identical formats
183 CFXMLNotationInfo
*data
= (CFXMLNotationInfo
*)node
->additionalData
;
184 if (data
->externalID
.systemID
) CFRelease(data
->externalID
.systemID
);
185 if (data
->externalID
.publicID
) CFRelease(data
->externalID
.publicID
);
188 case kCFXMLNodeTypeElementTypeDeclaration
:
189 if (((CFXMLElementTypeDeclarationInfo
*)node
->additionalData
)->contentDescription
) {
190 CFRelease(((CFXMLElementTypeDeclarationInfo
*)node
->additionalData
)->contentDescription
);
193 case kCFXMLNodeTypeAttributeListDeclaration
:
195 CFXMLAttributeListDeclarationInfo
*data
= (CFXMLAttributeListDeclarationInfo
*)node
->additionalData
;
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
);
202 CFAllocatorDeallocate(CFGetAllocator(node
), data
->attributes
);
206 CFAssert1(false, __kCFLogAssertion
, "%s(): Encountered unexpected typeID %d (additionalData should be empty)", node
->dataTypeID
);
211 static CFTypeID __kCFXMLNodeTypeID
= _kCFRuntimeNotATypeID
;
213 static const CFRuntimeClass __CFXMLNodeClass
= {
218 __CFXMLNodeDeallocate
,
222 __CFXMLNodeCopyDescription
225 __private_extern__
void __CFXMLNodeInitialize(void) {
226 __kCFXMLNodeTypeID
= _CFRuntimeRegisterClass(&__CFXMLNodeClass
);
229 CFTypeID
CFXMLNodeGetTypeID(void) {
230 return __kCFXMLNodeTypeID
;
233 CFXMLNodeRef
CFXMLNodeCreateCopy(CFAllocatorRef alloc
, CFXMLNodeRef origNode
) {
234 return CFXMLNodeCreate(alloc
, origNode
->dataTypeID
, origNode
->dataString
, origNode
->additionalData
, origNode
->version
);
237 static void _copyAddlDataForType(CFAllocatorRef alloc
, CFXMLNodeTypeCode xmlType
, const void *src
, void *dest
) {
239 case kCFXMLNodeTypeDocument
: {
240 CFXMLDocumentInfo
*srcData
= (CFXMLDocumentInfo
*)src
;
241 CFXMLDocumentInfo
*destData
= (CFXMLDocumentInfo
*)dest
;
242 destData
->sourceURL
= srcData
->sourceURL
? CFRetain(srcData
->sourceURL
) : NULL
;
243 destData
->encoding
= srcData
->encoding
;
246 case kCFXMLNodeTypeElement
: {
247 CFXMLElementInfo
*srcData
= (CFXMLElementInfo
*)src
;
248 CFXMLElementInfo
*destData
= (CFXMLElementInfo
*)dest
;
249 if (srcData
->attributes
&& CFDictionaryGetCount(srcData
->attributes
) != 0) {
250 destData
->attributes
= CFPropertyListCreateDeepCopy(alloc
, srcData
->attributes
, kCFPropertyListImmutable
);
251 destData
->attributeOrder
= CFPropertyListCreateDeepCopy(alloc
, srcData
->attributeOrder
, kCFPropertyListImmutable
);
253 destData
->attributes
= NULL
;
254 destData
->attributeOrder
= NULL
;
256 destData
->isEmpty
= srcData
->isEmpty
;
259 case kCFXMLNodeTypeProcessingInstruction
: {
260 CFXMLProcessingInstructionInfo
*srcData
= (CFXMLProcessingInstructionInfo
*)src
;
261 CFXMLProcessingInstructionInfo
*destData
= (CFXMLProcessingInstructionInfo
*)dest
;
262 destData
->dataString
= srcData
->dataString
? CFStringCreateCopy(alloc
, srcData
->dataString
) : NULL
;
265 case kCFXMLNodeTypeEntity
:
267 CFXMLEntityInfo
*sourceData
= (CFXMLEntityInfo
*)src
;
268 CFXMLEntityInfo
*destData
= (CFXMLEntityInfo
*)dest
;
269 destData
->entityType
= sourceData
->entityType
;
270 destData
->replacementText
= sourceData
->replacementText
? CFStringCreateCopy(alloc
, sourceData
->replacementText
) : NULL
;
271 destData
->entityID
.systemID
= sourceData
->entityID
.systemID
? CFRetain(sourceData
->entityID
.systemID
) : NULL
;
272 destData
->entityID
.publicID
= sourceData
->entityID
.publicID
? CFStringCreateCopy(alloc
, sourceData
->entityID
.publicID
) : NULL
;
273 destData
->notationName
= sourceData
->notationName
? CFStringCreateCopy(alloc
, sourceData
->notationName
) : NULL
;
276 case kCFXMLNodeTypeEntityReference
:
278 CFXMLEntityReferenceInfo
*srcData
= (CFXMLEntityReferenceInfo
*)src
;
279 CFXMLEntityReferenceInfo
*destData
= (CFXMLEntityReferenceInfo
*)dest
;
280 destData
->entityType
= srcData
->entityType
;
283 case kCFXMLNodeTypeDocumentType
:
284 case kCFXMLNodeTypeNotation
:
286 // We can get away with this because the structures of CFXMLNotationInfo and CFXMLDocumentTypeInfo match. -- REW, 3/8/2000
287 CFXMLNotationInfo
*srcData
= (CFXMLNotationInfo
*)src
;
288 CFXMLNotationInfo
*destData
= (CFXMLNotationInfo
*)dest
;
289 destData
->externalID
.systemID
= srcData
->externalID
.systemID
? CFRetain(srcData
->externalID
.systemID
) : NULL
;
290 destData
->externalID
.publicID
= srcData
->externalID
.publicID
? CFStringCreateCopy(alloc
, srcData
->externalID
.publicID
) : NULL
;
293 case kCFXMLNodeTypeElementTypeDeclaration
: {
294 CFXMLElementTypeDeclarationInfo
*srcData
= (CFXMLElementTypeDeclarationInfo
*)src
;
295 CFXMLElementTypeDeclarationInfo
*destData
= (CFXMLElementTypeDeclarationInfo
*)dest
;
296 destData
->contentDescription
= srcData
->contentDescription
? CFStringCreateCopy(alloc
, srcData
->contentDescription
) : NULL
;
299 case kCFXMLNodeTypeAttributeListDeclaration
:
301 CFXMLAttributeListDeclarationInfo
*sourceData
= (CFXMLAttributeListDeclarationInfo
*)src
;
302 CFXMLAttributeListDeclarationInfo
*destData
= (CFXMLAttributeListDeclarationInfo
*)dest
;
304 destData
->numberOfAttributes
= sourceData
->numberOfAttributes
;
305 destData
->attributes
= sourceData
->numberOfAttributes
? CFAllocatorAllocate(alloc
, sizeof(CFXMLAttributeDeclarationInfo
)*sourceData
->numberOfAttributes
, 0) : NULL
;
306 for (idx
= 0; idx
< sourceData
->numberOfAttributes
; idx
++) {
307 CFXMLAttributeDeclarationInfo sourceAttr
= sourceData
->attributes
[idx
];
308 CFXMLAttributeDeclarationInfo
*destAttr
= &(destData
->attributes
[idx
]);
309 destAttr
->attributeName
= CFStringCreateCopy(alloc
, sourceAttr
.attributeName
);
310 destAttr
->typeString
= CFStringCreateCopy(alloc
, sourceAttr
.typeString
);
311 destAttr
->defaultString
= CFStringCreateCopy(alloc
, sourceAttr
.defaultString
);
316 CFAssert2(false, __kCFLogAssertion
, "%s(): Encountered unexpected typeID %d (additionalData should be empty)", __PRETTY_FUNCTION__
, xmlType
);
320 // Designated initializer; all node creation (except the wonky one created by the parser) should happen here.
321 CFXMLNodeRef
CFXMLNodeCreate(CFAllocatorRef alloc
, CFXMLNodeTypeCode xmlType
, CFStringRef dataString
, const void *additionalData
, CFIndex version
) {
322 struct __CFXMLNode
*node
;
324 // Add assertions checking xmlType against the presence/absence of additionalData & dataString
326 case kCFXMLNodeTypeDocument
: extraSize
= sizeof(CFXMLDocumentInfo
); break;
327 case kCFXMLNodeTypeElement
: extraSize
= sizeof(CFXMLElementInfo
); break;
328 case kCFXMLNodeTypeProcessingInstruction
: extraSize
= sizeof(CFXMLProcessingInstructionInfo
); break;
329 case kCFXMLNodeTypeEntity
: extraSize
= sizeof(CFXMLEntityInfo
); break;
330 case kCFXMLNodeTypeEntityReference
: extraSize
= sizeof(CFXMLEntityReferenceInfo
); break;
331 case kCFXMLNodeTypeDocumentType
: extraSize
= sizeof(CFXMLDocumentTypeInfo
); break;
332 case kCFXMLNodeTypeNotation
: extraSize
= sizeof(CFXMLNotationInfo
); break;
333 case kCFXMLNodeTypeElementTypeDeclaration
: extraSize
= sizeof(CFXMLElementTypeDeclarationInfo
); break;
334 case kCFXMLNodeTypeAttributeListDeclaration
: extraSize
= sizeof(CFXMLAttributeListDeclarationInfo
); break;
335 default: extraSize
= 0;
338 node
= (struct __CFXMLNode
*)_CFRuntimeCreateInstance(alloc
, __kCFXMLNodeTypeID
, sizeof(struct __CFXMLNode
) + extraSize
- sizeof(CFRuntimeBase
), NULL
);
340 alloc
= CFGetAllocator(node
);
341 node
->version
= version
;
342 node
->dataTypeID
= xmlType
;
343 node
->dataString
= dataString
? CFStringCreateCopy(alloc
, dataString
) : NULL
;
344 if (extraSize
!= 0) {
345 node
->additionalData
= (void *)((uint8_t *)node
+ sizeof(struct __CFXMLNode
));
346 _copyAddlDataForType(alloc
, xmlType
, additionalData
, node
->additionalData
);
348 node
->additionalData
= NULL
;
354 CFXMLNodeTypeCode
CFXMLNodeGetTypeCode(CFXMLNodeRef node
) {
355 return node
->dataTypeID
;
358 CFStringRef
CFXMLNodeGetString(CFXMLNodeRef node
) {
359 return node
->dataString
;
362 const void *CFXMLNodeGetInfoPtr(CFXMLNodeRef node
) {
363 return node
->additionalData
;
366 CFIndex
CFXMLNodeGetVersion(CFXMLNodeRef node
) {
367 return node
->version
;