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(parserHeaderFile, "libtinyxml2", "tinyxml2.h"); 167 } else { 168 printGuardedIncludes(parserHeaderFile, "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(CodeWriter file, String libName, String mainHeader)269 private void printGuardedIncludes(CodeWriter file, String libName, String mainHeader) { 270 printGuardedIncludes(file, libName, mainHeader, Collections.emptyList()); 271 } 272 printGuardedIncludes(CodeWriter file, String libName, String mainHeader, Collection<String> additionalHeaders)273 private void printGuardedIncludes(CodeWriter file, 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 (baseValueType != null) { 560 printSetRawWithElementText("root"); 561 parserCppFile.print(baseValueType.getParsingExpression()); 562 parserCppFile.printf("instance.setValue(_value);\n"); 563 parserCppFile.printf("}\n"); 564 } else if (!allElements.isEmpty()) { 565 for (int i = 0; i < allElements.size(); ++i) { 566 CppType type = allElementTypes.get(i); 567 XsdElement element = allElements.get(i); 568 XsdElement elementValue = resolveElement(element); 569 String variableName = Utils.toVariableName(getElementName(elementValue)); 570 parserCppFile.printf("%s %s;\n", Utils.elementTypeName(type.getName(), 571 element.isMultiple() || type instanceof CppComplexType), variableName); 572 } 573 if (useTinyXml) { 574 parserCppFile.print("for (auto *_child = root->FirstChildElement();" 575 + " _child != nullptr;" 576 + " _child = _child->NextSiblingElement()) {\n"); 577 } else { 578 parserCppFile.print("for (auto *_child = root->xmlChildrenNode;" 579 + " _child != nullptr;" 580 + " _child = _child->next) {\n"); 581 } 582 for (int i = 0; i < allElements.size(); ++i) { 583 CppType type = allElementTypes.get(i); 584 XsdElement element = allElements.get(i); 585 XsdElement elementValue = resolveElement(element); 586 String variableName = Utils.toVariableName(getElementName(elementValue)); 587 588 if (i != 0) parserCppFile.printf("} else "); 589 if (useTinyXml) { 590 parserCppFile.printf("if (!strcmp(_child->Name(), \"%s\")) {\n", 591 elementValue.getName()); 592 } else { 593 parserCppFile.printf("if (!xmlStrcmp(_child->name," 594 + " reinterpret_cast<const xmlChar*>(\"%s\"))) {\n", 595 elementValue.getName()); 596 } 597 598 if (type instanceof CppSimpleType) { 599 printSetRawWithElementText("_child"); 600 } 601 602 parserCppFile.print(type.getParsingExpression()); 603 604 if (element.isMultiple() || type instanceof CppComplexType) { 605 parserCppFile.printf("%s.push_back(std::move(_value));\n", variableName); 606 } else { 607 parserCppFile.printf("%s = std::move(_value);\n", variableName); 608 } 609 } 610 parserCppFile.printf("}\n}\n"); 611 } 612 parserCppFile.printf("%s instance%s;\n", 613 fullName, args.length() > 0 ? "(" + args + ")" : ""); 614 parserCppFile.print("return instance;\n}\n"); 615 } 616 getXmlNodeType()617 private String getXmlNodeType() { 618 return (useTinyXml ? "tinyxml2::XMLElement" : "xmlNode"); 619 } 620 printSetRawWithElementText(String varName)621 private void printSetRawWithElementText(String varName) { 622 if (useTinyXml) { 623 // The tinyxml version, in contrast to xmlNodeListGetString does not deal 624 // with ENTITY_REF nodes 625 parserCppFile.printf("_raw = \"\";\n"); 626 parserCppFile.printf("for (auto *textNode = %s->FirstChild();" 627 + " textNode != nullptr;" 628 + " textNode = textNode->NextSibling()) {\n", varName); 629 parserCppFile.printf("if (textNode->ToText() != nullptr) {\n"); 630 parserCppFile.printf("_raw.append(textNode->Value());\n"); 631 parserCppFile.printf("}\n"); 632 parserCppFile.printf("}\n"); 633 } else { 634 parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString("); 635 parserCppFile.printf("%s->doc, %s->xmlChildrenNode, 1));\n", varName, varName); 636 parserCppFile.printf("if (xmlValue == nullptr) {\n_raw = \"\";\n} else {\n"); 637 parserCppFile.printf("_raw = reinterpret_cast<const char*>(xmlValue.get());\n}"); 638 parserCppFile.printf("\n"); 639 } 640 } 641 642 /** 643 * Prints write() member function for complex types. 644 * 645 * Foo.h: 646 * 647 * void write(ostream& _out, string name) const; 648 * 649 * Foo.cpp: 650 * 651 * void Foo::write(ostream& _out, string name) const { 652 * <FooElement attrs....> 653 * value_ 654 * </Fooelement> 655 * } 656 * 657 */ printWriter(String name, String nameScope, XsdComplexType complexType)658 private void printWriter(String name, String nameScope, XsdComplexType complexType) 659 throws CppCodeGeneratorException { 660 List<XsdElement> allElements = new ArrayList<>(); 661 List<XsdAttribute> allAttributes = new ArrayList<>(); 662 stackComponents(complexType, allElements, allAttributes); 663 664 // parse types for elements and attributes 665 List<CppType> allElementTypes = new ArrayList<>(); 666 for (XsdElement element : allElements) { 667 XsdElement elementValue = resolveElement(element); 668 CppType cppType = parseType(elementValue.getType(), elementValue.getName()); 669 allElementTypes.add(cppType); 670 } 671 List<CppSimpleType> allAttributeTypes = new ArrayList<>(); 672 for (XsdAttribute attribute : allAttributes) { 673 XsdType type = resolveAttribute(attribute).getType(); 674 allAttributeTypes.add(parseSimpleType(type, false)); 675 } 676 677 String fullName = nameScope + name; 678 parserHeaderFile.printf("void write(std::ostream& _out, const std::string& _name) const;\n"); 679 parserCppFile.printf( 680 "\nvoid %s::write(std::ostream& _out, const std::string& _name) const {\n", 681 fullName); 682 683 parserCppFile.printf("_out << printIndent() << \"<\" << _name;\n"); 684 for (int i = 0; i < allAttributes.size(); ++i) { 685 CppType type = allAttributeTypes.get(i); 686 XsdAttribute attribute = resolveAttribute(allAttributes.get(i)); 687 String variableName = Utils.toVariableName(attribute.getName()); 688 parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName)); 689 parserCppFile.printf("_out << \" %s=\\\"\";\n", attribute.getName()); 690 parserCppFile.print(type.getWritingExpression(String.format("%s%s()", 691 getterName(type.getName()), Utils.capitalize(variableName)), 692 attribute.getName())); 693 parserCppFile.printf("_out << \"\\\"\";\n}\n"); 694 } 695 parserCppFile.print("_out << \">\" << std::endl;\n"); 696 parserCppFile.print("++indentIndex;\n"); 697 698 if (!allElements.isEmpty()) { 699 for (int i = 0; i < allElements.size(); ++i) { 700 CppType type = allElementTypes.get(i); 701 XsdElement element = allElements.get(i); 702 XsdElement elementValue = resolveElement(element); 703 String elementName = getElementName(elementValue); 704 String variableName = Utils.toVariableName(elementName); 705 706 if (type instanceof CppComplexType || element.isMultiple()) { 707 parserCppFile.printf("for (auto& _value : get%s()) {\n", 708 Utils.capitalize(variableName)); 709 if (type instanceof CppSimpleType) { 710 parserCppFile.printf("_out << printIndent() << \"<%s>\";\n", 711 elementValue.getName()); 712 } 713 parserCppFile.printf( 714 type.getWritingExpression("_value", elementValue.getName())); 715 if (type instanceof CppSimpleType) { 716 parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", 717 elementValue.getName()); 718 } 719 parserCppFile.printf("}\n"); 720 } else { 721 parserCppFile.printf("if (has%s()) {\n", Utils.capitalize(variableName)); 722 if (type instanceof CppSimpleType) { 723 parserCppFile.printf("_out << printIndent() << \"<%s>\";\n", 724 elementValue.getName()); 725 } 726 parserCppFile.print(type.getWritingExpression(String.format("%s%s()", 727 getterName(type.getName()), Utils.capitalize(variableName)), 728 elementValue.getName())); 729 if (type instanceof CppSimpleType) { 730 parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", 731 elementValue.getName()); 732 } 733 parserCppFile.print("}\n"); 734 } 735 } 736 } 737 parserCppFile.print("--indentIndex;\n"); 738 parserCppFile.printf("_out << printIndent() << \"</\" << _name << \">\" << std::endl;\n"); 739 parserCppFile.printf("}\n"); 740 } 741 742 /** 743 * Prints hasAttr() and getAttr() member functions for each member field. 744 * 745 * Foo.h: 746 * 747 * const Attr& getAttr() const; 748 * bool hasAttr() const; 749 * const Item* getFirstItem() const; // for multi-value member 750 * 751 * Foo.cpp: 752 * 753 * const Attr& Foo::getAttr() const { 754 * return attr_; 755 * } 756 * bool Foo::hasAttr() const { 757 * return true; 758 * } 759 * const Item* Foo::getFirstItem() const { 760 * if (item_.empty()) { 761 * return nullptr; 762 * } 763 * return &item_[0]; 764 * } 765 * 766 */ printGetter(String name, CppType type, String variableName, boolean isMultiple, boolean isMultipleType, boolean isRequired)767 private void printGetter(String name, CppType type, String variableName, 768 boolean isMultiple, boolean isMultipleType, boolean isRequired) { 769 String typeName = isMultiple ? String.format("std::vector<%s>", 770 type.getName()) : type.getName(); 771 String assertHasValue = String.format("_xsdc_assert(has%s());\n", 772 Utils.capitalize(variableName)); 773 774 parserHeaderFile.printf("const %s& %s%s() const;\n", typeName, getterName(typeName), 775 Utils.capitalize(variableName)); 776 777 parserCppFile.println(); 778 parserCppFile.printf("const %s& %s::%s%s() const {\n", typeName, name, 779 getterName(typeName), Utils.capitalize(variableName)); 780 if (isMultiple || isRequired) { 781 parserCppFile.printf("return %s_;\n", variableName); 782 } else { 783 // Before accessing an optional::value(), we need to ensure that it has a value. 784 parserCppFile.print(assertHasValue); 785 parserCppFile.printf("return %s_.value();\n", variableName); 786 } 787 parserCppFile.printf("}\n\n"); 788 789 parserHeaderFile.printf("bool has%s() const;\n", Utils.capitalize(variableName)); 790 parserCppFile.printf("bool %s::has%s() const {\n", name, Utils.capitalize(variableName)); 791 if (isMultiple) { 792 parserCppFile.printf("return !(%s_.empty());\n}\n", variableName); 793 } else if (isRequired){ 794 parserCppFile.print("return true;\n}\n"); 795 } else { 796 parserCppFile.printf("return %s_.has_value();\n}\n", variableName); 797 } 798 799 // For elements that may occur multiple types or have a list of simple types 800 if (isMultiple || isMultipleType) { 801 String elementTypeName = type instanceof CppComplexType ? type.getName() : 802 ((CppSimpleType)type).getTypeName(); 803 if (elementTypeName.equals("bool")) { 804 parserHeaderFile.printf("%s getFirst%s() const;\n", 805 elementTypeName, Utils.capitalize(variableName)); 806 parserCppFile.println(); 807 parserCppFile.printf("%s %s::getFirst%s() const {\n" 808 + "%s" 809 + "if (%s_%sempty()) {\n" 810 + "return false;\n" 811 + "}\n" 812 + "return %s;\n" 813 + "}\n", 814 elementTypeName, name, Utils.capitalize(variableName), 815 isMultiple ? "" : assertHasValue, 816 variableName, 817 isMultiple ? "." : "->", 818 isMultiple ? String.format("%s_[0]", variableName) : 819 String.format("%s_.value()[0]", variableName)); 820 } else { 821 parserHeaderFile.printf("const %s* getFirst%s() const;\n", 822 elementTypeName, Utils.capitalize(variableName)); 823 parserCppFile.println(); 824 parserCppFile.printf("const %s* %s::getFirst%s() const {\n" 825 + "%s" 826 + "if (%s_%sempty()) {\n" 827 + "return nullptr;\n" 828 + "}\n" 829 + "return &%s;\n" 830 + "}\n", 831 elementTypeName, name, Utils.capitalize(variableName), 832 isMultiple ? "" : assertHasValue, 833 variableName, 834 isMultiple ? "." : "->", 835 isMultiple ? String.format("%s_[0]", variableName) : 836 String.format("%s_.value()[0]", variableName)); 837 } 838 } 839 } 840 841 /** 842 * Prints constructor for complex types 843 * 844 * Foo.h: 845 * 846 * Foo(args...); 847 * 848 * Foo.cpp: 849 * 850 * Foo::Foo(args...): initializer... {} 851 * 852 */ printConstructor(String name, String nameScope, XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes, String baseName)853 private String printConstructor(String name, String nameScope, XsdComplexType complexType, 854 List<XsdElement> elements, List<XsdAttribute> attributes, String baseName) 855 throws CppCodeGeneratorException { 856 String fullName = nameScope + name; 857 StringBuilder constructorArgs = new StringBuilder(); 858 StringBuilder parentArgs = new StringBuilder(); 859 StringBuilder constructor = new StringBuilder(); 860 StringBuilder args = new StringBuilder(); 861 862 List<XsdElement> allElements = new ArrayList<>(); 863 List<XsdAttribute> allAttributes = new ArrayList<>(); 864 stackComponents(complexType, allElements, allAttributes); 865 866 for (XsdElement element : allElements) { 867 XsdElement elementValue = resolveElement(element); 868 CppType type = parseType(elementValue.getType(), elementValue.getName()); 869 String variableName = Utils.toVariableName(getElementName(elementValue)); 870 constructorArgs.append(String.format(", %s %s", Utils.elementTypeName(type.getName(), 871 element.isMultiple() || type instanceof CppComplexType), variableName)); 872 args.append(String.format(", %s", variableName)); 873 boolean isMultipleType; 874 if (type instanceof CppComplexType) { 875 isMultipleType = true; 876 } else if (((CppSimpleType)type).isList()) { 877 isMultipleType = true; 878 } else { 879 isMultipleType = false; 880 } 881 882 if (elements.contains(element)) { 883 constructor.append(String.format(", %s_(%s)", variableName, 884 Utils.toAssignmentName(type.getName(), variableName, isMultipleType))); 885 } else { 886 parentArgs.append(String.format(", %s", variableName)); 887 } 888 } 889 for (XsdAttribute attribute : allAttributes) { 890 CppType type = parseSimpleType(resolveAttribute(attribute).getType(), false); 891 String variableName = Utils.toVariableName(resolveAttribute(attribute).getName()); 892 if (attribute.isRequired()) { 893 constructorArgs.append(String.format(", %s %s", type.getName(), variableName)); 894 } else { 895 constructorArgs.append(String.format(", std::optional<%s> %s", type.getName(), 896 variableName)); 897 } 898 args.append(String.format(", %s", variableName)); 899 boolean isMultipleType = ((CppSimpleType)type).isList() ? true : false; 900 if (attributes.contains(attribute)) { 901 constructor.append(String.format(", %s_(%s)", variableName, 902 Utils.toAssignmentName(type.getName(), variableName, isMultipleType))); 903 } else { 904 parentArgs.append(String.format(", %s", variableName)); 905 } 906 } 907 908 String constructorArgsString = constructorArgs.toString(); 909 String constructorString = constructor.toString(); 910 if (constructorArgsString.length() > 0) { 911 constructorArgsString = constructorArgsString.substring(2); 912 } 913 914 boolean useExplicit = 915 !(constructorArgsString.isEmpty() || constructorArgsString.contains(",")); 916 if (useExplicit) { 917 parserHeaderFile.printf("explicit %s(%s);\n", name, constructorArgsString); 918 } else { 919 parserHeaderFile.printf("%s(%s);\n", name, constructorArgsString); 920 } 921 parserCppFile.printf("\n%s::%s(%s) : ", fullName, name, constructorArgsString); 922 923 String parentArgsString = parentArgs.toString(); 924 if (parentArgsString.length() > 0) { 925 parentArgsString = parentArgsString.substring(2); 926 parserCppFile.printf("%s(%s)", baseName, parentArgsString); 927 } else { 928 constructorString = constructorString.substring(2); 929 } 930 parserCppFile.printf("%s {\n}\n", constructorString); 931 932 String argsString = args.toString(); 933 if (argsString.length() > 0) { 934 argsString = argsString.substring(2); 935 } 936 return argsString; 937 } 938 939 /** 940 * Prints reader functions for each top-level types. 941 * 942 * Foo.h: 943 * 944 * optional<Foo> readFoo(const char* filename); 945 * 946 * Foo.cpp: 947 * 948 * std::optional<Foo> readFoo(const char* filename) { 949 * ... 950 * Foo _value = Foo::read(root); 951 * return _value; 952 * } 953 * 954 */ printXmlParser()955 private void printXmlParser() throws CppCodeGeneratorException { 956 if (useTinyXml) { 957 // Nothing to do for libtinyxml2 958 } else { 959 parserCppFile.printf("template <class T>\n" 960 + "constexpr void (*xmlDeleter)(T* t);\n" 961 + "template <>\nconstexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;\n" 962 + "template <>\nauto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };\n\n" 963 + "template <class T>\n" 964 + "constexpr auto make_xmlUnique(T *t) {\n" 965 + "auto deleter = [](T *t) { xmlDeleter<T>(t); };\n" 966 + "return std::unique_ptr<T, decltype(deleter)>{t, deleter};\n" 967 + "}\n\n"); 968 } 969 970 if (hasAttr) { 971 parserCppFile.printf("static std::string getXmlAttribute" 972 + "(const %s *cur, const char *attribute) {\n", getXmlNodeType()); 973 if (useTinyXml) { 974 parserCppFile.printf("auto attrValue = cur->Attribute(attribute);\n" 975 + "if(attrValue == nullptr) {\n" 976 + "return \"\";\n" 977 + "}\n" 978 + "return std::string(attrValue);\n"); 979 } else { 980 parserCppFile.printf("auto xmlValue = make_xmlUnique(xmlGetProp(cur, " 981 + "reinterpret_cast<const xmlChar*>(attribute)));\n" 982 + "if (xmlValue == nullptr) {\n" 983 + "return \"\";\n" 984 + "}\n" 985 + "std::string value(reinterpret_cast<const char*>(xmlValue.get()));\n" 986 + "return value;\n"); 987 } 988 parserCppFile.printf("}\n\n"); 989 } 990 991 boolean isMultiRootElement = xmlSchema.getElementMap().values().size() > 1; 992 for (XsdElement element : xmlSchema.getElementMap().values()) { 993 // Skip parser if not specified as root. 994 if (rootElements != null 995 && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; 996 printXmlParserFor(element, /*loadFile=*/true, isMultiRootElement); 997 printXmlParserFor(element, /*loadFile=*/false, isMultiRootElement); 998 } 999 } 1000 1001 /** 1002 * Prints readType(const char* configFile) if loadFile is true. 1003 * Otherwise, prints parseType(const char* xml). 1004 */ printXmlParserFor(XsdElement element, boolean loadFile, boolean isMultiRootElement)1005 private void printXmlParserFor(XsdElement element, boolean loadFile, boolean isMultiRootElement) 1006 throws CppCodeGeneratorException { 1007 CppType cppType = parseType(element.getType(), element.getName()); 1008 String elementName = element.getName(); 1009 String typeName = cppType.getName(); 1010 String readerName = 1011 cppType instanceof CppSimpleType ? Utils.toClassName(elementName) : typeName; 1012 String methodName = loadFile ? "read" : "parse"; 1013 String argName = loadFile ? "configFile" : "xml"; 1014 parserHeaderFile.printf("std::optional<%s> %s%s(const char* %s);\n\n", 1015 typeName, 1016 methodName, 1017 isMultiRootElement ? readerName : "", 1018 argName); 1019 parserCppFile.printf("std::optional<%s> %s%s(const char* %s) {\n", 1020 typeName, 1021 methodName, 1022 isMultiRootElement ? readerName : "", 1023 argName); 1024 if (useTinyXml) { 1025 String innerParser = loadFile ? "LoadFile(configFile)" : "Parse(xml)"; 1026 parserCppFile.printf("tinyxml2::XMLDocument doc;\n" 1027 + "if (doc.%s != tinyxml2::XML_SUCCESS) {\n" 1028 + "return std::nullopt;\n" 1029 + "}\n" 1030 + "auto _child = doc.FirstChildElement();\n" 1031 + "if (_child == nullptr) {\n" 1032 + "return std::nullopt;\n" 1033 + "}\n\n" 1034 + "if (strcmp(_child->Name(), \"%s\") == 0) {\n", 1035 innerParser, 1036 elementName); 1037 } else { 1038 String innerParser = loadFile 1039 ? "xmlParseFile(configFile)" 1040 : "xmlParseDoc(reinterpret_cast<const xmlChar*>(xml))"; 1041 parserCppFile.printf("auto doc = make_xmlUnique(%s);\n" 1042 + "if (doc == nullptr) {\n" 1043 + "return std::nullopt;\n" 1044 + "}\n" 1045 + "xmlNodePtr _child = xmlDocGetRootElement(doc.get());\n" 1046 + "if (_child == nullptr) {\n" 1047 + "return std::nullopt;\n" 1048 + "}\n" 1049 + "if (xmlXIncludeProcess(doc.get()) < 0) {\n" 1050 + "return std::nullopt;\n" 1051 + "}\n\n" 1052 + "if (!xmlStrcmp(_child->name, reinterpret_cast<const xmlChar*>" 1053 + "(\"%s\"))) {\n", 1054 innerParser, 1055 elementName); 1056 } 1057 1058 if (cppType instanceof CppSimpleType) { 1059 parserCppFile.print("std::string _raw;\n"); 1060 printSetRawWithElementText("_child"); 1061 } 1062 parserCppFile.printf(cppType.getParsingExpression()); 1063 parserCppFile.printf("return _value;\n}\n"); 1064 parserCppFile.printf("return std::nullopt;\n"); 1065 parserCppFile.printf("}\n\n"); 1066 } 1067 1068 /** 1069 * Prints writer functions for each top-level types 1070 * 1071 * Foo.h: 1072 * 1073 * void write(ostream&, const Foo& foo); 1074 * 1075 * Foo.cpp: 1076 * 1077 * void write(ostream& _out, const Foo& foo) { 1078 * ... <?xml ... ?> 1079 * foo.write(_out, "FooElementName"); 1080 * } 1081 * 1082 */ printXmlWriter()1083 private void printXmlWriter() throws CppCodeGeneratorException { 1084 for (XsdElement element : xmlSchema.getElementMap().values()) { 1085 // Skip writer if not specified as root. 1086 if (rootElements != null 1087 && Arrays.asList(rootElements).indexOf(element.getName()) == -1) continue; 1088 CppType cppType = parseType(element.getType(), element.getName()); 1089 String elementName = element.getName(); 1090 String variableName = Utils.toVariableName(elementName); 1091 String typeName = cppType.getName(); 1092 String writerName = 1093 cppType instanceof CppSimpleType ? Utils.toClassName(elementName) : ""; 1094 parserHeaderFile.printf("void write%s(std::ostream& _out, const %s& %s);\n\n", 1095 writerName, typeName, variableName); 1096 parserCppFile.printf("void write%s(std::ostream& _out, const %s& %s) {\n", 1097 writerName, typeName, variableName); 1098 parserCppFile.print( 1099 "_out << \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\";\n"); 1100 if (cppType instanceof CppSimpleType) { 1101 parserCppFile.printf("_out << \"<%s>\";\n", elementName); 1102 parserCppFile.print(cppType.getWritingExpression(variableName, "")); 1103 parserCppFile.printf("_out << \"</%s>\" << std::endl;\n", elementName); 1104 } else { 1105 parserCppFile.printf("%s.write(_out, \"%s\");\n", variableName, elementName); 1106 } 1107 parserCppFile.printf("}\n\n"); 1108 } 1109 1110 parserCppFile.print("static int indentIndex = 0;\n" 1111 + "std::string printIndent() {\n" 1112 + "std::string s = \"\";\n" 1113 + "for (int index = 0; index < indentIndex; ++index) {\n" 1114 + "s += \" \";\n" 1115 + "}\nreturn s;\n}\n\n"); 1116 } 1117 getElementName(XsdElement element)1118 private String getElementName(XsdElement element) { 1119 if (element instanceof XsdChoice) { 1120 return element.getName() + "_optional"; 1121 } else if (element instanceof XsdAll) { 1122 return element.getName() + "_all"; 1123 } 1124 return element.getName(); 1125 } 1126 getterName(String type)1127 private String getterName(String type) { 1128 if (type.equals("bool") && booleanGetter) { 1129 return "is"; 1130 } 1131 return "get"; 1132 } 1133 stackComponents(XsdComplexType complexType, List<XsdElement> elements, List<XsdAttribute> attributes)1134 private void stackComponents(XsdComplexType complexType, List<XsdElement> elements, 1135 List<XsdAttribute> attributes) throws CppCodeGeneratorException { 1136 if (complexType.getBase() != null) { 1137 QName baseRef = complexType.getBase().getRef(); 1138 if (baseRef != null && !baseRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1139 XsdType parent = getType(baseRef.getLocalPart()); 1140 if (parent instanceof XsdComplexType) { 1141 stackComponents((XsdComplexType) parent, elements, attributes); 1142 } 1143 } 1144 } 1145 elements.addAll(getAllElements(complexType.getGroup())); 1146 elements.addAll(complexType.getElements()); 1147 for (XsdAttributeGroup attributeGroup : complexType.getAttributeGroups()) { 1148 attributes.addAll(getAllAttributes(resolveAttributeGroup(attributeGroup))); 1149 } 1150 attributes.addAll(complexType.getAttributes()); 1151 } 1152 getAllAttributes(XsdAttributeGroup attributeGroup)1153 private List<XsdAttribute> getAllAttributes(XsdAttributeGroup attributeGroup) 1154 throws CppCodeGeneratorException{ 1155 List<XsdAttribute> attributes = new ArrayList<>(); 1156 for (XsdAttributeGroup attrGroup : attributeGroup.getAttributeGroups()) { 1157 attributes.addAll(getAllAttributes(resolveAttributeGroup(attrGroup))); 1158 } 1159 attributes.addAll(attributeGroup.getAttributes()); 1160 return attributes; 1161 } 1162 getAllElements(XsdGroup group)1163 private List<XsdElement> getAllElements(XsdGroup group) throws CppCodeGeneratorException { 1164 List<XsdElement> elements = new ArrayList<>(); 1165 if (group == null) { 1166 return elements; 1167 } 1168 elements.addAll(getAllElements(resolveGroup(group))); 1169 elements.addAll(group.getElements()); 1170 return elements; 1171 } 1172 1173 getBaseName(XsdComplexType complexType)1174 private String getBaseName(XsdComplexType complexType) throws CppCodeGeneratorException { 1175 if (complexType.getBase() == null) return null; 1176 if (complexType.getBase().getRef().getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1177 return null; 1178 } 1179 XsdType base = getType(complexType.getBase().getRef().getLocalPart()); 1180 if (base instanceof XsdComplexType) { 1181 return Utils.toClassName(base.getName()); 1182 } 1183 return null; 1184 } 1185 getValueType(XsdSimpleContent simpleContent, boolean traverse)1186 private CppSimpleType getValueType(XsdSimpleContent simpleContent, boolean traverse) 1187 throws CppCodeGeneratorException { 1188 assert simpleContent.getBase() != null; 1189 QName baseRef = simpleContent.getBase().getRef(); 1190 assert baseRef != null; 1191 if (baseRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1192 return predefinedType(baseRef.getLocalPart()); 1193 } else { 1194 XsdType parent = getType(baseRef.getLocalPart()); 1195 if (parent instanceof XsdSimpleType) { 1196 return parseSimpleTypeReference(baseRef, false); 1197 } 1198 if (!traverse) return null; 1199 if (parent instanceof XsdSimpleContent) { 1200 return getValueType((XsdSimpleContent) parent, true); 1201 } else { 1202 throw new CppCodeGeneratorException( 1203 String.format("base not simple : %s", baseRef.getLocalPart())); 1204 } 1205 } 1206 } 1207 parseType(XsdType type, String defaultName)1208 private CppType parseType(XsdType type, String defaultName) throws CppCodeGeneratorException { 1209 if (type.getRef() != null) { 1210 String name = type.getRef().getLocalPart(); 1211 if (type.getRef().getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1212 return predefinedType(name); 1213 } else { 1214 XsdType typeValue = getType(name); 1215 if (typeValue instanceof XsdSimpleType) { 1216 return parseSimpleTypeReference(type.getRef(), false); 1217 } 1218 return parseType(typeValue, name); 1219 } 1220 } 1221 if (type instanceof XsdComplexType) { 1222 return new CppComplexType(Utils.toClassName(defaultName)); 1223 } else if (type instanceof XsdSimpleType) { 1224 return parseSimpleTypeValue((XsdSimpleType) type, false); 1225 } else { 1226 throw new CppCodeGeneratorException( 1227 String.format("unknown type name : %s", defaultName)); 1228 } 1229 } 1230 parseSimpleType(XsdType type, boolean traverse)1231 private CppSimpleType parseSimpleType(XsdType type, boolean traverse) 1232 throws CppCodeGeneratorException { 1233 if (type.getRef() != null) { 1234 return parseSimpleTypeReference(type.getRef(), traverse); 1235 } else { 1236 return parseSimpleTypeValue((XsdSimpleType) type, traverse); 1237 } 1238 } 1239 parseSimpleTypeReference(QName typeRef, boolean traverse)1240 private CppSimpleType parseSimpleTypeReference(QName typeRef, boolean traverse) 1241 throws CppCodeGeneratorException { 1242 assert typeRef != null; 1243 String typeName = typeRef.getLocalPart(); 1244 if (typeRef.getNamespaceURI().equals(XsdConstants.XSD_NAMESPACE)) { 1245 return predefinedType(typeName); 1246 } 1247 if (cppSimpleTypeMap.containsKey(typeName)) { 1248 return cppSimpleTypeMap.get(typeName); 1249 } else if (traverse) { 1250 XsdSimpleType simpleType = getSimpleType(typeName); 1251 CppSimpleType ret = parseSimpleTypeValue(simpleType, true); 1252 cppSimpleTypeMap.put(typeName, ret); 1253 return ret; 1254 } else { 1255 throw new CppCodeGeneratorException(String.format("unknown type name : %s", typeName)); 1256 } 1257 } 1258 parseSimpleTypeValue(XsdSimpleType simpleType, boolean traverse)1259 private CppSimpleType parseSimpleTypeValue(XsdSimpleType simpleType, boolean traverse) 1260 throws CppCodeGeneratorException { 1261 if (simpleType instanceof XsdList) { 1262 XsdList list = (XsdList) simpleType; 1263 return parseSimpleType(list.getItemType(), traverse).newListType(); 1264 } else if (simpleType instanceof XsdRestriction) { 1265 // we don't consider any restrictions. 1266 XsdRestriction restriction = (XsdRestriction) simpleType; 1267 if (restriction.getEnums() != null) { 1268 String name = Utils.toClassName(restriction.getName()); 1269 return new CppSimpleType(name, "stringTo" + name + "(%s)", false, true); 1270 } 1271 return parseSimpleType(restriction.getBase(), traverse); 1272 } else if (simpleType instanceof XsdUnion) { 1273 // unions are almost always interpreted as java.lang.String 1274 // Exceptionally, if any of member types of union are 'list', then we interpret it as 1275 // List<String> 1276 XsdUnion union = (XsdUnion) simpleType; 1277 for (XsdType memberType : union.getMemberTypes()) { 1278 if (parseSimpleType(memberType, traverse).isList()) { 1279 return new CppSimpleType("std::string", "%s", true); 1280 } 1281 } 1282 return new CppSimpleType("std::string", "%s", false); 1283 } else { 1284 // unreachable 1285 throw new IllegalStateException("unknown simple type"); 1286 } 1287 } 1288 resolveElement(XsdElement element)1289 private XsdElement resolveElement(XsdElement element) throws CppCodeGeneratorException { 1290 if (element.getRef() == null) return element; 1291 String name = element.getRef().getLocalPart(); 1292 XsdElement ret = xmlSchema.getElementMap().get(name); 1293 if (ret != null) return ret; 1294 throw new CppCodeGeneratorException(String.format("no element named : %s", name)); 1295 } 1296 resolveGroup(XsdGroup group)1297 private XsdGroup resolveGroup(XsdGroup group) throws CppCodeGeneratorException { 1298 if (group.getRef() == null) return null; 1299 String name = group.getRef().getLocalPart(); 1300 XsdGroup ret = xmlSchema.getGroupMap().get(name); 1301 if (ret != null) return ret; 1302 throw new CppCodeGeneratorException(String.format("no group named : %s", name)); 1303 } 1304 resolveAttribute(XsdAttribute attribute)1305 private XsdAttribute resolveAttribute(XsdAttribute attribute) 1306 throws CppCodeGeneratorException { 1307 if (attribute.getRef() == null) return attribute; 1308 String name = attribute.getRef().getLocalPart(); 1309 XsdAttribute ret = xmlSchema.getAttributeMap().get(name); 1310 if (ret != null) return ret; 1311 throw new CppCodeGeneratorException(String.format("no attribute named : %s", name)); 1312 } 1313 resolveAttributeGroup(XsdAttributeGroup attributeGroup)1314 private XsdAttributeGroup resolveAttributeGroup(XsdAttributeGroup attributeGroup) 1315 throws CppCodeGeneratorException { 1316 if (attributeGroup.getRef() == null) return attributeGroup; 1317 String name = attributeGroup.getRef().getLocalPart(); 1318 XsdAttributeGroup ret = xmlSchema.getAttributeGroupMap().get(name); 1319 if (ret != null) return ret; 1320 throw new CppCodeGeneratorException(String.format("no attribute group named : %s", name)); 1321 } 1322 getType(String name)1323 private XsdType getType(String name) throws CppCodeGeneratorException { 1324 XsdType type = xmlSchema.getTypeMap().get(name); 1325 if (type != null) return type; 1326 throw new CppCodeGeneratorException(String.format("no type named : %s", name)); 1327 } 1328 getSimpleType(String name)1329 private XsdSimpleType getSimpleType(String name) throws CppCodeGeneratorException { 1330 XsdType type = getType(name); 1331 if (type instanceof XsdSimpleType) return (XsdSimpleType) type; 1332 throw new CppCodeGeneratorException(String.format("not a simple type : %s", name)); 1333 } 1334 hasAttribute(XsdComplexType complexType)1335 private boolean hasAttribute(XsdComplexType complexType) throws CppCodeGeneratorException { 1336 if (complexType.getAttributes().size() > 0 || 1337 complexType.getAttributeGroups().size() > 0) { 1338 return true; 1339 } 1340 boolean results = false; 1341 for (XsdElement element : complexType.getElements()) { 1342 if (element.getRef() == null && element.getType().getRef() == null 1343 && element.getType() instanceof XsdComplexType) { 1344 results = hasAttribute((XsdComplexType) element.getType()); 1345 if (results) { 1346 return results; 1347 } 1348 } 1349 } 1350 return results; 1351 } 1352 predefinedType(String name)1353 private static CppSimpleType predefinedType(String name) throws CppCodeGeneratorException { 1354 switch (name) { 1355 case "string": 1356 case "token": 1357 case "normalizedString": 1358 case "language": 1359 case "ENTITY": 1360 case "ID": 1361 case "Name": 1362 case "NCName": 1363 case "NMTOKEN": 1364 case "anyURI": 1365 case "anyType": 1366 case "QName": 1367 case "NOTATION": 1368 case "IDREF": 1369 return new CppSimpleType("std::string", "%s", false); 1370 case "ENTITIES": 1371 case "NMTOKENS": 1372 case "IDREFS": 1373 return new CppSimpleType("std::string", "%s", true); 1374 case "date": 1375 case "dateTime": 1376 case "time": 1377 case "gDay": 1378 case "gMonth": 1379 case "gYear": 1380 case "gMonthDay": 1381 case "gYearMonth": 1382 case "duration": 1383 return new CppSimpleType("std::string", "%s", false); 1384 case "decimal": 1385 return new CppSimpleType("double", "std::stod(%s)", false); 1386 case "integer": 1387 case "negativeInteger": 1388 case "nonNegativeInteger": 1389 case "positiveInteger": 1390 case "nonPositiveInteger": 1391 return new CppSimpleType("int64_t", "std::stoll(%s)", false); 1392 case "unsignedLong": 1393 return new CppSimpleType("uint64_t", "std::stoull(%s)", false); 1394 case "long": 1395 return new CppSimpleType("int64_t", "std::stoll(%s)", false); 1396 case "unsignedInt": 1397 return new CppSimpleType("unsigned int", 1398 "static_cast<unsigned int>(stoul(%s))", false); 1399 case "int": 1400 return new CppSimpleType("int", "std::stoi(%s)", false); 1401 case "unsignedShort": 1402 return new CppSimpleType("unsigned short", 1403 "static_cast<unsigned short>(std::stoi(%s))", false); 1404 case "short": 1405 return new CppSimpleType("short", "static_cast<short>(std::stoi(%s))", false); 1406 case "unsignedByte": 1407 return new CppSimpleType("unsigned char", 1408 "static_cast<unsigned char>(std::stoi(%s))", false); 1409 case "byte": 1410 return new CppSimpleType("char", "static_cast<char>(std::stoi(%s))", false); 1411 case "boolean": 1412 return new CppSimpleType("bool", "%s == \"true\"", false); 1413 case "double": 1414 return new CppSimpleType("double", "std::stod(%s)", false); 1415 case "float": 1416 return new CppSimpleType("float", "std::stof(%s)", false); 1417 case "base64Binary": 1418 case "hexBinary": 1419 return new CppSimpleType("std::string", "%s", false); 1420 } 1421 throw new CppCodeGeneratorException("unknown xsd predefined type : " + name); 1422 } 1423 } 1424