1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.xsdc.cpp;
18 
19 import com.android.xsdc.CodeWriter;
20 import com.android.xsdc.FileSystem;
21 import com.android.xsdc.XmlSchema;
22 import com.android.xsdc.XsdConstants;
23 import com.android.xsdc.tag.*;
24 
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 
34 import javax.xml.namespace.QName;
35 
36 public class CppCodeGenerator {
37     public static final int GENERATE_ENUMS = 1 << 0;
38     public static final int GENERATE_PARSER = 1 << 1;
39 
40     private XmlSchema xmlSchema;
41     private String pkgName;
42     private Map<String, CppSimpleType> cppSimpleTypeMap;
43     private CodeWriter enumsCppFile;
44     private CodeWriter enumsHeaderFile;
45     private CodeWriter parserCppFile;
46     private CodeWriter parserHeaderFile;
47     private boolean hasAttr;
48     private boolean writer;
49     private int generators;
50     private boolean booleanGetter;
51 
52     private static final String UNKNOWN_ENUM = "UNKNOWN";
53 
CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer, int generators, boolean booleanGetter)54     public CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer, int generators,
55             boolean booleanGetter) throws CppCodeGeneratorException {
56         this.xmlSchema = xmlSchema;
57         this.pkgName = pkgName;
58         this.writer = writer;
59         this.generators = generators;
60         this.booleanGetter = booleanGetter;
61 
62         // class naming validation
63         {
64             Set<String> nameSet = new HashSet<>();
65             nameSet.add("XmlParser");
66             for (XsdType type : xmlSchema.getTypeMap().values()) {
67                 if ((type instanceof XsdComplexType) || (type instanceof XsdRestriction &&
68                         ((XsdRestriction)type).getEnums() != null)) {
69                     String name = Utils.toClassName(type.getName());
70                     if (nameSet.contains(name)) {
71                         throw new CppCodeGeneratorException(
72                                 String.format("duplicate class name : %s", name));
73                     }
74                     nameSet.add(name);
75                     if (type instanceof XsdComplexType && !hasAttr) {
76                         hasAttr = hasAttribute((XsdComplexType)type);
77                     }
78                 }
79             }
80             for (XsdElement element : xmlSchema.getElementMap().values()) {
81                 XsdType type = element.getType();
82                 if (type.getRef() == null && type instanceof XsdComplexType) {
83                     String name = Utils.toClassName(element.getName());
84                     if (nameSet.contains(name)) {
85                         throw new CppCodeGeneratorException(
86                                 String.format("duplicate class name : %s", name));
87                     }
88                     nameSet.add(name);
89                     if (!hasAttr) {
90                         hasAttr = hasAttribute((XsdComplexType)type);
91                     }
92                 }
93             }
94         }
95 
96         cppSimpleTypeMap = new HashMap<>();
97         for (XsdType type : xmlSchema.getTypeMap().values()) {
98             if (type instanceof XsdSimpleType) {
99                 XsdType refType = new XsdType(null, new QName(type.getName()));
100                 parseSimpleType(refType, true);
101             }
102         }
103     }
104 
print(FileSystem fs)105     public void print(FileSystem fs)
106             throws CppCodeGeneratorException, IOException {
107         // cpp file, header file init
108         String fileNameStem = pkgName.replace('.', '_');
109         String enumsCppFileName = fileNameStem + "_enums.cpp";
110         String enumsHeaderFileName = fileNameStem + "_enums.h";
111         String parserCppFileName = fileNameStem + ".cpp";
112         String parserHeaderFileName = fileNameStem + ".h";
113         if ((this.generators & GENERATE_ENUMS) == GENERATE_ENUMS) {
114             enumsCppFile = new CodeWriter(fs.getPrintWriter(enumsCppFileName));
115             enumsHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + enumsHeaderFileName));
116         } else {
117             enumsCppFile = new CodeWriter();
118             enumsHeaderFile = new CodeWriter();
119         }
120         if ((this.generators & GENERATE_PARSER) == GENERATE_PARSER) {
121             parserCppFile = new CodeWriter(fs.getPrintWriter(parserCppFileName));
122             parserHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + parserHeaderFileName));
123         } else {
124             parserCppFile = new CodeWriter();
125             parserHeaderFile = new CodeWriter();
126         }
127 
128         boolean hasEnums = false;
129         for (XsdType type : xmlSchema.getTypeMap().values()) {
130             if (type instanceof XsdRestriction &&
131                   ((XsdRestriction)type).getEnums() != null) {
132                 hasEnums = true;
133                 break;
134             }
135         }
136 
137         String enumsHeaderMacro = enumsHeaderFileName.toUpperCase().replace('.', '_');
138         String parserHeaderMacro = parserHeaderFileName.toUpperCase().replace('.', '_');
139         enumsHeaderFile.printf("#ifndef %s\n", enumsHeaderMacro);
140         enumsHeaderFile.printf("#define %s\n", enumsHeaderMacro);
141         enumsHeaderFile.printf("\n");
142         enumsHeaderFile.printf("#include <array>\n");
143         enumsHeaderFile.printf("#include <string>\n");
144         enumsHeaderFile.printf("\n");
145         parserHeaderFile.printf("#ifndef %s\n", parserHeaderMacro);
146         parserHeaderFile.printf("#define %s\n", parserHeaderMacro);
147         parserHeaderFile.printf("\n");
148         parserHeaderFile.printf("#include <array>\n");
149         parserHeaderFile.printf("#include <map>\n");
150         parserHeaderFile.printf("#include <optional>\n");
151         parserHeaderFile.printf("#include <string>\n");
152         parserHeaderFile.printf("#include <vector>\n");
153         if (writer) {
154             parserHeaderFile.printf("#include <iostream>\n");
155         }
156         parserHeaderFile.printf("\n");
157         parserHeaderFile.printf("#if __has_include(<libxml/parser.h>)\n");
158         parserHeaderFile.printf("#include <libxml/parser.h>\n");
159         parserHeaderFile.printf("#include <libxml/xinclude.h>\n");
160         parserHeaderFile.printf("#else\n");
161         parserHeaderFile.printf("#error Require libxml2 library. ");
162         parserHeaderFile.printf("Please add libxml2 to shared_libs or static_libs\n");
163         parserHeaderFile.printf("#endif\n");
164         if (hasEnums) {
165             enumsHeaderFile.printf("#include <xsdc/XsdcSupport.h>\n");
166             enumsHeaderFile.printf("\n");
167         }
168         parserHeaderFile.printf("\n");
169         parserHeaderFile.printf("#include \"%s\"\n", enumsHeaderFileName);
170         parserHeaderFile.printf("\n");
171 
172         enumsCppFile.printf("#include <map>\n");
173         enumsCppFile.printf("\n");
174         enumsCppFile.printf("#include \"%s\"\n\n", enumsHeaderFileName);
175         parserCppFile.printf("#define LOG_TAG \"%s\"\n", pkgName);
176         parserCppFile.printf("#include \"%s\"\n\n", parserHeaderFileName);
177 
178         List<String> namespace = new java.util.ArrayList<>();
179         for (String token : pkgName.split("\\.")) {
180             if (token.isEmpty()) {
181                 continue;
182             }
183             if (Character.isDigit(token.charAt(0))) {
184                 token = "_" + token;
185             }
186             namespace.add(token);
187             enumsHeaderFile.printf("namespace %s {\n", token);
188             enumsCppFile.printf("namespace %s {\n", token);
189             parserHeaderFile.printf("namespace %s {\n", token);
190             parserCppFile.printf("namespace %s {\n", token);
191         }
192 
193         printPrototype();
194         printXmlParser();
195         if (writer) {
196             printXmlWriter();
197         }
198 
199         for (XsdType type : xmlSchema.getTypeMap().values()) {
200             if (type instanceof XsdRestriction &&
201                   ((XsdRestriction)type).getEnums() != null) {
202                 String name = Utils.toClassName(type.getName());
203                 XsdRestriction restrictionType = (XsdRestriction) type;
204                 printEnum(name, restrictionType);
205             }
206         }
207         for (XsdType type : xmlSchema.getTypeMap().values()) {
208             if (type instanceof XsdComplexType) {
209                 String name = Utils.toClassName(type.getName());
210                 XsdComplexType complexType = (XsdComplexType) type;
211                 printClass(name, "", complexType);
212             }
213         }
214         for (XsdElement element : xmlSchema.getElementMap().values()) {
215             XsdType type = element.getType();
216             if (type.getRef() == null && type instanceof XsdComplexType) {
217                 String name = Utils.toClassName(element.getName());
218                 XsdComplexType complexType = (XsdComplexType) type;
219                 printClass(name, "", complexType);
220             }
221         }
222 
223         Collections.reverse(namespace);
224         for (String token : namespace) {
225             enumsHeaderFile.printf("} // %s\n", token);
226             enumsCppFile.printf("} // %s\n", token);
227             parserHeaderFile.printf("} // %s\n", token);
228             parserCppFile.printf("} // %s\n", token);
229         }
230 
231         if (hasEnums) {
232             enumsHeaderFile.printf("\n//\n// global type declarations for package\n//\n\n");
233             enumsHeaderFile.printf("namespace android {\nnamespace details {\n");
234             Collections.reverse(namespace);
235             for (XsdType type : xmlSchema.getTypeMap().values()) {
236                 if (type instanceof XsdRestriction &&
237                         ((XsdRestriction)type).getEnums() != null) {
238                     String name = Utils.toClassName(type.getName());
239                     XsdRestriction restrictionType = (XsdRestriction) type;
240                     printEnumValues(namespace, name, restrictionType);
241                 }
242             }
243             enumsHeaderFile.printf("}  // namespace details\n}  // namespace android\n\n");
244         }
245 
246         parserHeaderFile.printf("#endif // %s\n", parserHeaderMacro);
247         enumsHeaderFile.printf("#endif // %s\n", enumsHeaderMacro);
248         parserCppFile.close();
249         parserHeaderFile.close();
250         enumsCppFile.close();
251         enumsHeaderFile.close();
252     }
253 
printEnum(String name, XsdRestriction restrictionType)254     private void printEnum(String name, XsdRestriction restrictionType)
255             throws CppCodeGeneratorException {
256         enumsHeaderFile.printf("enum class %s {\n", name);
257         enumsCppFile.printf("const std::map<std::string, %s> %sString {\n", name, name);
258         List<XsdEnumeration> enums = restrictionType.getEnums();
259 
260         enumsHeaderFile.printf("%s = %d,\n", UNKNOWN_ENUM, -1);
261         for (XsdEnumeration tag : enums) {
262             String value = tag.getValue();
263             enumsHeaderFile.printf("%s,\n", Utils.toEnumName(value));
264             enumsCppFile.printf("{ \"%s\", %s::%s },\n", tag.getValue(), name,
265                     Utils.toEnumName(value));
266         }
267         enumsHeaderFile.printf("};\n");
268         enumsCppFile.printf("};\n\n");
269 
270         enumsHeaderFile.printf("%s stringTo%s(const std::string& value);\n",
271                 name, name);
272         enumsCppFile.printf("%s stringTo%s(const std::string& value) {\n"
273                 + "auto enumValue = %sString.find(value);\n"
274                 + "return enumValue != %sString.end() ? enumValue->second : %s::%s;\n"
275                 + "}\n\n", name, name, name, name, name, UNKNOWN_ENUM);
276 
277         enumsHeaderFile.printf("std::string toString(%s o);\n\n", name);
278         enumsCppFile.printf("std::string toString(%s o) {\n", name);
279         enumsCppFile.printf("switch (o) {\n");
280         for (XsdEnumeration tag : enums) {
281             String value = tag.getValue();
282             enumsCppFile.printf("case %s::%s: return \"%s\";\n",
283                     name, Utils.toEnumName(value), tag.getValue());
284         }
285         enumsCppFile.printf("default: return std::to_string(static_cast<int>(o));\n}\n");
286         enumsCppFile.printf("}\n\n");
287     }
288 
printEnumValues(List<String> namespace, String name, XsdRestriction restrictionType)289     private void printEnumValues(List<String> namespace, String name,
290             XsdRestriction restrictionType) throws CppCodeGeneratorException {
291         List<XsdEnumeration> enums = restrictionType.getEnums();
292         String absoluteNamespace = "::" + String.join("::", namespace);
293         enumsHeaderFile.printf("template<> inline constexpr std::array<%s::%s, %d> "
294                 + "xsdc_enum_values<%s::%s> = {\n",
295                 absoluteNamespace, name, enums.size(), absoluteNamespace, name);
296         for (XsdEnumeration tag : enums) {
297             String value = tag.getValue();
298             enumsHeaderFile.printf("%s::%s::%s,\n",
299                     absoluteNamespace, name, Utils.toEnumName(value));
300         }
301         enumsHeaderFile.printf("};\n");
302     }
303 
printPrototype()304     private void printPrototype() throws CppCodeGeneratorException {
305         for (XsdType type : xmlSchema.getTypeMap().values()) {
306             if (type instanceof XsdComplexType) {
307                 String name = Utils.toClassName(type.getName());
308                 parserHeaderFile.printf("class %s;\n", name);
309             }
310         }
311         for (XsdElement element : xmlSchema.getElementMap().values()) {
312             XsdType type = element.getType();
313             if (type.getRef() == null && type instanceof XsdComplexType) {
314                 String name = Utils.toClassName(element.getName());
315                 parserHeaderFile.printf("class %s;\n", name);
316             }
317         }
318     }
319 
printClass(String name, String nameScope, XsdComplexType complexType)320     private void printClass(String name, String nameScope, XsdComplexType complexType)
321             throws CppCodeGeneratorException {
322         assert name != null;
323         // need element, attribute name duplicate validation?
324 
325         String baseName = getBaseName(complexType);
326         CppSimpleType valueType = (complexType instanceof XsdSimpleContent) ?
327                 getValueType((XsdSimpleContent) complexType, false) : null;
328 
329         parserHeaderFile.printf("class %s ", name);
330 
331         if (baseName != null) {
332             parserHeaderFile.printf(": public %s {\n", baseName);
333         } else {
334             parserHeaderFile.println("{");
335         }
336 
337         // parse types for elements and attributes
338         List<CppType> elementTypes = new ArrayList<>();
339         List<XsdElement> elements = new ArrayList<>();
340         elements.addAll(getAllElements(complexType.getGroup()));
341         elements.addAll(complexType.getElements());
342 
343         for (XsdElement element : elements) {
344             CppType cppType;
345             XsdElement elementValue = resolveElement(element);
346             if (element.getRef() == null && element.getType().getRef() == null
347                     && element.getType() instanceof XsdComplexType) {
348                 // print inner class for anonymous types
349                 parserHeaderFile.printf("public:\n");
350                 String innerName = Utils.toClassName(getElementName(element));
351                 XsdComplexType innerType = (XsdComplexType) element.getType();
352                 printClass(innerName, nameScope + name + "::", innerType);
353                 parserHeaderFile.println();
354                 cppType = new CppComplexType(nameScope + name + "::"+ innerName);
355             } else {
356                 cppType = parseType(elementValue.getType(), getElementName(elementValue));
357             }
358             elementTypes.add(cppType);
359         }
360         List<CppSimpleType> attributeTypes = new ArrayList<>();
361         List<XsdAttribute> attributes = new ArrayList();
362         for (XsdAttributeGroup attributeGroup : complexType.getAttributeGroups()) {
363             attributes.addAll(getAllAttributes(resolveAttributeGroup(attributeGroup)));
364         }
365         attributes.addAll(complexType.getAttributes());
366 
367         for (XsdAttribute attribute : attributes) {
368             XsdType type = resolveAttribute(attribute).getType();
369             attributeTypes.add(parseSimpleType(type, false));
370         }
371 
372         // print member variables
373 
374         parserHeaderFile.printf("private:\n");
375         for (int i = 0; i < elementTypes.size(); ++i) {
376             CppType type = elementTypes.get(i);
377             XsdElement element = elements.get(i);
378             XsdElement elementValue = resolveElement(element);
379             String typeName = Utils.elementTypeName(type.getName(),
380                     element.isMultiple() || type instanceof CppComplexType);
381             parserHeaderFile.printf("const %s %s_;\n", typeName,
382                     Utils.toVariableName(getElementName(elementValue)));
383         }
384         for (int i = 0; i < attributeTypes.size(); ++i) {
385             CppType type = attributeTypes.get(i);
386             XsdAttribute attribute = resolveAttribute(attributes.get(i));
387             String variableName = Utils.toVariableName(attribute.getName());
388             if (attribute.isRequired()) {
389                 parserHeaderFile.printf("const %s %s_;\n", type.getName(), variableName);
390             } else {
391                 parserHeaderFile.printf("const std::optional<%s> %s_;\n",
392                         type.getName(), variableName);
393             }
394         }
395         if (valueType != null) {
396             parserHeaderFile.printf("const std::optional<%s> _value;\n", valueType.getName());
397         }
398 
399         parserHeaderFile.printf("public:\n");
400         String constructorArgs = printConstructor(name, nameScope, complexType, elements,
401                 attributes, baseName);
402 
403         // print getters and setters
404         for (int i = 0; i < elementTypes.size(); ++i) {
405             CppType type = elementTypes.get(i);
406             XsdElement element = elements.get(i);
407             XsdElement elementValue = resolveElement(element);
408             printGetter(nameScope + name, type,
409                     Utils.toVariableName(getElementName(elementValue)),
410                     type instanceof CppComplexType ? true : element.isMultiple(),
411                     type instanceof CppComplexType ? false : ((CppSimpleType)type).isList(),
412                     false);
413         }
414         for (int i = 0; i < attributeTypes.size(); ++i) {
415             CppType type = attributeTypes.get(i);
416             XsdAttribute attribute = resolveAttribute(attributes.get(i));
417             printGetter(nameScope + name, type, Utils.toVariableName(attribute.getName()),
418                     false, false, attribute.isRequired());
419         }
420         if (valueType != null) {
421             printGetter(nameScope + name, valueType, "value", false, false, false);
422         }
423 
424         printParser(name, nameScope, complexType, constructorArgs);
425 
426         if (writer) {
427             printWriter(name, nameScope, complexType);
428         }
429 
430         parserHeaderFile.println("};\n");
431     }
432 
printParser(String name, String nameScope, XsdComplexType complexType, String args)433     private void printParser(String name, String nameScope, XsdComplexType complexType, String args)
434             throws CppCodeGeneratorException {
435         CppSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ?
436                 getValueType((XsdSimpleContent) complexType, true) : null;
437         List<XsdElement> allElements = new ArrayList<>();
438         List<XsdAttribute> allAttributes = new ArrayList<>();
439         stackComponents(complexType, allElements, allAttributes);
440 
441         // parse types for elements and attributes
442         List<CppType> allElementTypes = new ArrayList<>();
443         for (XsdElement element : allElements) {
444             XsdElement elementValue = resolveElement(element);
445             CppType cppType = parseType(elementValue.getType(), elementValue.getName());
446             allElementTypes.add(cppType);
447         }
448         List<CppSimpleType> allAttributeTypes = new ArrayList<>();
449         for (XsdAttribute attribute : allAttributes) {
450             XsdType type = resolveAttribute(attribute).getType();
451             allAttributeTypes.add(parseSimpleType(type, false));
452         }
453 
454         String fullName = nameScope + name;
455         parserHeaderFile.printf("static %s read(xmlNode *root);\n", fullName, Utils.lowerize(name));
456         parserCppFile.printf("\n%s %s::read(xmlNode *root) {\n", fullName, fullName);
457 
458         parserCppFile.print("std::string raw;\n");
459 
460         for (int i = 0; i < allAttributes.size(); ++i) {
461             CppSimpleType type = allAttributeTypes.get(i);
462             XsdAttribute attribute = resolveAttribute(allAttributes.get(i));
463             String variableName = Utils.toVariableName(attribute.getName());
464             parserCppFile.printf("raw = getXmlAttribute(root, \"%s\");\n", attribute.getName());
465             if (attribute.isRequired()) {
466                 if (type.isEnum()) {
467                     parserCppFile.printf("%s %s = %s::%s;\n",
468                             type.getName(), variableName, type.getName(), UNKNOWN_ENUM);
469                 } else {
470                     parserCppFile.printf("%s %s{};\n", type.getName(), variableName);
471                 }
472             } else {
473                 parserCppFile.printf("std::optional<%s> %s = std::nullopt;\n", type.getName(),
474                         variableName);
475             }
476             parserCppFile.printf("if (raw != \"\") {\n");
477             parserCppFile.print(type.getParsingExpression());
478             parserCppFile.printf("%s = value;\n}\n", variableName);
479         }
480 
481         if (baseValueType != null) {
482             parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString("
483                     + "root->doc, root->xmlChildrenNode, 1));\n"
484                     + "if (xmlValue != nullptr) {\n"
485                     + "raw = reinterpret_cast<const char*>(xmlValue.get());\n");
486 
487             parserCppFile.print(baseValueType.getParsingExpression());
488             parserCppFile.printf("instance.setValue(value);\n");
489             parserCppFile.printf("}\n");
490         } else if (!allElements.isEmpty()) {
491             for (int i = 0; i < allElements.size(); ++i) {
492                 CppType type = allElementTypes.get(i);
493                 XsdElement element = allElements.get(i);
494                 XsdElement elementValue = resolveElement(element);
495                 String variableName = Utils.toVariableName(getElementName(elementValue));
496                 parserCppFile.printf("%s %s;\n", Utils.elementTypeName(type.getName(),
497                         element.isMultiple() || type instanceof CppComplexType), variableName);
498             }
499             parserCppFile.print("for (xmlNode *child = root->xmlChildrenNode; child != nullptr;"
500                     + " child = child->next) {\n");
501             for (int i = 0; i < allElements.size(); ++i) {
502                 CppType type = allElementTypes.get(i);
503                 XsdElement element = allElements.get(i);
504                 XsdElement elementValue = resolveElement(element);
505                 String variableName = Utils.toVariableName(getElementName(elementValue));
506 
507                 if (i != 0) parserCppFile.printf("} else ");
508                 parserCppFile.print("if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>");
509                 parserCppFile.printf("(\"%s\"))) {\n", elementValue.getName());
510 
511                 if (type instanceof CppSimpleType) {
512                     parserCppFile.print("auto xmlValue = make_xmlUnique(xmlNodeListGetString(");
513                     parserCppFile.print("child->doc, child->xmlChildrenNode, 1));\n");
514                     parserCppFile.print("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n");
515                     parserCppFile.print("raw = reinterpret_cast<const char*>(xmlValue.get());\n}");
516                     parserCppFile.print("\n");
517                 }
518 
519                 parserCppFile.print(type.getParsingExpression());
520 
521                 if (element.isMultiple() || type instanceof CppComplexType) {
522                     parserCppFile.printf("%s.push_back(std::move(value));\n", variableName);
523                 } else {
524                     parserCppFile.printf("%s = std::move(value);\n", variableName);
525                 }
526             }
527             parserCppFile.printf("}\n}\n");
528         }
529         parserCppFile.printf("%s instance%s;\n",
530                 fullName, args.length() > 0 ? "(" + args + ")" : "");
531         parserCppFile.print("return instance;\n}\n");
532     }
533 
printWriter(String name, String nameScope, XsdComplexType complexType)534     private void printWriter(String name, String nameScope, XsdComplexType complexType)
535             throws CppCodeGeneratorException {
536         CppSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ?
537                 getValueType((XsdSimpleContent) complexType, true) : null;
538         List<XsdElement> allElements = new ArrayList<>();
539         List<XsdAttribute> allAttributes = new ArrayList<>();
540         stackComponents(complexType, allElements, allAttributes);
541 
542         // parse types for elements and attributes
543         List<CppType> allElementTypes = new ArrayList<>();
544         for (XsdElement element : allElements) {
545             XsdElement elementValue = resolveElement(element);
546             CppType cppType = parseType(elementValue.getType(), elementValue.getName());
547             allElementTypes.add(cppType);
548         }
549         List<CppSimpleType> allAttributeTypes = new ArrayList<>();
550         for (XsdAttribute attribute : allAttributes) {
551             XsdType type = resolveAttribute(attribute).getType();
552             allAttributeTypes.add(parseSimpleType(type, false));
553         }
554 
555         String fullName = nameScope + name;
556         parserHeaderFile.printf("void write(std::ostream& out, const std::string& name) const;\n");
557         parserCppFile.printf(
558                 "\nvoid %s::write(std::ostream& out, const std::string& name) const {\n",
559                 fullName);
560 
561         parserCppFile.printf("out << printIndent() << \"<\" << name;\n");
562         for (int i = 0; i < allAttributes.size(); ++i) {
563             CppType type = allAttributeTypes.get(i);
564             XsdAttribute attribute = resolveAttribute(allAttributes.get(i));
565             String variableName = Utils.toVariableName(attribute.getName());
566             parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName));
567             parserCppFile.printf("out << \" %s=\\\"\";\n", attribute.getName());
568             parserCppFile.print(type.getWritingExpression(String.format("%s%s()",
569                     getterName(type.getName()), Utils.capitalize(variableName)),
570                     attribute.getName()));
571             parserCppFile.printf("out << \"\\\"\";\n}\n");
572         }
573         parserCppFile.print("out << \">\" << std::endl;\n");
574         parserCppFile.print("++indentIndex;\n");
575 
576         if (!allElements.isEmpty()) {
577             for (int i = 0; i < allElements.size(); ++i) {
578                 CppType type = allElementTypes.get(i);
579                 XsdElement element = allElements.get(i);
580                 XsdElement elementValue = resolveElement(element);
581                 String elementName = getElementName(elementValue);
582                 String variableName = Utils.toVariableName(elementName);
583 
584                 if (type instanceof CppComplexType || element.isMultiple()) {
585                     parserCppFile.printf("for (auto& value : get%s()) {\n",
586                             Utils.capitalize(variableName));
587                     if (type instanceof CppSimpleType) {
588                         parserCppFile.printf("out << printIndent() << \"<%s>\";\n",
589                                 elementValue.getName());
590                     }
591                     parserCppFile.printf(
592                             type.getWritingExpression("value", elementValue.getName()));
593                     if (type instanceof CppSimpleType) {
594                         parserCppFile.printf("out << \"</%s>\" << std::endl;\n",
595                                 elementValue.getName());
596                     }
597                     parserCppFile.printf("}\n");
598                 } else {
599                     parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName));
600                     if (type instanceof CppSimpleType) {
601                         parserCppFile.printf("out << printIndent() << \"<%s>\";\n",
602                                 elementValue.getName());
603                     }
604                     parserCppFile.print(type.getWritingExpression(String.format("%s%s()",
605                               getterName(type.getName()), Utils.capitalize(variableName)),
606                               elementValue.getName()));
607                     if (type instanceof CppSimpleType) {
608                         parserCppFile.printf("out << \"</%s>\" << std::endl;\n",
609                                 elementValue.getName());
610                     }
611                     parserCppFile.print("}\n");
612                 }
613             }
614         }
615         parserCppFile.print("--indentIndex;\n");
616         parserCppFile.printf("out << printIndent() << \"</\" << name << \">\" << std::endl;\n");
617         parserCppFile.printf("}\n");
618     }
619 
printGetter(String name, CppType type, String variableName, boolean isMultiple, boolean isMultipleType, boolean isRequired)620     private void printGetter(String name, CppType type, String variableName,
621             boolean isMultiple, boolean isMultipleType, boolean isRequired) {
622         String typeName = isMultiple ? String.format("std::vector<%s>",
623                 type.getName()) : type.getName();
624 
625         parserHeaderFile.printf("const %s& %s%s() const;\n", typeName, getterName(typeName),
626                 Utils.capitalize(variableName));
627 
628         parserCppFile.println();
629         parserCppFile.printf("const %s& %s::%s%s() const {\n"
630                 + "return %s;\n}\n\n",
631                 typeName, name, getterName(typeName), Utils.capitalize(variableName),
632                 isMultiple || isRequired ?
633                 variableName + "_" : String.format("%s_.value()", variableName));
634 
635         parserHeaderFile.printf("bool has%s() const;\n", Utils.capitalize(variableName));
636         parserCppFile.printf("bool %s::has%s() const {\n", name, Utils.capitalize(variableName));
637         if (isMultiple) {
638             parserCppFile.printf("return !(%s_.empty());\n}\n", variableName);
639         } else if (isRequired){
640             parserCppFile.print("return true;\n}\n");
641         } else {
642             parserCppFile.printf("return %s_.has_value();\n}\n", variableName);
643         }
644 
645         if (isMultiple || isMultipleType) {
646             String elementTypeName = type instanceof CppComplexType ? type.getName() :
647                     ((CppSimpleType)type).getTypeName();
648             if (elementTypeName.equals("bool")) {
649                 parserHeaderFile.printf("%s getFirst%s() const;\n",
650                         elementTypeName, Utils.capitalize(variableName));
651                 parserCppFile.println();
652                 parserCppFile.printf("%s %s::getFirst%s() const {\n"
653                         + "if (%s_%sempty()) {\n"
654                         + "return false;\n"
655                         + "}\n"
656                         + "return %s;\n"
657                         + "}\n",
658                         elementTypeName, name, Utils.capitalize(variableName), variableName,
659                         isMultiple ? "." : "->",
660                         isMultiple ? String.format("%s_[0]", variableName) :
661                         String.format("%s_.value()[0]", variableName));
662             } else {
663                 parserHeaderFile.printf("const %s* getFirst%s() const;\n",
664                         elementTypeName, Utils.capitalize(variableName));
665                 parserCppFile.println();
666                 parserCppFile.printf("const %s* %s::getFirst%s() const {\n"
667                         + "if (%s_%sempty()) {\n"
668                         + "return nullptr;\n"
669                         + "}\n"
670                         + "return &%s;\n"
671                         + "}\n",
672                         elementTypeName, name, Utils.capitalize(variableName), variableName,
673                         isMultiple ? "." : "->",
674                         isMultiple ? String.format("%s_[0]", variableName) :
675                         String.format("%s_.value()[0]", variableName));
676             }
677         }
678     }
679 
printConstructor(String name, String nameScope, XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes, String baseName)680     private String printConstructor(String name, String nameScope, XsdComplexType complexType,
681             List<XsdElement> elements, List<XsdAttribute> attributes, String baseName)
682             throws CppCodeGeneratorException {
683         String fullName = nameScope + name;
684         StringBuilder constructorArgs = new StringBuilder();
685         StringBuilder parentArgs = new StringBuilder();
686         StringBuilder constructor = new StringBuilder();
687         StringBuilder args = new StringBuilder();
688 
689         List<XsdElement> allElements = new ArrayList<>();
690         List<XsdAttribute> allAttributes = new ArrayList<>();
691         stackComponents(complexType, allElements, allAttributes);
692 
693         List<CppType> allElementTypes = new ArrayList<>();
694         for (XsdElement element : allElements) {
695             XsdElement elementValue = resolveElement(element);
696             CppType type = parseType(elementValue.getType(), elementValue.getName());
697             String variableName = Utils.toVariableName(getElementName(elementValue));
698             constructorArgs.append(String.format(", %s %s", Utils.elementTypeName(type.getName(),
699                     element.isMultiple() || type instanceof CppComplexType), variableName));
700             args.append(String.format(", %s", variableName));
701             boolean isMultipleType;
702             if (type instanceof CppComplexType) {
703                 isMultipleType = true;
704             } else if (((CppSimpleType)type).isList()) {
705                 isMultipleType = true;
706             } else {
707                 isMultipleType = false;
708             }
709 
710             if (elements.contains(element)) {
711                 constructor.append(String.format(", %s_(%s)", variableName,
712                         Utils.toAssignmentName(type.getName(), variableName, isMultipleType)));
713             } else {
714                 parentArgs.append(String.format(", %s", variableName));
715             }
716         }
717         List<CppSimpleType> allAttributeTypes = new ArrayList<>();
718         for (XsdAttribute attribute : allAttributes) {
719             CppType type = parseSimpleType(resolveAttribute(attribute).getType(), false);
720             String variableName = Utils.toVariableName(resolveAttribute(attribute).getName());
721             if (attribute.isRequired()) {
722                 constructorArgs.append(String.format(", %s %s", type.getName(), variableName));
723             } else {
724                 constructorArgs.append(String.format(", std::optional<%s> %s", type.getName(),
725                         variableName));
726             }
727             args.append(String.format(", %s", variableName));
728             boolean isMultipleType = ((CppSimpleType)type).isList() ? true : false;
729             if (attributes.contains(attribute)) {
730                 constructor.append(String.format(", %s_(%s)", variableName,
731                         Utils.toAssignmentName(type.getName(), variableName, isMultipleType)));
732             } else {
733                 parentArgs.append(String.format(", %s", variableName));
734             }
735         }
736 
737         String constructorArgsString = constructorArgs.toString();
738         String constructorString = constructor.toString();
739         if (constructorArgsString.length() > 0) {
740             constructorArgsString = constructorArgsString.substring(2);
741         }
742 
743         boolean useExplicit =
744                 !(constructorArgsString.isEmpty() || constructorArgsString.contains(","));
745         if (useExplicit) {
746             parserHeaderFile.printf("explicit %s(%s);\n", name, constructorArgsString);
747         } else {
748             parserHeaderFile.printf("%s(%s);\n", name, constructorArgsString);
749         }
750         parserCppFile.printf("\n%s::%s(%s) : ", fullName, name, constructorArgsString);
751 
752         String parentArgsString = parentArgs.toString();
753         if (parentArgsString.length() > 0) {
754             parentArgsString = parentArgsString.substring(2);
755             parserCppFile.printf("%s(%s)", baseName, parentArgsString);
756         } else {
757             constructorString = constructorString.substring(2);
758         }
759         parserCppFile.printf("%s {\n}\n", constructorString);
760 
761         String argsString = args.toString();
762         if (argsString.length() > 0) {
763             argsString = argsString.substring(2);
764         }
765         return argsString;
766     }
767 
printXmlParser()768     private void printXmlParser() throws CppCodeGeneratorException {
769         parserCppFile.printf("template <class T>\n"
770                 + "constexpr void (*xmlDeleter)(T* t);\n"
771                 + "template <>\nconstexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;\n"
772                 + "template <>\nauto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };\n\n"
773                 + "template <class T>\n"
774                 + "constexpr auto make_xmlUnique(T *t) {\n"
775                 + "auto deleter = [](T *t) { xmlDeleter<T>(t); };\n"
776                 + "return std::unique_ptr<T, decltype(deleter)>{t, deleter};\n"
777                 + "}\n\n");
778 
779         if (hasAttr) {
780             parserCppFile.printf("static std::string getXmlAttribute"
781                     + "(const xmlNode *cur, const char *attribute) {\n"
782                     + "auto xmlValue = make_xmlUnique(xmlGetProp(cur, "
783                     + "reinterpret_cast<const xmlChar*>(attribute)));\n"
784                     + "if (xmlValue == nullptr) {\n"
785                     + "return \"\";\n"
786                     + "}\n"
787                     + "std::string value(reinterpret_cast<const char*>(xmlValue.get()));\n"
788                     + "return value;\n"
789                     + "}\n\n");
790         }
791 
792         String className = Utils.toClassName(pkgName);
793 
794         boolean isMultiRootElement = xmlSchema.getElementMap().values().size() > 1;
795         for (XsdElement element : xmlSchema.getElementMap().values()) {
796             CppType cppType = parseType(element.getType(), element.getName());
797             String elementName = element.getName();
798             String VariableName = Utils.toVariableName(elementName);
799             String typeName = cppType instanceof CppSimpleType ? cppType.getName() :
800                     Utils.toClassName(cppType.getName());
801 
802             parserHeaderFile.printf("std::optional<%s> read%s(const char* configFile);\n\n",
803                     typeName, isMultiRootElement ? Utils.capitalize(typeName) : "");
804             parserCppFile.printf("std::optional<%s> read%s(const char* configFile) {\n",
805                     typeName, isMultiRootElement ? Utils.capitalize(typeName) : "");
806             parserCppFile.printf("auto doc = make_xmlUnique(xmlParseFile(configFile));\n"
807                     + "if (doc == nullptr) {\n"
808                     + "return std::nullopt;\n"
809                     + "}\n"
810                     + "xmlNodePtr child = xmlDocGetRootElement(doc.get());\n"
811                     + "if (child == nullptr) {\n"
812                     + "return std::nullopt;\n"
813                     + "}\n"
814                     + "if (xmlXIncludeProcess(doc.get()) < 0) {\n"
815                     + "return std::nullopt;\n"
816                     + "}\n\n"
817                     + "if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>"
818                     + "(\"%s\"))) {\n",
819                     elementName);
820 
821             if (cppType instanceof CppSimpleType) {
822                 parserCppFile.printf("%s value = getXmlAttribute(child, \"%s\");\n",
823                         elementName, elementName);
824             } else {
825                 parserCppFile.printf(cppType.getParsingExpression());
826             }
827             parserCppFile.printf("return value;\n}\n");
828             parserCppFile.printf("return std::nullopt;\n");
829             parserCppFile.printf("}\n\n");
830         }
831     }
832 
printXmlWriter()833     private void printXmlWriter() throws CppCodeGeneratorException {
834         for (XsdElement element : xmlSchema.getElementMap().values()) {
835             CppType cppType = parseType(element.getType(), element.getName());
836             String elementName = element.getName();
837             String VariableName = Utils.toVariableName(elementName);
838             String typeName = cppType instanceof CppSimpleType ? cppType.getName() :
839                     Utils.toClassName(cppType.getName());
840             parserHeaderFile.printf("void write(std::ostream& out, %s& %s);\n\n",
841                     typeName, VariableName);
842             parserCppFile.printf("void write(std::ostream& out, %s& %s) {\n",
843                     typeName, VariableName);
844 
845             parserCppFile.print(
846                     "out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n");
847             parserCppFile.printf("%s.write(out, \"%s\");\n", VariableName, elementName);
848             parserCppFile.printf("}\n\n");
849         }
850 
851         parserCppFile.print("static int indentIndex = 0;\n"
852                 + "std::string printIndent() {\n"
853                 + "std::string s = \"\";\n"
854                 + "for (int index = 0; index < indentIndex; ++index) {\n"
855                 + "s += \"    \";\n"
856                 + "}\nreturn s;\n}\n\n");
857     }
858 
getElementName(XsdElement element)859     private String getElementName(XsdElement element) {
860         if (element instanceof XsdChoice) {
861             return element.getName() + "_optional";
862         } else if (element instanceof XsdAll) {
863             return element.getName() + "_all";
864         }
865         return element.getName();
866     }
867 
getterName(String type)868     private String getterName(String type) {
869         if (type.equals("bool") && booleanGetter) {
870             return "is";
871         }
872         return "get";
873     }
874 
stackComponents(XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes)875     private void stackComponents(XsdComplexType complexType, List<XsdElement> elements,
876             List<XsdAttribute> attributes) throws CppCodeGeneratorException {
877         if (complexType.getBase() != null) {
878             QName baseRef = complexType.getBase().getRef();
879             if (baseRef != null && !baseRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) {
880                 XsdType parent = getType(baseRef.getLocalPart());
881                 if (parent instanceof XsdComplexType) {
882                     stackComponents((XsdComplexType) parent, elements, attributes);
883                 }
884             }
885         }
886         elements.addAll(getAllElements(complexType.getGroup()));
887         elements.addAll(complexType.getElements());
888         for (XsdAttributeGroup attributeGroup : complexType.getAttributeGroups()) {
889             attributes.addAll(getAllAttributes(resolveAttributeGroup(attributeGroup)));
890         }
891         attributes.addAll(complexType.getAttributes());
892     }
893 
getAllAttributes(XsdAttributeGroup attributeGroup)894     private List<XsdAttribute> getAllAttributes(XsdAttributeGroup attributeGroup)
895             throws CppCodeGeneratorException{
896         List<XsdAttribute> attributes = new ArrayList<>();
897         for (XsdAttributeGroup attrGroup : attributeGroup.getAttributeGroups()) {
898             attributes.addAll(getAllAttributes(resolveAttributeGroup(attrGroup)));
899         }
900         attributes.addAll(attributeGroup.getAttributes());
901         return attributes;
902     }
903 
getAllElements(XsdGroup group)904     private List<XsdElement> getAllElements(XsdGroup group) throws CppCodeGeneratorException {
905         List<XsdElement> elements = new ArrayList<>();
906         if (group == null) {
907             return elements;
908         }
909         elements.addAll(getAllElements(resolveGroup(group)));
910         elements.addAll(group.getElements());
911         return elements;
912     }
913 
914 
getBaseName(XsdComplexType complexType)915     private String getBaseName(XsdComplexType complexType) throws CppCodeGeneratorException {
916         if (complexType.getBase() == null) return null;
917         if (complexType.getBase().getRef().getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) {
918             return null;
919         }
920         XsdType base = getType(complexType.getBase().getRef().getLocalPart());
921         if (base instanceof XsdComplexType) {
922             return Utils.toClassName(base.getName());
923         }
924         return null;
925     }
926 
getValueType(XsdSimpleContent simpleContent, boolean traverse)927     private CppSimpleType getValueType(XsdSimpleContent simpleContent, boolean traverse)
928             throws CppCodeGeneratorException {
929         assert simpleContent.getBase() != null;
930         QName baseRef = simpleContent.getBase().getRef();
931         assert baseRef != null;
932         if (baseRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) {
933             return predefinedType(baseRef.getLocalPart());
934         } else {
935             XsdType parent = getType(baseRef.getLocalPart());
936             if (parent instanceof XsdSimpleType) {
937                 return parseSimpleTypeReference(baseRef, false);
938             }
939             if (!traverse) return null;
940             if (parent instanceof XsdSimpleContent) {
941                 return getValueType((XsdSimpleContent) parent, true);
942             } else {
943                 throw new CppCodeGeneratorException(
944                         String.format("base not simple : %s", baseRef.getLocalPart()));
945             }
946         }
947     }
948 
parseType(XsdType type, String defaultName)949     private CppType parseType(XsdType type, String defaultName) throws CppCodeGeneratorException {
950         if (type.getRef() != null) {
951             String name = type.getRef().getLocalPart();
952             if (type.getRef().getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) {
953                 return predefinedType(name);
954             } else {
955                 XsdType typeValue = getType(name);
956                 if (typeValue instanceof XsdSimpleType) {
957                     return parseSimpleTypeReference(type.getRef(), false);
958                 }
959                 return parseType(typeValue, name);
960             }
961         }
962         if (type instanceof XsdComplexType) {
963             return new CppComplexType(Utils.toClassName(defaultName));
964         } else if (type instanceof XsdSimpleType) {
965             return parseSimpleTypeValue((XsdSimpleType) type, false);
966         } else {
967             throw new CppCodeGeneratorException(
968                     String.format("unknown type name : %s", defaultName));
969         }
970     }
971 
parseSimpleType(XsdType type, boolean traverse)972     private CppSimpleType parseSimpleType(XsdType type, boolean traverse)
973             throws CppCodeGeneratorException {
974         if (type.getRef() != null) {
975             return parseSimpleTypeReference(type.getRef(), traverse);
976         } else {
977             return parseSimpleTypeValue((XsdSimpleType) type, traverse);
978         }
979     }
980 
parseSimpleTypeReference(QName typeRef, boolean traverse)981     private CppSimpleType parseSimpleTypeReference(QName typeRef, boolean traverse)
982             throws CppCodeGeneratorException {
983         assert typeRef != null;
984         String typeName = typeRef.getLocalPart();
985         if (typeRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) {
986             return predefinedType(typeName);
987         }
988         if (cppSimpleTypeMap.containsKey(typeName)) {
989             return cppSimpleTypeMap.get(typeName);
990         } else if (traverse) {
991             XsdSimpleType simpleType = getSimpleType(typeName);
992             CppSimpleType ret = parseSimpleTypeValue(simpleType, true);
993             cppSimpleTypeMap.put(typeName, ret);
994             return ret;
995         } else {
996             throw new CppCodeGeneratorException(String.format("unknown type name : %s", typeName));
997         }
998     }
999 
parseSimpleTypeValue(XsdSimpleType simpleType, boolean traverse)1000     private CppSimpleType parseSimpleTypeValue(XsdSimpleType simpleType, boolean traverse)
1001             throws CppCodeGeneratorException {
1002         if (simpleType instanceof XsdList) {
1003             XsdList list = (XsdList) simpleType;
1004             return parseSimpleType(list.getItemType(), traverse).newListType();
1005         } else if (simpleType instanceof XsdRestriction) {
1006             // we don't consider any restrictions.
1007             XsdRestriction restriction = (XsdRestriction) simpleType;
1008             if (restriction.getEnums() != null) {
1009                 String name = Utils.toClassName(restriction.getName());
1010                 return new CppSimpleType(name, "stringTo" + name + "(%s)", false, true);
1011             }
1012             return parseSimpleType(restriction.getBase(), traverse);
1013         } else if (simpleType instanceof XsdUnion) {
1014             // unions are almost always interpreted as java.lang.String
1015             // Exceptionally, if any of member types of union are 'list', then we interpret it as
1016             // List<String>
1017             XsdUnion union = (XsdUnion) simpleType;
1018             for (XsdType memberType : union.getMemberTypes()) {
1019                 if (parseSimpleType(memberType, traverse).isList()) {
1020                     return new CppSimpleType("std::string", "%s", true);
1021                 }
1022             }
1023             return new CppSimpleType("std::string", "%s", false);
1024         } else {
1025             // unreachable
1026             throw new IllegalStateException("unknown simple type");
1027         }
1028     }
1029 
resolveElement(XsdElement element)1030     private XsdElement resolveElement(XsdElement element) throws CppCodeGeneratorException {
1031         if (element.getRef() == null) return element;
1032         String name = element.getRef().getLocalPart();
1033         XsdElement ret = xmlSchema.getElementMap().get(name);
1034         if (ret != null) return ret;
1035         throw new CppCodeGeneratorException(String.format("no element named : %s", name));
1036     }
1037 
resolveGroup(XsdGroup group)1038     private XsdGroup resolveGroup(XsdGroup group) throws CppCodeGeneratorException {
1039         if (group.getRef() == null) return null;
1040         String name = group.getRef().getLocalPart();
1041         XsdGroup ret = xmlSchema.getGroupMap().get(name);
1042         if (ret != null) return ret;
1043         throw new CppCodeGeneratorException(String.format("no group named : %s", name));
1044     }
1045 
resolveAttribute(XsdAttribute attribute)1046     private XsdAttribute resolveAttribute(XsdAttribute attribute)
1047             throws CppCodeGeneratorException {
1048         if (attribute.getRef() == null) return attribute;
1049         String name = attribute.getRef().getLocalPart();
1050         XsdAttribute ret = xmlSchema.getAttributeMap().get(name);
1051         if (ret != null) return ret;
1052         throw new CppCodeGeneratorException(String.format("no attribute named : %s", name));
1053     }
1054 
resolveAttributeGroup(XsdAttributeGroup attributeGroup)1055     private XsdAttributeGroup resolveAttributeGroup(XsdAttributeGroup attributeGroup)
1056             throws CppCodeGeneratorException {
1057         if (attributeGroup.getRef() == null) return attributeGroup;
1058         String name = attributeGroup.getRef().getLocalPart();
1059         XsdAttributeGroup ret = xmlSchema.getAttributeGroupMap().get(name);
1060         if (ret != null) return ret;
1061         throw new CppCodeGeneratorException(String.format("no attribute group named : %s", name));
1062     }
1063 
getType(String name)1064     private XsdType getType(String name) throws CppCodeGeneratorException {
1065         XsdType type = xmlSchema.getTypeMap().get(name);
1066         if (type != null) return type;
1067         throw new CppCodeGeneratorException(String.format("no type named : %s", name));
1068     }
1069 
getSimpleType(String name)1070     private XsdSimpleType getSimpleType(String name) throws CppCodeGeneratorException {
1071         XsdType type = getType(name);
1072         if (type instanceof XsdSimpleType) return (XsdSimpleType) type;
1073         throw new CppCodeGeneratorException(String.format("not a simple type : %s", name));
1074     }
1075 
hasAttribute(XsdComplexType complexType)1076     private boolean hasAttribute(XsdComplexType complexType) throws CppCodeGeneratorException {
1077         if (complexType.getAttributes().size() > 0 ||
1078                 complexType.getAttributeGroups().size() > 0) {
1079             return true;
1080         }
1081         boolean results = false;
1082         for (XsdElement element : complexType.getElements()) {
1083             XsdElement elementValue = resolveElement(element);
1084             if (element.getRef() == null && element.getType().getRef() == null
1085                     && element.getType() instanceof XsdComplexType) {
1086                 results = hasAttribute((XsdComplexType) element.getType());
1087                 if (results) {
1088                     return results;
1089                 }
1090             }
1091         }
1092         return results;
1093     }
1094 
predefinedType(String name)1095     private static CppSimpleType predefinedType(String name) throws CppCodeGeneratorException {
1096         switch (name) {
1097             case "string":
1098             case "token":
1099             case "normalizedString":
1100             case "language":
1101             case "ENTITY":
1102             case "ID":
1103             case "Name":
1104             case "NCName":
1105             case "NMTOKEN":
1106             case "anyURI":
1107             case "anyType":
1108             case "QName":
1109             case "NOTATION":
1110             case "IDREF":
1111                 return new CppSimpleType("std::string", "%s", false);
1112             case "ENTITIES":
1113             case "NMTOKENS":
1114             case "IDREFS":
1115                 return new CppSimpleType("std::string", "%s", true);
1116             case "date":
1117             case "dateTime":
1118             case "time":
1119             case "gDay":
1120             case "gMonth":
1121             case "gYear":
1122             case "gMonthDay":
1123             case "gYearMonth":
1124             case "duration":
1125                 return new CppSimpleType("std::string", "%s", false);
1126             case "decimal":
1127                 return new CppSimpleType("double", "std::stod(%s)", false);
1128             case "integer":
1129             case "negativeInteger":
1130             case "nonNegativeInteger":
1131             case "positiveInteger":
1132             case "nonPositiveInteger":
1133                 return new CppSimpleType("int64_t", "std::stoll(%s)", false);
1134             case "unsignedLong":
1135                 return new CppSimpleType("uint64_t", "std::stoull(%s)", false);
1136             case "long":
1137                 return new CppSimpleType("int64_t", "std::stoll(%s)", false);
1138             case "unsignedInt":
1139                 return new CppSimpleType("unsigned int",
1140                         "static_cast<unsigned int>(stoul(%s))", false);
1141             case "int":
1142                 return new CppSimpleType("int", "std::stoi(%s)", false);
1143             case "unsignedShort":
1144                 return new CppSimpleType("unsigned short",
1145                         "static_cast<unsigned short>(std::stoi(%s))", false);
1146             case "short":
1147                 return new CppSimpleType("short", "static_cast<short>(std::stoi(%s))", false);
1148             case "unsignedByte":
1149                 return new CppSimpleType("unsigned char",
1150                         "static_cast<unsigned char>(std::stoi(%s))", false);
1151             case "byte":
1152                 return new CppSimpleType("char", "static_cast<char>(std::stoi(%s))", false);
1153             case "boolean":
1154                 return new CppSimpleType("bool", "%s == \"true\"", false);
1155             case "double":
1156                 return new CppSimpleType("double", "std::stod(%s)", false);
1157             case "float":
1158                 return new CppSimpleType("float", "std::stof(%s)", false);
1159             case "base64Binary":
1160             case "hexBinary":
1161                 return new CppSimpleType("std::string", "%s", false);
1162         }
1163         throw new CppCodeGeneratorException("unknown xsd predefined type : " + name);
1164     }
1165 }
1166