|
1 |
|
2 /* |
|
3 * Copyright 2006 The Android Open Source Project |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 |
|
10 #include "SkXMLWriter.h" |
|
11 #include "SkStream.h" |
|
12 |
|
13 SkXMLWriter::SkXMLWriter(bool doEscapeMarkup) : fDoEscapeMarkup(doEscapeMarkup) |
|
14 { |
|
15 } |
|
16 |
|
17 SkXMLWriter::~SkXMLWriter() |
|
18 { |
|
19 SkASSERT(fElems.count() == 0); |
|
20 } |
|
21 |
|
22 void SkXMLWriter::flush() |
|
23 { |
|
24 while (fElems.count()) |
|
25 this->endElement(); |
|
26 } |
|
27 |
|
28 void SkXMLWriter::addAttribute(const char name[], const char value[]) |
|
29 { |
|
30 this->addAttributeLen(name, value, strlen(value)); |
|
31 } |
|
32 |
|
33 void SkXMLWriter::addS32Attribute(const char name[], int32_t value) |
|
34 { |
|
35 SkString tmp; |
|
36 tmp.appendS32(value); |
|
37 this->addAttribute(name, tmp.c_str()); |
|
38 } |
|
39 |
|
40 void SkXMLWriter::addHexAttribute(const char name[], uint32_t value, int minDigits) |
|
41 { |
|
42 SkString tmp("0x"); |
|
43 tmp.appendHex(value, minDigits); |
|
44 this->addAttribute(name, tmp.c_str()); |
|
45 } |
|
46 |
|
47 void SkXMLWriter::addScalarAttribute(const char name[], SkScalar value) |
|
48 { |
|
49 SkString tmp; |
|
50 tmp.appendScalar(value); |
|
51 this->addAttribute(name, tmp.c_str()); |
|
52 } |
|
53 |
|
54 void SkXMLWriter::doEnd(Elem* elem) |
|
55 { |
|
56 delete elem; |
|
57 } |
|
58 |
|
59 bool SkXMLWriter::doStart(const char name[], size_t length) |
|
60 { |
|
61 int level = fElems.count(); |
|
62 bool firstChild = level > 0 && !fElems[level-1]->fHasChildren; |
|
63 if (firstChild) |
|
64 fElems[level-1]->fHasChildren = true; |
|
65 Elem** elem = fElems.push(); |
|
66 *elem = new Elem; |
|
67 (*elem)->fName.set(name, length); |
|
68 (*elem)->fHasChildren = 0; |
|
69 return firstChild; |
|
70 } |
|
71 |
|
72 SkXMLWriter::Elem* SkXMLWriter::getEnd() |
|
73 { |
|
74 Elem* elem; |
|
75 fElems.pop(&elem); |
|
76 return elem; |
|
77 } |
|
78 |
|
79 const char* SkXMLWriter::getHeader() |
|
80 { |
|
81 static const char gHeader[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"; |
|
82 return gHeader; |
|
83 } |
|
84 |
|
85 void SkXMLWriter::startElement(const char name[]) |
|
86 { |
|
87 this->startElementLen(name, strlen(name)); |
|
88 } |
|
89 |
|
90 static const char* escape_char(char c, char storage[2]) |
|
91 { |
|
92 static const char* gEscapeChars[] = { |
|
93 "<<", |
|
94 ">>", |
|
95 //"\""", |
|
96 //"''", |
|
97 "&&" |
|
98 }; |
|
99 |
|
100 const char** array = gEscapeChars; |
|
101 for (unsigned i = 0; i < SK_ARRAY_COUNT(gEscapeChars); i++) |
|
102 { |
|
103 if (array[i][0] == c) |
|
104 return &array[i][1]; |
|
105 } |
|
106 storage[0] = c; |
|
107 storage[1] = 0; |
|
108 return storage; |
|
109 } |
|
110 |
|
111 static size_t escape_markup(char dst[], const char src[], size_t length) |
|
112 { |
|
113 size_t extra = 0; |
|
114 const char* stop = src + length; |
|
115 |
|
116 while (src < stop) |
|
117 { |
|
118 char orig[2]; |
|
119 const char* seq = escape_char(*src, orig); |
|
120 size_t seqSize = strlen(seq); |
|
121 |
|
122 if (dst) |
|
123 { |
|
124 memcpy(dst, seq, seqSize); |
|
125 dst += seqSize; |
|
126 } |
|
127 |
|
128 // now record the extra size needed |
|
129 extra += seqSize - 1; // minus one to subtract the original char |
|
130 |
|
131 // bump to the next src char |
|
132 src += 1; |
|
133 } |
|
134 return extra; |
|
135 } |
|
136 |
|
137 void SkXMLWriter::addAttributeLen(const char name[], const char value[], size_t length) |
|
138 { |
|
139 SkString valueStr; |
|
140 |
|
141 if (fDoEscapeMarkup) |
|
142 { |
|
143 size_t extra = escape_markup(NULL, value, length); |
|
144 if (extra) |
|
145 { |
|
146 valueStr.resize(length + extra); |
|
147 (void)escape_markup(valueStr.writable_str(), value, length); |
|
148 value = valueStr.c_str(); |
|
149 length += extra; |
|
150 } |
|
151 } |
|
152 this->onAddAttributeLen(name, value, length); |
|
153 } |
|
154 |
|
155 void SkXMLWriter::startElementLen(const char elem[], size_t length) |
|
156 { |
|
157 this->onStartElementLen(elem, length); |
|
158 } |
|
159 |
|
160 //////////////////////////////////////////////////////////////////////////////////////// |
|
161 |
|
162 static void write_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLWriter* w, bool skipRoot) |
|
163 { |
|
164 if (!skipRoot) |
|
165 { |
|
166 w->startElement(dom.getName(node)); |
|
167 |
|
168 SkDOM::AttrIter iter(dom, node); |
|
169 const char* name; |
|
170 const char* value; |
|
171 while ((name = iter.next(&value)) != NULL) |
|
172 w->addAttribute(name, value); |
|
173 } |
|
174 |
|
175 node = dom.getFirstChild(node, NULL); |
|
176 while (node) |
|
177 { |
|
178 write_dom(dom, node, w, false); |
|
179 node = dom.getNextSibling(node, NULL); |
|
180 } |
|
181 |
|
182 if (!skipRoot) |
|
183 w->endElement(); |
|
184 } |
|
185 |
|
186 void SkXMLWriter::writeDOM(const SkDOM& dom, const SkDOM::Node* node, bool skipRoot) |
|
187 { |
|
188 if (node) |
|
189 write_dom(dom, node, this, skipRoot); |
|
190 } |
|
191 |
|
192 void SkXMLWriter::writeHeader() |
|
193 { |
|
194 } |
|
195 |
|
196 // SkXMLStreamWriter |
|
197 |
|
198 static void tab(SkWStream& stream, int level) |
|
199 { |
|
200 for (int i = 0; i < level; i++) |
|
201 stream.writeText("\t"); |
|
202 } |
|
203 |
|
204 SkXMLStreamWriter::SkXMLStreamWriter(SkWStream* stream) : fStream(*stream) |
|
205 { |
|
206 } |
|
207 |
|
208 SkXMLStreamWriter::~SkXMLStreamWriter() |
|
209 { |
|
210 this->flush(); |
|
211 } |
|
212 |
|
213 void SkXMLStreamWriter::onAddAttributeLen(const char name[], const char value[], size_t length) |
|
214 { |
|
215 SkASSERT(!fElems.top()->fHasChildren); |
|
216 fStream.writeText(" "); |
|
217 fStream.writeText(name); |
|
218 fStream.writeText("=\""); |
|
219 fStream.write(value, length); |
|
220 fStream.writeText("\""); |
|
221 } |
|
222 |
|
223 void SkXMLStreamWriter::onEndElement() |
|
224 { |
|
225 Elem* elem = getEnd(); |
|
226 if (elem->fHasChildren) |
|
227 { |
|
228 tab(fStream, fElems.count()); |
|
229 fStream.writeText("</"); |
|
230 fStream.writeText(elem->fName.c_str()); |
|
231 fStream.writeText(">"); |
|
232 } |
|
233 else |
|
234 fStream.writeText("/>"); |
|
235 fStream.newline(); |
|
236 doEnd(elem); |
|
237 } |
|
238 |
|
239 void SkXMLStreamWriter::onStartElementLen(const char name[], size_t length) |
|
240 { |
|
241 int level = fElems.count(); |
|
242 if (this->doStart(name, length)) |
|
243 { |
|
244 // the first child, need to close with > |
|
245 fStream.writeText(">"); |
|
246 fStream.newline(); |
|
247 } |
|
248 |
|
249 tab(fStream, level); |
|
250 fStream.writeText("<"); |
|
251 fStream.write(name, length); |
|
252 } |
|
253 |
|
254 void SkXMLStreamWriter::writeHeader() |
|
255 { |
|
256 const char* header = getHeader(); |
|
257 fStream.write(header, strlen(header)); |
|
258 fStream.newline(); |
|
259 } |
|
260 |
|
261 //////////////////////////////////////////////////////////////////////////////////////////////// |
|
262 |
|
263 #include "SkXMLParser.h" |
|
264 |
|
265 SkXMLParserWriter::SkXMLParserWriter(SkXMLParser* parser) |
|
266 : SkXMLWriter(false), fParser(*parser) |
|
267 { |
|
268 } |
|
269 |
|
270 SkXMLParserWriter::~SkXMLParserWriter() |
|
271 { |
|
272 this->flush(); |
|
273 } |
|
274 |
|
275 void SkXMLParserWriter::onAddAttributeLen(const char name[], const char value[], size_t length) |
|
276 { |
|
277 SkASSERT(fElems.count() == 0 || !fElems.top()->fHasChildren); |
|
278 SkString str(value, length); |
|
279 fParser.addAttribute(name, str.c_str()); |
|
280 } |
|
281 |
|
282 void SkXMLParserWriter::onEndElement() |
|
283 { |
|
284 Elem* elem = this->getEnd(); |
|
285 fParser.endElement(elem->fName.c_str()); |
|
286 this->doEnd(elem); |
|
287 } |
|
288 |
|
289 void SkXMLParserWriter::onStartElementLen(const char name[], size_t length) |
|
290 { |
|
291 (void)this->doStart(name, length); |
|
292 SkString str(name, length); |
|
293 fParser.startElement(str.c_str()); |
|
294 } |
|
295 |
|
296 |
|
297 //////////////////////////////////////////////////////////////////////////////////////// |
|
298 //////////////////////////////////////////////////////////////////////////////////////// |
|
299 |
|
300 #ifdef SK_DEBUG |
|
301 |
|
302 void SkXMLStreamWriter::UnitTest() |
|
303 { |
|
304 #ifdef SK_SUPPORT_UNITTEST |
|
305 SkDebugWStream s; |
|
306 SkXMLStreamWriter w(&s); |
|
307 |
|
308 w.startElement("elem0"); |
|
309 w.addAttribute("hello", "world"); |
|
310 w.addS32Attribute("dec", 42); |
|
311 w.addHexAttribute("hex", 0x42, 3); |
|
312 w.addScalarAttribute("scalar", -4.2f); |
|
313 w.startElement("elem1"); |
|
314 w.endElement(); |
|
315 w.startElement("elem1"); |
|
316 w.addAttribute("name", "value"); |
|
317 w.endElement(); |
|
318 w.startElement("elem1"); |
|
319 w.startElement("elem2"); |
|
320 w.startElement("elem3"); |
|
321 w.addAttribute("name", "value"); |
|
322 w.endElement(); |
|
323 w.endElement(); |
|
324 w.startElement("elem2"); |
|
325 w.endElement(); |
|
326 w.endElement(); |
|
327 w.endElement(); |
|
328 #endif |
|
329 } |
|
330 |
|
331 #endif |