diff options
Diffstat (limited to 'xsde/cxx/serializer/element-validation-source.cxx')
-rw-r--r-- | xsde/cxx/serializer/element-validation-source.cxx | 903 |
1 files changed, 903 insertions, 0 deletions
diff --git a/xsde/cxx/serializer/element-validation-source.cxx b/xsde/cxx/serializer/element-validation-source.cxx new file mode 100644 index 0000000..fd0dfb4 --- /dev/null +++ b/xsde/cxx/serializer/element-validation-source.cxx @@ -0,0 +1,903 @@ +// file : xsde/cxx/serializer/element-validation-source.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <cxx/serializer/element-validation-source.hxx> + +#include <xsd-frontend/semantic-graph.hxx> +#include <xsd-frontend/traversal.hxx> + +namespace CXX +{ + namespace Serializer + { + namespace + { + struct AnyTest: Traversal::Any, Context + { + AnyTest (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + String const& ns (a.definition_namespace ().name ()); + + for (SemanticGraph::Any::NamespaceIterator i (a.namespace_begin ()), + e (a.namespace_end ()); i != e;) + { + if (*i == L"##any") + { + if (stl) + os << "!name.empty ()"; + else + os << "(name != 0 && *name != '\\0')"; + } + else if (*i == L"##other") + { + if (ns) + { + // Note that here I assume that ##other does not include + // unqualified names in a schema with target namespace. + // This is not what the spec says but that seems to be + // the consensus. + // + if (stl) + os << "(!ns.empty () && ns != " << strlit (ns) << ")"; + else + os << "(ns != 0 && *ns != '\\0' && " << + "strcmp (ns, " << strlit (ns) << ") != 0)"; + } + else + { + if (stl) + os << "!ns.empty ()"; + else + os << "(ns != 0 && *ns != '\\0')"; + } + } + else if (*i == L"##local") + { + if (stl) + os << "(ns.empty () && !name.empty ())"; + else + os << "((ns == 0 || *ns == '\\0') && " << + "name != 0 && *name != '\\0')"; + } + else if (*i == L"##targetNamespace") + { + if (stl) + os << "ns == " << strlit (ns); + else + os << "(ns != 0 && strcmp (ns, " << strlit (ns) << ") == 0)"; + } + else + { + if (stl) + os << "ns == " << strlit (*i); + else + os << "(ns != 0 && strcmp (ns, " << strlit (*i) << ") == 0)"; + } + + if (++i != e) + os << " ||" << endl; + } + } + }; + + struct Compositor: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + Compositor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + UnsignedLong min (a.min ()); + + if (min == 0) + os << "if (this->" << epresent (a) << " ())" + << "{"; + + Traversal::All::traverse (a); + + if (min == 0) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (c) << " ())" + << "{"; + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (c) << " (); ++i)" + << "{"; + } + else + os << "while (this->" << enext (c) << " ())" + << "{"; + } + else if (!exceptions) + { + // Only sequence can have several choice compositors in a row. + // + os << "{"; + } + + if (exceptions) + os << "switch (this->" << earm (c) << " ())"; + else + os << earm_tag (c) << " t = this->" << earm (c) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "switch (t)"; + + + os << "{"; + + for (SemanticGraph::Choice::ContainsIterator + i (c.contains_begin ()); i != c.contains_end (); ++i) + { + os << "case " << etag (i->particle ()) << ":" + << "{"; + + edge_traverser ().dispatch (*i); + + os << "break;" + << "}"; + } + + os << "default:" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_element);" + << "return;" + << "}" + << "}"; // switch + + if (min == 0 && max == 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + else if (!exceptions) + { + os << "}"; + } + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (s) << " ())" + << "{"; + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (s) << " (); ++i)" + << "{"; + } + else + os << "while (this->" << enext (s) << " ())" + << "{"; + } + + Traversal::Sequence::traverse (s); + + if (min == 0 && max == 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + } + }; + + struct Particle: Traversal::Element, + Traversal::Any, + Context + { + Particle (Context& c) + : Context (c), any_test_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + String const& name (ename (e)); + + os << "// " << name << endl + << "//" << endl; + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (e) << " ())"; + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (e) << " (); ++i)"; + } + else + os << "while (this->" << enext (e) << " ())"; + } + + os << "{"; + + String const& ret (ret_type (e.type ())); + String const& arg (arg_type (e.type ())); + String fq_type (fq_name (e.type ())); + + Boolean poly (poly_code && !anonymous (e.type ())); + String inst (poly ? String (L"s") : L"this->" + emember (e)); + + if (poly) + os << "ctx.type_id (0);"; + + if (ret == L"void") + os << "this->" << name << " ();" + << endl; + else + os << arg << " r = this->" << name << " ();" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (poly) + { + // In case of mixin we use virtual inheritance and only + // dynamic_cast can be used. + // + String cast (mixin ? L"dynamic_cast" : L"static_cast"); + + os << "const void* t = ctx.type_id ();" + << "const char* dt = 0;" + << fq_type << "* " << inst << " = 0;" + << endl + << "if (t == 0 && this->" << emember (e) << " != 0)" << endl + << inst << " = this->" << emember (e) << ";" + << "else if (this->" << emember_map (e) << " != 0)" + << "{" + << serializer_base << "* b = this->" << emember_map (e) << + "->find (t);" + << endl + << "if (b != 0)" + << "{" + << "dt = b->_dynamic_type ();" + << "const char* st = " << fq_type << "::_static_type ();" + << endl + << "if (strcmp (dt, st) == 0)" << endl + << "dt = 0;" + << endl; + + // Check that the types are related by inheritance. + // + os << "if (dt != 0 && !::xsde::cxx::serializer::validating::" << + "inheritance_map_instance ().check (dt, st))" + << "{" + << "ctx.schema_error (::xsde::cxx::schema_error::not_derived);" + << "return;" + << "}"; + + os << inst << " = " << cast << "< " << fq_type << "* > (b);" + << "}" + << "}"; + } + + os << "if (" << inst << ")" + << "{"; + + if (ret == L"void") + os << inst << "->pre ();"; + else + os << inst << "->pre (r);"; + + if (!exceptions) + { + // Note that after pre() we need to check both parser and + // context error states because of the recursive parsing. + // + os << endl + << "if (" << inst << "->_error_type ())" << endl + << inst << "->_copy_error (ctx);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + + // Only a globally-defined element can be a subst-group root. + // + if (poly && e.global ()) + { + if (e.qualified () && e.namespace_ ().name ()) + os << "const char* ns = " << + strlit (e.namespace_ ().name ()) << ";"; + else + os << "const char* ns = 0;"; + + os << "const char* n = " << strlit (e.name ()) << ";" + << endl; + + os << "if (dt != 0 && " << + "::xsde::cxx::serializer::substitution_map_instance ()" << + ".check (ns, n, dt))" << endl + << "dt = 0;" + << endl; + + if (exceptions) + { + os << "if (ns != 0)" << endl + << "this->_start_element (ns, n);" + << "else" << endl + << "this->_start_element (n);" + << endl; + } + else + { + os << "if (ns != 0)" + << "{" + << "if (!this->_start_element (ns, n))" << endl + << "return;" + << "}" + << "else" + << "{" + << "if (!this->_start_element (n))" << endl + << "return;" + << "}"; + } + } + else + { + if (exceptions) + { + if (e.qualified () && e.namespace_ ().name ()) + os << "this->_start_element (" << + strlit (e.namespace_ ().name ()) << ", " << + strlit (e.name ()) << ");"; + else + os << "this->_start_element (" << strlit (e.name ()) << ");"; + } + else + { + os << "if (!"; + + if (e.qualified () && e.namespace_ ().name ()) + os << "this->_start_element (" << + strlit (e.namespace_ ().name ()) << ", " << + strlit (e.name ()) << ")"; + else + os << "this->_start_element (" << strlit (e.name ()) << ")"; + + os << ")" << endl + << "return;" + << endl; + } + } + + if (poly) + { + // Set xsi:type if necessary. + // + if (exceptions) + os << "if (dt != 0)" << endl + << "this->_set_type (dt);" + << endl; + else + os << "if (dt != 0)" + << "{" + << "if (!this->_set_type (dt))" << endl + << "return;" + << "}"; + } + + os << inst << "->_pre_impl (ctx);"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_serialize_attributes ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_serialize_content ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_post_impl ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_element ();"; + else + os << "if (!this->_end_element ())" << endl + << "return;" + << endl; + + os << inst << "->post ();"; + + if (!exceptions) + { + // Note that after post() we need to check both parser and + // context error states because of the recursive parsing. + // + os << endl + << "if (" << inst << "->_error_type ())" << endl + << inst << "->_copy_error (ctx);" + << endl + << "if (ctx.error_type ())" << endl + << "return;"; + } + + os << "}"; // if (inst) + + if (min != 0) + { + os << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + + if (min == 0 && max == 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + UnsignedLong min (a.min ()), max (a.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (a) << " ())"; + + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (a) << " (); ++i)"; + } + else + os << "while (this->" << enext (a) << " ())"; + } + + os << "{"; + + if (stl) + { + os << "::std::string ns, name;" + << "this->" << ename (a) << " (ns, name);" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "if ("; + + any_test_.dispatch (a); + + os << ")" + << "{"; + + os << "if (ns.empty ())" + << "{"; + + if (exceptions) + os << "this->_start_element (name.c_str ());"; + else + os << "if (!this->_start_element (name.c_str ()))" << endl + << "return;"; + + os << "}" + << "else" + << "{"; + + if (exceptions) + os << "this->_start_element (ns.c_str (), name.c_str ());"; + else + os << "if (!this->_start_element (ns.c_str (), " << + "name.c_str ()))" << endl + << "return;"; + + os << "}" + << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_element ();"; + else + os << "if (!this->_end_element ())" << endl + << "return;"; + + os << "}" // test + << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_element);" + << "return;" + << "}"; + } + else + { + os << "const char* ns = 0;" + << "const char* name;" + << "bool free;" + << "this->" << ename (a) << " (ns, name, free);" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + else + os << "::xsde::cxx::string auto_ns, auto_name;" + << "if (free)" + << "{" + << "auto_ns.attach (const_cast< char* > (ns));" + << "auto_name.attach (const_cast< char* > (name));" + << "}"; + + os << "if ("; + + any_test_.dispatch (a); + + os << ")" + << "{"; + + if (exceptions) + os << "if (ns == 0 || *ns == '\\0')" << endl + << "this->_start_element (name);" + << "else" << endl + << "this->_start_element (ns, name);" + << endl; + else + os << "bool r;" + << "if (ns == 0 || *ns == '\\0')" << endl + << "r = this->_start_element (name);" + << "else" << endl + << "r = this->_start_element (ns, name);" + << endl + << "if (free)" + << "{" + << "delete[] ns;" + << "delete[] name;" + << "}" + << "if (!r)" << endl + << "return;" + << endl; + + os << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_element ();"; + else + os << "if (!this->_end_element ())" << endl + << "return;"; + + os << "}" // test + << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_element);" + << "return;" + << "}"; + } + + os << "}"; + + if (min == 0 && max == 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + } + + private: + AnyTest any_test_; + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_ (c), + particle_ (c) + { + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + } + + virtual Void + traverse (Type& c) + { + if (!has<Traversal::Element> (c) && + !has_particle<Traversal::Any> (c)) + return; + + // Don't use restriction_p here since we don't want special + // treatment of anyType. + // + Boolean restriction ( + c.inherits_p () && + c.inherits ().is_a<SemanticGraph::Restricts> ()); + + String const& name (ename (c)); + + os <<"// Element validation and serialization for " << + name << "." << endl + <<"//" << endl; + + os << "void " << name << "::" << endl + << "_serialize_content ()" + << "{" + << "::xsde::cxx::serializer::context& ctx = this->_context ();" + << endl; + + if (c.inherits_p () && !restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_serialize_content ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + + contains_compositor (c, contains_compositor_); + + os << "}"; + } + + private: + Compositor compositor_; + Particle particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + }; + } + + Void + generate_element_validation_source (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Complex complex (ctx); + + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} |