| 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 |