[libxml++] Parsers: Improve the error handling.



commit f93008e2566cdd1e92b4253c2ec0e16fb0690a37
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Tue Aug 7 19:35:23 2012 +0200

    Parsers: Improve the error handling.
    
    * libxml++/parsers/domparser.[h|cc]:
    * libxml++/parsers/saxparser.[h|cc]:
    * libxml++/parsers/textreader.[h|cc]: Check more return codes from libxml2
    functions. Improve the description of errors in the reference documentation.
    Bug #635846.

 ChangeLog                      |   18 ++++-
 libxml++/parsers/domparser.cc  |   71 ++++++++++++++--------
 libxml++/parsers/domparser.h   |   46 +++++++++++----
 libxml++/parsers/saxparser.cc  |  129 +++++++++++++++++++++++++++++++--------
 libxml++/parsers/saxparser.h   |   39 ++++++++----
 libxml++/parsers/textreader.cc |   16 +----
 libxml++/parsers/textreader.h  |   63 +++++++++++++++++--
 7 files changed, 280 insertions(+), 102 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 4f71d8a..77d06e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2012-08-07  Kjell Ahlstedt  <kjell ahlstedt bredband net>
- 
+
+	Parsers: Improve the error handling.
+
+	* libxml++/parsers/domparser.[h|cc]:
+	* libxml++/parsers/saxparser.[h|cc]:
+	* libxml++/parsers/textreader.[h|cc]: Check more return codes from libxml2
+	functions. Improve the description of errors in the reference documentation.
+	Bug #635846.
+
+2012-08-07  Kjell Ahlstedt  <kjell ahlstedt bredband net>
+
 	Document, Element, Node: Remove unnecessary tests for null pointers.
 
 	* libxml++/document.cc:
@@ -9,14 +19,14 @@
 	tests were newly added when error handling was improved. Bug #635846.
 
 2012-08-05  Kjell Ahlstedt  <kjell ahlstedt bredband net>
- 
+
 	Schema::set_document(): Create empty document.
 
 	* libxml++/schema.[h|cc]: set_document(): If the argument 'document' is 0,
 	create an empty document, as the documentation says.
 
 2012-08-05  Kjell Ahlstedt  <kjell ahlstedt bredband net>
- 
+
 	Document, Schema: Improve the error handling.
 
 	* libxml++/document.[h|cc]:
@@ -24,7 +34,7 @@
 	Improve the description of errors in the reference documentation. Bug #635846.
 
 2012-08-02  Kjell Ahlstedt  <kjell ahlstedt bredband net>
- 
+
 	Element, Node: Improve the error handling.
 
 	* libxml++/nodes/element.[h|cc]:
diff --git a/libxml++/parsers/domparser.cc b/libxml++/parsers/domparser.cc
index 52fb8d2..f1aaa52 100644
--- a/libxml++/parsers/domparser.cc
+++ b/libxml++/parsers/domparser.cc
@@ -50,13 +50,12 @@ void DomParser::parse_file(const Glib::ustring& filename)
 
   if(!context_)
   {
-    throw internal_error("Couldn't create parsing context\n" + format_xml_error());
+    throw internal_error("Could not create parser context\n" + format_xml_error());
   }
 
   if(context_->directory == 0)
   {
-    char* directory = xmlParserGetDirectory(filename.c_str());
-    context_->directory = (char*) xmlStrdup((xmlChar*) directory);
+    context_->directory = xmlParserGetDirectory(filename.c_str());
   }
 
   parse_context();
@@ -74,7 +73,7 @@ void DomParser::parse_memory_raw(const unsigned char* contents, size_type bytes_
 
   if(!context_)
   {
-    throw internal_error("Couldn't create parsing context\n" + format_xml_error());
+    throw internal_error("Could not create parser context\n" + format_xml_error());
   }
 
   parse_context();
@@ -96,19 +95,28 @@ void DomParser::parse_context()
 
   if(!context_)
   {
-    throw internal_error("Context not initialized\n" + format_xml_error());
+    throw internal_error("Parser context not initialized\n" + format_xml_error());
   }
 
-  xmlParseDocument(context_);
+  const int parseError = xmlParseDocument(context_);
 
-  check_for_exception();
+  try
+  {
+    check_for_exception();
+  }
+  catch (...)
+  {
+    release_underlying(); //Free doc_ and context_
+    throw; // re-throw exception
+  }
 
-  const Glib::ustring error_str = format_xml_parser_error(context_);
+  Glib::ustring error_str = format_xml_parser_error(context_);
+  if (error_str.empty() && parseError == -1)
+    error_str = "xmlParseDocument() failed.";
 
   if(!error_str.empty())
   {
     release_underlying(); //Free doc_ and context_
-
     throw parse_error(error_str);
   }
 
@@ -120,11 +128,8 @@ void DomParser::parse_context()
   //Free the parse context, but keep the document alive so people can navigate the DOM tree:
   //TODO: Why not keep the context alive too?
   Parser::release_underlying();
-
-  check_for_exception();
 }
 
