|
From: <br...@us...> - 2010-09-13 18:14:05
|
Revision: 4188
http://openvrml.svn.sourceforge.net/openvrml/?rev=4188&view=rev
Author: braden
Date: 2010-09-13 18:13:59 +0000 (Mon, 13 Sep 2010)
Log Message:
-----------
Add (partially) parsed nodes to the scene in the event of an exception during parsing; ensure that the browser::initialized event gets send and scene::scene_loaded gets called in the event of an exception during parsing.
Modified Paths:
--------------
trunk/ChangeLog
trunk/src/libopenvrml/openvrml/browser.cpp
trunk/src/libopenvrml/openvrml/local/parse_vrml.h
trunk/src/libopenvrml/openvrml/scene.cpp
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2010-08-20 19:26:31 UTC (rev 4187)
+++ trunk/ChangeLog 2010-09-13 18:13:59 UTC (rev 4188)
@@ -1,3 +1,24 @@
+2010-09-13 Braden McDaniel <br...@en...>
+
+ Add (partially) parsed nodes to the scene in the event of an
+ exception during parsing; ensure that the browser::initialized
+ event gets send and scene::scene_loaded gets called in the event
+ of an exception during parsing.
+
+ * src/libopenvrml/openvrml/local/parse_vrml.h
+ (openvrml::local::vrml97_parse_actions::~vrml97_parse_actions()):
+ Add (partially) parsed nodes to the scene if the parse_scope stack
+ is not empty (that is, parsing was terminated prior to the end of
+ correctly formed input).
+ * src/libopenvrml/openvrml/scene.cpp
+ (openvrml::scene::load(resource_istream &)): Ensure that
+ scene_loaded gets called in the event of an exception during
+ parsing.
+ * src/libopenvrml/openvrml/browser.cpp
+ (openvrml::browser::set_world(resource_istream &)): Ensure that
+ the browser::initialized event gets sent in the event of an
+ exception during parsing.
+
2010-08-20 Braden McDaniel <br...@en...>
* src/libopenvrml/openvrml/event.h
Modified: trunk/src/libopenvrml/openvrml/browser.cpp
===================================================================
--- trunk/src/libopenvrml/openvrml/browser.cpp 2010-08-20 19:26:31 UTC (rev 4187)
+++ trunk/src/libopenvrml/openvrml/browser.cpp 2010-09-13 18:13:59 UTC (rev 4188)
@@ -33,6 +33,7 @@
# include <boost/function.hpp>
# include <boost/functional.hpp>
# include <boost/lexical_cast.hpp>
+# include <boost/scope_exit.hpp>
# include <algorithm>
# include <functional>
# include <cerrno>
@@ -1913,6 +1914,22 @@
using std::for_each;
using boost::shared_lock;
using boost::shared_mutex;
+
+ //
+ // Ensure that the "initialized" event is sent even if parsing throws.
+ //
+ browser & self = *this;
+ shared_mutex & listeners_mutex = this->listeners_mutex_;
+ std::set<browser_listener *> & listeners = this->listeners_;
+
+ BOOST_SCOPE_EXIT((&self)(&listeners_mutex)(&listeners)) {
+ shared_lock<shared_mutex> listeners_lock(listeners_mutex);
+ for_each(listeners.begin(), listeners.end(),
+ boost::bind2nd(
+ boost::mem_fun(&browser_listener::browser_changed),
+ browser_event(self, browser_event::initialized)));
+ } BOOST_SCOPE_EXIT_END
+
{
using std::string;
using boost::upgrade_lock;
@@ -1993,11 +2010,6 @@
this->modified(true);
this->new_view = true; // Force resetUserNav
} // unlock this->scene_mutex_, this->active_viewpoint_mutex_
-
- shared_lock<shared_mutex> listeners_lock(this->listeners_mutex_);
- for_each(this->listeners_.begin(), this->listeners_.end(),
- boost::bind2nd(boost::mem_fun(&browser_listener::browser_changed),
- browser_event(*this, browser_event::initialized)));
}
/**
Modified: trunk/src/libopenvrml/openvrml/local/parse_vrml.h
===================================================================
--- trunk/src/libopenvrml/openvrml/local/parse_vrml.h 2010-08-20 19:26:31 UTC (rev 4187)
+++ trunk/src/libopenvrml/openvrml/local/parse_vrml.h 2010-09-13 18:13:59 UTC (rev 4188)
@@ -2,7 +2,7 @@
//
// OpenVRML
//
-// Copyright 2009 Braden McDaniel
+// Copyright 2009, 2010 Braden McDaniel
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
@@ -85,6 +85,75 @@
nodes_(nodes)
{}
+ ~vrml97_parse_actions()
+ {
+ //
+ // If the parse scope stack is not empty, we must have hit a
+ // parse error. Since all inner scopes are associated with
+ // PROTOs, we'll just drop them. Back up to the top-level
+ // parse scope and use whatever nodes we have there.
+ //
+ if (!this->ps.empty()) {
+ while (this->ps.size() > 1) { this->ps.pop(); }
+
+ parse_scope & ps = this->ps.top();
+
+ //
+ // When we start out, the children stack is one bigger
+ // than the node_data stack. The node_data stack doesn't
+ // get pushed until we start parsing a node; and it gets
+ // popped when we finish parsing a node. Once we start
+ // parsing a contained node, children gets pushed again
+ // and it's again one bigger than node_data.
+ //
+ // So, if the node_data and children stacks are the same
+ // size, that means we started parsing a node, but haven't
+ // gotten as far as parsing any contained nodes. In this
+ // case, just go ahead and call on_node_finish to create
+ // the "current" node and pop the node_data stack.
+ //
+ if (ps.node_data_.size() == ps.children.size()) {
+ this->on_node_finish();
+ }
+
+ try {
+ while (ps.children.size() > 1) {
+ assert(!ps.node_data_.empty());
+ node_data & nd = ps.node_data_.top();
+ assert(nd.current_field_value);
+ const field_value::type_id current_field_type =
+ nd.current_field_value->second->type();
+ if (current_field_type == field_value::sfnode_id) {
+ nd.current_field_value->second->assign(
+ sfnode(ps.children.top().front()));
+ } else if (current_field_type
+ == field_value::mfnode_id) {
+ nd.current_field_value->second->assign(
+ mfnode(ps.children.top()));
+ } else {
+ assert(false);
+ }
+ ps.children.pop();
+
+ this->on_node_finish();
+ }
+
+ this->on_scene_finish();
+
+ } catch (std::exception & ex) {
+ //
+ // Known possible exceptions here are std::bad_alloc,
+ // std::bad_cast, and openvrml::unsupported_interface.
+ // We're in a destructor here, so we don't want to
+ // throw.
+ //
+ this->scene_.browser().err(
+ "caught exception while constructing scene from "
+ "invalid data: " + std::string(ex.what()));
+ }
+ }
+ }
+
struct on_scene_start_t {
explicit on_scene_start_t(vrml97_parse_actions & actions):
actions_(actions)
@@ -144,6 +213,7 @@
add_route(*from, r->eventout, *to, r->eventin);
}
this->actions_.ps.pop();
+ assert(this->actions_.ps.empty());
}
private:
@@ -760,7 +830,7 @@
.current_field_value->second->assign(
sfnode(ps.children.top().front()));
}
- actions_.ps.top().children.pop();
+ ps.children.pop();
}
private:
@@ -775,13 +845,13 @@
void operator()() const
{
assert(!this->actions_.ps.empty());
- assert(!this->actions_.ps.top().node_data_.empty());
- assert(!this->actions_.ps.top().children.empty());
- this->actions_.ps.top().node_data_.top()
- .current_field_value->second
- ->assign(
- mfnode(this->actions_.ps.top().children.top()));
- this->actions_.ps.top().children.pop();
+ parse_scope & ps = this->actions_.ps.top();
+
+ assert(!ps.node_data_.empty());
+ assert(!ps.children.empty());
+ ps.node_data_.top().current_field_value->second
+ ->assign(mfnode(ps.children.top()));
+ ps.children.pop();
}
private:
@@ -1180,6 +1250,9 @@
//
// We push a parse_scope onto the stack
// * at the scene root
+ // * when starting a PROTO definition
+ // * when starting an SFNode or MFNode PROTO default value
+ //
std::stack<parse_scope> ps;
private:
Modified: trunk/src/libopenvrml/openvrml/scene.cpp
===================================================================
--- trunk/src/libopenvrml/openvrml/scene.cpp 2010-08-20 19:26:31 UTC (rev 4187)
+++ trunk/src/libopenvrml/openvrml/scene.cpp 2010-09-13 18:13:59 UTC (rev 4188)
@@ -3,7 +3,7 @@
// OpenVRML
//
// Copyright 1998 Chris Morley
-// Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007 Braden McDaniel
+// Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2010 Braden McDaniel
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
@@ -25,6 +25,7 @@
# include <openvrml/local/parse_vrml.h>
# include <private.h>
# include <boost/function.hpp>
+# include <boost/scope_exit.hpp>
# ifdef HAVE_CONFIG_H
# include <config.h>
@@ -161,6 +162,9 @@
/**
* @brief Load the @c scene from a stream.
*
+ * This function calls @c #scene_loaded once parsing the scene from @p in has
+ * completed.
+ *
* @param[in,out] in an input stream.
*
* @exception bad_media_type if @p in.type() is not
@@ -171,6 +175,14 @@
*/
void openvrml::scene::load(resource_istream & in)
{
+ //
+ // Ensure that scene_loaded gets called even if parsing throws.
+ //
+ scene & self = *this;
+ BOOST_SCOPE_EXIT((&self)) {
+ self.scene_loaded();
+ } BOOST_SCOPE_EXIT_END
+
{
using boost::unique_lock;
using boost::shared_mutex;
@@ -185,7 +197,6 @@
local::parse_vrml(in, in.url(), in.type(),
*this, this->nodes_, this->meta_);
}
- this->scene_loaded();
}
/**
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|