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.Arrays; 27 import java.util.ArrayList; 28 import java.util.Collection; 29 import java.util.Collections; 30 import java.util.HashMap; 31 import java.util.HashSet; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Set; 35 36 import javax.xml.namespace.QName; 37 38 public class CppCodeGenerator { 39 public static final int GENERATE_ENUMS = 1 << 0; 40 public static final int GENERATE_PARSER = 1 << 1; 41 42 private XmlSchema xmlSchema; 43 private String pkgName; 44 private Map<String, CppSimpleType> cppSimpleTypeMap; 45 private CodeWriter enumsCppFile; 46 private CodeWriter enumsHeaderFile; 47 private CodeWriter parserCppFile; 48 private CodeWriter parserHeaderFile; 49 private boolean hasAttr; 50 private boolean writer; 51 private int generators; 52 private boolean booleanGetter; 53 private boolean useTinyXml; 54 private String[] rootElements; 55 56 private static final String UNKNOWN_ENUM = "UNKNOWN"; 57 CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer, int generators, boolean booleanGetter, boolean useTinyXml, String[] rootElements)58 public CppCodeGenerator(XmlSchema xmlSchema, String pkgName, boolean writer, int generators, 59 boolean booleanGetter, boolean useTinyXml, String[] rootElements) 60 throws CppCodeGeneratorException { 61 this.xmlSchema = xmlSchema; 62 this.pkgName = pkgName; 63 this.writer = writer; 64 this.generators = generators; 65 this.booleanGetter = booleanGetter; 66 this.useTinyXml = useTinyXml; 67 this.rootElements = rootElements; 68 69 // class naming validation 70 { 71 Set<String> nameSet = new HashSet<>(); 72 nameSet.add("XmlParser"); 73 for (XsdType type : xmlSchema.getTypeMap().values()) { 74 if ((type instanceof XsdComplexType) || (type instanceof XsdRestriction && 75 ((XsdRestriction)type).getEnums() != null)) { 76 String name = Utils.toClassName(type.getName()); 77 if (nameSet.contains(name)) { 78 throw new CppCodeGeneratorException( 79 String.format("duplicate class name : %s", name)); 80 } 81 nameSet.add(name); 82 if (type instanceof XsdComplexType && !hasAttr) { 83 hasAttr = hasAttribute((XsdComplexType)type); 84 } 85 } 86 } 87 for (XsdElement element : xmlSchema.getElementMap().values()) { 88 XsdType type = element.getType(); 89 if (type.getRef() == null && type instanceof XsdComplexType) { 90 String name = Utils.toClassName(element.getName()); 91 if (nameSet.contains(name)) { 92 throw new CppCodeGeneratorException( 93 String.format("duplicate class name : %s", name)); 94 } 95 nameSet.add(name); 96 if (!hasAttr) { 97 hasAttr = hasAttribute((XsdComplexType)type); 98 } 99 } 100 } 101 } 102 103 cppSimpleTypeMap = new HashMap<>(); 104 for (XsdType type : xmlSchema.getTypeMap().values()) { 105 if (type instanceof XsdSimpleType) { 106 XsdType refType = new XsdType(null, new QName(type.getName())); 107 parseSimpleType(refType, true); 108 } 109 } 110 } 111 print(FileSystem fs)112 public void print(FileSystem fs) 113 throws CppCodeGeneratorException, IOException { 114 // cpp file, header file init 115 String fileNameStem = pkgName.replace('.', '_'); 116 String enumsCppFileName = fileNameStem + "_enums.cpp"; 117 String enumsHeaderFileName = fileNameStem + "_enums.h"; 118 String parserCppFileName = fileNameStem + ".cpp"; 119 String parserHeaderFileName = fileNameStem + ".h"; 120 if ((this.generators & GENERATE_ENUMS) == GENERATE_ENUMS) { 121 enumsCppFile = new CodeWriter(fs.getPrintWriter(enumsCppFileName)); 122 enumsHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + enumsHeaderFileName)); 123 } else { 124 enumsCppFile = new CodeWriter(); 125 enumsHeaderFile = new CodeWriter(); 126 } 127 if ((this.generators & GENERATE_PARSER) == GENERATE_PARSER) { 128 parserCppFile = new CodeWriter(fs.getPrintWriter(parserCppFileName)); 129 parserHeaderFile = new CodeWriter(fs.getPrintWriter("include/" + parserHeaderFileName)); 130 } else { 131 parserCppFile = new CodeWriter(); 132 parserHeaderFile = new CodeWriter(); 133 } 134 135 boolean hasEnums = false; 136 for (XsdType type : xmlSchema.getTypeMap().values()) { 137 if (type instanceof XsdRestriction && 138 ((XsdRestriction)type).getEnums() != null) { 139 hasEnums = true; 140 break; 141 } 142 } 143 144 String enumsHeaderMacro = enumsHeaderFileName.toUpperCase().replace('.', '_'); 145 String parserHeaderMacro = parserHeaderFileName.toUpperCase().replace('.', '_'); 146 enumsHeaderFile.printf("#ifndef %s\n", enumsHeaderMacro); 147 enumsHeaderFile.printf("#define %s\n", enumsHeaderMacro); 148 enumsHeaderFile.printf("\n"); 149 enumsHeaderFile.printf("#include <array>\n"); 150 enumsHeaderFile.printf("#include <string>\n"); 151 enumsHeaderFile.printf("\n"); 152 parserHeaderFile.printf("#ifndef %s\n", parserHeaderMacro); 153 parserHeaderFile.printf("#define %s\n", parserHeaderMacro); 154 parserHeaderFile.printf("\n"); 155 parserHeaderFile.printf("#include <array>\n"); 156 parserHeaderFile.printf("#include <map>\n"); 157 parserHeaderFile.printf("#include <optional>\n"); 158 parserHeaderFile.printf("#include <string>\n"); 159 parserHeaderFile.printf("#include <vector>\n"); 160 parserHeaderFile.printf("#include <sstream>\n"); 161 if (writer) { 162 parserHeaderFile.printf("#include <iostream>\n"); 163 } 164 parserHeaderFile.printf("\n"); 165 if (useTinyXml) { 166 printGuardedIncludes("libtinyxml2", "tinyxml2.h"); 167 } else { 168 printGuardedIncludes("libxml2", "libxml/parser.h", 169 Arrays.asList("libxml/xinclude.h")); 170 } 171 if (hasEnums) { 172 enumsHeaderFile.printf("#include <xsdc/XsdcSupport.h>\n"); 173 enumsHeaderFile.printf("\n"); 174 } 175 parserHeaderFile.printf("\n"); 176 parserHeaderFile.printf("#include \"%s\"\n", enumsHeaderFileName); 177 parserHeaderFile.printf("\n"); 178 179 enumsCppFile.printf("#include <map>\n"); 180 enumsCppFile.printf("\n"); 181 enumsCppFile.printf("#include \"%s\"\n\n", enumsHeaderFileName); 182 parserCppFile.printf("#define LOG_TAG \"%s\"\n", pkgName); 183 parserCppFile.printf("#include \"%s\"\n\n", parserHeaderFileName); 184 // define _xsdc_assert to abort with message regardless of NDEBUG 185 parserCppFile.println("#include <assert.h>\n" 186 + "#ifndef __BIONIC__\n" 187 + "#define __assert2(f,n,fun,e) do { fprintf(stderr, \"%s:%d: %s: Assertion `%s'" 188 + " failed\", (f), (n), (fun), (e)); abort(); } while (false)\n" 189 + "#endif\n" 190 + "#define _xsdc_assert(e) do if (!(e)) __assert2(__FILE__, __LINE__," 191 + " __PRETTY_FUNCTION__, #e); while (false)\n"); 192 193 List<String> namespace = new java.util.ArrayList<>(); 194 for (String token : pkgName.split("\\.")) { 195 if (token.isEmpty()) { 196 continue; 197 } 198 if (Character.isDigit(token.charAt(0))) { 199 token = "_" + token; 200 } 201 namespace.add(token); 202 enumsHeaderFile.printf("namespace %s {\n", token); 203 enumsCppFile.printf("namespace %s {\n", token); 204 parserHeaderFile.printf("namespace %s {\n", token); 205 parserCppFile.printf("namespace %s {\n", token); 206 } 207 208 printPrototype(); 209 printXmlParser(); 210 if (writer) { 211 printXmlWriter(); 212 } 213 214 for (XsdType type : xmlSchema.getTypeMap().values()) { 215 if (type instanceof XsdRestriction && 216 ((XsdRestriction)type).getEnums() != null) { 217 String name = Utils.toClassName(type.getName()); 218 XsdRestriction restrictionType = (XsdRestriction) type; 219 printEnum(name, restrictionType); 220 } 221 } 222 for (XsdType type : xmlSchema.getTypeMap().values()) { 223 if (type instanceof XsdComplexType) { 224 String name = Utils.toClassName(type.getName()); 225 XsdComplexType complexType = (XsdComplexType) type; 226 printClass(name, "", complexType); 227 } 228 } 229 for (XsdElement element : xmlSchema.getElementMap().values()) { 230 XsdType type = element.getType(); 231 if (type.getRef() == null && type instanceof XsdComplexType) { 232 String name = Utils.toClassName(element.getName()); 233 XsdComplexType complexType = (XsdComplexType) type; 234 printClass(name, "", complexType); 235 } 236 } 237 238 Collections.reverse(namespace); 239 for (String token : namespace) { 240 enumsHeaderFile.printf("} // %s\n", token); 241 enumsCppFile.printf("} // %s\n", token); 242 parserHeaderFile.printf("} // %s\n", token); 243 parserCppFile.printf("} // %s\n", token); 244 } 245 246 if (hasEnums) { 247 enumsHeaderFile.printf("\n//\n// global type declarations for package\n//\n\n"); 248 enumsHeaderFile.printf("namespace android {\nnamespace details {\n"); 249 Collections.reverse(namespace); 250 for (XsdType type : xmlSchema.getTypeMap().values()) { 251 if (type instanceof XsdRestriction && 252 ((XsdRestriction)type).getEnums() != null) { 253 String name = Utils.toClassName(type.getName()); 254 XsdRestriction restrictionType = (XsdRestriction) type; 255 printEnumValues(namespace, name, restrictionType); 256 } 257 } 258 enumsHeaderFile.printf("} // namespace details\n} // namespace android\n\n"); 259 } 260 261 parserHeaderFile.printf("#endif // %s\n", parserHeaderMacro); 262 enumsHeaderFile.printf("#endif // %s\n", enumsHeaderMacro); 263 parserCppFile.close(); 264 parserHeaderFile.close(); 265 enumsCppFile.close(); 266 enumsHeaderFile.close(); 267 } 268 printGuardedIncludes(String libName, String mainHeader)269 private void printGuardedIncludes(String libName, String mainHeader) { 270 printGuardedIncludes(libName, mainHeader, Collections.emptyList()); 271 } 272 printGuardedIncludes(String libName, String mainHeader, Collection<String> additionalHeaders)273 private void printGuardedIncludes(String libName, String mainHeader, 274 Collection<String> additionalHeaders) { 275 parserHeaderFile.printf("#if __has_include(<%s>)\n", mainHeader); 276 parserHeaderFile.printf("#include <%s>\n", mainHeader); 277 for (String header : additionalHeaders) { 278 parserHeaderFile.printf("#include <%s>\n", header); 279 } 280 parserHeaderFile.printf("#else\n"); 281 parserHeaderFile.printf("#error Require %s library. ", libName); 282 parserHeaderFile.printf("Please add %s to shared_libs or static_libs\n", libName); 283 parserHeaderFile.printf("#endif\n"); 284 } 285 printEnum(String name, XsdRestriction restrictionType)286 private void printEnum(String name, XsdRestriction restrictionType) 287 throws CppCodeGeneratorException { 288 enumsHeaderFile.printf("enum class %s {\n", name); 289 enumsCppFile.printf("const std::map<std::string, %s> %sString {\n", name, name); 290 List<XsdEnumeration> enums = restrictionType.getEnums(); 291 292 enumsHeaderFile.printf("%s = %d,\n", UNKNOWN_ENUM, -1); 293 for (XsdEnumeration tag : enums) { 294 String value = tag.getValue(); 295 enumsHeaderFile.printf("%s,\n", Utils.toEnumName(value)); 296 enumsCppFile.printf("{ \"%s\", %s::%s },\n", tag.getValue(), name, 297 Utils.toEnumName(value)); 298 } 299 enumsHeaderFile.printf("};\n"); 300 enumsCppFile.printf("};\n\n"); 301 302 enumsHeaderFile.printf("%s stringTo%s(const std::string& value);\n", 303 name, name); 304 enumsCppFile.printf("%s stringTo%s(const std::string& value) {\n" 305 + "auto enumValue = %sString.find(value);\n" 306 + "return enumValue != %sString.end() ? enumValue->second : %s::%s;\n" 307 + "}\n\n", name, name, name, name, name, UNKNOWN_ENUM); 308 309 enumsHeaderFile.printf("std::string toString(%s o);\n\n", name); 310 enumsCppFile.printf("std::string toString(%s o) {\n", name); 311 enumsCppFile.printf("switch (o) {\n"); 312 for (XsdEnumeration tag : enums) { 313 String value = tag.getValue(); 314 enumsCppFile.printf("case %s::%s: return \"%s\";\n", 315 name, Utils.toEnumName(value), tag.getValue()); 316 } 317 enumsCppFile.printf("default: return std::to_string(static_cast<int>(o));\n}\n"); 318 enumsCppFile.printf("}\n\n"); 319 } 320 printEnumValues(List<String> namespace, String name, XsdRestriction restrictionType)321 private void printEnumValues(List<String> namespace, String name, 322 XsdRestriction restrictionType) throws CppCodeGeneratorException { 323 List<XsdEnumeration> enums = restrictionType.getEnums(); 324 String absoluteNamespace = "::" + String.join("::", namespace); 325 enumsHeaderFile.printf("template<> inline constexpr std::array<%s::%s, %d> " 326 + "xsdc_enum_values<%s::%s> = {\n", 327 absoluteNamespace, name, enums.size(), absoluteNamespace, name); 328 for (XsdEnumeration tag : enums) { 329 String value = tag.getValue(); 330 enumsHeaderFile.printf("%s::%s::%s,\n", 331 absoluteNamespace, name, Utils.toEnumName(value)); 332 } 333 enumsHeaderFile.printf("};\n"); 334 } 335 336 /** 337 * Prints forward declarations for complex types. 338 * 339 * Foo.h: 340 * 341 * class Foo; 342 * 343 */ printPrototype()344 private void printPrototype() throws CppCodeGeneratorException { 345 for (XsdType type : xmlSchema.getTypeMap().values()) { 346 if (type instanceof XsdComplexType) { 347 String name = Utils.toClassName(type.getName()); 348 parserHeaderFile.printf("class %s;\n", name); 349 } 350 } 351 for (XsdElement element : xmlSchema.getElementMap().values()) { 352 XsdType type = element.getType(); 353 if (type.getRef() == null && type instanceof XsdComplexType) { 354 String name = Utils.toClassName(element.getName()); 355 parserHeaderFile.printf("class %s;\n", name); 356 } 357 } 358 } 359 360 /** 361 * Prints class definitions for complex types. 362 * 363 * Foo.h: 364 * 365 * class Foo { 366 * printClass(<inner types>) 367 * <members> 368 * const optional<> value_; 369 * args = printConstructor() 370 * printGetter(<members>) 371 * printParser( args ) 372 * printWriter() 373 * }; 374 * 375 */ printClass(String name, String nameScope, XsdComplexType complexType)376 private void printClass(String name, String nameScope, XsdComplexType complexType) 377 throws CppCodeGeneratorException { 378 assert name != null; 379 // need element, attribute name duplicate validation? 380 381 String baseName = getBaseName(complexType); 382 CppSimpleType valueType = (complexType instanceof XsdSimpleContent) ? 383 getValueType((XsdSimpleContent) complexType, false) : null; 384 385 parserHeaderFile.printf("class %s ", name); 386 387 if (baseName != null) { 388 parserHeaderFile.printf(": public %s {\n", baseName); 389 } else { 390 parserHeaderFile.println("{"); 391 } 392 393 // parse types for elements and attributes 394 List<CppType> elementTypes = new ArrayList<>(); 395 List<XsdElement> elements = new ArrayList<>(); 396 elements.addAll(getAllElements(complexType.getGroup())); 397 elements.addAll(complexType.getElements()); 398 399 for (XsdElement element : elements) { 400 CppType cppType; 401 XsdElement elementValue = resolveElement(element); 402 if (element.getRef() == null && element.getType().getRef() == null 403 && element.getType() instanceof XsdComplexType) { 404 // print inner class for anonymous types 405 parserHeaderFile.printf("public:\n"); 406 String innerName = Utils.toClassName(getElementName(element)); 407 XsdComplexType innerType = (XsdComplexType) element.getType(); 408 printClass(innerName, nameScope + name + "::", innerType); 409 parserHeaderFile.println(); 410 cppType = new CppComplexType(nameScope + name + "::"+ innerName); 411 } else { 412 cppType = parseType(elementValue.getType(), getElementName(elementValue)); 413 } 414 elementTypes.add(cppType); 415 } 416 List<CppSimpleType> attributeTypes = new ArrayList<>(); 417 List<XsdAttribute> attributes = new ArrayList<>(); 418 for (XsdAttributeGroup attributeGroup : complexType.getAttributeGroups()) { 419 attributes.addAll(getAllAttributes(resolveAttributeGroup(attributeGroup))); 420 } 421 attributes.addAll(complexType.getAttributes()); 422 423 for (XsdAttribute attribute : attributes) { 424 XsdType type = resolveAttribute(attribute).getType(); 425 attributeTypes.add(parseSimpleType(type, false)); 426 } 427 428 // print member variables 429 430 parserHeaderFile.printf("private:\n"); 431 for (int i = 0; i < elementTypes.size(); ++i) { 432 CppType type = elementTypes.get(i); 433 XsdElement element = elements.get(i); 434 XsdElement elementValue = resolveElement(element); 435 String typeName = Utils.elementTypeName(type.getName(), 436 element.isMultiple() || type instanceof CppComplexType); 437 parserHeaderFile.printf("const %s %s_;\n", typeName, 438 Utils.toVariableName(getElementName(elementValue))); 439 } 440 for (int i = 0; i < attributeTypes.size(); ++i) { 441 CppType type = attributeTypes.get(i); 442 XsdAttribute attribute = resolveAttribute(attributes.get(i)); 443 String variableName = Utils.toVariableName(attribute.getName()); 444 if (attribute.isRequired()) { 445 parserHeaderFile.printf("const %s %s_;\n", type.getName(), variableName); 446 } else { 447 parserHeaderFile.printf("const std::optional<%s> %s_;\n", 448 type.getName(), variableName); 449 } 450 } 451 if (valueType != null) { 452 parserHeaderFile.printf("const std::optional<%s> value_;\n", valueType.getName()); 453 } 454 455 parserHeaderFile.printf("public:\n"); 456 String constructorArgs = printConstructor(name, nameScope, complexType, elements, 457 attributes, baseName); 458 459 // print getters and setters 460 for (int i = 0; i < elementTypes.size(); ++i) { 461 CppType type = elementTypes.get(i); 462 XsdElement element = elements.get(i); 463 XsdElement elementValue = resolveElement(element); 464 printGetter(nameScope + name, type, 465 Utils.toVariableName(getElementName(elementValue)), 466 type instanceof CppComplexType ? true : element.isMultiple(), 467 type instanceof CppComplexType ? false : ((CppSimpleType)type).isList(), 468 false); 469 } 470 for (int i = 0; i < attributeTypes.size(); ++i) { 471 CppType type = attributeTypes.get(i); 472 XsdAttribute attribute = resolveAttribute(attributes.get(i)); 473 printGetter(nameScope + name, type, Utils.toVariableName(attribute.getName()), 474 false, false, attribute.isRequired()); 475 } 476 if (valueType != null) { 477 printGetter(nameScope + name, valueType, "value", false, false, false); 478 } 479 480 printParser(name, nameScope, complexType, constructorArgs); 481 482 if (writer) { 483 printWriter(name, nameScope, complexType); 484 } 485 486 parserHeaderFile.println("};\n"); 487 } 488 489 /** 490 * Prints read() static member function for complex types. 491 * Note that read() is a non-validating parser. 492 * 493 * Foo.h: 494 * 495 * static Foo read(XmlNode* root); 496 * 497 * Foo.cpp: 498 * 499 * Foo Foo::read(XmlNode* root) { 500 * string _raw; 501 * for each member m 502 * _raw = .. 503 * parsing expressions for each member (read _raw, set _value) 504 * m = _value; 505 * Foo instance(args...); 506 * return instance; 507 * } 508 * 509 */ printParser(String name, String nameScope, XsdComplexType complexType, String args)510 private void printParser(String name, String nameScope, XsdComplexType complexType, String args) 511 throws CppCodeGeneratorException { 512 CppSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ? 513 getValueType((XsdSimpleContent) complexType, true) : null; 514 List<XsdElement> allElements = new ArrayList<>(); 515 List<XsdAttribute> allAttributes = new ArrayList<>(); 516 stackComponents(complexType, allElements, allAttributes); 517 518 // parse types for elements and attributes 519 List<CppType> allElementTypes = new ArrayList<>(); 520 for (XsdElement element : allElements) { 521 XsdElement elementValue = resolveElement(element); 522 CppType cppType = parseType(elementValue.getType(), elementValue.getName()); 523 allElementTypes.add(cppType); 524 } 525 List<CppSimpleType> allAttributeTypes = new ArrayList<>(); 526 for (XsdAttribute attribute : allAttributes) { 527 XsdType type = resolveAttribute(attribute).getType(); 528 allAttributeTypes.add(parseSimpleType(type, false)); 529 } 530 531 String fullName = nameScope + name; 532 String nodeType = getXmlNodeType(); 533 parserHeaderFile.printf("static %s read(%s *root);\n", fullName, nodeType); 534 parserCppFile.printf("\n%s %s::read(%s *root) {\n", fullName, fullName, nodeType); 535 536 parserCppFile.print("std::string _raw;\n"); 537 538 for (int i = 0; i < allAttributes.size(); ++i) { 539 CppSimpleType type = allAttributeTypes.get(i); 540 XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); 541 String variableName = Utils.toVariableName(attribute.getName()); 542 parserCppFile.printf("_raw = getXmlAttribute(root, \"%s\");\n", attribute.getName()); 543 if (attribute.isRequired()) { 544 if (type.isEnum()) { 545 parserCppFile.printf("%s %s = %s::%s;\n", 546 type.getName(), variableName, type.getName(), UNKNOWN_ENUM); 547 } else { 548 parserCppFile.printf("%s %s{};\n", type.getName(), variableName); 549 } 550 } else { 551 parserCppFile.printf("std::optional<%s> %s = std::nullopt;\n", type.getName(), 552 variableName); 553 } 554 parserCppFile.printf("if (_raw != \"\") {\n"); 555 parserCppFile.print(type.getParsingExpression()); 556 parserCppFile.printf("%s = _value;\n}\n", variableName); 557 } 558 559 if (!allElements.isEmpty()) { 560 for (int i = 0; i < allElements.size(); ++i) { 561 CppType type = allElementTypes.get(i); 562 XsdElement element = allElements.get(i); 563 XsdElement elementValue = resolveElement(element); 564 String variableName = Utils.toVariableName(getElementName(elementValue)); 565 parserCppFile.printf("%s %s;\n", Utils.elementTypeName(type.getName(), 566 element.isMultiple() || type instanceof CppComplexType), variableName); 567 } 568 if (useTinyXml) { 569 parserCppFile.print("for (auto *_child = root->FirstChildElement();" 570 + " _child != nullptr;" 571 + " _child = _child->NextSiblingElement()) {\n"); 572 } else { 573 parserCppFile.print("for (auto *_child = root->xmlChildrenNode;" 574 + " _child != nullptr;" 575 + " _child = _child->next) {\n"); 576 } 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 variableName = Utils.toVariableName(getElementName(elementValue)); 582 583 if (i != 0) parserCppFile.printf("} else "); 584 if (useTinyXml) { 585 parserCppFile.printf("if (!strcmp(_child->Name(), \"%s\")) {\n", 586 elementValue.getName()); 587 } else { 588 parserCppFile.printf("if (!xmlStrcmp(_child->name," 589 + " reinterpret_cast<const xmlChar*>(\"%s\"))) {\n", 590 elementValue.getName()); 591 } 592 593 if (type instanceof CppSimpleType) { 594 printSetRawWithElementText("_child"); 595 } 596 597 parserCppFile.print(type.getParsingExpression()); 598 599 if (element.isMultiple() || type instanceof CppComplexType) { 600 parserCppFile.printf("%s.push_back(std::move(_value));\n", variableName); 601 } else { 602 parserCppFile.printf("%s = std::move(_value);\n", variableName); 603 } 604 } 605 parserCppFile.printf("}\n}\n"); 606 } 607 if (baseValueType != null) { 608 printSetRawWithElementText("root"); 609 parserCppFile.print(baseValueType.getParsingExpression()); 610 } 611 parserCppFile.printf("%s instance%s;\n", 612 fullName, args.length() > 0 ? "(" + args + ")" : ""); 613 parserCppFile.print("return instance;\n}\n"); 614 } 615 getXmlNodeType()616 private String getXmlNodeType() { 617 return (useTinyXml ? "tinyxml2::XMLElement" : "xmlNode"); 618 } 619 printSetRawWithElementText(String varName)620 private void printSetRawWithElementText(String varName) { 621 if (useTinyXml) { 622 // The tinyxml version, in contrast to xmlNodeListGetString does not deal 623 // with ENTITY_REF nodes 624 parserCppFile.printf("_raw = \"\";\n"); 625 parserCppFile.printf("for (auto *textNode = %s->FirstChild();" 626 + " textNode != nullptr;" 627 + " textNode = textNode->NextSibling()) {\n", varName); 628 parserCppFile.printf("if (textNode->ToText() != nullptr) {\n"); 629 parserCppFile.printf("_raw.append(textNode->Value());\n"); 630 parserCppFile.printf("}\n"); 631 parserCppFile.printf("}\n"); 632 } else { 633 parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString("); 634 parserCppFile.printf("%s->doc, %s->xmlChildrenNode, 1));\n", varName, varName); 635 parserCppFile.printf("if (xmlValue == nullptr) {\n_raw = \"\";\n} else {\n"); 636 parserCppFile.printf("_raw = reinterpret_cast<const char*>(xmlValue.get());\n}"); 637 parserCppFile.printf("\n"); 638 } 639 } 640 641 /** 642 * Prints write() member function for complex types. 643 * 644 * Foo.h: 645 * 646 * void write(ostream& _out, string name) const; 647 * 648 * Foo.cpp: 649 * 650 * void Foo::write(ostream& _out, string name) const { 651 * <FooElement attrs....> 652 * value_ 653 * </Fooelement> 654 * } 655 * 656 */ printWriter(String name, String nameScope, XsdComplexType complexType)657 private void printWriter(String name, String nameScope, XsdComplexType complexType) 658 throws CppCodeGeneratorException { 659 List<XsdElement> allElements = new ArrayList<>(); 660 List<XsdAttribute> allAttributes = new ArrayList<>(); 661 stackComponents(complexType, allElements, allAttributes); 662 663 // parse types for elements and attributes 664 List<CppType> allElementTypes = new ArrayList<>(); 665 for (XsdElement element : allElements) { 666 XsdElement elementValue = resolveElement(element); 667 CppType cppType = parseType(elementValue.getType(), elementValue.getName()); 668 allElementTypes.add(cppType); 669 } 670 List<CppSimpleType> allAttributeTypes = new ArrayList<>(); 671 for (XsdAttribute attribute : allAttributes) { 672 XsdType type = resolveAttribute(attribute).getType(); 673 allAttributeTypes.add(parseSimpleType(type, false)); 674 } 675 676 String fullName = nameScope + name; 677 parserHeaderFile.printf("void write(std::ostream& _out, const std::string& _name) const;\n"); 678 parserCppFile.printf( 679 "\nvoid %s::write(std::ostream& _out, const std::string& _name) const {\n", 680 fullName); 681 682 parserCppFile.printf("_out << printIndent() << \"<\" << _name;\n"); 683 for (int i = 0; i < allAttributes.size(); ++i) { 684 CppType type = allAttributeTypes.get(i); 685 XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); 686 String variableName = Utils.toVariableName(attribute.getName()); 687 parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName)); 688 parserCppFile.printf("_out << \" %s=\\\"\";\n", attribute.getName()); 689 parserCppFile.print(type.getWritingExpression(String.format("%s%s()", 690 getterName(type.getName()), Utils.capitalize(variableName)), 691 attribute.getName())); 692 parserCppFile.printf("_out << \"\\\"\";\n}\n"); 693 } 694 parserCppFile.print("_out << \">\" << std::endl;\n"); 695 parserCppFile.print("++indentIndex;\n"); 696 697 if (!allElements.isEmpty()) { 698 for (int i = 0; i < allElements.size(); ++i) { 699 CppType type = allElementTypes.get(i); 700 XsdElement element = allElements.get(i); 701 XsdElement elementValue = resolveElement(element); 702 String elementName = getElementName(elementValue); 703 String variableName = Utils.toVariableName(elementName); 704 705 if (type instanceof CppComplexType || element.isMultiple()) { 706 parserCppFile.printf("for (auto& _value : get%s()) {\n", 707 Utils.capitalize(variableName)); 708 if (type instanceof CppSimpleType) { 709 parserCppFile.printf("_out << printIndent() << \"<%s>\";\n", 710 elementValue.getName()); 711 } 712 parserCppFile.printf( 713 type.getWritingExpression("_value", elementValue.getName())); 714 if (type instanceof CppSimpleType) { 715 parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", 716 elementValue.getName()); 717 } 718 parserCppFile.printf("}\n"); 719 } else { 720 parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName)); 721 if (type instanceof CppSimpleType) { 722 parserCppFile.printf("_out << printIndent() << \"<%s>\";\n", 723 elementValue.getName()); 724 } 725 parserCppFile.print(type.getWritingExpression(String.format("%s%s()", 726 getterName(type.getName()), Utils.capitalize(variableName)), 727 elementValue.getName())); 728 if (type instanceof CppSimpleType) { 729 parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", 730 elementValue.getName()); 731 } 732 parserCppFile.print("}\n"); 733 } 734 } 735 } 736 parserCppFile.print("--indentIndex;\n"); 737 parserCppFile.printf("_out << printIndent() << \"</\" << _name << \">\" << std::endl;\n"); 738 parserCppFile.printf("}\n"); 739 } 740 741 /** 742 * Prints hasAttr() and getAttr() member functions for each member field. 743 * 744 * Foo.h: 745 * 746 * const Attr& getAttr() const; 747 * bool hasAttr() const; 748 * const Item* getFirstItem() const; // for multi-value member 749 * 750 * Foo.cpp: 751 * 752 * const Attr& Foo::getAttr() const { 753 * return attr_; 754 * } 755 * bool Foo::hasAttr() const { 756 * return true; 757 * } 758 * const Item* Foo::getFirstItem() const { 759 * if (item_.empty()) { 760 * return nullptr; 761 * } 762 * return &item_[0]; 763 * } 764 * 765 */ printGetter(String name, CppType type, String variableName, boolean isMultiple, boolean isMultipleType, boolean isRequired)766 private void printGetter(String name, CppType type, String variableName, 767 boolean isMultiple, boolean isMultipleType, boolean isRequired) { 768 String typeName = isMultiple ? String.format("std::vector<%s>", 769 type.getName()) : type.getName(); 770 String assertHasValue = String.format("_xsdc_assert(has%s());\n", 771 Utils.capitalize(variableName)); 772 773 parserHeaderFile.printf("const %s& %s%s() const;\n", typeName, getterName(typeName), 774 Utils.capitalize(variableName)); 775 776 parserCppFile.println(); 777 parserCppFile.printf("const %s& %s::%s%s() const {\n", typeName, name, 778 getterName(typeName), Utils.capitalize(variableName)); 779 if (isMultiple || isRequired) { 780 parserCppFile.printf("return %s_;\n", variableName); 781 } else { 782 // Before accessing an optional::value(), we need to ensure that it has a value. 783 parserCppFile.print(assertHasValue); 784 parserCppFile.printf("return %s_.value();\n", variableName); 785 } 786 parserCppFile.printf("}\n\n"); 787 788 parserHeaderFile.printf("bool has%s() const;\n", Utils.capitalize(variableName)); 789 parserCppFile.printf("bool %s::has%s() const {\n", name, Utils.capitalize(variableName)); 790 if (isMultiple) { 791 parserCppFile.printf("return !(%s_.empty());\n}\n", variableName); 792 } else if (isRequired){ 793 parserCppFile.print("return true;\n}\n"); 794 } else { 795 parserCppFile.printf("return %s_.has_value();\n}\n", variableName); 796 } 797 798 // For elements that may occur multiple types or have a list of simple types 799 if (isMultiple || isMultipleType) { 800 String elementTypeName = type instanceof CppComplexType ? type.getName() : 801 ((CppSimpleType)type).getTypeName(); 802 if (elementTypeName.equals("bool")) { 803 parserHeaderFile.printf("%s getFirst%s() const;\n", 804 elementTypeName, Utils.capitalize(variableName)); 805 parserCppFile.println(); 806 parserCppFile.printf("%s %s::getFirst%s() const {\n" 807 + "%s" 808 + "if (%s_%sempty()) {\n" 809 + "return false;\n" 810 + "}\n" 811 + "return %s;\n" 812 + "}\n", 813 elementTypeName, name, Utils.capitalize(variableName), 814 isMultiple ? "" : assertHasValue, 815 variableName, 816 isMultiple ? "." : "->", 817 isMultiple ? String.format("%s_[0]", variableName) : 818 String.format("%s_.value()[0]", variableName)); 819 } else { 820 parserHeaderFile.printf("const %s* getFirst%s() const;\n", 821 elementTypeName, Utils.capitalize(variableName)); 822 parserCppFile.println(); 823 parserCppFile.printf("const %s* %s::getFirst%s() const {\n" 824 + "%s" 825 + "if (%s_%sempty()) {\n" 826 + "return nullptr;\n" 827 + "}\n" 828 + "return &%s;\n" 829 + "}\n", 830 elementTypeName, name, Utils.capitalize(variableName), 831 isMultiple ? "" : assertHasValue, 832 variableName, 833 isMultiple ? "." : "->", 834 isMultiple ? String.format("%s_[0]", variableName) : 835 String.format("%s_.value()[0]", variableName)); 836 } 837 } 838 } 839 840 /** 841 * Prints constructor for complex types 842 * 843 * Foo.h: 844 * 845 * Foo(args...); 846 * 847 * Foo.cpp: 848 * 849 * Foo::Foo(args...): initializer... {} 850 * 851 */ printConstructor(String name, String nameScope, XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes, String baseName)852 private String printConstructor(String name, String nameScope, XsdComplexType complexType, 853 List<XsdElement> elements, List<XsdAttribute> attributes, String baseName) 854 throws CppCodeGeneratorException { 855 String fullName = nameScope + name; 856 StringBuilder constructorArgs = new StringBuilder(); 857 StringBuilder parentArgs = new StringBuilder(); 858 StringBuilder constructor = new StringBuilder(); 859 StringBuilder args = new StringBuilder(); 860 861 List<XsdElement> allElements = new ArrayList<>(); 862 List<XsdAttribute> allAttributes = new ArrayList<>(); 863 stackComponents(complexType, allElements, allAttributes); 864 865 for (XsdElement element : allElements) { 866 XsdElement elementValue = resolveElement(element); 867 CppType type = parseType(elementValue.getType(), elementValue.getName()); 868 String variableName = Utils.toVariableName(getElementName(elementValue)); 869 constructorArgs.append(String.format(", %s %s", Utils.elementTypeName(type.getName(), 870 element.isMultiple() || type instanceof CppComplexType), variableName)); 871 args.append(String.format(", %s", variableName)); 872 boolean isMultipleType; 873 if (type instanceof CppComplexType) { 874 isMultipleType = true; 875 } else if (((CppSimpleType)type).isList()) { 876 isMultipleType = true; 877 } else { 878 isMultipleType = false; 879 } 880 881 if (elements.contains(element)) { 882 constructor.append(String.format(", %s_(%s)", variableName, 883 Utils.toAssignmentName(type.getName(), variableName, isMultipleType))); 884 } else { 885 parentArgs.append(String.format(", %s", variableName)); 886 } 887 } 888 for (XsdAttribute attribute : allAttributes) { 889 CppType type = parseSimpleType(resolveAttribute(attribute).getType(), false); 890 String variableName = Utils.toVariableName(resolveAttribute(attribute).getName()); 891 if (attribute.isRequired()) { 892 constructorArgs.append(String.format(", %s %s", type.getName(), variableName)); 893 } else { 894 constructorArgs.append(String.format(", std::optional<%s> %s", type.getName(), 895 variableName)); 896 } 897 args.append(String.format(", %s", variableName)); 898 boolean isMultipleType = ((CppSimpleType)type).isList() ? true : false; 899 if (attributes.contains(attribute)) { 900 constructor.append(String.format(", %s_(%s)", variableName, 901 Utils.toAssignmentName(type.getName(), variableName, isMultipleType))); 902 } else { 903 parentArgs.append(String.format(", %s", variableName)); 904 } 905 } 906 907 CppSimpleType valueType = (complexType instanceof XsdSimpleContent) ? 908 getValueType((XsdSimpleContent) complexType, false) : null; 909 if (valueType != null) { 910 constructorArgs.append(String.format(", %s %s", valueType.getName(), "value")); 911 constructor.append(String.format(", %s_(%s)", "value", "value")); 912 // getParsingExpression prepends with underscore, so set args for instantiation 913 args.append(String.format(", %s", "_value")); 914 } 915 916 String constructorArgsString = constructorArgs.toString(); 917 String constructorString = constructor.toString(); 918 if (constructorArgsString.length() > 0) { 919 constructorArgsString = constructorArgsString.substring(2); 920 } 921 922 boolean useExplicit = 923 !(constructorArgsString.isEmpty() || constructorArgsString.contains(",")); 924 if (useExplicit) { 925 parserHeaderFile.printf("explicit %s(%s);\n", name, constructorArgsString); 926 } else { 927 parserHeaderFile.printf("%s(%s);\n", name, constructorArgsString); 928 } 929 parserCppFile.printf("\n%s::%s(%s) : ", fullName, name, constructorArgsString); 930 931 String parentArgsString = parentArgs.toString(); 932 if (parentArgsString.length() > 0) { 933 parentArgsString = parentArgsString.substring(2); 934 parserCppFile.printf("%s(%s)", baseName, parentArgsString); 935 } else { 936 constructorString = constructorString.substring(2); 937 } 938 parserCppFile.printf("%s {\n}\n", constructorString); 939 940 String argsString = args.toString(); 941 if (argsString.length() > 0) { 942 argsString = argsString.substring(2); 943 } 944 return argsString; 945 } 946 947 /** 948 * Prints reader functions for each top-level types. 949 * 950 * Foo.h: 951 * 952 * optional<Foo> readFoo(const char* filename); 953 * 954 * Foo.cpp: 955 * 956 * std::optional<Foo> readFoo(const char* filename) { 957 * ... 958 * Foo _value = Foo::read(root); 959 * return _value; 960 * } 961 * 962 */ printXmlParser()963 private void printXmlParser() throws CppCodeGeneratorException { 964 if (useTinyXml) { 965 // Nothing to do for libtinyxml2 966 } else { 967 parserCppFile.printf("template <class T>\n" 968 + "constexpr void (*xmlDeleter)(T* t);\n" 969 + "template <>\nconstexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;\n" 970 + "template <>\nauto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };\n\n" 971 + "template <class T>\n" 972 + "constexpr auto make_xmlUnique(T *t) {\n" 973 + "auto deleter = [](T *t) { xmlDeleter<T>(t); };\n" 974 + "return std::unique_ptr<T, decltype(deleter)>{t, deleter};\n" 975 + "}\n\n"); 976 } 977 978 if (hasAttr) { 979 parserCppFile.printf("static std::string getXmlAttribute" 980 + "(const %s *cur, const char *attribute) {\n", getXmlNodeType()); 981 if (useTinyXml) { 982 parserCppFile.printf("auto attrValue = cur->Attribute(attribute);\n" 983 + "if(attrValue == nullptr) {\n" 984 + "return \"\";\n" 985 + "}\n" 986 + "return std::string(attrValue);\n"); 987 } else { 988 parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlGetProp(cur, " 989 + "reinterpret_cast<const xmlChar*>(attribute)));\n" 990 + "if (xmlValue == nullptr) {\n" 991 + "return \"\";\n" 992 + "}\n" 993 + "std::string value(reinterpret_cast<const char*>(xmlValue.get()));\n" 994 + "return value;\n"); 995 } 996 parserCppFile.printf("}\n\n"); 997 } 998 999 boolean isMultiRootElement = xmlSchema.getElementMap().values().size() > 1; 1000 for (XsdElement element : xmlSchema.getElementMap().values()) { 1001 // Skip parser if not specified as root. 1002 if (rootElements != null 1003 && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; 1004 printXmlParserFor(element, /*loadFile=*/true, isMultiRootElement); 1005 printXmlParserFor(element, /*loadFile=*/false, isMultiRootElement); 1006 } 1007 } 1008 1009 /** 1010 * Prints readType(const char* configFile) if loadFile is true. 1011 * Otherwise, prints parseType(const char* xml). 1012 */ printXmlParserFor(XsdElement element, boolean loadFile, boolean isMultiRootElement)1013 private void printXmlParserFor(XsdElement element, boolean loadFile, boolean isMultiRootElement) 1014 throws CppCodeGeneratorException { 1015 CppType cppType = parseType(element.getType(), element.getName()); 1016 String elementName = element.getName(); 1017 String typeName = cppType.getName(); 1018 String readerName = 1019 cppType instanceof CppSimpleType ? Utils.toClassName(elementName) : typeName; 1020 String methodName = loadFile ? "read" : "parse"; 1021 String argName = loadFile ? "configFile" : "xml"; 1022 parserHeaderFile.printf("std::optional<%s> %s%s(const char* %s);\n\n", 1023 typeName, 1024 methodName, 1025 isMultiRootElement ? readerName : "", 1026 argName); 1027 parserCppFile.printf("std::optional<%s> %s%s(const char* %s) {\n", 1028 typeName, 1029 methodName, 1030 isMultiRootElement ? readerName : "", 1031 argName); 1032 if (useTinyXml) { 1033 String innerParser = loadFile ? "LoadFile(configFile)" : "Parse(xml)"; 1034 parserCppFile.printf("tinyxml2::XMLDocument doc;\n" 1035 + "if (doc.%s != tinyxml2::XML_SUCCESS) {\n" 1036 + "return std::nullopt;\n" 1037 + "}\n" 1038 + "auto _child = doc.FirstChildElement();\n" 1039 + "if (_child == nullptr) {\n" 1040 + "return std::nullopt;\n" 1041 + "}\n\n" 1042 + "if (strcmp(_child->Name(), \"%s\") == 0) {\n", 1043 innerParser, 1044 elementName); 1045 } else { 1046 String innerParser = loadFile 1047 ? "xmlParseFile(configFile)" 1048 : "xmlParseDoc(reinterpret_cast<const xmlChar*>(xml))"; 1049 parserCppFile.printf("auto doc = make_xmlUnique(%s);\n" 1050 + "if (doc == nullptr) {\n" 1051 + "return std::nullopt;\n" 1052 + "}\n" 1053 + "xmlNodePtr _child = xmlDocGetRootElement(doc.get());\n" 1054 + "if (_child == nullptr) {\n" 1055 + "return std::nullopt;\n" 1056 + "}\n" 1057 + "if (xmlXIncludeProcess(doc.get()) < 0) {\n" 1058 + "return std::nullopt;\n" 1059 + "}\n\n" 1060 + "if (!xmlStrcmp(_child->name, reinterpret_cast<const xmlChar*>" 1061 + "(\"%s\"))) {\n", 1062 innerParser, 1063 elementName); 1064 } 1065 1066 if (cppType instanceof CppSimpleType) { 1067 parserCppFile.print("std::string _raw;\n"); 1068 printSetRawWithElementText("_child"); 1069 } 1070 parserCppFile.printf(cppType.getParsingExpression()); 1071 parserCppFile.printf("return _value;\n}\n"); 1072 parserCppFile.printf("return std::nullopt;\n"); 1073 parserCppFile.printf("}\n\n"); 1074 } 1075 1076 /** 1077 * Prints writer functions for each top-level types 1078 * 1079 * Foo.h: 1080 * 1081 * void write(ostream&, const Foo& foo); 1082 * 1083 * Foo.cpp: 1084 * 1085 * void write(ostream& _out, const Foo& foo) { 1086 * ... <?xml ... ?> 1087 * foo.write(_out, "FooElementName"); 1088 * } 1089 * 1090 */ printXmlWriter()1091 private void printXmlWriter() throws CppCodeGeneratorException { 1092 for (XsdElement element : xmlSchema.getElementMap().values()) { 1093 // Skip writer if not specified as root. 1094 if (rootElements != null 1095 && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; 1096 CppType cppType = parseType(element.getType(), element.getName()); 1097 String elementName = element.getName(); 1098 String variableName = Utils.toVariableName(elementName); 1099 String typeName = cppType.getName(); 1100 String writerName = 1101 cppType instanceof CppSimpleType ? Utils.toClassName(elementName) : ""; 1102 parserHeaderFile.printf("void write%s(std::ostream& _out, const %s& %s);\n\n", 1103 writerName, typeName, variableName); 1104 parserCppFile.printf("void write%s(std::ostream& _out, const %s& %s) {\n", 1105 writerName, typeName, variableName); 1106 parserCppFile.print( 1107 "_out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n"); 1108 if (cppType instanceof CppSimpleType) { 1109 parserCppFile.printf("_out << \"<%s>\";\n", elementName); 1110 parserCppFile.print(cppType.getWritingExpression(variableName, "")); 1111 parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", elementName); 1112 } else { 1113 parserCppFile.printf("%s.write(_out, \"%s\");\n", variableName, elementName); 1114 } 1115 parserCppFile.printf("}\n\n"); 1116 } 1117 1118 parserCppFile.print("static int indentIndex = 0;\n" 1119 + "std::string printIndent() {\n" 1120 + "std::string s = \"\";\n" 1121 + "for (int index = 0; index < indentIndex; ++index) {\n" 1122 + "s += \" \";\n" 1123 + "}\nreturn s;\n}\n\n"); 1124 } 1125 getElementName(XsdElement element)1126 private String getElementName(XsdElement element) { 1127 if (element instanceof XsdChoice) { 1128 return element.getName() + "_optional"; 1129 } else if (element instanceof XsdAll) { 1130 return element.getName() + "_all"; 1131 } 1132 return element.getName(); 1133 } 1134 getterName(String type)1135 private String getterName(String type) { 1136 if (type.equals("bool") && booleanGetter) { 1137 return "is"; 1138 } 1139 return "get"; 1140 } 1141 stackComponents(XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes)1142 private void stackComponents(XsdComplexType complexType, List<XsdElement> elements, 1143 List<XsdAttribute> attributes) throws CppCodeGeneratorException { 1144 if (complexType.getBase() != null) { 1145 QName baseRef = complexType.getBase().getRef(); 1146 if (baseRef != null && !baseRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1147 XsdType parent = getType(baseRef.getLocalPart()); 1148 if (parent instanceof XsdComplexType) { 1149 stackComponents((XsdComplexType) parent, elements, attributes); 1150 } 1151 } 1152 } 1153 elements.addAll(getAllElements(complexType.getGroup())); 1154 elements.addAll(complexType.getElements()); 1155 for (XsdAttributeGroup attributeGroup : complexType.getAttributeGroups()) { 1156 attributes.addAll(getAllAttributes(resolveAttributeGroup(attributeGroup))); 1157 } 1158 attributes.addAll(complexType.getAttributes()); 1159 } 1160 getAllAttributes(XsdAttributeGroup attributeGroup)1161 private List<XsdAttribute> getAllAttributes(XsdAttributeGroup attributeGroup) 1162 throws CppCodeGeneratorException{ 1163 List<XsdAttribute> attributes = new ArrayList<>(); 1164 for (XsdAttributeGroup attrGroup : attributeGroup.getAttributeGroups()) { 1165 attributes.addAll(getAllAttributes(resolveAttributeGroup(attrGroup))); 1166 } 1167 attributes.addAll(attributeGroup.getAttributes()); 1168 return attributes; 1169 } 1170 getAllElements(XsdGroup group)1171 private List<XsdElement> getAllElements(XsdGroup group) throws CppCodeGeneratorException { 1172 List<XsdElement> elements = new ArrayList<>(); 1173 if (group == null) { 1174 return elements; 1175 } 1176 elements.addAll(getAllElements(resolveGroup(group))); 1177 elements.addAll(group.getElements()); 1178 return elements; 1179 } 1180 1181 getBaseName(XsdComplexType complexType)1182 private String getBaseName(XsdComplexType complexType) throws CppCodeGeneratorException { 1183 if (complexType.getBase() == null) return null; 1184 if (complexType.getBase().getRef().getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1185 return null; 1186 } 1187 XsdType base = getType(complexType.getBase().getRef().getLocalPart()); 1188 if (base instanceof XsdComplexType) { 1189 return Utils.toClassName(base.getName()); 1190 } 1191 return null; 1192 } 1193 getValueType(XsdSimpleContent simpleContent, boolean traverse)1194 private CppSimpleType getValueType(XsdSimpleContent simpleContent, boolean traverse) 1195 throws CppCodeGeneratorException { 1196 assert simpleContent.getBase() != null; 1197 QName baseRef = simpleContent.getBase().getRef(); 1198 assert baseRef != null; 1199 if (baseRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1200 return predefinedType(baseRef.getLocalPart()); 1201 } else { 1202 XsdType parent = getType(baseRef.getLocalPart()); 1203 if (parent instanceof XsdSimpleType) { 1204 return parseSimpleTypeReference(baseRef, false); 1205 } 1206 if (!traverse) return null; 1207 if (parent instanceof XsdSimpleContent) { 1208 return getValueType((XsdSimpleContent) parent, true); 1209 } else { 1210 throw new CppCodeGeneratorException( 1211 String.format("base not simple : %s", baseRef.getLocalPart())); 1212 } 1213 } 1214 } 1215 parseType(XsdType type, String defaultName)1216 private CppType parseType(XsdType type, String defaultName) throws CppCodeGeneratorException { 1217 if (type.getRef() != null) { 1218 String name = type.getRef().getLocalPart(); 1219 if (type.getRef().getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1220 return predefinedType(name); 1221 } else { 1222 XsdType typeValue = getType(name); 1223 if (typeValue instanceof XsdSimpleType) { 1224 return parseSimpleTypeReference(type.getRef(), false); 1225 } 1226 return parseType(typeValue, name); 1227 } 1228 } 1229 if (type instanceof XsdComplexType) { 1230 return new CppComplexType(Utils.toClassName(defaultName)); 1231 } else if (type instanceof XsdSimpleType) { 1232 return parseSimpleTypeValue((XsdSimpleType) type, false); 1233 } else { 1234 throw new CppCodeGeneratorException( 1235 String.format("unknown type name : %s", defaultName)); 1236 } 1237 } 1238 parseSimpleType(XsdType type, boolean traverse)1239 private CppSimpleType parseSimpleType(XsdType type, boolean traverse) 1240 throws CppCodeGeneratorException { 1241 if (type.getRef() != null) { 1242 return parseSimpleTypeReference(type.getRef(), traverse); 1243 } else { 1244 return parseSimpleTypeValue((XsdSimpleType) type, traverse); 1245 } 1246 } 1247 parseSimpleTypeReference(QName typeRef, boolean traverse)1248 private CppSimpleType parseSimpleTypeReference(QName typeRef, boolean traverse) 1249 throws CppCodeGeneratorException { 1250 assert typeRef != null; 1251 String typeName = typeRef.getLocalPart(); 1252 if (typeRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1253 return predefinedType(typeName); 1254 } 1255 if (cppSimpleTypeMap.containsKey(typeName)) { 1256 return cppSimpleTypeMap.get(typeName); 1257 } else if (traverse) { 1258 XsdSimpleType simpleType = getSimpleType(typeName); 1259 CppSimpleType ret = parseSimpleTypeValue(simpleType, true); 1260 cppSimpleTypeMap.put(typeName, ret); 1261 return ret; 1262 } else { 1263 throw new CppCodeGeneratorException(String.format("unknown type name : %s", typeName)); 1264 } 1265 } 1266 parseSimpleTypeValue(XsdSimpleType simpleType, boolean traverse)1267 private CppSimpleType parseSimpleTypeValue(XsdSimpleType simpleType, boolean traverse) 1268 throws CppCodeGeneratorException { 1269 if (simpleType instanceof XsdList) { 1270 XsdList list = (XsdList) simpleType; 1271 return parseSimpleType(list.getItemType(), traverse).newListType(); 1272 } else if (simpleType instanceof XsdRestriction) { 1273 // we don't consider any restrictions. 1274 XsdRestriction restriction = (XsdRestriction) simpleType; 1275 if (restriction.getEnums() != null) { 1276 String name = Utils.toClassName(restriction.getName()); 1277 return new CppSimpleType(name, "stringTo" + name + "(%s)", false, true); 1278 } 1279 return parseSimpleType(restriction.getBase(), traverse); 1280 } else if (simpleType instanceof XsdUnion) { 1281 // unions are almost always interpreted as java.lang.String 1282 // Exceptionally, if any of member types of union are 'list', then we interpret it as 1283 // List<String> 1284 XsdUnion union = (XsdUnion) simpleType; 1285 for (XsdType memberType : union.getMemberTypes()) { 1286 if (parseSimpleType(memberType, traverse).isList()) { 1287 return new CppSimpleType("std::string", "%s", true); 1288 } 1289 } 1290 return new CppSimpleType("std::string", "%s", false); 1291 } else { 1292 // unreachable 1293 throw new IllegalStateException("unknown simple type"); 1294 } 1295 } 1296 resolveElement(XsdElement element)1297 private XsdElement resolveElement(XsdElement element) throws CppCodeGeneratorException { 1298 if (element.getRef() == null) return element; 1299 String name = element.getRef().getLocalPart(); 1300 XsdElement ret = xmlSchema.getElementMap().get(name); 1301 if (ret != null) return ret; 1302 throw new CppCodeGeneratorException(String.format("no element named : %s", name)); 1303 } 1304 resolveGroup(XsdGroup group)1305 private XsdGroup resolveGroup(XsdGroup group) throws CppCodeGeneratorException { 1306 if (group.getRef() == null) return null; 1307 String name = group.getRef().getLocalPart(); 1308 XsdGroup ret = xmlSchema.getGroupMap().get(name); 1309 if (ret != null) return ret; 1310 throw new CppCodeGeneratorException(String.format("no group named : %s", name)); 1311 } 1312 resolveAttribute(XsdAttribute attribute)1313 private XsdAttribute resolveAttribute(XsdAttribute attribute) 1314 throws CppCodeGeneratorException { 1315 if (attribute.getRef() == null) return attribute; 1316 String name = attribute.getRef().getLocalPart(); 1317 XsdAttribute ret = xmlSchema.getAttributeMap().get(name); 1318 if (ret != null) return ret; 1319 throw new CppCodeGeneratorException(String.format("no attribute named : %s", name)); 1320 } 1321 resolveAttributeGroup(XsdAttributeGroup attributeGroup)1322 private XsdAttributeGroup resolveAttributeGroup(XsdAttributeGroup attributeGroup) 1323 throws CppCodeGeneratorException { 1324 if (attributeGroup.getRef() == null) return attributeGroup; 1325 String name = attributeGroup.getRef().getLocalPart(); 1326 XsdAttributeGroup ret = xmlSchema.getAttributeGroupMap().get(name); 1327 if (ret != null) return ret; 1328 throw new CppCodeGeneratorException(String.format("no attribute group named : %s", name)); 1329 } 1330 getType(String name)1331 private XsdType getType(String name) throws CppCodeGeneratorException { 1332 XsdType type = xmlSchema.getTypeMap().get(name); 1333 if (type != null) return type; 1334 throw new CppCodeGeneratorException(String.format("no type named : %s", name)); 1335 } 1336 getSimpleType(String name)1337 private XsdSimpleType getSimpleType(String name) throws CppCodeGeneratorException { 1338 XsdType type = getType(name); 1339 if (type instanceof XsdSimpleType) return (XsdSimpleType) type; 1340 throw new CppCodeGeneratorException(String.format("not a simple type : %s", name)); 1341 } 1342 hasAttribute(XsdComplexType complexType)1343 private boolean hasAttribute(XsdComplexType complexType) throws CppCodeGeneratorException { 1344 if (complexType.getAttributes().size() > 0 || 1345 complexType.getAttributeGroups().size() > 0) { 1346 return true; 1347 } 1348 boolean results = false; 1349 for (XsdElement element : complexType.getElements()) { 1350 if (element.getRef() == null && element.getType().getRef() == null 1351 && element.getType() instanceof XsdComplexType) { 1352 results = hasAttribute((XsdComplexType) element.getType()); 1353 if (results) { 1354 return results; 1355 } 1356 } 1357 } 1358 return results; 1359 } 1360 predefinedType(String name)1361 private static CppSimpleType predefinedType(String name) throws CppCodeGeneratorException { 1362 switch (name) { 1363 case "string": 1364 case "token": 1365 case "normalizedString": 1366 case "language": 1367 case "ENTITY": 1368 case "ID": 1369 case "Name": 1370 case "NCName": 1371 case "NMTOKEN": 1372 case "anyURI": 1373 case "anyType": 1374 case "QName": 1375 case "NOTATION": 1376 case "IDREF": 1377 return new CppSimpleType("std::string", "%s", false); 1378 case "ENTITIES": 1379 case "NMTOKENS": 1380 case "IDREFS": 1381 return new CppSimpleType("std::string", "%s", true); 1382 case "date": 1383 case "dateTime": 1384 case "time": 1385 case "gDay": 1386 case "gMonth": 1387 case "gYear": 1388 case "gMonthDay": 1389 case "gYearMonth": 1390 case "duration": 1391 return new CppSimpleType("std::string", "%s", false); 1392 case "decimal": 1393 return new CppSimpleType("double", "std::stod(%s)", false); 1394 case "integer": 1395 case "negativeInteger": 1396 case "nonNegativeInteger": 1397 case "positiveInteger": 1398 case "nonPositiveInteger": 1399 return new CppSimpleType("int64_t", "std::stoll(%s)", false); 1400 case "unsignedLong": 1401 return new CppSimpleType("uint64_t", "std::stoull(%s)", false); 1402 case "long": 1403 return new CppSimpleType("int64_t", "std::stoll(%s)", false); 1404 case "unsignedInt": 1405 return new CppSimpleType("unsigned int", 1406 "static_cast<unsigned int>(stoul(%s))", false); 1407 case "int": 1408 return new CppSimpleType("int", "std::stoi(%s)", false); 1409 case "unsignedShort": 1410 return new CppSimpleType("unsigned short", 1411 "static_cast<unsigned short>(std::stoi(%s))", false); 1412 case "short": 1413 return new CppSimpleType("short", "static_cast<short>(std::stoi(%s))", false); 1414 case "unsignedByte": 1415 return new CppSimpleType("unsigned char", 1416 "static_cast<unsigned char>(std::stoi(%s))", false); 1417 case "byte": 1418 return new CppSimpleType("char", "static_cast<char>(std::stoi(%s))", false); 1419 case "boolean": 1420 return new CppSimpleType("bool", "%s == \"true\"", false); 1421 case "double": 1422 return new CppSimpleType("double", "std::stod(%s)", false); 1423 case "float": 1424 return new CppSimpleType("float", "std::stof(%s)", false); 1425 case "base64Binary": 1426 case "hexBinary": 1427 return new CppSimpleType("std::string", "%s", false); 1428 } 1429 throw new CppCodeGeneratorException("unknown xsd predefined type : " + name); 1430 } 1431 } 1432