| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/common/libxml_utils.h" |
| |
| #include "base/compiler_specific.h" |
| #include "base/file_path.h" |
| #include "base/logging.h" |
| #include "base/stringprintf.h" |
| #include "base/utf_string_conversions.h" |
| |
| #include "libxml/xmlreader.h" |
| |
| std::string XmlStringToStdString(const xmlChar* xmlstring) { |
| // xmlChar*s are UTF-8, so this cast is safe. |
| if (xmlstring) |
| return std::string(reinterpret_cast<const char*>(xmlstring)); |
| else |
| return ""; |
| } |
| |
| XmlReader::XmlReader() |
| : reader_(NULL), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| error_func_(this, &XmlReader::GenericErrorCallback)) { |
| } |
| |
| XmlReader::~XmlReader() { |
| if (reader_) |
| xmlFreeTextReader(reader_); |
| } |
| |
| // static |
| void XmlReader::GenericErrorCallback(void* context, const char* msg, ...) { |
| va_list args; |
| va_start(args, msg); |
| |
| XmlReader* reader = static_cast<XmlReader*>(context); |
| reader->errors_.append(base::StringPrintV(msg, args)); |
| va_end(args); |
| } |
| |
| bool XmlReader::Load(const std::string& input) { |
| const int kParseOptions = XML_PARSE_RECOVER | // recover on errors |
| XML_PARSE_NONET; // forbid network access |
| // TODO(evanm): Verify it's OK to pass NULL for the URL and encoding. |
| // The libxml code allows for these, but it's unclear what effect is has. |
| reader_ = xmlReaderForMemory(input.data(), static_cast<int>(input.size()), |
| NULL, NULL, kParseOptions); |
| return reader_ != NULL; |
| } |
| |
| bool XmlReader::LoadFile(const FilePath& file_path) { |
| const int kParseOptions = XML_PARSE_RECOVER | // recover on errors |
| XML_PARSE_NONET; // forbid network access |
| reader_ = xmlReaderForFile( |
| #if defined(OS_WIN) |
| // libxml takes UTF-8 paths on Windows; search the source for |
| // xmlWrapOpenUtf8 to see it converting UTF-8 back to wide |
| // characters. |
| WideToUTF8(file_path.value()).c_str(), |
| #else |
| file_path.value().c_str(), |
| #endif |
| NULL, kParseOptions); |
| return reader_ != NULL; |
| } |
| |
| bool XmlReader::NodeAttribute(const char* name, std::string* out) { |
| xmlChar* value = xmlTextReaderGetAttribute(reader_, BAD_CAST name); |
| if (!value) |
| return false; |
| *out = XmlStringToStdString(value); |
| xmlFree(value); |
| return true; |
| } |
| |
| bool XmlReader::ReadElementContent(std::string* content) { |
| DCHECK(NodeType() == XML_READER_TYPE_ELEMENT); |
| const int start_depth = Depth(); |
| |
| if (xmlTextReaderIsEmptyElement(reader_)) { |
| // Empty tag. We succesfully read the content, but it's |
| // empty. |
| *content = ""; |
| // Advance past this empty tag. |
| if (!Read()) |
| return false; |
| return true; |
| } |
| |
| // Advance past opening element tag. |
| if (!Read()) |
| return false; |
| |
| // Read the content. We read up until we hit a closing tag at the |
| // same level as our starting point. |
| while (NodeType() != XML_READER_TYPE_END_ELEMENT || Depth() != start_depth) { |
| *content += XmlStringToStdString(xmlTextReaderConstValue(reader_)); |
| if (!Read()) |
| return false; |
| } |
| |
| // Advance past ending element tag. |
| DCHECK_EQ(NodeType(), XML_READER_TYPE_END_ELEMENT); |
| if (!Read()) |
| return false; |
| |
| return true; |
| } |
| |
| bool XmlReader::SkipToElement() { |
| do { |
| switch (NodeType()) { |
| case XML_READER_TYPE_ELEMENT: |
| return true; |
| case XML_READER_TYPE_END_ELEMENT: |
| return false; |
| default: |
| // Skip all other node types. |
| continue; |
| } |
| } while (Read()); |
| return false; |
| } |
| |
| |
| // XmlWriter functions |
| |
| XmlWriter::XmlWriter() |
| : writer_(NULL), |
| buffer_(NULL) {} |
| |
| XmlWriter::~XmlWriter() { |
| if (writer_) |
| xmlFreeTextWriter(writer_); |
| if (buffer_) |
| xmlBufferFree(buffer_); |
| } |
| |
| void XmlWriter::StartWriting() { |
| buffer_ = xmlBufferCreate(); |
| writer_ = xmlNewTextWriterMemory(buffer_, 0); |
| xmlTextWriterSetIndent(writer_, 1); |
| xmlTextWriterStartDocument(writer_, NULL, NULL, NULL); |
| } |
| |
| void XmlWriter::StopWriting() { |
| xmlTextWriterEndDocument(writer_); |
| xmlFreeTextWriter(writer_); |
| writer_ = NULL; |
| } |