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