diff options
58 files changed, 2526 insertions, 121 deletions
@@ -48,6 +48,13 @@ Version 3.2.0 for variable-length types. These functions allow you to make dynamically- allocated copies of variable-length objects. + * Support for schema evolution using substitution groups. The 'ignore' and + 'passthrough' examples in the examples/cxx/hybrid/evolution/ directory + show how the new mechanism work. The 'ignore' example shows how to + ignores unknown elements. The 'passthrough' example shows how to pass + the unknown content through parsing and serialization so that the output + XML contains all the unknown elements. + * The anySimpleType build-in type is now mapped to std::string or a C-string, depending on whether STL is enabled or not. diff --git a/dist/examples/cxx/hybrid/evolution/ignore/makefile b/dist/examples/cxx/hybrid/evolution/ignore/makefile new file mode 100644 index 0000000..146a31d --- /dev/null +++ b/dist/examples/cxx/hybrid/evolution/ignore/makefile @@ -0,0 +1,68 @@ +root := ../../../../.. + +include $(root)/build/cxx/rules.make + +# Build. +# +EXTRA_CPPFLAGS := -I$(root)/libxsde + +ifeq ($(XSDE_ENCODING),iso8859-1) +EXTRA_XSDFLAGS += --char-encoding iso8859-1 +endif + +ifeq ($(XSDE_LONGLONG),n) +EXTRA_XSDFLAGS += --no-long-long +endif + +ifeq ($(XSDE_PARSER_VALIDATION),n) +EXTRA_XSDFLAGS += --suppress-parser-val +endif + +ifeq ($(XSDE_SERIALIZER_VALIDATION),n) +EXTRA_XSDFLAGS += --suppress-serializer-val +endif + +ifeq ($(XSDE_REUSE_STYLE),mixin) +EXTRA_XSDFLAGS += --reuse-style-mixin +endif + +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + +driver: driver.o transform.o transform-pskel.o transform-pimpl.o \ +$(root)/libxsde/xsde/libxsde.a + +driver.o: driver.cxx transform.hxx transform-pimpl.hxx +transform.o: transform.cxx transform.hxx +transform-pskel.o: transform-pskel.cxx +transform-pimpl.o: transform-pimpl.cxx + +.PRECIOUS: %.hxx %.cxx %-pskel.hxx %-pskel.cxx %-pimpl.hxx %-pimpl.cxx + +%.hxx %.cxx %-pskel.hxx %-pskel.cxx %-pimpl.hxx %-pimpl.cxx: %.xsd + $(root)/bin/xsde cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--generate-parser --generate-aggregate --root-element transformations \ +--generate-polymorphic $< + + +# Generate. +# +.PHONY: gen +gen: transform.hxx + + +# Test. +# +.PHONY: test +test: driver transform.xml + ./driver transform.xml + +# Clean. +# +.PHONY: clean cleanobj +cleanobj: + rm -f transform-pimpl.o transform-pskel.o transform.o driver.o driver + +clean: cleanobj + rm -f transform-pimpl.?xx transform-pskel.?xx transform.?xx diff --git a/dist/examples/cxx/hybrid/evolution/ignore/nmakefile b/dist/examples/cxx/hybrid/evolution/ignore/nmakefile new file mode 100644 index 0000000..188fa79 --- /dev/null +++ b/dist/examples/cxx/hybrid/evolution/ignore/nmakefile @@ -0,0 +1,66 @@ +root = ..\..\..\..\.. + +!include $(root)\build\cxx\rules.nmake + +# Build. +# +EXTRA_CPPFLAGS = /I$(root)\libxsde + +!if "$(XSDE_ENCODING)" == "iso8859-1" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --char-encoding iso8859-1 +!endif + +!if "$(XSDE_LONGLONG)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --no-long-long +!endif + +!if "$(XSDE_PARSER_VALIDATION)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-parser-val +!endif + +!if "$(XSDE_SERIALIZER_VALIDATION)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-serializer-val +!endif + +!if "$(XSDE_REUSE_STYLE)" == "mixin" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin +!endif + +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + +driver.exe: driver.obj transform.obj transform-pskel.obj transform-pimpl.obj \ +$(root)\libxsde\xsde\xsde.lib + +driver.obj: driver.cxx transform.hxx transform-pimpl.hxx +transform.obj: transform.cxx transform.hxx +transform-pskel.obj: transform-pskel.cxx +transform-pimpl.obj: transform-pimpl.cxx + +transform.cxx transform.hxx \ +transform-pskel.cxx transform-pskel.hxx transform-pimpl.cxx transform-pimpl.hxx \ +: transform.xsd + $(root)\bin\xsde.exe cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--generate-parser --generate-aggregate --root-element transformations \ +--generate-polymorphic transform.xsd + + +# Generate. +# +gen: transform.hxx + + +# Test. +# +test: driver.exe transform.xml + .\driver.exe transform.xml + +# Clean. +# +cleanobj: + -del transform-pimpl.obj transform-pskel.obj transform.obj \ +driver.obj driver.exe + +clean: cleanobj + -del transform-pimpl.?xx transform-pskel.?xx transform.?xx diff --git a/dist/examples/cxx/hybrid/evolution/makefile b/dist/examples/cxx/hybrid/evolution/makefile new file mode 100644 index 0000000..7a87d36 --- /dev/null +++ b/dist/examples/cxx/hybrid/evolution/makefile @@ -0,0 +1,27 @@ +root := ../../../.. + +include $(root)/build/config.make + +dirs := + +ifeq ($(XSDE_IOSTREAM),y) +ifeq ($(XSDE_EXCEPTIONS),y) + +ifeq ($(XSDE_STL),y) +dirs += ignore passthrough +endif + +endif +endif + +.PHONY: all $(dirs) + +all: $(dirs) + +$(dirs): + @$(MAKE) -C $@ $(MAKECMDGOALS) + +makefile: ; +%.make:: ; + +%:: $(dirs) ; diff --git a/dist/examples/cxx/hybrid/evolution/nmakefile b/dist/examples/cxx/hybrid/evolution/nmakefile new file mode 100644 index 0000000..61d6546 --- /dev/null +++ b/dist/examples/cxx/hybrid/evolution/nmakefile @@ -0,0 +1,27 @@ +root = ..\..\..\.. + +!include $(root)\build\config.nmake + +dirs = + +!if "$(XSDE_IOSTREAM)" == "y" +!if "$(XSDE_EXCEPTIONS)" == "y" + +!if "$(XSDE_STL)" == "y" +dirs = $(dirs) ignore passthrough +!endif + +!endif +!endif + +all: + @for %i in ( $(dirs) ) do \ +@cmd /c "echo entering %i && cd %i && $(MAKE) /nologo /f nmakefile" || exit 1 + +gen test: + @for %i in ( $(dirs) ) do \ +@cmd /c "echo entering %i && cd %i && $(MAKE) /nologo /f nmakefile $@" || exit 1 + +clean cleanobj: + @for %i in ( $(dirs) ) do \ +@cmd /c "echo entering %i && cd %i && $(MAKE) /nologo /f nmakefile $@" diff --git a/dist/examples/cxx/hybrid/evolution/passthrough/makefile b/dist/examples/cxx/hybrid/evolution/passthrough/makefile new file mode 100644 index 0000000..4f6520c --- /dev/null +++ b/dist/examples/cxx/hybrid/evolution/passthrough/makefile @@ -0,0 +1,82 @@ +root := ../../../../.. + +include $(root)/build/cxx/rules.make + +# Build. +# +EXTRA_CPPFLAGS := -I$(root)/libxsde + +ifeq ($(XSDE_ENCODING),iso8859-1) +EXTRA_XSDFLAGS += --char-encoding iso8859-1 +endif + +ifeq ($(XSDE_LONGLONG),n) +EXTRA_XSDFLAGS += --no-long-long +endif + +ifeq ($(XSDE_PARSER_VALIDATION),n) +EXTRA_XSDFLAGS += --suppress-parser-val +endif + +ifeq ($(XSDE_SERIALIZER_VALIDATION),n) +EXTRA_XSDFLAGS += --suppress-serializer-val +endif + +ifeq ($(XSDE_REUSE_STYLE),mixin) +EXTRA_XSDFLAGS += --reuse-style-mixin +endif + +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + +driver: driver.o unknown-type.o transform.o xml.o transform-pskel.o \ +transform-pimpl.o transform-sskel.o transform-simpl.o unknown-type-pimpl.o \ +unknown-type-simpl.o $(root)/libxsde/xsde/libxsde.a + +driver.o: driver.cxx transform.hxx unknown-type.hxx xml.hxx xml.ixx \ +transform-pimpl.hxx transform-simpl.hxx +transform.o: transform.cxx transform.hxx unknown-type.hxx +xml.o: xml.cxx xml.hxx xml.ixx transform.hxx +transform-pskel.o: transform-pskel.cxx +transform-pimpl.o: transform-pimpl.cxx +transform-simpl.o: transform-simpl.cxx +transform-simpl.o: transform-simpl.cxx +unknown-type.o: unknown-type.cxx unknown-type.hxx transform.hxx xml.hxx xml.ixx +unknown-type-pimpl.o: unknown-type-pimpl.cxx unknown-type-pimpl.hxx \ +transform.hxx xml.hxx xml.ixx +unknown-type-simpl.o: unknown-type-simpl.cxx unknown-type-simpl.hxx \ +transform.hxx xml.hxx xml.ixx + +.PRECIOUS: %.hxx %.cxx %-pskel.hxx %-pskel.cxx %-pimpl.hxx %-pimpl.cxx \ +%-sskel.hxx %-sskel.cxx %-simpl.hxx %-simpl.cxx + +%.hxx %.cxx %-pskel.hxx %-pskel.cxx %-pimpl.hxx %-pimpl.cxx \ +%-sskel.hxx %-sskel.cxx %-simpl.hxx %-simpl.cxx: %.xsd + $(root)/bin/xsde cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--options-file options $< + + +# Generate. +# +.PHONY: gen +gen: transform.hxx + + +# Test. +# +.PHONY: test +test: driver transform.xml + ./driver transform.xml + +# Clean. +# +.PHONY: clean cleanobj +cleanobj: + rm -f unknown-type.o unknown-type-pimpl.o unknown-type-simpl.o \ +transform-pimpl.o transform-pskel.o transform-simpl.o transform-sskel.o \ +xml.o transform.o driver.o driver + +clean: cleanobj + rm -f transform-pimpl.?xx transform-pskel.?xx transform-simpl.?xx \ +transform-sskel.?xx transform.?xx diff --git a/dist/examples/cxx/hybrid/evolution/passthrough/nmakefile b/dist/examples/cxx/hybrid/evolution/passthrough/nmakefile new file mode 100644 index 0000000..fe85b4a --- /dev/null +++ b/dist/examples/cxx/hybrid/evolution/passthrough/nmakefile @@ -0,0 +1,80 @@ +root = ..\..\..\..\.. + +!include $(root)\build\cxx\rules.nmake + +# Build. +# +EXTRA_CPPFLAGS = /I$(root)\libxsde + +!if "$(XSDE_ENCODING)" == "iso8859-1" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --char-encoding iso8859-1 +!endif + +!if "$(XSDE_LONGLONG)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --no-long-long +!endif + +!if "$(XSDE_PARSER_VALIDATION)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-parser-val +!endif + +!if "$(XSDE_SERIALIZER_VALIDATION)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-serializer-val +!endif + +!if "$(XSDE_REUSE_STYLE)" == "mixin" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin +!endif + +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + +driver.exe: driver.obj unknown-type.obj transform.obj xml.obj \ +transform-pskel.obj transform-pimpl.obj transform-sskel.obj \ +transform-simpl.obj unknown-type-pimpl.obj unknown-type-simpl.obj \ +$(root)\libxsde\xsde\xsde.lib + +driver.obj: driver.cxx transform.hxx unknown-type.hxx xml.hxx xml.ixx \ +transform-pimpl.hxx transform-simpl.hxx +transform.obj: transform.cxx transform.hxx unknown-type.hxx +xml.obj: xml.cxx xml.hxx xml.ixx transform.hxx +transform-pskel.obj: transform-pskel.cxx +transform-pimpl.obj: transform-pimpl.cxx +transform-simpl.obj: transform-simpl.cxx +transform-simpl.obj: transform-simpl.cxx +unknown-type.obj: unknown-type.cxx unknown-type.hxx transform.hxx xml.hxx \ +xml.ixx +unknown-type-pimpl.obj: unknown-type-pimpl.cxx unknown-type-pimpl.hxx \ +transform.hxx xml.hxx xml.ixx +unknown-type-simpl.obj: unknown-type-simpl.cxx unknown-type-simpl.hxx \ +transform.hxx xml.hxx xml.ixx + +transform.cxx transform.hxx \ +transform-pskel.cxx transform-pskel.hxx transform-pimpl.cxx transform-pimpl.hxx \ +transform-sskel.cxx transform-sskel.hxx transform-simpl.cxx transform-simpl.hxx \ +: transform.xsd + $(root)\bin\xsde.exe cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--options-file options transform.xsd + + +# Generate. +# +gen: transform.hxx + + +# Test. +# +test: driver.exe transform.xml + .\driver.exe transform.xml + +# Clean. +# +cleanobj: + -del unknown-type.obj unknown-type-pimpl.obj unknown-type-simpl.obj \ +transform-pimpl.obj transform-pskel.obj transform-simpl.obj \ +transform-sskel.obj xml.obj transform.obj driver.obj driver.exe + +clean: cleanobj + -del transform-pimpl.?xx transform-pskel.?xx transform-simpl.?xx \ +transform-sskel.?xx transform.?xx diff --git a/dist/examples/cxx/hybrid/evolution/passthrough/options b/dist/examples/cxx/hybrid/evolution/passthrough/options new file mode 100644 index 0000000..cd0eadc --- /dev/null +++ b/dist/examples/cxx/hybrid/evolution/passthrough/options @@ -0,0 +1,8 @@ +--generate-parser +--generate-serializer +--generate-aggregate +--root-element transformations +--generate-polymorphic +--custom-type unknown_type=//unknown_type_base/unknown-type.hxx +--custom-parser unknown_type=unknown_type_base_pimpl/unknown-type-pimpl.hxx +--custom-serializer unknown_type=unknown_type_base_simpl/unknown-type-simpl.hxx diff --git a/dist/examples/cxx/hybrid/makefile b/dist/examples/cxx/hybrid/makefile index 859451b..76c246b 100644 --- a/dist/examples/cxx/hybrid/makefile +++ b/dist/examples/cxx/hybrid/makefile @@ -6,7 +6,7 @@ dirs := ifeq ($(XSDE_CUSTOM_ALLOCATOR),n) -dirs += binary compositors custom +dirs += binary compositors custom evolution ifeq ($(XSDE_IOSTREAM),y) ifeq ($(XSDE_EXCEPTIONS),y) diff --git a/dist/examples/cxx/hybrid/nmakefile b/dist/examples/cxx/hybrid/nmakefile index 45c57ca..515fed9 100644 --- a/dist/examples/cxx/hybrid/nmakefile +++ b/dist/examples/cxx/hybrid/nmakefile @@ -6,7 +6,7 @@ dirs = !if "$(XSDE_CUSTOM_ALLOCATOR)" == "n" -dirs = $(dirs) binary compositors custom +dirs = $(dirs) binary compositors custom evolution !if "$(XSDE_IOSTREAM)" == "y" !if "$(XSDE_EXCEPTIONS)" == "y" diff --git a/examples/cxx/hybrid/README b/examples/cxx/hybrid/README index dabc11f..2761db4 100644 --- a/examples/cxx/hybrid/README +++ b/examples/cxx/hybrid/README @@ -53,6 +53,9 @@ custom/ to the generated ones. See the accompanying README file for an overview of each example in this directory. +evolution/ + A collection of examples that show how to handle schema evolution. + binary/ A collection of examples that show how to serialize the object model into a number of predefined and custom binary formats. diff --git a/examples/cxx/hybrid/evolution/README b/examples/cxx/hybrid/evolution/README new file mode 100644 index 0000000..878cb50 --- /dev/null +++ b/examples/cxx/hybrid/evolution/README @@ -0,0 +1,13 @@ +This directory contains a number of examples that show how to handle schema +evolution using the C++/Hybrid mapping. The following list gives an overview +of each example: + +ignore + Shows how to handle schema evolution using substitution groups. This + example ignores unknown elements. + +passthrough + Shows how to handle schema evolution using substitution groups. This + example passes the unknown content through parsing and serialization + so that the output XML contains all the unknown elements. + diff --git a/examples/cxx/hybrid/evolution/ignore/README b/examples/cxx/hybrid/evolution/ignore/README new file mode 100644 index 0000000..fb7272d --- /dev/null +++ b/examples/cxx/hybrid/evolution/ignore/README @@ -0,0 +1,61 @@ +This example shows how to handle schema evolution using substitution groups. +The general idea is as follows: the initial version of the schema defines +extension points using the XML Schema substitution group mechanism. The +subsequent versions of the schema add new elements to the substitution +groups. The goal here is for applications that were built using earlier +versions of the schema to be able to handle documents corresponding to the +newer versions without validation errors or any other failures. This example +shows how to ignore such new elements. The 'passthrough' example shows how +to pass the unknown content through parsing and serialization so that the +output XML contains all the unknown elements. + +This example uses XML Schema polymorphism in the form of substitution groups. +If you are not familiar with how to work with polymorphic object models, +refer to the C++/Hybrid Mapping Getting Started Guide as well as the +'polymorphism' example in the examples/cxx/hybrid/ directory. + +The example consists of the following files: + +transform.xsd + The initial version of the schema that describes simple transformations, + such as move and rotate. The schema makes it possible to add new + transformations in subsequent versions of the schema. Our example is built + using this schema. + +transform-v2.xsd + The second version of the schema which adds the scale transformation. This + schema is provided as an example. + +transform.xml + Sample XML document corresponding to the second version of the schema. In + particular, it contains the scale transformation which is unknown in + transform.xsd. + +transform.hxx +transform.cxx + +transform-pskel.hxx +transform-pskel.cxx + +transform-pimpl.hxx +transform-pimpl.cxx + Object model (the first pair of files), parser skeletons (the second pair) + and parser implementations (the third pair). These files are generated by + the XSD/e compiler from transform.xsd. The --generate-parser and + --generate-aggregate options were used to request the generation of the + parsing code. The --generate-polymorphic option was used to request the + generation of the polymorphism-aware code. + +driver.cxx + Driver for the example. It first sets the substitution map callback that + is used to tell the parser which elements should be ignored. The driver + then calls the parser that constructs the object model from the input XML + file. Finally, it prints the content of the object model to STDERR. + +To run the example on the sample XML instance document simply execute: + +$ ./driver transform.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <transform.xml diff --git a/examples/cxx/hybrid/evolution/ignore/driver.cxx b/examples/cxx/hybrid/evolution/ignore/driver.cxx new file mode 100644 index 0000000..6c1c45f --- /dev/null +++ b/examples/cxx/hybrid/evolution/ignore/driver.cxx @@ -0,0 +1,131 @@ +// file : examples/cxx/hybrid/evolution/ignore/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <string> +#include <iostream> + +#include "transform.hxx" +#include "transform-pimpl.hxx" + +using namespace std; +using namespace transform; + +// Parser substitution map callback. This callback is called when the +// parser needs to check whether an element belongs to a substitution +// group. We use this callback to return a special ignored type marker +// for unknown transformations. +// +static bool +parser_callback (const xml_schema::ro_string& root_ns, + const xml_schema::ro_string& root_name, + const xml_schema::ro_string& /*member_ns*/, + const xml_schema::ro_string& member_name, + const char*& type) +{ + // Check that the root of the substitution group is 'transformation'. + // + if (root_name == "transformation" && + root_ns == "http://www.codesynthesis.com/transform") + { + // Check that the element's name has the '-transformation' suffix. This + // is the convention we use in our schema to minimize the chance of + // treating any unknown elements as a transformation. + // + // + string s ("-transformation"); + string n (member_name); + + if (n.size () > s.size () && + string (n, n.size () - s.size (), s.size ()) == s) + { + // Set type to the special ignore marker. + // + type = "*"; + return true; + } + } + + return false; +} + +int +main (int argc, char* argv[]) +{ + const char* input; + + if (argc < 2) + { + input = "STDIN"; + cerr << "XML file not specified, reading from STDIN" << endl; + } + else + input = argv[1]; + + try + { + // Set the substitution map callback. + // + xml_schema::parser_smap_callback (&parser_callback); + + // Parse. + // + transformations_paggr transformations_p; + + // The last argument to the document's constructor indicates that we + // are parsing polymorphic XML documents. + // + xml_schema::document_pimpl doc_p ( + transformations_p.root_parser (), + transformations_p.root_namespace (), + transformations_p.root_name (), + true); + + transformations_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr<transformations_type> tf (transformations_p.post ()); + + // Print what we've got. + // + for (transformations_type::transformation_iterator i = + tf->transformation ().begin (); + i != tf->transformation ().end (); + ++i) + { + transformation_type& t = *i; + + if (move_type* m = dynamic_cast<move_type*> (&t)) + { + cout << m->name () << ": " << m->description () << endl + << "\tx: " << m->x () << endl + << "\ty: " << m->y () << endl + << endl; + } + else if (rotate_type* r = dynamic_cast<rotate_type*> (&t)) + { + cout << r->name () << ": " << r->description () << endl + << "\tangle: " << r->angle () << endl + << endl; + } + } + } + catch (const xml_schema::parser_exception& e) + { + cerr << input << ":" << e.line () << ":" << e.column () << ": " + << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << input << ": unable to open or read/write failure" << endl; + return 1; + } + + return 0; +} diff --git a/examples/cxx/hybrid/evolution/ignore/makefile b/examples/cxx/hybrid/evolution/ignore/makefile new file mode 100644 index 0000000..cde32fb --- /dev/null +++ b/examples/cxx/hybrid/evolution/ignore/makefile @@ -0,0 +1,103 @@ +# file : examples/cxx/hybrid/evolution/ignore/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := transform.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \ + $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \ + $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) + +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-aggregate \ +--root-element transformations --generate-polymorphic + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Dist. +# +dist-common := $(out_base)/.dist-common +$(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(dist-common): + $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) + $(call install-data,$(src_base)/transform.xsd,$(dist_prefix)/$(path)/transform.xsd) + $(call install-data,$(src_base)/transform-v2.xsd,$(dist_prefix)/$(path)/transform-v2.xsd) + $(call install-data,$(src_base)/transform.xml,$(dist_prefix)/$(path)/transform.xml) + +$(dist): $(dist-common) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) + $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/evolution/ignore/transform-v2.xsd b/examples/cxx/hybrid/evolution/ignore/transform-v2.xsd new file mode 100644 index 0000000..d9ceaec --- /dev/null +++ b/examples/cxx/hybrid/evolution/ignore/transform-v2.xsd @@ -0,0 +1,93 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/evolution/ignore/transform-v2.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tf="http://www.codesynthesis.com/transform" + targetNamespace="http://www.codesynthesis.com/transform" + elementFormDefault="qualified"> + + <xsd:complexType name="transformation_type" abstract="true"> + <xsd:sequence> + <xsd:element name="description" type="xsd:string"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + + <xsd:element name="transformation" type="tf:transformation_type"/> + + <!-- Document root. --> + + <xsd:complexType name="transformations_type"> + <xsd:sequence> + <xsd:element ref="tf:transformation" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="transformations" type="tf:transformations_type"/> + + <!-- Move. --> + + <xsd:complexType name="move_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="x" type="xsd:float"/> + <xsd:element name="y" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="move-transformation" + type="tf:move_type" + substitutionGroup="tf:transformation"/> + + <!-- Rotate. --> + + <xsd:complexType name="rotate_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="angle" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="rotate-transformation" + type="tf:rotate_type" + substitutionGroup="tf:transformation"/> + + <!-- Scale. --> + + <xsd:complexType name="ratio_type"> + <xsd:sequence> + <xsd:element name="x" type="xsd:float"/> + <xsd:element name="y" type="xsd:float"/> + </xsd:sequence> + <xsd:attribute name="unit" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="scale_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="ratios" type="tf:ratio_type"/> + </xsd:sequence> + <xsd:attribute name="proportional" type="xsd:boolean"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="scale-transformation" + type="tf:scale_type" + substitutionGroup="tf:transformation"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/evolution/ignore/transform.xml b/examples/cxx/hybrid/evolution/ignore/transform.xml new file mode 100644 index 0000000..d7e8cef --- /dev/null +++ b/examples/cxx/hybrid/evolution/ignore/transform.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/evolution/ignore/transform.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<transformations xmlns="http://www.codesynthesis.com/transform"> + + <move-transformation name="move"> + <description>Move an object.</description> + <x>1.1</x> + <y>2.1</y> + </move-transformation> + + <rotate-transformation name="rotate"> + <description>Rotate an object.</description> + <angle>90</angle> + </rotate-transformation> + + <scale-transformation name="scale" proportional="true"> + <description>Scale an object.</description> + <ratios unit="percent"> + <x>210</x> + <y>210</y> + </ratios> + </scale-transformation> + +</transformations> diff --git a/examples/cxx/hybrid/evolution/ignore/transform.xsd b/examples/cxx/hybrid/evolution/ignore/transform.xsd new file mode 100644 index 0000000..59cf48f --- /dev/null +++ b/examples/cxx/hybrid/evolution/ignore/transform.xsd @@ -0,0 +1,69 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/evolution/ignore/transform.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tf="http://www.codesynthesis.com/transform" + targetNamespace="http://www.codesynthesis.com/transform" + elementFormDefault="qualified"> + + <xsd:complexType name="transformation_type" abstract="true"> + <xsd:sequence> + <xsd:element name="description" type="xsd:string"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + + <xsd:element name="transformation" type="tf:transformation_type"/> + + <!-- Document root. --> + + <xsd:complexType name="transformations_type"> + <xsd:sequence> + <xsd:element ref="tf:transformation" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="transformations" type="tf:transformations_type"/> + + <!-- Move. --> + + <xsd:complexType name="move_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="x" type="xsd:float"/> + <xsd:element name="y" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="move-transformation" + type="tf:move_type" + substitutionGroup="tf:transformation"/> + + <!-- Rotate. --> + + <xsd:complexType name="rotate_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="angle" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="rotate-transformation" + type="tf:rotate_type" + substitutionGroup="tf:transformation"/> + + +</xsd:schema> diff --git a/examples/cxx/hybrid/evolution/makefile b/examples/cxx/hybrid/evolution/makefile new file mode 100644 index 0000000..79f1873 --- /dev/null +++ b/examples/cxx/hybrid/evolution/makefile @@ -0,0 +1,45 @@ +# file : examples/cxx/hybrid/evolution/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +all_examples := ignore passthrough +build_examples := + +ifeq ($(xsde_iostream),y) +ifeq ($(xsde_exceptions),y) + +ifeq ($(xsde_stl),y) +build_examples += ignore passthrough +endif + +endif +endif + +default := $(out_base)/ +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean := $(out_base)/.clean + +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples))) +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples))) + +# Dist. +# +$(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base)) + +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples))) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples))) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) + $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt) + + +ifneq ($(filter $(MAKECMDGOALS),dist dist-win),) +$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile)) +else +$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile)) +endif diff --git a/examples/cxx/hybrid/evolution/passthrough/README b/examples/cxx/hybrid/evolution/passthrough/README new file mode 100644 index 0000000..a4a3803 --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/README @@ -0,0 +1,104 @@ +This example shows how to handle schema evolution using substitution groups. +The general idea is as follows: the initial version of the schema defines +extension points using the XML Schema substitution group mechanism. The +subsequent versions of the schema add new elements to the substitution +groups. The goal here is for applications that were built using earlier +versions of the schema to be able to handle documents corresponding to the +newer versions without validation errors or any other failures. This example +shows how to pass the unknown content through parsing and serialization so +that the output XML contains all the unknown elements. The 'ignore' example +shows how to ignore such unknown elements. + +This example uses XML Schema polymorphism in the form of substitution groups. +If you are not familiar with how to work with polymorphic object models, +refer to the C++/Hybrid Mapping Getting Started Guide as well as the +'polymorphism' example in the examples/cxx/hybrid/ directory. + +This example also customizes a generated object model type as well as parser +and serializer implementations. If you are not familiar with the customization +mechanisms, refer to the C++/Hybrid Mapping Getting Started Guide as well as +the examples in the examples/cxx/hybrid/custom/ directory. + +The example consists of the following files: + +transform.xsd + The initial version of the schema that describes simple transformations, + such as move and rotate. The schema makes it possible to add new + transformations in subsequent versions of the schema. It also defines a + special unknown_type type which is used to handle unknown transformations. + Our example is built using this schema. + +transform-v2.xsd + The second version of the schema which adds the scale transformation. This + schema is provided as an example. + +transform.xml + Sample XML document corresponding to the second version of the schema. In + particular, it contains the scale transformation which is unknown in + transform.xsd. + +transform.hxx +transform.cxx + +transform-pskel.hxx +transform-pskel.cxx +transform-pimpl.hxx +transform-pimpl.cxx + +transform-sskel.hxx +transform-sskel.cxx +transform-simpl.hxx +transform-simpl.cxx + Object model (the first pair of files), parser skeletons (the second pair), + parser implementations (the third pair), serializer skeletons (the fourth + pair), and serializer implementations (the fifth pair). These files are + generated by the XSD/e compiler from transform.xsd. The --generate-parser, + --generate-serializer, and --generate-aggregate options were used to request + the generation of the parsing and serialization code. The + --generate-polymorphic option was used to request the generation of the + polymorphism-aware code. The --custom-type, --custom-parser, and + --custom-serializer options were used to customize the object model class + as well as the parser and serializer implementations for the unknown_type + XML Schema type. + +xml.hxx +xml.ixx +xml.cxx + Simple in-memory representation for raw XML. It is used to store the content + of unknown transformations. + +unknown-type.hxx +unknown-type.cxx + Custom unknown_type class. It uses the generated version as a base and adds + members that store the raw XML representation of an unknown transformation + as well as the parsed element name and namespace from the substitution group. + +unknown-type-pimpl.hxx +unknown-type-pimpl.cxx + Custom unknown_type parser implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the raw XML + callbacks to parse the unknown content and store it in the customized + unknown_type class. + +unknown-type-simpl.hxx +unknown-type-simpl.cxx + Custom unknown_type serializer implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the raw XML + callbacks to serialize the unknown content stored in the customized + unknown_type class. + +driver.cxx + Driver for the example. It first sets the substitution map callbacks that + are used to alter the default element mapping in the parser and serializer. + The driver then calls the parser that constructs the object model from the + input XML file. It then prints the content of the object model to STDERR. + Finally, the driver calls the serializer to serialize the object model + back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver transform.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <transform.xml diff --git a/examples/cxx/hybrid/evolution/passthrough/driver.cxx b/examples/cxx/hybrid/evolution/passthrough/driver.cxx new file mode 100644 index 0000000..35a334c --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/driver.cxx @@ -0,0 +1,193 @@ +// file : examples/cxx/hybrid/evolution/passthrough/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <string> +#include <iostream> + +#include "transform.hxx" +#include "transform-pimpl.hxx" +#include "transform-simpl.hxx" + +using namespace std; +using namespace transform; + +// Parser substitution map callback. This callback is called when the +// parser needs to check whether an element belongs to a substitution +// group. We use this callback to handle unknown transformations. +// +static bool +parser_callback (const xml_schema::ro_string& root_ns, + const xml_schema::ro_string& root_name, + const xml_schema::ro_string& /*member_ns*/, + const xml_schema::ro_string& member_name, + const char*& type) +{ + // Check that the root of the substitution group is 'transformation'. + // + if (root_name == "transformation" && + root_ns == "http://www.codesynthesis.com/transform") + { + // Check that the element's name has the '-transformation' suffix. This + // is the convention we use in our schema to minimize the chance of + // treating any unknown elements as a transformation. + // + // + string s ("-transformation"); + string n (member_name); + + if (n.size () > s.size () && + string (n, n.size () - s.size (), s.size ()) == s) + { + // Tell the parser to use unknown_type to parse this element. + // + type = unknown_type_pimpl::_static_type (); + return true; + } + } + + return false; +} + +// Serializer substitution map callback. This callback is called when +// the serializer needs to map a type to an element belonging to a +// substitution group. We use this callback to handle unknown +// transformations. +// +static bool +serializer_callback (const char* type, + const void* obj, + const char*& ns, + const char*& name) +{ + // Check whether this is unknown_type. + // + if (string (type) == unknown_type_simpl::_static_type ()) + { + // Cast the opaque obj pointer to unknown_type. + // + const unknown_type* u = reinterpret_cast<const unknown_type*> (obj); + + // Extract the actual element name from the object. + // + const xml::qname& n (u->element_name ()); + ns = n.ns ().c_str (); + name = n.name ().c_str (); + + return true; + } + + return false; +} + +int +main (int argc, char* argv[]) +{ + const char* input; + + if (argc < 2) + { + input = "STDIN"; + cerr << "XML file not specified, reading from STDIN" << endl; + } + else + input = argv[1]; + + try + { + // Set the substitution map callbacks. + // + xml_schema::parser_smap_callback (&parser_callback); + xml_schema::serializer_smap_callback (&serializer_callback); + + // Parse. + // + transformations_paggr transformations_p; + + // The last argument to the document's constructor indicates that we + // are parsing polymorphic XML documents. + // + xml_schema::document_pimpl doc_p ( + transformations_p.root_parser (), + transformations_p.root_namespace (), + transformations_p.root_name (), + true); + + transformations_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr<transformations_type> tf (transformations_p.post ()); + + // Print what we've got. + // + for (transformations_type::transformation_iterator i = + tf->transformation ().begin (); + i != tf->transformation ().end (); + ++i) + { + transformation_type& t = *i; + + if (move_type* m = dynamic_cast<move_type*> (&t)) + { + cout << m->name () << ": " << m->description () << endl + << "\tx: " << m->x () << endl + << "\ty: " << m->y () << endl + << endl; + } + else if (rotate_type* r = dynamic_cast<rotate_type*> (&t)) + { + cout << r->name () << ": " << r->description () << endl + << "\tangle: " << r->angle () << endl + << endl; + } + else if (unknown_type* u = dynamic_cast<unknown_type*> (&t)) + { + cout << u->name () << ": " << u->description () << endl + << "\ttransformation is unknown" << endl + << endl; + } + } + + // Serialize. + // + transformations_saggr transformations_s; + + // The last argument to the document's constructor indicates that we + // are serializing polymorphic XML documents. + // + xml_schema::document_simpl doc_s ( + transformations_s.root_serializer (), + transformations_s.root_namespace (), + transformations_s.root_name (), + true); + + doc_s.add_prefix ("", "http://www.codesynthesis.com/transform"); + + transformations_s.pre (*tf); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + transformations_s.post (); + } + catch (const xml_schema::parser_exception& e) + { + cerr << input << ":" << e.line () << ":" << e.column () << ": " + << e.text () << endl; + return 1; + } + catch (const xml_schema::serializer_exception& e) + { + cerr << "error: " << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << input << ": unable to open or read/write failure" << endl; + return 1; + } + + return 0; +} diff --git a/examples/cxx/hybrid/evolution/passthrough/makefile b/examples/cxx/hybrid/evolution/passthrough/makefile new file mode 100644 index 0000000..1f31f5c --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/makefile @@ -0,0 +1,120 @@ +# file : examples/cxx/hybrid/evolution/passthrough/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := transform.xsd +cxx := driver.cxx xml.cxx unknown-type.cxx unknown-type-pimpl.cxx \ +unknown-type-simpl.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \ + $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \ + $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) \ + $(xsd:.xsd=-sskel.hxx) $(xsd:.xsd=-sskel.cxx) \ + $(xsd:.xsd=-simpl.hxx) $(xsd:.xsd=-simpl.cxx) + +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate --root-element transformations --generate-polymorphic \ +--custom-type unknown_type=//unknown_type_base/unknown-type.hxx \ +--custom-parser unknown_type=unknown_type_base_pimpl/unknown-type-pimpl.hxx \ +--custom-serializer unknown_type=unknown_type_base_simpl/unknown-type-simpl.hxx + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Dist. +# +dist-common := $(out_base)/.dist-common +$(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(dist-common): + $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) + $(call install-data,$(src_base)/xml.hxx,$(dist_prefix)/$(path)/xml.hxx) + $(call install-data,$(src_base)/xml.ixx,$(dist_prefix)/$(path)/xml.ixx) + $(call install-data,$(src_base)/xml.cxx,$(dist_prefix)/$(path)/xml.cxx) + $(call install-data,$(src_base)/unknown-type.hxx,$(dist_prefix)/$(path)/unknown-type.hxx) + $(call install-data,$(src_base)/unknown-type.cxx,$(dist_prefix)/$(path)/unknown-type.cxx) + $(call install-data,$(src_base)/unknown-type-pimpl.hxx,$(dist_prefix)/$(path)/unknown-type-pimpl.hxx) + $(call install-data,$(src_base)/unknown-type-pimpl.cxx,$(dist_prefix)/$(path)/unknown-type-pimpl.cxx) + $(call install-data,$(src_base)/unknown-type-simpl.hxx,$(dist_prefix)/$(path)/unknown-type-simpl.hxx) + $(call install-data,$(src_base)/unknown-type-simpl.cxx,$(dist_prefix)/$(path)/unknown-type-simpl.cxx) + $(call install-data,$(src_base)/transform.xsd,$(dist_prefix)/$(path)/transform.xsd) + $(call install-data,$(src_base)/transform-v2.xsd,$(dist_prefix)/$(path)/transform-v2.xsd) + $(call install-data,$(src_base)/transform.xml,$(dist_prefix)/$(path)/transform.xml) + +$(dist): $(dist-common) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) + $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd b/examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd new file mode 100644 index 0000000..72cc12c --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd @@ -0,0 +1,103 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tf="http://www.codesynthesis.com/transform" + targetNamespace="http://www.codesynthesis.com/transform" + elementFormDefault="qualified"> + + <xsd:complexType name="transformation_type" abstract="true"> + <xsd:sequence> + <xsd:element name="description" type="xsd:string"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + + <xsd:element name="transformation" type="tf:transformation_type"/> + + <!-- Document root. --> + + <xsd:complexType name="transformations_type"> + <xsd:sequence> + <xsd:element ref="tf:transformation" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="transformations" type="tf:transformations_type"/> + + <!-- Special type for unknown transformations. --> + + <xsd:complexType name="unknown_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + + <!-- Move. --> + + <xsd:complexType name="move_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="x" type="xsd:float"/> + <xsd:element name="y" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="move-transformation" + type="tf:move_type" + substitutionGroup="tf:transformation"/> + + <!-- Rotate. --> + + <xsd:complexType name="rotate_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="angle" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="rotate-transformation" + type="tf:rotate_type" + substitutionGroup="tf:transformation"/> + + <!-- Scale. --> + + <xsd:complexType name="ratio_type"> + <xsd:sequence> + <xsd:element name="x" type="xsd:float"/> + <xsd:element name="y" type="xsd:float"/> + </xsd:sequence> + <xsd:attribute name="unit" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="scale_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="ratios" type="tf:ratio_type"/> + </xsd:sequence> + <xsd:attribute name="proportional" type="xsd:boolean"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="scale-transformation" + type="tf:scale_type" + substitutionGroup="tf:transformation"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/evolution/passthrough/transform.xml b/examples/cxx/hybrid/evolution/passthrough/transform.xml new file mode 100644 index 0000000..6747e3e --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/transform.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/evolution/passthrough/transform.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<transformations xmlns="http://www.codesynthesis.com/transform"> + + <move-transformation name="move"> + <description>Move an object.</description> + <x>1.1</x> + <y>2.1</y> + </move-transformation> + + <rotate-transformation name="rotate"> + <description>Rotate an object.</description> + <angle>90</angle> + </rotate-transformation> + + <scale-transformation name="scale" proportional="true"> + <description>Scale an object.</description> + <ratios unit="percent"> + <x>210</x> + <y>210</y> + </ratios> + </scale-transformation> + +</transformations> diff --git a/examples/cxx/hybrid/evolution/passthrough/transform.xsd b/examples/cxx/hybrid/evolution/passthrough/transform.xsd new file mode 100644 index 0000000..2400de1 --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/transform.xsd @@ -0,0 +1,79 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/evolution/passthrough/transform.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tf="http://www.codesynthesis.com/transform" + targetNamespace="http://www.codesynthesis.com/transform" + elementFormDefault="qualified"> + + <xsd:complexType name="transformation_type" abstract="true"> + <xsd:sequence> + <xsd:element name="description" type="xsd:string"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + + <xsd:element name="transformation" type="tf:transformation_type"/> + + <!-- Document root. --> + + <xsd:complexType name="transformations_type"> + <xsd:sequence> + <xsd:element ref="tf:transformation" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="transformations" type="tf:transformations_type"/> + + <!-- Special type for unknown transformations. --> + + <xsd:complexType name="unknown_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + + <!-- Move. --> + + <xsd:complexType name="move_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="x" type="xsd:float"/> + <xsd:element name="y" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="move-transformation" + type="tf:move_type" + substitutionGroup="tf:transformation"/> + + <!-- Rotate. --> + + <xsd:complexType name="rotate_type"> + <xsd:complexContent> + <xsd:extension base="tf:transformation_type"> + <xsd:sequence> + <xsd:element name="angle" type="xsd:float"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="rotate-transformation" + type="tf:rotate_type" + substitutionGroup="tf:transformation"/> + + +</xsd:schema> diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx new file mode 100644 index 0000000..31da98e --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx @@ -0,0 +1,142 @@ +// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr + +// Include transform-pimpl.hxx (which includes unknown-type-pimpl.hxx) +// instead of unknown-type-pimpl.hxx. +// +#include "transform-pimpl.hxx" + +namespace transform +{ + void unknown_type_pimpl:: + _pre () + { + unknown_type_base_pimpl::_pre (); + + // Set the element name and namespace. + // + unknown_type* obj = unknown_type_base_pimpl_state_.unknown_type_; + + obj->element_name ( + xml::qname (_context ().element_namespace (), + _context ().element_name ())); + + // Initialize the current element. + // + cur_ = &obj->content (); + } + + void unknown_type_pimpl:: + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char*) + { + // Create a new child element and add it to cur_. + // + std::auto_ptr<xml::element> e ( + new xml::element (xml::qname (ns, name), cur_)); + + cur_->children ().push_back (e.get ()); + cur_ = e.get (); + e.release (); + } + + void unknown_type_pimpl:: + _end_any_element (const xml_schema::ro_string&, + const xml_schema::ro_string&) + { + // Make the parent of cur_ the new cur_. + // + cur_ = cur_->parent (); + } + + void unknown_type_pimpl:: + _any_attribute (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const xml_schema::ro_string& value) + { + // Add a new attribute to cur_. + // + cur_->attributes ()[xml::qname (ns, name)] = value; + } + + void unknown_type_pimpl:: + _any_characters (const xml_schema::ro_string& s) + { + // Set the character value of cur_. + // + cur_->value (s); + } + + // + // Low-level content callbacks. + // + + void unknown_type_pimpl:: + _start_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char* type) + { + // If this is one of the elements from transformation_type, then + // delegate it to our base. Otherwise, forward it to the wildcard + // callback. + // + if (name == "description" && + ns == "http://www.codesynthesis.com/transform") + { + unknown_type_base_pimpl::_start_element (ns, name, type); + } + else + { + _context ().start_wildcard_content (); + _start_any_element (ns, name, type); + } + } + + + void unknown_type_pimpl:: + _end_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name) + { + // If this is one of the elements from transformation_type, then + // delegate it to our base. Otherwise, forward it to the wildcard + // callback. + // + if (name == "description" && + ns == "http://www.codesynthesis.com/transform") + { + unknown_type_base_pimpl::_end_element (ns, name); + } + else + _end_any_element (ns, name); + } + + void unknown_type_pimpl:: + _attribute (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const xml_schema::ro_string& value) + { + // If this is one of the elements from transformation_type, then + // delegate it to our base. Otherwise, forward it to the wildcard + // callback. + // + if (name == "name" && ns.empty ()) + { + unknown_type_base_pimpl::_attribute (ns, name, value); + } + else + _any_attribute (ns, name, value); + } + + void unknown_type_pimpl:: + _characters (const xml_schema::ro_string& s) + { + // transformation_type has no character content so forward this + // straight to the wildcard callback. + // + _any_characters (s); + } +} diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx new file mode 100644 index 0000000..1956e2c --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx @@ -0,0 +1,66 @@ +// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef UNKNOWN_TYPE_PIMPL_HXX +#define UNKNOWN_TYPE_PIMPL_HXX + +namespace transform +{ + // Customized unknown_type parser implementation. + // + class unknown_type_pimpl: public unknown_type_base_pimpl + { + public: + virtual void + _pre (); + + // Wildcard content callbacks. All the unknown content is routed + // to these functions. We use them to construct the raw XML + // representation of the unknown transformation. + // + virtual void + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char* type); + + virtual void + _end_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name); + + virtual void + _any_attribute (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const xml_schema::ro_string& value); + + virtual void + _any_characters (const xml_schema::ro_string&); + + // Low-level content callbacks. These are normally implemented by + // the generated parsers. However, we need to intercept them and + // re-route the known elements and attributes to the base parser + // and the unknown content to the wildcard callbacks above. + // + virtual void + _start_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char* type); + + virtual void + _end_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name); + + virtual void + _attribute (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const xml_schema::ro_string& value); + + virtual void + _characters (const xml_schema::ro_string&); + + private: + xml::element* cur_; + }; +} + +#endif // UNKNOWN_TYPE_PIMPL_HXX diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx new file mode 100644 index 0000000..142c1ee --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx @@ -0,0 +1,80 @@ +// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +// Include transform-simpl.hxx (which includes unknown-type-simpl.hxx) +// instead of unknown-type-simpl.hxx. +// +#include "transform-simpl.hxx" + +namespace transform +{ + void unknown_type_simpl:: + _serialize_attributes () + { + // Allow the base to serialize its attributes. + // + unknown_type_base_simpl::_serialize_attributes (); + + // Serialize attributes from the unknown content. + // + const xml::element& e = + unknown_type_base_simpl_state_.unknown_type_->content (); + + serialize (e.attributes ()); + } + + void unknown_type_simpl:: + _serialize_content () + { + // Allow the base to serialize its elements. + // + unknown_type_base_simpl::_serialize_content (); + + // Serialize elements from the unknown content. + // + const xml::element& e = + unknown_type_base_simpl_state_.unknown_type_->content (); + + serialize (e.children ()); + } + + void unknown_type_simpl:: + serialize (const xml::attributes& as) + { + for (xml::attributes::const_iterator i (as.begin ()); i != as.end (); ++i) + { + const xml::qname& n = i->first; + const std::string& v = i->second; + + if (n.ns ().empty ()) + _attribute (n.name ().c_str (), v.c_str ()); + else + _attribute (n.ns ().c_str (), n.name ().c_str (), v.c_str ()); + } + } + + void unknown_type_simpl:: + serialize (const xml::elements& es) + { + for (xml::elements::const_iterator i (es.begin ()); i != es.end (); ++i) + { + const xml::element& e = **i; + const xml::qname& n = e.name (); + + if (n.ns ().empty ()) + _start_element (n.name ().c_str ()); + else + _start_element (n.ns ().c_str (), n.name ().c_str ()); + + serialize (e.attributes ()); + + if (!e.children ().empty ()) + serialize (e.children ()); + else if (!e.value ().empty ()) + _characters (e.value ().c_str ()); + + _end_element (); + } + } +} diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx new file mode 100644 index 0000000..c2cabf7 --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx @@ -0,0 +1,34 @@ +// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef UNKNOWN_TYPE_SIMPL_HXX +#define UNKNOWN_TYPE_SIMPL_HXX + +namespace transform +{ + // Customized unknown_type serializer implementation. + // + class unknown_type_simpl: public unknown_type_base_simpl + { + public: + // Low-level raw XML serialization callbacks. + // + virtual void + _serialize_attributes (); + + virtual void + _serialize_content (); + + // Helper functions. + // + private: + void + serialize (const xml::attributes&); + + void + serialize (const xml::elements&); + }; +} + +#endif // UNKNOWN_TYPE_SIMPL_HXX diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx new file mode 100644 index 0000000..ba3a9f4 --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx @@ -0,0 +1,17 @@ +// file : examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +// Include transform.hxx (which includes unknown-type.hxx) instead of +// unknown-type.hxx. +// +#include "transform.hxx" + +namespace transform +{ + unknown_type:: + unknown_type () + : name_ ("unknown"), content_ ("unknown", 0) // Dummy names. + { + } +} diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx new file mode 100644 index 0000000..c3e544c --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx @@ -0,0 +1,51 @@ +// file : examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef UNKNOWN_TYPE_HXX +#define UNKNOWN_TYPE_HXX + +#include "xml.hxx" + +namespace transform +{ + // Customized unknown_type. We add members that store the raw XML + // representation of an unknown transformation as well as the parsed + // element name and namespace from the substitution group. + // + class unknown_type: public unknown_type_base + { + public: + unknown_type (); + + const xml::qname& + element_name () const + { + return name_; + } + + void + element_name (const xml::qname& n) + { + name_ = n; + } + + const xml::element& + content () const + { + return content_; + } + + xml::element& + content () + { + return content_; + } + + private: + xml::qname name_; + xml::element content_; + }; +} + +#endif // UNKNOWN_TYPE_HXX diff --git a/examples/cxx/hybrid/evolution/passthrough/xml.cxx b/examples/cxx/hybrid/evolution/passthrough/xml.cxx new file mode 100644 index 0000000..d60ba81 --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/xml.cxx @@ -0,0 +1,19 @@ +// file : examples/cxx/hybrid/evolution/passthrough/xml.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "xml.hxx" + +namespace xml +{ + element:: + ~element () + { + for (elements::iterator i = children_.begin (); + i != children_.end (); + ++i) + { + delete *i; + } + } +} diff --git a/examples/cxx/hybrid/evolution/passthrough/xml.hxx b/examples/cxx/hybrid/evolution/passthrough/xml.hxx new file mode 100644 index 0000000..fbcae6e --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/xml.hxx @@ -0,0 +1,111 @@ +// file : examples/cxx/hybrid/evolution/passthrough/xml.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +// +// In-memory representation for raw XML. The primary goal here is to provide +// a simple, if not very efficient, implementation. As a result, it probably +// shouldn't be used in production, especially if performance is important. +// It also does not support mixed content (interleaved elements and text). +// + +#ifndef XML_HXX +#define XML_HXX + +#include <map> +#include <vector> +#include <string> + +namespace xml +{ + // Qualified name. + // + class qname + { + public: + qname (const char* name); + qname (const std::string& name); + qname (const std::string& ns, const std::string& name); + + const std::string& + ns () const; + + const std::string& + name () const; + + private: + std::string ns_; + std::string name_; + }; + + bool + operator== (const qname&, const qname&); + + bool + operator!= (const qname&, const qname&); + + bool + operator< (const qname&, const qname&); + + // Attribute. + // + typedef std::map<qname, std::string> attributes; + + // Element. + // + class element; + typedef std::vector<element*> elements; + + class element + { + public: + ~element (); + element (const qname& name, element* parent); + element (const qname& name, const std::string value, element* parent); + + private: + element (const element&); + element& operator= (const element&); + + public: + const qname& + name () const; + + const element* + parent () const; + + element* + parent (); + + typedef xml::attributes attributes_type; + + const attributes_type& + attributes () const; + + attributes_type& + attributes (); + + const std::string& + value () const; + + void + value (const std::string&); + + const elements& + children () const; + + elements& + children (); + + private: + qname name_; + element* parent_; + attributes_type attributes_; + std::string value_; + elements children_; + }; +} + +#include "xml.ixx" + +#endif // XML_HXX diff --git a/examples/cxx/hybrid/evolution/passthrough/xml.ixx b/examples/cxx/hybrid/evolution/passthrough/xml.ixx new file mode 100644 index 0000000..52fb999 --- /dev/null +++ b/examples/cxx/hybrid/evolution/passthrough/xml.ixx @@ -0,0 +1,129 @@ +// file : examples/cxx/hybrid/evolution/passthrough/xml.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +namespace xml +{ + // + // qname + // + + inline qname:: + qname (const char* name) + : name_ (name) + { + } + + inline qname:: + qname (const std::string& name) + : name_ (name) + { + } + + inline qname:: + qname (const std::string& ns, const std::string& name) + : ns_ (ns), name_ (name) + { + } + + inline const std::string& qname:: + ns () const + { + return ns_; + } + + inline const std::string& qname:: + name () const + { + return name_; + } + + inline bool + operator== (const qname& x, const qname& y) + { + return x.name () == y.name () && x.ns () == y.ns (); + } + + inline bool + operator!= (const qname& x, const qname& y) + { + return !(x == y); + } + + inline bool + operator< (const qname& x, const qname& y) + { + int r (x.name ().compare (y.name ())); + return (r < 0) || (r == 0 && x.ns () < y.ns ()); + } + + // + // element + // + + inline element:: + element (const qname& name, element* parent) + : name_ (name), parent_ (parent) + { + } + + inline element:: + element (const qname& name, const std::string value, element* parent) + : name_ (name), parent_ (parent), value_ (value) + { + } + + inline const qname& element:: + name () const + { + return name_; + } + + inline const element* element:: + parent () const + { + return parent_; + } + + inline element* element:: + parent () + { + return parent_; + } + + inline const element::attributes_type& element:: + attributes () const + { + return attributes_; + } + + inline element::attributes_type& element:: + attributes () + { + return attributes_; + } + + inline const std::string& element:: + value () const + { + return value_; + } + + inline void element:: + value (const std::string& value) + { + value_ = value; + } + + inline const elements& element:: + children () const + { + return children_; + } + + inline elements& element:: + children () + { + return children_; + } +} diff --git a/examples/cxx/hybrid/makefile b/examples/cxx/hybrid/makefile index 8bdb2de..f54f56b 100644 --- a/examples/cxx/hybrid/makefile +++ b/examples/cxx/hybrid/makefile @@ -10,6 +10,7 @@ allocator \ binary \ compositors \ custom \ +evolution \ hello \ multiroot \ polymorphism \ @@ -20,7 +21,7 @@ wildcard \ filter \ minimal -build_examples := binary compositors custom +build_examples := binary compositors custom evolution ifeq ($(xsde_iostream),y) ifeq ($(xsde_exceptions),y) diff --git a/libxsde/xsde/cxx/hybrid/any-type-pskel.cxx b/libxsde/xsde/cxx/hybrid/any-type-pskel.cxx index d8434b2..bb5bb7f 100644 --- a/libxsde/xsde/cxx/hybrid/any-type-pskel.cxx +++ b/libxsde/xsde/cxx/hybrid/any-type-pskel.cxx @@ -13,15 +13,16 @@ namespace xsde { #ifdef XSDE_POLYMORPHIC bool any_type_pskel:: - _start_element_impl (const ro_string& ns, - const ro_string& name, - const char* type) + _start_element_impl ( +#ifdef XSDE_PARSER_VALIDATION + const ro_string& ns, const ro_string& name, const char* type +#else + const ro_string&, const ro_string&, const char* +#endif + ) { #ifdef XSDE_PARSER_VALIDATION - parser::context& ctx = _context (); - ctx.current_.any_ = true; - ctx.current_.depth_++; - + _context ().start_wildcard_content (); _start_any_element (ns, name, type); return true; #else @@ -30,13 +31,16 @@ namespace xsde } #else bool any_type_pskel:: - _start_element_impl (const ro_string& ns, const ro_string& name) + _start_element_impl ( +#ifdef XSDE_PARSER_VALIDATION + const ro_string& ns, const ro_string& name +#else + const ro_string&, const ro_string& +#endif + ) { #ifdef XSDE_PARSER_VALIDATION - parser::context& ctx = _context (); - ctx.current_.any_ = true; - ctx.current_.depth_++; - + _context ().start_wildcard_content (); _start_any_element (ns, name); return true; #else @@ -46,7 +50,13 @@ namespace xsde #endif bool any_type_pskel:: - _end_element_impl (const ro_string& ns, const ro_string& name) + _end_element_impl ( +#ifdef XSDE_PARSER_VALIDATION + const ro_string& ns, const ro_string& name +#else + const ro_string&, const ro_string& +#endif + ) { #ifdef XSDE_PARSER_VALIDATION _end_any_element (ns, name); @@ -76,7 +86,13 @@ namespace xsde #endif bool any_type_pskel:: - _characters_impl (const ro_string& s) + _characters_impl ( +#ifdef XSDE_PARSER_VALIDATION + const ro_string& s +#else + const ro_string& +#endif + ) { #ifdef XSDE_PARSER_VALIDATION _any_characters (s); diff --git a/libxsde/xsde/cxx/hybrid/parser-map.cxx b/libxsde/xsde/cxx/hybrid/parser-map.cxx index ae67b94..33b0a53 100644 --- a/libxsde/xsde/cxx/hybrid/parser-map.cxx +++ b/libxsde/xsde/cxx/hybrid/parser-map.cxx @@ -21,23 +21,26 @@ namespace xsde if (size_ == 0) return 0; + int r (1); + size_t m; size_t l = 0; size_t h = size_ - 1; while (l <= h) { - size_t m = l + (h - l)/2; - int r = strcmp (entries_[m].type_id, tid); + m = l + (h - l)/2; + r = strcmp (entries_[m].type_id, tid); - if (r > 0) - h = m - 1; - else if (r < 0) + if (r == 0 || l == h) + break; + + if (r < 0) l = m + 1; else - return entries_[m].parser; + h = (m == 0 ? 0 : m - 1); } - return 0; + return r == 0 ? entries_[m].parser : 0; } void parser_map_impl:: diff --git a/libxsde/xsde/cxx/hybrid/serializer-map.cxx b/libxsde/xsde/cxx/hybrid/serializer-map.cxx index d20f8d1..be32cc4 100644 --- a/libxsde/xsde/cxx/hybrid/serializer-map.cxx +++ b/libxsde/xsde/cxx/hybrid/serializer-map.cxx @@ -23,23 +23,26 @@ namespace xsde if (size_ == 0) return 0; + int r (1); + size_t m; size_t l = 0; size_t h = size_ - 1; while (l <= h) { - size_t m = l + (h - l)/2; - int r = strcmp (entries_[m].type_id, tid); + m = l + (h - l)/2; + r = strcmp (entries_[m].type_id, tid); - if (r > 0) - h = m - 1; - else if (r < 0) + if (r == 0 || l == h) + break; + + if (r < 0) l = m + 1; else - return entries_[m].serializer; + h = (m == 0 ? 0 : m - 1); } - return 0; + return r == 0 ? entries_[m].serializer : 0; } void serializer_map_impl:: diff --git a/libxsde/xsde/cxx/parser/context.hxx b/libxsde/xsde/cxx/parser/context.hxx index 6019f34..34ded3e 100644 --- a/libxsde/xsde/cxx/parser/context.hxx +++ b/libxsde/xsde/cxx/parser/context.hxx @@ -140,6 +140,9 @@ namespace xsde public: void + start_wildcard_content (); + + void reset (XML_Parser); void diff --git a/libxsde/xsde/cxx/parser/context.ixx b/libxsde/xsde/cxx/parser/context.ixx index b3828f5..5e38ae2 100644 --- a/libxsde/xsde/cxx/parser/context.ixx +++ b/libxsde/xsde/cxx/parser/context.ixx @@ -47,6 +47,13 @@ namespace xsde } inline void context:: + start_wildcard_content () + { + current_.any_ = true; + current_.depth_++; + } + + inline void context:: reset (XML_Parser parser) { xml_parser_ = parser; diff --git a/libxsde/xsde/cxx/parser/non-validating/parser.cxx b/libxsde/xsde/cxx/parser/non-validating/parser.cxx index aec43e0..1bd20a5 100644 --- a/libxsde/xsde/cxx/parser/non-validating/parser.cxx +++ b/libxsde/xsde/cxx/parser/non-validating/parser.cxx @@ -195,11 +195,7 @@ namespace xsde { if (!_start_element_impl (ns, name, type)) { - context& c = _context (); - - c.current_.any_ = true; - c.current_.depth_++; - + _context ().start_wildcard_content (); _start_any_element (ns, name, type); } } @@ -210,11 +206,7 @@ namespace xsde { if (!_start_element_impl (ns, name)) { - context& c = _context (); - - c.current_.any_ = true; - c.current_.depth_++; - + _context ().start_wildcard_content (); _start_any_element (ns, name); } } diff --git a/libxsde/xsde/cxx/parser/substitution-map-callback.hxx b/libxsde/xsde/cxx/parser/substitution-map-callback.hxx new file mode 100644 index 0000000..97d22c9 --- /dev/null +++ b/libxsde/xsde/cxx/parser/substitution-map-callback.hxx @@ -0,0 +1,29 @@ +// file : xsde/cxx/parser/substitution-map-callback.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSDE_CXX_PARSER_SUBSTITUTION_MAP_CALLBACK_HXX +#define XSDE_CXX_PARSER_SUBSTITUTION_MAP_CALLBACK_HXX + +#include <xsde/cxx/ro-string.hxx> + +namespace xsde +{ + namespace cxx + { + namespace parser + { + void + parser_smap_callback ( + bool (*callback) ( + const ro_string& root_ns, + const ro_string& root_name, + const ro_string& member_ns, + const ro_string& member_name, + const char*& type)); + } + } +} + +#endif // XSDE_CXX_PARSER_SUBSTITUTION_MAP_CALLBACK_HXX diff --git a/libxsde/xsde/cxx/parser/substitution-map.cxx b/libxsde/xsde/cxx/parser/substitution-map.cxx index 5cbe4a1..d58ac84 100644 --- a/libxsde/xsde/cxx/parser/substitution-map.cxx +++ b/libxsde/xsde/cxx/parser/substitution-map.cxx @@ -5,7 +5,7 @@ #include <xsde/cxx/config.hxx> -#include <string.h> // strlen, strcmp, strncmp +#include <string.h> // strlen, strcmp, strncmp, strchr #ifndef XSDE_EXCEPTIONS # include <assert.h> // assert @@ -17,6 +17,7 @@ #endif #include <xsde/cxx/parser/substitution-map.hxx> +#include <xsde/cxx/parser/substitution-map-callback.hxx> #include <xsde/cxx/parser/substitution-map-load.hxx> namespace xsde @@ -47,6 +48,22 @@ namespace xsde *type = v->type_; } + // Call the callback. + // + if (!r && callback_ != 0) + { + const char* t; + const char* p = strchr (root, ' '); + + ro_string rname (p ? root : 0, p ? p - root : 0); + ro_string rns (p ? p + 1 : root); + + r = callback_ (rns, rname, ns, name, t); + + if (r && type != 0 && *type == 0) + *type = t; + } + return r; } @@ -78,6 +95,20 @@ namespace xsde *type = v->type_; } + // Call the callback. + // + if (!r && callback_ != 0) + { + const char* t; + ro_string rns (root_ns); + ro_string rname (root_name); + + r = callback_ (rns, rname, ns, name, t); + + if (r && type != 0 && *type == 0) + *type = t; + } + return r; } @@ -249,7 +280,21 @@ namespace xsde #endif } + // Callback. // + void + parser_smap_callback ( + bool (*callback) ( + const ro_string& root_ns, + const ro_string& root_name, + const ro_string& member_ns, + const ro_string& member_name, + const char*& type)) + { + substitution_map_instance ().callback (callback); + } + + // Load. // size_t parser_smap_elements () diff --git a/libxsde/xsde/cxx/parser/substitution-map.hxx b/libxsde/xsde/cxx/parser/substitution-map.hxx index a6df80f..1e50c0e 100644 --- a/libxsde/xsde/cxx/parser/substitution-map.hxx +++ b/libxsde/xsde/cxx/parser/substitution-map.hxx @@ -27,6 +27,16 @@ namespace xsde const char* root, const char* type); + typedef bool (*callback_func) ( + const ro_string& root_ns, + const ro_string& root_name, + const ro_string& member_ns, + const ro_string& member_name, + const char*& type); + + void + callback (callback_func); + // Check and have the type set if found. // bool @@ -81,6 +91,9 @@ namespace xsde const value* find_ (const ro_string& member_ns, const ro_string& member_name) const; + + private: + callback_func callback_; }; diff --git a/libxsde/xsde/cxx/parser/substitution-map.ixx b/libxsde/xsde/cxx/parser/substitution-map.ixx index ddd0b4d..995da4e 100644 --- a/libxsde/xsde/cxx/parser/substitution-map.ixx +++ b/libxsde/xsde/cxx/parser/substitution-map.ixx @@ -11,7 +11,7 @@ namespace xsde { inline substitution_map:: substitution_map (size_t buckets) - : hashmap (buckets, sizeof (value)) + : hashmap (buckets, sizeof (value)), callback_ (0) { } @@ -26,6 +26,12 @@ namespace xsde hashmap::insert (member, &v); } + inline void substitution_map:: + callback (callback_func c) + { + callback_ = c; + } + inline bool substitution_map:: check (const ro_string& member_ns, const ro_string& member_name, @@ -33,9 +39,9 @@ namespace xsde const char*& type) const { - return empty () - ? false - : check_ (member_ns, member_name, root, &type); + return !empty () || callback_ != 0 + ? check_ (member_ns, member_name, root, &type) + : false; } inline bool substitution_map:: @@ -45,9 +51,9 @@ namespace xsde const char* root_name, const char*& type) const { - return empty () - ? false - : check_ (member_ns, member_name, root_ns, root_name, &type); + return !empty () || callback_ != 0 + ? check_ (member_ns, member_name, root_ns, root_name, &type) + : false; } inline bool substitution_map:: @@ -56,9 +62,9 @@ namespace xsde const char* root) const { - return empty () - ? false - : check_ (member_ns, member_name, root, 0); + return !empty () || callback_ != 0 + ? check_ (member_ns, member_name, root, 0) + : false; } inline substitution_map& diff --git a/libxsde/xsde/cxx/parser/validating/inheritance-map.cxx b/libxsde/xsde/cxx/parser/validating/inheritance-map.cxx index f23e841..c46ac1f 100644 --- a/libxsde/xsde/cxx/parser/validating/inheritance-map.cxx +++ b/libxsde/xsde/cxx/parser/validating/inheritance-map.cxx @@ -33,6 +33,11 @@ namespace xsde bool inheritance_map:: check (const char* derived, const char* base) const { + // Check for the special match-anything marker. + // + if (derived[0] == '*') + return true; + if (strcmp (derived, base) == 0) return true; diff --git a/libxsde/xsde/cxx/parser/validating/inheritance-map.hxx b/libxsde/xsde/cxx/parser/validating/inheritance-map.hxx index ba8335e..1462fb2 100644 --- a/libxsde/xsde/cxx/parser/validating/inheritance-map.hxx +++ b/libxsde/xsde/cxx/parser/validating/inheritance-map.hxx @@ -60,4 +60,3 @@ namespace xsde #include <xsde/cxx/parser/validating/inheritance-map.ixx> #endif // XSDE_CXX_PARSER_VALIDATING_INHERITANCE_MAP_HXX - diff --git a/libxsde/xsde/cxx/ro-string.ixx b/libxsde/xsde/cxx/ro-string.ixx index cf37c81..6906923 100644 --- a/libxsde/xsde/cxx/ro-string.ixx +++ b/libxsde/xsde/cxx/ro-string.ixx @@ -43,7 +43,7 @@ namespace xsde inline ro_string:: operator std::string () const { - return std::string (data (), size ()); + return size () ? std::string (data (), size ()) : std::string (); } #endif diff --git a/libxsde/xsde/cxx/serializer/genx/document.cxx b/libxsde/xsde/cxx/serializer/genx/document.cxx index 4c634a4..e8cacc0 100644 --- a/libxsde/xsde/cxx/serializer/genx/document.cxx +++ b/libxsde/xsde/cxx/serializer/genx/document.cxx @@ -514,7 +514,7 @@ namespace xsde // Call to check sets ns and n if successful. // if (strcmp (dt, root_static_type_) == 0 || - substitution_map_instance ().check (ns, n, dt)) + substitution_map_instance ().check (ns, n, dt, 0)) dt = 0; } diff --git a/libxsde/xsde/cxx/serializer/substitution-map-callback.hxx b/libxsde/xsde/cxx/serializer/substitution-map-callback.hxx new file mode 100644 index 0000000..c29a00d --- /dev/null +++ b/libxsde/xsde/cxx/serializer/substitution-map-callback.hxx @@ -0,0 +1,26 @@ +// file : xsde/cxx/serializer/substitution-map-callback.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSDE_CXX_SERIALIZER_SUBSTITUTION_MAP_CALLBACK_HXX +#define XSDE_CXX_SERIALIZER_SUBSTITUTION_MAP_CALLBACK_HXX + +namespace xsde +{ + namespace cxx + { + namespace serializer + { + void + serializer_smap_callback ( + bool (*callback) ( + const char* type, + const void* obj, + const char*& ns, + const char*& name)); + } + } +} + +#endif // XSDE_CXX_SERIALIZER_SUBSTITUTION_MAP_CALLBACK_HXX diff --git a/libxsde/xsde/cxx/serializer/substitution-map.cxx b/libxsde/xsde/cxx/serializer/substitution-map.cxx index 28f01b5..dc73fd2 100644 --- a/libxsde/xsde/cxx/serializer/substitution-map.cxx +++ b/libxsde/xsde/cxx/serializer/substitution-map.cxx @@ -17,6 +17,7 @@ #endif #include <xsde/cxx/serializer/substitution-map.hxx> +#include <xsde/cxx/serializer/substitution-map-callback.hxx> #include <xsde/cxx/serializer/substitution-map-load.hxx> namespace xsde @@ -103,8 +104,19 @@ namespace xsde bool substitution_map:: check_ (const char*& ns, const char*& name, - const char* type) const + const char* type, + const void* obj, + bool top) const { + // Call the callback first to allow the user to provide a custom + // substitution group mapping. + // + if (top && callback_ != 0) + { + if (callback_ (type, obj, ns, name)) + return true; + } + size_t h = hash (name); if (ns) @@ -115,70 +127,70 @@ namespace xsde const bucket* p = find (h); - if (p == 0) - return false; - - // Search for the entry in the bucket. - // - const size_t el_size = sizeof (element) + sizeof (hashmap*); - const char* b = reinterpret_cast<const char*> (p) + sizeof (bucket); - const char* e = b + p->size_ * el_size; - - size_t nl = ns ? strlen (name) : 0; - - for (; b < e; b += el_size) + if (p != 0) { - const element* e = reinterpret_cast<const element*> (b); + // Search for the entry in the bucket. + // + const size_t el_size = sizeof (element) + sizeof (hashmap*); + const char* b = reinterpret_cast<const char*> (p) + sizeof (bucket); + const char* e = b + p->size_ * el_size; + + size_t nl = ns ? strlen (name) : 0; - if (e->hash_ == h) + for (; b < e; b += el_size) { - if (ns == 0) - { - if (strcmp (e->key_, name) == 0) - break; - } - else + const element* e = reinterpret_cast<const element*> (b); + + if (e->hash_ == h) { - if (strncmp (e->key_, name, nl) == 0 && - e->key_[nl] == ' ' && - strcmp (e->key_ + nl + 1, ns) == 0) - break; + if (ns == 0) + { + if (strcmp (e->key_, name) == 0) + break; + } + else + { + if (strncmp (e->key_, name, nl) == 0 && + e->key_[nl] == ' ' && + strcmp (e->key_ + nl + 1, ns) == 0) + break; + } } } - } - if (b == e) - return false; - - const hashmap* map = *reinterpret_cast<const hashmap* const*> ( - b + sizeof (element)); + if (b != e) + { + const hashmap* map = *reinterpret_cast<const hashmap* const*> ( + b + sizeof (element)); - // See if we have a direct substitution. - // - if (const value* v = static_cast<const value*> (map->find (type))) - { - ns = v->ns_; - name = v->name_; - return true; - } + // See if we have a direct substitution. + // + if (const value* v = static_cast<const value*> (map->find (type))) + { + ns = v->ns_; + name = v->name_; + return true; + } - // Otherwise we have to iterate over possible substitutions and - // see if any of them can in turn be substituted with something - // that we can use. - // - for (const_iterator i (map->begin ()), end (map->end ()); - i != end; ++i) - { - const value* v = static_cast<const value*> (*i); + // Otherwise we have to iterate over possible substitutions and + // see if any of them can in turn be substituted with something + // that we can use. + // + for (const_iterator i (map->begin ()), end (map->end ()); + i != end; ++i) + { + const value* v = static_cast<const value*> (*i); - const char* tns = v->ns_; - const char* tn = v->name_; + const char* tns = v->ns_; + const char* tn = v->name_; - if (check_ (tns, tn, type)) - { - ns = tns; - name = tn; - return true; + if (check_ (tns, tn, type, obj, false)) + { + ns = tns; + name = tn; + return true; + } + } } } @@ -264,7 +276,20 @@ namespace xsde #endif } + // Callback. // + void + serializer_smap_callback ( + bool (*callback) ( + const char* type, + const void* obj, + const char*& ns, + const char*& name)) + { + substitution_map_instance ().callback (callback); + } + + // Load. // size_t serializer_smap_elements () diff --git a/libxsde/xsde/cxx/serializer/substitution-map.hxx b/libxsde/xsde/cxx/serializer/substitution-map.hxx index ae16f4c..e36c481 100644 --- a/libxsde/xsde/cxx/serializer/substitution-map.hxx +++ b/libxsde/xsde/cxx/serializer/substitution-map.hxx @@ -30,21 +30,34 @@ namespace xsde const char* member_name, const char* member_type); + typedef bool (*callback_func) ( + const char* type, + const void* obj, + const char*& ns, + const char*& name); + + void + callback (callback_func); + // Check whether there is a substitution available for this // root element with the specified type. If so, return true // and override namespace and name (ns is 0 if there is no - // namespace). + // namespace). The obj argument is an opaque pointer to the + // instance being serialized or 0 if there is none. // bool check (const char*& ns, const char*& name, - const char* type) const; + const char* type, + const void* obj) const; private: bool check_ (const char*& ns, const char*& name, - const char* type) const; + const char* type, + const void* obj, + bool top) const; private: struct value @@ -52,6 +65,9 @@ namespace xsde const char* ns_; const char* name_; }; + + private: + callback_func callback_; }; @@ -85,4 +101,3 @@ namespace xsde #include <xsde/cxx/serializer/substitution-map.ixx> #endif // XSDE_CXX_SERIALIZER_SUBSTITUTION_MAP_HXX - diff --git a/libxsde/xsde/cxx/serializer/substitution-map.ixx b/libxsde/xsde/cxx/serializer/substitution-map.ixx index 6622e33..6dbd951 100644 --- a/libxsde/xsde/cxx/serializer/substitution-map.ixx +++ b/libxsde/xsde/cxx/serializer/substitution-map.ixx @@ -15,12 +15,21 @@ namespace xsde { } + inline void substitution_map:: + callback (callback_func c) + { + callback_ = c; + } + inline bool substitution_map:: check (const char*& ns, const char*& name, - const char* type) const + const char* type, + const void* obj) const { - return empty () ? false : check_ (ns, name, type); + return !empty () || callback_ != 0 + ? check_ (ns, name, type, obj, true) + : false; } inline substitution_map& diff --git a/xsde/cxx/parser/element-validation-source.cxx b/xsde/cxx/parser/element-validation-source.cxx index 5533549..82428f6 100644 --- a/xsde/cxx/parser/element-validation-source.cxx +++ b/xsde/cxx/parser/element-validation-source.cxx @@ -494,9 +494,7 @@ namespace CXX } else { - os << "ctx.current_.any_ = true;" - << "ctx.current_.depth_++;" - << endl + os << "ctx.start_wildcard_content ();" << "this->_start_any_element (ns, n" << (poly_runtime ? (poly_code ? ", t" : ", 0") : "") << ");" << "}" diff --git a/xsde/cxx/parser/parser-header.cxx b/xsde/cxx/parser/parser-header.cxx index 2498768..bf9e31e 100644 --- a/xsde/cxx/parser/parser-header.cxx +++ b/xsde/cxx/parser/parser-header.cxx @@ -1625,6 +1625,11 @@ namespace CXX << "using ::xsde::cxx::parser::parser_map_impl;" << endl; + os << "// Parser substitution map callack." << endl + << "//" << endl + << "using ::xsde::cxx::parser::parser_smap_callback;" + << endl; + os << "// Substitution and inheritance hashmaps load querying." << endl << "//" << endl << "using ::xsde::cxx::parser::parser_smap_buckets;" @@ -1775,6 +1780,7 @@ namespace CXX if (ctx.poly_code) { ctx.os << "#include <xsde/cxx/parser/map.hxx>" << endl + << "#include <xsde/cxx/parser/substitution-map-callback.hxx>" << endl << "#include <xsde/cxx/parser/substitution-map-load.hxx>" << endl; if (ctx.validation) diff --git a/xsde/cxx/serializer/element-validation-source.cxx b/xsde/cxx/serializer/element-validation-source.cxx index 3ca784d..bb09275 100644 --- a/xsde/cxx/serializer/element-validation-source.cxx +++ b/xsde/cxx/serializer/element-validation-source.cxx @@ -447,7 +447,8 @@ namespace CXX os << "if (dt != 0 && " << "::xsde::cxx::serializer::substitution_map_instance ()" << - ".check (ns, n, dt))" << endl + ".check (ns, n, dt, " << (ret == L"void" ? "0" : "&r") << + "))" << endl << "dt = 0;" << endl; diff --git a/xsde/cxx/serializer/serializer-header.cxx b/xsde/cxx/serializer/serializer-header.cxx index bf2c724..2d65cf2 100644 --- a/xsde/cxx/serializer/serializer-header.cxx +++ b/xsde/cxx/serializer/serializer-header.cxx @@ -1787,6 +1787,11 @@ namespace CXX << "using ::xsde::cxx::serializer::serializer_map_impl;" << endl; + os << "// Serializer substitution map callack." << endl + << "//" << endl + << "using ::xsde::cxx::serializer::serializer_smap_callback;" + << endl; + os << "// Substitution and inheritance hashmaps load querying." << endl << "//" << endl << "using ::xsde::cxx::serializer::serializer_smap_buckets;" @@ -1938,6 +1943,7 @@ namespace CXX if (ctx.poly_code) { ctx.os << "#include <xsde/cxx/serializer/map.hxx>" << endl + << "#include <xsde/cxx/serializer/substitution-map-callback.hxx>" << endl << "#include <xsde/cxx/serializer/substitution-map-load.hxx>" << endl; if (ctx.validation) diff --git a/xsde/cxx/serializer/serializer-source.cxx b/xsde/cxx/serializer/serializer-source.cxx index e75a4ed..ab5c123 100644 --- a/xsde/cxx/serializer/serializer-source.cxx +++ b/xsde/cxx/serializer/serializer-source.cxx @@ -1108,7 +1108,8 @@ namespace CXX os << "if (dt != 0 && " << "::xsde::cxx::serializer::substitution_map_instance ()" << - ".check (ns, n, dt))" << endl + ".check (ns, n, dt, " << (ret == L"void" ? "0" : "&r") << + "))" << endl << "dt = 0;" << endl; @@ -1190,7 +1191,8 @@ namespace CXX os << "if (dt != 0 && " << "::xsde::cxx::serializer::substitution_map_instance ()" << - ".check (ns, n, dt))" << endl + ".check (ns, n, dt, " << (ret == L"void" ? "0" : "&r") << + "))" << endl << "dt = 0;" << endl; |