-
 void DomParser::parse_stream(std::istream& in)
 {
   release_underlying(); //Free any existing document.
@@ -133,20 +138,21 @@ void DomParser::parse_stream(std::istream& in)
   xmlResetLastError();
 
   context_ = xmlCreatePushParserCtxt(
-      0, // setting thoses two parameters to 0 force the parser
+      0, // Setting those two parameters to 0 force the parser
       0, // to create a document while parsing.
-      0,
-      0,
-      ""); // here should come the filename. I don't know if it is a problem to let it empty
+      0, // chunk
+      0, // size
+      0); // no filename for fetching external entities
 
   if(!context_)
   {
-    throw internal_error("Couldn't create parsing context\n" + format_xml_error());
+    throw internal_error("Could not create parser context\n" + format_xml_error());
   }
 
   initialize_context();
 
   //TODO: Shouldn't we use a Glib::ustring here, and some alternative to std::getline()?
+  int firstParseError = XML_ERR_OK;
   std::string line;
   while(std::getline(in, line))
   {
@@ -154,19 +160,36 @@ void DomParser::parse_stream(std::istream& in)
     // about layout in certain cases.
     line += '\n';
 
-    xmlParseChunk(context_, line.c_str(), line.size() /* This is a std::string, not a ustring, so this is the number of bytes. */, 0);
+    const int parseError = xmlParseChunk(context_, line.c_str(),
+      line.size() /* This is a std::string, not a ustring, so this is the number of bytes. */, 0);
+
+    // Save the first error code if any, but read on.
+    // More errors might be reported and then thrown by check_for_exception().
+    if (parseError != XML_ERR_OK && firstParseError == XML_ERR_OK)
+      firstParseError = parseError;
   }
 
-  xmlParseChunk(context_, 0, 0, 1);
+  const int parseError = xmlParseChunk(context_, 0, 0, 1 /* last chunk */);
+  if (parseError != XML_ERR_OK && firstParseError == XML_ERR_OK)
+    firstParseError = parseError;
 
-  check_for_exception();
+  try
+  {
+    check_for_exception();
+  }
+  catch (...)
+  {
+    release_underlying(); //Free doc_ and context_
+    throw; // re-throw exception
+  }
 
-  const Glib::ustring error_str = format_xml_parser_error(context_);
+  Glib::ustring error_str = format_xml_parser_error(context_);
+  if (error_str.empty() && firstParseError != XML_ERR_OK)
+    error_str = "Error code from xmlParseChunk(): " + Glib::ustring::format(firstParseError);
 
   if(!error_str.empty())
   {
     release_underlying(); //Free doc_ and context_
-
     throw parse_error(error_str);
   }
 
@@ -179,8 +202,6 @@ void DomParser::parse_stream(std::istream& in)
   //Free the parse context, but keep the document alive so people can navigate the DOM tree:
   //TODO: Why not keep the context alive too?
   Parser::release_underlying();
-
-  check_for_exception();
 }
 
 void DomParser::release_underlying()
@@ -210,5 +231,3 @@ const Document* DomParser::get_document() const
 }
 
 } // namespace xmlpp
