SkXMLWriter.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. * Copyright 2006 The Android Open Source Project
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/xml/SkXMLWriter.h"
  8. #include "include/core/SkStream.h"
  9. #include "include/private/SkTo.h"
  10. SkXMLWriter::SkXMLWriter(bool doEscapeMarkup) : fDoEscapeMarkup(doEscapeMarkup)
  11. {}
  12. SkXMLWriter::~SkXMLWriter() {
  13. SkASSERT(fElems.count() == 0);
  14. }
  15. void SkXMLWriter::flush() {
  16. while (fElems.count()) {
  17. this->endElement();
  18. }
  19. }
  20. void SkXMLWriter::addAttribute(const char name[], const char value[]) {
  21. this->addAttributeLen(name, value, strlen(value));
  22. }
  23. void SkXMLWriter::addS32Attribute(const char name[], int32_t value) {
  24. SkString tmp;
  25. tmp.appendS32(value);
  26. this->addAttribute(name, tmp.c_str());
  27. }
  28. void SkXMLWriter::addHexAttribute(const char name[], uint32_t value, int minDigits) {
  29. SkString tmp("0x");
  30. tmp.appendHex(value, minDigits);
  31. this->addAttribute(name, tmp.c_str());
  32. }
  33. void SkXMLWriter::addScalarAttribute(const char name[], SkScalar value) {
  34. SkString tmp;
  35. tmp.appendScalar(value);
  36. this->addAttribute(name, tmp.c_str());
  37. }
  38. void SkXMLWriter::addText(const char text[], size_t length) {
  39. if (fElems.isEmpty()) {
  40. return;
  41. }
  42. this->onAddText(text, length);
  43. fElems.top()->fHasText = true;
  44. }
  45. void SkXMLWriter::doEnd(Elem* elem) {
  46. delete elem;
  47. }
  48. bool SkXMLWriter::doStart(const char name[], size_t length) {
  49. int level = fElems.count();
  50. bool firstChild = level > 0 && !fElems[level-1]->fHasChildren;
  51. if (firstChild) {
  52. fElems[level-1]->fHasChildren = true;
  53. }
  54. Elem** elem = fElems.push();
  55. *elem = new Elem(name, length);
  56. return firstChild;
  57. }
  58. SkXMLWriter::Elem* SkXMLWriter::getEnd() {
  59. Elem* elem;
  60. fElems.pop(&elem);
  61. return elem;
  62. }
  63. const char* SkXMLWriter::getHeader() {
  64. static const char gHeader[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
  65. return gHeader;
  66. }
  67. void SkXMLWriter::startElement(const char name[]) {
  68. this->startElementLen(name, strlen(name));
  69. }
  70. static const char* escape_char(char c, char storage[2]) {
  71. static const char* gEscapeChars[] = {
  72. "<&lt;",
  73. ">&gt;",
  74. //"\"&quot;",
  75. //"'&apos;",
  76. "&&amp;"
  77. };
  78. const char** array = gEscapeChars;
  79. for (unsigned i = 0; i < SK_ARRAY_COUNT(gEscapeChars); i++) {
  80. if (array[i][0] == c) {
  81. return &array[i][1];
  82. }
  83. }
  84. storage[0] = c;
  85. storage[1] = 0;
  86. return storage;
  87. }
  88. static size_t escape_markup(char dst[], const char src[], size_t length) {
  89. size_t extra = 0;
  90. const char* stop = src + length;
  91. while (src < stop) {
  92. char orig[2];
  93. const char* seq = escape_char(*src, orig);
  94. size_t seqSize = strlen(seq);
  95. if (dst) {
  96. memcpy(dst, seq, seqSize);
  97. dst += seqSize;
  98. }
  99. // now record the extra size needed
  100. extra += seqSize - 1; // minus one to subtract the original char
  101. // bump to the next src char
  102. src += 1;
  103. }
  104. return extra;
  105. }
  106. void SkXMLWriter::addAttributeLen(const char name[], const char value[], size_t length) {
  107. SkString valueStr;
  108. if (fDoEscapeMarkup) {
  109. size_t extra = escape_markup(nullptr, value, length);
  110. if (extra) {
  111. valueStr.resize(length + extra);
  112. (void)escape_markup(valueStr.writable_str(), value, length);
  113. value = valueStr.c_str();
  114. length += extra;
  115. }
  116. }
  117. this->onAddAttributeLen(name, value, length);
  118. }
  119. void SkXMLWriter::startElementLen(const char elem[], size_t length) {
  120. this->onStartElementLen(elem, length);
  121. }
  122. ////////////////////////////////////////////////////////////////////////////////////////
  123. static void write_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLWriter* w, bool skipRoot) {
  124. if (!skipRoot) {
  125. const char* elem = dom.getName(node);
  126. if (dom.getType(node) == SkDOM::kText_Type) {
  127. SkASSERT(dom.countChildren(node) == 0);
  128. w->addText(elem, strlen(elem));
  129. return;
  130. }
  131. w->startElement(elem);
  132. SkDOM::AttrIter iter(dom, node);
  133. const char* name;
  134. const char* value;
  135. while ((name = iter.next(&value)) != nullptr) {
  136. w->addAttribute(name, value);
  137. }
  138. }
  139. node = dom.getFirstChild(node, nullptr);
  140. while (node) {
  141. write_dom(dom, node, w, false);
  142. node = dom.getNextSibling(node, nullptr);
  143. }
  144. if (!skipRoot) {
  145. w->endElement();
  146. }
  147. }
  148. void SkXMLWriter::writeDOM(const SkDOM& dom, const SkDOM::Node* node, bool skipRoot) {
  149. if (node) {
  150. write_dom(dom, node, this, skipRoot);
  151. }
  152. }
  153. void SkXMLWriter::writeHeader()
  154. {}
  155. // SkXMLStreamWriter
  156. static void tab(SkWStream& stream, int level) {
  157. for (int i = 0; i < level; i++) {
  158. stream.writeText("\t");
  159. }
  160. }
  161. SkXMLStreamWriter::SkXMLStreamWriter(SkWStream* stream) : fStream(*stream)
  162. {}
  163. SkXMLStreamWriter::~SkXMLStreamWriter() {
  164. this->flush();
  165. }
  166. void SkXMLStreamWriter::onAddAttributeLen(const char name[], const char value[], size_t length) {
  167. SkASSERT(!fElems.top()->fHasChildren && !fElems.top()->fHasText);
  168. fStream.writeText(" ");
  169. fStream.writeText(name);
  170. fStream.writeText("=\"");
  171. fStream.write(value, length);
  172. fStream.writeText("\"");
  173. }
  174. void SkXMLStreamWriter::onAddText(const char text[], size_t length) {
  175. Elem* elem = fElems.top();
  176. if (!elem->fHasChildren && !elem->fHasText) {
  177. fStream.writeText(">");
  178. fStream.newline();
  179. }
  180. tab(fStream, fElems.count() + 1);
  181. fStream.write(text, length);
  182. fStream.newline();
  183. }
  184. void SkXMLStreamWriter::onEndElement() {
  185. Elem* elem = getEnd();
  186. if (elem->fHasChildren || elem->fHasText) {
  187. tab(fStream, fElems.count());
  188. fStream.writeText("</");
  189. fStream.writeText(elem->fName.c_str());
  190. fStream.writeText(">");
  191. } else {
  192. fStream.writeText("/>");
  193. }
  194. fStream.newline();
  195. doEnd(elem);
  196. }
  197. void SkXMLStreamWriter::onStartElementLen(const char name[], size_t length) {
  198. int level = fElems.count();
  199. if (this->doStart(name, length)) {
  200. // the first child, need to close with >
  201. fStream.writeText(">");
  202. fStream.newline();
  203. }
  204. tab(fStream, level);
  205. fStream.writeText("<");
  206. fStream.write(name, length);
  207. }
  208. void SkXMLStreamWriter::writeHeader() {
  209. const char* header = getHeader();
  210. fStream.write(header, strlen(header));
  211. fStream.newline();
  212. }
  213. ////////////////////////////////////////////////////////////////////////////////////////////////
  214. #include "src/xml/SkXMLParser.h"
  215. SkXMLParserWriter::SkXMLParserWriter(SkXMLParser* parser)
  216. : SkXMLWriter(false), fParser(*parser)
  217. {
  218. }
  219. SkXMLParserWriter::~SkXMLParserWriter() {
  220. this->flush();
  221. }
  222. void SkXMLParserWriter::onAddAttributeLen(const char name[], const char value[], size_t length) {
  223. SkASSERT(fElems.count() == 0 || (!fElems.top()->fHasChildren && !fElems.top()->fHasText));
  224. SkString str(value, length);
  225. fParser.addAttribute(name, str.c_str());
  226. }
  227. void SkXMLParserWriter::onAddText(const char text[], size_t length) {
  228. fParser.text(text, SkToInt(length));
  229. }
  230. void SkXMLParserWriter::onEndElement() {
  231. Elem* elem = this->getEnd();
  232. fParser.endElement(elem->fName.c_str());
  233. this->doEnd(elem);
  234. }
  235. void SkXMLParserWriter::onStartElementLen(const char name[], size_t length) {
  236. (void)this->doStart(name, length);
  237. SkString str(name, length);
  238. fParser.startElement(str.c_str());
  239. }