• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
XmlStringToStdString(const xmlChar * xmlstring)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 
XmlReader()23 XmlReader::XmlReader()
24     : reader_(NULL),
25       ALLOW_THIS_IN_INITIALIZER_LIST(
26           error_func_(this, &XmlReader::GenericErrorCallback)) {
27 }
28 
~XmlReader()29 XmlReader::~XmlReader() {
30   if (reader_)
31     xmlFreeTextReader(reader_);
32 }
33 
34 // static
GenericErrorCallback(void * context,const char * msg,...)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 
Load(const std::string & input)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 
LoadFile(const FilePath & file_path)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 
NodeAttribute(const char * name,std::string * out)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 
ReadElementContent(std::string * content)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 
SkipToElement()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 
XmlWriter()131 XmlWriter::XmlWriter()
132     : writer_(NULL),
133       buffer_(NULL) {}
134 
~XmlWriter()135 XmlWriter::~XmlWriter() {
136   if (writer_)
137     xmlFreeTextWriter(writer_);
138   if (buffer_)
139     xmlBufferFree(buffer_);
140 }
141 
StartWriting()142 void XmlWriter::StartWriting() {
143   buffer_ = xmlBufferCreate();
144   writer_ = xmlNewTextWriterMemory(buffer_, 0);
145   xmlTextWriterSetIndent(writer_, 1);
146   xmlTextWriterStartDocument(writer_, NULL, NULL, NULL);
147 }
148 
StopWriting()149 void XmlWriter::StopWriting() {
150   xmlTextWriterEndDocument(writer_);
151   xmlFreeTextWriter(writer_);
152   writer_ = NULL;
153 }
154