Home | History | Annotate | Download | only in xml
      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         "<&lt;",
     94         ">&gt;",
     95         //"\"&quot;",
     96         //"'&apos;",
     97         "&&amp;"
     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 #ifdef SK_SCALAR_IS_FLOAT
    313     w.addScalarAttribute("scalar", -4.2f);
    314 #endif
    315     w.startElement("elem1");
    316         w.endElement();
    317         w.startElement("elem1");
    318         w.addAttribute("name", "value");
    319         w.endElement();
    320         w.startElement("elem1");
    321             w.startElement("elem2");
    322                 w.startElement("elem3");
    323                 w.addAttribute("name", "value");
    324                 w.endElement();
    325             w.endElement();
    326             w.startElement("elem2");
    327             w.endElement();
    328         w.endElement();
    329     w.endElement();
    330 #endif
    331 }
    332 
    333 #endif
    334 
    335