From f0510d2f90467de8e8f260b47d79a9baaf9bef17 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 17 Sep 2009 07:15:29 +0200 Subject: Start tracking XSD with git --- libxsd/xsd/cxx/parser/expat/elements.txx | 822 +++++++++++++++++++++++++++++++ 1 file changed, 822 insertions(+) create mode 100644 libxsd/xsd/cxx/parser/expat/elements.txx (limited to 'libxsd/xsd/cxx/parser/expat/elements.txx') diff --git a/libxsd/xsd/cxx/parser/expat/elements.txx b/libxsd/xsd/cxx/parser/expat/elements.txx new file mode 100644 index 0000000..5a60eb5 --- /dev/null +++ b/libxsd/xsd/cxx/parser/expat/elements.txx @@ -0,0 +1,822 @@ +// file : xsd/cxx/parser/expat/elements.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include // std::bad_alloc +#include +#include +#include // std::strchr +#include + +#include // xml::bits::{xml_prefix, etc} + +namespace xsd +{ + namespace cxx + { + namespace parser + { + namespace expat + { + + // document + // + + template + document:: + document (parser_base& p, + const std::basic_string& name, + bool polymorphic) + : cxx::parser::document (p, std::basic_string (), name), + xml_parser_ (0), + eh_ (0), + polymorphic_ (polymorphic) + { + } + + template + document:: + document (parser_base& p, + const C* name, + bool polymorphic) + : cxx::parser::document (p, std::basic_string (), name), + xml_parser_ (0), + eh_ (0), + polymorphic_ (polymorphic) + { + } + + template + document:: + document (parser_base& p, + const C* ns, + const C* name, + bool polymorphic) + : cxx::parser::document (p, ns, name), + xml_parser_ (0), + eh_ (0), + polymorphic_ (polymorphic) + { + } + + template + document:: + document (parser_base& p, + const std::basic_string& ns, + const std::basic_string& name, + bool polymorphic) + : cxx::parser::document (p, ns, name), + xml_parser_ (0), + eh_ (0), + polymorphic_ (polymorphic) + { + } + + template + document:: + document (bool polymorphic) + : xml_parser_ (0), + eh_ (0), + polymorphic_ (polymorphic) + { + } + + // file + // + + template + void document:: + parse (const std::basic_string& file) + { + std::ifstream ifs; + ifs.exceptions (std::ios_base::badbit | std::ios_base::failbit); + ifs.open (file.c_str (), std::ios_base::in | std::ios_base::binary); + + parse (ifs, file); + } + + template + void document:: + parse (const std::basic_string& file, xml::error_handler& eh) + { + std::ifstream ifs; + ifs.exceptions (std::ios_base::badbit | std::ios_base::failbit); + ifs.open (file.c_str (), std::ios_base::in | std::ios_base::binary); + + parse (ifs, file, eh); + } + + + // istream + // + + template + void document:: + parse (std::istream& is) + { + parse (is, 0, 0, default_eh_); + } + + template + void document:: + parse (std::istream& is, xml::error_handler& eh) + { + if (!parse (is, 0, 0, eh)) + throw parsing (); + } + + template + void document:: + parse (std::istream& is, const std::basic_string& system_id) + { + default_eh_.reset (); + parse (is, &system_id, 0, default_eh_); + } + + template + void document:: + parse (std::istream& is, + const std::basic_string& system_id, + xml::error_handler& eh) + { + if (!parse (is, &system_id, 0, eh)) + throw parsing (); + } + + template + void document:: + parse (std::istream& is, + const std::basic_string& system_id, + const std::basic_string& public_id) + { + default_eh_.reset (); + parse (is, &system_id, &public_id, default_eh_); + } + + template + void document:: + parse (std::istream& is, + const std::basic_string& system_id, + const std::basic_string& public_id, + xml::error_handler& eh) + { + if (!parse (is, &system_id, &public_id, eh)) + throw parsing (); + } + + // data + // + + template + void document:: + parse (const void* data, std::size_t size, bool last) + { + default_eh_.reset (); + parse (data, size, last, 0, 0, default_eh_); + } + + template + void document:: + parse (const void* data, std::size_t size, bool last, + xml::error_handler& eh) + { + if (!parse (data, size, last, 0, 0, eh)) + throw parsing (); + } + + template + void document:: + parse (const void* data, std::size_t size, bool last, + const std::basic_string& system_id) + { + default_eh_.reset (); + parse (data, size, last, &system_id, 0, default_eh_); + } + + template + void document:: + parse (const void* data, std::size_t size, bool last, + const std::basic_string& system_id, + xml::error_handler& eh) + { + if (!parse (data, size, last, &system_id, 0, eh)) + throw parsing (); + } + + template + void document:: + parse (const void* data, std::size_t size, bool last, + const std::basic_string& system_id, + const std::basic_string& public_id) + { + default_eh_.reset (); + parse (data, size, last, &system_id, &public_id, default_eh_); + } + + template + void document:: + parse (const void* data, std::size_t size, bool last, + const std::basic_string& system_id, + const std::basic_string& public_id, + xml::error_handler& eh) + { + if (!parse (data, size, last, &system_id, &public_id, eh)) + throw parsing (); + } + + // Implementation details. + // + + namespace bits + { + struct stream_exception_controller + { + ~stream_exception_controller () + { + std::ios_base::iostate s = is_.rdstate (); + s &= ~std::ios_base::failbit; + + // If our error state (sans failbit) intersects with the + // exception state then that means we have an active + // exception and changing error/exception state will + // cause another to be thrown. + // + if (!(old_state_ & s)) + { + // Clear failbit if it was caused by eof. + // + if (is_.fail () && is_.eof ()) + is_.clear (s); + + is_.exceptions (old_state_); + } + } + + stream_exception_controller (std::istream& is) + : is_ (is), old_state_ (is_.exceptions ()) + { + is_.exceptions (old_state_ & ~std::ios_base::failbit); + } + + private: + stream_exception_controller (const stream_exception_controller&); + + stream_exception_controller& + operator= (const stream_exception_controller&); + + private: + std::istream& is_; + std::ios_base::iostate old_state_; + }; + }; + + template + bool document:: + parse (std::istream& is, + const std::basic_string* system_id, + const std::basic_string* public_id, + xml::error_handler& eh) + { + parser_auto_ptr parser (XML_ParserCreateNS (0, XML_Char (' '))); + + if (parser == 0) + throw std::bad_alloc (); + + if (system_id || public_id) + parse_begin (parser, system_id ? *system_id : *public_id, eh); + else + parse_begin (parser, eh); + + // Temporarily unset the exception failbit. Also clear the + // fail bit when we reset the old state if it was caused + // by eof. + // + bits::stream_exception_controller sec (is); + + char buf[16384]; // 4 x page size. + + bool r (true); + + do + { + is.read (buf, sizeof (buf)); + + if (is.bad () || (is.fail () && !is.eof ())) + { + // If the stream is not using exceptions then the user + // will have to test for stream failures before calling + // post. + // + break; + } + + if (XML_Parse ( + parser, buf, is.gcount (), is.eof ()) == XML_STATUS_ERROR) + { + r = false; + break; + } + } while (!is.eof ()); + + parse_end (); + return r; + } + + template + bool document:: + parse (const void* data, + std::size_t size, + bool last, + const std::basic_string* system_id, + const std::basic_string* public_id, + xml::error_handler& eh) + { + // First call. + // + if (auto_xml_parser_ == 0) + { + auto_xml_parser_ = XML_ParserCreateNS (0, XML_Char (' ')); + + if (auto_xml_parser_ == 0) + throw std::bad_alloc (); + + if (system_id || public_id) + parse_begin (auto_xml_parser_, + system_id ? *system_id : *public_id, eh); + else + parse_begin (auto_xml_parser_, eh); + } + + bool r (XML_Parse (xml_parser_, + static_cast (data), + static_cast (size), + last) != XML_STATUS_ERROR); + parse_end (); + return r; + } + + // XML_Parser + // + + template + void document:: + parse_begin (XML_Parser parser) + { + xml_parser_ = parser; + eh_ = &default_eh_; + public_id_.clear (); + set (); + } + + template + void document:: + parse_begin (XML_Parser parser, + const std::basic_string& public_id) + { + xml_parser_ = parser; + eh_ = &default_eh_; + public_id_ = public_id; + set (); + } + + template + void document:: + parse_begin (XML_Parser parser, xml::error_handler& eh) + { + xml_parser_ = parser; + eh_ = &eh; + public_id_.clear (); + set (); + } + + template + void document:: + parse_begin (XML_Parser parser, + const std::basic_string& public_id, + xml::error_handler& eh) + { + xml_parser_ = parser; + eh_ = &eh; + public_id_ = public_id; + set (); + } + + template + void document:: + parse_end () + { + XML_Error e (XML_GetErrorCode (xml_parser_)); + + if (e == XML_ERROR_NONE || e == XML_ERROR_ABORTED) + { + clear (); + xml_parser_ = 0; + auto_xml_parser_ = 0; + } + else + { + unsigned long l = XML_GetCurrentLineNumber (xml_parser_); + unsigned long c = XML_GetCurrentColumnNumber (xml_parser_); + std::basic_string message (XML_ErrorString (e)); + + eh_->handle (public_id_, + l, c, + xml::error_handler::severity::fatal, + message); + + clear (); + xml_parser_ = 0; + auto_xml_parser_ = 0; + + // We don't want to throw an empty parsing exception here + // since the user probably already knows about the error. + } + + if (eh_ == &default_eh_) + default_eh_.throw_if_failed (); + } + + // + // + template + void document:: + set () + { + assert (xml_parser_ != 0); + + XML_SetUserData(xml_parser_, this); + + XML_SetStartElementHandler (xml_parser_, start_element_thunk_); + XML_SetEndElementHandler (xml_parser_, end_element_thunk_); + XML_SetCharacterDataHandler (xml_parser_, characters_thunk_); + + if (polymorphic_) + { + XML_SetNamespaceDeclHandler (xml_parser_, + start_namespace_decl_thunk_, + end_namespace_decl_thunk_); + } + } + + template + void document:: + clear () + { + assert (xml_parser_ != 0); + + XML_SetUserData (xml_parser_, 0); + XML_SetStartElementHandler (xml_parser_, 0); + XML_SetEndElementHandler (xml_parser_, 0); + XML_SetCharacterDataHandler (xml_parser_, 0); + + if (polymorphic_) + XML_SetNamespaceDeclHandler (xml_parser_, 0, 0); + } + + template + void document:: + translate_schema_exception (const schema_exception& e) + { + unsigned long l = XML_GetCurrentLineNumber (xml_parser_); + unsigned long c = XML_GetCurrentColumnNumber (xml_parser_); + + eh_->handle (public_id_, + l, c, + xml::error_handler::severity::fatal, + e.message ()); + + XML_StopParser (xml_parser_, false); + } + + // Event routing. + // + + // Expat thunks. + // + template + void XMLCALL document:: + start_element_thunk_ (void* data, + const XML_Char* ns_name, + const XML_Char** atts) + { + document& d (*reinterpret_cast (data)); + d.start_element_ (ns_name, atts); + } + + template + void XMLCALL document:: + end_element_thunk_ (void* data, const XML_Char* ns_name) + { + document& d (*reinterpret_cast (data)); + d.end_element_ (ns_name); + } + + template + void XMLCALL document:: + characters_thunk_ (void* data, const XML_Char* s, int n) + { + document& d (*reinterpret_cast (data)); + d.characters_ (s, static_cast (n)); + } + + template + void XMLCALL document:: + start_namespace_decl_thunk_ (void* data, + const XML_Char* prefix, + const XML_Char* ns) + { + document& d (*reinterpret_cast (data)); + d.start_namespace_decl_ (prefix, ns); + } + + template + void XMLCALL document:: + end_namespace_decl_thunk_ (void* data, const XML_Char* prefix) + { + document& d (*reinterpret_cast (data)); + d.end_namespace_decl_ (prefix); + } + + namespace bits + { + inline void + split_name (const XML_Char* s, + const char*& ns, std::size_t& ns_s, + const char*& name, std::size_t& name_s) + { + const char* p (std::strchr (s, ' ')); + + if (p) + { + ns = s; + ns_s = p - s; + name = p + 1; + } + else + { + ns = s; + ns_s = 0; + name = s; + } + + name_s = std::char_traits::length (name); + } + } + + template + void document:: + start_element_ (const XML_Char* ns_name, const XML_Char** atts) + { + // Current Expat (2.0.0) has a (mis)-feature of a possibility of + // calling callbacks even after the non-resumable XML_StopParser + // call. The following code accounts for this. + // + { + XML_ParsingStatus s; + XML_GetParsingStatus (xml_parser_, &s); + if (s.parsing == XML_FINISHED) + return; + } + + typedef std::basic_string string; + + const char* ns_p; + const char* name_p; + size_t ns_s, name_s; + + bits::split_name (ns_name, ns_p, ns_s, name_p, name_s); + + { + const ro_string ns (ns_p, ns_s), name (name_p, name_s); + + if (!polymorphic_) + { + try + { + start_element (ns, name, 0); + } + catch (const schema_exception& e) + { + translate_schema_exception (e); + return; + } + } + else + { + // Search for the xsi:type attribute. + // + const XML_Char** p = atts; // VC8 can't handle p (atts) + for (; *p != 0; p += 2) + { + bits::split_name (*p, ns_p, ns_s, name_p, name_s); + const ro_string ns (ns_p, ns_s), name (name_p, name_s); + + if (name == xml::bits::type () && + ns == xml::bits::xsi_namespace ()) + break; + } + + if (*p == 0) + { + try + { + start_element (ns, name, 0); + } + catch (const schema_exception& e) + { + translate_schema_exception (e); + return; + } + } + else + { + // @@ Need proper QName validation. + // + // Get the qualified type name and try to resolve it. + // + ro_string qn (*(p + 1)); + + ro_string tp, tn; + typename ro_string::size_type pos (qn.find (C (':'))); + + try + { + if (pos != ro_string::npos) + { + tp.assign (qn.data (), pos); + tn.assign (qn.data () + pos + 1); + + if (tp.empty ()) + throw dynamic_type (qn); + } + else + tn.assign (qn.data (), qn.size ()); + + if (tn.empty ()) + throw dynamic_type (qn); + + // Search our namespace declaration stack. Note that + // we need to do this even if prefix is empty. Sun CC + // 5.7 blows if we use const_reverse_iterator. + // + ro_string tns; + for (typename ns_decls::reverse_iterator + it (ns_decls_.rbegin ()), e (ns_decls_.rend ()); + it != e; ++it) + { + if (it->prefix == tp) + { + tns.assign (it->ns); + break; + } + } + + if (!tp.empty () && tns.empty ()) + { + // The 'xml' prefix requires special handling. + // + if (tp == xml::bits::xml_prefix ()) + tns.assign (xml::bits::xml_namespace ()); + else + throw dynamic_type (qn); + } + + // Construct the compound type id. + // + string id (tn.data (), tn.size ()); + + if (!tns.empty ()) + { + id += C (' '); + id.append (tns.data (), tns.size ()); + } + + ro_string ro_id (id); + start_element (ns, name, &ro_id); + } + catch (const schema_exception& e) + { + translate_schema_exception (e); + return; + } + } + } + } + + for (; *atts != 0; atts += 2) + { + bits::split_name (*atts, ns_p, ns_s, name_p, name_s); + + const ro_string ns (ns_p, ns_s), name (name_p, name_s); + const ro_string value (*(atts + 1)); + + try + { + attribute (ns, name, value); + } + catch (const schema_exception& e) + { + translate_schema_exception (e); + break; + } + } + } + + template + void document:: + end_element_ (const XML_Char* ns_name) + { + // Current Expat (2.0.0) has a (mis)-feature of a possibility of + // calling callbacks even after the non-resumable XML_StopParser + // call. The following code accounts for this. + // + { + XML_ParsingStatus s; + XML_GetParsingStatus (xml_parser_, &s); + if (s.parsing == XML_FINISHED) + return; + } + + const char* ns_p; + const char* name_p; + size_t ns_s, name_s; + + bits::split_name (ns_name, ns_p, ns_s, name_p, name_s); + + const ro_string ns (ns_p, ns_s), name (name_p, name_s); + + try + { + end_element (ns, name); + } + catch (const schema_exception& e) + { + translate_schema_exception (e); + } + } + + template + void document:: + characters_ (const XML_Char* s, std::size_t n) + { + // Current Expat (2.0.0) has a (mis)-feature of a possibility of + // calling callbacks even after the non-resumable XML_StopParser + // call. The following code accounts for this. + // + { + XML_ParsingStatus s; + XML_GetParsingStatus (xml_parser_, &s); + if (s.parsing == XML_FINISHED) + return; + } + + if (n != 0) + { + const ro_string str (s, n); + + try + { + characters (str); + } + catch (const schema_exception& e) + { + translate_schema_exception (e); + } + } + } + + template + void document:: + start_namespace_decl_ (const XML_Char* p, const XML_Char* ns) + { + // prefix is 0 for default namespace + // namespace is 0 when unsetting default namespace + // + if (polymorphic_) + ns_decls_.push_back (ns_decl ((p ? p : ""), (ns ? ns : ""))); + } + + template + void document:: + end_namespace_decl_ (const XML_Char* p) + { + // prefix is 0 for default namespace + // + if (polymorphic_) + { + // Here we assume the prefixes are removed in the reverse + // order of them being added. This appears to how every + // sensible implementation works. + // + assert (p + ? ns_decls_.back ().prefix == p + : ns_decls_.back ().prefix.empty ()); + + ns_decls_.pop_back (); + } + } + } + } + } +} -- cgit v1.1