|
From: <br...@us...> - 2008-09-07 22:31:49
|
Revision: 3587
http://openvrml.svn.sourceforge.net/openvrml/?rev=3587&view=rev
Author: braden
Date: 2008-09-07 22:31:56 +0000 (Sun, 07 Sep 2008)
Log Message:
-----------
Use libxml's XmlTextReader interface rather than its SAX one. The XmlTextReader interface is a lot closer to Microsoft's XmlLite interface, which should better facilitate using XmlLite when building on Windows.
Modified Paths:
--------------
trunk/ChangeLog
trunk/configure.ac
trunk/src/libopenvrml/openvrml/browser.cpp
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2008-09-06 05:41:07 UTC (rev 3586)
+++ trunk/ChangeLog 2008-09-07 22:31:56 UTC (rev 3587)
@@ -1,3 +1,34 @@
+2008-09-07 Braden McDaniel <br...@en...>
+
+ Use libxml's XmlTextReader interface rather than its SAX one. The
+ XmlTextReader interface is a lot closer to Microsoft's XmlLite
+ interface, which should better facilitate using XmlLite when
+ building on Windows.
+
+ * configure.ac: Require at least libxml 2.5.
+ * src/libopenvrml/openvrml/browser.cpp
+ (component::parser): Removed.
+ (component::xml_reader): Added; a parser for OpenVRML's XML
+ component descriptors using libxml's XmlTextReader interface.
+ (openvrml_component_parser_startElement(void *, const xmlChar *,
+ const xmlChar **)): Removed.
+ (openvrml_component_parser_endElement(void *, const xmlChar *)):
+ Removed.
+ (component::xml_reader::xml_reader(::component &)): Added;
+ construct the xml_reader.
+ (component::xml_reader::read(const std::string &)): Added; read an
+ XML component descriptor.
+ (component::xml_reader::process_node(xmlTextReader &)): Added;
+ process a node.
+ (component::xml_reader::start_element(xmlTextReader &)): Process
+ the start of an element.
+ (component::xml_reader::end_element(xmlTextReader &)): Process the
+ end of an element.
+ (component::parser::parser(::component &)): Removed.
+ (component::parser::parse(const std::string &)): Removed.
+ (component::component(const std::string & filename)): Parse the
+ component descriptor using xml_reader.
+
2008-09-06 Braden McDaniel <br...@en...>
Use D-Bus for communication between openvrml-xembed and its hosts,
Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac 2008-09-06 05:41:07 UTC (rev 3586)
+++ trunk/configure.ac 2008-09-07 22:31:56 UTC (rev 3587)
@@ -111,7 +111,10 @@
AS_IF([test X$ov_cv_boost_thread = Xno],
[AC_MSG_FAILURE([libboost_thread$BOOST_LIB_SUFFIX not found])])
-PKG_CHECK_MODULES([XML], [libxml-2.0])
+#
+# The XmlTextReader interface appears in libxml 2.5.
+#
+PKG_CHECK_MODULES([XML], [libxml-2.0 >= 2.5])
PKG_CHECK_MODULES([FONTCONFIG], [$REQUIRE_FONTCONFIG], , [have_fontconfig=no])
PKG_CHECK_MODULES([FREETYPE], [$REQUIRE_FREETYPE], , [have_freetype=no])
Modified: trunk/src/libopenvrml/openvrml/browser.cpp
===================================================================
--- trunk/src/libopenvrml/openvrml/browser.cpp 2008-09-06 05:41:07 UTC (rev 3586)
+++ trunk/src/libopenvrml/openvrml/browser.cpp 2008-09-07 22:31:56 UTC (rev 3587)
@@ -47,7 +47,7 @@
# include <boost/thread/thread.hpp>
# include <boost/tokenizer.hpp>
# include <boost/utility.hpp>
-# include <libxml/parser.h>
+# include <libxml/xmlreader.h>
# include <private.h>
# include "browser.h"
# include "vrml97_grammar.h"
@@ -6375,37 +6375,19 @@
};
}
-extern "C"
-OPENVRML_LOCAL
-void openvrml_component_parser_startElement(void * ctx,
- const xmlChar * name,
- const xmlChar ** atts);
-extern "C"
-OPENVRML_LOCAL
-void openvrml_component_parser_endElement(void * ctx,
- const xmlChar * name);
-
namespace {
class OPENVRML_LOCAL component {
- friend void (::openvrml_component_parser_startElement)(
- void * ctx,
- const xmlChar * name,
- const xmlChar ** atts);
- friend void (::openvrml_component_parser_endElement)(
- void * ctx,
- const xmlChar * name);
-
struct node_type_decl {
openvrml::node_interface_set interfaces;
std::string metatype_id;
};
+ class xml_reader;
+
class level : std::map<std::string, node_type_decl> {
- friend void (::openvrml_component_parser_startElement)(
- void * ctx,
- const xmlChar * name,
- const xmlChar ** atts);
+ friend class xml_reader;
+
public:
typedef std::map<std::string, size_t> dependencies_t;
@@ -6425,7 +6407,7 @@
const dependencies_t & requires() const;
};
- struct parser : boost::noncopyable {
+ class xml_reader : boost::noncopyable {
enum parse_state {
none,
component,
@@ -6434,16 +6416,22 @@
node,
field
};
- xmlSAXHandler handler;
- parse_state state;
- std::vector<component::level>::value_type * current_level;
- level::value_type * current_node;
+
::component & component_;
+ parse_state state_;
+ std::vector<component::level>::value_type * current_level_;
+ level::value_type * current_node_;
- explicit parser(::component & c);
+ public:
+ explicit xml_reader(::component & c);
- void parse(const std::string & filename)
+ void read(const std::string & filename)
OPENVRML_THROW1(std::runtime_error);
+
+ private:
+ void process_node(xmlTextReader & reader);
+ void start_element(xmlTextReader & reader);
+ void end_element(xmlTextReader & reader);
};
std::string id_;
@@ -12089,183 +12077,210 @@
return node;
}
-extern "C" OPENVRML_LOCAL
-void openvrml_component_parser_startElement(void * ctx,
- const xmlChar * name,
- const xmlChar ** atts)
-{
- using std::pair;
- using std::strcmp;
- using std::string;
- ::component::parser & parser = *static_cast< ::component::parser *>(ctx);
- switch (parser.state) {
- case component::parser::none:
- parser.state = component::parser::component;
- while (*atts) {
- if (xmlStrcmp(*atts++, BAD_CAST("id")) == 0) {
- parser.component_.id_.assign(*atts,
- *atts + xmlStrlen(*atts));
- }
- ++atts;
+namespace {
+
+ component::xml_reader::xml_reader(::component & c):
+ component_(c),
+ state_(none),
+ current_level_(0),
+ current_node_(0)
+ {}
+
+ void component::xml_reader::read(const std::string & filename)
+ OPENVRML_THROW1(std::runtime_error)
+ {
+ static const char * const encoding = 0;
+ static const int options = 0;
+ const xmlTextReaderPtr reader =
+ xmlReaderForFile(filename.c_str(), encoding, options);
+ if (!reader) {
+ throw std::runtime_error("could not open \"" + filename
+ + "\" for reading");
}
- break;
- case component::parser::component:
- parser.state = ::component::parser::level;
- parser.component_.levels_.push_back(component::level());
- parser.current_level = &parser.component_.levels_.back();
- break;
- case component::parser::level:
- if (xmlStrcmp(name, BAD_CAST("requires")) == 0) {
- parser.state = component::parser::requires;
- string id;
- size_t level;
- while (*atts) {
- if (xmlStrcmp(*atts, BAD_CAST("id")) == 0) {
- ++atts;
- id.assign(*atts, *atts + xmlStrlen(*atts));
- } else if (xmlStrcmp(*atts, BAD_CAST("level")) == 0) {
- ++atts;
- using boost::lexical_cast;
- level = lexical_cast<size_t>(
- string(*atts, *atts + xmlStrlen(*atts)));
- }
- ++atts;
+ scope_guard reader_guard = make_guard(xmlFreeTextReader, reader);
+ boost::ignore_unused_variable_warning(reader_guard);
+
+ int result;
+ while ((result = xmlTextReaderRead(reader)) == 1) {
+ this->process_node(*reader);
+ }
+
+ if (result != 0) {
+ throw std::runtime_error('\"' + filename + "\" failed to parse");
+ }
+ }
+
+ void component::xml_reader::process_node(xmlTextReader & reader)
+ {
+ const int node_type = xmlTextReaderNodeType(&reader);
+ switch (node_type) {
+ case XML_READER_TYPE_ELEMENT:
+ this->start_element(reader);
+ break;
+ case XML_READER_TYPE_END_ELEMENT:
+ this->end_element(reader);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void component::xml_reader::start_element(xmlTextReader & reader)
+ {
+ using std::pair;
+ using std::strcmp;
+ using std::string;
+
+ switch (this->state_) {
+ case component::xml_reader::none:
+ this->state_ = component::xml_reader::component;
+ {
+ xmlChar * id = xmlTextReaderGetAttribute(&reader,
+ BAD_CAST("id"));
+ scope_guard id_guard = make_guard(free, id);
+ boost::ignore_unused_variable_warning(id_guard);
+ this->component_.id_.assign(id, id + xmlStrlen(id));
}
- parser.current_level->dependencies_.insert(make_pair(id, level));
- } else if (xmlStrcmp(name, BAD_CAST("node")) == 0) {
- parser.state = component::parser::node;
- string id;
- component::node_type_decl node_type;
- while (*atts) {
- if (xmlStrcmp(*atts, BAD_CAST("id")) == 0) {
- ++atts;
- id.assign(*atts, *atts + xmlStrlen(*atts));
- } else if (xmlStrcmp(*atts, BAD_CAST("metatype-id")) == 0) {
- ++atts;
- node_type.metatype_id.assign(*atts,
- *atts + xmlStrlen(*atts));
- } else {
- ++atts;
+ break;
+ case component::xml_reader::component:
+ this->state_ = ::component::xml_reader::level;
+ this->component_.levels_.push_back(component::level());
+ this->current_level_ = &this->component_.levels_.back();
+ break;
+ case component::xml_reader::level:
+ if (xmlStrcmp(xmlTextReaderName(&reader), BAD_CAST("requires"))
+ == 0) {
+ using boost::lexical_cast;
+
+ xmlChar * id_chars = xmlTextReaderGetAttribute(&reader,
+ BAD_CAST("id"));
+ scope_guard id_chars_guard = make_guard(free, id_chars);
+ boost::ignore_unused_variable_warning(id_chars_guard);
+ const string id(id_chars, id_chars + xmlStrlen(id_chars));
+
+ xmlChar * level_chars =
+ xmlTextReaderGetAttribute(&reader, BAD_CAST("level"));
+ scope_guard level_chars_guard = make_guard(free, level_chars);
+ boost::ignore_unused_variable_warning(level_chars_guard);
+ const size_t level =
+ lexical_cast<size_t>(
+ string(level_chars,
+ level_chars + xmlStrlen(level_chars)));
+
+ this->current_level_->dependencies_.insert(
+ make_pair(id, level));
+ } else if (xmlStrcmp(xmlTextReaderName(&reader), BAD_CAST("node"))
+ == 0) {
+ this->state_ = component::xml_reader::node;
+
+ xmlChar * id_chars = xmlTextReaderGetAttribute(&reader,
+ BAD_CAST("id"));
+ scope_guard id_chars_guard = make_guard(free, id_chars);
+ boost::ignore_unused_variable_warning(id_chars_guard);
+ const string id(id_chars, id_chars + xmlStrlen(id_chars));
+
+ component::node_type_decl node_type;
+ xmlChar * metatype_id_chars =
+ xmlTextReaderGetAttribute(&reader, BAD_CAST("metatype-id"));
+ scope_guard metatype_id_chars_guard =
+ make_guard(free, metatype_id_chars);
+ boost::ignore_unused_variable_warning(metatype_id_chars_guard);
+ node_type.metatype_id.assign(
+ metatype_id_chars,
+ metatype_id_chars + xmlStrlen(metatype_id_chars));
+
+ pair<component::level::iterator, bool> result =
+ this->current_level_->insert(std::make_pair(id, node_type));
+ if (result.second) {
+ this->current_node_ = &*result.first;
}
- ++atts;
+ } else {
+ xmlChar * name_chars = xmlTextReaderName(&reader);
+ const std::string name(name_chars,
+ name_chars + xmlStrlen(name_chars));;
+ throw std::runtime_error("unexpected element: " + name);
}
- pair<component::level::iterator, bool> result =
- parser.current_level->insert(std::make_pair(id, node_type));
- if (result.second) {
- parser.current_node = &*result.first;
- }
- } else {
- std::cerr << "unexpected element: " << name << std::endl;
- }
- break;
- case component::parser::requires:
- break;
- case component::parser::node:
- parser.state = component::parser::field;
- try {
- using openvrml::node_interface;
- node_interface interface_;
- while (*atts) {
+ break;
+ case component::xml_reader::requires:
+ break;
+ case component::xml_reader::node:
+ {
using boost::lexical_cast;
using openvrml::field_value;
- if (xmlStrcmp(*atts, BAD_CAST("id")) == 0) {
- ++atts;
- interface_.id.assign(*atts, *atts + xmlStrlen(*atts));
- } else if (xmlStrcmp(*atts, BAD_CAST("type")) == 0) {
- ++atts;
- try {
- interface_.field_type =
- lexical_cast<field_value::type_id>(
- string(*atts, *atts + xmlStrlen(*atts)));
- } catch (const boost::bad_lexical_cast &) {
- std::cerr << "invalid field value type identifier \""
- << *atts << '\"' << std::endl;
- throw;
- }
- } else if (xmlStrcmp(*atts, BAD_CAST("access-type")) == 0) {
- ++atts;
- try {
- interface_.type =
- lexical_cast<node_interface::type_id>(
- string(*atts, *atts + xmlStrlen(*atts)));
- } catch (const boost::bad_lexical_cast &) {
- std::cerr << "invalid field access type identifier \""
- << *atts << '\"' << std::endl;
- throw;
- }
- } else {
- ++atts;
+ using openvrml::node_interface;
+
+ node_interface interface_;
+ xmlChar * id_chars = xmlTextReaderGetAttribute(&reader,
+ BAD_CAST("id"));
+ scope_guard id_chars_guard = make_guard(free, id_chars);
+ boost::ignore_unused_variable_warning(id_chars_guard);
+ interface_.id.assign(id_chars, id_chars + xmlStrlen(id_chars));
+
+ xmlChar * type_chars =
+ xmlTextReaderGetAttribute(&reader, BAD_CAST("type"));
+ scope_guard type_chars_guard = make_guard(free, type_chars);
+ boost::ignore_unused_variable_warning(type_chars_guard);
+ const string type(type_chars,
+ type_chars + xmlStrlen(type_chars));
+ try {
+ interface_.field_type =
+ lexical_cast<field_value::type_id>(string(type));
+ } catch (const boost::bad_lexical_cast &) {
+ throw std::runtime_error(
+ "invalid field value type identifier \"" + type + '\"');
}
- ++atts;
- }
- parser.current_node->second.interfaces.insert(interface_);
- } catch (const boost::bad_lexical_cast &) {}
- break;
- case component::parser::field: default:
- assert(false);
- }
-}
-extern "C" OPENVRML_LOCAL
-void openvrml_component_parser_endElement(void * ctx,
- const xmlChar * /* name */)
-{
- component::parser & parser = *static_cast<component::parser *>(ctx);
- switch (parser.state) {
- case component::parser::none:
- break;
- case component::parser::component:
- break;
- case component::parser::level:
- parser.state = component::parser::component;
- break;
- case component::parser::requires:
- parser.state = component::parser::level;
- break;
- case component::parser::node:
- parser.state = component::parser::level;
- break;
- case component::parser::field:
- parser.state = component::parser::node;
- break;
- }
-}
+ xmlChar * access_type_chars =
+ xmlTextReaderGetAttribute(&reader, BAD_CAST("access-type"));
+ scope_guard access_type_chars_guard =
+ make_guard(free, access_type_chars);
+ boost::ignore_unused_variable_warning(access_type_chars_guard);
+ const string access_type(
+ access_type_chars,
+ access_type_chars + xmlStrlen(access_type_chars));
-namespace {
+ try {
+ interface_.type =
+ lexical_cast<node_interface::type_id>(access_type);
+ } catch (const boost::bad_lexical_cast &) {
+ throw std::runtime_error(
+ "invalid field access type identifier \"" + access_type
+ + '\"');
+ }
- component::parser::parser(::component & c):
- handler(),
- state(none),
- current_level(0),
- current_node(0),
- component_(c)
- {
- this->handler.startElement = openvrml_component_parser_startElement;
- this->handler.endElement = openvrml_component_parser_endElement;
+ this->current_node_->second.interfaces.insert(interface_);
+ }
+ break;
+ case component::xml_reader::field: default:
+ assert(false);
+ }
}
- void component::parser::parse(const std::string & filename)
- OPENVRML_THROW1(std::runtime_error)
+ void component::xml_reader::end_element(xmlTextReader & /* reader */)
{
- int result = xmlSAXUserParseFile(&this->handler,
- this,
- filename.c_str());
- if (result != XML_ERR_OK) {
- using std::string;
- using boost::lexical_cast;
- xmlErrorPtr err = xmlGetLastError();
- throw std::runtime_error(string(err->file) + ':'
- + lexical_cast<string>(err->line) + ':'
- + lexical_cast<string>(err->int2) + ": "
- + err->message);
+ switch (this->state_) {
+ case component::xml_reader::none:
+ break;
+ case component::xml_reader::component:
+ break;
+ case component::xml_reader::level:
+ this->state_ = component::xml_reader::component;
+ break;
+ case component::xml_reader::requires:
+ break;
+ case component::xml_reader::node:
+ this->state_ = component::xml_reader::level;
+ break;
+ case component::xml_reader::field:
+ break;
}
}
component::component(const std::string & filename)
OPENVRML_THROW1(std::runtime_error)
{
- parser p(*this);
- p.parse(filename);
+ xml_reader reader(*this);
+ reader.read(filename);
}
const std::string & component::id() const OPENVRML_NOTHROW
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|