• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef THIRD_PARTY_LIBXML_CHROMIUM_LIBXML_UTILS_H_
6 #define THIRD_PARTY_LIBXML_CHROMIUM_LIBXML_UTILS_H_
7 #pragma once
8 
9 #include <string>
10 
11 #include "libxml/xmlreader.h"
12 #include "libxml/xmlwriter.h"
13 
14 // Converts a libxml xmlChar* into a UTF-8 std::string.
15 // NULL inputs produce an empty string.
16 std::string XmlStringToStdString(const xmlChar* xmlstring);
17 
18 // libxml uses a global error function pointer for reporting errors.
19 // A ScopedXmlErrorFunc object lets you change the global error pointer
20 // for the duration of the object's lifetime.
21 class ScopedXmlErrorFunc {
22  public:
ScopedXmlErrorFunc(void * context,xmlGenericErrorFunc func)23   ScopedXmlErrorFunc(void* context, xmlGenericErrorFunc func) {
24     old_error_func_ = xmlGenericError;
25     old_error_context_ = xmlGenericErrorContext;
26     xmlSetGenericErrorFunc(context, func);
27   }
~ScopedXmlErrorFunc()28   ~ScopedXmlErrorFunc() {
29     xmlSetGenericErrorFunc(old_error_context_, old_error_func_);
30   }
31 
32  private:
33   xmlGenericErrorFunc old_error_func_;
34   void* old_error_context_;
35 };
36 
37 // XmlReader is a wrapper class around libxml's xmlReader,
38 // providing a simplified C++ API.
39 class XmlReader {
40  public:
41   XmlReader();
42   ~XmlReader();
43 
44   // Load a document into the reader from memory.  |input| must be UTF-8 and
45   // exist for the lifetime of this object.  Returns false on error.
46   // TODO(evanm): handle encodings other than UTF-8?
47   bool Load(const std::string& input);
48 
49   // Load a document into the reader from a file.  Returns false on error.
50   bool LoadFile(const std::string& file_path);
51 
52   // Wrappers around libxml functions -----------------------------------------
53 
54   // Read() advances to the next node.  Returns false on EOF or error.
Read()55   bool Read() { return xmlTextReaderRead(reader_) == 1; }
56 
57   // Next(), when pointing at an opening tag, advances to the node after
58   // the matching closing tag.  Returns false on EOF or error.
Next()59   bool Next() { return xmlTextReaderNext(reader_) == 1; }
60 
61   // Return the depth in the tree of the current node.
Depth()62   int Depth() { return xmlTextReaderDepth(reader_); }
63 
64   // Returns the "local" name of the current node.
65   // For a tag like <foo:bar>, this is the string "foo:bar".
NodeName()66   std::string NodeName() {
67     return XmlStringToStdString(xmlTextReaderConstLocalName(reader_));
68   }
69 
70   // When pointing at a tag, retrieves the value of an attribute.
71   // Returns false on failure.
72   // E.g. for <foo bar:baz="a">, NodeAttribute("bar:baz", &value)
73   // returns true and |value| is set to "a".
74   bool NodeAttribute(const char* name, std::string* value);
75 
76   // Returns true if the node is a closing element (e.g. </foo>).
77   bool IsClosingElement();
78 
79   // Helper functions not provided by libxml ----------------------------------
80 
81   // Return the string content within an element.
82   // "<foo>bar</foo>" is a sequence of three nodes:
83   // (1) open tag, (2) text, (3) close tag.
84   // With the reader currently at (1), this returns the text of (2),
85   // and advances past (3).
86   // Returns false on error.
87   bool ReadElementContent(std::string* content);
88 
89   // Skip to the next opening tag, returning false if we reach a closing
90   // tag or EOF first.
91   // If currently on an opening tag, doesn't advance at all.
92   bool SkipToElement();
93 
94  private:
95   // Returns the libxml node type of the current node.
NodeType()96   int NodeType() { return xmlTextReaderNodeType(reader_); }
97 
98   // The underlying libxml xmlTextReader.
99   xmlTextReaderPtr reader_;
100 };
101 
102 // XmlWriter is a wrapper class around libxml's xmlWriter,
103 // providing a simplified C++ API.
104 // StartWriting must be called before other methods, and StopWriting
105 // must be called before GetWrittenString() will return results.
106 class XmlWriter {
107  public:
108   XmlWriter();
109   ~XmlWriter();
110 
111   // Allocates the xmlTextWriter and an xmlBuffer and starts an XML document.
112   // This must be called before any other functions. By default, indenting is
113   // set to true.
114   void StartWriting();
115 
116   // Ends the XML document and frees the xmlTextWriter.
117   // This must be called before GetWrittenString() is called.
118   void StopWriting();
119   // Wrappers around libxml functions -----------------------------------------
120 
121   // All following elements will be indented to match their depth.
StartIndenting()122   void StartIndenting() { xmlTextWriterSetIndent(writer_, 1); }
123 
124   // All follow elements will not be indented.
StopIndenting()125   void StopIndenting() { xmlTextWriterSetIndent(writer_, 0); }
126 
127   // Start an element with the given name. All future elements added will be
128   // children of this element, until it is ended. Returns false on error.
StartElement(const std::string & element_name)129   bool StartElement(const std::string& element_name) {
130     return xmlTextWriterStartElement(writer_,
131                                      BAD_CAST element_name.c_str()) >= 0;
132   }
133 
134   // Ends the current open element. Returns false on error.
EndElement()135   bool EndElement() {
136     return xmlTextWriterEndElement(writer_) >= 0;
137   }
138 
139   // Appends to the content of the current open element.
AppendElementContent(const std::string & content)140   bool AppendElementContent(const std::string& content) {
141     return xmlTextWriterWriteString(writer_,
142                                     BAD_CAST content.c_str()) >= 0;
143   }
144 
145   // Adds an attribute to the current open element. Returns false on error.
AddAttribute(const std::string & attribute_name,const std::string & attribute_value)146   bool AddAttribute(const std::string& attribute_name,
147                     const std::string& attribute_value) {
148     return xmlTextWriterWriteAttribute(writer_,
149                                        BAD_CAST attribute_name.c_str(),
150                                        BAD_CAST attribute_value.c_str()) >= 0;
151   }
152 
153   // Adds a new element with name |element_name| and content |content|
154   // to the buffer. Example: <|element_name|>|content|</|element_name|>
155   // Returns false on errors.
WriteElement(const std::string & element_name,const std::string & content)156   bool WriteElement(const std::string& element_name,
157                     const std::string& content) {
158     return xmlTextWriterWriteElement(writer_,
159                                      BAD_CAST element_name.c_str(),
160                                      BAD_CAST content.c_str()) >= 0;
161   }
162 
163   // Helper functions not provided by xmlTextWriter ---------------------------
164 
165   // Returns the string that has been written to the buffer.
GetWrittenString()166   std::string GetWrittenString() {
167     if (buffer_ == NULL)
168       return "";
169     return XmlStringToStdString(buffer_->content);
170   }
171 
172  private:
173   // The underlying libxml xmlTextWriter.
174   xmlTextWriterPtr writer_;
175 
176   // Stores the output.
177   xmlBufferPtr buffer_;
178 };
179 
180 #endif  // THIRD_PARTY_LIBXML_CHROMIUM_INCLUDE_LIBXML_LIBXML_UTILS_H_
181