diff options
-rw-r--r-- | Android.bp | 16 | ||||
-rw-r--r-- | build/xsdc.go | 37 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/CodeWriter.java (renamed from src/com/android/xsdc/CodeWriter.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/FileSystem.java (renamed from src/com/android/xsdc/FileSystem.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/Main.java (renamed from src/com/android/xsdc/Main.java) | 57 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/XmlSchema.java (renamed from src/com/android/xsdc/XmlSchema.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/XsdConstants.java (renamed from src/com/android/xsdc/XsdConstants.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/XsdHandler.java (renamed from src/com/android/xsdc/XsdHandler.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/XsdParserException.java (renamed from src/com/android/xsdc/XsdParserException.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/cpp/CppCodeGenerator.java (renamed from src/com/android/xsdc/cpp/CppCodeGenerator.java) | 397 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/cpp/CppCodeGeneratorException.java (renamed from src/com/android/xsdc/cpp/CppCodeGeneratorException.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/cpp/CppComplexType.java (renamed from src/com/android/xsdc/cpp/CppComplexType.java) | 4 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/cpp/CppSimpleType.java (renamed from src/com/android/xsdc/cpp/CppSimpleType.java) | 40 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/cpp/CppType.java (renamed from src/com/android/xsdc/cpp/CppType.java) | 7 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/cpp/Utils.java (renamed from src/com/android/xsdc/cpp/Utils.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/java/JavaCodeGenerator.java (renamed from src/com/android/xsdc/java/JavaCodeGenerator.java) | 154 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/java/JavaCodeGeneratorException.java (renamed from src/com/android/xsdc/java/JavaCodeGeneratorException.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/java/JavaComplexType.java (renamed from src/com/android/xsdc/java/JavaComplexType.java) | 4 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/java/JavaSimpleType.java (renamed from src/com/android/xsdc/java/JavaSimpleType.java) | 24 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/java/JavaType.java (renamed from src/com/android/xsdc/java/JavaType.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/java/Utils.java (renamed from src/com/android/xsdc/java/Utils.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/Nullability.java (renamed from src/com/android/xsdc/tag/Nullability.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdAll.java (renamed from src/com/android/xsdc/tag/XsdAll.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdAttribute.java (renamed from src/com/android/xsdc/tag/XsdAttribute.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdAttributeGroup.java (renamed from src/com/android/xsdc/tag/XsdAttributeGroup.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdChoice.java (renamed from src/com/android/xsdc/tag/XsdChoice.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdComplexContent.java (renamed from src/com/android/xsdc/tag/XsdComplexContent.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdComplexType.java (renamed from src/com/android/xsdc/tag/XsdComplexType.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdElement.java (renamed from src/com/android/xsdc/tag/XsdElement.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdEnumRestriction.java (renamed from src/com/android/xsdc/tag/XsdEnumRestriction.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdEnumeration.java (renamed from src/com/android/xsdc/tag/XsdEnumeration.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdGeneralExtension.java (renamed from src/com/android/xsdc/tag/XsdGeneralExtension.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdGeneralRestriction.java (renamed from src/com/android/xsdc/tag/XsdGeneralRestriction.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdGroup.java (renamed from src/com/android/xsdc/tag/XsdGroup.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdList.java (renamed from src/com/android/xsdc/tag/XsdList.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdRestriction.java (renamed from src/com/android/xsdc/tag/XsdRestriction.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdSimpleContent.java (renamed from src/com/android/xsdc/tag/XsdSimpleContent.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdSimpleType.java (renamed from src/com/android/xsdc/tag/XsdSimpleType.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdTag.java (renamed from src/com/android/xsdc/tag/XsdTag.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdType.java (renamed from src/com/android/xsdc/tag/XsdType.java) | 0 | ||||
-rw-r--r-- | src/main/java/com/android/xsdc/tag/XsdUnion.java (renamed from src/com/android/xsdc/tag/XsdUnion.java) | 0 | ||||
-rw-r--r-- | src/test/java/com/android/xsdc/cpp/TestCppCodeGenerator.java | 150 | ||||
-rw-r--r-- | tests/resources/simple_complex_content/api/current.txt | 6 | ||||
-rw-r--r-- | tests/resources/simple_complex_content/simple_complex_content.xsd | 2 | ||||
-rw-r--r-- | tests/resources/simple_type/api/current.txt | 6 | ||||
-rw-r--r-- | tests/resources/simple_type/simple_type.xsd | 3 | ||||
-rw-r--r-- | tests/resources/simple_type_root.xml | 2 | ||||
-rw-r--r-- | tests/simple_type.cpp | 26 | ||||
-rw-r--r-- | tests/src/com/android/xsdc/tests/XmlParserTest.java | 25 |
49 files changed, 737 insertions, 223 deletions
@@ -4,9 +4,23 @@ package { java_binary_host { name: "xsdc", - srcs: ["src/**/*.java"], + srcs: [ + "src/main/java/**/*.java", + ], static_libs: [ "commons-cli-1.2", ], manifest: "MANIFEST.MF" } + +java_test_host { + name: "xsdc-unittest", + srcs: [ + "src/test/java/**/*.java", + ], + static_libs: [ + "commons-cli-1.2", + "junit", + "xsdc", + ], +} diff --git a/build/xsdc.go b/build/xsdc.go index f92ba28..c5bc28d 100644 --- a/build/xsdc.go +++ b/build/xsdc.go @@ -40,16 +40,23 @@ var ( xsdc = pctx.HostBinToolVariable("xsdcCmd", "xsdc") xsdcJavaRule = pctx.StaticRule("xsdcJavaRule", blueprint.RuleParams{ Command: `rm -rf "${out}.temp" && mkdir -p "${out}.temp" && ` + - `${xsdcCmd} $in -p $pkgName -o ${out}.temp -j $args && ` + + `${xsdcCmd} $in -p $pkgName -o ${out}.temp -j $args -d ${out}.dep && ` + + `echo "${out} : \\" > ${out}.d && cat ${out}.dep >> ${out}.d && ` + `${config.SoongZipCmd} -jar -o ${out} -C ${out}.temp -D ${out}.temp && ` + - `rm -rf ${out}.temp`, + `rm -rf ${out}.temp && rm -rf ${out}.dep`, + Depfile: "${out}.d", + Deps: blueprint.DepsGCC, CommandDeps: []string{"${xsdcCmd}", "${config.SoongZipCmd}"}, Description: "xsdc Java ${in} => ${out}", }, "pkgName", "args") xsdcCppRule = pctx.StaticRule("xsdcCppRule", blueprint.RuleParams{ Command: `rm -rf "${outDir}" && ` + - `${xsdcCmd} $in -p $pkgName -o ${outDir} -c $args`, + `${xsdcCmd} $in -p $pkgName -o ${outDir} -c $args -d ${out}.dep && ` + + `echo "${out} : \\" > ${out}.d && cat ${out}.dep >> ${out}.d && ` + + `rm -rf ${out}.dep`, + Depfile: "${out}.d", + Deps: blueprint.DepsGCC, CommandDeps: []string{"${xsdcCmd}", "${config.SoongZipCmd}"}, Description: "xsdc C++ ${in} => ${out}", }, "pkgName", "outDir", "args") @@ -86,6 +93,11 @@ type xsdConfigProperties struct { // ENTITY_REFs. // This can improve memory footprint. Default value is false. Tinyxml *bool + // Specify root elements explicitly. If not set, XSDC generates parsers and + // writers for all elements which can be root element. When set, XSDC + // generates parsers and writers for specified root elements. This can be + // used to avoid unnecessary code. + Root_elements []string } type xsdConfig struct { @@ -214,6 +226,10 @@ func (module *xsdConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) args = args + " -t " } + for _, elem := range module.properties.Root_elements { + args = args + " -r " + elem + } + module.genOutputs_j = android.PathForModuleGen(ctx, "java", filenameStem+"_xsdcgen.srcjar") ctx.Build(pctx, android.BuildParams{ @@ -246,6 +262,15 @@ func (module *xsdConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h"), android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+"_enums.h")} } + + output := module.genOutputs_c[0] + // Multiple outputs aren't supported by depslog. + // So ImplicitOutputs is used for additional generated code. + implicitOutputs := module.genOutputs_h + if len(module.genOutputs_c) > 1 { + implicitOutputs = append(implicitOutputs, module.genOutputs_c[1:]...) + } + module.genOutputDir = android.PathForModuleGen(ctx, "cpp", "include") ctx.Build(pctx, android.BuildParams{ @@ -253,8 +278,8 @@ func (module *xsdConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) Description: "xsdc " + xsdFile.String(), Input: xsdFile, Implicit: module.docsPath, - Outputs: module.genOutputs_c, - ImplicitOutputs: module.genOutputs_h, + Output: output, + ImplicitOutputs: implicitOutputs, Args: map[string]string{ "pkgName": pkgName, "outDir": android.PathForModuleGen(ctx, "cpp").String(), @@ -330,4 +355,4 @@ func (module *xsdConfig) OutputFiles(tag string) (android.Paths, error) { } } -var _ android.OutputFileProducer = (*xsdConfig)(nil); +var _ android.OutputFileProducer = (*xsdConfig)(nil) diff --git a/src/com/android/xsdc/CodeWriter.java b/src/main/java/com/android/xsdc/CodeWriter.java index 489ccdc..489ccdc 100644 --- a/src/com/android/xsdc/CodeWriter.java +++ b/src/main/java/com/android/xsdc/CodeWriter.java diff --git a/src/com/android/xsdc/FileSystem.java b/src/main/java/com/android/xsdc/FileSystem.java index 2d746f3..2d746f3 100644 --- a/src/com/android/xsdc/FileSystem.java +++ b/src/main/java/com/android/xsdc/FileSystem.java diff --git a/src/com/android/xsdc/Main.java b/src/main/java/com/android/xsdc/Main.java index 0f486d0..90e0719 100644 --- a/src/com/android/xsdc/Main.java +++ b/src/main/java/com/android/xsdc/Main.java @@ -18,7 +18,11 @@ package com.android.xsdc; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintWriter; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; import static java.lang.System.exit; @@ -101,6 +105,18 @@ public class Main { .withDescription("Only generate XML parser in Cpp code.") .create("x"); options.addOption(genParserOnly); + Option genDepFile = OptionBuilder + .withLongOpt("depfile") + .hasArgs(1) + .withDescription("Generate depfile for ninja.") + .create("d"); + options.addOption(genDepFile); + options.addOption(OptionBuilder + .withLongOpt("root") + .hasArgs(1) + .withDescription("Root element.") + .create("r")); + // "Only generate enums" and "Only generate parser" options are mutually exclusive. OptionGroup genOnlyGroup = new OptionGroup(); genOnlyGroup.setRequired(false); @@ -119,7 +135,6 @@ public class Main { return; } - String[] xsdFile = cmd.getArgs(); String packageName = cmd.getOptionValue('p', null); String outDir = cmd.getOptionValue('o', null); boolean writer = cmd.hasOption('w'); @@ -129,8 +144,10 @@ public class Main { boolean parserOnly = cmd.hasOption('x'); boolean booleanGetter = cmd.hasOption('b'); boolean useTinyXml = cmd.hasOption('t'); + String depFile = cmd.getOptionValue('d', null); + String[] rootElements = cmd.getOptionValues('r'); - if (xsdFile.length != 1 || packageName == null) { + if (cmd.getArgs().length != 1 || packageName == null) { System.err.println("Error: no xsd files or package name"); help(options); } @@ -139,7 +156,20 @@ public class Main { outDir = "."; } - XmlSchema xmlSchema = parse(xsdFile[0]); + String xsdFile = cmd.getArgs()[0]; + List<String> included = new ArrayList<>(); + included.add(xsdFile); + XmlSchema xmlSchema = parse(xsdFile, included); + + // When -r (root element) is specified, then validate if it's defined in schema. + if (rootElements != null) { + for (String rootElement : rootElements) { + if (!xmlSchema.getElementMap().containsKey(rootElement)) { + System.err.println("Invalid root element(-r): " + rootElement); + System.exit(1); + } + } + } if (cmd.hasOption('j')) { File packageDir = new File(Paths.get(outDir, packageName.replace(".", "/")).toString()); @@ -147,7 +177,7 @@ public class Main { FileSystem fs = new FileSystem(packageDir); JavaCodeGenerator javaCodeGenerator = new JavaCodeGenerator(xmlSchema, packageName, writer, nullability, genHas, - booleanGetter); + booleanGetter, rootElements); javaCodeGenerator.print(fs); } else if (cmd.hasOption('c')) { File includeDir = new File(Paths.get(outDir, "include").toString()); @@ -158,12 +188,16 @@ public class Main { CppCodeGenerator.GENERATE_ENUMS | CppCodeGenerator.GENERATE_PARSER); CppCodeGenerator cppCodeGenerator = new CppCodeGenerator(xmlSchema, packageName, writer, generators, - booleanGetter, useTinyXml); + booleanGetter, useTinyXml, rootElements); cppCodeGenerator.print(fs); } + + if (depFile != null) { + writeDepFile(depFile, included); + } } - private static XmlSchema parse(String xsdFile) throws Exception { + private static XmlSchema parse(String xsdFile, List<String> included) throws Exception { XmlSchema xmlSchema; try (FileInputStream in = new FileInputStream(xsdFile)) { SAXParserFactory factory = SAXParserFactory.newInstance(); @@ -174,12 +208,21 @@ public class Main { xmlSchema = xsdHandler.getSchema(); } for (String file : xmlSchema.getIncludeList()) { - XmlSchema temp = parse(Paths.get(xsdFile).resolveSibling(file).toString()); + String filePath = Paths.get(xsdFile).resolveSibling(file).toString(); + included.add(filePath); + XmlSchema temp = parse(filePath, included); xmlSchema.include(temp); } return xmlSchema; } + private static void writeDepFile(String depFile, List<String> files) + throws IOException { + try (PrintWriter out = new PrintWriter(new File(depFile))) { + out.println(String.format(" %s", String.join(" \\\n ", files))); + } + } + private static void help(Options options) { new HelpFormatter().printHelp( "xsdc path/to/xsd_file.xsd","", options, null, true); diff --git a/src/com/android/xsdc/XmlSchema.java b/src/main/java/com/android/xsdc/XmlSchema.java index 4bfa3fd..4bfa3fd 100644 --- a/src/com/android/xsdc/XmlSchema.java +++ b/src/main/java/com/android/xsdc/XmlSchema.java diff --git a/src/com/android/xsdc/XsdConstants.java b/src/main/java/com/android/xsdc/XsdConstants.java index 6c79b9b..6c79b9b 100644 --- a/src/com/android/xsdc/XsdConstants.java +++ b/src/main/java/com/android/xsdc/XsdConstants.java diff --git a/src/com/android/xsdc/XsdHandler.java b/src/main/java/com/android/xsdc/XsdHandler.java index f6a9492..f6a9492 100644 --- a/src/com/android/xsdc/XsdHandler.java +++ b/src/main/java/com/android/xsdc/XsdHandler.java diff --git a/src/com/android/xsdc/XsdParserException.java b/src/main/java/com/android/xsdc/XsdParserException.java index aa755d5..aa755d5 100644 --- a/src/com/android/xsdc/XsdParserException.java +++ b/src/main/java/com/android/xsdc/XsdParserException.java diff --git a/src/com/android/xsdc/cpp/CppCodeGenerator.java b/src/main/java/com/android/xsdc/cpp/CppCodeGenerator.java index e470216..9bfbe56 100644 --- a/src/com/android/xsdc/cpp/CppCodeGenerator.java +++ b/src/main/java/com/android/xsdc/cpp/CppCodeGenerator.java @@ -51,17 +51,20 @@ public class CppCodeGenerator { private int generators; private boolean booleanGetter; private boolean useTinyXml; + private String[] rootElements; private static final String UNKNOWN_ENUM = "UNKNOWN"; public CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer, int generators, - boolean booleanGetter, boolean useTinyXml) throws CppCodeGeneratorException { + boolean booleanGetter, boolean useTinyXml, String[] rootElements) + throws CppCodeGeneratorException { this.xmlSchema = xmlSchema; this.pkgName = pkgName; this.writer = writer; this.generators = generators; this.booleanGetter = booleanGetter; this.useTinyXml = useTinyXml; + this.rootElements = rootElements; // class naming validation { @@ -178,6 +181,14 @@ public class CppCodeGenerator { enumsCppFile.printf("#include \"%s\"\n\n", enumsHeaderFileName); parserCppFile.printf("#define LOG_TAG \"%s\"\n", pkgName); parserCppFile.printf("#include \"%s\"\n\n", parserHeaderFileName); + // define _xsdc_assert to abort with message regardless of NDEBUG + parserCppFile.println("#include <assert.h>\n" + + "#ifndef __BIONIC__\n" + + "#define __assert2(f,n,fun,e) do { fprintf(stderr, \"%s:%d: %s: Assertion `%s'" + + " failed\", (f), (n), (fun), (e)); abort(); } while (false)\n" + + "#endif\n" + + "#define _xsdc_assert(e) do if (!(e)) __assert2(__FILE__, __LINE__," + + " __PRETTY_FUNCTION__, #e); while (false)\n"); List<String> namespace = new java.util.ArrayList<>(); for (String token : pkgName.split("\\.")) { @@ -322,6 +333,14 @@ public class CppCodeGenerator { enumsHeaderFile.printf("};\n"); } + /** + * Prints forward declarations for complex types. + * + * Foo.h: + * + * class Foo; + * + */ private void printPrototype() throws CppCodeGeneratorException { for (XsdType type : xmlSchema.getTypeMap().values()) { if (type instanceof XsdComplexType) { @@ -338,6 +357,22 @@ public class CppCodeGenerator { } } + /** + * Prints class definitions for complex types. + * + * Foo.h: + * + * class Foo { + * printClass(<inner types>) + * <members> + * const optional<> value_; + * args = printConstructor() + * printGetter(<members>) + * printParser( args ) + * printWriter() + * }; + * + */ private void printClass(String name, String nameScope, XsdComplexType complexType) throws CppCodeGeneratorException { assert name != null; @@ -379,7 +414,7 @@ public class CppCodeGenerator { elementTypes.add(cppType); } List<CppSimpleType> attributeTypes = new ArrayList<>(); - List<XsdAttribute> attributes = new ArrayList(); + List<XsdAttribute> attributes = new ArrayList<>(); for (XsdAttributeGroup attributeGroup : complexType.getAttributeGroups()) { attributes.addAll(getAllAttributes(resolveAttributeGroup(attributeGroup))); } @@ -451,6 +486,27 @@ public class CppCodeGenerator { parserHeaderFile.println("};\n"); } + /** + * Prints read() static member function for complex types. + * Note that read() is a non-validating parser. + * + * Foo.h: + * + * static Foo read(XmlNode* root); + * + * Foo.cpp: + * + * Foo Foo::read(XmlNode* root) { + * string _raw; + * for each member m + * _raw = .. + * parsing expressions for each member (read _raw, set _value) + * m = _value; + * Foo instance(args...); + * return instance; + * } + * + */ private void printParser(String name, String nameScope, XsdComplexType complexType, String args) throws CppCodeGeneratorException { CppSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ? @@ -477,13 +533,13 @@ public class CppCodeGenerator { parserHeaderFile.printf("static %s read(%s *root);\n", fullName, nodeType); parserCppFile.printf("\n%s %s::read(%s *root) {\n", fullName, fullName, nodeType); - parserCppFile.print("std::string raw;\n"); + parserCppFile.print("std::string _raw;\n"); for (int i = 0; i < allAttributes.size(); ++i) { CppSimpleType type = allAttributeTypes.get(i); XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); String variableName = Utils.toVariableName(attribute.getName()); - parserCppFile.printf("raw = getXmlAttribute(root, \"%s\");\n", attribute.getName()); + parserCppFile.printf("_raw = getXmlAttribute(root, \"%s\");\n", attribute.getName()); if (attribute.isRequired()) { if (type.isEnum()) { parserCppFile.printf("%s %s = %s::%s;\n", @@ -495,15 +551,15 @@ public class CppCodeGenerator { parserCppFile.printf("std::optional<%s> %s = std::nullopt;\n", type.getName(), variableName); } - parserCppFile.printf("if (raw != \"\") {\n"); + parserCppFile.printf("if (_raw != \"\") {\n"); parserCppFile.print(type.getParsingExpression()); - parserCppFile.printf("%s = value;\n}\n", variableName); + parserCppFile.printf("%s = _value;\n}\n", variableName); } if (baseValueType != null) { - printNodeListGetString("root"); + printSetRawWithElementText("root"); parserCppFile.print(baseValueType.getParsingExpression()); - parserCppFile.printf("instance.setValue(value);\n"); + parserCppFile.printf("instance.setValue(_value);\n"); parserCppFile.printf("}\n"); } else if (!allElements.isEmpty()) { for (int i = 0; i < allElements.size(); ++i) { @@ -515,13 +571,13 @@ public class CppCodeGenerator { element.isMultiple() || type instanceof CppComplexType), variableName); } if (useTinyXml) { - parserCppFile.print("for (auto *child = root->FirstChildElement();" - + " child != nullptr;" - + " child = child->NextSiblingElement()) {\n"); + parserCppFile.print("for (auto *_child = root->FirstChildElement();" + + " _child != nullptr;" + + " _child = _child->NextSiblingElement()) {\n"); } else { - parserCppFile.print("for (auto *child = root->xmlChildrenNode;" - + " child != nullptr;" - + " child = child->next) {\n"); + parserCppFile.print("for (auto *_child = root->xmlChildrenNode;" + + " _child != nullptr;" + + " _child = _child->next) {\n"); } for (int i = 0; i < allElements.size(); ++i) { CppType type = allElementTypes.get(i); @@ -531,24 +587,24 @@ public class CppCodeGenerator { if (i != 0) parserCppFile.printf("} else "); if (useTinyXml) { - parserCppFile.printf("if (!strcmp(child->Name(), \"%s\")) {\n", + parserCppFile.printf("if (!strcmp(_child->Name(), \"%s\")) {\n", elementValue.getName()); } else { - parserCppFile.printf("if (!xmlStrcmp(child->name," + parserCppFile.printf("if (!xmlStrcmp(_child->name," + " reinterpret_cast<const xmlChar*>(\"%s\"))) {\n", elementValue.getName()); } if (type instanceof CppSimpleType) { - printNodeListGetString("child"); + printSetRawWithElementText("_child"); } parserCppFile.print(type.getParsingExpression()); if (element.isMultiple() || type instanceof CppComplexType) { - parserCppFile.printf("%s.push_back(std::move(value));\n", variableName); + parserCppFile.printf("%s.push_back(std::move(_value));\n", variableName); } else { - parserCppFile.printf("%s = std::move(value);\n", variableName); + parserCppFile.printf("%s = std::move(_value);\n", variableName); } } parserCppFile.printf("}\n}\n"); @@ -562,31 +618,45 @@ public class CppCodeGenerator { return (useTinyXml ? "tinyxml2::XMLElement" : "xmlNode"); } - private void printNodeListGetString(String varName) { + private void printSetRawWithElementText(String varName) { if (useTinyXml) { // The tinyxml version, in contrast to xmlNodeListGetString does not deal // with ENTITY_REF nodes - parserCppFile.printf("raw = \"\";\n"); + parserCppFile.printf("_raw = \"\";\n"); parserCppFile.printf("for (auto *textNode = %s->FirstChild();" + " textNode != nullptr;" + " textNode = textNode->NextSibling()) {\n", varName); parserCppFile.printf("if (textNode->ToText() != nullptr) {\n"); - parserCppFile.printf("raw.append(textNode->Value());\n"); + parserCppFile.printf("_raw.append(textNode->Value());\n"); parserCppFile.printf("}\n"); parserCppFile.printf("}\n"); } else { parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString("); parserCppFile.printf("%s->doc, %s->xmlChildrenNode, 1));\n", varName, varName); - parserCppFile.printf("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n"); - parserCppFile.printf("raw = reinterpret_cast<const char*>(xmlValue.get());\n}"); + parserCppFile.printf("if (xmlValue == nullptr) {\n_raw = \"\";\n} else {\n"); + parserCppFile.printf("_raw = reinterpret_cast<const char*>(xmlValue.get());\n}"); parserCppFile.printf("\n"); } } + /** + * Prints write() member function for complex types. + * + * Foo.h: + * + * void write(ostream& _out, string name) const; + * + * Foo.cpp: + * + * void Foo::write(ostream& _out, string name) const { + * <FooElement attrs....> + * value_ + * </Fooelement> + * } + * + */ private void printWriter(String name, String nameScope, XsdComplexType complexType) throws CppCodeGeneratorException { - CppSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ? - getValueType((XsdSimpleContent) complexType, true) : null; List<XsdElement> allElements = new ArrayList<>(); List<XsdAttribute> allAttributes = new ArrayList<>(); stackComponents(complexType, allElements, allAttributes); @@ -605,24 +675,24 @@ public class CppCodeGenerator { } String fullName = nameScope + name; - parserHeaderFile.printf("void write(std::ostream& out, const std::string& name) const;\n"); + parserHeaderFile.printf("void write(std::ostream& _out, const std::string& _name) const;\n"); parserCppFile.printf( - "\nvoid %s::write(std::ostream& out, const std::string& name) const {\n", + "\nvoid %s::write(std::ostream& _out, const std::string& _name) const {\n", fullName); - parserCppFile.printf("out << printIndent() << \"<\" << name;\n"); + parserCppFile.printf("_out << printIndent() << \"<\" << _name;\n"); for (int i = 0; i < allAttributes.size(); ++i) { CppType type = allAttributeTypes.get(i); XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); String variableName = Utils.toVariableName(attribute.getName()); parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName)); - parserCppFile.printf("out << \" %s=\\\"\";\n", attribute.getName()); + parserCppFile.printf("_out << \" %s=\\\"\";\n", attribute.getName()); parserCppFile.print(type.getWritingExpression(String.format("%s%s()", getterName(type.getName()), Utils.capitalize(variableName)), attribute.getName())); - parserCppFile.printf("out << \"\\\"\";\n}\n"); + parserCppFile.printf("_out << \"\\\"\";\n}\n"); } - parserCppFile.print("out << \">\" << std::endl;\n"); + parserCppFile.print("_out << \">\" << std::endl;\n"); parserCppFile.print("++indentIndex;\n"); if (!allElements.isEmpty()) { @@ -634,30 +704,30 @@ public class CppCodeGenerator { String variableName = Utils.toVariableName(elementName); if (type instanceof CppComplexType || element.isMultiple()) { - parserCppFile.printf("for (auto& value : get%s()) {\n", + parserCppFile.printf("for (auto& _value : get%s()) {\n", Utils.capitalize(variableName)); if (type instanceof CppSimpleType) { - parserCppFile.printf("out << printIndent() << \"<%s>\";\n", + parserCppFile.printf("_out << printIndent() << \"<%s>\";\n", elementValue.getName()); } parserCppFile.printf( - type.getWritingExpression("value", elementValue.getName())); + type.getWritingExpression("_value", elementValue.getName())); if (type instanceof CppSimpleType) { - parserCppFile.printf("out << \"</%s>\" << std::endl;\n", + parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", elementValue.getName()); } parserCppFile.printf("}\n"); } else { parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName)); if (type instanceof CppSimpleType) { - parserCppFile.printf("out << printIndent() << \"<%s>\";\n", + parserCppFile.printf("_out << printIndent() << \"<%s>\";\n", elementValue.getName()); } parserCppFile.print(type.getWritingExpression(String.format("%s%s()", getterName(type.getName()), Utils.capitalize(variableName)), elementValue.getName())); if (type instanceof CppSimpleType) { - parserCppFile.printf("out << \"</%s>\" << std::endl;\n", + parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", elementValue.getName()); } parserCppFile.print("}\n"); @@ -665,24 +735,56 @@ public class CppCodeGenerator { } } parserCppFile.print("--indentIndex;\n"); - parserCppFile.printf("out << printIndent() << \"</\" << name << \">\" << std::endl;\n"); + parserCppFile.printf("_out << printIndent() << \"</\" << _name << \">\" << std::endl;\n"); parserCppFile.printf("}\n"); } + /** + * Prints hasAttr() and getAttr() member functions for each member field. + * + * Foo.h: + * + * const Attr& getAttr() const; + * bool hasAttr() const; + * const Item* getFirstItem() const; // for multi-value member + * + * Foo.cpp: + * + * const Attr& Foo::getAttr() const { + * return attr_; + * } + * bool Foo::hasAttr() const { + * return true; + * } + * const Item* Foo::getFirstItem() const { + * if (item_.empty()) { + * return nullptr; + * } + * return &item_[0]; + * } + * + */ private void printGetter(String name, CppType type, String variableName, boolean isMultiple, boolean isMultipleType, boolean isRequired) { String typeName = isMultiple ? String.format("std::vector<%s>", type.getName()) : type.getName(); + String assertHasValue = String.format("_xsdc_assert(has%s());\n", + Utils.capitalize(variableName)); parserHeaderFile.printf("const %s& %s%s() const;\n", typeName, getterName(typeName), Utils.capitalize(variableName)); parserCppFile.println(); - parserCppFile.printf("const %s& %s::%s%s() const {\n" - + "return %s;\n}\n\n", - typeName, name, getterName(typeName), Utils.capitalize(variableName), - isMultiple || isRequired ? - variableName + "_" : String.format("%s_.value()", variableName)); + parserCppFile.printf("const %s& %s::%s%s() const {\n", typeName, name, + getterName(typeName), Utils.capitalize(variableName)); + if (isMultiple || isRequired) { + parserCppFile.printf("return %s_;\n", variableName); + } else { + // Before accessing an optional::value(), we need to ensure that it has a value. + parserCppFile.print(assertHasValue); + parserCppFile.printf("return %s_.value();\n", variableName); + } + parserCppFile.printf("}\n\n"); parserHeaderFile.printf("bool has%s() const;\n", Utils.capitalize(variableName)); parserCppFile.printf("bool %s::has%s() const {\n", name, Utils.capitalize(variableName)); @@ -694,6 +796,7 @@ public class CppCodeGenerator { parserCppFile.printf("return %s_.has_value();\n}\n", variableName); } + // For elements that may occur multiple types or have a list of simple types if (isMultiple || isMultipleType) { String elementTypeName = type instanceof CppComplexType ? type.getName() : ((CppSimpleType)type).getTypeName(); @@ -702,12 +805,15 @@ public class CppCodeGenerator { elementTypeName, Utils.capitalize(variableName)); parserCppFile.println(); parserCppFile.printf("%s %s::getFirst%s() const {\n" + + "%s" + "if (%s_%sempty()) {\n" + "return false;\n" + "}\n" + "return %s;\n" + "}\n", - elementTypeName, name, Utils.capitalize(variableName), variableName, + elementTypeName, name, Utils.capitalize(variableName), + isMultiple ? "" : assertHasValue, + variableName, isMultiple ? "." : "->", isMultiple ? String.format("%s_[0]", variableName) : String.format("%s_.value()[0]", variableName)); @@ -716,12 +822,15 @@ public class CppCodeGenerator { elementTypeName, Utils.capitalize(variableName)); parserCppFile.println(); parserCppFile.printf("const %s* %s::getFirst%s() const {\n" + + "%s" + "if (%s_%sempty()) {\n" + "return nullptr;\n" + "}\n" + "return &%s;\n" + "}\n", - elementTypeName, name, Utils.capitalize(variableName), variableName, + elementTypeName, name, Utils.capitalize(variableName), + isMultiple ? "" : assertHasValue, + variableName, isMultiple ? "." : "->", isMultiple ? String.format("%s_[0]", variableName) : String.format("%s_.value()[0]", variableName)); @@ -729,6 +838,18 @@ public class CppCodeGenerator { } } + /** + * Prints constructor for complex types + * + * Foo.h: + * + * Foo(args...); + * + * Foo.cpp: + * + * Foo::Foo(args...): initializer... {} + * + */ private String printConstructor(String name, String nameScope, XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes, String baseName) throws CppCodeGeneratorException { @@ -742,7 +863,6 @@ public class CppCodeGenerator { List<XsdAttribute> allAttributes = new ArrayList<>(); stackComponents(complexType, allElements, allAttributes); - List<CppType> allElementTypes = new ArrayList<>(); for (XsdElement element : allElements) { XsdElement elementValue = resolveElement(element); CppType type = parseType(elementValue.getType(), elementValue.getName()); @@ -766,7 +886,6 @@ public class CppCodeGenerator { parentArgs.append(String.format(", %s", variableName)); } } - List<CppSimpleType> allAttributeTypes = new ArrayList<>(); for (XsdAttribute attribute : allAttributes) { CppType type = parseSimpleType(resolveAttribute(attribute).getType(), false); String variableName = Utils.toVariableName(resolveAttribute(attribute).getName()); @@ -817,6 +936,22 @@ public class CppCodeGenerator { return argsString; } + /** + * Prints reader functions for each top-level types. + * + * Foo.h: + * + * optional<Foo> readFoo(const char* filename); + * + * Foo.cpp: + * + * std::optional<Foo> readFoo(const char* filename) { + * ... + * Foo _value = Foo::read(root); + * return _value; + * } + * + */ private void printXmlParser() throws CppCodeGeneratorException { if (useTinyXml) { // Nothing to do for libtinyxml2 @@ -853,75 +988,122 @@ public class CppCodeGenerator { parserCppFile.printf("}\n\n"); } - String className = Utils.toClassName(pkgName); - boolean isMultiRootElement = xmlSchema.getElementMap().values().size() > 1; for (XsdElement element : xmlSchema.getElementMap().values()) { - CppType cppType = parseType(element.getType(), element.getName()); - String elementName = element.getName(); - String VariableName = Utils.toVariableName(elementName); - String typeName = cppType instanceof CppSimpleType ? cppType.getName() : - Utils.toClassName(cppType.getName()); - - parserHeaderFile.printf("std::optional<%s> read%s(const char* configFile);\n\n", - typeName, isMultiRootElement ? Utils.capitalize(typeName) : ""); - parserCppFile.printf("std::optional<%s> read%s(const char* configFile) {\n", - typeName, isMultiRootElement ? Utils.capitalize(typeName) : ""); - if (useTinyXml) { - parserCppFile.printf("tinyxml2::XMLDocument doc;\n" - + "if (doc.LoadFile(configFile) != tinyxml2::XML_SUCCESS) {\n" - + "return std::nullopt;\n" - + "}\n" - + "auto child = doc.FirstChildElement();\n" - + "if (child == nullptr) {\n" - + "return std::nullopt;\n" - + "}\n\n" - + "if (strcmp(child->Name(), \"%s\") == 0) {\n", - elementName); - } else { - parserCppFile.printf("auto doc = make_xmlUnique(xmlParseFile(configFile));\n" - + "if (doc == nullptr) {\n" - + "return std::nullopt;\n" - + "}\n" - + "xmlNodePtr child = xmlDocGetRootElement(doc.get());\n" - + "if (child == nullptr) {\n" - + "return std::nullopt;\n" - + "}\n" - + "if (xmlXIncludeProcess(doc.get()) < 0) {\n" - + "return std::nullopt;\n" - + "}\n\n" - + "if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>" - + "(\"%s\"))) {\n", - elementName); - } - - if (cppType instanceof CppSimpleType) { - parserCppFile.printf("%s value = getXmlAttribute(child, \"%s\");\n", - elementName, elementName); - } else { - parserCppFile.printf(cppType.getParsingExpression()); - } - parserCppFile.printf("return value;\n}\n"); - parserCppFile.printf("return std::nullopt;\n"); - parserCppFile.printf("}\n\n"); + // Skip parser if not specified as root. + if (rootElements != null + && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; + printXmlParserFor(element, /*loadFile=*/true, isMultiRootElement); + printXmlParserFor(element, /*loadFile=*/false, isMultiRootElement); } } + /** + * Prints readType(const char* configFile) if loadFile is true. + * Otherwise, prints parseType(const char* xml). + */ + private void printXmlParserFor(XsdElement element, boolean loadFile, boolean isMultiRootElement) + throws CppCodeGeneratorException { + CppType cppType = parseType(element.getType(), element.getName()); + String elementName = element.getName(); + String typeName = cppType.getName(); + String readerName = + cppType instanceof CppSimpleType ? Utils.toClassName(elementName) : typeName; + String methodName = loadFile ? "read" : "parse"; + String argName = loadFile ? "configFile" : "xml"; + parserHeaderFile.printf("std::optional<%s> %s%s(const char* %s);\n\n", + typeName, + methodName, + isMultiRootElement ? readerName : "", + argName); + parserCppFile.printf("std::optional<%s> %s%s(const char* %s) {\n", + typeName, + methodName, + isMultiRootElement ? readerName : "", + argName); + if (useTinyXml) { + String innerParser = loadFile ? "LoadFile(configFile)" : "Parse(xml)"; + parserCppFile.printf("tinyxml2::XMLDocument doc;\n" + + "if (doc.%s != tinyxml2::XML_SUCCESS) {\n" + + "return std::nullopt;\n" + + "}\n" + + "auto _child = doc.FirstChildElement();\n" + + "if (_child == nullptr) {\n" + + "return std::nullopt;\n" + + "}\n\n" + + "if (strcmp(_child->Name(), \"%s\") == 0) {\n", + innerParser, + elementName); + } else { + String innerParser = loadFile + ? "xmlParseFile(configFile)" + : "xmlParseDoc(reinterpret_cast<const xmlChar*>(xml))"; + parserCppFile.printf("auto doc = make_xmlUnique(%s);\n" + + "if (doc == nullptr) {\n" + + "return std::nullopt;\n" + + "}\n" + + "xmlNodePtr _child = xmlDocGetRootElement(doc.get());\n" + + "if (_child == nullptr) {\n" + + "return std::nullopt;\n" + + "}\n" + + "if (xmlXIncludeProcess(doc.get()) < 0) {\n" + + "return std::nullopt;\n" + + "}\n\n" + + "if (!xmlStrcmp(_child->name, reinterpret_cast<const xmlChar*>" + + "(\"%s\"))) {\n", + innerParser, + elementName); + } + + if (cppType instanceof CppSimpleType) { + parserCppFile.print("std::string _raw;\n"); + printSetRawWithElementText("_child"); + } + parserCppFile.printf(cppType.getParsingExpression()); + parserCppFile.printf("return _value;\n}\n"); + parserCppFile.printf("return std::nullopt;\n"); + parserCppFile.printf("}\n\n"); + } + + /** + * Prints writer functions for each top-level types + * + * Foo.h: + * + * void write(ostream&, const Foo& foo); + * + * Foo.cpp: + * + * void write(ostream& _out, const Foo& foo) { + * ... <?xml ... ?> + * foo.write(_out, "FooElementName"); + * } + * + */ private void printXmlWriter() throws CppCodeGeneratorException { for (XsdElement element : xmlSchema.getElementMap().values()) { + // Skip writer if not specified as root. + if (rootElements != null + && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; CppType cppType = parseType(element.getType(), element.getName()); String elementName = element.getName(); - String VariableName = Utils.toVariableName(elementName); - String typeName = cppType instanceof CppSimpleType ? cppType.getName() : - Utils.toClassName(cppType.getName()); - parserHeaderFile.printf("void write(std::ostream& out, %s& %s);\n\n", - typeName, VariableName); - parserCppFile.printf("void write(std::ostream& out, %s& %s) {\n", - typeName, VariableName); - + String variableName = Utils.toVariableName(elementName); + String typeName = cppType.getName(); + String writerName = + cppType instanceof CppSimpleType ? Utils.toClassName(elementName) : ""; + parserHeaderFile.printf("void write%s(std::ostream& _out, const %s& %s);\n\n", + writerName, typeName, variableName); + parserCppFile.printf("void write%s(std::ostream& _out, const %s& %s) {\n", + writerName, typeName, variableName); parserCppFile.print( - "out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n"); - parserCppFile.printf("%s.write(out, \"%s\");\n", VariableName, elementName); + "_out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n"); + if (cppType instanceof CppSimpleType) { + parserCppFile.printf("_out << \"<%s>\";\n", elementName); + parserCppFile.print(cppType.getWritingExpression(variableName, "")); + parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", elementName); + } else { + parserCppFile.printf("%s.write(_out, \"%s\");\n", variableName, elementName); + } parserCppFile.printf("}\n\n"); } @@ -1157,7 +1339,6 @@ public class CppCodeGenerator { } boolean results = false; for (XsdElement element : complexType.getElements()) { - XsdElement elementValue = resolveElement(element); if (element.getRef() == null && element.getType().getRef() == null && element.getType() instanceof XsdComplexType) { results = hasAttribute((XsdComplexType) element.getType()); diff --git a/src/com/android/xsdc/cpp/CppCodeGeneratorException.java b/src/main/java/com/android/xsdc/cpp/CppCodeGeneratorException.java index a6ccf2a..a6ccf2a 100644 --- a/src/com/android/xsdc/cpp/CppCodeGeneratorException.java +++ b/src/main/java/com/android/xsdc/cpp/CppCodeGeneratorException.java diff --git a/src/com/android/xsdc/cpp/CppComplexType.java b/src/main/java/com/android/xsdc/cpp/CppComplexType.java index 64d735d..4a87afa 100644 --- a/src/com/android/xsdc/cpp/CppComplexType.java +++ b/src/main/java/com/android/xsdc/cpp/CppComplexType.java @@ -30,11 +30,11 @@ class CppComplexType implements CppType { @Override public String getParsingExpression() { - return String.format("%s value = %s::read(child);\n", name, name); + return String.format("%s _value = %s::read(_child);\n", name, name); } @Override public String getWritingExpression(String getValue, String name) { - return String.format("%s.write(out, \"%s\");\n", getValue, name); + return String.format("%s.write(_out, \"%s\");\n", getValue, name); } } diff --git a/src/com/android/xsdc/cpp/CppSimpleType.java b/src/main/java/com/android/xsdc/cpp/CppSimpleType.java index d063ebe..5168329 100644 --- a/src/com/android/xsdc/cpp/CppSimpleType.java +++ b/src/main/java/com/android/xsdc/cpp/CppSimpleType.java @@ -62,19 +62,19 @@ class CppSimpleType implements CppType { StringBuilder expression = new StringBuilder(); if (list) { expression.append( - String.format("%s value;\n", getName())); + String.format("%s _value;\n", getName())); expression.append(String.format("{\n" - + "std::istringstream stream(raw);\n" - + "for(std::string str; stream >> str; ) {\n" - + " value.push_back(%s);\n" + + "std::istringstream _stream(_raw);\n" + + "for(std::string str; _stream >> str; ) {\n" + + " _value.push_back(%s);\n" + "}\n", String.format(rawParsingExpression, "str"))); expression.append("}\n"); } else { expression.append( - String.format("%s %svalue = %s;\n", getName(), + String.format("%s %s_value = %s;\n", getName(), this.name.equals("std::string") ? "&" : "", - String.format(rawParsingExpression, "raw"))); + String.format(rawParsingExpression, "_raw"))); } return expression.toString(); } @@ -83,31 +83,31 @@ class CppSimpleType implements CppType { public String getWritingExpression(String getValue, String name) { StringBuilder expression = new StringBuilder(); if (list) { - expression.append("{\nint count = 0;\n"); - expression.append(String.format("for (const auto& v : %s) {\n", getValue)); + expression.append("{\nint _count = 0;\n"); + expression.append(String.format("for (const auto& _v : %s) {\n", getValue)); String value; if (isEnum) { - value = String.format("%sToString(v)", this.name); + value = String.format("%sToString(_v)", this.name); } else if (this.name.equals("char") || this.name.equals("unsigned char")) { - value = "(int)v"; + value = "(int)_v"; } else if (this.name.equals("bool")) { - value = "(v ? \"true\" : \"false\")"; + value = "(_v ? \"true\" : \"false\")"; } else { - value = "v"; + value = "_v"; } - expression.append("if (count != 0) {\n" - + "out << \" \";\n}\n" - + "++count;\n"); - expression.append(String.format("out << %s;\n}\n}\n", value)); + expression.append("if (_count != 0) {\n" + + "_out << \" \";\n}\n" + + "++_count;\n"); + expression.append(String.format("_out << %s;\n}\n}\n", value)); } else { if (isEnum) { - expression.append(String.format("out << toString(%s);\n", getValue)); + expression.append(String.format("_out << toString(%s);\n", getValue)); } else if (this.name.equals("char") || this.name.equals("unsigned char")) { - expression.append(String.format("out << (int)%s;\n", getValue)); + expression.append(String.format("_out << (int)%s;\n", getValue)); } else if (this.name.equals("bool")) { - expression.append(String.format("out << (%s ? \"true\" : \"false\");\n", getValue)); + expression.append(String.format("_out << (%s ? \"true\" : \"false\");\n", getValue)); } else { - expression.append(String.format("out << %s;\n", getValue)); + expression.append(String.format("_out << %s;\n", getValue)); } } return expression.toString(); diff --git a/src/com/android/xsdc/cpp/CppType.java b/src/main/java/com/android/xsdc/cpp/CppType.java index 05d4da9..1c72d3f 100644 --- a/src/com/android/xsdc/cpp/CppType.java +++ b/src/main/java/com/android/xsdc/cpp/CppType.java @@ -19,6 +19,13 @@ package com.android.xsdc.cpp; interface CppType { String getName(); + /** + * Statements to parse the input to this type. For simple types, + * `_raw(std::string)` should be available. For complex types, + * `_child(T)` should be available. + * + * @return statements declaring `_value` for this type from input + */ String getParsingExpression(); public String getWritingExpression(String getValue, String name); diff --git a/src/com/android/xsdc/cpp/Utils.java b/src/main/java/com/android/xsdc/cpp/Utils.java index d54a9aa..d54a9aa 100644 --- a/src/com/android/xsdc/cpp/Utils.java +++ b/src/main/java/com/android/xsdc/cpp/Utils.java diff --git a/src/com/android/xsdc/java/JavaCodeGenerator.java b/src/main/java/com/android/xsdc/java/JavaCodeGenerator.java index 0025896..0fc2b7c 100644 --- a/src/com/android/xsdc/java/JavaCodeGenerator.java +++ b/src/main/java/com/android/xsdc/java/JavaCodeGenerator.java @@ -23,6 +23,7 @@ import com.android.xsdc.XsdConstants; import com.android.xsdc.tag.*; import java.io.IOException; +import java.util.Arrays; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -41,9 +42,11 @@ public class JavaCodeGenerator { private boolean generateHasMethod; private boolean useHexBinary; private boolean booleanGetter; + private String[] rootElements; public JavaCodeGenerator(XmlSchema xmlSchema, String packageName, boolean writer, - boolean showNullability, boolean generateHasMethod, boolean booleanGetter) + boolean showNullability, boolean generateHasMethod, boolean booleanGetter, + String[] rootElements) throws JavaCodeGeneratorException { this.xmlSchema = xmlSchema; this.packageName = packageName; @@ -51,6 +54,7 @@ public class JavaCodeGenerator { this.showNullability = showNullability; this.generateHasMethod = generateHasMethod; this.booleanGetter = booleanGetter; + this.rootElements = rootElements; useHexBinary = false; // class naming validation @@ -306,69 +310,69 @@ public class JavaCodeGenerator { allAttributeTypes.add(parseSimpleType(type, false)); } - out.printf("static %s%s read(%sorg.xmlpull.v1.XmlPullParser parser) " + + out.printf("static %s%s read(%sorg.xmlpull.v1.XmlPullParser _parser) " + "throws org.xmlpull.v1.XmlPullParserException, java.io.IOException, " + "javax.xml.datatype.DatatypeConfigurationException {\n", getDefaultNullability(Nullability.NON_NULL), name, getDefaultNullability(Nullability.NON_NULL)); - out.printf("%s instance = new %s();\n" - + "String raw = null;\n", name, name); + out.printf("%s _instance = new %s();\n" + + "String _raw = null;\n", name, name); for (int i = 0; i < allAttributes.size(); ++i) { JavaType type = allAttributeTypes.get(i); XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); String variableName = Utils.toVariableName(attribute.getName()); - out.printf("raw = parser.getAttributeValue(null, \"%s\");\n" - + "if (raw != null) {\n", attribute.getName()); + out.printf("_raw = _parser.getAttributeValue(null, \"%s\");\n" + + "if (_raw != null) {\n", attribute.getName()); out.print(type.getParsingExpression()); - out.printf("instance.set%s(value);\n" + out.printf("_instance.set%s(_value);\n" + "}\n", Utils.capitalize(variableName)); } if (baseValueType != null) { - out.print("raw = XmlParser.readText(parser);\n" - + "if (raw != null) {\n"); + out.print("_raw = XmlParser.readText(_parser);\n" + + "if (_raw != null) {\n"); out.print(baseValueType.getParsingExpression()); - out.print("instance.setValue(value);\n" + out.print("_instance.setValue(_value);\n" + "}\n"); } else if (!allElements.isEmpty()) { - out.print("int outerDepth = parser.getDepth();\n" + out.print("int outerDepth = _parser.getDepth();\n" + "int type;\n" - + "while ((type=parser.next()) != org.xmlpull.v1.XmlPullParser.END_DOCUMENT\n" + + "while ((type=_parser.next()) != org.xmlpull.v1.XmlPullParser.END_DOCUMENT\n" + " && type != org.xmlpull.v1.XmlPullParser.END_TAG) {\n" - + "if (parser.getEventType() != org.xmlpull.v1.XmlPullParser.START_TAG) " + + "if (_parser.getEventType() != org.xmlpull.v1.XmlPullParser.START_TAG) " + "continue;\n" - + "String tagName = parser.getName();\n"); + + "String _tagName = _parser.getName();\n"); for (int i = 0; i < allElements.size(); ++i) { JavaType type = allElementTypes.get(i); XsdElement element = allElements.get(i); XsdElement elementValue = resolveElement(element); String variableName = Utils.toVariableName(getElementName(elementValue)); - out.printf("if (tagName.equals(\"%s\")) {\n", elementValue.getName()); + out.printf("if (_tagName.equals(\"%s\")) {\n", elementValue.getName()); if (type instanceof JavaSimpleType) { - out.print("raw = XmlParser.readText(parser);\n"); + out.print("_raw = XmlParser.readText(_parser);\n"); } out.print(type.getParsingExpression()); if (element.isMultiple()) { - out.printf("instance.get%s().add(value);\n", + out.printf("_instance.get%s().add(_value);\n", Utils.capitalize(variableName)); } else { - out.printf("instance.set%s(value);\n", + out.printf("_instance.set%s(_value);\n", Utils.capitalize(variableName)); } out.printf("} else "); } out.print("{\n" - + "XmlParser.skip(parser);\n" + + "XmlParser.skip(_parser);\n" + "}\n" + "}\n"); out.printf("if (type != org.xmlpull.v1.XmlPullParser.END_TAG) {\n" + "throw new javax.xml.datatype.DatatypeConfigurationException(\"%s is not closed\");\n" + "}\n", name); } else { - out.print("XmlParser.skip(parser);\n"); + out.print("XmlParser.skip(_parser);\n"); } - out.print("return instance;\n" + out.print("return _instance;\n" + "}\n"); } @@ -393,27 +397,27 @@ public class JavaCodeGenerator { allAttributeTypes.add(parseSimpleType(type, false)); } - out.printf("\nvoid write(%sXmlWriter out, %sString name) " + + out.printf("\nvoid write(%sXmlWriter _out, %sString _name) " + "throws java.io.IOException {\n", getDefaultNullability(Nullability.NON_NULL), getDefaultNullability(Nullability.NON_NULL)); - out.print("out.print(\"<\" + name);\n"); + out.print("_out.print(\"<\" + _name);\n"); for (int i = 0; i < allAttributes.size(); ++i) { JavaType type = allAttributeTypes.get(i); boolean isList = allAttributeTypes.get(i).isList(); XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); String variableName = Utils.toVariableName(attribute.getName()); out.printf("if (has%s()) {\n", Utils.capitalize(variableName)); - out.printf("out.print(\" %s=\\\"\");\n", attribute.getName()); + out.printf("_out.print(\" %s=\\\"\");\n", attribute.getName()); out.print(type.getWritingExpression(String.format("%s%s()", getterName(type.getName()), Utils.capitalize(variableName)), attribute.getName())); - out.printf("out.print(\"\\\"\");\n}\n"); + out.printf("_out.print(\"\\\"\");\n}\n"); } - out.printf("out.print(\">\\n\");\n"); + out.printf("_out.print(\">\\n\");\n"); if (!allElements.isEmpty()) { - out.printf("out.increaseIndent();\n"); + out.printf("_out.increaseIndent();\n"); for (int i = 0; i < allElements.size(); ++i) { JavaType type = allElementTypes.get(i); XsdElement element = allElements.get(i); @@ -425,31 +429,31 @@ public class JavaCodeGenerator { out.printf("for (%s value : get%s()) {\n", type.getName(), Utils.capitalize(variableName)); if (type instanceof JavaSimpleType) { - out.printf("out.print(\"<%s>\");\n", elementValue.getName()); + out.printf("_out.print(\"<%s>\");\n", elementValue.getName()); } out.print(type.getWritingExpression("value", elementValue.getName())); if (type instanceof JavaSimpleType) { - out.printf("out.print(\"</%s>\\n\");\n", elementValue.getName()); + out.printf("_out.print(\"</%s>\\n\");\n", elementValue.getName()); } out.print("}\n"); } else { out.printf("if (has%s()) {\n", Utils.capitalize(variableName)); if (type instanceof JavaSimpleType) { - out.printf("out.print(\"<%s>\");\n", elementValue.getName()); + out.printf("_out.print(\"<%s>\");\n", elementValue.getName()); } out.print(type.getWritingExpression(String.format("%s%s()", getterName(type.getName()), Utils.capitalize(variableName)), elementValue.getName())); if (type instanceof JavaSimpleType) { - out.printf("out.print(\"</%s>\\n\");\n", elementValue.getName()); + out.printf("_out.print(\"</%s>\\n\");\n", elementValue.getName()); } out.printf("}\n"); } } - out.printf("out.decreaseIndent();\n"); + out.printf("_out.decreaseIndent();\n"); } - out.print("out.print(\"</\" + name + \">\\n\");\n"); + out.print("_out.print(\"</\" + _name + \">\\n\");\n"); out.print("}\n"); } @@ -509,26 +513,33 @@ public class JavaCodeGenerator { boolean isMultiRootElement = xmlSchema.getElementMap().values().size() > 1; for (XsdElement element : xmlSchema.getElementMap().values()) { + // Skip parser if not specified as root. + if (rootElements != null + && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; JavaType javaType = parseType(element.getType(), element.getName()); + String elementName = element.getName(); + String typeName = javaType.getName(); + String readerName = + javaType instanceof JavaSimpleType ? Utils.toClassName(elementName) : typeName; out.printf("public static %s%s read%s(%sjava.io.InputStream in)" - + " throws org.xmlpull.v1.XmlPullParserException, java.io.IOException, " - + "javax.xml.datatype.DatatypeConfigurationException {\n" - + "org.xmlpull.v1.XmlPullParser parser = org.xmlpull.v1.XmlPullParserFactory" - + ".newInstance().newPullParser();\n" - + "parser.setFeature(org.xmlpull.v1.XmlPullParser.FEATURE_PROCESS_NAMESPACES, " - + "true);\n" - + "parser.setInput(in, null);\n" - + "parser.nextTag();\n" - + "String tagName = parser.getName();\n" - + "String raw = null;\n", getDefaultNullability(Nullability.NULLABLE), - javaType.getName(), isMultiRootElement ? Utils.capitalize(javaType.getName()) : "", - getDefaultNullability(Nullability.NON_NULL)); - out.printf("if (tagName.equals(\"%s\")) {\n", element.getName()); + + " throws org.xmlpull.v1.XmlPullParserException, java.io.IOException, " + + "javax.xml.datatype.DatatypeConfigurationException {\n" + + "org.xmlpull.v1.XmlPullParser _parser = org.xmlpull.v1.XmlPullParserFactory" + + ".newInstance().newPullParser();\n" + + "_parser.setFeature(org.xmlpull.v1.XmlPullParser.FEATURE_PROCESS_NAMESPACES, " + + "true);\n" + + "_parser.setInput(in, null);\n" + + "_parser.nextTag();\n" + + "String _tagName = _parser.getName();\n" + + "String _raw = null;\n", getDefaultNullability(Nullability.NULLABLE), + typeName, isMultiRootElement ? readerName : "", + getDefaultNullability(Nullability.NON_NULL)); + out.printf("if (_tagName.equals(\"%s\")) {\n", elementName); if (javaType instanceof JavaSimpleType) { - out.print("raw = XmlParser.readText(parser);\n"); + out.print("_raw = XmlParser.readText(_parser);\n"); } out.print(javaType.getParsingExpression()); - out.print("return value;\n" + out.print("return _value;\n" + "}\n" + "return null;\n" + "}\n"); @@ -536,12 +547,12 @@ public class JavaCodeGenerator { } out.printf( - "public static %sjava.lang.String readText(%sorg.xmlpull.v1.XmlPullParser parser)" + "public static %sjava.lang.String readText(%sorg.xmlpull.v1.XmlPullParser _parser)" + " throws org.xmlpull.v1.XmlPullParserException, java.io.IOException {\n" + "String result = \"\";\n" - + "if (parser.next() == org.xmlpull.v1.XmlPullParser.TEXT) {\n" - + " result = parser.getText();\n" - + " parser.nextTag();\n" + + "if (_parser.next() == org.xmlpull.v1.XmlPullParser.TEXT) {\n" + + " result = _parser.getText();\n" + + " _parser.nextTag();\n" + "}\n" + "return result;\n" + "}\n", getDefaultNullability(Nullability.NULLABLE), @@ -549,14 +560,14 @@ public class JavaCodeGenerator { out.println(); out.printf( - "public static void skip(%sorg.xmlpull.v1.XmlPullParser parser)" + "public static void skip(%sorg.xmlpull.v1.XmlPullParser _parser)" + " throws org.xmlpull.v1.XmlPullParserException, java.io.IOException {\n" - + "if (parser.getEventType() != org.xmlpull.v1.XmlPullParser.START_TAG) {\n" + + "if (_parser.getEventType() != org.xmlpull.v1.XmlPullParser.START_TAG) {\n" + " throw new IllegalStateException();\n" + "}\n" + "int depth = 1;\n" + "while (depth != 0) {\n" - + " switch (parser.next()) {\n" + + " switch (_parser.next()) {\n" + " case org.xmlpull.v1.XmlPullParser.END_TAG:\n" + " depth--;\n" + " break;\n" @@ -622,18 +633,31 @@ public class JavaCodeGenerator { for (XsdElement element : xmlSchema.getElementMap().values()) { + // Skip writer if not specified as root. + if (rootElements != null + && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; JavaType javaType = parseType(element.getType(), element.getName()); String elementName = element.getName(); - String VariableName = Utils.toVariableName(elementName); - String typeName = javaType instanceof JavaSimpleType ? javaType.getName() : - Utils.toClassName(javaType.getName()); - out.printf("public static void write(%sXmlWriter out, %s%s %s) " - + "throws java.io.IOException {", getDefaultNullability(Nullability.NON_NULL), - getDefaultNullability(Nullability.NON_NULL), typeName, VariableName); - out.print("\nout.print(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\");\n"); - out.printf("if (%s != null) {\n", VariableName); - out.printf("%s.write(out, \"%s\");\n}\n", VariableName, elementName); - out.print("out.printXml();\n}\n\n"); + String variableName = Utils.toVariableName(elementName); + String typeName = javaType.getName(); + String writerName + = javaType instanceof JavaSimpleType ? Utils.toClassName(elementName) : ""; + out.printf("public static void write%s(%sXmlWriter _out, %s%s %s) " + + "throws java.io.IOException {", + writerName, + getDefaultNullability(Nullability.NON_NULL), + getDefaultNullability(Nullability.NON_NULL), typeName, variableName); + out.print("\n_out.print(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\");\n"); + out.printf("if (%s != null) {\n", variableName); + if (javaType instanceof JavaSimpleType) { + out.printf("_out.print(\"<%s>\");\n", elementName); + out.print(javaType.getWritingExpression(variableName, "")); + out.printf("_out.print(\"</%s>\\n\");\n", elementName); + } else { + out.printf("%s.write(_out, \"%s\");\n", variableName, elementName); + } + out.print("}\n"); + out.print("_out.printXml();\n}\n\n"); } out.printf("}\n"); } diff --git a/src/com/android/xsdc/java/JavaCodeGeneratorException.java b/src/main/java/com/android/xsdc/java/JavaCodeGeneratorException.java index b37a284..b37a284 100644 --- a/src/com/android/xsdc/java/JavaCodeGeneratorException.java +++ b/src/main/java/com/android/xsdc/java/JavaCodeGeneratorException.java diff --git a/src/com/android/xsdc/java/JavaComplexType.java b/src/main/java/com/android/xsdc/java/JavaComplexType.java index 1a66794..e25acd7 100644 --- a/src/com/android/xsdc/java/JavaComplexType.java +++ b/src/main/java/com/android/xsdc/java/JavaComplexType.java @@ -40,11 +40,11 @@ class JavaComplexType implements JavaType { @Override public String getParsingExpression() { - return String.format("%s value = %s.read(parser);\n", name, name); + return String.format("%s _value = %s.read(_parser);\n", name, name); } @Override public String getWritingExpression(String getValue, String name) { - return String.format("%s.write(out, \"%s\");\n", getValue, name); + return String.format("%s.write(_out, \"%s\");\n", getValue, name); } } diff --git a/src/com/android/xsdc/java/JavaSimpleType.java b/src/main/java/com/android/xsdc/java/JavaSimpleType.java index 5c73466..5ad905f 100644 --- a/src/com/android/xsdc/java/JavaSimpleType.java +++ b/src/main/java/com/android/xsdc/java/JavaSimpleType.java @@ -74,15 +74,15 @@ class JavaSimpleType implements JavaType { StringBuilder expression = new StringBuilder(); if (list) { expression.append( - String.format("%s value = new java.util.ArrayList<>();\n", getName())); - expression.append("for (String token : raw.split(\"\\\\s+\")) {\n"); - expression.append(String.format("value.add(%s);\n", - String.format(rawParsingExpression, "token"))); + String.format("%s _value = new java.util.ArrayList<>();\n", getName())); + expression.append("for (String _token : _raw.split(\"\\\\s+\")) {\n"); + expression.append(String.format("_value.add(%s);\n", + String.format(rawParsingExpression, "_token"))); expression.append("}\n"); } else { expression.append( - String.format("%s value = %s;\n", getName(), - String.format(rawParsingExpression, "raw"))); + String.format("%s _value = %s;\n", getName(), + String.format(rawParsingExpression, "_raw"))); } return expression.toString(); } @@ -91,16 +91,16 @@ class JavaSimpleType implements JavaType { public String getWritingExpression(String getValue, String name) { StringBuilder expression = new StringBuilder(); if (list) { - expression.append("{\nint count = 0;\n"); + expression.append("{\nint _count = 0;\n"); expression.append(String.format("for (%s v : %s) {\n", this.name, getValue)); - expression.append("if (count != 0) {\n" - + "out.print(\" \");\n}\n" - + "++count;\n"); - expression.append(String.format("out.print(%s);\n}\n", + expression.append("if (_count != 0) {\n" + + "_out.print(\" \");\n}\n" + + "++_count;\n"); + expression.append(String.format("_out.print(%s);\n}\n", String.format(rawWritingExpression, "v"))); expression.append("}\n"); } else { - expression.append(String.format("out.print(%s);\n", + expression.append(String.format("_out.print(%s);\n", String.format(rawWritingExpression, getValue))); } return expression.toString(); diff --git a/src/com/android/xsdc/java/JavaType.java b/src/main/java/com/android/xsdc/java/JavaType.java index 8605f5d..8605f5d 100644 --- a/src/com/android/xsdc/java/JavaType.java +++ b/src/main/java/com/android/xsdc/java/JavaType.java diff --git a/src/com/android/xsdc/java/Utils.java b/src/main/java/com/android/xsdc/java/Utils.java index 5a7a92a..5a7a92a 100644 --- a/src/com/android/xsdc/java/Utils.java +++ b/src/main/java/com/android/xsdc/java/Utils.java diff --git a/src/com/android/xsdc/tag/Nullability.java b/src/main/java/com/android/xsdc/tag/Nullability.java index 9e81635..9e81635 100644 --- a/src/com/android/xsdc/tag/Nullability.java +++ b/src/main/java/com/android/xsdc/tag/Nullability.java diff --git a/src/com/android/xsdc/tag/XsdAll.java b/src/main/java/com/android/xsdc/tag/XsdAll.java index 39c2562..39c2562 100644 --- a/src/com/android/xsdc/tag/XsdAll.java +++ b/src/main/java/com/android/xsdc/tag/XsdAll.java diff --git a/src/com/android/xsdc/tag/XsdAttribute.java b/src/main/java/com/android/xsdc/tag/XsdAttribute.java index 0c46eb0..0c46eb0 100644 --- a/src/com/android/xsdc/tag/XsdAttribute.java +++ b/src/main/java/com/android/xsdc/tag/XsdAttribute.java diff --git a/src/com/android/xsdc/tag/XsdAttributeGroup.java b/src/main/java/com/android/xsdc/tag/XsdAttributeGroup.java index 6c8f853..6c8f853 100644 --- a/src/com/android/xsdc/tag/XsdAttributeGroup.java +++ b/src/main/java/com/android/xsdc/tag/XsdAttributeGroup.java diff --git a/src/com/android/xsdc/tag/XsdChoice.java b/src/main/java/com/android/xsdc/tag/XsdChoice.java index 223bb44..223bb44 100644 --- a/src/com/android/xsdc/tag/XsdChoice.java +++ b/src/main/java/com/android/xsdc/tag/XsdChoice.java diff --git a/src/com/android/xsdc/tag/XsdComplexContent.java b/src/main/java/com/android/xsdc/tag/XsdComplexContent.java index aa9de87..aa9de87 100644 --- a/src/com/android/xsdc/tag/XsdComplexContent.java +++ b/src/main/java/com/android/xsdc/tag/XsdComplexContent.java diff --git a/src/com/android/xsdc/tag/XsdComplexType.java b/src/main/java/com/android/xsdc/tag/XsdComplexType.java index a7e0311..a7e0311 100644 --- a/src/com/android/xsdc/tag/XsdComplexType.java +++ b/src/main/java/com/android/xsdc/tag/XsdComplexType.java diff --git a/src/com/android/xsdc/tag/XsdElement.java b/src/main/java/com/android/xsdc/tag/XsdElement.java index 40a6695..40a6695 100644 --- a/src/com/android/xsdc/tag/XsdElement.java +++ b/src/main/java/com/android/xsdc/tag/XsdElement.java diff --git a/src/com/android/xsdc/tag/XsdEnumRestriction.java b/src/main/java/com/android/xsdc/tag/XsdEnumRestriction.java index 3ae7ae0..3ae7ae0 100644 --- a/src/com/android/xsdc/tag/XsdEnumRestriction.java +++ b/src/main/java/com/android/xsdc/tag/XsdEnumRestriction.java diff --git a/src/com/android/xsdc/tag/XsdEnumeration.java b/src/main/java/com/android/xsdc/tag/XsdEnumeration.java index 2f9fdc0..2f9fdc0 100644 --- a/src/com/android/xsdc/tag/XsdEnumeration.java +++ b/src/main/java/com/android/xsdc/tag/XsdEnumeration.java diff --git a/src/com/android/xsdc/tag/XsdGeneralExtension.java b/src/main/java/com/android/xsdc/tag/XsdGeneralExtension.java index 24043e4..24043e4 100644 --- a/src/com/android/xsdc/tag/XsdGeneralExtension.java +++ b/src/main/java/com/android/xsdc/tag/XsdGeneralExtension.java diff --git a/src/com/android/xsdc/tag/XsdGeneralRestriction.java b/src/main/java/com/android/xsdc/tag/XsdGeneralRestriction.java index 6583622..6583622 100644 --- a/src/com/android/xsdc/tag/XsdGeneralRestriction.java +++ b/src/main/java/com/android/xsdc/tag/XsdGeneralRestriction.java diff --git a/src/com/android/xsdc/tag/XsdGroup.java b/src/main/java/com/android/xsdc/tag/XsdGroup.java index dd8f008..dd8f008 100644 --- a/src/com/android/xsdc/tag/XsdGroup.java +++ b/src/main/java/com/android/xsdc/tag/XsdGroup.java diff --git a/src/com/android/xsdc/tag/XsdList.java b/src/main/java/com/android/xsdc/tag/XsdList.java index 70023c8..70023c8 100644 --- a/src/com/android/xsdc/tag/XsdList.java +++ b/src/main/java/com/android/xsdc/tag/XsdList.java diff --git a/src/com/android/xsdc/tag/XsdRestriction.java b/src/main/java/com/android/xsdc/tag/XsdRestriction.java index 17dfdd5..17dfdd5 100644 --- a/src/com/android/xsdc/tag/XsdRestriction.java +++ b/src/main/java/com/android/xsdc/tag/XsdRestriction.java diff --git a/src/com/android/xsdc/tag/XsdSimpleContent.java b/src/main/java/com/android/xsdc/tag/XsdSimpleContent.java index cefa60e..cefa60e 100644 --- a/src/com/android/xsdc/tag/XsdSimpleContent.java +++ b/src/main/java/com/android/xsdc/tag/XsdSimpleContent.java diff --git a/src/com/android/xsdc/tag/XsdSimpleType.java b/src/main/java/com/android/xsdc/tag/XsdSimpleType.java index c7d7e37..c7d7e37 100644 --- a/src/com/android/xsdc/tag/XsdSimpleType.java +++ b/src/main/java/com/android/xsdc/tag/XsdSimpleType.java diff --git a/src/com/android/xsdc/tag/XsdTag.java b/src/main/java/com/android/xsdc/tag/XsdTag.java index 3397267..3397267 100644 --- a/src/com/android/xsdc/tag/XsdTag.java +++ b/src/main/java/com/android/xsdc/tag/XsdTag.java diff --git a/src/com/android/xsdc/tag/XsdType.java b/src/main/java/com/android/xsdc/tag/XsdType.java index a7e41a0..a7e41a0 100644 --- a/src/com/android/xsdc/tag/XsdType.java +++ b/src/main/java/com/android/xsdc/tag/XsdType.java diff --git a/src/com/android/xsdc/tag/XsdUnion.java b/src/main/java/com/android/xsdc/tag/XsdUnion.java index f738330..f738330 100644 --- a/src/com/android/xsdc/tag/XsdUnion.java +++ b/src/main/java/com/android/xsdc/tag/XsdUnion.java diff --git a/src/test/java/com/android/xsdc/cpp/TestCppCodeGenerator.java b/src/test/java/com/android/xsdc/cpp/TestCppCodeGenerator.java new file mode 100644 index 0000000..6106696 --- /dev/null +++ b/src/test/java/com/android/xsdc/cpp/TestCppCodeGenerator.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.xsdc.cpp; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.android.xsdc.FileSystem; +import com.android.xsdc.XmlSchema; +import com.android.xsdc.XsdHandler; + +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +public class TestCppCodeGenerator { + public static final String SCHEMA = "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" + + " <xs:element name=\"class\" type=\"xs:string\" />\n" + + "</xs:schema>"; + + @Test + public void testParseSchema() throws Exception { + XmlSchema schema = parseSchema(SCHEMA); + assertEquals(schema.getElementMap().keySet(), Set.of("class")); + } + + @Test + public void testSimpleTypeRootParser() throws Exception { + // We need two root elements to generate reader with element name. + String schema = "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" + + " <xs:element name=\"simple-type-element\" type=\"xs:string\" />\n" + + " <xs:element name=\"another-root\" type=\"xs:string\" />\n" + + "</xs:schema>"; + Map<String, StringBuffer> files = new TreeMap<>(); + CppCodeGenerator gen = + new CppCodeGenerator( + parseSchema(schema), + "com.abc", + /*writer=*/ true, + CppCodeGenerator.GENERATE_PARSER, + false, + false, + null); + + FileSystem fs = new FileSystem(files); + gen.print(fs); + assertTrue(files.get("com_abc.cpp").toString().contains("readSimpleTypeElement")); + assertTrue(files.get("com_abc.cpp").toString().contains("writeSimpleTypeElement")); + } + + @Test + public void testPrintWithoutEnumOutput() throws Exception { + Map<String, StringBuffer> files = new TreeMap<>(); + CppCodeGenerator gen = + new CppCodeGenerator( + parseSchema(SCHEMA), + "com.abc", + false, + CppCodeGenerator.GENERATE_PARSER, + false, + false, + null); + + FileSystem fs = new FileSystem(files); + gen.print(fs); + + assertEquals(files.keySet(), Set.of("com_abc.cpp", "include/com_abc.h")); + } + + @Test + public void printWithEnumOutput() throws Exception { + Map<String, StringBuffer> files = new TreeMap<>(); + + CppCodeGenerator gen = + new CppCodeGenerator( + parseSchema(SCHEMA), + "com.abc", + false, + CppCodeGenerator.GENERATE_PARSER | CppCodeGenerator.GENERATE_ENUMS, + false, + false, + null); + + FileSystem fs = new FileSystem(files); + gen.print(fs); + + assertEquals( + files.keySet(), + Set.of( + "com_abc.cpp", + "include/com_abc.h", + "com_abc_enums.cpp", + "include/com_abc_enums.h")); + } + + private XmlSchema parseSchema(String contents) throws Exception { + byte[] bytes = contents.getBytes(StandardCharsets.UTF_8); + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + SAXParser parser = factory.newSAXParser(); + XsdHandler xsdHandler = new XsdHandler(); + parser.parse(new ByteArrayInputStream(bytes), xsdHandler); + return xsdHandler.getSchema(); + } + + @Test + public void generateParsersForSpecifiedRoot() throws Exception { + Map<String, StringBuffer> files = new TreeMap<>(); + String schema = "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" + + " <xs:element name=\"root1\" type=\"xs:string\" />\n" + + " <xs:element name=\"root2\" type=\"xs:string\" />\n" + + "</xs:schema>"; + CppCodeGenerator gen = + new CppCodeGenerator( + parseSchema(schema), + "com.abc", + false, + CppCodeGenerator.GENERATE_PARSER | CppCodeGenerator.GENERATE_ENUMS, + false, + false, + new String[]{"root1"}); + + FileSystem fs = new FileSystem(files); + gen.print(fs); + assertTrue(files.get("com_abc.cpp").toString().contains("readRoot1")); + assertFalse(files.get("com_abc.cpp").toString().contains("readRoot2")); + } +} diff --git a/tests/resources/simple_complex_content/api/current.txt b/tests/resources/simple_complex_content/api/current.txt index 043fb50..785e014 100644 --- a/tests/resources/simple_complex_content/api/current.txt +++ b/tests/resources/simple_complex_content/api/current.txt @@ -24,14 +24,17 @@ package simple.complex.content { method public String getName(); method public simple.complex.content.SubAddress getSubAddress(); method public simple.complex.content.USAddressP getUSAddressP(); + method public simple.complex.content.KRAddress getValue(); method public boolean hasKRAddress(); method public boolean hasName(); method public boolean hasSubAddress(); method public boolean hasUSAddressP(); + method public boolean hasValue(); method public void setKRAddress(simple.complex.content.KRAddress); method public void setName(String); method public void setSubAddress(simple.complex.content.SubAddress); method public void setUSAddressP(simple.complex.content.USAddressP); + method public void setValue(simple.complex.content.KRAddress); } public class Person2 { @@ -40,14 +43,17 @@ package simple.complex.content { method public String getName(); method @NonNull public simple.complex.content.SubAddress getSubAddress(); method public simple.complex.content.USAddressP getUSAddressP(); + method public String getValue(); method public boolean hasKRAddress(); method public boolean hasName(); method public boolean hasSubAddress(); method public boolean hasUSAddressP(); + method public boolean hasValue(); method public void setKRAddress(simple.complex.content.KRAddress); method public void setName(String); method public void setSubAddress(@NonNull simple.complex.content.SubAddress); method public void setUSAddressP(simple.complex.content.USAddressP); + method public void setValue(String); } public class SubAddress { diff --git a/tests/resources/simple_complex_content/simple_complex_content.xsd b/tests/resources/simple_complex_content/simple_complex_content.xsd index 62a6497..7bb57b5 100644 --- a/tests/resources/simple_complex_content/simple_complex_content.xsd +++ b/tests/resources/simple_complex_content/simple_complex_content.xsd @@ -50,6 +50,7 @@ <xs:element name="USAddressP" type="USAddressP"/> <xs:element name="KRAddress" type="KRAddress"/> <xs:element name="subAddress" type="subAddress"/> + <xs:element name="value" type="KRAddress" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> @@ -62,6 +63,7 @@ <xs:element name="subAddress" type="subAddress"> <xs:annotation name="nonnull"/> </xs:element> + <xs:element name="value" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> diff --git a/tests/resources/simple_type/api/current.txt b/tests/resources/simple_type/api/current.txt index 0b163a5..8368c23 100644 --- a/tests/resources/simple_type/api/current.txt +++ b/tests/resources/simple_type/api/current.txt @@ -18,16 +18,20 @@ package simple.type { public class SimpleTypes { ctor public SimpleTypes(); method public java.util.List<java.lang.Integer> getListInt(); + method public java.util.List<java.lang.Integer> getOptionalIntList(); method public java.util.List<java.lang.String> getUnionTest(); method public java.util.List<simple.type.EnumType> getYesOrNo(); method public boolean isExample1(); method public boolean isExample2(); method public boolean isExample3(); + method public boolean isValue(); method public void setExample1(boolean); method public void setExample2(boolean); method public void setExample3(boolean); method public void setListInt(java.util.List<java.lang.Integer>); + method public void setOptionalIntList(java.util.List<java.lang.Integer>); method public void setUnionTest(java.util.List<java.lang.String>); + method public void setValue(boolean); } public class SingleChoice { @@ -43,6 +47,7 @@ package simple.type { public class XmlParser { ctor public XmlParser(); method public static simple.type.MultiChoice readMultiChoice(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static java.math.BigInteger readPercent(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public static simple.type.SimpleTypes readSimpleTypes(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public static simple.type.SingleChoice readSingleChoice(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; @@ -55,6 +60,7 @@ package simple.type { method public static void write(simple.type.XmlWriter, simple.type.SimpleTypes) throws java.io.IOException; method public static void write(simple.type.XmlWriter, simple.type.MultiChoice) throws java.io.IOException; method public static void write(simple.type.XmlWriter, simple.type.SingleChoice) throws java.io.IOException; + method public static void writePercent(simple.type.XmlWriter, java.math.BigInteger) throws java.io.IOException; } } diff --git a/tests/resources/simple_type/simple_type.xsd b/tests/resources/simple_type/simple_type.xsd index 481c476..9bbd283 100644 --- a/tests/resources/simple_type/simple_type.xsd +++ b/tests/resources/simple_type/simple_type.xsd @@ -33,8 +33,10 @@ <xs:element name="yesOrNo" type="enumType" maxOccurs="2"/> <xs:element name="example1" type="xs:boolean"/> <xs:element name="example2" type="xs:boolean"/> + <xs:element name="optional-int-list" maxOccurs="1" type="ints"/> </xs:sequence> <xs:attribute name="example3" type="xs:boolean"/> + <xs:attribute name="value" type="xs:boolean"/> </xs:complexType> </xs:element> <xs:element name="multi-choice"> @@ -55,4 +57,5 @@ </xs:choice> </xs:complexType> </xs:element> + <xs:element name="percent" type="percent" /> </xs:schema> diff --git a/tests/resources/simple_type_root.xml b/tests/resources/simple_type_root.xml new file mode 100644 index 0000000..a6fed4f --- /dev/null +++ b/tests/resources/simple_type_root.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?> +<percent>100</percent> diff --git a/tests/simple_type.cpp b/tests/simple_type.cpp index 5162c6d..3f1b2de 100644 --- a/tests/simple_type.cpp +++ b/tests/simple_type.cpp @@ -16,6 +16,7 @@ #include <iostream> #include <fstream> +#include <sstream> #include <android-base/macros.h> @@ -50,3 +51,28 @@ TEST_F(XmlTest, Simpletype) { EXPECT_EQ(simple.getYesOrNo()[0], simple2.getYesOrNo()[0]); EXPECT_EQ(simple.getYesOrNo()[1], simple2.getYesOrNo()[1]); } + +TEST_F(XmlTest, Simpletype_AccessingEmptyOptionalAbortsWithMessage) { + using namespace simple::type; + + string file_name = Resource("simple_type.xml"); + SimpleTypes simple = *readSimpleTypes(file_name.c_str()); + + // trying to get the value for optional attribute + ASSERT_DEATH(simple.isExample3(), "hasExample3()"); + // trying to get the value for optional element + ASSERT_DEATH(simple.getOptionalIntList(), "hasOptionalIntList()"); + // trying to get the first value from optional element of list of simple values + ASSERT_DEATH(simple.getFirstOptionalIntList(), "hasOptionalIntList()"); +} + +TEST_F(XmlTest, SimpleTypeRoot) { + using namespace simple::type; + + string file_name = Resource("simple_type_root.xml"); + ASSERT_EQ(*readPercent(file_name.c_str()), 100); + + ostringstream out; + writePercent(out, 100); + ASSERT_EQ(out.str(), "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<percent>100</percent>\n"); +} diff --git a/tests/src/com/android/xsdc/tests/XmlParserTest.java b/tests/src/com/android/xsdc/tests/XmlParserTest.java index f3b5eaf..bb54099 100644 --- a/tests/src/com/android/xsdc/tests/XmlParserTest.java +++ b/tests/src/com/android/xsdc/tests/XmlParserTest.java @@ -248,6 +248,31 @@ public class XmlParserTest { } @Test + public void testSimpleTypeRoot() throws Exception { + BigInteger percent; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "simple_type_root.xml")) { + percent = simple.type.XmlParser.readPercent(str); + } + + assertThat(percent, is(BigInteger.valueOf(100))); + + String actualStr, expectedStr; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "simple_type_root.xml")) { + expectedStr = new String(str.readAllBytes()); + } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try(simple.type.XmlWriter writer = new simple.type.XmlWriter(new PrintWriter(baos))) { + simple.type.XmlWriter.writePercent(writer, percent); + } + actualStr = new String(baos.toByteArray()); + } + + assertThat(new String(actualStr), is(expectedStr)); + } + + @Test public void testReference() throws Exception { reference.Class _class; try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( |