-
-
diff --git a/libxml++/parsers/domparser.h b/libxml++/parsers/domparser.h
index 8d6c296..5c2282a 100644
--- a/libxml++/parsers/domparser.h
+++ b/libxml++/parsers/domparser.h
@@ -19,46 +19,74 @@ namespace xmlpp {
 class DomParser : public Parser
 {
 public:
+  /** Create a parser with an empty document.
+   * @throws xmlpp::internal_error If an empty document can't be created.
+   */
   DomParser();
 
   /** Instantiate the parser and parse a document immediately.
-   * @throw exception
    * @param filename The path to the file.
    * @param validate Whether the parser should validate the XML.             
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   explicit DomParser(const Glib::ustring& filename, bool validate = false);
   virtual ~DomParser();
 
   /** Parse an XML document from a file.
-   * @throw exception
+   * If the parser already contains a document, that document and all its nodes
+   * are deleted.
    * @param filename The path to the file.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void parse_file(const Glib::ustring& filename);
 
   /** Parse an XML document from a string.
-   * @throw exception  
+   * If the parser already contains a document, that document and all its nodes
+   * are deleted.
    * @param contents The XML document as a string.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void parse_memory(const Glib::ustring& contents);
   
   /** Parse an XML document from raw memory.
-   * @throw exception
+   * If the parser already contains a document, that document and all its nodes
+   * are deleted.
    * @param contents The XML document as an array of bytes.
    * @param bytes_count The number of bytes in the @a contents array.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   void parse_memory_raw(const unsigned char* contents, size_type bytes_count);
 
   /** Parse an XML document from a stream.
-   * @throw exception
+   * If the parser already contains a document, that document and all its nodes
+   * are deleted.
    * @param in The stream.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void parse_stream(std::istream& in);
 
   /** Test whether a document has been parsed.
-  */
+   */
   operator bool() const;
   
+  /** Get the parsed document.
+   * @returns A pointer to the parsed document, or <tt>0</tt>.
+   */
   Document* get_document();
+
+  /** Get the parsed document.
+   * @returns A pointer to the parsed document, or <tt>0</tt>.
+   */
   const Document* get_document() const;
   
 protected:
@@ -69,12 +97,6 @@ protected:
   Document* doc_;
 };
 
-
-
-
 } // namespace xmlpp
 
 #endif //__LIBXMLPP_PARSERS_DOMPARSER_H
-
-
-
diff --git a/libxml++/parsers/saxparser.cc b/libxml++/parsers/saxparser.cc
index d937cbf..204dd7d 100644
--- a/libxml++/parsers/saxparser.cc
+++ b/libxml++/parsers/saxparser.cc
@@ -15,7 +15,6 @@
 #include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt
 
 #include <cstdarg> //For va_list.
-#include <cassert> // for assert()
 #include <iostream>
 
 namespace xmlpp {
@@ -147,28 +146,41 @@ void SaxParser::on_internal_subset(const Glib::ustring& name,
 // (http://www.daa.com.au/~james/gnome/xml-sax/implementing.html)
 void SaxParser::parse()
 {
-  
+  //TODO If this is not the first parsing with this SaxParser, the xmlDoc object
+  // in entity_resolver_doc_ should be deleted and replaced by a new one.
+  // Otherwise entity declarations from a previous parsing may erroneously affect
+  // this parsing. This would be much easier if entity_resolver_doc_ were a
+  // std::auto_ptr<Document>, so the xmlpp::Document could be deleted and a new
+  // one created. A good place for such code would be in an overridden
+  // SaxParser::initialize_context(). It would be an ABI break.
+
   if(!context_)
   {
-    throw internal_error("Parse context not created.");
+    throw internal_error("Parser context not created.");
   }
 
   xmlSAXHandlerPtr old_sax = context_->sax;
   context_->sax = sax_handler_.get();
 
+  xmlResetLastError();
   initialize_context();
   
-  xmlParseDocument(context_);
+  const int parseError = xmlParseDocument(context_);
 
   context_->sax = old_sax;
 
-  if( (! context_->wellFormed)
-      && (! exception_) )
-    exception_ = new parse_error("Document not well-formed");
+  Glib::ustring error_str = format_xml_parser_error(context_);
+  if (error_str.empty() && parseError == -1)
+    error_str = "xmlParseDocument() failed.";
 
-  release_underlying();
+  release_underlying(); // Free context_
 
   check_for_exception();
+
+  if(!error_str.empty())
+  {
+    throw parse_error(error_str);
+  }
 }
 
 void SaxParser::parse_file(const Glib::ustring& filename)
@@ -210,17 +222,24 @@ void SaxParser::parse_stream(std::istream& in)
   }
 
   KeepBlanks k(KeepBlanks::Default);
+  xmlResetLastError();
 
   context_ = xmlCreatePushParserCtxt(
       sax_handler_.get(),
       0, // user_data
-      0,
-      0,
-      ""); // This should be the filename. I don't know if it is a problem to leave it empty.
+      0, // chunk
+      0, // size
+      0); // no filename for fetching external entities
+
+  if(!context_)
+  {
+    throw internal_error("Could not create parser context\n" + format_xml_error());
+  }
 
   initialize_context();
 
   //TODO: Shouldn't we use a Glib::ustring here, and some alternative to std::getline()?
