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