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