+  int firstParseError = XML_ERR_OK;
   std::string line;
   while( ( ! exception_ )
       && std::getline(in, line))
@@ -229,15 +248,37 @@ void SaxParser::parse_stream(std::istream& in)
     // about layout in certain cases.
     line += '\n';
 
-    xmlParseChunk(context_, line.c_str(), line.size() /* This is a std::string, not a ustring, so this is the number of bytes. */, 0 /* don't terminate */);
+    const int parseError = xmlParseChunk(context_, line.c_str(),
+      line.size() /* This is a std::string, not a ustring, so this is the number of bytes. */,
+      0 /* don't terminate */);
+
+    // Save the first error code if any, but read on.
+    // More errors might be reported and then thrown by check_for_exception().
+    if (parseError != XML_ERR_OK && firstParseError == XML_ERR_OK)
+      firstParseError = parseError;
   }
 
   if( ! exception_ )
-    xmlParseChunk(context_, 0 /* chunk */, 0 /* size */, 1 /* terminate (1 or 0) */); //This seems to be called just to terminate parsing.
+  {
+     //This is called just to terminate parsing.
+    const int parseError = xmlParseChunk(context_, 0 /* chunk */, 0 /* size */, 1 /* terminate (1 or 0) */);
 
-  release_underlying();
+    if (parseError != XML_ERR_OK && firstParseError == XML_ERR_OK)
+      firstParseError = parseError;
+  }
+
+  Glib::ustring error_str = format_xml_parser_error(context_);
+  if (error_str.empty() && firstParseError != XML_ERR_OK)
+    error_str = "Error code from xmlParseChunk(): " + Glib::ustring::format(firstParseError);
+
+  release_underlying(); // Free context_
 
   check_for_exception();
+
+  if(!error_str.empty())
+  {
+    throw parse_error(error_str);
+  }
 }
 
 void SaxParser::parse_chunk(const Glib::ustring& chunk)
@@ -248,23 +289,39 @@ void SaxParser::parse_chunk(const Glib::ustring& chunk)
 void SaxParser::parse_chunk_raw(const unsigned char* contents, size_type bytes_count)
 {
   KeepBlanks k(KeepBlanks::Default);
+  xmlResetLastError();
 
   if(!context_)
   {
     context_ = xmlCreatePushParserCtxt(
       sax_handler_.get(),
       0, // user_data
-      0,
-      0,
-      ""); // This should be the filename. I don't know if it is a problem to let it empty
-
+      0, // chunk
+      0, // size
+      0); // no filename for fetching external entities
+
+    if(!context_)
+    {
+      throw internal_error("Could not create parser context\n" + format_xml_error());
+    }
     initialize_context();
   }
+  else
+    xmlCtxtResetLastError(context_);
   
+  int parseError = XML_ERR_OK;
   if(!exception_)
-    xmlParseChunk(context_, (const char*)contents, bytes_count, 0 /* don't terminate */);
+    parseError = xmlParseChunk(context_, (const char*)contents, bytes_count, 0 /* don't terminate */);
 
   check_for_exception();
+
+  Glib::ustring error_str = format_xml_parser_error(context_);
+  if (error_str.empty() && parseError != XML_ERR_OK)
+    error_str = "Error code from xmlParseChunk(): " + Glib::ustring::format(parseError);
+  if(!error_str.empty())
+  {
+    throw parse_error(error_str);
+  }
 }
 
 void SaxParser::release_underlying()
@@ -274,22 +331,42 @@ void SaxParser::release_underlying()
 
 void SaxParser::finish_chunk_parsing()
 {
+  xmlResetLastError();
   if(!context_)
   {
     context_ = xmlCreatePushParserCtxt(
       sax_handler_.get(),
       0, // this, // user_data
-      0,
-      0,
-      ""); // This should be the filename. I don't know if it is a problem to leave it empty
+      0, // chunk
+      0, // size
+      0); // no filename for fetching external entities
+
+    if(!context_)
+    {
+      throw internal_error("Could not create parser context\n" + format_xml_error());
+    }
+    initialize_context();
   }
