1// Copyright (c) 2012 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 "libxml_utils.h"
6
7#include "libxml/xmlreader.h"
8
9std::string XmlStringToStdString(const xmlChar* xmlstring) {
10  // xmlChar*s are UTF-8, so this cast is safe.
11  if (xmlstring)
12    return std::string(reinterpret_cast<const char*>(xmlstring));
13  else
14    return "";
15}
16
17XmlReader::XmlReader() : reader_(NULL) {
18}
19
20XmlReader::~XmlReader() {
21  if (reader_)
22    xmlFreeTextReader(reader_);
23}
24
25bool XmlReader::Load(const std::string& input) {
26  const int kParseOptions = XML_PARSE_RECOVER |  // recover on errors
27                            XML_PARSE_NONET;     // forbid network access
28  // TODO(evanm): Verify it's OK to pass NULL for the URL and encoding.
29  // The libxml code allows for these, but it's unclear what effect is has.
30  reader_ = xmlReaderForMemory(input.data(), static_cast<int>(input.size()),
31                               NULL, NULL, kParseOptions);
32  return reader_ != NULL;
33}
34
35bool XmlReader::LoadFile(const std::string& file_path) {
36  const int kParseOptions = XML_PARSE_RECOVER |  // recover on errors
37                            XML_PARSE_NONET;     // forbid network access
38  reader_ = xmlReaderForFile(file_path.c_str(), NULL, kParseOptions);
39  return reader_ != NULL;
40}
41
42bool XmlReader::NodeAttribute(const char* name, std::string* out) {
43  xmlChar* value = xmlTextReaderGetAttribute(reader_, BAD_CAST name);
44  if (!value)
45    return false;
46  *out = XmlStringToStdString(value);
47  xmlFree(value);
48  return true;
49}
50
51bool XmlReader::IsClosingElement() {
52  return NodeType() == XML_READER_TYPE_END_ELEMENT;
53}
54
55bool XmlReader::ReadElementContent(std::string* content) {
56  const int start_depth = Depth();
57
58  if (xmlTextReaderIsEmptyElement(reader_)) {
59    // Empty tag.  We succesfully read the content, but it's
60    // empty.
61    *content = "";
62    // Advance past this empty tag.
63    if (!Read())
64      return false;
65    return true;
66  }
67
68  // Advance past opening element tag.
69  if (!Read())
70    return false;
71
72  // Read the content.  We read up until we hit a closing tag at the
73  // same level as our starting point.
74  while (NodeType() != XML_READER_TYPE_END_ELEMENT || Depth() != start_depth) {
75    *content += XmlStringToStdString(xmlTextReaderConstValue(reader_));
76    if (!Read())
77      return false;
78  }
79
80  // Advance past ending element tag.
81  if (!Read())
82    return false;
83
84  return true;
85}
86
87bool XmlReader::SkipToElement() {
88  do {
89    switch (NodeType()) {
90    case XML_READER_TYPE_ELEMENT:
91      return true;
92    case XML_READER_TYPE_END_ELEMENT:
93      return false;
94    default:
95      // Skip all other node types.
96      continue;
97    }
98  } while (Read());
99  return false;
100}
101
102
103// XmlWriter functions
104
105XmlWriter::XmlWriter()
106    : writer_(NULL),
107      buffer_(NULL) {}
108
109XmlWriter::~XmlWriter() {
110  if (writer_)
111    xmlFreeTextWriter(writer_);
112  if (buffer_)
113    xmlBufferFree(buffer_);
114}
115
116void XmlWriter::StartWriting() {
117  buffer_ = xmlBufferCreate();
118  writer_ = xmlNewTextWriterMemory(buffer_, 0);
119  xmlTextWriterSetIndent(writer_, 1);
120  xmlTextWriterStartDocument(writer_, NULL, NULL, NULL);
121}
122
123void XmlWriter::StopWriting() {
124  xmlTextWriterEndDocument(writer_);
125  xmlFreeTextWriter(writer_);
126  writer_ = NULL;
127}
128