1 /** 2 * Copyright © 2008-2012 NetAllied Systems GmbH, Ravensburg, Germany. 3 * 4 * Licensed under the MIT Open Source License, 5 * for details please see LICENSE file or the website 6 * http://www.opensource.org/licenses/mit-license.php 7 */ 8 package de.netallied.xsd2cppsax; 9 10 import java.io.PrintStream; 11 import java.util.ArrayList; 12 import java.util.List; 13 import java.util.Map; 14 15 import org.apache.xerces.xs.StringList; 16 import org.apache.xerces.xs.XSAttributeUse; 17 import org.apache.xerces.xs.XSComplexTypeDefinition; 18 import org.apache.xerces.xs.XSConstants; 19 import org.apache.xerces.xs.XSElementDeclaration; 20 import org.apache.xerces.xs.XSModel; 21 import org.apache.xerces.xs.XSModelGroup; 22 import org.apache.xerces.xs.XSNamespaceItemList; 23 import org.apache.xerces.xs.XSObject; 24 import org.apache.xerces.xs.XSObjectList; 25 import org.apache.xerces.xs.XSParticle; 26 import org.apache.xerces.xs.XSSimpleTypeDefinition; 27 import org.apache.xerces.xs.XSTerm; 28 import org.apache.xerces.xs.XSTypeDefinition; 29 import org.apache.xerces.xs.XSWildcard; 30 31 import de.netallied.xsd2cppsax.TypeMapping.TypeMap; 32 33 /** 34 * Contains static utility methods. 35 * 36 */ 37 public class Util { 38 39 /** 40 * Calculates Hash. 41 * 42 * @param str 43 * String to hash. 44 * @return hash. 45 */ calculateHash(String str)46 static public String calculateHash(String str) { 47 long h = 0; 48 long g; 49 int pos = 0; 50 51 while (pos < str.length()) { 52 h = (h << 4) + str.charAt(pos++); 53 if ((g = (h & 0xf0000000)) != 0) 54 h ^= g >> 24; 55 h &= ~g; 56 } 57 return String.valueOf(h); 58 } 59 60 /** 61 * Collects attribute uses of given element. 62 * 63 * @param element 64 * Element to collect attributes for. 65 */ collectAttributeUses(XSElementDeclaration element)66 public static List<XSAttributeUse> collectAttributeUses(XSElementDeclaration element) { 67 XSTypeDefinition type = element.getTypeDefinition(); 68 if (type instanceof XSComplexTypeDefinition) { 69 XSComplexTypeDefinition complexType = (XSComplexTypeDefinition) type; 70 List<XSAttributeUse> attrList = objectListToList(complexType.getAttributeUses()); 71 return attrList; 72 } 73 return new ArrayList<XSAttributeUse>(); 74 } 75 76 /** 77 * Obtains pattern facet of simple type. 78 */ collectPatternFacet(XSSimpleTypeDefinition simpleType)79 public static String collectPatternFacet(XSSimpleTypeDefinition simpleType) { 80 String pattern = new String(); 81 StringList lexicalPatterns = simpleType.getLexicalPattern(); 82 83 // TODO check how to use multiple pattern values 84 // http://www.w3.org/TR/xmlschema11-2/#rf-pattern 85 // 4.3.4.2 XML Representation of pattern Schema Components 86 87 // for (int i = 0; i < lexicalPatterns.getLength(); i++) { 88 // pattern += lexicalPatterns.item(i); 89 // } 90 91 // for (int i = 0; i < lexicalPatterns.getLength(); i++) { 92 // if (i != 0) { 93 // // pattern = "|" + pattern; 94 // pattern = "&(" + pattern + ")"; 95 // } 96 // pattern += lexicalPatterns.item(i); 97 // } 98 99 // if (lexicalPatterns.getLength() > 0) { 100 // pattern = lexicalPatterns.item(0); 101 // } 102 103 if (lexicalPatterns.getLength() > 0) { 104 pattern = lexicalPatterns.item(lexicalPatterns.getLength() - 1); 105 } 106 107 return pattern; 108 } 109 110 /** 111 * Counts how many elements with same name have same type, too. 112 * 113 * @param elementUsage 114 * Element usage data of element to check. 115 * @param element 116 * Element to check. 117 * @return count. 118 */ countElementsWithSameType(ElementUsage elementUsage, XSElementDeclaration element)119 public static int countElementsWithSameType(ElementUsage elementUsage, XSElementDeclaration element) { 120 int elementsWithSameType = 0; 121 for (XSElementDeclaration siblingElement : elementUsage.getElements()) { 122 if (siblingElement.getTypeDefinition() == element.getTypeDefinition()) { 123 elementsWithSameType++; 124 } 125 } 126 return elementsWithSameType; 127 } 128 129 /** 130 * Creates C++ identifier (-> constant name) of attribute name hash. 131 * 132 * @param attrName 133 * Attribute Name to get identifier for. 134 * @return Identifier. 135 * @see CppConstantsCreator#createAttributeNameIdentifier(String) 136 */ createAttributeNameHashIdentifier(String attrName)137 public static String createAttributeNameHashIdentifier(String attrName) { 138 // don't use uppercase for constant names because of a name clash in plm 139 // xml 140 // element: Locator 141 // attrs: subtype and subType 142 return "HASH_ATTRIBUTE_" + attrName/* .toUpperCase() */; 143 } 144 145 /** 146 * Creates C++ name of constant to check if an attribute is present. 147 * 148 * @param attrUse 149 * Attribute to create C++ present constant name for. 150 */ createAttributePresentMaskName(XSAttributeUse attrUse, Config config)151 public static String createAttributePresentMaskName(XSAttributeUse attrUse, Config config) { 152 return "ATTRIBUTE_" + getAttributeName(attrUse, config).toUpperCase() + "_PRESENT"; 153 } 154 155 /** 156 * Creates name of C++ attributes struct. 157 * 158 * @param cppElementName 159 * C++ name of element. 160 * @param element 161 * XSD representation of element. 162 * @return struct name. 163 */ createAttributeStructName(String cppElementName, XSElementDeclaration element, Config config, Map<String, ElementUsage> completeElementUsage)164 public static String createAttributeStructName(String cppElementName, XSElementDeclaration element, Config config, 165 Map<String, ElementUsage> completeElementUsage) { 166 ElementUsage elementUsage = completeElementUsage.get(element.getName()); 167 int elementsWithSameType = countElementsWithSameType(elementUsage, element); 168 if (elementsWithSameType == elementUsage.getElements().size()) 169 return Util.replaceCharactersForbiddenInCppIdentifiers(element.getName()) 170 + config.getAttributeStructSuffix(); 171 return Util.replaceCharactersForbiddenInCppIdentifiers(cppElementName) + config.getAttributeStructSuffix(); 172 } 173 174 /** 175 * Creates name of begin element method 176 * 177 * @param cppName 178 * C++ element name. 179 * @return Method name. 180 */ createBeginConvenienceMethodName(String cppName, Config config)181 public static String createBeginConvenienceMethodName(String cppName, Config config) { 182 return config.getBeginMethodPrefix() + cppName; 183 } 184 185 /** 186 * Creates name of internal used begin element method 187 * 188 * @param cppName 189 * C++ element name. 190 * @return Method name. 191 */ createBeginInternalMethodName(String cppName, Config config)192 public static String createBeginInternalMethodName(String cppName, Config config) { 193 return "_" + createBeginConvenienceMethodName(cppName, config); 194 } 195 196 /** 197 * Creates name of a validation data struct member. Member is a child 198 * element, validation data struct is for a parent element. 199 * 200 * @param term 201 * XS Term to create member name for. 202 * @return C++ struct member name. 203 */ createComplexValidationDataStructMemberName(XSTerm term, Config config)204 public static String createComplexValidationDataStructMemberName(XSTerm term, Config config) { 205 String returnValue = null; 206 String nameFromConfig = config.getCppStructMemberNameMapping().get(term.getName()); 207 if (nameFromConfig != null) { 208 returnValue = nameFromConfig; 209 } else if (term instanceof XSWildcard) { 210 returnValue = config.getWildcardValidationDataStructName(); 211 } else { 212 returnValue = term.getName(); 213 } 214 return replaceCharactersForbiddenInCppIdentifiers(returnValue); 215 216 } 217 218 /** 219 * Creates method name of internal data method. 220 * 221 * @param cppName 222 * C++ name of element. 223 * @return Method name. 224 */ createDataInternalMethodName(String cppName)225 public static String createDataInternalMethodName(String cppName) { 226 return "_data__" + cppName; 227 } 228 229 /** 230 * Creates C++ identifier (-> constant name) of element name hash. 231 * 232 * @param elemName 233 * Element name (XSD or C++) to get identifier for. 234 * @return Identifier. 235 */ createElementNameHashIdentifier(String elemName)236 static public String createElementNameHashIdentifier(String elemName) { 237 return "HASH_ELEMENT_" + replaceCharactersForbiddenInCppIdentifiers(elemName).toUpperCase(); 238 } 239 240 /** 241 * Creates method name of C++ end element method. 242 * 243 * @param cppName 244 * C++ element name. 245 * @return Method name. 246 */ createEndConvenienceMethodName(String cppName, Config config)247 public static String createEndConvenienceMethodName(String cppName, Config config) { 248 return config.getEndMethodPrefix() + cppName; 249 } 250 251 /** 252 * Creates name of internal used end element method 253 * 254 * @param cppName 255 * C++ element name. 256 * @return Method name. 257 */ createEndInternalMethodName(String cppName, Config config)258 public static String createEndInternalMethodName(String cppName, Config config) { 259 return "_" + createEndConvenienceMethodName(cppName, config); 260 } 261 262 /** 263 * Creates name of enum count value. 264 * 265 * @param cppEnumTypeName 266 * Name of C++ enum type. 267 */ createEnumCountName(String cppEnumTypeName, Config config)268 public static String createEnumCountName(String cppEnumTypeName, Config config) { 269 return cppEnumTypeName + config.getElementNameDelimiter() + config.getEnumCountName(); 270 } 271 272 /** 273 * Creates name of enum convenience function characterData2EnumData. 274 * 275 * @param cppEnumTypeName 276 * C++ type name of enum. 277 * @return C++ function name. 278 */ createEnumFuncNameCharData(String cppEnumTypeName, Config config)279 public static String createEnumFuncNameCharData(String cppEnumTypeName, Config config) { 280 return config.getEnumFuncPrefixCharData() + cppEnumTypeName; 281 } 282 283 /** 284 * Creates name of enum convenience function dataEnumEnd. 285 * 286 * @param cppEnumTypeName 287 * C++ type name of enum. 288 * @return C++ function name. 289 */ createEnumFuncNameDataEnd(String cppEnumTypeName, Config config)290 public static String createEnumFuncNameDataEnd(String cppEnumTypeName, Config config) { 291 return config.getEnumFuncPrefixDataEnd() + cppEnumTypeName; 292 } 293 294 /** 295 * Creates name of enum convenience function toEnumDataPrefix. 296 * 297 * @param cppEnumTypeName 298 * C++ type name of enum. 299 * @return C++ function name. 300 */ createEnumFuncNameDataPrefix(String cppEnumTypeName, Config config)301 public static String createEnumFuncNameDataPrefix(String cppEnumTypeName, Config config) { 302 return config.getEnumFuncPrefixDataPrefix() + cppEnumTypeName; 303 } 304 305 /** 306 * Creates name of enum convenience function toEnum. 307 * 308 * @param cppEnumTypeName 309 * C++ type name of enum. 310 * @return C++ function name. 311 */ createEnumFuncNameToEnum(String cppEnumTypeName, Config config)312 public static String createEnumFuncNameToEnum(String cppEnumTypeName, Config config) { 313 return config.getEnumFuncPrefixToEnum() + cppEnumTypeName; 314 } 315 316 /** 317 * Creates name of enum map. 318 * 319 * @param cppEnumTypeName 320 * Name of C++ enum type. 321 */ createEnumMapName(String cppEnumTypeName, Config config)322 public static String createEnumMapName(String cppEnumTypeName, Config config) { 323 return cppEnumTypeName + config.getEnumMapNameSuffix(); 324 } 325 326 /** 327 * Creates name of enum NOT_PRESENT value. 328 * 329 * @param cppEnumTypeName 330 * Name of C++ enum type. 331 */ createEnumNotPresentName(String cppEnumTypeName, Config config)332 public static String createEnumNotPresentName(String cppEnumTypeName, Config config) { 333 return cppEnumTypeName + config.getElementNameDelimiter() + config.getEnumNotPresentName(); 334 } 335 336 /** 337 * Creates C++ name of one enum value. 338 * 339 * @param cppEnumTypeName 340 * Name of C++ enum type. 341 * @param enumValues 342 * Enum values to process. 343 * @param enumValue 344 * Enum value to create name for. 345 * @param type 346 * XSD type of enum. 347 */ createEnumValueName(String cppEnumTypeName, List<String> enumValues, int enumValue, XSSimpleTypeDefinition type, Config config)348 public static String createEnumValueName(String cppEnumTypeName, List<String> enumValues, int enumValue, 349 XSSimpleTypeDefinition type, Config config) { 350 String enumValueString = null; 351 if (isFloatType(type, config)) { 352 double tmp = Double.parseDouble(enumValues.get(enumValue)); 353 enumValueString = String.valueOf(tmp); 354 } else { 355 enumValueString = enumValues.get(enumValue); 356 } 357 return cppEnumTypeName + config.getElementNameDelimiter() 358 + Util.replaceCharactersForbiddenInCppIdentifiers(enumValueString); 359 } 360 361 /** 362 * Creates method name of freeAttributes method. 363 * 364 * @param cppName 365 * C++ name of element. 366 * @return Method name. 367 */ createFreeAttributesMethodName(String cppName)368 public static String createFreeAttributesMethodName(String cppName) { 369 return "_freeAttributes__" + cppName; 370 } 371 372 /** 373 * Creates C++ Constant name for a xml namespace. 374 * 375 * @param namespace 376 * Namespace to create constant for. 377 * @param baseName 378 * Part of name depending on constant's type. 379 * @param config 380 * Config. 381 * @return C++ name. 382 */ createNamespaceConstantName(String namespace, String baseName, Config config)383 protected static String createNamespaceConstantName(String namespace, String baseName, Config config) { 384 String nsPrefix = config.getXsNamespaceMapping().get(namespace); 385 if (nsPrefix != null) { 386 baseName += nsPrefix; 387 } else { 388 baseName += namespace; 389 } 390 return replaceCharactersForbiddenInCppIdentifiers(baseName); 391 392 } 393 394 /** 395 * Creates C++ hash constant name for a xml namespace. 396 * 397 * @param namespace 398 * Namespace to create constant for. 399 * @param config 400 * Config. 401 * @return C++ name. 402 */ createNamespaceHashConstantName(String namespace, Config config)403 public static String createNamespaceHashConstantName(String namespace, Config config) { 404 String name = "HASH_NAMESPACE_"; 405 return createNamespaceConstantName(namespace, name, config); 406 } 407 408 /** 409 * Creates C++ string constant name for a xml namespace. 410 * 411 * @param namespace 412 * Namespace to create constant for. 413 * @param config 414 * Config. 415 * @return C++ name. 416 */ createNamespaceStringConstantName(String namespace, Config config)417 public static String createNamespaceStringConstantName(String namespace, Config config) { 418 String name = "NAME_NAMESPACE_"; 419 return createNamespaceConstantName(namespace, name, config); 420 } 421 422 /** 423 * Creates method name of preBegin method. 424 * 425 * @param cppName 426 * C++ name of element. 427 * @return Method name. 428 */ createPreBeginMethodName(String cppName)429 public static String createPreBeginMethodName(String cppName) { 430 return "_preBegin__" + cppName; 431 } 432 433 /** 434 * Creates method name of preEnd method. 435 * 436 * @param cppName 437 * C++ name of element. 438 * @return Method name. 439 */ createPreEndMethodName(String cppName)440 public static String createPreEndMethodName(String cppName) { 441 return "_preEnd__" + cppName; 442 } 443 444 /** 445 * Creates C++ function name for validation function which validates data at 446 * end of stream. 447 * 448 * @param functionName 449 * Base validation function name of simple type. 450 * @return Function name. 451 */ createSimpleValidationStreamEndFunctionName(String functionName, Config config)452 public static String createSimpleValidationStreamEndFunctionName(String functionName, Config config) { 453 return functionName + config.getSimpleValidationFunctionStreamEndSuffix(); 454 } 455 456 /** 457 * Creates C++ function name for validation function which validates data in 458 * stream. 459 * 460 * @param functionName 461 * Base validation function name of simple type. 462 * @return Function name. 463 */ createSimpleValidationStreamFunctionName(String functionName, Config config)464 public static String createSimpleValidationStreamFunctionName(String functionName, Config config) { 465 return functionName + config.getSimpleValidationFunctionStreamSuffix(); 466 } 467 468 /** 469 * Creates name of union convenience function toUnion. 470 * 471 * @param cppUnionTypeName 472 * C++ type name of union. 473 * @return C++ function name. 474 */ createUnionFuncNameToUnion(String cppUnionTypeName, Config config)475 public static String createUnionFuncNameToUnion(String cppUnionTypeName, Config config) { 476 return config.getUnionFuncPrefixToUnion() + cppUnionTypeName; 477 } 478 479 /** 480 * Creates name of union convenience function toUnionPrefix. 481 * 482 * @param cppUnionTypeName 483 * C++ type name of union. 484 * @return C++ function name. 485 */ createUnionFuncNameToUnionPrefix(String cppUnionTypeName, Config config)486 public static String createUnionFuncNameToUnionPrefix(String cppUnionTypeName, Config config) { 487 return config.getUnionFuncPrefixToUnionPrefix() + cppUnionTypeName; 488 } 489 490 /** 491 * Creates method name of validateBegin method. 492 * 493 * @param cppName 494 * C++ name of element. 495 * @return Method name. 496 */ createValidateBeginMethodName(String cppName)497 public static String createValidateBeginMethodName(String cppName) { 498 return "_validateBegin__" + cppName; 499 } 500 501 /** 502 * Creates method name of validateEnd method. 503 * 504 * @param cppName 505 * C++ name of element. 506 * @return Method name. 507 */ createValidateEndMethodName(String cppName)508 public static String createValidateEndMethodName(String cppName) { 509 return "_validateEnd__" + cppName; 510 } 511 512 /** 513 * Finds build in type given type is derived from. 514 * 515 * @param type 516 * Type to find base type for. 517 * @return Base Type. 518 */ findBuildinBaseType(XSSimpleTypeDefinition type, Config config)519 static public XSSimpleTypeDefinition findBuildinBaseType(XSSimpleTypeDefinition type, Config config) { 520 if (type == null) { 521 return null; 522 } 523 Map<String, TypeMap> typeMapping = config.getTypeMapping(); 524 String namespace = type.getNamespace(); 525 String xsNamespace = config.getXSNamespace(); 526 if (typeMapping.containsKey(type.getName()) && namespace.equals(xsNamespace)) { 527 return type; 528 } else { 529 XSTypeDefinition baseType = type.getBaseType(); 530 XSSimpleTypeDefinition simpleBaseType = findSimpleTypeDefinition(baseType); 531 if (simpleBaseType != null) { 532 return findBuildinBaseType(simpleBaseType, config); 533 } else { 534 return null; 535 } 536 } 537 } 538 539 /** 540 * Finds C++ type as string. Takes care of simple and complex type, base 541 * types and variety. When variety is list, the item type is returned. 542 * 543 * @note {@link TemplateEngine#fillInTemplate(String, String, String, String, XSTypeDefinition)} 544 * has a copy of this code, as it requires temporary variables. 545 * @note {@link Generator#createDataConvenienceParameterList(XSTypeDefinition)} 546 * does something similar, too. 547 * @param type 548 * XSD type to find C++ type for. 549 * @return C++ type. 550 */ findCorrectCppAtomicType(XSTypeDefinition type, Config config)551 static public String findCorrectCppAtomicType(XSTypeDefinition type, Config config) { 552 XSSimpleTypeDefinition simpleType = Util.findSimpleTypeDefinition(type); 553 Variety variety = Util.findVariety(simpleType); 554 if (variety == Variety.LIST) { 555 simpleType = Util.findListItemType(simpleType); 556 } 557 String xsdType = Util.findXSDSimpleTypeString(simpleType, config); 558 559 return config.getTypeMapping().get(xsdType).getAttrAtomicType(); 560 } 561 562 /** 563 * @param type 564 * List type to find item type for. 565 * @return Item type of given list type. 566 */ findListItemType(XSSimpleTypeDefinition type)567 static public XSSimpleTypeDefinition findListItemType(XSSimpleTypeDefinition type) { 568 return type != null ? type.getItemType() : null; 569 } 570 571 /** 572 * Finds simple type. If given type is simple, it is returned. If given type 573 * is complex it's content type is returned. 574 * 575 * @param typeDefi 576 * Type to find simple type for. 577 * @return Simple type or null. 578 */ findSimpleTypeDefinition(XSTypeDefinition typeDefi)579 static public XSSimpleTypeDefinition findSimpleTypeDefinition(XSTypeDefinition typeDefi) { 580 if (typeDefi instanceof XSSimpleTypeDefinition) { 581 return (XSSimpleTypeDefinition) typeDefi; 582 } else if (typeDefi instanceof XSComplexTypeDefinition) { 583 XSComplexTypeDefinition complexType = (XSComplexTypeDefinition) typeDefi; 584 if (complexType.getSimpleType() == null 585 && complexType.getContentType() == XSComplexTypeDefinition.CONTENTTYPE_MIXED) { 586 return XSFactory.createXSAnyType(); 587 } 588 if (complexType.getSimpleType() != null) { 589 return complexType.getSimpleType(); 590 } else { 591 return findSimpleTypeDefinition(complexType.getBaseType()); 592 } 593 } 594 return null; 595 } 596 597 /** 598 * Finds target namespace of given model. 599 * 600 * @param model 601 * Model to find target namespace for. 602 * @return target namespace. 603 */ findTargetNamespace(XSModel model)604 public static String findTargetNamespace(XSModel model) { 605 XSNamespaceItemList namespaceItems = model.getNamespaceItems(); 606 if (namespaceItems.getLength() > 0) 607 return namespaceItems.item(0).getSchemaNamespace(); 608 return null; 609 } 610 611 /** 612 * Finds out variety of given type. 613 * 614 * @param type 615 * Type to find variety for. 616 * @return Variety. 617 */ findVariety(XSSimpleTypeDefinition type)618 static public Variety findVariety(XSSimpleTypeDefinition type) { 619 if (type == null) { 620 return Variety.ATOMIC; 621 } 622 switch (type.getVariety()) { 623 case XSSimpleTypeDefinition.VARIETY_LIST: 624 return Variety.LIST; 625 case XSSimpleTypeDefinition.VARIETY_UNION: 626 return Variety.UNION; 627 case XSSimpleTypeDefinition.VARIETY_ATOMIC: 628 default: 629 return Variety.ATOMIC; 630 } 631 } 632 633 /** 634 * Finds string representing xsd type. Takes care of base types. Result can 635 * be used to get C++ types or type conversions from config. 636 * 637 * @param typeDefi 638 * Type to find string for. 639 * @return String representing type. 640 */ findXSDSimpleTypeString(XSSimpleTypeDefinition simpleType, Config config)641 static public String findXSDSimpleTypeString(XSSimpleTypeDefinition simpleType, Config config) { 642 if (simpleType == null) { 643 // TODO check what happens here 644 // System.err.println("*** Try to find type for null"); 645 return Constants.DEFAULT_XSD_TYPE; 646 } 647 XSSimpleTypeDefinition baseType = findBuildinBaseType(simpleType, config); 648 if (baseType != null) { 649 return baseType.getName(); 650 } else { 651 // TODO check what happens here 652 // System.err.println("*** Could not find base type for: " + 653 // simpleType.getName()); 654 return Constants.DEFAULT_XSD_TYPE; 655 } 656 } 657 658 /** 659 * Finds attribute name of a attribute use. Takes care of C++ keywords. 660 */ getAttributeName(XSAttributeUse attrUse, Config config)661 public static String getAttributeName(XSAttributeUse attrUse, Config config) { 662 String tmpName = attrUse.getAttrDeclaration().getName(); 663 if (config != null) { 664 Map<String, String> attributeNameMapping = config.getCppStructMemberNameMapping(); 665 if (attributeNameMapping.containsKey(tmpName)) { 666 tmpName = attributeNameMapping.get(tmpName); 667 } 668 } 669 return replaceCharactersForbiddenInCppIdentifiers(tmpName); 670 } 671 672 /** 673 * Returns attribute name as in XSD (may clash with a C++ keyword). 674 */ getAttributeOriginalName(XSAttributeUse attrUse, Config config)675 public static String getAttributeOriginalName(XSAttributeUse attrUse, Config config) { 676 return attrUse.getAttrDeclaration().getName(); 677 } 678 679 /** 680 * If given type is a complex type it is returned as such. If not 681 * <code>null</code> is returned. 682 * 683 * @param type 684 * Type to check. 685 * @return Complex type or null. 686 */ getComplexType(XSTypeDefinition type)687 public static XSComplexTypeDefinition getComplexType(XSTypeDefinition type) { 688 689 // //////////////////////////////////////////////////////////////////// 690 // old version of this method: 691 // public XSComplexTypeDefinition getComplexType(XSTypeDefinition type) 692 // throws ClassCastException { 693 // return (XSComplexTypeDefinition) type; 694 // } 695 // That was used in early versions of max/maya plugins 696 // but it caused generation to abort too early. 697 // //////////////////////////////////////////////////////////////////// 698 699 if (type instanceof XSComplexTypeDefinition) 700 return (XSComplexTypeDefinition) type; 701 return null; 702 } 703 704 /** 705 * Find XSD type of given attribute. 706 * 707 * @param attrUse 708 * Attribute to find type for. 709 * @return Type of attribute. 710 */ getType(XSAttributeUse attrUse)711 public static XSSimpleTypeDefinition getType(XSAttributeUse attrUse) { 712 return attrUse.getAttrDeclaration().getTypeDefinition(); 713 } 714 715 /** 716 * Finds out if given attribute has a default value. 717 */ hasDefaultValue(XSAttributeUse attrUse)718 public static boolean hasDefaultValue(XSAttributeUse attrUse) { 719 short constraintType = attrUse.getConstraintType(); 720 if (constraintType == XSConstants.VC_DEFAULT || constraintType == XSConstants.VC_FIXED) { 721 return true; 722 } 723 return false; 724 } 725 726 /** 727 * Finds out if given type is an enum. 728 * 729 * @param simpleType 730 * Type to check. 731 * @return True if type is enum. 732 */ hasFacetEnum(XSSimpleTypeDefinition simpleType)733 public static boolean hasFacetEnum(XSSimpleTypeDefinition simpleType) { 734 return simpleType == null ? false 735 : (simpleType.getDefinedFacets() & XSSimpleTypeDefinition.FACET_ENUMERATION) == XSSimpleTypeDefinition.FACET_ENUMERATION; 736 } 737 738 /** 739 * Checks if given type has facets which need accumulation of character data 740 * length. 741 * 742 * @param simpleType 743 * Type to check. 744 * @return True if type has facets which need to be checked in stream. 745 */ hasStreamingFacets(XSSimpleTypeDefinition simpleType)746 static public boolean hasStreamingFacets(XSSimpleTypeDefinition simpleType) { 747 if (simpleType == null) { 748 return false; 749 } 750 short facets = simpleType.getDefinedFacets(); 751 if ((facets & XSSimpleTypeDefinition.FACET_LENGTH) == XSSimpleTypeDefinition.FACET_LENGTH) { 752 return true; 753 } 754 if ((facets & XSSimpleTypeDefinition.FACET_MINLENGTH) == XSSimpleTypeDefinition.FACET_MINLENGTH) { 755 return true; 756 } 757 if ((facets & XSSimpleTypeDefinition.FACET_MAXLENGTH) == XSSimpleTypeDefinition.FACET_MAXLENGTH) { 758 return true; 759 } 760 761 return false; 762 } 763 764 /** 765 * Finds out if given type has facets which are supported. 766 * 767 * @return True if type can be validated. 768 */ hasSupportedFacets(XSSimpleTypeDefinition simpleType, Config config)769 static public boolean hasSupportedFacets(XSSimpleTypeDefinition simpleType, Config config) { 770 short facets = simpleType.getDefinedFacets(); 771 if ((facets & XSSimpleTypeDefinition.FACET_WHITESPACE) == XSSimpleTypeDefinition.FACET_WHITESPACE) { 772 facets -= XSSimpleTypeDefinition.FACET_WHITESPACE; 773 } 774 if ((facets & XSSimpleTypeDefinition.FACET_TOTALDIGITS) == XSSimpleTypeDefinition.FACET_TOTALDIGITS) { 775 facets -= XSSimpleTypeDefinition.FACET_TOTALDIGITS; 776 } 777 if ((facets & XSSimpleTypeDefinition.FACET_FRACTIONDIGITS) == XSSimpleTypeDefinition.FACET_FRACTIONDIGITS) { 778 facets -= XSSimpleTypeDefinition.FACET_FRACTIONDIGITS; 779 } 780 781 if ((facets & XSSimpleTypeDefinition.FACET_MAXINCLUSIVE) == XSSimpleTypeDefinition.FACET_MAXINCLUSIVE) { 782 String cppType = Util.findCorrectCppAtomicType(simpleType, config); 783 String maxValue = config.getBuiltInTypeMaxValues().get(cppType); 784 if (maxValue != null) { 785 if (maxValue.equals(simpleType.getLexicalFacetValue(XSSimpleTypeDefinition.FACET_MAXINCLUSIVE))) { 786 facets -= XSSimpleTypeDefinition.FACET_MAXINCLUSIVE; 787 } 788 } 789 } 790 if ((facets & XSSimpleTypeDefinition.FACET_MININCLUSIVE) == XSSimpleTypeDefinition.FACET_MININCLUSIVE) { 791 String cppType = Util.findCorrectCppAtomicType(simpleType, config); 792 String minValue = config.getBuiltInTypeMinValues().get(cppType); 793 if (minValue != null) { 794 if (minValue.equals(simpleType.getLexicalFacetValue(XSSimpleTypeDefinition.FACET_MININCLUSIVE))) { 795 facets -= XSSimpleTypeDefinition.FACET_MININCLUSIVE; 796 } 797 } 798 } 799 800 if (!isFacetPatternSupported(simpleType, config)) { 801 if ((facets & XSSimpleTypeDefinition.FACET_PATTERN) == XSSimpleTypeDefinition.FACET_PATTERN) { 802 facets -= XSSimpleTypeDefinition.FACET_PATTERN; 803 } 804 } 805 806 return facets != XSSimpleTypeDefinition.FACET_NONE; 807 } 808 809 /** 810 * Finds out whether an attribute must be initialized after the memcpy call. 811 * 812 * @param attrUse 813 * Attribute to check. 814 * @param config 815 * Config. 816 * @return True if initialization is required, false otherwise. 817 */ isAttributeInitializationRequired(XSAttributeUse attrUse, Config config)818 public static boolean isAttributeInitializationRequired(XSAttributeUse attrUse, Config config) { 819 XSSimpleTypeDefinition type = getType(attrUse); 820 Variety variety = findVariety(type); 821 if (variety == Variety.LIST || variety == Variety.UNION) { 822 return true; 823 } else { 824 if (hasFacetEnum(type) || isStringType(type, config) || isNumericType(type, config) 825 || isBoolType(type, config)) { 826 return false; 827 } else { 828 // e.g. URI 829 return true; 830 } 831 } 832 } 833 834 /** 835 * Finds out if given type maps to C++ bool. 836 * 837 * @param type 838 * Type to check. 839 * @param config 840 * Configuration. 841 * @return True if type maps to C++ bool. 842 */ isBoolType(XSSimpleTypeDefinition type, Config config)843 public static boolean isBoolType(XSSimpleTypeDefinition type, Config config) { 844 String cppType = Util.findCorrectCppAtomicType(type, config); 845 return cppType.equals("bool"); 846 } 847 848 /** 849 * Finds out if given XSD type maps to C++ double. 850 * 851 * @see #isFloatType(XSSimpleTypeDefinition, Config) 852 */ isDouble(XSSimpleTypeDefinition type, Config config)853 public static boolean isDouble(XSSimpleTypeDefinition type, Config config) { 854 String cppType = Util.findCorrectCppAtomicType(type, config); 855 return cppType.equals("double"); 856 } 857 858 /** 859 * Finds out if facet pattern is supported for given type. 860 */ isFacetPatternSupported(XSSimpleTypeDefinition simpleType, Config config)861 public static boolean isFacetPatternSupported(XSSimpleTypeDefinition simpleType, Config config) { 862 Variety variety = findVariety(simpleType); 863 if (variety != Variety.ATOMIC) { 864 return false; 865 } 866 short facets = simpleType.getDefinedFacets(); 867 if ((facets & XSSimpleTypeDefinition.FACET_PATTERN) != XSSimpleTypeDefinition.FACET_PATTERN) { 868 return false; 869 } 870 if (hasFacetEnum(simpleType)) { 871 return false; 872 } 873 if (!isStringType(simpleType, config)) { 874 return false; 875 } else { 876 String pattern = collectPatternFacet(simpleType); 877 if (pattern.length() == 0) { 878 return false; 879 } 880 } 881 return true; 882 } 883 884 /** 885 * Finds out if given XSD type maps to C++ float. 886 * 887 * @see #isFloatType(XSSimpleTypeDefinition, Config) 888 */ isFloat(XSSimpleTypeDefinition type, Config config)889 public static boolean isFloat(XSSimpleTypeDefinition type, Config config) { 890 String cppType = Util.findCorrectCppAtomicType(type, config); 891 return cppType.equals("float"); 892 } 893 894 /** 895 * Finds out if given type is of float kind (C++ float or double). If given 896 * type uses variety list, it's itemtype is used. 897 * 898 * @param type 899 * Type to check 900 * @return True if type is of float kind. 901 */ isFloatType(XSSimpleTypeDefinition type, Config config)902 public static boolean isFloatType(XSSimpleTypeDefinition type, Config config) { 903 String cppType = Util.findCorrectCppAtomicType(type, config); 904 return cppType.equals("float") || cppType.equals("double"); 905 906 } 907 908 /** 909 * Finds out if given type is numeric. Works only for variety atomic. 910 */ isNumericType(XSSimpleTypeDefinition type, Config config)911 static public boolean isNumericType(XSSimpleTypeDefinition type, Config config) { 912 if (type != null && type.getNamespace() != null) { 913 if (type.getNamespace().equals(config.getXSNamespace()) && type.getName().equals("hexBinary")) { 914 return true; 915 } 916 } 917 return type == null ? false : type.getNumeric(); 918 } 919 920 /** 921 * Special stream end validation is required for list types with facets 922 * length or minLength. 923 */ isSpecialStreamEndValidationRequired(XSSimpleTypeDefinition simpleType)924 public static boolean isSpecialStreamEndValidationRequired(XSSimpleTypeDefinition simpleType) { 925 Variety variety = Util.findVariety(simpleType); 926 if (variety == Variety.LIST) { 927 short facets = simpleType.getDefinedFacets(); 928 if ((facets & XSSimpleTypeDefinition.FACET_LENGTH) == XSSimpleTypeDefinition.FACET_LENGTH) { 929 return true; 930 } 931 if ((facets & XSSimpleTypeDefinition.FACET_MINLENGTH) == XSSimpleTypeDefinition.FACET_MINLENGTH) { 932 return true; 933 } 934 } 935 return false; 936 } 937 938 /** 939 * Finds out if given type is of string kind. If given type uses variety 940 * list, it's itemtype is used. 941 * 942 * @param type 943 * Type to check 944 * @return True if type is of string kind. 945 */ isStringType(XSSimpleTypeDefinition type, Config config)946 public static boolean isStringType(XSSimpleTypeDefinition type, Config config) { 947 String cppType = Util.findCorrectCppAtomicType(type, config); 948 return cppType.equals(Constants.DEFAULT_CPP_TYPE); 949 } 950 951 /** 952 * Finds out if a member for unknown attributes in C++ AttributeData struct 953 * is required for given type. 954 * 955 * @param type 956 * XSD type to check. 957 * @return True if unknown attributes member is required. 958 */ isUnknownAttributesMemberRequired(XSTypeDefinition type)959 public static boolean isUnknownAttributesMemberRequired(XSTypeDefinition type) { 960 if (type instanceof XSComplexTypeDefinition) { 961 return ((XSComplexTypeDefinition) type).getAttributeWildcard() != null; 962 } 963 return false; 964 } 965 966 /** 967 * Finds out if given type may have char data. 968 */ mayHaveCharData(XSComplexTypeDefinition type, Config config)969 public static boolean mayHaveCharData(XSComplexTypeDefinition type, Config config) { 970 short contentType = type.getContentType(); 971 if (contentType == XSComplexTypeDefinition.CONTENTTYPE_SIMPLE 972 || contentType == XSComplexTypeDefinition.CONTENTTYPE_MIXED) { 973 return true; 974 } 975 if (type.getBaseType() != null) { 976 if (Constants.XSD_ANYTYPE_NAME.equals(type.getBaseType().getName()) 977 && config.getXSNamespace().equals(type.getBaseType().getNamespace())) { 978 return false; 979 } 980 return mayHaveCharData(type.getBaseType(), config); 981 } 982 return false; 983 } 984 985 /** 986 * Finds out if given type may have char data. 987 */ mayHaveCharData(XSTypeDefinition type, Config config)988 public static boolean mayHaveCharData(XSTypeDefinition type, Config config) { 989 if (type instanceof XSComplexTypeDefinition) { 990 return mayHaveCharData((XSComplexTypeDefinition) type, config); 991 } else if (type instanceof XSSimpleTypeDefinition) { 992 return true; 993 } 994 return false; 995 } 996 997 /** 998 * Finds out if given type may have child elements. 999 */ mayHaveChildElements(XSComplexTypeDefinition type, Config config)1000 public static boolean mayHaveChildElements(XSComplexTypeDefinition type, Config config) { 1001 if (type == null) { 1002 return false; 1003 } 1004 short contentType = type.getContentType(); 1005 if (contentType == XSComplexTypeDefinition.CONTENTTYPE_ELEMENT 1006 || contentType == XSComplexTypeDefinition.CONTENTTYPE_MIXED) { 1007 return true; 1008 } 1009 if (type.getBaseType() != null) { 1010 if (Constants.XSD_ANYTYPE_NAME.equals(type.getBaseType().getName()) 1011 && config.getXSNamespace().equals(type.getBaseType().getNamespace())) { 1012 return false; 1013 } 1014 return mayHaveChildElements(type.getBaseType(), config); 1015 } 1016 return false; 1017 } 1018 1019 /** 1020 * Finds out if given type may have child elements. 1021 */ mayHaveChildElements(XSTypeDefinition type, Config config)1022 public static boolean mayHaveChildElements(XSTypeDefinition type, Config config) { 1023 if (type instanceof XSComplexTypeDefinition) { 1024 return mayHaveChildElements((XSComplexTypeDefinition) type, config); 1025 } else { 1026 return false; 1027 } 1028 } 1029 1030 /** 1031 * Converts general {@link XSObjectList} to a {@link List}. 1032 * 1033 * @param objList 1034 * List to covert 1035 * @return Converted list. 1036 */ 1037 @SuppressWarnings("unchecked") objectListToList(XSObjectList objList)1038 public static <T extends XSObject> List<T> objectListToList(XSObjectList objList) { 1039 List<T> list = new ArrayList<T>(); 1040 for (int i = 0; i < objList.getLength(); i++) { 1041 list.add((T) objList.item(i)); 1042 } 1043 return list; 1044 } 1045 1046 /** 1047 * Finds out if it is necessary to crate a C++ present mask for given 1048 * attribute. 1049 */ presentMaskRequired(XSAttributeUse attrUse, Config config)1050 public static boolean presentMaskRequired(XSAttributeUse attrUse, Config config) { 1051 XSSimpleTypeDefinition type = getType(attrUse); 1052 Variety variety = findVariety(type); 1053 if (variety == Variety.LIST || variety == Variety.UNION) { 1054 return true; 1055 } else { 1056 if (hasFacetEnum(type)) { 1057 return false; 1058 } else if (isNumericType(type, config) || isBoolType(type, config)) { 1059 if (hasDefaultValue(attrUse)) { 1060 return false; 1061 } else { 1062 return true; 1063 } 1064 } else if (isStringType(type, config)) { 1065 return false; 1066 } else { 1067 return true; 1068 } 1069 } 1070 } 1071 1072 /** 1073 * Prints an entry of map containing element hash to namespace hash. 1074 * 1075 * @param mapVariableName 1076 * Name of C++ map. 1077 * @param elementHash 1078 * Hash constant or hash itself of element. 1079 * @param element 1080 * Element, needed to find out namespace. 1081 * @param stream 1082 * Stream to print map entry to. 1083 * @param config 1084 * Config. 1085 */ printElementToNamespaceMapEntry(String mapVariableName, String elementHash, XSElementDeclaration element, PrintStream stream, Config config)1086 public static void printElementToNamespaceMapEntry(String mapVariableName, String elementHash, 1087 XSElementDeclaration element, PrintStream stream, Config config) { 1088 stream.print(mapVariableName + "[" + elementHash + "] = "); 1089 String namespace = element.getNamespace(); 1090 String namespaceHash = null; 1091 if (namespace != null) { 1092 namespaceHash = createNamespaceHashConstantName(namespace, config); 1093 } else { 1094 namespaceHash = "0"; 1095 } 1096 1097 stream.println(namespaceHash + ";"); 1098 } 1099 1100 /** 1101 * Prints entry in function map for element. 1102 * 1103 * @param hashID 1104 * C++ constant for hash. 1105 * @param cppElementName 1106 * C++ element name. 1107 */ printFunctionMapEntry(String mapVariableName, String hashID, String cppElementName, PrintStream stream, Config config, boolean printFunctionStructNamespace)1108 public static void printFunctionMapEntry(String mapVariableName, String hashID, String cppElementName, 1109 PrintStream stream, Config config, boolean printFunctionStructNamespace) { 1110 stream.print(mapVariableName + "[" + hashID + "] = "); 1111 if (printFunctionStructNamespace) { 1112 stream.print(config.getClassNamePrivate() + "::"); 1113 } 1114 stream.print("FunctionStruct" + "("); 1115 1116 printFunctionMapEntryAddressStart(stream, config); 1117 stream.print(createBeginInternalMethodName(cppElementName, config) + ", "); 1118 printFunctionMapEntryAddressStart(stream, config); 1119 stream.print(createDataInternalMethodName(cppElementName) + ", "); 1120 printFunctionMapEntryAddressStart(stream, config); 1121 stream.print(createEndInternalMethodName(cppElementName, config) + ", "); 1122 printFunctionMapEntryAddressStart(stream, config); 1123 stream.print(createPreBeginMethodName(cppElementName) + ", "); 1124 printFunctionMapEntryAddressStart(stream, config); 1125 stream.print(createPreEndMethodName(cppElementName) + ", "); 1126 printFunctionMapEntryAddressStart(stream, config); 1127 stream.print(createFreeAttributesMethodName(cppElementName)); 1128 1129 stream.println(");"); 1130 } 1131 1132 /** 1133 * Prints beginning of address assignment of function map entry. 1134 */ printFunctionMapEntryAddressStart(PrintStream stream, Config config)1135 protected static void printFunctionMapEntryAddressStart(PrintStream stream, Config config) { 1136 stream.print("&" + config.getClassNamePrivate() + "::"); 1137 } 1138 1139 /** 1140 * Replaces characters in identifiers which are not allowed in C++. 1141 * 1142 * @param identifier 1143 * XSD identifier to check. 1144 * @return Identifier valid in C++. 1145 */ replaceCharactersForbiddenInCppIdentifiers(String identifier)1146 static public String replaceCharactersForbiddenInCppIdentifiers(String identifier) { 1147 if (identifier.contains(".")) { 1148 identifier = identifier.replace(".", "_"); 1149 } 1150 if (identifier.contains(":")) { 1151 identifier = identifier.replace(":", "_"); 1152 } 1153 if (identifier.contains("-")) { 1154 identifier = identifier.replace("-", "_M_"); 1155 } 1156 if (identifier.contains("+")) { 1157 identifier = identifier.replace("+", "_P_"); 1158 } 1159 if (identifier.contains("*")) { 1160 identifier = identifier.replace("*", "_"); 1161 } 1162 if (identifier.contains("/")) { 1163 identifier = identifier.replace("/", "_"); 1164 } 1165 if (identifier.contains(",")) { 1166 identifier = identifier.replace(",", "_"); 1167 } 1168 if (identifier.contains(" ")) { 1169 identifier = identifier.replace(" ", "_"); 1170 } 1171 return identifier; 1172 } 1173 1174 /** 1175 * Checks if given string contains one environment variable in the form 1176 * ${variable_name} and replaces it. 1177 * 1178 * @param str 1179 * String to check. 1180 * @return String with replaced environment variable. 1181 */ replaceEnvVar(String str)1182 public static String replaceEnvVar(String str) { 1183 if (str.contains("${")) { 1184 int envVarStartIndex = str.indexOf("${"); 1185 int envVarEndIndex = str.indexOf('}', envVarStartIndex); 1186 String envVarName = str.substring(envVarStartIndex + 2, envVarEndIndex); 1187 String envVarValue = System.getenv().get(envVarName); 1188 if (envVarValue != null) { 1189 str = str.replace("${" + envVarName + "}", envVarValue); 1190 } 1191 } 1192 return str; 1193 } 1194 1195 /** 1196 * Splits particles of a model group with compositor choice. 1197 * 1198 * @param modelGroup 1199 * Model group to split. 1200 * @param particle 1201 * Current particle. 1202 * @return List of siblings. 1203 */ splitParticlesForChoice(XSModelGroup modelGroup, XSParticle particle)1204 public static List<XSParticle> splitParticlesForChoice(XSModelGroup modelGroup, XSParticle particle) { 1205 List<XSParticle> siblings = new ArrayList<XSParticle>(); 1206 for (int i = 0; i < modelGroup.getParticles().getLength(); i++) { 1207 XSObject item = modelGroup.getParticles().item(i); 1208 if (item instanceof XSParticle) { 1209 XSParticle currentParticle = (XSParticle) item; 1210 if (currentParticle != particle) { 1211 siblings.add(currentParticle); 1212 } 1213 } 1214 } 1215 return siblings; 1216 } 1217 1218 /** 1219 * Splits particles of a model group with compositor sequence. 1220 * 1221 * @param modelGroup 1222 * Model group to split. 1223 * @param particle 1224 * Current particle. 1225 * @param previousSiblings 1226 * Output parameter. 1227 * @param followingSiblings 1228 * Output parameter. 1229 */ splitParticlesForSequence(XSModelGroup modelGroup, XSParticle particle, List<XSParticle> previousSiblings, List<XSParticle> followingSiblings)1230 public static void splitParticlesForSequence(XSModelGroup modelGroup, XSParticle particle, 1231 List<XSParticle> previousSiblings, List<XSParticle> followingSiblings) { 1232 boolean foundSelf = false; 1233 for (int i = 0; i < modelGroup.getParticles().getLength(); i++) { 1234 XSObject item = modelGroup.getParticles().item(i); 1235 if (item instanceof XSParticle) { 1236 XSParticle currentParticle = (XSParticle) item; 1237 if (!foundSelf) { 1238 if (currentParticle == particle) { 1239 foundSelf = true; 1240 } else { 1241 previousSiblings.add(currentParticle); 1242 } 1243 } else { 1244 followingSiblings.add(currentParticle); 1245 } 1246 } 1247 } 1248 } 1249 1250 /** 1251 * Converts StringList to List<String>. 1252 */ stringListToList(StringList stringList)1253 public static List<String> stringListToList(StringList stringList) { 1254 List<String> list = new ArrayList<String>(); 1255 for (int i = 0; i < stringList.getLength(); i++) { 1256 list.add(stringList.item(i)); 1257 } 1258 return list; 1259 } 1260 1261 /** 1262 * Checks if attribute is a XML special case and adds a namespace prefix if 1263 * necessary. 1264 * 1265 * @param elementNamespace 1266 * Namespace of element attribute is used in. 1267 * @param attr 1268 * Attribute. 1269 * @param attrName 1270 * Attribute name to use. May contain characters illegal in C++. 1271 */ updateAttributeNameWithNamespace(String elementNamespace, XSAttributeUse attr, String attrName)1272 static public String updateAttributeNameWithNamespace(String elementNamespace, XSAttributeUse attr, String attrName) { 1273 String attrStringValue = attrName; 1274 String attrNamespace = attr.getAttrDeclaration().getNamespace(); 1275 if (Constants.XML_BASE_NAMESPACE.equals(attrNamespace)) { 1276 if (!attrNamespace.equals(elementNamespace)) { 1277 attrStringValue = Constants.XML_BASE_NAMESPACE_PREFIX + ":" + attrName; 1278 } 1279 } 1280 return attrStringValue; 1281 } 1282 } 1283