Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/common/libxml_utils.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/file_path.h"
      9 #include "base/logging.h"
     10 #include "base/stringprintf.h"
     11 #include "base/utf_string_conversions.h"
     12 
     13 #include "libxml/xmlreader.h"
     14 
     15 std::string XmlStringToStdString(const xmlChar* xmlstring) {
     16   // xmlChar*s are UTF-8, so this cast is safe.
     17   if (xmlstring)
     18     return std::string(reinterpret_cast<const char*>(xmlstring));
     19   else
     20     return "";
     21 }
     22 
     23 XmlReader::XmlReader()
     24     : reader_(NULL),
     25       ALLOW_THIS_IN_INITIALIZER_LIST(
     26           error_func_(this, &XmlReader::GenericErrorCallback)) {
     27 }
     28 
     29 XmlReader::~XmlReader() {
     30   if (reader_)
     31     xmlFreeTextReader(reader_);
     32 }
     33 
     34 // static
     35 void XmlReader::GenericErrorCallback(void* context, const char* msg, ...) {
     36   va_list args;
     37   va_start(args, msg);
     38 
     39   XmlReader* reader = static_cast<XmlReader*>(context);
     40   reader->errors_.append(base::StringPrintV(msg, args));
     41   va_end(args);
     42 }
     43 
     44 bool XmlReader::Load(const std::string& input) {
     45   const int kParseOptions = XML_PARSE_RECOVER |  // recover on errors
     46                             XML_PARSE_NONET;     // forbid network access
     47   // TODO(evanm): Verify it's OK to pass NULL for the URL and encoding.
     48   // The libxml code allows for these, but it's unclear what effect is has.
     49   reader_ = xmlReaderForMemory(input.data(), static_cast<int>(input.size()),
     50                                NULL, NULL, kParseOptions);
     51   return reader_ != NULL;
     52 }
     53 
     54 bool XmlReader::LoadFile(const FilePath& file_path) {
     55   const int kParseOptions = XML_PARSE_RECOVER |  // recover on errors
     56                             XML_PARSE_NONET;     // forbid network access
     57   reader_ = xmlReaderForFile(
     58 #if defined(OS_WIN)
     59       // libxml takes UTF-8 paths on Windows; search the source for
     60       // xmlWrapOpenUtf8 to see it converting UTF-8 back to wide
     61       // characters.
     62       WideToUTF8(file_path.value()).c_str(),
     63 #else
     64       file_path.value().c_str(),
     65 #endif
     66       NULL, kParseOptions);
     67   return reader_ != NULL;
     68 }
     69 
     70 bool XmlReader::NodeAttribute(const char* name, std::string* out) {
     71   xmlChar* value = xmlTextReaderGetAttribute(reader_, BAD_CAST name);
     72   if (!value)
     73     return false;
     74   *out = XmlStringToStdString(value);
     75   xmlFree(value);
     76   return true;
     77 }
     78 
     79 bool XmlReader::ReadElementContent(std::string* content) {
     80   DCHECK(NodeType() == XML_READER_TYPE_ELEMENT);
     81   const int start_depth = Depth();
     82 
     83   if (xmlTextReaderIsEmptyElement(reader_)) {
     84     // Empty tag.  We succesfully read the content, but it's
     85     // empty.
     86     *content = "";
     87     // Advance past this empty tag.
     88     if (!Read())
     89       return false;
     90     return true;
     91   }
     92 
     93   // Advance past opening element tag.
     94   if (!Read())
     95     return false;
     96 
     97   // Read the content.  We read up until we hit a closing tag at the
     98   // same level as our starting point.
     99   while (NodeType() != XML_READER_TYPE_END_ELEMENT || Depth() != start_depth) {
    100     *content += XmlStringToStdString(xmlTextReaderConstValue(reader_));
    101     if (!Read())
    102       return false;
    103   }
    104 
    105   // Advance past ending element tag.
    106   DCHECK_EQ(NodeType(), XML_READER_TYPE_END_ELEMENT);
    107   if (!Read())
    108     return false;
    109 
    110   return true;
    111 }
    112 
    113 bool XmlReader::SkipToElement() {
    114   do {
    115     switch (NodeType()) {
    116     case XML_READER_TYPE_ELEMENT:
    117       return true;
    118     case XML_READER_TYPE_END_ELEMENT:
    119       return false;
    120     default:
    121       // Skip all other node types.
    122       continue;
    123     }
    124   } while (Read());
    125   return false;
    126 }
    127 
    128 
    129 // XmlWriter functions
    130 
    131 XmlWriter::XmlWriter()
    132     : writer_(NULL),
    133       buffer_(NULL) {}
    134 
    135 XmlWriter::~XmlWriter() {
    136   if (writer_)
    137     xmlFreeTextWriter(writer_);
    138   if (buffer_)
    139     xmlBufferFree(buffer_);
    140 }
    141 
    142 void XmlWriter::StartWriting() {
    143   buffer_ = xmlBufferCreate();
    144   writer_ = xmlNewTextWriterMemory(buffer_, 0);
    145   xmlTextWriterSetIndent(writer_, 1);
    146   xmlTextWriterStartDocument(writer_, NULL, NULL, NULL);
    147 }
    148 
    149 void XmlWriter::StopWriting() {
    150   xmlTextWriterEndDocument(writer_);
    151   xmlFreeTextWriter(writer_);
    152   writer_ = NULL;
    153 }
    154