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