-  
+  else
+    xmlCtxtResetLastError(context_);
+
+  int parseError = XML_ERR_OK;
   if(!exception_)
-    xmlParseChunk(context_, 0 /* chunk */, 0 /* size */, 1 /* terminate (1 or 0) */); //This seems to be called just to terminate parsing.
+    //This is called just to terminate parsing.
+    parseError = xmlParseChunk(context_, 0 /* chunk */, 0 /* size */, 1 /* terminate (1 or 0) */);
 
-  release_underlying();
+  Glib::ustring error_str = format_xml_parser_error(context_);
+  if (error_str.empty() && parseError != XML_ERR_OK)
+    error_str = "Error code from xmlParseChunk(): " + Glib::ustring::format(parseError);
+
+  release_underlying(); // Free context_
 
   check_for_exception();
+
+  if(!error_str.empty())
+  {
+    throw parse_error(error_str);
+  }
 }
 
 
@@ -548,5 +625,3 @@ void SaxParserCallback::internal_subset(void* context, const xmlChar* name,
 }
 
 } // namespace xmlpp
-
-
diff --git a/libxml++/parsers/saxparser.h b/libxml++/parsers/saxparser.h
index 6c30440..2e64482 100644
--- a/libxml++/parsers/saxparser.h
+++ b/libxml++/parsers/saxparser.h
@@ -81,27 +81,35 @@ public:
   virtual ~SaxParser();
 
   /** Parse an XML document from a file.
-   * @throw exception
    * @param filename The path to the file.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void parse_file(const Glib::ustring& filename);
 
   /** Parse an XML document from a string.
-   * @throw exception
    * @param contents The XML document as a string.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void parse_memory(const Glib::ustring& contents);
 
   /** Parse an XML document from raw memory.
-   * @throw exception
    * @param contents The XML document as an array of bytes.
    * @param bytes_count The number of bytes in the @a contents array.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   void parse_memory_raw(const unsigned char* contents, size_type bytes_count);
 
   /** Parse an XML document from a stream.
-   * @throw exception
    * @param in The stream.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void parse_stream(std::istream& in);
   
@@ -114,8 +122,10 @@ public:
    * The first call to parse_chunk will setup the parser. When the last chunk
    * has been parsed, call finish_chunk_parsing() to finish the parse.
    *
-   * @throw exception
    * @param chunk The next piece of the XML document.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void parse_chunk(const Glib::ustring& chunk);
 
@@ -130,9 +140,11 @@ public:
    * The first call to parse_chunk will setup the parser. When the last chunk
    * has been parsed, call finish_chunk_parsing() to finish the parse.
    *
-   * @throw exception
    * @param contents The next piece of the XML document as an array of bytes.
    * @param bytes_count The number of bytes in the @a contents array.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   void parse_chunk_raw(const unsigned char* contents, size_type bytes_count);
 
@@ -140,6 +152,9 @@ public:
    *
    * Call this after the last call to parse_chunk(). Don't use this function with
    * the other parsing methods.
+   * @throws xmlpp::internal_error
+   * @throws xmlpp::parse_error
+   * @throws xmlpp::validity_error
    */
   virtual void finish_chunk_parsing();
 
@@ -153,6 +168,8 @@ protected:
   virtual void on_comment(const Glib::ustring& text);
   virtual void on_warning(const Glib::ustring& text);
   virtual void on_error(const Glib::ustring& text);
+  /** @throws xmlpp::parse_error
+   */
   virtual void on_fatal_error(const Glib::ustring& text);
   virtual void on_cdata_block(const Glib::ustring& text);
 
@@ -176,7 +193,8 @@ protected:
    * Unlike the DomParser, the SaxParser will also tell you about entity references for the 5 predefined entities.
    *
    * @param name The entity reference name.
-   * @returns The resolved xmlEntity for the entity reference. You must include libxml/parser.h in order to use this C struct.
+   * @returns The resolved xmlEntity for the entity reference, or <tt>0</tt> if not found.
+   *          You must include libxml/parser.h in order to use this C struct.
    * This instance will not be freed by the caller.
    */
   virtual _xmlEntity* on_get_entity(const Glib::ustring& name);
@@ -185,6 +203,7 @@ protected:
    * If you override this function, and you want normal entity substitution to work, then you must call the base class in your override.
    *
    * This would be useful when overriding on_get_entity().
