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