diff options
60 files changed, 3357 insertions, 981 deletions
@@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_binary_host { name: "xsdc", srcs: ["src/**/*.java"], @@ -5,4 +9,4 @@ java_binary_host { "commons-cli-1.2", ], manifest: "MANIFEST.MF" -}
\ No newline at end of file +} diff --git a/build/Android.bp b/build/Android.bp index befa978..446cd8f 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "xsdc-soong-rules", pkgPath: "android/soong/xsdc", diff --git a/build/xsdc.go b/build/xsdc.go index 0546ec4..3a09d71 100644 --- a/build/xsdc.go +++ b/build/xsdc.go @@ -39,19 +39,19 @@ 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 && ` + + `${xsdcCmd} $in -p $pkgName -o ${out}.temp -j $args && ` + `${config.SoongZipCmd} -jar -o ${out} -C ${out}.temp -D ${out}.temp && ` + `rm -rf ${out}.temp`, CommandDeps: []string{"${xsdcCmd}", "${config.SoongZipCmd}"}, Description: "xsdc Java ${in} => ${out}", - }, "pkgName") + }, "pkgName", "args") xsdcCppRule = pctx.StaticRule("xsdcCppRule", blueprint.RuleParams{ Command: `rm -rf "${outDir}" && ` + - `${xsdcCmd} $in -p $pkgName -o ${outDir} -c`, + `${xsdcCmd} $in -p $pkgName -o ${outDir} -c $args`, CommandDeps: []string{"${xsdcCmd}", "${config.SoongZipCmd}"}, Description: "xsdc C++ ${in} => ${out}", - }, "pkgName", "outDir") + }, "pkgName", "outDir", "args") xsdConfigRule = pctx.StaticRule("xsdConfigRule", blueprint.RuleParams{ Command: "cp -f ${in} ${output}", @@ -63,6 +63,23 @@ type xsdConfigProperties struct { Srcs []string Package_name *string Api_dir *string + Gen_writer *bool + Nullability *bool + + // Whether has{element or atrribute} methods are set to public. + // It is not applied to C++, because these methods are always + // generated to public for C++. + Gen_has *bool + // Only generate code for enum converters. Applies to C++ only. + // This is useful for memory footprint reduction since it avoids + // depending on libxml2. + Enums_only *bool + // Only generate complementary code for XML parser. Applies to C++ only. + // The code being generated depends on the enum converters module. + Parser_only *bool + // Whether getter name of boolean element or attribute is getX or isX. + // Default value is false. If the property is true, getter name is isX. + Boolean_getter *bool } type xsdConfig struct { @@ -72,13 +89,13 @@ type xsdConfig struct { genOutputDir android.Path genOutputs_j android.WritablePath - genOutputs_c android.WritablePath - genOutputs_h android.WritablePath + genOutputs_c android.WritablePaths + genOutputs_h android.WritablePaths docsPath android.Path xsdConfigPath android.OptionalPath - genOutputs android.Paths + genOutputs android.Paths } var _ android.SourceFileProducer = (*xsdConfig)(nil) @@ -105,7 +122,7 @@ type DroidstubsProperties struct { } func (module *xsdConfig) GeneratedSourceFiles() android.Paths { - return android.Paths{module.genOutputs_c} + return module.genOutputs_c.Paths() } func (module *xsdConfig) Srcs() android.Paths { @@ -113,7 +130,7 @@ func (module *xsdConfig) Srcs() android.Paths { } func (module *xsdConfig) GeneratedDeps() android.Paths { - return android.Paths{module.genOutputs_h} + return module.genOutputs_h.Paths() } func (module *xsdConfig) GeneratedHeaderDirs() android.Paths { @@ -159,6 +176,31 @@ func (module *xsdConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) pkgName := *module.properties.Package_name filenameStem := strings.Replace(pkgName, ".", "_", -1) + args := "" + if proptools.Bool(module.properties.Gen_writer) { + args = "-w" + } + + if proptools.Bool(module.properties.Nullability) { + args = args + " -n " + } + + if proptools.Bool(module.properties.Gen_has) { + args = args + " -g " + } + + if proptools.Bool(module.properties.Enums_only) { + args = args + " -e " + } + + if proptools.Bool(module.properties.Parser_only) { + args = args + " -x " + } + + if proptools.Bool(module.properties.Boolean_getter) { + args = args + " -b " + } + module.genOutputs_j = android.PathForModuleGen(ctx, "java", filenameStem+"_xsdcgen.srcjar") ctx.Build(pctx, android.BuildParams{ @@ -169,23 +211,41 @@ func (module *xsdConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) Output: module.genOutputs_j, Args: map[string]string{ "pkgName": pkgName, + "args": args, }, }) - module.genOutputs_c = android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp") - module.genOutputs_h = android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h") + if proptools.Bool(module.properties.Enums_only) { + module.genOutputs_c = android.WritablePaths{ + android.PathForModuleGen(ctx, "cpp", filenameStem+"_enums.cpp")} + module.genOutputs_h = android.WritablePaths{ + android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+"_enums.h")} + } else if proptools.Bool(module.properties.Parser_only) { + module.genOutputs_c = android.WritablePaths{ + android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp")} + module.genOutputs_h = android.WritablePaths{ + android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h")} + } else { + module.genOutputs_c = android.WritablePaths{ + android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp"), + android.PathForModuleGen(ctx, "cpp", filenameStem+"_enums.cpp")} + module.genOutputs_h = android.WritablePaths{ + android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h"), + android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+"_enums.h")} + } module.genOutputDir = android.PathForModuleGen(ctx, "cpp", "include") ctx.Build(pctx, android.BuildParams{ - Rule: xsdcCppRule, - Description: "xsdc " + xsdFile.String(), - Input: xsdFile, - Implicit: module.docsPath, - Output: module.genOutputs_c, - ImplicitOutput: module.genOutputs_h, + Rule: xsdcCppRule, + Description: "xsdc " + xsdFile.String(), + Input: xsdFile, + Implicit: module.docsPath, + Outputs: module.genOutputs_c, + ImplicitOutputs: module.genOutputs_h, Args: map[string]string{ "pkgName": pkgName, "outDir": android.PathForModuleGen(ctx, "cpp").String(), + "args": args, }, }) module.xsdConfigPath = android.ExistentPathForSource(ctx, xsdFile.String()) diff --git a/src/com/android/xsdc/CodeWriter.java b/src/com/android/xsdc/CodeWriter.java index 1ffe801..489ccdc 100644 --- a/src/com/android/xsdc/CodeWriter.java +++ b/src/com/android/xsdc/CodeWriter.java @@ -24,6 +24,10 @@ public class CodeWriter implements Closeable { private int indent; private boolean startLine; + public CodeWriter() { + this(null); + } + public CodeWriter(PrintWriter printWriter) { out = printWriter; indent = 0; @@ -33,13 +37,15 @@ public class CodeWriter implements Closeable { private void printIndent() { assert startLine; for (int i = 0; i < indent; ++i) { - out.print(" "); + printImpl(" "); } startLine = false; } public void println() { - out.println(); + if (out != null) { + out.println(); + } startLine = true; } @@ -58,13 +64,12 @@ public class CodeWriter implements Closeable { if (startLine && !line.isEmpty()) { printIndent(); } - out.print(line); + printImpl(line); if (line.endsWith("{")) { ++indent; } if (i + 1 < lines.length) { - out.println(); - startLine = true; + println(); } } } @@ -79,4 +84,10 @@ public class CodeWriter implements Closeable { out.close(); } } + + private void printImpl(String code) { + if (out != null) { + out.print(code); + } + } } diff --git a/src/com/android/xsdc/Main.java b/src/com/android/xsdc/Main.java index b8f6dd3..0358f08 100644 --- a/src/com/android/xsdc/Main.java +++ b/src/com/android/xsdc/Main.java @@ -29,7 +29,9 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.OptionGroup; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; @@ -60,6 +62,44 @@ public class Main { .hasArgs(0) .withDescription("Generate Cpp code.") .create("c")); + options.addOption(OptionBuilder + .withLongOpt("writer") + .hasArgs(0) + .withDescription("Generate Writer code.") + .create("w")); + options.addOption(OptionBuilder + .withLongOpt("nullability") + .hasArgs(0) + .withDescription("Add @NonNull or @Nullable annotation to generated java code.") + .create("n")); + options.addOption(OptionBuilder + .withLongOpt("genHas") + .hasArgs(0) + .withDescription("Generate public hasX() method") + .create("g")); + options.addOption(OptionBuilder + .withLongOpt("booleanGetter") + .hasArgs(0) + .withDescription("Generate isX() for boolean element or attribute.") + .create("b")); + Option genEnumsOnly = OptionBuilder + .withLongOpt("genEnumsOnly") + .hasArgs(0) + .withDescription("Only generate enum converters in Cpp code.") + .create("e"); + options.addOption(genEnumsOnly); + Option genParserOnly = OptionBuilder + .withLongOpt("genParserOnly") + .hasArgs(0) + .withDescription("Only generate XML parser in Cpp code.") + .create("x"); + options.addOption(genParserOnly); + // "Only generate enums" and "Only generate parser" options are mutually exclusive. + OptionGroup genOnlyGroup = new OptionGroup(); + genOnlyGroup.setRequired(false); + genOnlyGroup.addOption(genEnumsOnly); + genOnlyGroup.addOption(genParserOnly); + options.addOptionGroup(genOnlyGroup); CommandLineParser CommandParser = new GnuParser(); CommandLine cmd; @@ -75,9 +115,15 @@ public class Main { String[] xsdFile = cmd.getArgs(); String packageName = cmd.getOptionValue('p', null); String outDir = cmd.getOptionValue('o', null); + boolean writer = cmd.hasOption('w'); + boolean nullability = cmd.hasOption('n'); + boolean genHas = cmd.hasOption('g'); + boolean enumsOnly = cmd.hasOption('e'); + boolean parserOnly = cmd.hasOption('x'); + boolean booleanGetter = cmd.hasOption('b'); if (xsdFile.length != 1 || packageName == null) { - System.err.println("Error: no xsd files or pacakge name"); + System.err.println("Error: no xsd files or package name"); help(options); } @@ -85,31 +131,46 @@ public class Main { outDir = "."; } - XmlSchema xmlSchema; - try (FileInputStream in = new FileInputStream(xsdFile[0])) { - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - SAXParser parser = factory.newSAXParser(); - XsdHandler xsdHandler = new XsdHandler(); - parser.parse(in, xsdHandler); - xmlSchema = xsdHandler.getSchema(); - } + XmlSchema xmlSchema = parse(xsdFile[0]); if (cmd.hasOption('j')) { File packageDir = new File(Paths.get(outDir, packageName.replace(".", "/")).toString()); packageDir.mkdirs(); FileSystem fs = new FileSystem(packageDir); - JavaCodeGenerator javaCodeGenerator = new JavaCodeGenerator(xmlSchema, packageName); + JavaCodeGenerator javaCodeGenerator = + new JavaCodeGenerator(xmlSchema, packageName, writer, nullability, genHas, + booleanGetter); javaCodeGenerator.print(fs); } else if (cmd.hasOption('c')) { File includeDir = new File(Paths.get(outDir, "include").toString()); includeDir.mkdirs(); FileSystem fs = new FileSystem(new File(outDir)); - CppCodeGenerator cppCodeGenerator = new CppCodeGenerator(xmlSchema, packageName); + int generators = enumsOnly ? CppCodeGenerator.GENERATE_ENUMS : + (parserOnly ? CppCodeGenerator.GENERATE_PARSER : + CppCodeGenerator.GENERATE_ENUMS | CppCodeGenerator.GENERATE_PARSER); + CppCodeGenerator cppCodeGenerator = + new CppCodeGenerator(xmlSchema, packageName, writer, generators, booleanGetter); cppCodeGenerator.print(fs); } } + private static XmlSchema parse(String xsdFile) throws Exception { + XmlSchema xmlSchema; + try (FileInputStream in = new FileInputStream(xsdFile)) { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + SAXParser parser = factory.newSAXParser(); + XsdHandler xsdHandler = new XsdHandler(); + parser.parse(in, xsdHandler); + xmlSchema = xsdHandler.getSchema(); + } + for (String file : xmlSchema.getIncludeList()) { + XmlSchema temp = parse(Paths.get(xsdFile).resolveSibling(file).toString()); + xmlSchema.include(temp); + } + return xmlSchema; + } + 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/com/android/xsdc/XmlSchema.java index a941791..4bfa3fd 100644 --- a/src/com/android/xsdc/XmlSchema.java +++ b/src/com/android/xsdc/XmlSchema.java @@ -19,6 +19,7 @@ package com.android.xsdc; import com.android.xsdc.tag.*; import java.util.Collections; +import java.util.List; import java.util.Map; public class XmlSchema { @@ -27,16 +28,18 @@ public class XmlSchema { final private Map<String, XsdAttribute> attributeMap; final private Map<String, XsdAttributeGroup> attributeGroupMap; final private Map<String, XsdGroup> groupMap; + final private List<String> includeList; XmlSchema(Map<String, XsdElement> elementMap, Map<String, XsdType> typeMap, Map<String, XsdAttribute> attributeMap, Map<String, XsdAttributeGroup> attributeGroupMap, - Map<String, XsdGroup> groupMap) { - this.elementMap = Collections.unmodifiableMap(elementMap); - this.typeMap = Collections.unmodifiableMap(typeMap); - this.attributeMap = Collections.unmodifiableMap(attributeMap); - this.attributeGroupMap = Collections.unmodifiableMap(attributeGroupMap); - this.groupMap = Collections.unmodifiableMap(groupMap); + Map<String, XsdGroup> groupMap, List<String> includeList) { + this.elementMap = elementMap; + this.typeMap = typeMap; + this.attributeMap = attributeMap; + this.attributeGroupMap = attributeGroupMap; + this.groupMap = groupMap; + this.includeList = includeList; } public Map<String, XsdElement> getElementMap() { @@ -58,4 +61,16 @@ public class XmlSchema { public Map<String, XsdGroup> getGroupMap() { return groupMap; } + + public List<String> getIncludeList() { + return includeList; + } + + public void include(XmlSchema schema) { + elementMap.putAll(schema.getElementMap()); + typeMap.putAll(schema.getTypeMap()); + attributeMap.putAll(schema.getAttributeMap()); + attributeGroupMap.putAll(schema.getAttributeGroupMap()); + groupMap.putAll(schema.getGroupMap()); + } } diff --git a/src/com/android/xsdc/XsdHandler.java b/src/com/android/xsdc/XsdHandler.java index a2cc57c..f6a9492 100644 --- a/src/com/android/xsdc/XsdHandler.java +++ b/src/com/android/xsdc/XsdHandler.java @@ -60,6 +60,7 @@ public class XsdHandler extends DefaultHandler { private boolean documentationFlag; private boolean enumerationFlag; private List<XsdTag> enumTags; + private List<String> includeList; public XsdHandler() { stateStack = new Stack<>(); @@ -67,6 +68,7 @@ public class XsdHandler extends DefaultHandler { documentationFlag = false; enumerationFlag = false; enumTags = new ArrayList<>(); + includeList = new ArrayList<>(); } public XmlSchema getSchema() { @@ -226,6 +228,9 @@ public class XsdHandler extends DefaultHandler { // They are using when validating xml files via xsd file. // So they are ignored. break; + case "include": + addInclude(state); + break; default: throw new XsdParserException(String.format("unsupported tag : %s", state.name)); } @@ -259,7 +264,7 @@ public class XsdHandler extends DefaultHandler { } } - return new XmlSchema(elementMap, typeMap, attrMap, attrGroupMap, groupMap); + return new XmlSchema(elementMap, typeMap, attrMap, attrGroupMap, groupMap, includeList); } private XsdElement makeElement(State state) throws XsdParserException { @@ -311,6 +316,11 @@ public class XsdHandler extends DefaultHandler { if (use != null && use.equals("prohibited")) return null; + boolean required = false; + if (use != null && use.equals("required")) { + required = true; + } + XsdType type = null; if (typename != null) { type = new XsdType(null, typename); @@ -322,7 +332,7 @@ public class XsdHandler extends DefaultHandler { } } - return setDeprecatedAndFinal(new XsdAttribute(name, ref, type), state.deprecated, + return setDeprecatedAndFinal(new XsdAttribute(name, ref, type, required), state.deprecated, state.finalValue, state.nullability); } @@ -658,6 +668,11 @@ public class XsdHandler extends DefaultHandler { state.finalValue, state.nullability); } + private void addInclude(State state) throws XsdParserException { + String fileName = state.attributeMap.get("schemaLocation"); + includeList.add(fileName); + } + private boolean isDeprecated(Map<String, String> attributeMap,List<XsdTag> tags, boolean deprecated) throws XsdParserException { String name = attributeMap.get("name"); diff --git a/src/com/android/xsdc/cpp/CppCodeGenerator.java b/src/com/android/xsdc/cpp/CppCodeGenerator.java index f7ef86b..3f4b844 100644 --- a/src/com/android/xsdc/cpp/CppCodeGenerator.java +++ b/src/com/android/xsdc/cpp/CppCodeGenerator.java @@ -34,17 +34,30 @@ import java.util.Set; import javax.xml.namespace.QName; public class CppCodeGenerator { + public static final int GENERATE_ENUMS = 1 << 0; + public static final int GENERATE_PARSER = 1 << 1; + private XmlSchema xmlSchema; private String pkgName; private Map<String, CppSimpleType> cppSimpleTypeMap; - private CodeWriter cppFile; - private CodeWriter headerFile; + private CodeWriter enumsCppFile; + private CodeWriter enumsHeaderFile; + private CodeWriter parserCppFile; + private CodeWriter parserHeaderFile; private boolean hasAttr; + private boolean writer; + private int generators; + private boolean booleanGetter; - public CppCodeGenerator(XmlSchema xmlSchema, String pkgName) - throws CppCodeGeneratorException { + private static final String UNKNOWN_ENUM = "UNKNOWN"; + + public CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer, int generators, + boolean booleanGetter) throws CppCodeGeneratorException { this.xmlSchema = xmlSchema; this.pkgName = pkgName; + this.writer = writer; + this.generators = generators; + this.booleanGetter = booleanGetter; // class naming validation { @@ -91,28 +104,76 @@ public class CppCodeGenerator { public void print(FileSystem fs) throws CppCodeGeneratorException, IOException { - // cpp file, headr file init - String cppFileName = pkgName.replace(".", "_") + ".cpp"; - String hFileName = pkgName.replace(".", "_") + ".h"; - cppFile = new CodeWriter(fs.getPrintWriter(cppFileName)); - headerFile = new CodeWriter(fs.getPrintWriter("include/" + hFileName)); - - String headerMacro = hFileName.toUpperCase().replace(".", "_"); - headerFile.printf("#ifndef %s\n", headerMacro); - headerFile.printf("#define %s\n\n", headerMacro); - headerFile.printf("#include <libxml/parser.h>\n"); - headerFile.printf("#include <libxml/xinclude.h>\n\n"); - headerFile.printf("#include <map>\n"); - headerFile.printf("#include <optional>\n"); - headerFile.printf("#include <string>\n"); - headerFile.printf("#include <vector>\n\n"); - - cppFile.printf("#define LOG_TAG \"%s\"\n\n", pkgName); - cppFile.printf("#include <android/log.h>\n"); - cppFile.printf("#include <android-base/strings.h>\n\n"); - cppFile.printf("#include <libxml/parser.h>\n"); - cppFile.printf("#include <libxml/xinclude.h>\n\n"); - cppFile.printf("#include \"%s\"\n\n", hFileName); + // cpp file, header file init + String fileNameStem = pkgName.replace('.', '_'); + String enumsCppFileName = fileNameStem + "_enums.cpp"; + String enumsHeaderFileName = fileNameStem + "_enums.h"; + String parserCppFileName = fileNameStem + ".cpp"; + String parserHeaderFileName = fileNameStem + ".h"; + if ((this.generators & GENERATE_ENUMS) == GENERATE_ENUMS) { + enumsCppFile = new CodeWriter(fs.getPrintWriter(enumsCppFileName)); + enumsHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + enumsHeaderFileName)); + } else { + enumsCppFile = new CodeWriter(); + enumsHeaderFile = new CodeWriter(); + } + if ((this.generators & GENERATE_PARSER) == GENERATE_PARSER) { + parserCppFile = new CodeWriter(fs.getPrintWriter(parserCppFileName)); + parserHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + parserHeaderFileName)); + } else { + parserCppFile = new CodeWriter(); + parserHeaderFile = new CodeWriter(); + } + + boolean hasEnums = false; + for (XsdType type : xmlSchema.getTypeMap().values()) { + if (type instanceof XsdRestriction && + ((XsdRestriction)type).getEnums() != null) { + hasEnums = true; + break; + } + } + + String enumsHeaderMacro = enumsHeaderFileName.toUpperCase().replace('.', '_'); + String parserHeaderMacro = parserHeaderFileName.toUpperCase().replace('.', '_'); + enumsHeaderFile.printf("#ifndef %s\n", enumsHeaderMacro); + enumsHeaderFile.printf("#define %s\n", enumsHeaderMacro); + enumsHeaderFile.printf("\n"); + enumsHeaderFile.printf("#include <array>\n"); + enumsHeaderFile.printf("#include <string>\n"); + enumsHeaderFile.printf("\n"); + parserHeaderFile.printf("#ifndef %s\n", parserHeaderMacro); + parserHeaderFile.printf("#define %s\n", parserHeaderMacro); + parserHeaderFile.printf("\n"); + parserHeaderFile.printf("#include <array>\n"); + parserHeaderFile.printf("#include <map>\n"); + parserHeaderFile.printf("#include <optional>\n"); + parserHeaderFile.printf("#include <string>\n"); + parserHeaderFile.printf("#include <vector>\n"); + if (writer) { + parserHeaderFile.printf("#include <iostream>\n"); + } + parserHeaderFile.printf("\n"); + parserHeaderFile.printf("#if __has_include(<libxml/parser.h>)\n"); + parserHeaderFile.printf("#include <libxml/parser.h>\n"); + parserHeaderFile.printf("#include <libxml/xinclude.h>\n"); + parserHeaderFile.printf("#else\n"); + parserHeaderFile.printf("#error Require libxml2 library. "); + parserHeaderFile.printf("Please add libxml2 to shared_libs or static_libs\n"); + parserHeaderFile.printf("#endif\n"); + if (hasEnums) { + enumsHeaderFile.printf("#include <xsdc/XsdcSupport.h>\n"); + enumsHeaderFile.printf("\n"); + } + parserHeaderFile.printf("\n"); + parserHeaderFile.printf("#include \"%s\"\n", enumsHeaderFileName); + parserHeaderFile.printf("\n"); + + enumsCppFile.printf("#include <map>\n"); + enumsCppFile.printf("\n"); + enumsCppFile.printf("#include \"%s\"\n\n", enumsHeaderFileName); + parserCppFile.printf("#define LOG_TAG \"%s\"\n", pkgName); + parserCppFile.printf("#include \"%s\"\n\n", parserHeaderFileName); List<String> namespace = new java.util.ArrayList<>(); for (String token : pkgName.split("\\.")) { @@ -123,25 +184,33 @@ public class CppCodeGenerator { token = "_" + token; } namespace.add(token); - headerFile.printf("namespace %s {\n", token); - cppFile.printf("namespace %s {\n", token); + enumsHeaderFile.printf("namespace %s {\n", token); + enumsCppFile.printf("namespace %s {\n", token); + parserHeaderFile.printf("namespace %s {\n", token); + parserCppFile.printf("namespace %s {\n", token); } printPrototype(); printXmlParser(); + if (writer) { + printXmlWriter(); + } for (XsdType type : xmlSchema.getTypeMap().values()) { - if (type instanceof XsdComplexType) { - String name = Utils.toClassName(type.getName()); - XsdComplexType complexType = (XsdComplexType) type; - printClass(name, "", complexType); - } else if (type instanceof XsdRestriction && + if (type instanceof XsdRestriction && ((XsdRestriction)type).getEnums() != null) { String name = Utils.toClassName(type.getName()); XsdRestriction restrictionType = (XsdRestriction) type; printEnum(name, restrictionType); } } + for (XsdType type : xmlSchema.getTypeMap().values()) { + if (type instanceof XsdComplexType) { + String name = Utils.toClassName(type.getName()); + XsdComplexType complexType = (XsdComplexType) type; + printClass(name, "", complexType); + } + } for (XsdElement element : xmlSchema.getElementMap().values()) { XsdType type = element.getType(); if (type.getRef() == null && type instanceof XsdComplexType) { @@ -153,52 +222,97 @@ public class CppCodeGenerator { Collections.reverse(namespace); for (String token : namespace) { - headerFile.printf("} // %s\n", token); - cppFile.printf("} // %s\n", token); + enumsHeaderFile.printf("} // %s\n", token); + enumsCppFile.printf("} // %s\n", token); + parserHeaderFile.printf("} // %s\n", token); + parserCppFile.printf("} // %s\n", token); + } + + if (hasEnums) { + enumsHeaderFile.printf("\n//\n// global type declarations for package\n//\n\n"); + enumsHeaderFile.printf("namespace android {\nnamespace details {\n"); + Collections.reverse(namespace); + for (XsdType type : xmlSchema.getTypeMap().values()) { + if (type instanceof XsdRestriction && + ((XsdRestriction)type).getEnums() != null) { + String name = Utils.toClassName(type.getName()); + XsdRestriction restrictionType = (XsdRestriction) type; + printEnumValues(namespace, name, restrictionType); + } + } + enumsHeaderFile.printf("} // namespace details\n} // namespace android\n\n"); } - headerFile.printf("#endif // %s\n", headerMacro); - cppFile.close(); - headerFile.close(); + parserHeaderFile.printf("#endif // %s\n", parserHeaderMacro); + enumsHeaderFile.printf("#endif // %s\n", enumsHeaderMacro); + parserCppFile.close(); + parserHeaderFile.close(); + enumsCppFile.close(); + enumsHeaderFile.close(); } private void printEnum(String name, XsdRestriction restrictionType) throws CppCodeGeneratorException { - headerFile.printf("enum class %s {\n", name); - cppFile.printf("const std::map<std::string, %s> %sString {\n", name, name); + enumsHeaderFile.printf("enum class %s {\n", name); + enumsCppFile.printf("const std::map<std::string, %s> %sString {\n", name, name); List<XsdEnumeration> enums = restrictionType.getEnums(); + enumsHeaderFile.printf("%s = %d,\n", UNKNOWN_ENUM, -1); for (XsdEnumeration tag : enums) { String value = tag.getValue(); - if ("".equals(value)) { - value = "EMPTY"; - } - headerFile.printf("%s,\n", Utils.toEnumName(value)); - cppFile.printf("{ \"%s\", %s::%s },\n", tag.getValue(), name, + enumsHeaderFile.printf("%s,\n", Utils.toEnumName(value)); + enumsCppFile.printf("{ \"%s\", %s::%s },\n", tag.getValue(), name, Utils.toEnumName(value)); } - headerFile.printf("UNKNOWN\n};\n\n"); - cppFile.printf("};\n\n"); - - cppFile.printf("static %s stringTo%s(std::string value) {\n" - + "auto enumValue = %sString.find(value);\n" - + "return enumValue == %sString.end() ? %s::UNKNOWN : enumValue->second;\n" - + "}\n\n", name, name, name, name, name); + enumsHeaderFile.printf("};\n"); + enumsCppFile.printf("};\n\n"); + + enumsHeaderFile.printf("%s stringTo%s(const std::string& value);\n", + name, name); + enumsCppFile.printf("%s stringTo%s(const std::string& value) {\n" + + "auto enumValue = %sString.find(value);\n" + + "return enumValue != %sString.end() ? enumValue->second : %s::%s;\n" + + "}\n\n", name, name, name, name, name, UNKNOWN_ENUM); + + enumsHeaderFile.printf("std::string toString(%s o);\n\n", name); + enumsCppFile.printf("std::string toString(%s o) {\n", name); + enumsCppFile.printf("switch (o) {\n"); + for (XsdEnumeration tag : enums) { + String value = tag.getValue(); + enumsCppFile.printf("case %s::%s: return \"%s\";\n", + name, Utils.toEnumName(value), tag.getValue()); + } + enumsCppFile.printf("default: return std::to_string(static_cast<int>(o));\n}\n"); + enumsCppFile.printf("}\n\n"); } + private void printEnumValues(List<String> namespace, String name, + XsdRestriction restrictionType) throws CppCodeGeneratorException { + List<XsdEnumeration> enums = restrictionType.getEnums(); + String absoluteNamespace = "::" + String.join("::", namespace); + enumsHeaderFile.printf("template<> inline constexpr std::array<%s::%s, %d> " + + "xsdc_enum_values<%s::%s> = {\n", + absoluteNamespace, name, enums.size(), absoluteNamespace, name); + for (XsdEnumeration tag : enums) { + String value = tag.getValue(); + enumsHeaderFile.printf("%s::%s::%s,\n", + absoluteNamespace, name, Utils.toEnumName(value)); + } + enumsHeaderFile.printf("};\n"); + } private void printPrototype() throws CppCodeGeneratorException { for (XsdType type : xmlSchema.getTypeMap().values()) { if (type instanceof XsdComplexType) { String name = Utils.toClassName(type.getName()); - headerFile.printf("class %s;\n", name); + parserHeaderFile.printf("class %s;\n", name); } } for (XsdElement element : xmlSchema.getElementMap().values()) { XsdType type = element.getType(); if (type.getRef() == null && type instanceof XsdComplexType) { String name = Utils.toClassName(element.getName()); - headerFile.printf("class %s;\n", name); + parserHeaderFile.printf("class %s;\n", name); } } } @@ -212,12 +326,12 @@ public class CppCodeGenerator { CppSimpleType valueType = (complexType instanceof XsdSimpleContent) ? getValueType((XsdSimpleContent) complexType, false) : null; - headerFile.printf("class %s ", name); + parserHeaderFile.printf("class %s ", name); if (baseName != null) { - headerFile.printf(": public %s {\n", baseName); + parserHeaderFile.printf(": public %s {\n", baseName); } else { - headerFile.println("{"); + parserHeaderFile.println("{"); } // parse types for elements and attributes @@ -232,11 +346,11 @@ public class CppCodeGenerator { if (element.getRef() == null && element.getType().getRef() == null && element.getType() instanceof XsdComplexType) { // print inner class for anonymous types - headerFile.printf("public:\n"); + parserHeaderFile.printf("public:\n"); String innerName = Utils.toClassName(getElementName(element)); XsdComplexType innerType = (XsdComplexType) element.getType(); printClass(innerName, nameScope + name + "::", innerType); - headerFile.println(); + parserHeaderFile.println(); cppType = new CppComplexType(nameScope + name + "::"+ innerName); } else { cppType = parseType(elementValue.getType(), getElementName(elementValue)); @@ -257,53 +371,66 @@ public class CppCodeGenerator { // print member variables - headerFile.printf("private:\n"); + parserHeaderFile.printf("private:\n"); for (int i = 0; i < elementTypes.size(); ++i) { CppType type = elementTypes.get(i); XsdElement element = elements.get(i); XsdElement elementValue = resolveElement(element); - String typeName = element.isMultiple() || type instanceof CppComplexType ? - String.format("std::vector<%s>", type.getName()) : type.getName(); - headerFile.printf("%s %s;\n", typeName, + String typeName = Utils.elementTypeName(type.getName(), + element.isMultiple() || type instanceof CppComplexType); + parserHeaderFile.printf("const %s %s_;\n", typeName, Utils.toVariableName(getElementName(elementValue))); } for (int i = 0; i < attributeTypes.size(); ++i) { CppType type = attributeTypes.get(i); XsdAttribute attribute = resolveAttribute(attributes.get(i)); - headerFile.printf("%s %s;\n", type.getName(), - Utils.toVariableName(attribute.getName())); + String variableName = Utils.toVariableName(attribute.getName()); + if (attribute.isRequired()) { + parserHeaderFile.printf("const %s %s_;\n", type.getName(), variableName); + } else { + parserHeaderFile.printf("const std::optional<%s> %s_;\n", + type.getName(), variableName); + } } if (valueType != null) { - headerFile.printf("%s value;\n", valueType.getName()); + parserHeaderFile.printf("const std::optional<%s> _value;\n", valueType.getName()); } - // print getters and setters + parserHeaderFile.printf("public:\n"); + String constructorArgs = printConstructor(name, nameScope, complexType, elements, + attributes, baseName); - headerFile.printf("public:\n"); + // print getters and setters for (int i = 0; i < elementTypes.size(); ++i) { CppType type = elementTypes.get(i); XsdElement element = elements.get(i); XsdElement elementValue = resolveElement(element); - printGetterAndSetter(nameScope + name, type, + printGetter(nameScope + name, type, Utils.toVariableName(getElementName(elementValue)), type instanceof CppComplexType ? true : element.isMultiple(), - type instanceof CppComplexType ? false : ((CppSimpleType)type).isList()); + type instanceof CppComplexType ? false : ((CppSimpleType)type).isList(), + false); } for (int i = 0; i < attributeTypes.size(); ++i) { CppType type = attributeTypes.get(i); XsdAttribute attribute = resolveAttribute(attributes.get(i)); - printGetterAndSetter(nameScope + name, type, - Utils.toVariableName(attribute.getName()), false, false); + printGetter(nameScope + name, type, Utils.toVariableName(attribute.getName()), + false, false, attribute.isRequired()); } if (valueType != null) { - printGetterAndSetter(nameScope + name, valueType, "value", false, false); + printGetter(nameScope + name, valueType, "value", false, false, false); + } + + printParser(name, nameScope, complexType, constructorArgs); + + if (writer) { + printWriter(name, nameScope, complexType); } - printParser(name, nameScope, complexType); - headerFile.println("};\n"); + parserHeaderFile.println("};\n"); } - private void printParser(String name, String nameScope, XsdComplexType complexType) + private void printParser(String name, String nameScope, XsdComplexType complexType, String args) throws CppCodeGeneratorException { CppSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ? getValueType((XsdSimpleContent) complexType, true) : null; @@ -325,118 +452,321 @@ public class CppCodeGenerator { } String fullName = nameScope + name; - headerFile.printf("static %s read(xmlNode *root);\n", fullName, Utils.lowerize(name)); - cppFile.printf("\n%s %s::read(xmlNode *root) {\n", fullName, fullName); + parserHeaderFile.printf("static %s read(xmlNode *root);\n", fullName, Utils.lowerize(name)); + parserCppFile.printf("\n%s %s::read(xmlNode *root) {\n", fullName, fullName); - cppFile.printf("%s instance;\n std::string raw;\n", fullName, fullName); + parserCppFile.print("std::string raw;\n"); for (int i = 0; i < allAttributes.size(); ++i) { - CppType type = allAttributeTypes.get(i); + CppSimpleType type = allAttributeTypes.get(i); XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); String variableName = Utils.toVariableName(attribute.getName()); - cppFile.printf("raw = getXmlAttribute(root, \"%s\");\n", attribute.getName()); - cppFile.printf("if (raw != \"\") {\n"); - cppFile.print(type.getParsingExpression()); - cppFile.printf("instance.set%s(value);\n}\n", Utils.capitalize(variableName)); + parserCppFile.printf("raw = getXmlAttribute(root, \"%s\");\n", attribute.getName()); + if (attribute.isRequired()) { + if (type.isEnum()) { + parserCppFile.printf("%s %s = %s::%s;\n", + type.getName(), variableName, type.getName(), UNKNOWN_ENUM); + } else { + parserCppFile.printf("%s %s{};\n", type.getName(), variableName); + } + } else { + parserCppFile.printf("std::optional<%s> %s = std::nullopt;\n", type.getName(), + variableName); + } + parserCppFile.printf("if (raw != \"\") {\n"); + parserCppFile.print(type.getParsingExpression()); + parserCppFile.printf("%s = value;\n}\n", variableName); } if (baseValueType != null) { - cppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString(" + parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString(" + "root->doc, root->xmlChildrenNode, 1));\n" + "if (xmlValue != nullptr) {\n" + "raw = reinterpret_cast<const char*>(xmlValue.get());\n"); - cppFile.print(baseValueType.getParsingExpression()); - cppFile.printf("instance.setValue(value);\n"); - cppFile.printf("}\n"); + parserCppFile.print(baseValueType.getParsingExpression()); + parserCppFile.printf("instance.setValue(value);\n"); + parserCppFile.printf("}\n"); } else if (!allElements.isEmpty()) { - cppFile.print("for (xmlNode *child = root->xmlChildrenNode; child != nullptr;" + for (int i = 0; i < allElements.size(); ++i) { + CppType type = allElementTypes.get(i); + XsdElement element = allElements.get(i); + XsdElement elementValue = resolveElement(element); + String variableName = Utils.toVariableName(getElementName(elementValue)); + parserCppFile.printf("%s %s;\n", Utils.elementTypeName(type.getName(), + element.isMultiple() || type instanceof CppComplexType), variableName); + } + parserCppFile.print("for (xmlNode *child = root->xmlChildrenNode; child != nullptr;" + " child = child->next) {\n"); for (int i = 0; i < allElements.size(); ++i) { CppType type = allElementTypes.get(i); XsdElement element = allElements.get(i); XsdElement elementValue = resolveElement(element); String variableName = Utils.toVariableName(getElementName(elementValue)); - if (i != 0) cppFile.printf("} else "); - cppFile.printf("if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>"); - cppFile.printf("(\"%s\"))) {\n", elementValue.getName()); + + if (i != 0) parserCppFile.printf("} else "); + parserCppFile.print("if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>"); + parserCppFile.printf("(\"%s\"))) {\n", elementValue.getName()); if (type instanceof CppSimpleType) { - cppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString("); - cppFile.printf("child->doc, child->xmlChildrenNode, 1));\n"); - cppFile.printf("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n"); - cppFile.printf("raw = reinterpret_cast<const char*>(xmlValue.get());\n}\n"); + parserCppFile.print("auto xmlValue = make_xmlUnique(xmlNodeListGetString("); + parserCppFile.print("child->doc, child->xmlChildrenNode, 1));\n"); + parserCppFile.print("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n"); + parserCppFile.print("raw = reinterpret_cast<const char*>(xmlValue.get());\n}"); + parserCppFile.print("\n"); } - cppFile.print(type.getParsingExpression()); + parserCppFile.print(type.getParsingExpression()); if (element.isMultiple() || type instanceof CppComplexType) { - cppFile.printf("instance.get%s().push_back(std::move(value));\n", - Utils.capitalize(variableName)); + parserCppFile.printf("%s.push_back(std::move(value));\n", variableName); } else { - cppFile.printf("instance.set%s(value);\n", Utils.capitalize(variableName)); + parserCppFile.printf("%s = std::move(value);\n", variableName); } } - cppFile.printf("}\n}\n"); + parserCppFile.printf("}\n}\n"); } - cppFile.printf("return instance;\n" - + "}\n"); + parserCppFile.printf("%s instance%s;\n", + fullName, args.length() > 0 ? "(" + args + ")" : ""); + parserCppFile.print("return instance;\n}\n"); } - private void printGetterAndSetter(String name, CppType type, String variableName, - boolean isMultiple, boolean isMultipleType) { - String typeName = isMultiple ? String.format("std::vector<%s>", type.getName()) - : type.getName(); + 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); - headerFile.printf("%s& get%s();\n", typeName, Utils.capitalize(variableName)); + // parse types for elements and attributes + List<CppType> allElementTypes = new ArrayList<>(); + for (XsdElement element : allElements) { + XsdElement elementValue = resolveElement(element); + CppType cppType = parseType(elementValue.getType(), elementValue.getName()); + allElementTypes.add(cppType); + } + List<CppSimpleType> allAttributeTypes = new ArrayList<>(); + for (XsdAttribute attribute : allAttributes) { + XsdType type = resolveAttribute(attribute).getType(); + allAttributeTypes.add(parseSimpleType(type, false)); + } + + String fullName = nameScope + name; + 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", + fullName); + + 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.print(type.getWritingExpression(String.format("%s%s()", + getterName(type.getName()), Utils.capitalize(variableName)), + attribute.getName())); + parserCppFile.printf("out << \"\\\"\";\n}\n"); + } + parserCppFile.print("out << \">\" << std::endl;\n"); + parserCppFile.print("++indentIndex;\n"); + + if (!allElements.isEmpty()) { + for (int i = 0; i < allElements.size(); ++i) { + CppType type = allElementTypes.get(i); + XsdElement element = allElements.get(i); + XsdElement elementValue = resolveElement(element); + String elementName = getElementName(elementValue); + String variableName = Utils.toVariableName(elementName); + + if (type instanceof CppComplexType || element.isMultiple()) { + parserCppFile.printf("for (auto& value : get%s()) {\n", + Utils.capitalize(variableName)); + if (type instanceof CppSimpleType) { + parserCppFile.printf("out << printIndent() << \"<%s>\";\n", + elementValue.getName()); + } + parserCppFile.printf( + type.getWritingExpression("value", elementValue.getName())); + if (type instanceof CppSimpleType) { + 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", + 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", + elementValue.getName()); + } + parserCppFile.print("}\n"); + } + } + } + parserCppFile.print("--indentIndex;\n"); + parserCppFile.printf("out << printIndent() << \"</\" << name << \">\" << std::endl;\n"); + parserCppFile.printf("}\n"); + } - cppFile.println(); - cppFile.printf("%s& %s::get%s() {\n" - + "return %s;\n}\n", - typeName, name, Utils.capitalize(variableName), variableName); + 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(); + + 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)); + + parserHeaderFile.printf("bool has%s() const;\n", Utils.capitalize(variableName)); + parserCppFile.printf("bool %s::has%s() const {\n", name, Utils.capitalize(variableName)); + if (isMultiple) { + parserCppFile.printf("return !(%s_.empty());\n}\n", variableName); + } else if (isRequired){ + parserCppFile.print("return true;\n}\n"); + } else { + parserCppFile.printf("return %s_.has_value();\n}\n", variableName); + } if (isMultiple || isMultipleType) { String elementTypeName = type instanceof CppComplexType ? type.getName() : ((CppSimpleType)type).getTypeName(); if (elementTypeName.equals("bool")) { - headerFile.printf("%s getFirst%s();\n", + parserHeaderFile.printf("%s getFirst%s() const;\n", elementTypeName, Utils.capitalize(variableName)); - cppFile.println(); - cppFile.printf("%s %s::getFirst%s() {\n" - + "if (%s.empty()) {\n" + parserCppFile.println(); + parserCppFile.printf("%s %s::getFirst%s() const {\n" + + "if (%s_%sempty()) {\n" + "return false;\n" + "}\n" - + "return %s[0];\n" + + "return %s;\n" + "}\n", elementTypeName, name, Utils.capitalize(variableName), variableName, - variableName); + isMultiple ? "." : "->", + isMultiple ? String.format("%s_[0]", variableName) : + String.format("%s_.value()[0]", variableName)); } else { - headerFile.printf("%s* getFirst%s();\n", + parserHeaderFile.printf("const %s* getFirst%s() const;\n", elementTypeName, Utils.capitalize(variableName)); - cppFile.println(); - cppFile.printf("%s* %s::getFirst%s() {\n" - + "if (%s.empty()) {\n" + parserCppFile.println(); + parserCppFile.printf("const %s* %s::getFirst%s() const {\n" + + "if (%s_%sempty()) {\n" + "return nullptr;\n" + "}\n" - + "return &%s[0];\n" + + "return &%s;\n" + "}\n", elementTypeName, name, Utils.capitalize(variableName), variableName, - variableName); + isMultiple ? "." : "->", + isMultiple ? String.format("%s_[0]", variableName) : + String.format("%s_.value()[0]", variableName)); + } + } + } + + private String printConstructor(String name, String nameScope, XsdComplexType complexType, + List<XsdElement> elements, List<XsdAttribute> attributes, String baseName) + throws CppCodeGeneratorException { + String fullName = nameScope + name; + StringBuilder constructorArgs = new StringBuilder(); + StringBuilder parentArgs = new StringBuilder(); + StringBuilder constructor = new StringBuilder(); + StringBuilder args = new StringBuilder(); + + List<XsdElement> allElements = new ArrayList<>(); + 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()); + String variableName = Utils.toVariableName(getElementName(elementValue)); + constructorArgs.append(String.format(", %s %s", Utils.elementTypeName(type.getName(), + element.isMultiple() || type instanceof CppComplexType), variableName)); + args.append(String.format(", %s", variableName)); + boolean isMultipleType; + if (type instanceof CppComplexType) { + isMultipleType = true; + } else if (((CppSimpleType)type).isList()) { + isMultipleType = true; + } else { + isMultipleType = false; + } + + if (elements.contains(element)) { + constructor.append(String.format(", %s_(%s)", variableName, + Utils.toAssignmentName(type.getName(), variableName, isMultipleType))); + } else { + 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()); + if (attribute.isRequired()) { + constructorArgs.append(String.format(", %s %s", type.getName(), variableName)); + } else { + constructorArgs.append(String.format(", std::optional<%s> %s", type.getName(), + variableName)); + } + args.append(String.format(", %s", variableName)); + boolean isMultipleType = ((CppSimpleType)type).isList() ? true : false; + if (attributes.contains(attribute)) { + constructor.append(String.format(", %s_(%s)", variableName, + Utils.toAssignmentName(type.getName(), variableName, isMultipleType))); + } else { + parentArgs.append(String.format(", %s", variableName)); } } - if (isMultiple) return; - headerFile.printf("void set%s(%s);\n", Utils.capitalize(variableName), typeName); - cppFile.println(); - cppFile.printf("void %s::set%s(%s %s) {\n" - + "this->%s = std::move(%s);\n" - + "}\n", - name, Utils.capitalize(variableName), typeName, variableName, - variableName, variableName); + String constructorArgsString = constructorArgs.toString(); + String constructorString = constructor.toString(); + if (constructorArgsString.length() > 0) { + constructorArgsString = constructorArgsString.substring(2); + } + + boolean useExplicit = + !(constructorArgsString.isEmpty() || constructorArgsString.contains(",")); + if (useExplicit) { + parserHeaderFile.printf("explicit %s(%s);\n", name, constructorArgsString); + } else { + parserHeaderFile.printf("%s(%s);\n", name, constructorArgsString); + } + parserCppFile.printf("\n%s::%s(%s) : ", fullName, name, constructorArgsString); + + String parentArgsString = parentArgs.toString(); + if (parentArgsString.length() > 0) { + parentArgsString = parentArgsString.substring(2); + parserCppFile.printf("%s(%s)", baseName, parentArgsString); + } else { + constructorString = constructorString.substring(2); + } + parserCppFile.printf("%s {\n}\n", constructorString); + + String argsString = args.toString(); + if (argsString.length() > 0) { + argsString = argsString.substring(2); + } + return argsString; } private void printXmlParser() throws CppCodeGeneratorException { - cppFile.printf("template <class T>\n" + parserCppFile.printf("template <class T>\n" + "constexpr void (*xmlDeleter)(T* t);\n" + "template <>\nconstexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;\n" + "template <>\nauto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };\n\n" @@ -447,7 +777,7 @@ public class CppCodeGenerator { + "}\n\n"); if (hasAttr) { - cppFile.printf("static std::string getXmlAttribute" + parserCppFile.printf("static std::string getXmlAttribute" + "(const xmlNode *cur, const char *attribute) {\n" + "auto xmlValue = make_xmlUnique(xmlGetProp(cur, " + "reinterpret_cast<const xmlChar*>(attribute)));\n" @@ -469,16 +799,19 @@ public class CppCodeGenerator { String typeName = cppType instanceof CppSimpleType ? cppType.getName() : Utils.toClassName(cppType.getName()); - headerFile.printf("std::optional<%s> read%s(const char* configFile);\n\n", + parserHeaderFile.printf("std::optional<%s> read%s(const char* configFile);\n\n", typeName, isMultiRootElement ? Utils.capitalize(typeName) : ""); - cppFile.printf("std::optional<%s> read%s(const char* configFile) {\n", + parserCppFile.printf("std::optional<%s> read%s(const char* configFile) {\n", typeName, isMultiRootElement ? Utils.capitalize(typeName) : ""); - cppFile.printf("auto doc = make_xmlUnique(xmlParseFile(configFile));\n" + 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 == NULL) {\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*>" @@ -486,15 +819,41 @@ public class CppCodeGenerator { elementName); if (cppType instanceof CppSimpleType) { - cppFile.printf("%s value = getXmlAttribute(child, \"%s\");\n", + parserCppFile.printf("%s value = getXmlAttribute(child, \"%s\");\n", elementName, elementName); } else { - cppFile.printf(cppType.getParsingExpression()); + parserCppFile.printf(cppType.getParsingExpression()); } - cppFile.printf("return value;\n}\n"); - cppFile.printf("return std::nullopt;\n"); - cppFile.printf("}\n\n"); + parserCppFile.printf("return value;\n}\n"); + parserCppFile.printf("return std::nullopt;\n"); + parserCppFile.printf("}\n\n"); + } + } + + private void printXmlWriter() throws CppCodeGeneratorException { + 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("void write(std::ostream& out, %s& %s);\n\n", + typeName, VariableName); + parserCppFile.printf("void write(std::ostream& out, %s& %s) {\n", + typeName, VariableName); + + parserCppFile.print( + "out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n"); + parserCppFile.printf("%s.write(out, \"%s\");\n", VariableName, elementName); + parserCppFile.printf("}\n\n"); } + + parserCppFile.print("static int indentIndex = 0;\n" + + "std::string printIndent() {\n" + + "std::string s = \"\";\n" + + "for (int index = 0; index < indentIndex; ++index) {\n" + + "s += \" \";\n" + + "}\nreturn s;\n}\n\n"); } private String getElementName(XsdElement element) { @@ -506,6 +865,13 @@ public class CppCodeGenerator { return element.getName(); } + private String getterName(String type) { + if (type.equals("bool") && booleanGetter) { + return "is"; + } + return "get"; + } + private void stackComponents(XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes) throws CppCodeGeneratorException { if (complexType.getBase() != null) { @@ -641,7 +1007,7 @@ public class CppCodeGenerator { XsdRestriction restriction = (XsdRestriction) simpleType; if (restriction.getEnums() != null) { String name = Utils.toClassName(restriction.getName()); - return new CppSimpleType(name, "stringTo" + name + "(%s)", false); + return new CppSimpleType(name, "stringTo" + name + "(%s)", false, true); } return parseSimpleType(restriction.getBase(), traverse); } else if (simpleType instanceof XsdUnion) { @@ -764,11 +1130,11 @@ public class CppCodeGenerator { case "nonNegativeInteger": case "positiveInteger": case "nonPositiveInteger": - return new CppSimpleType("long long", "std::stoll(%s)", false); + return new CppSimpleType("int64_t", "std::stoll(%s)", false); case "unsignedLong": - return new CppSimpleType("unsigned long long", "std::stoull(%s)", false); + return new CppSimpleType("uint64_t", "std::stoull(%s)", false); case "long": - return new CppSimpleType("long long", "std::stoll(%s)", false); + return new CppSimpleType("int64_t", "std::stoll(%s)", false); case "unsignedInt": return new CppSimpleType("unsigned int", "static_cast<unsigned int>(stoul(%s))", false); diff --git a/src/com/android/xsdc/cpp/CppComplexType.java b/src/com/android/xsdc/cpp/CppComplexType.java index 2c9d397..64d735d 100644 --- a/src/com/android/xsdc/cpp/CppComplexType.java +++ b/src/com/android/xsdc/cpp/CppComplexType.java @@ -32,4 +32,9 @@ class CppComplexType implements CppType { public String getParsingExpression() { 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); + } } diff --git a/src/com/android/xsdc/cpp/CppSimpleType.java b/src/com/android/xsdc/cpp/CppSimpleType.java index f59aec5..282855f 100644 --- a/src/com/android/xsdc/cpp/CppSimpleType.java +++ b/src/com/android/xsdc/cpp/CppSimpleType.java @@ -21,18 +21,28 @@ class CppSimpleType implements CppType { final private String fullName; final private String rawParsingExpression; final private boolean list; + final private boolean isEnum; - CppSimpleType(String name, String rawParsingExpression, boolean list) { + CppSimpleType(String name, String rawParsingExpression, boolean list, boolean isEnum) { this.rawParsingExpression = rawParsingExpression; this.list = list; this.name = name; this.fullName = list ? String.format("std::vector<%s>", name) : name; + this.isEnum = isEnum; + } + + CppSimpleType(String name, String rawParsingExpression, boolean list) { + this(name, rawParsingExpression, list, false); } boolean isList() { return list; } + boolean isEnum() { + return isEnum; + } + CppSimpleType newListType() throws CppCodeGeneratorException { if (list) throw new CppCodeGeneratorException("list of list is not supported"); return new CppSimpleType(name, rawParsingExpression, true); @@ -53,15 +63,56 @@ class CppSimpleType implements CppType { if (list) { expression.append( String.format("%s value;\n", getName())); - expression.append("for (auto& token : android::base::Split(raw, \" \")) {\n"); - expression.append(String.format("value.push_back(std::move(%s));\n", - String.format(rawParsingExpression, "token"))); + expression.append(String.format("{\nint base = 0;\n" + + "int found;\n" + + "while(true) {\n" + + "found = raw.find_first_of(\" \", base);\n" + + "value.push_back(%s);\n" + + "if (found == raw.npos) break;\n" + + "base = found + 1;\n" + + "}\n", + String.format(rawParsingExpression, "raw.substr(base, found - base)"))); expression.append("}\n"); } else { expression.append( - String.format("%s value = %s;\n", getName(), + String.format("%s %svalue = %s;\n", getName(), + this.name.equals("std::string") ? "&" : "", String.format(rawParsingExpression, "raw"))); } return expression.toString(); } + + @Override + 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)); + String value; + if (isEnum) { + value = String.format("%sToString(v)", this.name); + } else if (this.name.equals("char") || this.name.equals("unsigned char")) { + value = "(int)v"; + } else if (this.name.equals("bool")) { + value = "(v ? \"true\" : \"false\")"; + } else { + value = "v"; + } + 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)); + } else if (this.name.equals("char") || this.name.equals("unsigned char")) { + 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)); + } else { + expression.append(String.format("out << %s;\n", getValue)); + } + } + return expression.toString(); + } } diff --git a/src/com/android/xsdc/cpp/CppType.java b/src/com/android/xsdc/cpp/CppType.java index 097d663..05d4da9 100644 --- a/src/com/android/xsdc/cpp/CppType.java +++ b/src/com/android/xsdc/cpp/CppType.java @@ -20,4 +20,6 @@ interface CppType { String getName(); String getParsingExpression(); + + public String getWritingExpression(String getValue, String name); } diff --git a/src/com/android/xsdc/cpp/Utils.java b/src/com/android/xsdc/cpp/Utils.java index c612fc6..d54a9aa 100644 --- a/src/com/android/xsdc/cpp/Utils.java +++ b/src/com/android/xsdc/cpp/Utils.java @@ -75,6 +75,9 @@ class Utils { } static String toEnumName(String name) throws CppCodeGeneratorException { + if ("".equals(name)) { + name = "EMPTY"; + } String trimmed = name.replace(".", "_").replaceAll("[^A-Za-z0-9_]", ""); if (trimmed.isEmpty()) { throw new CppCodeGeneratorException( @@ -83,4 +86,21 @@ class Utils { String enumName = Character.isDigit(trimmed.charAt(0)) ? "_" + trimmed : trimmed; return (keywordSet.contains(enumName)) ? "_" + enumName : enumName; } + + static String toAssignmentName(String typeName, String variableName, boolean isMultipleType) { + if (isMultipleType || typeName.equals("std::string")) { + return String.format("std::move(%s)", variableName); + } + return variableName; + } + + static String elementTypeName(String name, boolean isMultipleType) { + String res; + if (isMultipleType) { + res = "std::vector<" + name + ">"; + } else { + res = "std::optional<" + name + ">"; + } + return res; + } } diff --git a/src/com/android/xsdc/java/JavaCodeGenerator.java b/src/com/android/xsdc/java/JavaCodeGenerator.java index 23ce51d..0025896 100644 --- a/src/com/android/xsdc/java/JavaCodeGenerator.java +++ b/src/com/android/xsdc/java/JavaCodeGenerator.java @@ -36,11 +36,22 @@ public class JavaCodeGenerator { private XmlSchema xmlSchema; private String packageName; private Map<String, JavaSimpleType> javaSimpleTypeMap; - - public JavaCodeGenerator(XmlSchema xmlSchema, String packageName) + private boolean writer; + private boolean showNullability; + private boolean generateHasMethod; + private boolean useHexBinary; + private boolean booleanGetter; + + public JavaCodeGenerator(XmlSchema xmlSchema, String packageName, boolean writer, + boolean showNullability, boolean generateHasMethod, boolean booleanGetter) throws JavaCodeGeneratorException { this.xmlSchema = xmlSchema; this.packageName = packageName; + this.writer = writer; + this.showNullability = showNullability; + this.generateHasMethod = generateHasMethod; + this.booleanGetter = booleanGetter; + useHexBinary = false; // class naming validation { @@ -113,6 +124,16 @@ public class JavaCodeGenerator { try (CodeWriter out = new CodeWriter(fs.getPrintWriter("XmlParser.java"))) { printXmlParser(out); } + if (writer) { + try (CodeWriter out = new CodeWriter(fs.getPrintWriter("XmlWriter.java"))) { + printXmlWriter(out); + } + } + if (useHexBinary) { + try (CodeWriter out = new CodeWriter(fs.getPrintWriter("HexBinaryHelper.java"))) { + printHexBinaryHelper(out); + } + } } private void printEnumClass(CodeWriter out, String name, XsdRestriction restrictionType) @@ -128,19 +149,33 @@ public class JavaCodeGenerator { out.printf("@java.lang.Deprecated\n"); } String value = tag.getValue(); - if ("".equals(value)) { - value = "EMPTY"; - } - out.printf("\n%s(\"%s\"),", Utils.toEnumName(value), tag.getValue()); + out.printf("\n%s(\"%s\"),", Utils.toEnumName(value), value); } out.printf(";\n\n"); out.printf("private final String rawName;\n\n"); - out.printf("%s(String rawName) {\n" + out.printf("%s(%sString rawName) {\n" + "this.rawName = rawName;\n" - + "}\n\n", name); - out.printf("public String getRawName() {\n" + + "}\n\n", name, getDefaultNullability(Nullability.NON_NULL)); + out.printf("public %sString getRawName() {\n" + "return rawName;\n" - + "}\n"); + + "}\n\n", getDefaultNullability(Nullability.NON_NULL)); + + out.printf("static %s%s fromString(%sString rawString) {\n" + + "for (%s _f : values()) {\n" + + "if (_f.getRawName().equals(rawString)) {\n" + + "return _f;\n" + + "}\n" + + "}\n" + + "throw new IllegalArgumentException(rawString);\n" + + "}\n\n", getDefaultNullability(Nullability.NULLABLE), name, + getDefaultNullability(Nullability.NON_NULL), name); + + if (writer) { + out.printf("@Override\n" + + "public %sString toString() {\n" + + "return rawName;\n" + + "}\n", getDefaultNullability(Nullability.NON_NULL)); + } out.println("}"); } @@ -209,7 +244,7 @@ public class JavaCodeGenerator { XsdElement element = elements.get(i); XsdElement elementValue = resolveElement(element); String typeName = element.isMultiple() ? String.format("java.util.List<%s>", - type.getNullableName()) : type.getName(); + type.getNullableName()) : type.getNullableName(); out.printf("%sprivate %s %s;\n", getNullabilityString(element.getNullability()), typeName, Utils.toVariableName(getElementName(elementValue))); } @@ -217,7 +252,7 @@ public class JavaCodeGenerator { JavaType type = attributeTypes.get(i); XsdAttribute attribute = resolveAttribute(attributes.get(i)); out.printf("%sprivate %s %s;\n", getNullabilityString(attribute.getNullability()), - type.getName(), Utils.toVariableName(attribute.getName())); + type.getNullableName(), Utils.toVariableName(attribute.getName())); } if (valueType != null) { out.printf("private %s value;\n", valueType.getName()); @@ -243,6 +278,9 @@ public class JavaCodeGenerator { out.println(); printParser(out, nameScope + name, complexType); + if (writer) { + printWriter(out, name, complexType); + } out.println("}"); } @@ -268,9 +306,11 @@ public class JavaCodeGenerator { allAttributeTypes.add(parseSimpleType(type, false)); } - out.printf("static %s read(org.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", name); + "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); @@ -332,6 +372,87 @@ public class JavaCodeGenerator { + "}\n"); } + private void printWriter(CodeWriter out, String name, XsdComplexType complexType) + throws JavaCodeGeneratorException { + JavaSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ? + getValueType((XsdSimpleContent) complexType, true) : null; + List<XsdElement> allElements = new ArrayList<>(); + List<XsdAttribute> allAttributes = new ArrayList<>(); + stackComponents(complexType, allElements, allAttributes); + + // parse types for elements and attributes + List<JavaType> allElementTypes = new ArrayList<>(); + for (XsdElement element : allElements) { + XsdElement elementValue = resolveElement(element); + JavaType javaType = parseType(elementValue.getType(), elementValue.getName()); + allElementTypes.add(javaType); + } + List<JavaSimpleType> allAttributeTypes = new ArrayList<>(); + for (XsdAttribute attribute : allAttributes) { + XsdType type = resolveAttribute(attribute).getType(); + allAttributeTypes.add(parseSimpleType(type, false)); + } + + 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"); + 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.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"); + + if (!allElements.isEmpty()) { + out.printf("out.increaseIndent();\n"); + for (int i = 0; i < allElements.size(); ++i) { + JavaType type = allElementTypes.get(i); + XsdElement element = allElements.get(i); + XsdElement elementValue = resolveElement(element); + String elementName = getElementName(elementValue); + String variableName = Utils.toVariableName(elementName); + + if (element.isMultiple()) { + 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.print(type.getWritingExpression("value", elementValue.getName())); + if (type instanceof JavaSimpleType) { + 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.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("}\n"); + } + + } + out.printf("out.decreaseIndent();\n"); + } + out.print("out.print(\"</\" + name + \">\\n\");\n"); + out.print("}\n"); + } + private void printGetterAndSetter(CodeWriter out, JavaType type, String variableName, boolean isMultiple, XsdTag tag) { String typeName = isMultiple ? String.format("java.util.List<%s>", type.getNullableName()) @@ -343,18 +464,33 @@ public class JavaCodeGenerator { if (deprecated) { out.printf("@java.lang.Deprecated\n"); } - out.printf("public%s %s%s get%s() {\n", getFinalString(finalValue), - getNullabilityString(nullability), typeName, Utils.capitalize(variableName)); - if (isMultiple) { + out.printf("public%s %s%s %s%s() {\n", getFinalString(finalValue), + getNullabilityString(nullability), typeName, getterName(typeName), + Utils.capitalize(variableName)); + if ((type instanceof JavaSimpleType && ((JavaSimpleType)type).isList()) || isMultiple) { out.printf("if (%s == null) {\n" + "%s = new java.util.ArrayList<>();\n" + "}\n", variableName, variableName); + } else if (type.isPrimitiveType()) { + out.printf("if (%s == null) {\n", variableName); + if (typeName.equals("boolean")) { + out.printf("return false;\n}\n", variableName); + } else { + out.printf("return (%s)0;\n}\n", typeName); + } } out.printf("return %s;\n" + "}\n", variableName); if (isMultiple) return; out.println(); + out.printf("%sboolean has%s() {\n" + + "if (%s == null) {\n" + + "return false;\n" + + "}\n" + + "return true;\n}\n\n", + generateHasMethod ? "public " : "", + Utils.capitalize(variableName), variableName); if (deprecated) { out.printf("@java.lang.Deprecated\n"); } @@ -374,7 +510,7 @@ public class JavaCodeGenerator { boolean isMultiRootElement = xmlSchema.getElementMap().values().size() > 1; for (XsdElement element : xmlSchema.getElementMap().values()) { JavaType javaType = parseType(element.getType(), element.getName()); - out.printf("public static %s read%s(java.io.InputStream in)" + 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" @@ -384,8 +520,9 @@ public class JavaCodeGenerator { + "parser.setInput(in, null);\n" + "parser.nextTag();\n" + "String tagName = parser.getName();\n" - + "String raw = null;\n", javaType.getName(), - isMultiRootElement ? Utils.capitalize(javaType.getName()) : ""); + + "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()); if (javaType instanceof JavaSimpleType) { out.print("raw = XmlParser.readText(parser);\n"); @@ -398,8 +535,8 @@ public class JavaCodeGenerator { out.println(); } - out.print( - "public static java.lang.String readText(org.xmlpull.v1.XmlPullParser parser)" + out.printf( + "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" @@ -407,11 +544,12 @@ public class JavaCodeGenerator { + " parser.nextTag();\n" + "}\n" + "return result;\n" - + "}\n"); + + "}\n", getDefaultNullability(Nullability.NULLABLE), + getDefaultNullability(Nullability.NON_NULL)); out.println(); - out.print( - "public static void skip(org.xmlpull.v1.XmlPullParser parser)" + out.printf( + "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" + " throw new IllegalStateException();\n" @@ -427,11 +565,106 @@ public class JavaCodeGenerator { + " break;\n" + " }\n" + "}\n" - + "}\n"); + + "}\n", getDefaultNullability(Nullability.NON_NULL)); out.println("}"); } + private void printXmlWriter(CodeWriter out) throws JavaCodeGeneratorException { + out.printf("package %s;\n", packageName); + out.println(); + out.println("public class XmlWriter implements java.io.Closeable {"); + + out.printf("private java.io.PrintWriter out;\n" + + "private StringBuilder outBuffer;\n" + + "private int indent;\n" + + "private boolean startLine;\n\n" + + "public XmlWriter(%sjava.io.PrintWriter printWriter) {\n" + + " out = printWriter;\n" + + " outBuffer = new StringBuilder();\n" + + " indent = 0;\n" + + " startLine = true;\n" + + "}\n\n" + + "private void printIndent() {\n" + + " assert startLine;\n" + + " for (int i = 0; i < indent; ++i) {\n" + + " outBuffer.append(\" \");\n" + + " }\n" + + " startLine = false;\n" + + "}\n\n" + + "void print(String code) {\n" + + " String[] lines = code.split(\"\\n\", -1);\n" + + " for (int i = 0; i < lines.length; ++i) {\n" + + " if (startLine && !lines[i].isEmpty()) {\n" + + " printIndent();\n" + + " }\n" + + " outBuffer.append(lines[i]);\n" + + " if (i + 1 < lines.length) {\n" + + " outBuffer.append(\"\\n\");\n" + + " startLine = true;\n" + + " }\n" + + " }\n" + + "}\n\n" + + "void increaseIndent() {\n" + + " ++indent;\n}\n\n" + + "void decreaseIndent() {\n" + + " --indent;\n" + + "}\n\n" + + "void printXml() {\n" + + " out.print(outBuffer.toString());\n" + + "}\n\n" + + "@Override\n" + + "public void close() {\n" + + " if (out != null) {\n" + + " out.close();\n" + + " }\n" + + "}\n\n", getDefaultNullability(Nullability.NON_NULL)); + + + for (XsdElement element : xmlSchema.getElementMap().values()) { + 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"); + } + out.printf("}\n"); + } + + private void printHexBinaryHelper(CodeWriter out) throws JavaCodeGeneratorException { + out.printf("package %s;\n", packageName); + out.println(); + out.println("public class HexBinaryHelper {"); + out.print("public static byte[] hexStringToByteArray(String hexString) {\n" + + "if (hexString.length() % 2 != 0) {\n" + + "throw new IllegalArgumentException(\"length must be multiple of 2\");\n" + + "}\n" + + "byte[] outputBytes = new byte[hexString.length() / 2];\n" + + "for (int i = 0; i < hexString.length(); i += 2) {\n" + + "char c1 = hexString.charAt(i);\n" + + "char c2 = hexString.charAt(i + 1);\n" + + "outputBytes[i / 2] = (byte) ((Character.digit(c1, 16) << 4)" + + " + Character.digit(c2, 16));\n" + + "}\n" + + "return outputBytes;" + + "}\n\n" + + "public static String byteArrayToHexString(byte[] b) {\n" + + "StringBuffer s = new StringBuffer();\n" + + "for (int i = 0; i < b.length; i++) {\n" + + "s.append(Integer.toHexString(0x100 + (b[i] & 0xff)).substring(1));\n" + + "}\n" + + "return s.toString();\n" + + "}\n" + + "}\n"); + } + private String getElementName(XsdElement element) { if (element instanceof XsdChoice) { return element.getName() + "_optional"; @@ -448,15 +681,31 @@ public class JavaCodeGenerator { return ""; } + private String getDefaultNullability(Nullability nullability) { + if (showNullability) { + return getNullabilityString(nullability); + } + return ""; + } + private String getNullabilityString(Nullability nullability) { if (nullability == Nullability.NON_NULL) { return "@android.annotation.NonNull "; } else if (nullability == Nullability.NULLABLE) { return "@android.annotation.Nullable "; + } else if (showNullability) { + return "@android.annotation.Nullable "; } return ""; } + private String getterName(String type) { + if (type.equals("boolean") && booleanGetter) { + return "is"; + } + return "get"; + } + private void stackComponents(XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes) throws JavaCodeGeneratorException { if (complexType.getBase() != null) { @@ -591,8 +840,8 @@ public class JavaCodeGenerator { XsdRestriction restriction = (XsdRestriction) simpleType; if (restriction.getEnums() != null) { String name = Utils.toClassName(restriction.getName()); - return new JavaSimpleType(name, name + ".valueOf(%s.replace(\".\", \"_\")." - + "replaceAll(\"[^A-Za-z0-9_]\", \"\"))", false); + return new JavaSimpleType(name, name, name + ".fromString(%s)", "%s.toString()", + false); } return parseSimpleType(restriction.getBase(), traverse); } else if (simpleType instanceof XsdUnion) { @@ -658,7 +907,7 @@ public class JavaCodeGenerator { throw new JavaCodeGeneratorException(String.format("not a simple type : %s", name)); } - private static JavaSimpleType predefinedType(String name) throws JavaCodeGeneratorException { + private JavaSimpleType predefinedType(String name) throws JavaCodeGeneratorException { switch (name) { case "string": case "token": @@ -688,51 +937,61 @@ public class JavaCodeGenerator { case "gMonthDay": case "gYearMonth": return new JavaSimpleType("javax.xml.datatype.XMLGregorianCalendar", + "javax.xml.datatype.XMLGregorianCalendar", "javax.xml.datatype.DatatypeFactory.newInstance()" + ".newXMLGregorianCalendar(%s)", - false); + "%s.toString()", false); case "duration": return new JavaSimpleType("javax.xml.datatype.Duration", - "javax.xml.datatype.DatatypeFactory.newInstance().newDuration(%s)", false); + "javax.xml.datatype.Duration", + "javax.xml.datatype.DatatypeFactory.newInstance().newDuration(%s)", + "%s.toString()", false); case "decimal": - return new JavaSimpleType("java.math.BigDecimal", "new java.math.BigDecimal(%s)", - false); + return new JavaSimpleType("java.math.BigDecimal", "java.math.BigDecimal", + "new java.math.BigDecimal(%s)", "%s.toString()", false); case "integer": case "negativeInteger": case "nonNegativeInteger": case "positiveInteger": case "nonPositiveInteger": case "unsignedLong": - return new JavaSimpleType("java.math.BigInteger", "new java.math.BigInteger(%s)", - false); + return new JavaSimpleType("java.math.BigInteger", "java.math.BigInteger", + "new java.math.BigInteger(%s)", "%s.toString()", false); case "long": case "unsignedInt": - return new JavaSimpleType("long", "java.lang.Long", "Long.parseLong(%s)", false); + return new JavaSimpleType("long", "java.lang.Long", "Long.parseLong(%s)", + "Long.toString(%s)", false); case "int": case "unsignedShort": return new JavaSimpleType("int", "java.lang.Integer", "Integer.parseInt(%s)", - false); + "Integer.toString(%s)", false); case "short": case "unsignedByte": return new JavaSimpleType("short", "java.lang.Short", "Short.parseShort(%s)", - false); + "Short.toString(%s)", false); case "byte": - return new JavaSimpleType("byte", "java.lang.Byte", "Byte.parseByte(%s)", false); + return new JavaSimpleType("byte", "java.lang.Byte", "Byte.parseByte(%s)", + "Byte.toString(%s)",false); case "boolean": return new JavaSimpleType("boolean", "java.lang.Boolean", - "Boolean.parseBoolean(%s)", false); + "Boolean.parseBoolean(%s)", "Boolean.toString(%s)", false); case "double": return new JavaSimpleType("double", "java.lang.Double", "Double.parseDouble(%s)", - false); + "Double.toString(%s)", false); case "float": return new JavaSimpleType("float", "java.lang.Float", "Float.parseFloat(%s)", - false); + "Float.toString(%s)", false); case "base64Binary": - return new JavaSimpleType("byte[]", "java.util.Base64.getDecoder().decode(%s)", + return new JavaSimpleType("byte[]", "byte[]", + "java.util.Base64.getDecoder().decode(%s)", + "java.util.Base64.getEncoder().encodeToString(%s)", false); case "hexBinary": - return new JavaSimpleType("java.math.BigInteger", - "new java.math.BigInteger(%s, 16)", false); + useHexBinary = true; + return new JavaSimpleType("byte[]", "byte[]", + "HexBinaryHelper.hexStringToByteArray(%s)", + "HexBinaryHelper.byteArrayToHexString(%s)", + false); } throw new JavaCodeGeneratorException("unknown xsd predefined type : " + name); } diff --git a/src/com/android/xsdc/java/JavaComplexType.java b/src/com/android/xsdc/java/JavaComplexType.java index c0c694a..1a66794 100644 --- a/src/com/android/xsdc/java/JavaComplexType.java +++ b/src/com/android/xsdc/java/JavaComplexType.java @@ -24,6 +24,11 @@ class JavaComplexType implements JavaType { } @Override + public boolean isPrimitiveType() { + return false; + } + + @Override public String getName() { return name; } @@ -37,4 +42,9 @@ class JavaComplexType implements JavaType { public String getParsingExpression() { 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); + } } diff --git a/src/com/android/xsdc/java/JavaSimpleType.java b/src/com/android/xsdc/java/JavaSimpleType.java index 4aac0d1..5c73466 100644 --- a/src/com/android/xsdc/java/JavaSimpleType.java +++ b/src/com/android/xsdc/java/JavaSimpleType.java @@ -20,19 +20,26 @@ class JavaSimpleType implements JavaType { final private String name; final private String nullableName; final private String rawParsingExpression; + final private String rawWritingExpression; final private boolean list; final private String fullName; final private String nullableFullName; - JavaSimpleType(String name, String nullableName, String rawParsingExpression, boolean list) { + JavaSimpleType(String name, String nullableName, String rawParsingExpression, + String rawWritingExpression, boolean list) { this.name = name; this.nullableName = nullableName; this.rawParsingExpression = rawParsingExpression; + this.rawWritingExpression = rawWritingExpression; this.list = list; fullName = list ? String.format("java.util.List<%s>", nullableName) : name; nullableFullName = list ? String.format("java.util.List<%s>", nullableName) : nullableName; } + JavaSimpleType(String name, String nullableName, String rawParsingExpression, boolean list) { + this(name, nullableName, rawParsingExpression, "%s", list); + } + JavaSimpleType(String name, String rawParsingExpression, boolean list) { this(name, name, rawParsingExpression, list); } @@ -43,7 +50,8 @@ class JavaSimpleType implements JavaType { JavaSimpleType newListType() throws JavaCodeGeneratorException { if (list) throw new JavaCodeGeneratorException("list of list is not supported"); - return new JavaSimpleType(name, nullableName, rawParsingExpression, true); + return new JavaSimpleType(name, nullableName, rawParsingExpression, rawWritingExpression, + true); } @Override @@ -52,6 +60,11 @@ class JavaSimpleType implements JavaType { } @Override + public boolean isPrimitiveType() { + return !fullName.equals(nullableName); + } + + @Override public String getNullableName() { return nullableFullName; } @@ -73,4 +86,23 @@ class JavaSimpleType implements JavaType { } return expression.toString(); } + + @Override + public String getWritingExpression(String getValue, String name) { + StringBuilder expression = new StringBuilder(); + if (list) { + 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", + String.format(rawWritingExpression, "v"))); + expression.append("}\n"); + } else { + 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/com/android/xsdc/java/JavaType.java index a0de172..8605f5d 100644 --- a/src/com/android/xsdc/java/JavaType.java +++ b/src/com/android/xsdc/java/JavaType.java @@ -24,4 +24,8 @@ interface JavaType { String getNullableName(); String getParsingExpression(); + + String getWritingExpression(String getValue, String name); + + boolean isPrimitiveType(); } diff --git a/src/com/android/xsdc/java/Utils.java b/src/com/android/xsdc/java/Utils.java index 4d825e9..5a7a92a 100644 --- a/src/com/android/xsdc/java/Utils.java +++ b/src/com/android/xsdc/java/Utils.java @@ -72,6 +72,9 @@ class Utils { } static String toEnumName(String name) throws JavaCodeGeneratorException { + if ("".equals(name)) { + name = "EMPTY"; + } String trimmed = name.replace(".", "_").replaceAll("[^A-Za-z0-9_]", ""); if (trimmed.isEmpty()) { throw new JavaCodeGeneratorException( diff --git a/src/com/android/xsdc/tag/XsdAttribute.java b/src/com/android/xsdc/tag/XsdAttribute.java index d940ed4..0c46eb0 100644 --- a/src/com/android/xsdc/tag/XsdAttribute.java +++ b/src/com/android/xsdc/tag/XsdAttribute.java @@ -22,8 +22,9 @@ import javax.xml.namespace.QName; public class XsdAttribute extends XsdTag { final private XsdType type; + final private boolean required; - public XsdAttribute(String name, QName ref, XsdType type) + public XsdAttribute(String name, QName ref, XsdType type, boolean required) throws XsdParserException { super(name, ref); if (name == null && ref == null) { @@ -33,9 +34,14 @@ public class XsdAttribute extends XsdTag { throw new XsdParserException("type definition should exist"); } this.type = type; + this.required = required; } public XsdType getType() { return type; } + + public boolean isRequired() { + return required; + } } diff --git a/tests/Android.bp b/tests/Android.bp index afd6150..ab44220 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -1,21 +1,47 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} java_test_host { name: "xsdc-java-tests", - srcs: ["src/**/*.java"], + srcs: [ + "src/**/*.java", + ":xsdc_attr_group_simple_tests", + ":xsdc_attr_enumtype_tests", + ":xsdc_group_tests", + ":xsdc_nested_type_tests", + ":xsdc_predefined_types_tests", + ":xsdc_purchase_simple_tests", + ":xsdc_reference_tests", + ":xsdc_simple_complex_content_tests", + ":xsdc_simple_type_tests", + ], + test_options: { + unit_test: true, + }, static_libs: [ "junit", "xsdc", + "stub-annotations", + "kxml2-2.3.0", ], - java_resource_dirs: ["resources"] + java_resource_dirs: ["resources"], + test_suites: ["general-tests"], } cc_test_host { name: "xsdc-cpp-tests", srcs: [ + "simple_type.cpp", + "tests.cpp", "main.cpp", ], + test_options: { + unit_test: true, + }, generated_sources: [ "xsdc_attr_group_simple_tests", + "xsdc_attr_enumtype_tests", "xsdc_group_tests", "xsdc_nested_type_tests", "xsdc_predefined_types_tests", @@ -26,6 +52,7 @@ cc_test_host { ], generated_headers: [ "xsdc_attr_group_simple_tests", + "xsdc_attr_enumtype_tests", "xsdc_group_tests", "xsdc_nested_type_tests", "xsdc_predefined_types_tests", @@ -34,9 +61,64 @@ cc_test_host { "xsdc_simple_complex_content_tests", "xsdc_simple_type_tests", ], + header_libs: ["libxsdc-utils"], + shared_libs: [ + "libbase", + "libxml2", + ], + data: ["resources/*.xml"], + test_suites: ["general-tests"], +} + +// These tests verify that enums-only and parser-only +// modules can be combined later. +cc_test_host { + name: "xsdc-cpp-tests-split", + srcs: [ + "simple_type.cpp", + "main.cpp", + ], + test_options: { + unit_test: true, + }, + generated_sources: [ + "xsdc_simple_type_tests_enums", + "xsdc_simple_type_tests_parser", + ], + generated_headers: [ + "xsdc_simple_type_tests_enums", + "xsdc_simple_type_tests_parser", + ], + header_libs: ["libxsdc-utils"], shared_libs: [ "libbase", "libxml2", ], data: ["resources/*.xml"], + test_suites: ["general-tests"], +} + +// These tests verify that enums-only module can be used on +// its own and it does not depend on libxml2. +cc_test_host { + name: "xsdc-cpp-tests-enums", + srcs: [ + "simple_type_enumsonly.cpp", + "main.cpp", + ], + test_options: { + unit_test: true, + }, + generated_sources: [ + "xsdc_simple_type_tests_enums", + ], + generated_headers: [ + "xsdc_simple_type_tests_enums", + ], + header_libs: ["libxsdc-utils"], + shared_libs: [ + "libbase", + ], + data: ["resources/*.xml"], + test_suites: ["general-tests"], } diff --git a/tests/main.cpp b/tests/main.cpp index fa9d82c..5e91e2d 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2021 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. @@ -14,212 +14,7 @@ * limitations under the License. */ -#include <iostream> -#include <string> #include <gtest/gtest.h> -#include "nested_type.h" -#include "purchase_simple.h" -#include "simple_complex_content.h" - -#include "predefined_types.h" -#include "reference.h" -#include "simple_type.h" -#include "attr_group_simple.h" -#include "group.h" - -using namespace std; - -class XmlTest : public ::testing::Test { -public: - virtual void SetUp() override { - } - virtual void TearDown() override { - } -}; - -TEST_F(XmlTest, Simpletype) { - using namespace simple::type; - string file_name = "resources/simple_type.xml"; - SimpleTypes simple = *readSimpleTypes(file_name.c_str()); - - for (int i = 0; i < simple.getListInt().size(); ++i) { - EXPECT_EQ(simple.getListInt()[i], i + 1); - } - EXPECT_EQ(*simple.getFirstUnionTest(), "100"); - EXPECT_EQ(simple.getYesOrNo()[0], EnumType::YES); - EXPECT_EQ(simple.getYesOrNo()[1], EnumType::EMPTY); -} - -TEST_F(XmlTest, Predefinedtypes) { - using namespace predefined::types; - Types type = *read("resources/predefined_types.xml"); - - StringTypes stringTypes = *type.getFirstStringTypes(); - DateTypes dateTypes = *type.getFirstDateTypes(); - NumericTypes numericTypes = *type.getFirstNumericTypes(); - MiscTypes miscTypes = *type.getFirstMiscTypes(); - ListPrimitiveTypes listPrimitiveTypes = *type.getFirstListPrimitiveTypes(); - - EXPECT_EQ(stringTypes.getString(), "abcd"); - EXPECT_EQ(stringTypes.getToken(), "abcd"); - EXPECT_EQ(stringTypes.getNormalizedString(), "abcd"); - EXPECT_EQ(stringTypes.getLanguage(), "abcd"); - EXPECT_EQ(stringTypes.getEntity(), "abcd"); - EXPECT_EQ(stringTypes.getEntities()[0], "a"); - EXPECT_EQ(stringTypes.getEntities()[1], "b"); - EXPECT_EQ(stringTypes.getEntities()[2], "c"); - EXPECT_EQ(stringTypes.getEntities()[3], "d"); - EXPECT_EQ(stringTypes.getId(), "abcd"); - EXPECT_EQ(stringTypes.getName(), "abcd"); - EXPECT_EQ(stringTypes.getNcname(), "abcd"); - EXPECT_EQ(stringTypes.getNmtoken(), "abcd"); - EXPECT_EQ(stringTypes.getNmtokens()[0], "a"); - EXPECT_EQ(stringTypes.getNmtokens()[1], "b"); - EXPECT_EQ(stringTypes.getNmtokens()[2], "c"); - EXPECT_EQ(stringTypes.getNmtokens()[3], "d"); - - - EXPECT_EQ(dateTypes.getDate(), "2018-06-18"); - EXPECT_EQ(dateTypes.getDateTime(), "2018-06-18T21:32:52"); - EXPECT_EQ(dateTypes.getDuration(), "P3M"); - EXPECT_EQ(dateTypes.getGDay(), "---18"); - EXPECT_EQ(dateTypes.getGMonth(), "--06"); - EXPECT_EQ(dateTypes.getGMonthDay(), "--06-18"); - EXPECT_EQ(dateTypes.getGYear(), "2018"); - EXPECT_EQ(dateTypes.getGYearMonth(), "2018-06"); - EXPECT_EQ(dateTypes.getTime(), "21:32:52"); - - EXPECT_EQ(numericTypes.getDecimal(), 1234.57); - EXPECT_EQ(numericTypes.getInteger(), 1234567890123456789); - EXPECT_EQ(numericTypes.get_long(), 9223372036854775807); - EXPECT_EQ(numericTypes.get_int(), 2147483647); - EXPECT_EQ(numericTypes.get_short(), 32767); - EXPECT_EQ((int)numericTypes.getByte(), 127); - EXPECT_EQ(numericTypes.getNegativeInteger(), -1234); - EXPECT_EQ(numericTypes.getNonNegativeInteger(), 1234); - EXPECT_EQ(numericTypes.getPositiveInteger(), 1234); - EXPECT_EQ(numericTypes.getNonPositiveInteger(), -1234); - EXPECT_EQ(numericTypes.getUnsignedLong(), 1234); - EXPECT_EQ(numericTypes.getUnsignedInt(), 1234); - EXPECT_EQ(numericTypes.getUnsignedShort(), 1234); - EXPECT_EQ((int)(numericTypes.getUnsignedByte()), 255); - - EXPECT_EQ(miscTypes.get_double(), 1234.57); - EXPECT_EQ(miscTypes.getAnyURI(), "https://www.google.com"); - EXPECT_EQ(miscTypes.getBase64Binary(), "Z29vZ2xl"); - EXPECT_TRUE(miscTypes.getBoolean()); - EXPECT_EQ(miscTypes.getHexBinary(), "516a75cb56d7e7"); - EXPECT_EQ(miscTypes.getQName(), "abcd"); - EXPECT_EQ(miscTypes.getIDREF(), "abcd"); - EXPECT_EQ(miscTypes.getIDREFS()[0], "abcd"); - EXPECT_EQ(miscTypes.getIDREFS()[1], "abcd"); - EXPECT_EQ(miscTypes.getAnyType(), "abcd"); - - EXPECT_EQ(listPrimitiveTypes.getListInt()[0], -2147483648); - EXPECT_EQ(listPrimitiveTypes.getListInt()[1], 2147483647); - EXPECT_EQ(listPrimitiveTypes.getListShort()[0], -32768); - EXPECT_EQ(listPrimitiveTypes.getListShort()[1], 32767); - EXPECT_EQ((int)listPrimitiveTypes.getListByte()[0], -128); - EXPECT_EQ((int)listPrimitiveTypes.getListByte()[1], 127); - EXPECT_EQ(listPrimitiveTypes.getListDouble()[0], 1234.56); - EXPECT_EQ(listPrimitiveTypes.getListDouble()[1], 5678.12); - EXPECT_TRUE(listPrimitiveTypes.getListBoolean()[0]); - EXPECT_FALSE(listPrimitiveTypes.getListBoolean()[1]); - -} - -TEST_F(XmlTest, Nestedtype) { - using namespace nested::type; - Employee employee = *read("resources/nested_type.xml"); - - Employee::Address address = *employee.getFirstAddress(); - Employee::Address::Extra extra = *address.getFirstExtra(); - - EXPECT_EQ((int)employee.getId(), 1); - EXPECT_EQ(employee.getName(), "Peter"); - EXPECT_EQ(address.getCountry(), "US"); - EXPECT_EQ(address.getState(), "Mountain View"); - EXPECT_EQ(address.getZip(), 3342); - EXPECT_EQ(extra.getLine1(), "Donga 303-111"); - EXPECT_EQ(extra.getLine2(), "Good Street"); -} - -TEST_F(XmlTest, Purchasesimple) { - using namespace purchase::simple; - PurchaseOrderType orderType = *read("resources/purchase_simple.xml"); - - EXPECT_EQ(orderType.getOrderDate(), "1900-01-01"); - - EXPECT_EQ(orderType.getShipTo()[0].getName(), "name1"); - EXPECT_EQ(orderType.getShipTo()[0].getStreet(), "street1"); - EXPECT_EQ(orderType.getShipTo()[0].getCity(), "city1"); - EXPECT_EQ(orderType.getShipTo()[0].getState(), "state1"); - EXPECT_EQ(orderType.getShipTo()[0].getZip(), 1); - EXPECT_EQ(orderType.getShipTo()[0].getCountry(), "US"); - EXPECT_EQ(orderType.getShipTo()[1].getName(), "name2"); - EXPECT_EQ(orderType.getShipTo()[1].getStreet(), "street2"); - EXPECT_EQ(orderType.getShipTo()[1].getCity(), "city2"); - EXPECT_EQ(orderType.getShipTo()[1].getState(), "state2"); - EXPECT_EQ(orderType.getShipTo()[1].getZip(), -7922816251426433759); - EXPECT_EQ(orderType.getShipTo()[1].getCountry(), "US"); - - EXPECT_EQ(orderType.getBillTo()[0].getName(), "billName"); - EXPECT_EQ(orderType.getBillTo()[0].getStreet(), "billStreet"); - EXPECT_EQ(orderType.getBillTo()[0].getCity(), "billCity"); - EXPECT_EQ(orderType.getBillTo()[0].getState(), "billState"); - EXPECT_EQ(orderType.getBillTo()[0].getZip(), 1); - EXPECT_EQ(orderType.getBillTo()[0].getCountry(), "US"); -} - -TEST_F(XmlTest, Reference) { - using namespace reference; - Class _class = *read("resources/reference.xml"); - - EXPECT_EQ(_class.getStudent()[0], "Sam"); - EXPECT_EQ(_class.getStudent()[1], "Paul"); - EXPECT_EQ(_class.getStudent()[2], "Peter"); -} - -TEST_F(XmlTest, Simplecomplexcontent) { - using namespace simple::complex::content; - Person person = *readPerson("resources/simple_complex_content.xml"); - USAddressP uSAddressP = *person.getFirstUSAddressP(); - KRAddress kRAddress = *person.getFirstKRAddress(); - SubAddress subAddress = *person.getFirstSubAddress(); - - EXPECT_EQ(person.getName(), "Petr"); - - EXPECT_EQ(uSAddressP.getName(), "404"); - EXPECT_EQ(uSAddressP.getStreet(), "street fighter"); - EXPECT_EQ(uSAddressP.getCity(), "New York"); - EXPECT_EQ(uSAddressP.getState(), "Washington"); - EXPECT_EQ(uSAddressP.getZipcode(), 323232318329852); - - EXPECT_EQ(kRAddress.getName(), "Donga Studio"); - EXPECT_EQ(kRAddress.getStreet(), "Nokdu Street"); - EXPECT_EQ(kRAddress.getCity(), "Seoul"); - - EXPECT_EQ(subAddress.getChoice1_optional(), "Temp"); -} - -TEST_F(XmlTest, Attrgroupsimple) { - using namespace attr::group::simple; - Student student = *read("resources/attr_group_simple.xml"); - - EXPECT_EQ(student.getName(), "Jun"); - EXPECT_EQ(student.getCity(), "Mountain View"); - EXPECT_EQ(student.getState(), "CA"); - EXPECT_EQ(student.getRoad(), "Street 101"); -} - -TEST_F(XmlTest, Group) { - using namespace group; - Student student = *read("resources/group.xml"); - - EXPECT_EQ(student.getCity(), "Mountain View"); - EXPECT_EQ(student.getState(), "CA"); - EXPECT_EQ(student.getRoad(), "Street 101"); -} int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/tests/resources/attr_group_simple.xml b/tests/resources/attr_group_simple.xml index fb3bfc8..0a14222 100644 --- a/tests/resources/attr_group_simple.xml +++ b/tests/resources/attr_group_simple.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<Student State="CA" city="Mountain View" road="Street 101"> +<Student State="CA" city="Mountain View" road="Street 101" list="1 2 3"> <Name>Jun</Name> </Student> diff --git a/tests/resources/attr_group_simple/Android.bp b/tests/resources/attr_group_simple/Android.bp index fe62b55..ef3136d 100644 --- a/tests/resources/attr_group_simple/Android.bp +++ b/tests/resources/attr_group_simple/Android.bp @@ -1,7 +1,11 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_attr_group_simple_tests", srcs: ["attr_group_simple.xsd"], package_name: "attr.group.simple", + gen_writer: true, } - diff --git a/tests/resources/attr_group_simple/api/current.txt b/tests/resources/attr_group_simple/api/current.txt index 20aefda..9203633 100644 --- a/tests/resources/attr_group_simple/api/current.txt +++ b/tests/resources/attr_group_simple/api/current.txt @@ -4,10 +4,12 @@ package attr.group.simple { public class Student { ctor public Student(); method public String getCity(); + method public java.util.List<java.lang.Integer> getList(); method public String getName(); method public String getRoad(); method public String getState(); method public void setCity(String); + method public void setList(java.util.List<java.lang.Integer>); method public void setName(String); method public void setRoad(String); method public void setState(String); @@ -20,5 +22,11 @@ package attr.group.simple { method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; } + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + method public static void write(attr.group.simple.XmlWriter, attr.group.simple.Student) throws java.io.IOException; + } + } diff --git a/tests/resources/attr_group_simple/attr_group_simple.xsd b/tests/resources/attr_group_simple/attr_group_simple.xsd index 7f94e31..0853848 100644 --- a/tests/resources/attr_group_simple/attr_group_simple.xsd +++ b/tests/resources/attr_group_simple/attr_group_simple.xsd @@ -1,18 +1,22 @@ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="attr_group_simple" elementFormDefault="qualified"> <xs:attributeGroup name="address"> <xs:attribute name="State" type="xs:string"/> - <xs:attribute name="city" type="xs:string"/> + <xs:attribute name="city" type="xs:string" use="required"/> </xs:attributeGroup> <xs:attributeGroup name="homeAddress"> <xs:attributeGroup ref="address"/> <xs:attribute name="road" type="xs:string"/> </xs:attributeGroup> + <xs:simpleType name="listInt"> + <xs:list itemType="xs:int" /> + </xs:simpleType> <xs:element name="Student"> <xs:complexType> <xs:sequence> <xs:element name="Name" type="xs:string"/> </xs:sequence> <xs:attributeGroup ref="homeAddress"/> + <xs:attribute name="list" type="listInt" use="required"/> </xs:complexType> </xs:element> </xs:schema> diff --git a/tests/resources/enum_type/Android.bp b/tests/resources/enum_type/Android.bp new file mode 100644 index 0000000..979ae6d --- /dev/null +++ b/tests/resources/enum_type/Android.bp @@ -0,0 +1,9 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +xsd_config { + name: "xsdc_attr_enumtype_tests", + srcs: ["attr_enumtype.xsd"], + package_name: "attr.enumtype", +} diff --git a/tests/resources/enum_type/api/current.txt b/tests/resources/enum_type/api/current.txt new file mode 100644 index 0000000..263deed --- /dev/null +++ b/tests/resources/enum_type/api/current.txt @@ -0,0 +1,532 @@ +// Signature format: 2.0 +package attr.enumtype { + + public class AttachedDevices { + ctor public AttachedDevices(); + method public java.util.List<java.lang.String> getItem(); + } + + public enum AudioChannelMask { + method public String getRawName(); + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_1; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_10; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_11; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_12; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_13; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_14; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_15; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_16; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_17; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_18; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_19; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_2; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_20; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_21; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_22; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_23; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_24; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_3; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_4; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_5; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_6; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_7; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_8; + enum_constant public static final attr.enumtype.AudioChannelMask INDEX_MASK_9; + enum_constant public static final attr.enumtype.AudioChannelMask IN_2POINT0POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask IN_2POINT1POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask IN_3POINT0POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask IN_3POINT1POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask IN_5POINT1; + enum_constant public static final attr.enumtype.AudioChannelMask IN_6; + enum_constant public static final attr.enumtype.AudioChannelMask IN_FRONT_BACK; + enum_constant public static final attr.enumtype.AudioChannelMask IN_MONO; + enum_constant public static final attr.enumtype.AudioChannelMask IN_STEREO; + enum_constant public static final attr.enumtype.AudioChannelMask IN_VOICE_CALL_MONO; + enum_constant public static final attr.enumtype.AudioChannelMask IN_VOICE_DNLINK_MONO; + enum_constant public static final attr.enumtype.AudioChannelMask IN_VOICE_UPLINK_MONO; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_2POINT0POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_2POINT1; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_2POINT1POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_3POINT0POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_3POINT1POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_5POINT1; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_5POINT1POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_5POINT1POINT4; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_6POINT1; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_7POINT1; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_7POINT1POINT2; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_7POINT1POINT4; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_HAPTIC_AB; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_MONO; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_MONO_HAPTIC_A; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_MONO_HAPTIC_AB; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_PENTA; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_QUAD; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_QUAD_BACK; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_QUAD_SIDE; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_STEREO; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_STEREO_HAPTIC_A; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_STEREO_HAPTIC_AB; + enum_constant public static final attr.enumtype.AudioChannelMask OUT_SURROUND; + } + + public enum AudioContentType { + method public String getRawName(); + enum_constant public static final attr.enumtype.AudioContentType AUDIO_CONTENT_TYPE_MOVIE; + enum_constant public static final attr.enumtype.AudioContentType AUDIO_CONTENT_TYPE_MUSIC; + enum_constant public static final attr.enumtype.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION; + enum_constant public static final attr.enumtype.AudioContentType AUDIO_CONTENT_TYPE_SPEECH; + enum_constant public static final attr.enumtype.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN; + } + + public enum AudioDevice { + method public String getRawName(); + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_AMBIENT; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_BACK_MIC; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_BUS; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_DEFAULT; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_FM_TUNER; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_HDMI; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_IP; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_LINE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_LOOPBACK; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_PROXY; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_SPDIF; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_STUB; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_TV_TUNER; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_NONE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_BUS; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_DEFAULT; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_EARPIECE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_FM; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_HDMI; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_IP; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_LINE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_PROXY; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_SPDIF; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_SPEAKER; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_STUB; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + enum_constant public static final attr.enumtype.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET; + } + + public enum AudioFormat { + method public String getRawName(); + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADIF; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ELD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_ERLC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_HE_V1; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_HE_V2; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_LATM; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_LATM_LC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_LC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_LD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_LTP; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_MAIN; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_SCALABLE; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_SSR; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AAC_XHE; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AC3; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AC4; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_ALAC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AMR_NB; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AMR_WB; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_APE; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_APTX; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_APTX_HD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_APTX_TWSP; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_CELT; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_DSD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_DTS; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_DTS_HD; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_EVRC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_EVRCB; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_EVRCNW; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_EVRCWB; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_E_AC3; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_E_AC3_JOC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_FLAC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_HE_AAC_V1; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_HE_AAC_V2; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_IEC61937; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_LDAC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_LHDC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_LHDC_LL; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_MAT_1_0; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_MAT_2_0; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_MAT_2_1; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_MP2; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_MP3; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_OPUS; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_PCM_16_BIT; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_PCM_32_BIT; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_PCM_8_BIT; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_PCM_FLOAT; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_QCELP; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_SBC; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_VORBIS; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_WMA; + enum_constant public static final attr.enumtype.AudioFormat AUDIO_FORMAT_WMA_PRO; + } + + public class AudioPolicyConfiguration { + ctor public AudioPolicyConfiguration(); + method public attr.enumtype.GlobalConfiguration getGlobalConfiguration(); + method public java.util.List<attr.enumtype.Modules> getModules(); + method public attr.enumtype.SurroundSound getSurroundSound(); + method public attr.enumtype.Version getVersion(); + method public java.util.List<attr.enumtype.Volumes> getVolumes(); + method public void setGlobalConfiguration(attr.enumtype.GlobalConfiguration); + method public void setSurroundSound(attr.enumtype.SurroundSound); + method public void setVersion(attr.enumtype.Version); + } + + public enum AudioSource { + method public String getRawName(); + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_CAMCORDER; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_DEFAULT; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_ECHO_REFERENCE; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_FM_TUNER; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_HOTWORD; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_MIC; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_REMOTE_SUBMIX; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_UNPROCESSED; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_VOICE_CALL; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_VOICE_COMMUNICATION; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_VOICE_DOWNLINK; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_VOICE_PERFORMANCE; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_VOICE_RECOGNITION; + enum_constant public static final attr.enumtype.AudioSource AUDIO_SOURCE_VOICE_UPLINK; + } + + public enum AudioStreamType { + method public String getRawName(); + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_ACCESSIBILITY; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_ALARM; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_ASSISTANT; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_BLUETOOTH_SCO; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_DEFAULT; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_DTMF; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_ENFORCED_AUDIBLE; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_MUSIC; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_NOTIFICATION; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_PATCH; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_REROUTING; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_RING; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_SYSTEM; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_TTS; + enum_constant public static final attr.enumtype.AudioStreamType AUDIO_STREAM_VOICE_CALL; + } + + public enum AudioUsage { + method public String getRawName(); + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_ALARM; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_ANNOUNCEMENT; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_ASSISTANT; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_CALL_ASSISTANT; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_EMERGENCY; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_GAME; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_MEDIA; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_NOTIFICATION; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_SAFETY; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_UNKNOWN; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_VEHICLE_STATUS; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION; + enum_constant public static final attr.enumtype.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; + } + + public enum DeviceCategory { + method public String getRawName(); + enum_constant public static final attr.enumtype.DeviceCategory DEVICE_CATEGORY_EARPIECE; + enum_constant public static final attr.enumtype.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA; + enum_constant public static final attr.enumtype.DeviceCategory DEVICE_CATEGORY_HEADSET; + enum_constant public static final attr.enumtype.DeviceCategory DEVICE_CATEGORY_HEARING_AID; + enum_constant public static final attr.enumtype.DeviceCategory DEVICE_CATEGORY_SPEAKER; + } + + public class DevicePorts { + ctor public DevicePorts(); + method public java.util.List<attr.enumtype.DevicePorts.DevicePort> getDevicePort(); + } + + public static class DevicePorts.DevicePort { + ctor public DevicePorts.DevicePort(); + method public String getAddress(); + method public java.util.List<attr.enumtype.AudioFormat> getEncodedFormats(); + method public attr.enumtype.Gains getGains(); + method public java.util.List<attr.enumtype.Profile> getProfile(); + method public attr.enumtype.Role getRole(); + method public String getTagName(); + method public String getType(); + method public boolean get_default(); + method public void setAddress(String); + method public void setEncodedFormats(java.util.List<attr.enumtype.AudioFormat>); + method public void setGains(attr.enumtype.Gains); + method public void setRole(attr.enumtype.Role); + method public void setTagName(String); + method public void setType(String); + method public void set_default(boolean); + } + + public enum EngineSuffix { + method public String getRawName(); + enum_constant public static final attr.enumtype.EngineSuffix _default; + enum_constant public static final attr.enumtype.EngineSuffix configurable; + } + + public enum GainMode { + method public String getRawName(); + enum_constant public static final attr.enumtype.GainMode AUDIO_GAIN_MODE_CHANNELS; + enum_constant public static final attr.enumtype.GainMode AUDIO_GAIN_MODE_JOINT; + enum_constant public static final attr.enumtype.GainMode AUDIO_GAIN_MODE_RAMP; + } + + public class Gains { + ctor public Gains(); + method public java.util.List<attr.enumtype.Gains.Gain> getGain(); + } + + public static class Gains.Gain { + ctor public Gains.Gain(); + method public String getChannel_mask(); + method public int getDefaultValueMB(); + method public int getMaxRampMs(); + method public int getMaxValueMB(); + method public int getMinRampMs(); + method public int getMinValueMB(); + method public attr.enumtype.GainMode getMode(); + method public String getName(); + method public int getStepValueMB(); + method public boolean getUseForVolume(); + method public void setChannel_mask(String); + method public void setDefaultValueMB(int); + method public void setMaxRampMs(int); + method public void setMaxValueMB(int); + method public void setMinRampMs(int); + method public void setMinValueMB(int); + method public void setMode(attr.enumtype.GainMode); + method public void setName(String); + method public void setStepValueMB(int); + method public void setUseForVolume(boolean); + } + + public class GlobalConfiguration { + ctor public GlobalConfiguration(); + method public boolean getCall_screen_mode_supported(); + method public attr.enumtype.EngineSuffix getEngine_library(); + method public boolean getSpeaker_drc_enabled(); + method public void setCall_screen_mode_supported(boolean); + method public void setEngine_library(attr.enumtype.EngineSuffix); + method public void setSpeaker_drc_enabled(boolean); + } + + public enum HalVersion { + method public String getRawName(); + enum_constant public static final attr.enumtype.HalVersion _2_0; + enum_constant public static final attr.enumtype.HalVersion _3_0; + } + + public class MixPorts { + ctor public MixPorts(); + method public java.util.List<attr.enumtype.MixPorts.MixPort> getMixPort(); + } + + public static class MixPorts.MixPort { + ctor public MixPorts.MixPort(); + method public String getFlags(); + method public attr.enumtype.Gains getGains(); + method public long getMaxActiveCount(); + method public long getMaxOpenCount(); + method public String getName(); + method public java.util.List<attr.enumtype.AudioUsage> getPreferredUsage(); + method public java.util.List<attr.enumtype.Profile> getProfile(); + method public attr.enumtype.Role getRole(); + method public void setFlags(String); + method public void setGains(attr.enumtype.Gains); + method public void setMaxActiveCount(long); + method public void setMaxOpenCount(long); + method public void setName(String); + method public void setPreferredUsage(java.util.List<attr.enumtype.AudioUsage>); + method public void setRole(attr.enumtype.Role); + } + + public enum MixType { + method public String getRawName(); + enum_constant public static final attr.enumtype.MixType mix; + enum_constant public static final attr.enumtype.MixType mux; + } + + public class Modules { + ctor public Modules(); + method public java.util.List<attr.enumtype.Modules.Module> getModule(); + } + + public static class Modules.Module { + ctor public Modules.Module(); + method public attr.enumtype.AttachedDevices getAttachedDevices(); + method public String getDefaultOutputDevice(); + method public attr.enumtype.DevicePorts getDevicePorts(); + method public attr.enumtype.HalVersion getHalVersion(); + method public attr.enumtype.MixPorts getMixPorts(); + method public String getName(); + method public attr.enumtype.Routes getRoutes(); + method public void setAttachedDevices(attr.enumtype.AttachedDevices); + method public void setDefaultOutputDevice(String); + method public void setDevicePorts(attr.enumtype.DevicePorts); + method public void setHalVersion(attr.enumtype.HalVersion); + method public void setMixPorts(attr.enumtype.MixPorts); + method public void setName(String); + method public void setRoutes(attr.enumtype.Routes); + } + + public class Profile { + ctor public Profile(); + method public String getChannelMasks(); + method public String getFormat(); + method public String getName(); + method public String getSamplingRates(); + method public void setChannelMasks(String); + method public void setFormat(String); + method public void setName(String); + method public void setSamplingRates(String); + } + + public class Reference { + ctor public Reference(); + method public String getName(); + method public java.util.List<java.lang.String> getPoint(); + method public void setName(String); + } + + public enum Role { + method public String getRawName(); + enum_constant public static final attr.enumtype.Role sink; + enum_constant public static final attr.enumtype.Role source; + } + + public class Routes { + ctor public Routes(); + method public java.util.List<attr.enumtype.Routes.Route> getRoute(); + } + + public static class Routes.Route { + ctor public Routes.Route(); + method public String getSink(); + method public String getSources(); + method public attr.enumtype.MixType getType(); + method public void setSink(String); + method public void setSources(String); + method public void setType(attr.enumtype.MixType); + } + + public class SurroundFormats { + ctor public SurroundFormats(); + method public java.util.List<attr.enumtype.SurroundFormats.Format> getFormat(); + } + + public static class SurroundFormats.Format { + ctor public SurroundFormats.Format(); + method public attr.enumtype.AudioFormat getName(); + method public java.util.List<attr.enumtype.AudioFormat> getSubformats(); + method public void setName(attr.enumtype.AudioFormat); + method public void setSubformats(java.util.List<attr.enumtype.AudioFormat>); + } + + public class SurroundSound { + ctor public SurroundSound(); + method public attr.enumtype.SurroundFormats getFormats(); + method public void setFormats(attr.enumtype.SurroundFormats); + } + + public enum Version { + method public String getRawName(); + enum_constant public static final attr.enumtype.Version _1_0; + } + + public class Volume { + ctor public Volume(); + method public attr.enumtype.DeviceCategory getDeviceCategory(); + method public java.util.List<java.lang.String> getPoint(); + method public String getRef(); + method public attr.enumtype.AudioStreamType getStream(); + method public void setDeviceCategory(attr.enumtype.DeviceCategory); + method public void setRef(String); + method public void setStream(attr.enumtype.AudioStreamType); + } + + public class Volumes { + ctor public Volumes(); + method public java.util.List<attr.enumtype.Reference> getReference(); + method public java.util.List<attr.enumtype.Volume> getVolume(); + } + + public class XmlParser { + ctor public XmlParser(); + method public static attr.enumtype.AudioPolicyConfiguration read(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; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/tests/resources/enum_type/api/last_current.txt b/tests/resources/enum_type/api/last_current.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/resources/enum_type/api/last_current.txt diff --git a/tests/resources/enum_type/api/last_removed.txt b/tests/resources/enum_type/api/last_removed.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/resources/enum_type/api/last_removed.txt diff --git a/tests/resources/enum_type/api/removed.txt b/tests/resources/enum_type/api/removed.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/tests/resources/enum_type/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/tests/resources/enum_type/attr_enumtype.xsd b/tests/resources/enum_type/attr_enumtype.xsd new file mode 100644 index 0000000..65223b1 --- /dev/null +++ b/tests/resources/enum_type/attr_enumtype.xsd @@ -0,0 +1,743 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema version="2.0" + elementFormDefault="qualified" + attributeFormDefault="unqualified" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <!-- List the config versions supported by audio policy. --> + <xs:simpleType name="version"> + <xs:restriction base="xs:decimal"> + <xs:enumeration value="1.0"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="halVersion"> + <xs:restriction base="xs:decimal"> + <!-- List of HAL versions supported by the framework. --> + <xs:enumeration value="2.0"/> + <xs:enumeration value="3.0"/> + </xs:restriction> + </xs:simpleType> + <xs:element name="audioPolicyConfiguration"> + <xs:complexType> + <xs:sequence> + <xs:element name="globalConfiguration" type="globalConfiguration"/> + <xs:element name="modules" type="modules" maxOccurs="unbounded"/> + <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/> + <xs:element name="surroundSound" type="surroundSound" minOccurs="0" /> + </xs:sequence> + <xs:attribute name="version" type="version"/> + </xs:complexType> + <xs:key name="moduleNameKey"> + <xs:selector xpath="modules/module"/> + <xs:field xpath="@name"/> + </xs:key> + <xs:unique name="volumeTargetUniqueness"> + <xs:selector xpath="volumes/volume"/> + <xs:field xpath="@stream"/> + <xs:field xpath="@deviceCategory"/> + </xs:unique> + <xs:key name="volumeCurveNameKey"> + <xs:selector xpath="volumes/reference"/> + <xs:field xpath="@name"/> + </xs:key> + <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey"> + <xs:selector xpath="volumes/volume"/> + <xs:field xpath="@ref"/> + </xs:keyref> + </xs:element> + <xs:complexType name="globalConfiguration"> + <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/> + <xs:attribute name="call_screen_mode_supported" type="xs:boolean" use="optional"/> + <xs:attribute name="engine_library" type="engineSuffix" use="optional"/> + </xs:complexType> + <xs:complexType name="modules"> + <xs:annotation> + <xs:documentation xml:lang="en"> + There should be one section per audio HW module present on the platform. + Each <module/> contains two mandatory tags: “halVersion” and “name”. + The module "name" is the same as in previous .conf file. + Each module must contain the following sections: + - <devicePorts/>: a list of device descriptors for all + input and output devices accessible via this module. + This contains both permanently attached devices and removable devices. + - <mixPorts/>: listing all output and input streams exposed by the audio HAL + - <routes/>: list of possible connections between input + and output devices or between stream and devices. + A <route/> is defined by a set of 3 attributes: + -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix) + -"sink": the sink involved in this route + -"sources": all the sources than can be connected to the sink via this route + - <attachedDevices/>: permanently attached devices. + The attachedDevices section is a list of devices names. + Their names correspond to device names defined in "devicePorts" section. + - <defaultOutputDevice/> is the device to be used when no policy rule applies + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element name="module" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0"> + <xs:unique name="attachedDevicesUniqueness"> + <xs:selector xpath="item"/> + <xs:field xpath="."/> + </xs:unique> + </xs:element> + <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/> + <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/> + <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/> + <xs:element name="routes" type="routes" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="halVersion" type="halVersion" use="required"/> + </xs:complexType> + <xs:unique name="mixPortNameUniqueness"> + <xs:selector xpath="mixPorts/mixPort"/> + <xs:field xpath="@name"/> + </xs:unique> + <xs:key name="devicePortNameKey"> + <xs:selector xpath="devicePorts/devicePort"/> + <xs:field xpath="@tagName"/> + </xs:key> + <xs:unique name="devicePortUniqueness"> + <xs:selector xpath="devicePorts/devicePort"/> + <xs:field xpath="@type"/> + <xs:field xpath="@address"/> + </xs:unique> + <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey"> + <xs:selector xpath="defaultOutputDevice"/> + <xs:field xpath="."/> + </xs:keyref> + <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey"> + <xs:selector xpath="attachedDevices/item"/> + <xs:field xpath="."/> + </xs:keyref> + <!-- The following 3 constraints try to make sure each sink port + is reference in one an only one route. --> + <xs:key name="routeSinkKey"> + <!-- predicate [@type='sink'] does not work in xsd 1.0 --> + <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/> + <xs:field xpath="@tagName|@name"/> + </xs:key> + <xs:keyref name="routeSinkRef" refer="routeSinkKey"> + <xs:selector xpath="routes/route"/> + <xs:field xpath="@sink"/> + </xs:keyref> + <xs:unique name="routeUniqueness"> + <xs:selector xpath="routes/route"/> + <xs:field xpath="@sink"/> + </xs:unique> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="attachedDevices"> + <xs:sequence> + <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + <!-- TODO: separate values by space for better xsd validations. --> + <xs:simpleType name="audioInOutFlags"> + <xs:annotation> + <xs:documentation xml:lang="en"> + "|" separated list of audio_output_flags_t or audio_input_flags_t. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="role"> + <xs:restriction base="xs:string"> + <xs:enumeration value="sink"/> + <xs:enumeration value="source"/> + </xs:restriction> + </xs:simpleType> + <xs:complexType name="mixPorts"> + <xs:sequence> + <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="gains" type="gains" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:token" use="required"/> + <xs:attribute name="role" type="role" use="required"/> + <xs:attribute name="flags" type="audioInOutFlags"/> + <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/> + <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/> + <xs:attribute name="preferredUsage" type="audioUsageList"> + <xs:annotation> + <xs:documentation xml:lang="en"> + When choosing the mixPort of an audio track, the audioPolicy + first considers the mixPorts with a preferredUsage including + the track AudioUsage preferred . + If non support the track format, the other mixPorts are considered. + Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive + the audio of all apps playing with a MEDIA usage. + It may receive audio from ALARM if there are no audio compatible + <mixPort preferredUsage="AUDIO_USAGE_ALARM" />. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + <xs:unique name="mixPortProfileUniqueness"> + <xs:selector xpath="profile"/> + <xs:field xpath="format"/> + <xs:field xpath="samplingRate"/> + <xs:field xpath="channelMasks"/> + </xs:unique> + <xs:unique name="mixPortGainUniqueness"> + <xs:selector xpath="gains/gain"/> + <xs:field xpath="@name"/> + </xs:unique> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:simpleType name="audioDevice"> + <xs:restriction base="xs:string"> + <xs:enumeration value="AUDIO_DEVICE_NONE"/> + + <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/> + <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/> + + <!-- Due to the xml format, IN types can not be a separated from OUT types --> + <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/> + <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/> + <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/> + <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/> + <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/> + <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/> + <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/> + <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/> + <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/> + <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/> + <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/> + <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/> + <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/> + <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/> + <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/> + <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/> + <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/> + <xs:enumeration value="AUDIO_DEVICE_IN_IP"/> + <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/> + <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/> + <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/> + <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/> + <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/> + <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/> + <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/> + <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="vendorExtension"> + <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from AOSP values. + Vendor are encouraged to namespace their module names to avoid conflicts. + Example for an hypothetical Google virtual reality device: + <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink"> + --> + <xs:restriction base="xs:string"> + <xs:pattern value="VX_[_a-zA-Z0-9]+"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="extendableAudioDevice"> + <xs:union memberTypes="audioDevice vendorExtension"/> + </xs:simpleType> + <xs:simpleType name="audioFormat"> + <xs:restriction base="xs:string"> + <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" /> + <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/> + <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/> + <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/> + <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/> + <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/> + <xs:enumeration value="AUDIO_FORMAT_MP3"/> + <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/> + <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/> + <xs:enumeration value="AUDIO_FORMAT_AAC"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/> + <xs:enumeration value="AUDIO_FORMAT_VORBIS"/> + <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/> + <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/> + <xs:enumeration value="AUDIO_FORMAT_OPUS"/> + <xs:enumeration value="AUDIO_FORMAT_AC3"/> + <xs:enumeration value="AUDIO_FORMAT_E_AC3"/> + <xs:enumeration value="AUDIO_FORMAT_DTS"/> + <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/> + <xs:enumeration value="AUDIO_FORMAT_IEC61937"/> + <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/> + <xs:enumeration value="AUDIO_FORMAT_EVRC"/> + <xs:enumeration value="AUDIO_FORMAT_EVRCB"/> + <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/> + <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/> + <xs:enumeration value="AUDIO_FORMAT_WMA"/> + <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/> + <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/> + <xs:enumeration value="AUDIO_FORMAT_MP2"/> + <xs:enumeration value="AUDIO_FORMAT_QCELP"/> + <xs:enumeration value="AUDIO_FORMAT_DSD"/> + <xs:enumeration value="AUDIO_FORMAT_FLAC"/> + <xs:enumeration value="AUDIO_FORMAT_ALAC"/> + <xs:enumeration value="AUDIO_FORMAT_APE"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/> + <xs:enumeration value="AUDIO_FORMAT_SBC"/> + <xs:enumeration value="AUDIO_FORMAT_APTX"/> + <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/> + <xs:enumeration value="AUDIO_FORMAT_AC4"/> + <xs:enumeration value="AUDIO_FORMAT_LDAC"/> + <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/> + <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/> + <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/> + <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/> + <xs:enumeration value="AUDIO_FORMAT_CELT"/> + <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/> + <xs:enumeration value="AUDIO_FORMAT_LHDC"/> + <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/> + <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="extendableAudioFormat"> + <xs:union memberTypes="audioFormat vendorExtension"/> + </xs:simpleType> + <xs:simpleType name="audioUsage"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Audio usage specifies the intention cased the sound to be played. + Please consult frameworks/base/media/java/android/media/AudioAttributes.java + for the description of each value. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:enumeration value="AUDIO_USAGE_UNKNOWN" /> + <xs:enumeration value="AUDIO_USAGE_MEDIA" /> + <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" /> + <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" /> + <xs:enumeration value="AUDIO_USAGE_ALARM" /> + <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" /> + <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" /> + <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" /> + <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" /> + <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" /> + <xs:enumeration value="AUDIO_USAGE_GAME" /> + <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" /> + <xs:enumeration value="AUDIO_USAGE_ASSISTANT" /> + <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT" /> + <xs:enumeration value="AUDIO_USAGE_EMERGENCY" /> + <xs:enumeration value="AUDIO_USAGE_SAFETY" /> + <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" /> + <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" /> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="audioUsageList"> + <xs:list itemType="audioUsage"/> + </xs:simpleType> + <xs:simpleType name="audioContentType"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Audio content type expresses the general category of the content. + Please consult frameworks/base/media/java/android/media/AudioAttributes.java + for the description of each value. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/> + <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/> + <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/> + <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/> + <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/> + </xs:restriction> + </xs:simpleType> + <!-- TODO: Change to a space separated list to xsd enforce correctness. --> + <xs:simpleType name="samplingRates"> + <xs:restriction base="xs:string"> + <xs:pattern value="[0-9]+(,[0-9]+)*"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="audioChannelMask"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Audio channel mask specifies presence of particular channels. + There are two representations: + - representation position (traditional discrete channel specification, + e.g. "left", "right"); + - indexed (this is similar to "tracks" in audio mixing, channels + are represented using numbers). + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:enumeration value="OUT_MONO"/> + <xs:enumeration value="OUT_STEREO"/> + <xs:enumeration value="OUT_2POINT1"/> + <xs:enumeration value="OUT_2POINT0POINT2"/> + <xs:enumeration value="OUT_2POINT1POINT2"/> + <xs:enumeration value="OUT_3POINT0POINT2"/> + <xs:enumeration value="OUT_3POINT1POINT2"/> + <xs:enumeration value="OUT_QUAD"/> + <xs:enumeration value="OUT_QUAD_BACK"/> + <xs:enumeration value="OUT_QUAD_SIDE"/> + <xs:enumeration value="OUT_SURROUND"/> + <xs:enumeration value="OUT_PENTA"/> + <xs:enumeration value="OUT_5POINT1"/> + <xs:enumeration value="OUT_5POINT1POINT2"/> + <xs:enumeration value="OUT_5POINT1POINT4"/> + <xs:enumeration value="OUT_6POINT1"/> + <xs:enumeration value="OUT_7POINT1"/> + <xs:enumeration value="OUT_7POINT1POINT2"/> + <xs:enumeration value="OUT_7POINT1POINT4"/> + <xs:enumeration value="OUT_MONO_HAPTIC_A"/> + <xs:enumeration value="OUT_STEREO_HAPTIC_A"/> + <xs:enumeration value="OUT_HAPTIC_AB"/> + <xs:enumeration value="OUT_MONO_HAPTIC_AB"/> + <xs:enumeration value="OUT_STEREO_HAPTIC_AB"/> + <xs:enumeration value="IN_MONO"/> + <xs:enumeration value="IN_STEREO"/> + <xs:enumeration value="IN_FRONT_BACK"/> + <xs:enumeration value="IN_6"/> + <xs:enumeration value="IN_2POINT0POINT2"/> + <xs:enumeration value="IN_2POINT1POINT2"/> + <xs:enumeration value="IN_3POINT0POINT2"/> + <xs:enumeration value="IN_3POINT1POINT2"/> + <xs:enumeration value="IN_5POINT1"/> + <xs:enumeration value="IN_VOICE_UPLINK_MONO"/> + <xs:enumeration value="IN_VOICE_DNLINK_MONO"/> + <xs:enumeration value="IN_VOICE_CALL_MONO"/> + <xs:enumeration value="INDEX_MASK_1"/> + <xs:enumeration value="INDEX_MASK_2"/> + <xs:enumeration value="INDEX_MASK_3"/> + <xs:enumeration value="INDEX_MASK_4"/> + <xs:enumeration value="INDEX_MASK_5"/> + <xs:enumeration value="INDEX_MASK_6"/> + <xs:enumeration value="INDEX_MASK_7"/> + <xs:enumeration value="INDEX_MASK_8"/> + <xs:enumeration value="INDEX_MASK_9"/> + <xs:enumeration value="INDEX_MASK_10"/> + <xs:enumeration value="INDEX_MASK_11"/> + <xs:enumeration value="INDEX_MASK_12"/> + <xs:enumeration value="INDEX_MASK_13"/> + <xs:enumeration value="INDEX_MASK_14"/> + <xs:enumeration value="INDEX_MASK_15"/> + <xs:enumeration value="INDEX_MASK_16"/> + <xs:enumeration value="INDEX_MASK_17"/> + <xs:enumeration value="INDEX_MASK_18"/> + <xs:enumeration value="INDEX_MASK_19"/> + <xs:enumeration value="INDEX_MASK_20"/> + <xs:enumeration value="INDEX_MASK_21"/> + <xs:enumeration value="INDEX_MASK_22"/> + <xs:enumeration value="INDEX_MASK_23"/> + <xs:enumeration value="INDEX_MASK_24"/> + </xs:restriction> + </xs:simpleType> + <!-- TODO: Change to a space separated list to xsd enforce correctness. --> + <xs:simpleType name="channelMask"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Comma (",") separated list of channel flags + from audio_channel_mask_t. + </xs:documentation> + </xs:annotation> + <!-- Need to use audioChannelMask --> + <xs:restriction base="xs:string"> + <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/> + </xs:restriction> + </xs:simpleType> + <xs:complexType name="profile"> + <xs:attribute name="name" type="xs:token" use="optional"/> + <xs:attribute name="format" type="extendableAudioFormat" use="optional"/> + <xs:attribute name="samplingRates" type="samplingRates" use="optional"/> + <xs:attribute name="channelMasks" type="channelMask" use="optional"/> + </xs:complexType> + <xs:simpleType name="gainMode"> + <xs:restriction base="xs:string"> + <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/> + <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/> + <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/> + </xs:restriction> + </xs:simpleType> + <xs:complexType name="gains"> + <xs:sequence> + <xs:element name="gain" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="name" type="xs:token" use="required"/> + <xs:attribute name="mode" type="gainMode" use="required"/> + <xs:attribute name="channel_mask" type="channelMask" use="optional"/> + <xs:attribute name="minValueMB" type="xs:int" use="optional"/> + <xs:attribute name="maxValueMB" type="xs:int" use="optional"/> + <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/> + <xs:attribute name="stepValueMB" type="xs:int" use="optional"/> + <xs:attribute name="minRampMs" type="xs:int" use="optional"/> + <xs:attribute name="maxRampMs" type="xs:int" use="optional"/> + <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="devicePorts"> + <xs:sequence> + <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="gains" type="gains" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="tagName" type="xs:token" use="required"/> + <xs:attribute name="type" type="extendableAudioDevice" use="required"/> + <xs:attribute name="role" type="role" use="required"/> + <xs:attribute name="address" type="xs:string" use="optional" default=""/> + <!-- Note that XSD 1.0 can not check that a type only has one default. --> + <xs:attribute name="default" type="xs:boolean" use="optional"> + <xs:annotation> + <xs:documentation xml:lang="en"> + The default device will be used if multiple have the same type + and no explicit route request exists for a specific device of + that type. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional" + default="" /> + </xs:complexType> + <xs:unique name="devicePortProfileUniqueness"> + <xs:selector xpath="profile"/> + <xs:field xpath="format"/> + <xs:field xpath="samplingRate"/> + <xs:field xpath="channelMasks"/> + </xs:unique> + <xs:unique name="devicePortGainUniqueness"> + <xs:selector xpath="gains/gain"/> + <xs:field xpath="@name"/> + </xs:unique> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:simpleType name="mixType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="mix"/> + <xs:enumeration value="mux"/> + </xs:restriction> + </xs:simpleType> + <xs:complexType name="routes"> + <xs:sequence> + <xs:element name="route" minOccurs="0" maxOccurs="unbounded"> + <xs:annotation> + <xs:documentation xml:lang="en"> + List all available sources for a given sink. + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:attribute name="type" type="mixType" use="required"/> + <xs:attribute name="sink" type="xs:string" use="required"/> + <xs:attribute name="sources" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="volumes"> + <xs:sequence> + <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded"> + </xs:element> + </xs:sequence> + </xs:complexType> + <!-- TODO: Always require a ref for better xsd validations. + Currently a volume could have no points nor ref + as it can not be forbidden by xsd 1.0.--> + <xs:simpleType name="volumePoint"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Comma separated pair of number. + The fist one is the framework level (between 0 and 100). + The second one is the volume to send to the HAL. + The framework will interpolate volumes not specified. + Their MUST be at least 2 points specified. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="audioStreamType"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Audio stream type describing the intended use case of a stream. + Please consult frameworks/base/media/java/android/media/AudioSystem.java + for the description of each value. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <!-- Do we need DEFAULT? --> + <xs:enumeration value="AUDIO_STREAM_DEFAULT"/> + <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/> + <xs:enumeration value="AUDIO_STREAM_SYSTEM"/> + <xs:enumeration value="AUDIO_STREAM_RING"/> + <xs:enumeration value="AUDIO_STREAM_MUSIC"/> + <xs:enumeration value="AUDIO_STREAM_ALARM"/> + <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/> + <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/> + <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/> + <xs:enumeration value="AUDIO_STREAM_DTMF"/> + <xs:enumeration value="AUDIO_STREAM_TTS"/> + <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/> + <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/> + <xs:enumeration value="AUDIO_STREAM_REROUTING"/> + <xs:enumeration value="AUDIO_STREAM_PATCH"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="audioSource"> + <xs:annotation> + <xs:documentation xml:lang="en"> + An audio source defines both a default physical source of audio + signal and a recording configuration. + Please consult frameworks/base/media/java/android/media/MediaRecorder.java + for the description of each value. + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <!-- Do we need DEFAULT? --> + <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/> + <xs:enumeration value="AUDIO_SOURCE_MIC"/> + <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/> + <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/> + <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/> + <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/> + <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/> + <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/> + <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/> + <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/> + <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/> + <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/> + <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/> + <xs:enumeration value="AUDIO_SOURCE_HOTWORD"/> + </xs:restriction> + </xs:simpleType> + <!-- Enum values of device_category from Volume.h. --> + <xs:simpleType name="deviceCategory"> + <xs:restriction base="xs:string"> + <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/> + <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/> + <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/> + <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/> + <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/> + </xs:restriction> + </xs:simpleType> + <xs:complexType name="volume"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Volume section defines a volume curve for a given use case and device category. + It contains a list of points of this curve expressing the attenuation in Millibels + for a given volume index from 0 to 100. + <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"> + <point>0,-9600</point> + <point>100,0</point> + </volume> + + It may also reference a reference/@name to avoid duplicating curves. + <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER" + ref="DEFAULT_MEDIA_VOLUME_CURVE"/> + <reference name="DEFAULT_MEDIA_VOLUME_CURVE"> + <point>0,-9600</point> + <point>100,0</point> + </reference> + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="stream" type="audioStreamType"/> + <xs:attribute name="deviceCategory" type="deviceCategory"/> + <xs:attribute name="ref" type="xs:token" use="optional"/> + </xs:complexType> + <xs:complexType name="reference"> + <xs:sequence> + <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="name" type="xs:token" use="required"/> + </xs:complexType> + <xs:complexType name="surroundSound"> + <xs:annotation> + <xs:documentation xml:lang="en"> + Surround Sound section provides configuration related to handling of + multi-channel formats. + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element name="formats" type="surroundFormats"/> + </xs:sequence> + </xs:complexType> + <xs:simpleType name="audioFormatsList"> + <xs:list itemType="audioFormat" /> + </xs:simpleType> + <xs:complexType name="surroundFormats"> + <xs:sequence> + <xs:element name="format" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="name" type="audioFormat" use="required"/> + <xs:attribute name="subformats" type="audioFormatsList" /> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:simpleType name="engineSuffix"> + <xs:restriction base="xs:string"> + <xs:enumeration value="default"/> + <xs:enumeration value="configurable"/> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/tests/resources/group.xml b/tests/resources/group.xml index 9a51ab6..6e9f45d 100644 --- a/tests/resources/group.xml +++ b/tests/resources/group.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<Student> - <State>CA</State> - <city>Mountain View</city> - <road>Street 101</road> +<Student version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude"> + <State>CA</State> + <city>Mountain View</city> + <xi:include href="group2.xml"/> </Student> diff --git a/tests/resources/group/Android.bp b/tests/resources/group/Android.bp index 21e7242..6560ffd 100644 --- a/tests/resources/group/Android.bp +++ b/tests/resources/group/Android.bp @@ -1,7 +1,11 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_group_tests", srcs: ["group.xsd"], package_name: "group", + gen_writer: true, } - diff --git a/tests/resources/group/address.xsd b/tests/resources/group/address.xsd new file mode 100644 index 0000000..6fc075c --- /dev/null +++ b/tests/resources/group/address.xsd @@ -0,0 +1,8 @@ +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="attr_group_simple" elementFormDefault="qualified"> + <xs:group name="address1"> + <xs:sequence> + <xs:element name="State" type="xs:string"/> + <xs:element name="city" type="xs:string"/> + </xs:sequence> + </xs:group> +</xs:schema> diff --git a/tests/resources/group/api/current.txt b/tests/resources/group/api/current.txt index c79d293..4a0c206 100644 --- a/tests/resources/group/api/current.txt +++ b/tests/resources/group/api/current.txt @@ -18,5 +18,11 @@ package group { method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; } + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + method public static void write(group.XmlWriter, group.Student) throws java.io.IOException; + } + } diff --git a/tests/resources/group/group.xsd b/tests/resources/group/group.xsd index 2bef1a3..3e96834 100644 --- a/tests/resources/group/group.xsd +++ b/tests/resources/group/group.xsd @@ -1,10 +1,5 @@ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="attr_group_simple" elementFormDefault="qualified"> - <xs:group name="address1"> - <xs:sequence> - <xs:element name="State" type="xs:string"/> - <xs:element name="city" type="xs:string"/> - </xs:sequence> - </xs:group> + <xs:include schemaLocation="address.xsd" /> <xs:group name="address2" ref="address1"> <xs:sequence> <xs:element name="road" type="xs:string"/> diff --git a/tests/resources/group2.xml b/tests/resources/group2.xml new file mode 100644 index 0000000..c7bc0d3 --- /dev/null +++ b/tests/resources/group2.xml @@ -0,0 +1 @@ +<road>Street 101</road> diff --git a/tests/resources/nested_type/Android.bp b/tests/resources/nested_type/Android.bp index b228879..15140fb 100644 --- a/tests/resources/nested_type/Android.bp +++ b/tests/resources/nested_type/Android.bp @@ -1,7 +1,11 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_nested_type_tests", srcs: ["nested_type.xsd"], package_name: "nested.type", + gen_writer: true, } - diff --git a/tests/resources/nested_type/api/current.txt b/tests/resources/nested_type/api/current.txt index a655437..cd75080 100644 --- a/tests/resources/nested_type/api/current.txt +++ b/tests/resources/nested_type/api/current.txt @@ -49,5 +49,11 @@ package nested.type { method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; } + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + method public static void write(nested.type.XmlWriter, nested.type.Employee) throws java.io.IOException; + } + } diff --git a/tests/resources/predefined_types.xml b/tests/resources/predefined_types.xml index 7c4cf1b..9c24542 100644 --- a/tests/resources/predefined_types.xml +++ b/tests/resources/predefined_types.xml @@ -46,7 +46,7 @@ <anyURI>https://www.google.com</anyURI> <base64Binary>Z29vZ2xl</base64Binary> <boolean>true</boolean> - <hexBinary>516a75cb56d7e7</hexBinary> + <hexBinary>016a75cb56d7e7</hexBinary> <QName>abcd</QName> <IDREF>abcd</IDREF> <IDREFS>abcd abcd</IDREFS> diff --git a/tests/resources/predefined_types/Android.bp b/tests/resources/predefined_types/Android.bp index 8501f1a..05f2ae0 100644 --- a/tests/resources/predefined_types/Android.bp +++ b/tests/resources/predefined_types/Android.bp @@ -1,7 +1,11 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_predefined_types_tests", srcs: ["predefined_types.xsd"], package_name: "predefined.types", + gen_writer: true, } - diff --git a/tests/resources/predefined_types/api/current.txt b/tests/resources/predefined_types/api/current.txt index 5b7f393..e7141d3 100644 --- a/tests/resources/predefined_types/api/current.txt +++ b/tests/resources/predefined_types/api/current.txt @@ -23,6 +23,12 @@ package predefined.types { method public void setTime(javax.xml.datatype.XMLGregorianCalendar); } + public class HexBinaryHelper { + ctor public HexBinaryHelper(); + method public static String byteArrayToHexString(byte[]); + method public static byte[] hexStringToByteArray(String); + } + public class ListPrimitiveTypes { ctor public ListPrimitiveTypes(); method public java.util.List<java.lang.Boolean> getListBoolean(); @@ -46,7 +52,7 @@ package predefined.types { method public String getAnyType(); method public String getAnyURI(); method public byte[] getBase64Binary(); - method public java.math.BigInteger getHexBinary(); + method public byte[] getHexBinary(); method public String getIDREF(); method public java.util.List<java.lang.String> getIDREFS(); method public String getQName(); @@ -56,7 +62,7 @@ package predefined.types { method public void setAnyType(String); method public void setAnyURI(String); method public void setBase64Binary(byte[]); - method public void setHexBinary(java.math.BigInteger); + method public void setHexBinary(byte[]); method public void setIDREF(String); method public void setIDREFS(java.util.List<java.lang.String>); method public void setQName(String); @@ -144,5 +150,11 @@ package predefined.types { method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; } + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + method public static void write(predefined.types.XmlWriter, predefined.types.Types) throws java.io.IOException; + } + } diff --git a/tests/resources/purchase_simple/Android.bp b/tests/resources/purchase_simple/Android.bp index a607e25..0773cb8 100644 --- a/tests/resources/purchase_simple/Android.bp +++ b/tests/resources/purchase_simple/Android.bp @@ -1,7 +1,11 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_purchase_simple_tests", srcs: ["purchase_simple.xsd"], package_name: "purchase.simple", + gen_writer: true, } - diff --git a/tests/resources/purchase_simple/api/current.txt b/tests/resources/purchase_simple/api/current.txt index c7a455e..eb138a8 100644 --- a/tests/resources/purchase_simple/api/current.txt +++ b/tests/resources/purchase_simple/api/current.txt @@ -33,5 +33,11 @@ package purchase.simple { method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; } + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + method public static void write(purchase.simple.XmlWriter, purchase.simple.PurchaseOrderType) throws java.io.IOException; + } + } diff --git a/tests/resources/reference/Android.bp b/tests/resources/reference/Android.bp index 842b236..b0e7bca 100644 --- a/tests/resources/reference/Android.bp +++ b/tests/resources/reference/Android.bp @@ -1,7 +1,12 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_reference_tests", srcs: ["reference.xsd"], package_name: "reference", + gen_writer: true, + nullability: true, } - diff --git a/tests/resources/reference/api/current.txt b/tests/resources/reference/api/current.txt index 1ef6ee5..e33fb20 100644 --- a/tests/resources/reference/api/current.txt +++ b/tests/resources/reference/api/current.txt @@ -3,16 +3,22 @@ package reference { public class Class { ctor public Class(); - method public String getName(); - method public java.util.List<java.lang.String> getStudent(); - method public void setName(String); + method @Nullable public String getName(); + method @Nullable public java.util.List<java.lang.String> getStudent(); + method public void setName(@Nullable String); } public class XmlParser { ctor public XmlParser(); - method public static reference.Class read(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; - method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method @Nullable public static reference.Class read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(@NonNull java.io.PrintWriter); + method public void close(); + method public static void write(@NonNull reference.XmlWriter, @NonNull reference.Class) throws java.io.IOException; } } diff --git a/tests/resources/simple_complex_content.xml b/tests/resources/simple_complex_content.xml index 06c590f..2f18161 100644 --- a/tests/resources/simple_complex_content.xml +++ b/tests/resources/simple_complex_content.xml @@ -1,8 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <person> <name>Petr</name> - <shoeSize sizing="Korea">265</shoeSize> - <generalPrice currency="dollar">1234.56</generalPrice> <USAddressP> <name>404</name> <street>street fighter</street> diff --git a/tests/resources/simple_complex_content/Android.bp b/tests/resources/simple_complex_content/Android.bp index 34c5300..00502cb 100644 --- a/tests/resources/simple_complex_content/Android.bp +++ b/tests/resources/simple_complex_content/Android.bp @@ -1,7 +1,12 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_simple_complex_content_tests", srcs: ["simple_complex_content.xsd"], package_name: "simple.complex.content", + gen_writer: true, + gen_has: true, } - diff --git a/tests/resources/simple_complex_content/api/current.txt b/tests/resources/simple_complex_content/api/current.txt index 8ca1793..043fb50 100644 --- a/tests/resources/simple_complex_content/api/current.txt +++ b/tests/resources/simple_complex_content/api/current.txt @@ -6,6 +6,9 @@ package simple.complex.content { method @Deprecated public String getCity(); method @Deprecated public final String getName(); method @Deprecated public String getStreet(); + method @Deprecated public boolean hasCity(); + method @Deprecated public boolean hasName(); + method @Deprecated public boolean hasStreet(); method @Deprecated public void setCity(String); method @Deprecated public final void setName(String); method @Deprecated public void setStreet(String); @@ -21,6 +24,10 @@ package simple.complex.content { method public String getName(); method public simple.complex.content.SubAddress getSubAddress(); method public simple.complex.content.USAddressP getUSAddressP(); + method public boolean hasKRAddress(); + method public boolean hasName(); + method public boolean hasSubAddress(); + method public boolean hasUSAddressP(); method public void setKRAddress(simple.complex.content.KRAddress); method public void setName(String); method public void setSubAddress(simple.complex.content.SubAddress); @@ -33,6 +40,10 @@ 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 boolean hasKRAddress(); + method public boolean hasName(); + method public boolean hasSubAddress(); + method public boolean hasUSAddressP(); method public void setKRAddress(simple.complex.content.KRAddress); method public void setName(String); method public void setSubAddress(@NonNull simple.complex.content.SubAddress); @@ -43,6 +54,8 @@ package simple.complex.content { ctor public SubAddress(); method @Nullable public final String getChoice1_optional(); method @NonNull public final String getChoice2_optional(); + method public boolean hasChoice1_optional(); + method public boolean hasChoice2_optional(); method public final void setChoice1_optional(@Nullable String); method public final void setChoice2_optional(@NonNull String); } @@ -51,6 +64,8 @@ package simple.complex.content { ctor public USAddressP(); method public String getState(); method public java.math.BigInteger getZipcode(); + method public boolean hasState(); + method public boolean hasZipcode(); method public void setState(String); method public void setZipcode(java.math.BigInteger); } @@ -63,5 +78,12 @@ package simple.complex.content { method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; } + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + method public static void write(simple.complex.content.XmlWriter, simple.complex.content.Person) throws java.io.IOException; + method public static void write(simple.complex.content.XmlWriter, simple.complex.content.Person2) throws java.io.IOException; + } + } diff --git a/tests/resources/simple_type/Android.bp b/tests/resources/simple_type/Android.bp index fba259f..b4be8d4 100644 --- a/tests/resources/simple_type/Android.bp +++ b/tests/resources/simple_type/Android.bp @@ -1,7 +1,30 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + xsd_config { name: "xsdc_simple_type_tests", srcs: ["simple_type.xsd"], package_name: "simple.type", + gen_writer: true, + boolean_getter: true, } +xsd_config { + name: "xsdc_simple_type_tests_enums", + srcs: ["simple_type.xsd"], + package_name: "simple.type", + enums_only: true, + gen_writer: true, + boolean_getter: true, +} + +xsd_config { + name: "xsdc_simple_type_tests_parser", + srcs: ["simple_type.xsd"], + package_name: "simple.type", + parser_only: true, + gen_writer: true, + boolean_getter: true, +} diff --git a/tests/resources/simple_type/api/current.txt b/tests/resources/simple_type/api/current.txt index e61f1fa..0b163a5 100644 --- a/tests/resources/simple_type/api/current.txt +++ b/tests/resources/simple_type/api/current.txt @@ -20,6 +20,12 @@ package simple.type { method public java.util.List<java.lang.Integer> getListInt(); 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 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 setUnionTest(java.util.List<java.lang.String>); } @@ -43,5 +49,13 @@ package simple.type { method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; } + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + 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; + } + } diff --git a/tests/resources/simple_type/simple_type.xsd b/tests/resources/simple_type/simple_type.xsd index 23a46b4..481c476 100644 --- a/tests/resources/simple_type/simple_type.xsd +++ b/tests/resources/simple_type/simple_type.xsd @@ -31,7 +31,10 @@ <xs:element name="listInt" type="restrictedInts"/> <xs:element name="union-test" type="unionOfListAndInteger"/> <xs:element name="yesOrNo" type="enumType" maxOccurs="2"/> + <xs:element name="example1" type="xs:boolean"/> + <xs:element name="example2" type="xs:boolean"/> </xs:sequence> + <xs:attribute name="example3" type="xs:boolean"/> </xs:complexType> </xs:element> <xs:element name="multi-choice"> diff --git a/tests/simple_type.cpp b/tests/simple_type.cpp new file mode 100644 index 0000000..5162c6d --- /dev/null +++ b/tests/simple_type.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 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. + */ + +#include <iostream> +#include <fstream> + +#include <android-base/macros.h> + +#include "simple_type.h" +#include "xmltest.h" + +using namespace std; + +TEST_F(XmlTest, Simpletype) { + using namespace simple::type; + for (const auto v : android::xsdc_enum_range<EnumType>()) { + EXPECT_NE(v, EnumType::UNKNOWN); + EXPECT_EQ(stringToEnumType(toString(v)), v); + } + + string file_name = Resource("simple_type.xml"); + SimpleTypes simple = *readSimpleTypes(file_name.c_str()); + + for (int i = 0; i < simple.getListInt().size(); ++i) { + EXPECT_EQ(simple.getListInt()[i], i + 1); + } + EXPECT_EQ(*simple.getFirstUnionTest(), "100"); + EXPECT_EQ(simple.getYesOrNo()[0], EnumType::YES); + EXPECT_EQ(simple.getYesOrNo()[1], EnumType::EMPTY); + ofstream out("old_simple_type.xml"); + write(out, simple); + SimpleTypes simple2 = *readSimpleTypes("old_simple_type.xml"); + for (int i = 0; i < simple.getListInt().size(); ++i) { + EXPECT_EQ(simple.getListInt()[i], simple2.getListInt()[i]); + } + EXPECT_EQ(*simple.getFirstUnionTest(), *simple2.getFirstUnionTest()); + EXPECT_EQ(simple.getYesOrNo()[0], simple2.getYesOrNo()[0]); + EXPECT_EQ(simple.getYesOrNo()[1], simple2.getYesOrNo()[1]); +} diff --git a/tests/simple_type_enumsonly.cpp b/tests/simple_type_enumsonly.cpp new file mode 100644 index 0000000..b083a6c --- /dev/null +++ b/tests/simple_type_enumsonly.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 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. + */ + +#include <android-base/macros.h> + +#include "simple_type_enums.h" +#include "xmltest.h" + +TEST_F(XmlTest, SimpletypeEnumsOnly) { + using namespace simple::type; + for (const auto v : android::xsdc_enum_range<EnumType>()) { + EXPECT_NE(v, EnumType::UNKNOWN); + EXPECT_EQ(stringToEnumType(toString(v)), v); + } +} diff --git a/tests/src/com/android/xsdc/tests/TestCompilationResult.java b/tests/src/com/android/xsdc/tests/TestCompilationResult.java deleted file mode 100644 index 840fc37..0000000 --- a/tests/src/com/android/xsdc/tests/TestCompilationResult.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 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.tests; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -class TestCompilationResult { - private static class ByteArrayClassLoader extends ClassLoader { - private Map<String, byte[]> codeMap; - - ByteArrayClassLoader(List<TestHelper.InMemoryJavaClassObject> objects) { - super(); - codeMap = new HashMap<>(); - for (TestHelper.InMemoryJavaClassObject object : objects) { - codeMap.put(object.getClassName(), object.getBytes()); - } - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - byte[] code = codeMap.get(name); - return defineClass(name, code, 0, code.length); - } - } - - private Map<String, Class<?>> classes; - - TestCompilationResult(List<TestHelper.InMemoryJavaClassObject> objects) - throws ClassNotFoundException { - ByteArrayClassLoader loader = new ByteArrayClassLoader(objects); - classes = new HashMap<>(); - - for (TestHelper.InMemoryJavaClassObject object : objects) { - Class<?> cls = loader.loadClass(object.getClassName()); - classes.put(object.getClassName(), cls); - } - } - - Class<?> loadClass(String name) { - return classes.get(TestHelper.packageName + "." + name); - } -} diff --git a/tests/src/com/android/xsdc/tests/TestHelper.java b/tests/src/com/android/xsdc/tests/TestHelper.java deleted file mode 100644 index c801dc8..0000000 --- a/tests/src/com/android/xsdc/tests/TestHelper.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2018 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.tests; - -import com.android.xsdc.FileSystem; -import com.android.xsdc.XmlSchema; -import com.android.xsdc.XsdHandler; -import com.android.xsdc.java.JavaCodeGenerator; - -import javax.tools.*; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import java.io.*; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import static org.junit.Assert.fail; - -class TestHelper { - static class InMemoryJavaFileObject extends SimpleJavaFileObject { - private final String contents; - - InMemoryJavaFileObject(String className, String contents) { - super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), - Kind.SOURCE); - this.contents = contents; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return contents; - } - } - - static class InMemoryJavaClassObject extends SimpleJavaFileObject { - private ByteArrayOutputStream baos; - private String name; - - InMemoryJavaClassObject(String name, Kind kind) { - super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind); - baos = new ByteArrayOutputStream(); - this.name = name; - } - - byte[] getBytes() { - return baos.toByteArray(); - } - - @Override - public OutputStream openOutputStream() { - return baos; - } - - String getClassName() { - return name; - } - } - - static class InMemoryClassManager extends ForwardingJavaFileManager<JavaFileManager> { - private List<InMemoryJavaClassObject> classObjects; - - InMemoryClassManager(JavaFileManager fileManager) { - super(fileManager); - classObjects = new ArrayList<>(); - } - - @Override - public JavaFileObject getJavaFileForOutput(Location location, String name, - JavaFileObject.Kind kind, FileObject sibling) { - InMemoryJavaClassObject object = new InMemoryJavaClassObject(name, kind); - classObjects.add(object); - return object; - } - - List<InMemoryJavaClassObject> getAllClasses() { - return classObjects; - } - } - - final static String packageName = "test"; - - static TestCompilationResult parseXsdAndCompile(InputStream in) throws Exception { - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - SAXParser parser = factory.newSAXParser(); - XsdHandler xsdHandler = new XsdHandler(); - parser.parse(in, xsdHandler); - XmlSchema xmlSchema = xsdHandler.getSchema(); - Map<String, StringBuffer> fileOutputMap = new HashMap<>(); - FileSystem fs = new FileSystem(fileOutputMap); - JavaCodeGenerator javaCodeGenerator = new JavaCodeGenerator(xmlSchema, packageName); - javaCodeGenerator.print(fs); - List<JavaFileObject> javaFileObjects = new ArrayList<>(); - for (Map.Entry<String, StringBuffer> entry : fileOutputMap.entrySet()) { - String className = entry.getKey().split("\\.")[0]; - javaFileObjects.add( - new InMemoryJavaFileObject(className, entry.getValue().toString())); - } - return new TestCompilationResult(compile(javaFileObjects)); - } - - private static List<InMemoryJavaClassObject> compile(List<JavaFileObject> javaFileObjects) - throws IOException { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); - List<InMemoryJavaClassObject> ret = null; - - try (InMemoryClassManager fileManager = new InMemoryClassManager( - compiler.getStandardFileManager(diagnostics, null, null))) { - JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, - null, null, javaFileObjects); - boolean success = task.call(); - - if (!success) { - StringBuilder log = new StringBuilder(); - log.append("Compilation failed!\n\n"); - for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { - log.append("Code: ").append(diagnostic.getCode()).append("\n"); - log.append("Kind: " + diagnostic.getKind() + "\n"); - log.append("Line: " + diagnostic.getLineNumber() + "\n"); - log.append("Column: " + diagnostic.getColumnNumber() + "\n"); - log.append("Source: " + diagnostic.getSource() + "\n"); - log.append("Message: " + diagnostic.getMessage(Locale.getDefault()) + "\n"); - } - fail(log.toString()); - } - ret = fileManager.getAllClasses(); - } - return ret; - } -}
\ No newline at end of file diff --git a/tests/src/com/android/xsdc/tests/XmlParserTest.java b/tests/src/com/android/xsdc/tests/XmlParserTest.java index 0e42f67..f3b5eaf 100644 --- a/tests/src/com/android/xsdc/tests/XmlParserTest.java +++ b/tests/src/com/android/xsdc/tests/XmlParserTest.java @@ -33,361 +33,242 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.*; + public class XmlParserTest { @Test public void testPurchaseSimple() throws Exception { - TestCompilationResult result; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "purchase_simple/purchase_simple.xsd")) { - result = TestHelper.parseXsdAndCompile(in); - } - - Class<?> xmlParser = result.loadClass("XmlParser"); - Class<?> purchaseOrderType = result.loadClass("PurchaseOrderType"); - Class<?> usAddress = result.loadClass("USAddress"); - - Object instance; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( + purchase.simple.PurchaseOrderType orderType; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( "purchase_simple.xml")) { - instance = xmlParser.getMethod("read", InputStream.class).invoke(null, in); + orderType = purchase.simple.XmlParser.read(str); } - Object billTo = purchaseOrderType.getMethod("getBillTo").invoke(instance); - List shipToList = (List) purchaseOrderType.getMethod("getShipTo").invoke(instance); - - String name = (String) usAddress.getMethod("getName").invoke(billTo); - BigInteger zip = (BigInteger) usAddress.getMethod("getZip").invoke(billTo); - String street = (String) usAddress.getMethod("getStreet").invoke(shipToList.get(0)); - BigInteger largeZip = (BigInteger) usAddress.getMethod("getZip").invoke(shipToList.get(1)); - XMLGregorianCalendar orderDate = (XMLGregorianCalendar) purchaseOrderType.getMethod( - "getOrderDate").invoke(instance); - - assertThat(name, is("billName")); - assertThat(zip, is(new BigInteger("1"))); - assertThat(street, is("street1")); - assertThat(largeZip, is(new BigInteger("-7922816251426433759"))); - assertThat(orderDate, + + assertThat(orderType.getOrderDate(), is(javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar( - "1900-01-01"))); + "1900-01-01"))); + assertThat(orderType.getBillTo().getName(), is("billName")); + assertThat(orderType.getBillTo().getZip(), is(new BigInteger("1"))); + assertThat(orderType.getShipTo().get(0).getStreet(), is("street1")); + assertThat(orderType.getShipTo().get(1).getZip(), + is(new BigInteger("-7922816251426433759"))); + + String actualStr, expectedStr; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "purchase_simple.xml")) { + expectedStr = new String(str.readAllBytes()); + } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try(purchase.simple.XmlWriter writer = + new purchase.simple.XmlWriter(new PrintWriter(baos))) { + purchase.simple.XmlWriter.write(writer, orderType); + } + actualStr = new String(baos.toByteArray()); + } + + assertThat(new String(actualStr), is(expectedStr)); } @Test public void testNestedType() throws Exception { - TestCompilationResult result; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "nested_type/nested_type.xsd")) { - result = TestHelper.parseXsdAndCompile(in); - } - - Class<?> xmlParser = result.loadClass("XmlParser"); - Class<?> employee = result.loadClass("Employee"); - Class<?> address = result.loadClass("Employee$Address"); - Class<?> extra = result.loadClass("Employee$Address$Extra"); - - Object instance; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( + nested.type.Employee employee; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( "nested_type.xml")) { - instance = xmlParser.getMethod("read", InputStream.class).invoke(null, in); + employee = nested.type.XmlParser.read(str); } - String name = (String) employee.getMethod("getName").invoke(instance); - Object addressInstance = employee.getMethod("getAddress").invoke(instance); - String country = (String) address.getMethod("getCountry").invoke(addressInstance); - Object extraInstance = address.getMethod("getExtra").invoke(addressInstance); - String line2 = (String) extra.getMethod("getLine2").invoke(extraInstance); - - assertThat(name, is("Peter")); - assertThat(country, is("US")); - assertThat(line2, is("Good Street")); + assertThat(employee.getName(), is("Peter")); + assertThat(employee.getAddress().getCountry(), is("US")); + assertThat(employee.getAddress().getExtra().getLine2(), is("Good Street")); } @Test public void testSimpleComplexContent() throws Exception { - TestCompilationResult result; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "simple_complex_content/simple_complex_content.xsd")) { - result = TestHelper.parseXsdAndCompile(in); - } - - Class<?> xmlParser = result.loadClass("XmlParser"); - Class<?> person = result.loadClass("Person"); - Class<?> usAddress = result.loadClass("USAddressP"); - Class<?> krAddress = result.loadClass("KRAddress"); - - Object instance; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( + simple.complex.content.Person person; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( "simple_complex_content.xml")) { - instance = xmlParser.getMethod("readPerson", InputStream.class).invoke(null, in); + person = simple.complex.content.XmlParser.readPerson(str); } - String name = (String) person.getMethod("getName").invoke(instance); - - Object usAddressInstance = person.getMethod("getUSAddressP").invoke(instance); - String usStreet = (String) usAddress.getMethod("getStreet").invoke(usAddressInstance); - BigInteger usZipcode = (BigInteger) usAddress.getMethod("getZipcode").invoke( - usAddressInstance); + assertThat(person.getName(), is("Petr")); + assertThat(person.getUSAddressP().getStreet(), is("street fighter")); + assertThat(person.getUSAddressP().getZipcode(), is(new BigInteger("323232318329852"))); + assertThat(person.getKRAddress().getStreet(), is("Nokdu Street")); - Object krAddressInstance = person.getMethod("getKRAddress").invoke(instance); - String krStreet = (String) krAddress.getMethod("getStreet").invoke(krAddressInstance); + String actualStr, expectedStr; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "simple_complex_content.xml")) { + expectedStr = new String(str.readAllBytes()); + } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try(simple.complex.content.XmlWriter writer = + new simple.complex.content.XmlWriter(new PrintWriter(baos))) { + simple.complex.content.XmlWriter.write(writer, person); + } + actualStr = new String(baos.toByteArray()); + } - assertThat(name, is("Petr")); - assertThat(usStreet, is("street fighter")); - assertThat(usZipcode, is(new BigInteger("323232318329852"))); - assertThat(krStreet, is("Nokdu Street")); + assertThat(new String(actualStr), is(expectedStr)); } @Test public void testPredefinedTypes() throws Exception { - TestCompilationResult result; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "predefined_types/predefined_types.xsd")) { - result = TestHelper.parseXsdAndCompile(in); - } - - Class<?> xmlParser = result.loadClass("XmlParser"); - Class<?> types = result.loadClass("Types"); - Class<?> stringTypes = result.loadClass("StringTypes"); - Class<?> dateTypes = result.loadClass("DateTypes"); - Class<?> numericTypes = result.loadClass("NumericTypes"); - Class<?> miscTypes = result.loadClass("MiscTypes"); - Class<?> listPrimitiveTypes = result.loadClass("ListPrimitiveTypes"); + predefined.types.Types type; - Object instance; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( "predefined_types.xml")) { - instance = xmlParser.getMethod("read", InputStream.class).invoke(null, in); + type = predefined.types.XmlParser.read(str); } { - Object stringTypesInstance = types.getMethod("getStringTypes").invoke(instance); - String string = (String) stringTypes.getMethod("getString").invoke(stringTypesInstance); - String token = (String) stringTypes.getMethod("getToken").invoke(stringTypesInstance); - String normalizedString = (String) stringTypes.getMethod("getNormalizedString").invoke( - stringTypesInstance); - String language = (String) stringTypes.getMethod("getLanguage").invoke( - stringTypesInstance); - String entity = (String) stringTypes.getMethod("getEntity").invoke(stringTypesInstance); - List entities = (List) stringTypes.getMethod("getEntities").invoke(stringTypesInstance); - String id = (String) stringTypes.getMethod("getId").invoke(stringTypesInstance); - String name = (String) stringTypes.getMethod("getName").invoke(stringTypesInstance); - String ncName = (String) stringTypes.getMethod("getNcname").invoke(stringTypesInstance); - String nmToken = (String) stringTypes.getMethod("getNmtoken").invoke( - stringTypesInstance); - List nmTokens = (List) stringTypes.getMethod("getNmtokens").invoke(stringTypesInstance); - - assertThat(string, is("abcd")); - assertThat(token, is("abcd")); - assertThat(normalizedString, is("abcd")); - assertThat(language, is("abcd")); - assertThat(entity, is("abcd")); - assertThat(entities, is(Arrays.asList("a", "b", "c", "d"))); - assertThat(id, is("abcd")); - assertThat(name, is("abcd")); - assertThat(ncName, is("abcd")); - assertThat(nmToken, is("abcd")); - assertThat(nmTokens, is(Arrays.asList("a", "b", "c", "d"))); + predefined.types.StringTypes stringTypes = type.getStringTypes(); + + assertThat(stringTypes.getString(), is("abcd")); + assertThat(stringTypes.getToken(), is("abcd")); + assertThat(stringTypes.getNormalizedString(), is("abcd")); + assertThat(stringTypes.getLanguage(), is("abcd")); + assertThat(stringTypes.getEntity(), is("abcd")); + assertThat(stringTypes.getEntities(), is(Arrays.asList("a", "b", "c", "d"))); + assertThat(stringTypes.getId(), is("abcd")); + assertThat(stringTypes.getName(), is("abcd")); + assertThat(stringTypes.getNcname(), is("abcd")); + assertThat(stringTypes.getNmtoken(), is("abcd")); + assertThat(stringTypes.getNmtokens(), is(Arrays.asList("a", "b", "c", "d"))); } { - Object dateTypesInstance = types.getMethod("getDateTypes").invoke(instance); - XMLGregorianCalendar date = (XMLGregorianCalendar) dateTypes.getMethod( - "getDate").invoke(dateTypesInstance); - XMLGregorianCalendar dateTime = (XMLGregorianCalendar) dateTypes.getMethod( - "getDateTime").invoke(dateTypesInstance); - Duration duration = (Duration) dateTypes.getMethod("getDuration").invoke( - dateTypesInstance); - XMLGregorianCalendar gDay = (XMLGregorianCalendar) dateTypes.getMethod( - "getGDay").invoke(dateTypesInstance); - XMLGregorianCalendar gMonth = (XMLGregorianCalendar) dateTypes.getMethod( - "getGMonth").invoke(dateTypesInstance); - XMLGregorianCalendar gMonthDay = (XMLGregorianCalendar) dateTypes.getMethod( - "getGMonthDay").invoke(dateTypesInstance); - XMLGregorianCalendar gYear = (XMLGregorianCalendar) dateTypes.getMethod( - "getGYear").invoke(dateTypesInstance); - XMLGregorianCalendar gYearMonth = (XMLGregorianCalendar) dateTypes.getMethod( - "getGYearMonth").invoke(dateTypesInstance); - XMLGregorianCalendar time = (XMLGregorianCalendar) dateTypes.getMethod( - "getTime").invoke(dateTypesInstance); - + predefined.types.DateTypes dateTypes = type.getDateTypes(); DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); - assertThat(date, is(datatypeFactory.newXMLGregorianCalendar("2018-06-18"))); - assertThat(dateTime, + + assertThat(dateTypes.getDate(), + is(datatypeFactory.newXMLGregorianCalendar("2018-06-18"))); + assertThat(dateTypes.getDateTime(), is(datatypeFactory.newXMLGregorianCalendar("2018-06-18T21:32:52"))); - assertThat(duration, is(datatypeFactory.newDuration("P3M"))); - assertThat(gDay, is(datatypeFactory.newXMLGregorianCalendar("---18"))); - assertThat(gMonth, is(datatypeFactory.newXMLGregorianCalendar("--06"))); - assertThat(gMonthDay, is(datatypeFactory.newXMLGregorianCalendar("--06-18"))); - assertThat(gYear, is(datatypeFactory.newXMLGregorianCalendar("2018"))); - assertThat(gYearMonth, is(datatypeFactory.newXMLGregorianCalendar("2018-06"))); - assertThat(time, is(datatypeFactory.newXMLGregorianCalendar("21:32:52"))); + assertThat(dateTypes.getDuration(), is(datatypeFactory.newDuration("P3M"))); + assertThat(dateTypes.getGDay(), is(datatypeFactory.newXMLGregorianCalendar("---18"))); + assertThat(dateTypes.getGMonth(), is(datatypeFactory.newXMLGregorianCalendar("--06"))); + assertThat(dateTypes.getGMonthDay(), + is(datatypeFactory.newXMLGregorianCalendar("--06-18"))); + assertThat(dateTypes.getGYear(), is(datatypeFactory.newXMLGregorianCalendar("2018"))); + assertThat(dateTypes.getGYearMonth(), + is(datatypeFactory.newXMLGregorianCalendar("2018-06"))); + assertThat(dateTypes.getTime(), + is(datatypeFactory.newXMLGregorianCalendar("21:32:52"))); } - { - Object numericTypesInstance = types.getMethod("getNumericTypes").invoke(instance); - BigDecimal decimal = (BigDecimal) numericTypes.getMethod("getDecimal").invoke( - numericTypesInstance); - BigInteger integer = (BigInteger) numericTypes.getMethod("getInteger").invoke( - numericTypesInstance); - long _long = (long) numericTypes.getMethod("get_long").invoke(numericTypesInstance); - int _int = (int) numericTypes.getMethod("get_int").invoke(numericTypesInstance); - short _short = (short) numericTypes.getMethod("get_short").invoke(numericTypesInstance); - byte _byte = (byte) numericTypes.getMethod("get_byte").invoke(numericTypesInstance); - BigInteger negativeInteger = (BigInteger) numericTypes.getMethod( - "getNegativeInteger").invoke(numericTypesInstance); - BigInteger nonNegativeInteger = (BigInteger) numericTypes.getMethod( - "getNonNegativeInteger").invoke(numericTypesInstance); - BigInteger positiveInteger = (BigInteger) numericTypes.getMethod( - "getPositiveInteger").invoke(numericTypesInstance); - BigInteger nonPositiveInteger = (BigInteger) numericTypes.getMethod( - "getNonPositiveInteger").invoke(numericTypesInstance); - BigInteger unsignedLong = (BigInteger) numericTypes.getMethod("getUnsignedLong").invoke( - numericTypesInstance); - long unsignedInt = (long) numericTypes.getMethod("getUnsignedInt").invoke( - numericTypesInstance); - int unsignedShort = (int) numericTypes.getMethod("getUnsignedShort").invoke( - numericTypesInstance); - short unsignedByte = (short) numericTypes.getMethod("getUnsignedByte").invoke( - numericTypesInstance); - - assertThat(decimal, is(new BigDecimal("1234.57"))); - assertThat(integer, is(new BigInteger("1234567890123456789"))); - assertThat(_long, is(9223372036854775807L)); - assertThat(_int, is(2147483647)); - assertThat(_short, is((short) 32767)); - assertThat(_byte, is((byte) 127)); - assertThat(negativeInteger, is(new BigInteger("-1234"))); - assertThat(nonNegativeInteger, is(new BigInteger("1234"))); - assertThat(positiveInteger, is(new BigInteger("1234"))); - assertThat(nonPositiveInteger, is(new BigInteger("-1234"))); - assertThat(unsignedLong, is(new BigInteger("1234"))); - assertThat(unsignedInt, is(1234L)); - assertThat(unsignedShort, is(1234)); - assertThat(unsignedByte, is((short) 255)); + predefined.types.NumericTypes numericTypes = type.getNumericTypes(); + + assertThat(numericTypes.getDecimal(), is(new BigDecimal("1234.57"))); + assertThat(numericTypes.getInteger(), is(new BigInteger("1234567890123456789"))); + assertThat(numericTypes.get_long(), is(9223372036854775807L)); + assertThat(numericTypes.get_int(), is(2147483647)); + assertThat(numericTypes.get_short(), is((short) 32767)); + assertThat(numericTypes.get_byte(), is((byte) 127)); + assertThat(numericTypes.getNegativeInteger(), is(new BigInteger("-1234"))); + assertThat(numericTypes.getNonNegativeInteger(), is(new BigInteger("1234"))); + assertThat(numericTypes.getPositiveInteger(), is(new BigInteger("1234"))); + assertThat(numericTypes.getNonPositiveInteger(), is(new BigInteger("-1234"))); + assertThat(numericTypes.getUnsignedLong(), is(new BigInteger("1234"))); + assertThat(numericTypes.getUnsignedInt(), is(1234L)); + assertThat(numericTypes.getUnsignedShort(), is(1234)); + assertThat(numericTypes.getUnsignedByte(), is((short) 255)); } { - Object miscTypesInstance = types.getMethod("getMiscTypes").invoke(instance); - double _double = (double) miscTypes.getMethod("get_double").invoke(miscTypesInstance); - float _float = (float) miscTypes.getMethod("get_float").invoke(miscTypesInstance); - String anyURI = (String) miscTypes.getMethod("getAnyURI").invoke(miscTypesInstance); - byte[] base64Binary = (byte[]) miscTypes.getMethod("getBase64Binary").invoke( - miscTypesInstance); - boolean _boolean = (boolean) miscTypes.getMethod("get_boolean").invoke( - miscTypesInstance); - BigInteger hexBinary = (BigInteger) miscTypes.getMethod("getHexBinary").invoke( - miscTypesInstance); - String qName = (String) miscTypes.getMethod("getQName").invoke(miscTypesInstance); - String iDREF = (String) miscTypes.getMethod("getIDREF").invoke(miscTypesInstance); - List iDREFS = (List) miscTypes.getMethod("getIDREFS").invoke(miscTypesInstance); - String anyType = (String) miscTypes.getMethod("getAnyType").invoke(miscTypesInstance); - - assertThat(_double, is(1234.57)); - assertThat(_float, is(123.4f)); - assertThat(anyURI, is("https://www.google.com")); - assertThat(base64Binary, is(Base64.getDecoder().decode("Z29vZ2xl"))); - assertThat(_boolean, is(true)); - assertThat(hexBinary, is(new BigInteger("516a75cb56d7e7", 16))); - assertThat(qName, is("abcd")); - assertThat(iDREF, is("abcd")); - assertThat(iDREFS, is(Arrays.asList("abcd", "abcd"))); - assertThat(anyType, is("abcd")); + predefined.types.MiscTypes miscTypes = type.getMiscTypes(); + + assertThat(miscTypes.get_double(), is(1234.57)); + assertThat(miscTypes.getAnyURI(), is("https://www.google.com")); + assertThat(miscTypes.getBase64Binary(), is(Base64.getDecoder().decode("Z29vZ2xl"))); + assertThat(miscTypes.get_boolean(), is(true)); + assertThat(miscTypes.getHexBinary(), + is(predefined.types.HexBinaryHelper.hexStringToByteArray("016a75cb56d7e7"))); + assertThat(miscTypes.getQName(), is("abcd")); + assertThat(miscTypes.getIDREF(), is("abcd")); + assertThat(miscTypes.getIDREFS(), is(Arrays.asList("abcd", "abcd"))); + assertThat(miscTypes.getAnyType(), is("abcd")); } { - Object listPrimitiveTypesInstance = types.getMethod("getListPrimitiveTypes").invoke( - instance); - List listLong = (List) listPrimitiveTypes.getMethod("getListLong").invoke( - listPrimitiveTypesInstance); - List listInt = (List) listPrimitiveTypes.getMethod("getListInt").invoke( - listPrimitiveTypesInstance); - List listShort = (List) listPrimitiveTypes.getMethod("getListShort").invoke( - listPrimitiveTypesInstance); - List listByte = (List) listPrimitiveTypes.getMethod("getListByte").invoke( - listPrimitiveTypesInstance); - List listDouble = (List) listPrimitiveTypes.getMethod("getListDouble").invoke( - listPrimitiveTypesInstance); - List listFloat = (List) listPrimitiveTypes.getMethod("getListFloat").invoke( - listPrimitiveTypesInstance); - List listBoolean = (List) listPrimitiveTypes.getMethod("getListBoolean").invoke( - listPrimitiveTypesInstance); - - assertThat(listLong, is(Arrays.asList(-9223372036854775808L, 9223372036854775807L))); - assertThat(listInt, is(Arrays.asList(-2147483648, 2147483647))); - assertThat(listShort, is(Arrays.asList((short) -32768, (short) 32767))); - assertThat(listByte, is(Arrays.asList((byte) -128, (byte) 127))); - assertThat(listDouble, is(Arrays.asList(1234.56, 5678.12))); - assertThat(listFloat, is(Arrays.asList(123.4f, 456.1f))); - assertThat(listBoolean, is(Arrays.asList(true, false))); + predefined.types.ListPrimitiveTypes listPrimitiveTypes = + type.getListPrimitiveTypes(); + + assertThat(listPrimitiveTypes.getListLong(), + is(Arrays.asList(-9223372036854775808L, 9223372036854775807L))); + assertThat(listPrimitiveTypes.getListInt(), + is(Arrays.asList(-2147483648, 2147483647))); + assertThat(listPrimitiveTypes.getListShort(), + is(Arrays.asList((short) -32768, (short) 32767))); + assertThat(listPrimitiveTypes.getListByte(), + is(Arrays.asList((byte) -128, (byte) 127))); + assertThat(listPrimitiveTypes.getListDouble(), is(Arrays.asList(1234.56, 5678.12))); + assertThat(listPrimitiveTypes.getListFloat(), is(Arrays.asList(123.4f, 456.1f))); + assertThat(listPrimitiveTypes.getListBoolean(), is(Arrays.asList(true, false))); } - } - @Test - public void testSimpleType() throws Exception { - TestCompilationResult result; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "simple_type/simple_type.xsd")) { - result = TestHelper.parseXsdAndCompile(in); + String actualStr, expectedStr; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "predefined_types.xml")) { + expectedStr = new String(str.readAllBytes()); } - - Class<?> xmlParser = result.loadClass("XmlParser"); - Class<?> simpleTypes = result.loadClass("SimpleTypes"); - - Object instance; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "simple_type.xml")) { - instance = xmlParser.getMethod("read", InputStream.class).invoke(null, in); + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try(predefined.types.XmlWriter writer = + new predefined.types.XmlWriter(new PrintWriter(baos))) { + predefined.types.XmlWriter.write(writer, type); + } + actualStr = new String(baos.toByteArray()); } - List listInt = (List) simpleTypes.getMethod("getListInt").invoke(instance); - List uniontest = (List) simpleTypes.getMethod("getUnionTest").invoke(instance); - - assertThat(listInt, is(Arrays.asList(1, 2, 3, 4, 5))); - assertThat(uniontest, is(Arrays.asList("100"))); + assertThat(new String(actualStr), is(expectedStr)); } @Test - public void testReference() throws Exception { - TestCompilationResult result; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "reference/reference.xsd")) { - result = TestHelper.parseXsdAndCompile(in); + public void testSimpleType() throws Exception { + simple.type.SimpleTypes simples; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "simple_type.xml")) { + simples = simple.type.XmlParser.readSimpleTypes(str); } - Class<?> xmlParser = result.loadClass("XmlParser"); - Class<?> cls = result.loadClass("Class"); + assertThat(simples.getListInt(), is(Arrays.asList(1, 2, 3, 4, 5))); + assertThat(simples.getUnionTest(), is(Arrays.asList("100"))); - Object instance; - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "reference.xml")) { - instance = xmlParser.getMethod("read", InputStream.class).invoke(null, in); + String actualStr, expectedStr; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "simple_type.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.write(writer, simples); + } + actualStr = new String(baos.toByteArray()); } - List student = (List) cls.getMethod("getStudent").invoke(instance); - - assertThat(student, is(Arrays.asList("Sam", "Paul", "Peter"))); + assertThat(new String(actualStr), is(expectedStr)); } - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test - public void testUnsupportedTag() throws Exception { - thrown.expect(SAXException.class); - thrown.expectMessage("unsupported tag : import"); - - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "unsupported_tag.xsd")) { - TestHelper.parseXsdAndCompile(in); + public void testReference() throws Exception { + reference.Class _class; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "reference.xml")) { + _class = reference.XmlParser.read(str); } - } - @Test - public void testUnsupportedAttribute() throws Exception { - thrown.expect(SAXException.class); - thrown.expectMessage("substitution group of an element is not supported."); + assertThat(_class.getStudent(), is(Arrays.asList("Sam", "Paul", "Peter"))); - try (InputStream in = this.getClass().getClassLoader().getResourceAsStream( - "unsupported_attribute.xsd")) { - TestHelper.parseXsdAndCompile(in); + String actualStr, expectedStr; + try (InputStream str = this.getClass().getClassLoader().getResourceAsStream( + "reference.xml")) { + expectedStr = new String(str.readAllBytes()); } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try(reference.XmlWriter writer = new reference.XmlWriter(new PrintWriter(baos))) { + reference.XmlWriter.write(writer, _class); + } + actualStr = new String(baos.toByteArray()); + } + + assertThat(new String(actualStr), is(expectedStr)); } } diff --git a/tests/tests.cpp b/tests/tests.cpp new file mode 100644 index 0000000..c143f4e --- /dev/null +++ b/tests/tests.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2021 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. + */ + +#include <iostream> +#include <fstream> +#include <string> +#include <optional> + +#include <android-base/macros.h> +#include <gtest/gtest.h> +#include "nested_type.h" +#include "purchase_simple.h" +#include "simple_complex_content.h" + +#include "predefined_types.h" +#include "reference.h" +#include "attr_group_simple.h" +#include "group.h" +#include "xmltest.h" + +using namespace std; + +TEST_F(XmlTest, Predefinedtypes) { + using namespace predefined::types; + Types type = *read(Resource("predefined_types.xml").c_str()); + + StringTypes stringTypes = *type.getFirstStringTypes(); + DateTypes dateTypes = *type.getFirstDateTypes(); + NumericTypes numericTypes = *type.getFirstNumericTypes(); + MiscTypes miscTypes = *type.getFirstMiscTypes(); + ListPrimitiveTypes listPrimitiveTypes = *type.getFirstListPrimitiveTypes(); + + EXPECT_EQ(stringTypes.getString(), "abcd"); + EXPECT_EQ(stringTypes.getToken(), "abcd"); + EXPECT_EQ(stringTypes.getNormalizedString(), "abcd"); + EXPECT_EQ(stringTypes.getLanguage(), "abcd"); + EXPECT_EQ(stringTypes.getEntity(), "abcd"); + EXPECT_EQ(stringTypes.getEntities()[0], "a"); + EXPECT_EQ(stringTypes.getEntities()[1], "b"); + EXPECT_EQ(stringTypes.getEntities()[2], "c"); + EXPECT_EQ(stringTypes.getEntities()[3], "d"); + EXPECT_EQ(stringTypes.getId(), "abcd"); + EXPECT_EQ(stringTypes.getName(), "abcd"); + EXPECT_EQ(stringTypes.getNcname(), "abcd"); + EXPECT_EQ(stringTypes.getNmtoken(), "abcd"); + EXPECT_EQ(stringTypes.getNmtokens()[0], "a"); + EXPECT_EQ(stringTypes.getNmtokens()[1], "b"); + EXPECT_EQ(stringTypes.getNmtokens()[2], "c"); + EXPECT_EQ(stringTypes.getNmtokens()[3], "d"); + + + EXPECT_EQ(dateTypes.getDate(), "2018-06-18"); + EXPECT_EQ(dateTypes.getDateTime(), "2018-06-18T21:32:52"); + EXPECT_EQ(dateTypes.getDuration(), "P3M"); + EXPECT_EQ(dateTypes.getGDay(), "---18"); + EXPECT_EQ(dateTypes.getGMonth(), "--06"); + EXPECT_EQ(dateTypes.getGMonthDay(), "--06-18"); + EXPECT_EQ(dateTypes.getGYear(), "2018"); + EXPECT_EQ(dateTypes.getGYearMonth(), "2018-06"); + EXPECT_EQ(dateTypes.getTime(), "21:32:52"); + + EXPECT_EQ(numericTypes.getDecimal(), 1234.57); + EXPECT_EQ(numericTypes.getInteger(), 1234567890123456789); + EXPECT_EQ(numericTypes.get_long(), 9223372036854775807); + EXPECT_EQ(numericTypes.get_int(), 2147483647); + EXPECT_EQ(numericTypes.get_short(), 32767); + EXPECT_EQ((int)numericTypes.getByte(), 127); + EXPECT_EQ(numericTypes.getNegativeInteger(), -1234); + EXPECT_EQ(numericTypes.getNonNegativeInteger(), 1234); + EXPECT_EQ(numericTypes.getPositiveInteger(), 1234); + EXPECT_EQ(numericTypes.getNonPositiveInteger(), -1234); + EXPECT_EQ(numericTypes.getUnsignedLong(), 1234); + EXPECT_EQ(numericTypes.getUnsignedInt(), 1234); + EXPECT_EQ(numericTypes.getUnsignedShort(), 1234); + EXPECT_EQ((int)(numericTypes.getUnsignedByte()), 255); + + EXPECT_EQ(miscTypes.get_double(), 1234.57); + EXPECT_EQ(miscTypes.getAnyURI(), "https://www.google.com"); + EXPECT_EQ(miscTypes.getBase64Binary(), "Z29vZ2xl"); + EXPECT_TRUE(miscTypes.getBoolean()); + EXPECT_EQ(miscTypes.getHexBinary(), "016a75cb56d7e7"); + EXPECT_EQ(miscTypes.getQName(), "abcd"); + EXPECT_EQ(miscTypes.getIDREF(), "abcd"); + EXPECT_EQ(miscTypes.getIDREFS()[0], "abcd"); + EXPECT_EQ(miscTypes.getIDREFS()[1], "abcd"); + EXPECT_EQ(miscTypes.getAnyType(), "abcd"); + + EXPECT_EQ(listPrimitiveTypes.getListInt()[0], -2147483648); + EXPECT_EQ(listPrimitiveTypes.getListInt()[1], 2147483647); + EXPECT_EQ(listPrimitiveTypes.getListShort()[0], -32768); + EXPECT_EQ(listPrimitiveTypes.getListShort()[1], 32767); + EXPECT_EQ((int)listPrimitiveTypes.getListByte()[0], -128); + EXPECT_EQ((int)listPrimitiveTypes.getListByte()[1], 127); + EXPECT_EQ(listPrimitiveTypes.getListDouble()[0], 1234.56); + EXPECT_EQ(listPrimitiveTypes.getListDouble()[1], 5678.12); + EXPECT_TRUE(listPrimitiveTypes.getListBoolean()[0]); + EXPECT_FALSE(listPrimitiveTypes.getListBoolean()[1]); + + ofstream out("old_predefined_types.xml"); + write(out, type); + Types type2 = *read("old_predefined_types.xml"); + + NumericTypes numericTypes2 = *type.getFirstNumericTypes(); + ListPrimitiveTypes listPrimitiveTypes2 = *type.getFirstListPrimitiveTypes(); + + EXPECT_EQ(numericTypes.getDecimal(), numericTypes2.getDecimal()); + EXPECT_EQ(numericTypes.getInteger(), numericTypes2.getInteger()); + EXPECT_EQ(numericTypes.get_long(), numericTypes2.get_long()); + EXPECT_EQ(numericTypes.get_int(), numericTypes2.get_int()); + EXPECT_EQ(numericTypes.get_short(), numericTypes2.get_short()); + EXPECT_EQ(numericTypes.getByte(), numericTypes2.getByte()); + EXPECT_EQ(numericTypes.getNegativeInteger(), numericTypes2.getNegativeInteger()); + EXPECT_EQ(numericTypes.getNonNegativeInteger(), numericTypes2.getNonNegativeInteger()); + EXPECT_EQ(numericTypes.getPositiveInteger(), numericTypes2.getPositiveInteger()); + EXPECT_EQ(numericTypes.getNonPositiveInteger(), numericTypes2.getNonPositiveInteger()); + EXPECT_EQ(numericTypes.getUnsignedLong(), numericTypes2.getUnsignedLong()); + EXPECT_EQ(numericTypes.getUnsignedInt(), numericTypes2.getUnsignedInt()); + EXPECT_EQ(numericTypes.getUnsignedShort(), numericTypes2.getUnsignedShort()); + EXPECT_EQ((numericTypes.getUnsignedByte()), numericTypes2.getUnsignedByte()); + + EXPECT_EQ(listPrimitiveTypes.getListInt()[0], listPrimitiveTypes2.getListInt()[0]); + EXPECT_EQ(listPrimitiveTypes.getListInt()[1], listPrimitiveTypes2.getListInt()[1]); + EXPECT_EQ(listPrimitiveTypes.getListShort()[0], listPrimitiveTypes2.getListShort()[0]); + EXPECT_EQ(listPrimitiveTypes.getListShort()[1], listPrimitiveTypes2.getListShort()[1]); + EXPECT_EQ(listPrimitiveTypes.getListByte()[0], listPrimitiveTypes2.getListByte()[0]); + EXPECT_EQ(listPrimitiveTypes.getListByte()[1], listPrimitiveTypes2.getListByte()[1]); + EXPECT_EQ(listPrimitiveTypes.getListDouble()[0], listPrimitiveTypes2.getListDouble()[0]); + EXPECT_EQ(listPrimitiveTypes.getListDouble()[1], listPrimitiveTypes2.getListDouble()[1]); + EXPECT_EQ(listPrimitiveTypes.getListBoolean()[0], listPrimitiveTypes2.getListBoolean()[0]); + EXPECT_EQ(listPrimitiveTypes.getListBoolean()[1], listPrimitiveTypes2.getListBoolean()[1]); +} + +TEST_F(XmlTest, Nestedtype) { + using namespace nested::type; + Employee employee = *read(Resource("nested_type.xml").c_str()); + + Employee::Address address = *employee.getFirstAddress(); + Employee::Address::Extra extra = *address.getFirstExtra(); + + EXPECT_EQ((int)employee.getId(), 1); + EXPECT_EQ(employee.getName(), "Peter"); + EXPECT_EQ(address.getCountry(), "US"); + EXPECT_EQ(address.getState(), "Mountain View"); + EXPECT_EQ(address.getZip(), 3342); + EXPECT_EQ(extra.getLine1(), "Donga 303-111"); + EXPECT_EQ(extra.getLine2(), "Good Street"); + + ofstream out("old_nested_type.xml"); + write(out, employee); +} + +TEST_F(XmlTest, Purchasesimple) { + using namespace purchase::simple; + PurchaseOrderType orderType = *read(Resource("purchase_simple.xml").c_str()); + + EXPECT_EQ(orderType.getOrderDate(), "1900-01-01"); + + EXPECT_EQ(orderType.getShipTo()[0].getName(), "name1"); + EXPECT_EQ(orderType.getShipTo()[0].getStreet(), "street1"); + EXPECT_EQ(orderType.getShipTo()[0].getCity(), "city1"); + EXPECT_EQ(orderType.getShipTo()[0].getState(), "state1"); + EXPECT_EQ(orderType.getShipTo()[0].getZip(), 1); + EXPECT_EQ(orderType.getShipTo()[0].getCountry(), "US"); + EXPECT_EQ(orderType.getShipTo()[1].getName(), "name2"); + EXPECT_EQ(orderType.getShipTo()[1].getStreet(), "street2"); + EXPECT_EQ(orderType.getShipTo()[1].getCity(), "city2"); + EXPECT_EQ(orderType.getShipTo()[1].getState(), "state2"); + EXPECT_EQ(orderType.getShipTo()[1].getZip(), -7922816251426433759); + EXPECT_EQ(orderType.getShipTo()[1].getCountry(), "US"); + + EXPECT_EQ(orderType.getBillTo()[0].getName(), "billName"); + EXPECT_EQ(orderType.getBillTo()[0].getStreet(), "billStreet"); + EXPECT_EQ(orderType.getBillTo()[0].getCity(), "billCity"); + EXPECT_EQ(orderType.getBillTo()[0].getState(), "billState"); + EXPECT_EQ(orderType.getBillTo()[0].getZip(), 1); + EXPECT_EQ(orderType.getBillTo()[0].getCountry(), "US"); + + ofstream out("old_purchase_simple.xml"); + write(out, orderType); + + PurchaseOrderType orderType2 = *read("old_purchase_simple.xml"); + + EXPECT_EQ(orderType.getOrderDate(), orderType2.getOrderDate()); + + EXPECT_EQ(orderType.getShipTo()[0].getName(), orderType2.getShipTo()[0].getName()); + EXPECT_EQ(orderType.getShipTo()[0].getStreet(), orderType2.getShipTo()[0].getStreet()); + EXPECT_EQ(orderType.getShipTo()[0].getCity(), orderType2.getShipTo()[0].getCity()); + EXPECT_EQ(orderType.getShipTo()[0].getState(), orderType2.getShipTo()[0].getState()); + EXPECT_EQ(orderType.getShipTo()[0].getZip(), orderType2.getShipTo()[0].getZip()); + EXPECT_EQ(orderType.getShipTo()[0].getCountry(), orderType2.getShipTo()[0].getCountry()); + EXPECT_EQ(orderType.getShipTo()[1].getName(), orderType2.getShipTo()[1].getName()); + EXPECT_EQ(orderType.getShipTo()[1].getStreet(), orderType2.getShipTo()[1].getStreet()); + EXPECT_EQ(orderType.getShipTo()[1].getCity(), orderType2.getShipTo()[1].getCity()); + EXPECT_EQ(orderType.getShipTo()[1].getState(), orderType2.getShipTo()[1].getState()); + EXPECT_EQ(orderType.getShipTo()[1].getZip(), orderType2.getShipTo()[1].getZip()); + EXPECT_EQ(orderType.getShipTo()[1].getCountry(), orderType2.getShipTo()[1].getCountry()); + + EXPECT_EQ(orderType.getBillTo()[0].getName(), orderType2.getBillTo()[0].getName()); + EXPECT_EQ(orderType.getBillTo()[0].getStreet(), orderType2.getBillTo()[0].getStreet()); + EXPECT_EQ(orderType.getBillTo()[0].getCity(), orderType2.getBillTo()[0].getCity()); + EXPECT_EQ(orderType.getBillTo()[0].getState(), orderType2.getBillTo()[0].getState()); + EXPECT_EQ(orderType.getBillTo()[0].getZip(), orderType2.getBillTo()[0].getZip()); + EXPECT_EQ(orderType.getBillTo()[0].getCountry(), orderType2.getBillTo()[0].getCountry()); +} + +TEST_F(XmlTest, Reference) { + using namespace reference; + Class _class = *read(Resource("reference.xml").c_str()); + + EXPECT_EQ(_class.getStudent()[0], "Sam"); + EXPECT_EQ(_class.getStudent()[1], "Paul"); + EXPECT_EQ(_class.getStudent()[2], "Peter"); + + ofstream out("old_reference.xml"); + write(out, _class); +} + +TEST_F(XmlTest, Simplecomplexcontent) { + using namespace simple::complex::content; + Person person = *readPerson(Resource("simple_complex_content.xml").c_str()); + USAddressP uSAddressP = *person.getFirstUSAddressP(); + KRAddress kRAddress = *person.getFirstKRAddress(); + SubAddress subAddress = *person.getFirstSubAddress(); + + EXPECT_EQ(person.getName(), "Petr"); + + EXPECT_EQ(uSAddressP.getName(), "404"); + EXPECT_EQ(uSAddressP.getStreet(), "street fighter"); + EXPECT_EQ(uSAddressP.getCity(), "New York"); + EXPECT_EQ(uSAddressP.getState(), "Washington"); + EXPECT_EQ(uSAddressP.getZipcode(), 323232318329852); + + EXPECT_EQ(kRAddress.getName(), "Donga Studio"); + EXPECT_EQ(kRAddress.getStreet(), "Nokdu Street"); + EXPECT_EQ(kRAddress.getCity(), "Seoul"); + + EXPECT_EQ(subAddress.getChoice1_optional(), "Temp"); + + ofstream out("old_simple_complex_content.xml"); + write(out, person); +} + +TEST_F(XmlTest, Attrgroupsimple) { + using namespace attr::group::simple; + Student student = *read(Resource("attr_group_simple.xml").c_str()); + + EXPECT_EQ(student.getName(), "Jun"); + EXPECT_EQ(student.getCity(), "Mountain View"); + EXPECT_EQ(student.getState(), "CA"); + EXPECT_EQ(student.getRoad(), "Street 101"); + EXPECT_EQ(student.getList()[0], 1); + EXPECT_EQ(student.getList()[1], 2); + EXPECT_EQ(student.getList()[2], 3); + + ofstream out("old_attr_group_simple.xml"); + write(out, student); +} + +TEST_F(XmlTest, Group) { + using namespace group; + Student student = *read(Resource("group.xml").c_str()); + + EXPECT_EQ(student.getCity(), "Mountain View"); + EXPECT_EQ(student.getState(), "CA"); + EXPECT_EQ(student.getRoad(), "Street 101"); + + ofstream out("old_group.xml"); + write(out, student); +} diff --git a/tests/xmltest.h b/tests/xmltest.h new file mode 100644 index 0000000..b645b98 --- /dev/null +++ b/tests/xmltest.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 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. + */ + +#pragma once + +#include <string> + +#include <android-base/file.h> +#include <gtest/gtest.h> + +class XmlTest : public ::testing::Test { +public: + std::string Resource(const std::string& filename) { + return ::android::base::GetExecutableDirectory() + "/resources/" + filename; + } +}; diff --git a/utils/Android.bp b/utils/Android.bp new file mode 100644 index 0000000..5204bbc --- /dev/null +++ b/utils/Android.bp @@ -0,0 +1,24 @@ +// Copyright (C) 2020 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_headers { + name: "libxsdc-utils", + export_include_dirs: ["include"], + host_supported: true, + vendor_available: true, +} diff --git a/utils/include/xsdc/XsdcSupport.h b/utils/include/xsdc/XsdcSupport.h new file mode 100644 index 0000000..fe0d31c --- /dev/null +++ b/utils/include/xsdc/XsdcSupport.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 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. + */ + +#ifndef ANDROID_XSDC_SUPPORT_H +#define ANDROID_XSDC_SUPPORT_H + +#include <iterator> +#include <type_traits> + +namespace android { + +namespace details { +// Never instantiated. Used as a placeholder for template variables. +template <typename T> +struct xsdc_invalid_type; + +// XSDC generates specializations of this for enums. See xsdc_enum_range. +template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>> +constexpr xsdc_invalid_type<T> xsdc_enum_values; +} // namespace details + +/** + * Every XSDC generated enum supports this function. + * E.x.: for (const auto v : xsdc_enum_range<Enum>()) { ... } + */ +template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>> +struct xsdc_enum_range { + // Container-like associated type. + using value_type = T; + + constexpr auto begin() const { return std::begin(details::xsdc_enum_values<T>); } + constexpr auto cbegin() const { return begin(); } + constexpr auto rbegin() const { return std::rbegin(details::xsdc_enum_values<T>); } + constexpr auto crbegin() const { return rbegin(); } + constexpr auto end() const { return std::end(details::xsdc_enum_values<T>); } + constexpr auto cend() const { return end(); } + constexpr auto rend() const { return std::rend(details::xsdc_enum_values<T>); } + constexpr auto crend() const { return rend(); } +}; + +} // namespace android + +#endif // ANDROID_XSDC_SUPPORT_H |