+   * @throws xmlpp::internal_error
    */
   virtual void on_entity_declaration(const Glib::ustring& name, XmlEntityType type, const Glib::ustring& publicId, const Glib::ustring& systemId, const Glib::ustring& content);
 
@@ -202,12 +221,6 @@ private:
   friend struct SaxParserCallback;
 };
 
-
-
-
 } // namespace xmlpp
 
 #endif //__LIBXMLPP_PARSERS_SAXPARSER_H
-
-
-
diff --git a/libxml++/parsers/textreader.cc b/libxml++/parsers/textreader.cc
index 4a258dc..c041cd4 100644
--- a/libxml++/parsers/textreader.cc
+++ b/libxml++/parsers/textreader.cc
@@ -106,7 +106,7 @@ int TextReader::get_attribute_count() const
 Glib::ustring TextReader::get_base_uri() const
 {
   return propertyreader->String(
-      xmlTextReaderBaseUri(impl_));
+      xmlTextReaderBaseUri(impl_), true);
 }
 
 int TextReader::get_depth() const
@@ -306,15 +306,7 @@ Node* TextReader::get_current_node()
 
 const Node* TextReader::get_current_node() const
 {
-  xmlNodePtr node = xmlTextReaderCurrentNode(impl_);
-  if(node)
-  {
-    Node::create_wrapper(node);
-    return static_cast<Node*>(node->_private);
-  }
-
-  check_for_exceptions();
-  return 0;
+  return const_cast<TextReader*>(this)->get_current_node();
 }
 
 /*
@@ -331,7 +323,6 @@ Node* TextReader::expand()
 {
   xmlNodePtr node = xmlTextReaderExpand(impl_);
   if(node)
-  if(node)
   {
     Node::create_wrapper(node);
     return static_cast<Node*>(node->_private);
@@ -384,7 +375,6 @@ void TextReader::check_for_exceptions() const
   int severity = severity_;
   ths->severity_ = 0;
 
-  //TODO: Offer an alternative when not using exceptions?
   if( severity == XML_PARSER_SEVERITY_ERROR )
     throw parse_error(error_);
   else if( severity == XML_PARSER_SEVERITY_VALIDITY_ERROR )
@@ -404,7 +394,7 @@ bool TextReader::PropertyReader::Bool(int value)
   if(value == -1)
     owner_.check_for_exceptions();
     
-  return value;
+  return value > 0;
 }
 
 char TextReader::PropertyReader::Char(int value)
diff --git a/libxml++/parsers/textreader.h b/libxml++/parsers/textreader.h
index 595e2e5..5901894 100644
--- a/libxml++/parsers/textreader.h
+++ b/libxml++/parsers/textreader.h
@@ -22,7 +22,7 @@ extern "C"
 namespace xmlpp
 {
 
-/** A TextReader-style XML parser
+/** A TextReader-style XML parser.
  * A reader that provides fast, non-cached, forward-only access to XML data,
  * in the style of .Net's <a href="http://msdn.microsoft.com/en-us/library/system.xml.xmltextreader.aspx";>XmlTextReader</a> class.
  */
@@ -81,6 +81,7 @@ class TextReader: NonCopyable
     /**
      * Creates a new TextReader object to parse a file or URI.
      * @param URI The URI to read.
+     * @throws xmlpp::internal_error If an xmlTextReader object cannot be created.
      */
     TextReader(const Glib::ustring& URI);
 
@@ -88,39 +89,53 @@ class TextReader: NonCopyable
      * Creates a new TextReader object which parses in memory data.
      * @param data The data to parse.
      * @param size The number of bytes in data.
