1 // =================================================================================================
2 // Copyright 2005-2007 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
6 // of the Adobe license agreement accompanying it.
7 // =================================================================================================
8
9 #include "XMP_Environment.h" // ! Must be the first #include!
10 #include "XMLParserAdapter.hpp"
11
12 #include <map>
13 #include <cstring>
14 #include <cstdio>
15
16 // ! Can't include XMP..._Impl.hpp - used by both Core and Files.
17 #define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0)
18
19 #if XMP_WinBuild
20 #ifdef _MSC_VER
21 #define snprintf _snprintf
22 #pragma warning ( disable : 4996 ) // snprintf is safe
23 #endif
24 #endif
25
26 // =================================================================================================
27
28 #if 0 // Pattern for iterating over the children or attributes:
29 for ( size_t xxNum = 0, xxLim = _node_->_offspring_->size(); xxNum < xxLim; ++xxNum ) {
30 const XML_NodePtr _curr_ = _node_->_offspring_[xxNum];
31 }
32 #endif
33
34 // =================================================================================================
35 // XML_Node::IsWhitespaceNode
36 //===========================
37
IsWhitespaceNode() const38 bool XML_Node::IsWhitespaceNode() const
39 {
40 if ( this->kind != kCDataNode ) return false;
41
42 for ( size_t i = 0; i < this->value.size(); ++i ) {
43 unsigned char ch = this->value[i];
44 if ( IsWhitespaceChar ( ch ) ) continue;
45 // *** Add checks for other whitespace characters.
46 return false; // All the checks failed, this isn't whitespace.
47 }
48
49 return true;
50
51 } // XML_Node::IsWhitespaceNode
52
53 // =================================================================================================
54 // XML_Node::IsLeafContentNode
55 //============================
56
IsLeafContentNode() const57 bool XML_Node::IsLeafContentNode() const
58 {
59 if ( this->kind != kElemNode ) return false;
60 if ( this->content.size() == 0 ) return true;
61 if ( this->content.size() > 1 ) return false;
62 if ( this->content[0]->kind != kCDataNode ) return false;
63
64 return true;
65
66 } // XML_Node::IsLeafContentNode
67
68 // =================================================================================================
69 // XML_Node::IsEmptyLeafNode
70 //==========================
71
IsEmptyLeafNode() const72 bool XML_Node::IsEmptyLeafNode() const
73 {
74
75 if ( (this->kind != kElemNode) || (this->content.size() != 0) ) return false;
76 return true;
77
78 } // XML_Node::IsEmptyLeafNode
79
80 // =================================================================================================
81 // XML_Node::GetAttrValue
82 //=======================
83
GetAttrValue(XMP_StringPtr attrName) const84 XMP_StringPtr XML_Node::GetAttrValue ( XMP_StringPtr attrName ) const
85 {
86
87 for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) {
88 XML_Node * attrPtr = this->attrs[i];
89 if ( ! attrPtr->ns.empty() ) continue; // This form of GetAttrValue is for attrs in no namespace.
90 if ( attrPtr->name == attrName ) return attrPtr->value.c_str();
91 }
92
93 return 0; // Not found.
94
95 } // XML_Node::GetAttrValue
96
97 // =================================================================================================
98 // XML_Node::SetAttrValue
99 //=======================
100
SetAttrValue(XMP_StringPtr attrName,XMP_StringPtr attrValue)101 void XML_Node::SetAttrValue ( XMP_StringPtr attrName, XMP_StringPtr attrValue )
102 {
103
104 for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) {
105 XML_Node * attrPtr = this->attrs[i];
106 if ( ! attrPtr->ns.empty() ) continue; // This form of SetAttrValue is for attrs in no namespace.
107 if ( attrPtr->name == attrName ) {
108 attrPtr->value = attrValue;
109 return;
110 }
111 }
112
113 } // XML_Node::SetAttrValue
114
115 // =================================================================================================
116 // XML_Node::GetLeafContentValue
117 //==============================
118
GetLeafContentValue() const119 XMP_StringPtr XML_Node::GetLeafContentValue() const
120 {
121 if ( (! this->IsLeafContentNode()) || this->content.empty() ) return "";
122
123 return this->content[0]->value.c_str();
124
125 } // XML_Node::GetLeafContentValue
126
127 // =================================================================================================
128 // XML_Node::SetLeafContentValue
129 //==============================
130
SetLeafContentValue(XMP_StringPtr newValue)131 void XML_Node::SetLeafContentValue ( XMP_StringPtr newValue )
132 {
133 XML_Node * valueNode;
134
135 if ( ! this->content.empty() ) {
136 valueNode = this->content[0];
137 } else {
138 valueNode = new XML_Node ( this, "", kCDataNode );
139 this->content.push_back ( valueNode );
140 }
141
142 valueNode->value = newValue;
143
144 } // XML_Node::SetLeafContentValue
145
146 // =================================================================================================
147 // XML_Node::CountNamedElements
148 //=============================
149
CountNamedElements(XMP_StringPtr nsURI,XMP_StringPtr localName) const150 size_t XML_Node::CountNamedElements ( XMP_StringPtr nsURI, XMP_StringPtr localName ) const
151 {
152 size_t count = 0;
153
154 for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) {
155 const XML_Node & child = *this->content[i];
156 if ( child.ns != nsURI ) continue;
157 if ( strcmp ( localName, child.name.c_str()+child.nsPrefixLen ) != 0 ) continue;
158 ++count;
159 }
160
161 return count;
162
163 } // XML_Node::CountNamedElements
164
165 // =================================================================================================
166 // XML_Node::GetNamedElement
167 //==========================
168
GetNamedElement(XMP_StringPtr nsURI,XMP_StringPtr localName,size_t which)169 XML_NodePtr XML_Node::GetNamedElement ( XMP_StringPtr nsURI, XMP_StringPtr localName, size_t which /* = 0 */ )
170 {
171
172 for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) {
173 XML_Node * childPtr = this->content[i];
174 if ( childPtr->ns != nsURI ) continue;
175 if ( strcmp ( localName, childPtr->name.c_str()+childPtr->nsPrefixLen ) != 0 ) continue;
176 if ( which == 0 ) return childPtr;
177 --which;
178 }
179
180 return 0; /// Not found.
181
182 } // XML_Node::GetNamedElement
183
184 // =================================================================================================
185 // DumpNodeList
186 // ============
187
188 static const char * kNodeKinds[] = { "root", "elem", "attr", "cdata", "pi" };
189
DumpNodeList(std::string * buffer,const XML_NodeVector & list,int indent)190 static void DumpNodeList ( std::string * buffer, const XML_NodeVector & list, int indent )
191 {
192
193 for ( size_t i = 0, limit = list.size(); i < limit; ++i ) {
194
195 const XML_Node * node = list[i];
196
197 for ( int t = indent; t > 0; --t ) *buffer += " ";
198 if ( node->IsWhitespaceNode() ) {
199 *buffer += "-- whitespace --\n";
200 continue;
201 }
202
203 *buffer += node->name;
204 *buffer += " - ";
205 *buffer += kNodeKinds[node->kind];
206 if ( ! node->value.empty() ) {
207 *buffer += ", value=\"";
208 *buffer += node->value;
209 *buffer += "\"";
210 }
211 if ( ! node->ns.empty() ) {
212 *buffer += ", ns=\"";
213 *buffer += node->ns;
214 *buffer += "\"";
215 }
216 if ( node->nsPrefixLen != 0 ) {
217 *buffer += ", prefixLen=";
218 char numBuf [20];
219 snprintf ( numBuf, sizeof(numBuf), "%lu", (unsigned long)node->nsPrefixLen );
220 *buffer += numBuf;
221 }
222 *buffer += "\n";
223
224 if ( ! node->attrs.empty() ) {
225 for ( int t = indent+1; t > 0; --t ) *buffer += " ";
226 *buffer += "attrs:\n";
227 DumpNodeList ( buffer, node->attrs, indent+2 );
228 }
229
230 if ( ! node->content.empty() ) {
231 DumpNodeList ( buffer, node->content, indent+1 );
232 }
233
234 }
235
236 } // DumpNodeList
237
238 // =================================================================================================
239 // XML_Node::Dump
240 //===============
241
Dump(std::string * buffer)242 void XML_Node::Dump ( std::string * buffer )
243 {
244
245 *buffer = "Dump of XML_Node tree\n";
246
247 *buffer += "Root info: name=\"";
248 *buffer += this->name;
249 *buffer += "\", value=\"";
250 *buffer += this->value;
251 *buffer += "\", ns=\"";
252 *buffer += this->ns;
253 *buffer += "\", kind=";
254 *buffer += kNodeKinds[this->kind];
255 *buffer += "\n";
256
257 if ( ! this->attrs.empty() ) {
258 *buffer += " attrs:\n";
259 DumpNodeList ( buffer, this->attrs, 2 );
260 }
261 *buffer += "\n";
262
263 DumpNodeList ( buffer, this->content, 0 );
264
265 } // XML_Node::Dump
266
267 // =================================================================================================
268 // SerializeOneNode
269 // ================
270
SerializeOneNode(std::string * buffer,const XML_Node & node)271 static void SerializeOneNode ( std::string * buffer, const XML_Node & node )
272 {
273 size_t i, limit;
274 XMP_StringPtr namePtr = node.name.c_str();
275 if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces.
276
277 switch ( node.kind ) {
278
279 case kElemNode:
280 *buffer += '<';
281 *buffer += namePtr;
282 for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) {
283 SerializeOneNode ( buffer, *node.attrs[i] );
284 }
285 if ( node.content.empty() ) {
286 *buffer += "/>";
287 } else {
288 *buffer += '>';
289 for ( i = 0, limit = node.content.size(); i < limit; ++i ) {
290 SerializeOneNode ( buffer, *node.content[i] );
291 }
292 *buffer += "</";
293 *buffer += namePtr;
294 *buffer += '>';
295 }
296 break;
297
298 case kAttrNode:
299 *buffer += ' ';
300 *buffer += namePtr;
301 *buffer += "=\"";
302 *buffer += node.value;
303 *buffer += '"';
304 break;
305
306 case kCDataNode:
307 *buffer += node.value;
308 break;
309
310 case kPINode:
311 *buffer += node.value; // *** Note that we're dropping PIs during the Expat parse.
312 break;
313
314 }
315
316 } // SerializeOneNode
317
318 // =================================================================================================
319 // CollectNamespaceDecls
320 // =====================
321
322 typedef std::map < std::string, std::string > NamespaceMap;
323
CollectNamespaceDecls(NamespaceMap * nsMap,const XML_Node & node)324 static void CollectNamespaceDecls ( NamespaceMap * nsMap, const XML_Node & node )
325 {
326 size_t i, limit;
327
328 if ( ! node.ns.empty() ) {
329 size_t nameMid = 0;
330 while ( node.name[nameMid] != ':' ) ++nameMid;
331 std::string prefix = node.name.substr ( 0, nameMid );
332 (*nsMap)[prefix] = node.ns;
333 }
334
335 if ( node.kind == kElemNode ) {
336
337 for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) {
338 CollectNamespaceDecls ( nsMap, *node.attrs[i] );
339 }
340
341 for ( i = 0, limit = node.content.size(); i < limit; ++i ) {
342 const XML_Node & content = *node.content[i];
343 if ( content.kind == kElemNode ) CollectNamespaceDecls ( nsMap, content );
344 }
345
346 }
347
348 } // CollectNamespaceDecls
349
350 // =================================================================================================
351 // XML_Node::Serialize
352 //====================
353
Serialize(std::string * buffer)354 void XML_Node::Serialize ( std::string * buffer )
355 {
356 buffer->erase();
357
358 if ( this->kind != kRootNode ) {
359
360 SerializeOneNode ( buffer, *this );
361
362 } else {
363
364 // Do the outermost level here, in order to add the XML version and namespace declarations.
365
366 *buffer += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
367
368 for ( size_t outer = 0, oLimit = this->content.size(); outer < oLimit; ++outer ) {
369
370 const XML_Node & node = *this->content[outer];
371
372 if ( node.kind != kElemNode ) {
373
374 SerializeOneNode ( buffer, node );
375
376 } else {
377
378 XMP_StringPtr namePtr = node.name.c_str();
379 if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces.
380
381 *buffer += '<';
382 *buffer += namePtr;
383
384 NamespaceMap nsMap;
385 CollectNamespaceDecls ( &nsMap, node );
386 NamespaceMap::iterator nsDecl = nsMap.begin();
387 NamespaceMap::iterator nsEnd = nsMap.end();
388 for ( ; nsDecl != nsEnd; ++nsDecl ) {
389 const std::string & prefix = nsDecl->first;
390 *buffer += " xmlns";
391 if ( prefix != "_dflt_" ) { *buffer += ':'; *buffer += prefix; }
392 *buffer += "=\"";
393 *buffer += nsDecl->second;
394 *buffer += '"';
395 }
396
397 for ( size_t attr = 0, aLimit = node.attrs.size(); attr < aLimit; ++attr ) {
398 SerializeOneNode ( buffer, *node.attrs[attr] );
399 }
400
401 if ( node.content.empty() ) {
402 *buffer += "/>";
403 } else {
404 *buffer += '>';
405 for ( size_t child = 0, cLimit = node.content.size(); child < cLimit; ++child ) {
406 SerializeOneNode ( buffer, *node.content[child] );
407 }
408 *buffer += "</";
409 *buffer += namePtr;
410 *buffer += '>';
411 }
412
413 }
414
415 }
416
417 }
418
419
420 } // XML_Node::Serialize
421
422 // =================================================================================================
423 // XML_Node::RemoveAttrs
424 //======================
425
RemoveAttrs()426 void XML_Node::RemoveAttrs()
427 {
428
429 for ( size_t i = 0, vLim = this->attrs.size(); i < vLim; ++i ) delete this->attrs[i];
430 this->attrs.clear();
431
432 } // XML_Node::RemoveAttrs
433
434 // =================================================================================================
435 // XML_Node::RemoveContent
436 //========================
437
RemoveContent()438 void XML_Node::RemoveContent()
439 {
440
441 for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) delete this->content[i];
442 this->content.clear();
443
444 } // XML_Node::RemoveContent
445
446 // =================================================================================================
447 // XML_Node::ClearNode
448 //====================
449
ClearNode()450 void XML_Node::ClearNode()
451 {
452
453 this->kind = 0;
454 this->ns.erase();
455 this->name.erase();
456 this->value.erase();
457
458 this->RemoveAttrs();
459 this->RemoveContent();
460
461 } // XML_Node::ClearNode
462
463 // =================================================================================================
464