]> git.saurik.com Git - apple/cf.git/blob - CFXMLTree.c
CF-1153.18.tar.gz
[apple/cf.git] / CFXMLTree.c
1 /*
2 * Copyright (c) 2015 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
24 /* CFXMLTree.c
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: David Smith
27 */
28
29 #include "CFInternal.h"
30 #include <CoreFoundation/CFXMLParser.h>
31
32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
34
35 /*************/
36 /* CFXMLTree */
37 /*************/
38
39 /* Creates a childless node from desc */
40 CFXMLTreeRef CFXMLTreeCreateWithNode(CFAllocatorRef allocator, CFXMLNodeRef node) {
41 CFTreeContext treeCtxt;
42 treeCtxt.version = 0;
43 treeCtxt.info = (void *)node;
44 treeCtxt.retain = CFRetain;
45 treeCtxt.release = CFRelease;
46 treeCtxt.copyDescription = CFCopyDescription;
47 return CFTreeCreate(allocator, &treeCtxt);
48 }
49
50 CFXMLNodeRef CFXMLTreeGetNode(CFXMLTreeRef xmlNode) {
51 CFTreeContext treeContext;
52 treeContext.version = 0;
53 CFTreeGetContext(xmlNode, &treeContext);
54 return (CFXMLNodeRef)treeContext.info;
55 }
56
57 // We will probably ultimately want to export this under some public API name
58 CF_PRIVATE Boolean CFXMLTreeEqual(CFXMLTreeRef xmlTree1, CFXMLTreeRef xmlTree2) {
59 CFXMLNodeRef node1, node2;
60 CFXMLTreeRef child1, child2;
61 if (CFTreeGetChildCount(xmlTree1) != CFTreeGetChildCount(xmlTree2)) return false;
62 node1 = CFXMLTreeGetNode(xmlTree1);
63 node2 = CFXMLTreeGetNode(xmlTree2);
64 if (!CFEqual(node1, node2)) return false;
65 for (child1 = CFTreeGetFirstChild(xmlTree1), child2 = CFTreeGetFirstChild(xmlTree2); child1 && child2; child1 = CFTreeGetNextSibling(child1), child2 = CFTreeGetNextSibling(child2)) {
66 if (!CFXMLTreeEqual(child1, child2)) return false;
67 }
68 return true;
69 }
70
71 static void _CFAppendXML(CFMutableStringRef str, CFXMLTreeRef tree);
72 static void _CFAppendXMLProlog(CFMutableStringRef str, const CFXMLTreeRef node);
73 static void _CFAppendXMLEpilog(CFMutableStringRef str, const CFXMLTreeRef node);
74
75 CFDataRef CFXMLTreeCreateXMLData(CFAllocatorRef allocator, CFXMLTreeRef xmlTree) {
76 CFMutableStringRef xmlStr;
77 CFDataRef result;
78 CFStringEncoding encoding;
79
80 __CFGenericValidateType(xmlTree, CFTreeGetTypeID());
81
82 xmlStr = CFStringCreateMutable(allocator, 0);
83 _CFAppendXML(xmlStr, xmlTree);
84 if (CFXMLNodeGetTypeCode(CFXMLTreeGetNode(xmlTree)) == kCFXMLNodeTypeDocument) {
85 const CFXMLDocumentInfo *docData = (CFXMLDocumentInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(xmlTree));
86 encoding = docData ? docData->encoding : kCFStringEncodingUTF8;
87 } else {
88 encoding = kCFStringEncodingUTF8;
89 }
90 result = CFStringCreateExternalRepresentation(allocator, xmlStr, encoding, 0);
91 CFRelease(xmlStr);
92 return result;
93 }
94
95 static void _CFAppendXML(CFMutableStringRef str, CFXMLTreeRef tree) {
96 CFXMLTreeRef child;
97 _CFAppendXMLProlog(str, tree);
98 for (child = CFTreeGetFirstChild(tree); child; child = CFTreeGetNextSibling(child)) {
99 _CFAppendXML(str, child);
100 }
101 _CFAppendXMLEpilog(str, tree);
102 }
103
104 CF_PRIVATE void appendQuotedString(CFMutableStringRef str, CFStringRef strToQuote) {
105 char quoteChar = CFStringFindWithOptions(strToQuote, CFSTR("\""), CFRangeMake(0, CFStringGetLength(strToQuote)), 0, NULL) ? '\'' : '\"';
106 CFStringAppendFormat(str, NULL, CFSTR("%c%@%c"), quoteChar, strToQuote, quoteChar);
107 }
108
109 static void appendExternalID(CFMutableStringRef str, CFXMLExternalID *extID) {
110 if (extID->publicID) {
111 CFStringAppendCString(str, " PUBLIC ", kCFStringEncodingASCII);
112 appendQuotedString(str, extID->publicID);
113 if (extID->systemID) {
114 // Technically, for externalIDs, systemID must not be NULL. However, by testing for a NULL systemID, we can use this to emit publicIDs, too. REW, 2/15/2000
115 CFStringAppendCString(str, " ", kCFStringEncodingASCII);
116 appendQuotedString(str, CFURLGetString(extID->systemID));
117 }
118 } else if (extID->systemID) {
119 CFStringAppendCString(str, " SYSTEM ", kCFStringEncodingASCII);
120 appendQuotedString(str, CFURLGetString(extID->systemID));
121 } else {
122 // Should never get here
123 }
124 }
125
126 static void appendElementProlog(CFMutableStringRef str, CFXMLTreeRef tree) {
127 const CFXMLElementInfo *data = (CFXMLElementInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree));
128 CFStringAppendFormat(str, NULL, CFSTR("<%@"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
129 if (data->attributeOrder) {
130 CFIndex i, c = CFArrayGetCount(data->attributeOrder);
131 for (i = 0; i < c; i ++) {
132 CFStringRef attr = (CFStringRef)CFArrayGetValueAtIndex(data->attributeOrder, i);
133 CFStringRef value = (CFStringRef)CFDictionaryGetValue(data->attributes, attr);
134 CFStringAppendFormat(str, NULL, CFSTR(" %@="), attr);
135 appendQuotedString(str, value);
136 }
137 }
138 if (data->isEmpty) {
139 CFStringAppendCString(str, "/>", kCFStringEncodingASCII);
140 } else {
141 CFStringAppendCString(str, ">", kCFStringEncodingASCII);
142 }
143 }
144
145 /* Although named "prolog", for leafs of the tree, this is the only XML generation function called. This is why Comments, Processing Instructions, etc. generate their XML during this function. REW, 2/11/2000 */
146 static void _CFAppendXMLProlog(CFMutableStringRef str, const CFXMLTreeRef tree) {
147 switch (CFXMLNodeGetTypeCode(CFXMLTreeGetNode(tree))) {
148 case kCFXMLNodeTypeDocument:
149 break;
150 case kCFXMLNodeTypeElement:
151 appendElementProlog(str, tree);
152 break;
153 case kCFXMLNodeTypeAttribute:
154 // Should never be encountered
155 break;
156 case kCFXMLNodeTypeProcessingInstruction: {
157 CFXMLProcessingInstructionInfo *data = (CFXMLProcessingInstructionInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree));
158 if (data->dataString) {
159 CFStringAppendFormat(str, NULL, CFSTR("<?%@ %@?>"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)), data->dataString);
160 } else {
161 CFStringAppendFormat(str, NULL, CFSTR("<?%@?>"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
162 }
163 break;
164 }
165 case kCFXMLNodeTypeComment:
166 CFStringAppendFormat(str, NULL, CFSTR("<!--%@-->"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
167 break;
168 case kCFXMLNodeTypeText:
169 CFStringAppend(str, CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
170 break;
171 case kCFXMLNodeTypeCDATASection:
172 CFStringAppendFormat(str, NULL, CFSTR("<![CDATA[%@]]>"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
173 break;
174 case kCFXMLNodeTypeDocumentFragment:
175 break;
176 case kCFXMLNodeTypeEntity: {
177 CFXMLEntityInfo *data = (CFXMLEntityInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree));
178 CFStringAppendCString(str, "<!ENTITY ", kCFStringEncodingASCII);
179 if (data->entityType == kCFXMLEntityTypeParameter) {
180 CFStringAppend(str, CFSTR("% "));
181 }
182 CFStringAppend(str, CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
183 CFStringAppend(str, CFSTR(" "));
184 if (data->replacementText) {
185 appendQuotedString(str, data->replacementText);
186 CFStringAppendCString(str, ">", kCFStringEncodingASCII);
187 } else {
188 appendExternalID(str, &(data->entityID));
189 if (data->notationName) {
190 CFStringAppendFormat(str, NULL, CFSTR(" NDATA %@"), data->notationName);
191 }
192 CFStringAppendCString(str, ">", kCFStringEncodingASCII);
193 }
194 break;
195 }
196 case kCFXMLNodeTypeEntityReference:
197 {
198 CFXMLEntityTypeCode entityType = ((CFXMLEntityReferenceInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree)))->entityType;
199 if (entityType == kCFXMLEntityTypeParameter) {
200 CFStringAppendFormat(str, NULL, CFSTR("%%%@;"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
201 } else {
202 CFStringAppendFormat(str, NULL, CFSTR("&%@;"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
203 }
204 break;
205 }
206 case kCFXMLNodeTypeDocumentType:
207 CFStringAppendCString(str, "<!DOCTYPE ", kCFStringEncodingASCII);
208 CFStringAppend(str, CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
209 if (CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree))) {
210 CFXMLExternalID *extID = &((CFXMLDocumentTypeInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree)))->externalID;
211 appendExternalID(str, extID);
212 }
213 CFStringAppendCString(str, " [", kCFStringEncodingASCII);
214 break;
215 case kCFXMLNodeTypeWhitespace:
216 CFStringAppend(str, CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
217 break;
218 case kCFXMLNodeTypeNotation: {
219 CFXMLNotationInfo *data = (CFXMLNotationInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree));
220 CFStringAppendFormat(str, NULL, CFSTR("<!NOTATION %@ "), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
221 appendExternalID(str, &(data->externalID));
222 CFStringAppendCString(str, ">", kCFStringEncodingASCII);
223 break;
224 }
225 case kCFXMLNodeTypeElementTypeDeclaration:
226 CFStringAppendFormat(str, NULL, CFSTR("<!ELEMENT %@ %@>"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)), ((CFXMLElementTypeDeclarationInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree)))->contentDescription);
227 break;
228 case kCFXMLNodeTypeAttributeListDeclaration: {
229 CFXMLAttributeListDeclarationInfo *attListData = (CFXMLAttributeListDeclarationInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree));
230 CFIndex idx;
231 CFStringAppendCString(str, "<!ATTLIST ", kCFStringEncodingASCII);
232 CFStringAppend(str, CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
233 for (idx = 0; idx < attListData->numberOfAttributes; idx ++) {
234 CFXMLAttributeDeclarationInfo *attr = &(attListData->attributes[idx]);
235 CFStringAppendFormat(str, NULL, CFSTR("\n\t%@ %@ %@"), attr->attributeName, attr->typeString, attr->defaultString);
236 }
237 CFStringAppendCString(str, ">", kCFStringEncodingASCII);
238 break;
239 }
240 default:
241 CFAssert1(false, __kCFLogAssertion, "Encountered unexpected XMLDataTypeID %d", CFXMLNodeGetTypeCode(CFXMLTreeGetNode(tree)));
242 }
243 }
244
245 static void _CFAppendXMLEpilog(CFMutableStringRef str, CFXMLTreeRef tree) {
246 CFXMLNodeTypeCode typeID = CFXMLNodeGetTypeCode(CFXMLTreeGetNode(tree));
247 if (typeID == kCFXMLNodeTypeElement) {
248 if (((CFXMLElementInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree)))->isEmpty) return;
249 CFStringAppendFormat(str, NULL, CFSTR("</%@>"), CFXMLNodeGetString(CFXMLTreeGetNode(tree)));
250 } else if (typeID == kCFXMLNodeTypeDocumentType) {
251 CFIndex len = CFStringGetLength(str);
252 if (CFStringHasSuffix(str, CFSTR(" ["))) {
253 // There were no in-line DTD elements
254 CFStringDelete(str, CFRangeMake(len-2, 2));
255 } else {
256 CFStringAppendCString(str, "]", kCFStringEncodingASCII);
257 }
258 CFStringAppendCString(str, ">", kCFStringEncodingASCII);
259 }
260 }
261
262 #pragma GCC diagnostic pop