-     * @param uri The base URI of the file.
+     * @param uri The base URI to use for the document.
+     * @throws xmlpp::internal_error If an xmlTextReader object cannot be created.
      */
     TextReader(const unsigned char* data, size_type size, const Glib::ustring& uri = Glib::ustring());
 
     ~TextReader();
 
     /** Moves the position of the current instance to the next node in the stream, exposing its properties.
-     * @return true if the node was read successfully, false if there is no more nodes to read.
+     * @return true if the node was read successfully, false if there are no more nodes to read.
+     * @throws xmlpp::parse_error
+     * @throws xmlpp::validity_error
      */
     bool read();
 
     /** Reads the contents of the current node, including child nodes and markup.
-     * @return A Glib::ustring containing the XML content, or and empty Glib::ustring if the current node is neither an element nor attribute, or has no child nodes.
+     * @return A Glib::ustring containing the XML content, or an empty Glib::ustring if the current node is neither an element nor attribute, or has no child nodes.
+     * @throws xmlpp::parse_error
+     * @throws xmlpp::validity_error
      */
     Glib::ustring read_inner_xml();
 
     /** Reads the current node and its contents, including child nodes and markup.
      * @return A Glib::ustring containing the XML content, or an empty Glib::ustring if the current node is neither an element nor attribute.
+     * @throws xmlpp::parse_error
+     * @throws xmlpp::validity_error
      */
     Glib::ustring read_outer_xml();
 
     /** Reads the contents of an element or a text node as a string.
      * @return A Glib::ustring containing the contents of the Element or Text node, or an empty Glib::ustring if the reader is positioned on any other type of node.
+     * @throws xmlpp::parse_error
+     * @throws xmlpp::validity_error
      */
     Glib::ustring read_string();
 
     /** Parses an attribute value into one or more Text and EntityReference nodes.
      * @return A bool where true indicates the attribute value was parsed, and false indicates the reader was not positioned on an attribute node or all the attribute values have been read.
+     * @throws xmlpp::parse_error
+     * @throws xmlpp::validity_error
      */
     bool read_attribute_value();
 
     /** Gets the number of attributes on the current node.
-     * @return The number of attributes on the current node, or zero if the current node does not support attributes.
+     * @return The number of attributes on the current node, or zero if the current node
+     *         does not support attributes, or -1 in case of error.
+     * @throws xmlpp::parse_error
+     * @throws xmlpp::validity_error
      */
     int get_attribute_count() const;
 
@@ -130,7 +145,7 @@ class TextReader: NonCopyable
     Glib::ustring get_base_uri() const;
 
     /** Gets the depth of the current node in the XML document.
-     * @return The depth of the current node in the XML document.
+     * @return The depth of the current node in the XML document, or -1 in case of error.
      */
     int get_depth() const;
 
@@ -139,7 +154,7 @@ class TextReader: NonCopyable
      */
     bool has_attributes() const;
 
-    /**  Whether the node can have a text value.
+    /** Whether the node can have a text value.
      * @return true if the current node can have an associated text value, false otherwise.
      */
     bool has_value() const;
@@ -158,9 +173,19 @@ class TextReader: NonCopyable
     Glib::ustring get_name() const;
     Glib::ustring get_namespace_uri() const;
 
+    /** Get the node type of the current node.
+     * @returns The xmlpp::xmlNodeType of the current node, or -1 in case of error.
+     */
     xmlNodeType get_node_type() const;
 
+    /** Get the namespace prefix associated with the current node.
+     * @returns The namespace prefix, or an empty string if not available.
+     */
     Glib::ustring get_prefix() const;
+
+    /** Get the quotation mark character used to enclose the value of an attribute.
+     * @returns Returns " or ' and -1 in case of error.
+     */
     char get_quote_char() const;
 
     Glib::ustring get_value() const;
@@ -191,9 +216,33 @@ class TextReader: NonCopyable
     bool get_parser_property(ParserProperties property) const;
     void set_parser_property(ParserProperties property, bool value);
 
+    /** Get a pointer to the current node.
+     * @warning This is dangerous because the underlying node may be destroyed on the next read.
+     * The C++ wrapper is not deleted. Using this method causes memory leaks,
+     * unless you call xmlpp::Node::free_wrappers(), which is not intended to be
+     * called by the application.
+     * @returns A pointer to the current node, or 0 in case of error.
+     */
     Node* get_current_node();
+
+    /** Get a pointer to the current node.
+     * @warning See the non-const get_current_node().
+     * @returns A pointer to the current node, or 0 in case of error.
+     */
     const Node* get_current_node() const;
+
 //    Document* CurrentDocument();
+
+    /** Expand the current node.
+     * Reads the contents of the current node and the full subtree. It then makes
+     * the subtree available until the next call to read() or next().
+     * @warning The C++ wrappers are not deleted. Using this method causes memory leaks,
+     * unless you call xmlpp::Node::free_wrappers(), which is not intended to be
+     * called by the application.
+     * @returns A pointer to the current node, or 0 in case of error.
+     * @throws xmlpp::parse_error
+     * @throws xmlpp::validity_error
+     */
     Node* expand();
 
     bool next();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]