2 * Copyright (c) 2003 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 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Chris Parker
30 #include <CoreFoundation/CFXMLNode.h>
31 #include <CoreFoundation/CFPropertyList.h>
32 #include "CFInternal.h"
33 #include "CFXMLInputStream.h"
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
);
42 static Boolean
externalIDEqual(CFXMLExternalID
*ext1
, CFXMLExternalID
*ext2
) {
43 return _nullSafeCFEqual(ext1
->systemID
, ext2
->systemID
) && _nullSafeCFEqual(ext1
->publicID
, ext2
->publicID
);
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
:{
58 url1
= ((CFXMLDocumentInfo
*)desc1
->additionalData
)->sourceURL
;
59 url2
= ((CFXMLDocumentInfo
*)desc2
->additionalData
)->sourceURL
;
60 return _nullSafeCFEqual(url1
, url2
);
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
);
72 case kCFXMLNodeTypeProcessingInstruction
: {
73 CFStringRef str1
, str2
;
74 str1
= ((CFXMLProcessingInstructionInfo
*)desc1
->additionalData
)->dataString
;
75 str2
= ((CFXMLProcessingInstructionInfo
*)desc2
->additionalData
)->dataString
;
76 return _nullSafeCFEqual(str1
, str2
);
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
);
87 case kCFXMLNodeTypeEntityReference
: {
88 return ((CFXMLEntityReferenceInfo
*)(desc1
->additionalData
))->entityType
== ((CFXMLEntityReferenceInfo
*)(desc2
->additionalData
))->entityType
;
90 case kCFXMLNodeTypeNotation
: {
91 CFXMLNotationInfo
*data1
, *data2
;
92 data1
= (CFXMLNotationInfo
*)desc1
->additionalData
;
93 data2
= (CFXMLNotationInfo
*)desc2
->additionalData
;
94 return externalIDEqual(&(data1
->externalID
), &(data2
->externalID
));
96 case kCFXMLNodeTypeDocumentType
: {
97 CFXMLDocumentTypeInfo
*data1
, *data2
;
98 data1
= (CFXMLDocumentTypeInfo
*)desc1
->additionalData
;
99 data2
= (CFXMLDocumentTypeInfo
*)desc2
->additionalData
;
100 return externalIDEqual(&(data1
->externalID
), &(data2
->externalID
));
102 case kCFXMLNodeTypeElementTypeDeclaration
: {
103 CFXMLElementTypeDeclarationInfo
*d1
= (CFXMLElementTypeDeclarationInfo
*)desc1
->additionalData
;
104 CFXMLElementTypeDeclarationInfo
*d2
= (CFXMLElementTypeDeclarationInfo
*)desc2
->additionalData
;
105 return _nullSafeCFEqual(d1
->contentDescription
, d2
->contentDescription
);
107 case kCFXMLNodeTypeAttributeListDeclaration
: {
108 CFXMLAttributeListDeclarationInfo
*attList1
= (CFXMLAttributeListDeclarationInfo
*)desc1
->additionalData
;
109 CFXMLAttributeListDeclarationInfo
*attList2
= (CFXMLAttributeListDeclarationInfo
*)desc2
->additionalData
;
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;
127 static UInt32
__CFXMLNodeHash(CFTypeRef cf
) {
128 CFXMLNodeRef node
= (CFXMLNodeRef
)cf
;
129 if (node
->dataString
) {
130 return CFHash(node
->dataString
);
132 if (node
->dataTypeID
== kCFXMLNodeTypeDocument
) {
133 CFURLRef url
= ((CFXMLDocumentInfo
*)node
->additionalData
)->sourceURL
;
134 return url
? CFHash(url
) : (UInt32
)cf
;
136 CFAssert2(false, __kCFLogAssertion
, "%s(): Saw unexpected XML type code %d", __PRETTY_FUNCTION__
, node
->dataTypeID
);
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
);
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
);
156 case kCFXMLNodeTypeElement
:
157 if (((CFXMLElementInfo
*)node
->additionalData
)->attributes
) {
158 CFRelease(((CFXMLElementInfo
*)node
->additionalData
)->attributes
);
159 CFRelease(((CFXMLElementInfo
*)node
->additionalData
)->attributeOrder
);
162 case kCFXMLNodeTypeProcessingInstruction
:
163 if (((CFXMLProcessingInstructionInfo
*)node
->additionalData
)->dataString
) {
164 CFRelease(((CFXMLProcessingInstructionInfo
*)node
->additionalData
)->dataString
);
167 case kCFXMLNodeTypeEntity
:
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
);
176 case kCFXMLNodeTypeEntityReference
:
178 // Do nothing; additionalData has no structure of its own, with dependent pieces to release. -- REW, 2/11/2000
181 case kCFXMLNodeTypeDocumentType
:
182 case kCFXMLNodeTypeNotation
:
183 // We get away with this because CFXMLNotationInfo and CFXMLDocumentTypeInfo have identical formats
185 CFXMLNotationInfo
*data
= (CFXMLNotationInfo
*)node
->additionalData
;
186 if (data
->externalID
.systemID
) CFRelease(data
->externalID
.systemID
);
187 if (data
->externalID
.publicID
) CFRelease(data
->externalID
.publicID
);
190 case kCFXMLNodeTypeElementTypeDeclaration
:
191 if (((CFXMLElementTypeDeclarationInfo
*)node
->additionalData
)->contentDescription
) {
192 CFRelease(((CFXMLElementTypeDeclarationInfo
*)node
->additionalData
)->contentDescription
);
195 case kCFXMLNodeTypeAttributeListDeclaration
:
197 CFXMLAttributeListDeclarationInfo
*data
= (CFXMLAttributeListDeclarationInfo
*)node
->additionalData
;
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
);
204 CFAllocatorDeallocate(CFGetAllocator(node
), data
->attributes
);
208 CFAssert1(false, __kCFLogAssertion
, "%s(): Encountered unexpected typeID %d (additionalData should be empty)", node
->dataTypeID
);
213 static CFTypeID __kCFXMLNodeTypeID
= _kCFRuntimeNotATypeID
;
215 static const CFRuntimeClass __CFXMLNodeClass
= {
220 __CFXMLNodeDeallocate
,
224 __CFXMLNodeCopyDescription
227 __private_extern__
void __CFXMLNodeInitialize(void) {
228 __kCFXMLNodeTypeID
= _CFRuntimeRegisterClass(&__CFXMLNodeClass
);
231 CFTypeID
CFXMLNodeGetTypeID(void) {
232 return __kCFXMLNodeTypeID
;
235 CFXMLNodeRef
CFXMLNodeCreateCopy(CFAllocatorRef alloc
, CFXMLNodeRef origNode
) {
236 return CFXMLNodeCreate(alloc
, origNode
->dataTypeID
, origNode
->dataString
, origNode
->additionalData
, origNode
->version
);
239 static void _copyAddlDataForType(CFAllocatorRef alloc
, CFXMLNodeTypeCode xmlType
, const void *src
, void *dest
) {
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
;
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
);
255 destData
->attributes
= NULL
;
256 destData
->attributeOrder
= NULL
;
258 destData
->isEmpty
= srcData
->isEmpty
;
261 case kCFXMLNodeTypeProcessingInstruction
: {
262 CFXMLProcessingInstructionInfo
*srcData
= (CFXMLProcessingInstructionInfo
*)src
;
263 CFXMLProcessingInstructionInfo
*destData
= (CFXMLProcessingInstructionInfo
*)dest
;
264 destData
->dataString
= srcData
->dataString
? CFStringCreateCopy(alloc
, srcData
->dataString
) : NULL
;
267 case kCFXMLNodeTypeEntity
:
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
;
278 case kCFXMLNodeTypeEntityReference
:
280 CFXMLEntityReferenceInfo
*srcData
= (CFXMLEntityReferenceInfo
*)src
;
281 CFXMLEntityReferenceInfo
*destData
= (CFXMLEntityReferenceInfo
*)dest
;
282 destData
->entityType
= srcData
->entityType
;
285 case kCFXMLNodeTypeDocumentType
:
286 case kCFXMLNodeTypeNotation
:
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
;
295 case kCFXMLNodeTypeElementTypeDeclaration
: {
296 CFXMLElementTypeDeclarationInfo
*srcData
= (CFXMLElementTypeDeclarationInfo
*)src
;
297 CFXMLElementTypeDeclarationInfo
*destData
= (CFXMLElementTypeDeclarationInfo
*)dest
;
298 destData
->contentDescription
= srcData
->contentDescription
? CFStringCreateCopy(alloc
, srcData
->contentDescription
) : NULL
;
301 case kCFXMLNodeTypeAttributeListDeclaration
:
303 CFXMLAttributeListDeclarationInfo
*sourceData
= (CFXMLAttributeListDeclarationInfo
*)src
;
304 CFXMLAttributeListDeclarationInfo
*destData
= (CFXMLAttributeListDeclarationInfo
*)dest
;
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
);
318 CFAssert2(false, __kCFLogAssertion
, "%s(): Encountered unexpected typeID %d (additionalData should be empty)", __PRETTY_FUNCTION__
, xmlType
);
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
;
326 // Add assertions checking xmlType against the presence/absence of additionalData & dataString
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;
340 node
= (struct __CFXMLNode
*)_CFRuntimeCreateInstance(alloc
, __kCFXMLNodeTypeID
, sizeof(struct __CFXMLNode
) + extraSize
- sizeof(CFRuntimeBase
), NULL
);
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
);
350 node
->additionalData
= NULL
;
356 CFXMLNodeTypeCode
CFXMLNodeGetTypeCode(CFXMLNodeRef node
) {
357 return node
->dataTypeID
;
360 CFStringRef
CFXMLNodeGetString(CFXMLNodeRef node
) {
361 return node
->dataString
;
364 const void *CFXMLNodeGetInfoPtr(CFXMLNodeRef node
) {
365 return node
->additionalData
;
368 CFIndex
CFXMLNodeGetVersion(CFXMLNodeRef node
) {
369 return node
->version
;