com.beanit.asn1bean.compiler.BerClassWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of asn1bean-compiler Show documentation
Show all versions of asn1bean-compiler Show documentation
ASN1bean Compiler generates Java classes out of ASN.1 code that can be used to encode/decode BER data.
The newest version!
/*
* Copyright 2012 The ASN1bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.asn1bean.compiler;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beanit.asn1bean.ber.BerTag;
import com.beanit.asn1bean.ber.types.BerObjectIdentifier;
import com.beanit.asn1bean.compiler.model.AsnAny;
import com.beanit.asn1bean.compiler.model.AsnBitString;
import com.beanit.asn1bean.compiler.model.AsnBoolean;
import com.beanit.asn1bean.compiler.model.AsnCharacterString;
import com.beanit.asn1bean.compiler.model.AsnChoice;
import com.beanit.asn1bean.compiler.model.AsnClassNumber;
import com.beanit.asn1bean.compiler.model.AsnConstructedType;
import com.beanit.asn1bean.compiler.model.AsnDefinedType;
import com.beanit.asn1bean.compiler.model.AsnElementType;
import com.beanit.asn1bean.compiler.model.AsnEmbeddedPdv;
import com.beanit.asn1bean.compiler.model.AsnEnum;
import com.beanit.asn1bean.compiler.model.AsnInformationObjectClass;
import com.beanit.asn1bean.compiler.model.AsnInteger;
import com.beanit.asn1bean.compiler.model.AsnModule;
import com.beanit.asn1bean.compiler.model.AsnModule.TagDefault;
import com.beanit.asn1bean.compiler.model.AsnNull;
import com.beanit.asn1bean.compiler.model.AsnObjectIdentifier;
import com.beanit.asn1bean.compiler.model.AsnOctetString;
import com.beanit.asn1bean.compiler.model.AsnParameter;
import com.beanit.asn1bean.compiler.model.AsnReal;
import com.beanit.asn1bean.compiler.model.AsnSequenceOf;
import com.beanit.asn1bean.compiler.model.AsnSequenceSet;
import com.beanit.asn1bean.compiler.model.AsnTag;
import com.beanit.asn1bean.compiler.model.AsnTaggedType;
import com.beanit.asn1bean.compiler.model.AsnType;
import com.beanit.asn1bean.compiler.model.AsnUniversalType;
import com.beanit.asn1bean.compiler.model.AsnValueAssignment;
import com.beanit.asn1bean.compiler.model.SymbolsFromModule;
import com.beanit.asn1bean.util.HexString;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class BerClassWriter {
private static final Set reservedKeywords =
Collections.unmodifiableSet(
new TreeSet<>(
Arrays.asList(
"public",
"private",
"protected",
"final",
"void",
"int",
"short",
"float",
"double",
"long",
"byte",
"char",
"String",
"throw",
"throws",
"new",
"static",
"volatile",
"if",
"else",
"for",
"switch",
"case",
"enum",
"this",
"super",
"boolean",
"class",
"abstract",
"package",
"import",
"null",
"code",
"getClass",
"setClass")));
private static final Tag stdSeqTag = new Tag();
private static final Tag stdSetTag = new Tag();
static {
stdSeqTag.tagClass = TagClass.UNIVERSAL;
stdSeqTag.value = 16;
stdSeqTag.typeStructure = TypeStructure.CONSTRUCTED;
stdSetTag.tagClass = TagClass.UNIVERSAL;
stdSetTag.value = 17;
stdSetTag.typeStructure = TypeStructure.CONSTRUCTED;
}
private final String basePackageName;
private final boolean jaxbMode;
private final boolean accessExtended;
private final HashMap modulesByName;
private final boolean insertVersion;
private final String berTypeInterfaceString = "BerType, ";
BufferedWriter out;
private TagDefault tagDefault;
private boolean extensibilityImplied;
private File outputBaseDir;
private int indentNum = 0;
private AsnModule module;
private File outputDirectory;
BerClassWriter(
HashMap modulesByName,
String outputBaseDir,
String basePackageName,
boolean jaxbMode,
boolean disableWritingVersion,
boolean accessExtended) {
this.jaxbMode = jaxbMode;
this.accessExtended = accessExtended;
this.outputBaseDir = new File(outputBaseDir);
insertVersion = !disableWritingVersion;
if (basePackageName.isEmpty()) {
this.basePackageName = "";
} else {
this.outputBaseDir = new File(this.outputBaseDir, basePackageName.replace('.', '/'));
this.basePackageName = basePackageName + ".";
}
this.modulesByName = modulesByName;
}
private static String getBerTagParametersString(Tag tag) {
return "BerTag."
+ tag.tagClass
+ "_CLASS, BerTag."
+ tag.typeStructure.toString()
+ ", "
+ tag.value;
}
public void translate() throws IOException {
for (AsnModule module : modulesByName.values()) {
for (SymbolsFromModule symbolsFromModule : module.importSymbolFromModuleList) {
if (modulesByName.get(symbolsFromModule.modref) == null) {
throw new IOException(
"Module \""
+ module.moduleIdentifier.name
+ "\" imports missing module \""
+ symbolsFromModule.modref
+ "\".");
}
}
}
for (AsnModule module : modulesByName.values()) {
translateModule(module);
}
}
int[] toIntArray(List list) {
int[] ret = new int[list.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = list.get(i);
}
return ret;
}
public void translateModule(AsnModule module) throws IOException {
System.out.println("Generating classes for module \"" + module.moduleIdentifier.name + "\"");
outputDirectory =
new File(
outputBaseDir, moduleToPackageName(module.moduleIdentifier.name).replace('.', '/'));
this.module = module;
tagDefault = module.tagDefault;
extensibilityImplied = module.extensible;
for (AsnType typeDefinition : module.typesByName.values()) {
if (typeDefinition instanceof AsnDefinedType) {
if (getInformationObjectClass(((AsnDefinedType) typeDefinition).typeName, module) != null) {
continue;
}
}
String typeName = cleanUpName(typeDefinition.name);
writeClassHeader(typeName, module);
if (typeDefinition instanceof AsnTaggedType) {
AsnTaggedType asnTaggedType = (AsnTaggedType) typeDefinition;
Tag tag = getTag(asnTaggedType);
if (asnTaggedType.definedType != null) {
writeRetaggingTypeClass(
typeName, asnTaggedType.definedType.typeName, typeDefinition, tag);
} else {
AsnType assignedAsnType = asnTaggedType.typeReference;
if (assignedAsnType instanceof AsnConstructedType) {
writeConstructedTypeClass(typeName, assignedAsnType, tag, false, null);
} else {
writeRetaggingTypeClass(typeName, getBerType(assignedAsnType), typeDefinition, tag);
}
}
} else if (typeDefinition instanceof AsnDefinedType) {
writeRetaggingTypeClass(
typeName, ((AsnDefinedType) typeDefinition).typeName, typeDefinition, null);
} else if (typeDefinition instanceof AsnConstructedType) {
writeConstructedTypeClass(typeName, typeDefinition, null, false, null);
} else {
writeRetaggingTypeClass(typeName, getBerType(typeDefinition), typeDefinition, null);
}
out.close();
}
writeOidValues(module);
}
private void writeOidValues(AsnModule module) throws IOException {
boolean first = true;
List values = new ArrayList<>(module.asnValueAssignmentsByName.keySet());
Collections.sort(values);
for (String valueName : values) {
if (module.asnValueAssignmentsByName.get(valueName).type instanceof AsnObjectIdentifier) {
BerObjectIdentifier oid;
try {
oid = parseObjectIdentifierValue(valueName, module);
} catch (IllegalStateException e) {
System.out.println("Warning: could not parse object identifier value: " + e.getMessage());
continue;
}
StringBuilder sb =
new StringBuilder(
"public static final BerObjectIdentifier "
+ cleanUpName(valueName)
+ " = new BerObjectIdentifier(new int[]{");
if (first) {
first = false;
writeClassHeader("OidValues", module);
write("public final class OidValues {");
}
boolean firstOidComponent = true;
if (oid != null) {
for (int i : oid.value) {
if (firstOidComponent) {
firstOidComponent = false;
} else {
sb.append(", ");
}
sb.append(i);
}
}
sb.append("});");
write(sb.toString());
}
}
if (!first) {
write("}");
out.close();
}
}
private String moduleToPackageName(String moduleName) {
String[] moduleParts = moduleName.split("-", -1);
StringBuilder packageName = new StringBuilder();
for (String part : moduleParts) {
if (packageName.length() > 0) {
packageName.append(".");
}
packageName.append(sanitize(part.toLowerCase()));
}
return packageName.toString();
}
private BerObjectIdentifier parseObjectIdentifierValue(String name, AsnModule module) {
AsnValueAssignment valueAssignment = module.asnValueAssignmentsByName.get(name);
if (valueAssignment == null || !(valueAssignment.type instanceof AsnObjectIdentifier)) {
return null;
// throw new IOException(
// "no object identifier named \"" + name + "\" in module \"" + module.moduleIdentifier.name);
}
if (!valueAssignment.value.isValueInBraces) {
throw new IllegalStateException(
"value of object identifier \"" + valueAssignment.name + "\" is not defined in braces.");
}
List oidComponents = new ArrayList<>();
List tokens = valueAssignment.value.valueInBracesTokens;
for (int i = 0; i < tokens.size(); i++) {
String token = tokens.get(i);
if (Character.isDigit(token.charAt(0))) {
oidComponents.add(Integer.parseInt(token));
} else if (Character.isLetter(token.charAt(0))) {
if ((tokens.size() == i + 1) || !tokens.get(i + 1).equals("(")) {
// this is either a value reference of another object identifier or a registered name
if (!parseRegisteredOidComponentName(oidComponents, token)) {
BerObjectIdentifier oid = parseObjectIdentifierValue(token, module);
if (oid == null) {
for (SymbolsFromModule symbolsFromModule : module.importSymbolFromModuleList) {
for (String importedTypeName : symbolsFromModule.symbolList) {
if (token.equals(importedTypeName)) {
oid =
parseObjectIdentifierValue(
token, modulesByName.get(symbolsFromModule.modref));
}
}
}
}
if (oid == null) {
throw new IllegalStateException(
"AsnValueAssignment \""
+ token
+ "\" was not found in module \""
+ module.moduleIdentifier.name
+ "\"");
}
for (int element : oid.value) {
oidComponents.add(element);
}
}
}
}
}
return new BerObjectIdentifier(toIntArray(oidComponents));
}
private boolean parseRegisteredOidComponentName(List oidComponents, String token) {
if (oidComponents.size() == 0) {
switch (token) {
case "itu-t":
case "ccitt":
oidComponents.add(0);
return true;
case "iso":
oidComponents.add(1);
return true;
case "joint-iso-itu-t":
case "joint-iso-ccitt":
oidComponents.add(2);
return true;
}
} else if (oidComponents.size() == 1) {
switch (oidComponents.get(0)) {
case 0:
switch (token) {
case "recommendation":
oidComponents.add(0);
return true;
case "question":
oidComponents.add(1);
return true;
case "administration":
oidComponents.add(2);
return true;
case "network-operator":
oidComponents.add(3);
return true;
case "identified-organization":
oidComponents.add(4);
return true;
}
break;
case 1:
switch (token) {
case "standard":
oidComponents.add(0);
return true;
case "registration-authority":
oidComponents.add(1);
return true;
case "member-body":
oidComponents.add(2);
return true;
case "identified-organization":
oidComponents.add(3);
return true;
}
}
}
return false;
}
/**
* Gets the tag from the AsnTaggedType structure. The returned tag will contain the correct class
* and type (explicit or implicit). Return null if the passed tagged type does not have a tag.
*
* @param asnTaggedType the tagged type
* @return the tag from the AsnTaggedType structure
*/
private Tag getTag(AsnTaggedType asnTaggedType) {
AsnTag asnTag = asnTaggedType.tag;
if (asnTag == null) {
return null;
}
Tag tag = new Tag();
String tagClassString = asnTag.clazz;
if (tagClassString.isEmpty() || "CONTEXT".equals(tagClassString)) {
tag.tagClass = TagClass.CONTEXT;
} else if ("APPLICATION".equals(tagClassString)) {
tag.tagClass = TagClass.APPLICATION;
} else if ("PRIVATE".equals(tagClassString)) {
tag.tagClass = TagClass.PRIVATE;
} else if ("UNIVERSAL".equals(tagClassString)) {
tag.tagClass = TagClass.UNIVERSAL;
} else {
throw new IllegalStateException("unknown tag class: " + tagClassString);
}
String tagTypeString = asnTaggedType.tagType;
if (tagTypeString.isEmpty()) {
if (tagDefault == TagDefault.EXPLICIT) {
tag.type = TagType.EXPLICIT;
} else {
tag.type = TagType.IMPLICIT;
}
} else if (tagTypeString.equals("IMPLICIT")) {
tag.type = TagType.IMPLICIT;
} else if (tagTypeString.equals("EXPLICIT")) {
tag.type = TagType.EXPLICIT;
} else {
throw new IllegalStateException("unexpected tag type: " + tagTypeString);
}
if (tag.type == TagType.IMPLICIT) {
if (isDirectAnyOrChoice(asnTaggedType)) {
tag.type = TagType.EXPLICIT;
}
}
if ((tag.type == TagType.IMPLICIT) && isPrimitive(asnTaggedType)) {
tag.typeStructure = TypeStructure.PRIMITIVE;
} else {
tag.typeStructure = TypeStructure.CONSTRUCTED;
}
tag.value = asnTaggedType.tag.classNumber.num;
return tag;
}
private String cleanUpName(String name) {
name = replaceCharByCamelCase(name, '-');
name = replaceCharByCamelCase(name, '_');
return sanitize(name);
}
private String sanitize(String name) {
if (name.isEmpty()) return name;
String result = replaceCharByCamelCase(name, '.');
if (Character.isDigit(result.charAt(0))) {
result = "_" + result;
}
if (reservedKeywords.contains(result)) {
result += "_";
}
return result;
}
private String replaceCharByCamelCase(String name, char charToBeReplaced) {
StringBuilder nameSb = new StringBuilder(name);
int index = name.indexOf(charToBeReplaced);
while (index != -1 && index != (name.length() - 1)) {
if (!Character.isUpperCase(name.charAt(index + 1))) {
nameSb.setCharAt(index + 1, Character.toUpperCase(name.charAt(index + 1)));
}
index = name.indexOf(charToBeReplaced, index + 1);
}
name = nameSb.toString();
name = name.replace("" + charToBeReplaced, "");
return name;
}
private void writeConstructedTypeClass(
String className,
AsnType asnType,
Tag tag,
boolean asInternalClass,
List listOfSubClassNames)
throws IOException {
if (listOfSubClassNames == null) {
listOfSubClassNames = new ArrayList<>();
}
String isStaticStr = "";
if (asInternalClass) {
isStaticStr = " static";
}
if (asnType instanceof AsnSequenceSet) {
writeSequenceOrSetClass(
className, (AsnSequenceSet) asnType, tag, isStaticStr, listOfSubClassNames);
} else if (asnType instanceof AsnSequenceOf) {
writeSequenceOfClass(
className, (AsnSequenceOf) asnType, tag, isStaticStr, listOfSubClassNames);
} else if (asnType instanceof AsnChoice) {
writeChoiceClass(className, (AsnChoice) asnType, tag, isStaticStr, listOfSubClassNames);
}
}
private void writeChoiceClass(
String className,
AsnChoice asn1TypeElement,
Tag tag,
String isStaticStr,
List listOfSubClassNames)
throws IOException {
write(
"public"
+ isStaticStr
+ " class "
+ className
+ " implements "
+ berTypeInterfaceString
+ "Serializable {\n");
write("private static final long serialVersionUID = 1L;\n");
write("private byte[] code = null;");
if (tag != null) {
write(
"public static final BerTag tag = new BerTag(" + getBerTagParametersString(tag) + ");\n");
}
List componentTypes = asn1TypeElement.componentTypes;
addAutomaticTagsIfNeeded(componentTypes);
if (asn1TypeElement.parameters != null) {
List parameters = asn1TypeElement.parameters;
replaceParametersByAnyTypes(componentTypes, parameters);
}
for (AsnElementType componentType : componentTypes) {
if ((componentType.typeReference instanceof AsnConstructedType)) {
listOfSubClassNames.add(getClassName(componentType, className));
}
}
for (AsnElementType componentType : componentTypes) {
if (isInnerType(componentType)) {
String subClassName = getClassName(componentType, className);
writeConstructedTypeClass(
subClassName, componentType.typeReference, null, true, listOfSubClassNames);
}
}
setClassNamesOfComponents(listOfSubClassNames, componentTypes, className);
writeMembers(componentTypes);
writeEmptyConstructor(className);
if (!jaxbMode) {
writeEncodeConstructor(className, componentTypes);
}
if (jaxbMode) {
writeGetterAndSetter(componentTypes);
}
writeChoiceEncodeFunction(componentTypes, tag != null);
writeChoiceDecodeMethod(convertToComponentInfos(componentTypes), tag != null);
writeEncodeAndSaveFunction(tag == null);
writeChoiceToStringFunction(componentTypes);
write("}\n");
}
private void setClassNamesOfComponents(
List listOfSubClassNames, List componentTypes, String parentClass) {
for (AsnElementType element : componentTypes) {
element.className = getClassName(listOfSubClassNames, element, parentClass);
}
}
private String getClassName(AsnElementType asnElementType) {
if (!asnElementType.className.equals("")) {
return asnElementType.className;
}
return getClassName(null, asnElementType, null);
}
private String getClassName(AsnElementType asnElementType, String parentClass) {
if (!asnElementType.className.isEmpty()) {
return asnElementType.className;
}
return getClassName(null, asnElementType, parentClass);
}
private String getClassName(
List listOfSubClassNames, AsnTaggedType element, String parentClass) {
if (listOfSubClassNames == null) {
listOfSubClassNames = new ArrayList<>();
}
if (element.typeReference == null) {
if (element.definedType.isObjectClassField) {
AsnInformationObjectClass informationObjectClass =
getInformationObjectClass(element.definedType.moduleOrObjectClassReference, module);
if (informationObjectClass == null) {
throw new CompileException(
"no information object class of name \""
+ element.definedType.moduleOrObjectClassReference
+ "\" found in asn.1 module "
+ module.moduleIdentifier.name);
}
for (AsnElementType elementType : informationObjectClass.elementList) {
if (elementType.name.equals(element.definedType.typeName)) {
return getClassName(listOfSubClassNames, elementType, parentClass);
}
}
throw new IllegalStateException(
"Could not find field \""
+ element.definedType.typeName
+ "\" of information object class \""
+ element.definedType.moduleOrObjectClassReference
+ "\"");
} else {
String cleanedUpClassName = cleanUpName(element.definedType.typeName);
for (String subClassName : listOfSubClassNames) {
if (subClassName.equals(cleanedUpClassName)) {
String moduleName = module.moduleIdentifier.name;
for (SymbolsFromModule symbols : this.module.importSymbolFromModuleList) {
if (symbols.symbolList.contains(element.definedType.typeName)) {
moduleName = symbols.modref;
break;
}
}
return basePackageName + moduleToPackageName(moduleName) + "." + cleanedUpClassName;
}
}
return cleanedUpClassName;
}
} else {
AsnType typeDefinition = element.typeReference;
if (typeDefinition instanceof AsnConstructedType) {
String cleanedUpName = cleanUpName(capitalizeFirstCharacter(element.name));
if (parentClass != null) {
if (cleanedUpName.equals(parentClass)) {
cleanedUpName = cleanedUpName + "_";
}
}
return cleanedUpName;
} else {
return getBerType(typeDefinition);
}
}
}
private AsnInformationObjectClass getInformationObjectClass(
String objectClassReference, AsnModule module) {
AsnInformationObjectClass ioClass = module.objectClassesByName.get(objectClassReference);
if (ioClass == null) {
AsnType asnType = module.typesByName.get(objectClassReference);
if (asnType == null) {
for (SymbolsFromModule symbolsFromModule : module.importSymbolFromModuleList) {
for (String importedTypeName : symbolsFromModule.symbolList) {
if (objectClassReference.equals(importedTypeName)) {
return getInformationObjectClass(
objectClassReference, getAsnModule(symbolsFromModule.modref));
}
}
}
return null;
} else {
if (asnType instanceof AsnDefinedType) {
// error handling: if the reference and the type name are the same, this is an infinite
// loop
if (objectClassReference.equals(((AsnDefinedType) asnType).typeName)) {
throw new CompileException(
"Self reference "
+ objectClassReference
+ " to "
+ ((AsnDefinedType) asnType).typeName);
}
return getInformationObjectClass(((AsnDefinedType) asnType).typeName, module);
}
}
}
return ioClass;
}
private void writeSequenceOrSetClass(
String className,
AsnSequenceSet asnSequenceSet,
Tag tag,
String isStaticStr,
List listOfSubClassNames)
throws IOException {
write(
"public"
+ isStaticStr
+ " class "
+ className
+ " implements "
+ berTypeInterfaceString
+ "Serializable {\n");
write("private static final long serialVersionUID = 1L;\n");
List componentTypes = asnSequenceSet.componentTypes;
addAutomaticTagsIfNeeded(componentTypes);
if (asnSequenceSet.parameters != null) {
List parameters = asnSequenceSet.parameters;
replaceParametersByAnyTypes(componentTypes, parameters);
}
for (AsnElementType componentType : componentTypes) {
if ((componentType.typeReference instanceof AsnConstructedType)) {
listOfSubClassNames.add(getClassName(componentType));
}
}
for (AsnElementType componentType : componentTypes) {
if (isInnerType(componentType)) {
String subClassName = getClassName(componentType, className);
writeConstructedTypeClass(
subClassName, componentType.typeReference, null, true, listOfSubClassNames);
}
}
Tag mainTag;
if (tag == null) {
if (asnSequenceSet.isSequence) {
mainTag = stdSeqTag;
} else {
mainTag = stdSetTag;
}
} else {
mainTag = tag;
}
write(
"public static final BerTag tag = new BerTag("
+ getBerTagParametersString(mainTag)
+ ");\n");
write("private byte[] code = null;");
setClassNamesOfComponents(listOfSubClassNames, componentTypes, className);
writeMembers(componentTypes);
if (asnSequenceSet.isSequence && accessExtended && extensibilityImplied) {
String accessModifierString = jaxbMode ? "private" : "public";
write(accessModifierString + " byte[] extensionBytes = null;");
}
writeEmptyConstructor(className);
if (jaxbMode) {
writeGetterAndSetter(componentTypes);
if (asnSequenceSet.isSequence && accessExtended && extensibilityImplied) {
write("public byte[] getExtensionBytes() {");
write("return extensionBytes;");
write("}\n");
write("public void setExtensionBytes(byte[] bytes) {");
write("this.extensionBytes = bytes;");
write("}\n");
}
} else {
writeEncodeConstructor(className, componentTypes);
}
boolean hasExplicitTag = (tag != null) && (tag.type == TagType.EXPLICIT);
writeSimpleEncodeFunction();
writeSequenceOrSetEncodeFunction(componentTypes, hasExplicitTag, asnSequenceSet.isSequence);
writeSimpleDecodeFunction("true");
if (asnSequenceSet.isSequence) {
writeSequenceDecodeMethod(convertToComponentInfos(componentTypes), hasExplicitTag);
} else {
writeSetDecodeFunction(convertToComponentInfos(componentTypes), hasExplicitTag);
}
writeEncodeAndSaveFunction();
writeSequenceOrSetToStringFunction(componentTypes);
write("}\n");
}
private List convertToComponentInfos(List asnElementTypes) {
int lastRequiredComponentIndex = getLastRequiredComponentIndex(asnElementTypes);
List componentInfos = new ArrayList<>(asnElementTypes.size());
int i = 0;
for (AsnElementType asnElementType : asnElementTypes) {
boolean mayBeLastComponent = lastRequiredComponentIndex <= i;
componentInfos.add(convertToComponentInfo(asnElementType, mayBeLastComponent, null));
i++;
}
return componentInfos;
}
private ComponentInfo convertToComponentInfo(
AsnElementType asnElementType, boolean mayBeLastComponent, String sequenceOrSetOfClassName) {
String variableName = getVariableName(asnElementType);
String className;
if (sequenceOrSetOfClassName != null) {
className = sequenceOrSetOfClassName;
} else {
className = getClassName(asnElementType);
}
Tag componentTag = getTag(asnElementType);
boolean isOptional = isOptional(asnElementType);
boolean isUntaggedAnyOrChoice = isDirectAnyOrChoice(asnElementType);
return new ComponentInfo(
variableName,
className,
componentTag,
mayBeLastComponent,
isOptional,
isUntaggedAnyOrChoice);
}
private void replaceParametersByAnyTypes(
List componentTypes, List parameters) {
for (AsnParameter parameter : parameters) {
if (parameter.paramGovernor == null) {
for (AsnElementType componentType : componentTypes) {
if (componentType.definedType != null
&& componentType.definedType.typeName.equals(parameter.dummyReference)) {
componentType.typeReference = new AsnAny();
componentType.definedType = null;
componentType.isDefinedType = false;
}
}
}
}
}
private void writeSimpleDecodeFunction(String param) throws IOException {
write("@Override public int decode(InputStream is) throws IOException {");
write("return decode(is, " + param + ");");
write("}\n");
}
private void writeSimpleEncodeFunction() throws IOException {
write("@Override public int encode(OutputStream reverseOS) throws IOException {");
write("return encode(reverseOS, true);");
write("}\n");
}
private void writeSequenceOfClass(
String className,
AsnSequenceOf asnSequenceOf,
Tag tag,
String isStaticStr,
List listOfSubClassNames)
throws IOException {
write(
"public"
+ isStaticStr
+ " class "
+ className
+ " implements "
+ berTypeInterfaceString
+ "Serializable {\n");
write("private static final long serialVersionUID = 1L;\n");
AsnElementType componentType = asnSequenceOf.componentType;
String referencedTypeName = getClassNameOfSequenceOfElement(componentType, listOfSubClassNames);
if (isInnerType(componentType)) {
writeConstructedTypeClass(
referencedTypeName, componentType.typeReference, null, true, listOfSubClassNames);
}
Tag mainTag;
if (tag == null) {
if (asnSequenceOf.isSequenceOf) {
mainTag = stdSeqTag;
} else {
mainTag = stdSetTag;
}
} else {
mainTag = tag;
}
write(
"public static final BerTag tag = new BerTag(" + getBerTagParametersString(mainTag) + ");");
write("private byte[] code = null;");
if (jaxbMode) {
write("private List<" + referencedTypeName + "> seqOf = null;\n");
} else {
write("public List<" + referencedTypeName + "> seqOf = null;\n");
}
write("public " + className + "() {");
write("seqOf = new ArrayList<>();");
write("}\n");
write("public " + className + "(byte[] code) {");
write("this.code = code;");
write("}\n");
if (!jaxbMode) {
write("public " + className + "(List<" + referencedTypeName + "> seqOf) {");
write("this.seqOf = seqOf;");
write("}\n");
}
if (jaxbMode) {
writeGetterForSeqOf(referencedTypeName);
}
boolean hasExplicitTag = (tag != null) && (tag.type == TagType.EXPLICIT);
writeSimpleEncodeFunction();
writeSequenceOfEncodeFunction(componentType, hasExplicitTag, asnSequenceOf.isSequenceOf);
writeSimpleDecodeFunction("true");
writeSequenceOrSetOfDecodeFunction(
convertToComponentInfo(componentType, false, referencedTypeName),
hasExplicitTag,
asnSequenceOf.isSequenceOf);
writeEncodeAndSaveFunction();
writeSequenceOrSetOfToStringFunction(referencedTypeName, componentType);
write("}\n");
}
private void writeRetaggingTypeClass(
String typeName, String assignedTypeName, AsnType typeDefinition, Tag tag)
throws IOException {
write("public class " + typeName + " extends " + cleanUpName(assignedTypeName) + " {\n");
write("private static final long serialVersionUID = 1L;\n");
String[] constructorParameters = getConstructorParameters(getUniversalType(typeDefinition));
if (tag != null) {
write(
"public static final BerTag tag = new BerTag(" + getBerTagParametersString(tag) + ");\n");
}
if (constructorParameters.length != 2 || !constructorParameters[0].equals("byte[]")) {
if (tag != null) {
write("private byte[] code = null;\n");
}
}
write("public " + typeName + "() {");
write("}\n");
if (constructorParameters.length != 2 || !constructorParameters[0].equals("byte[]")) {
write("public " + typeName + "(byte[] code) {");
if (tag != null) {
write("this.code = code;");
} else {
write("super(code);");
}
write("}\n");
}
if ((!jaxbMode || isPrimitiveOrRetaggedPrimitive(typeDefinition))
&& (constructorParameters.length != 0)) {
StringBuilder constructorParameterString = new StringBuilder();
StringBuilder superCallParameterString = new StringBuilder();
for (int i = 0; i < constructorParameters.length; i += 2) {
if (i > 0) {
constructorParameterString.append(", ");
superCallParameterString.append(", ");
}
constructorParameterString
.append(constructorParameters[i])
.append(" ")
.append(constructorParameters[i + 1]);
superCallParameterString.append(constructorParameters[i + 1]);
}
write("public " + typeName + "(" + constructorParameterString + ") {");
write("super(" + superCallParameterString + ");");
write("}\n");
if (constructorParameters[0].equals("BigInteger")) {
write("public " + typeName + "(long value) {");
write("super(value);");
write("}\n");
} else if (constructorParameters.length == 4 && constructorParameters[3].equals("numBits")) {
write("public " + typeName + "(boolean[] value) {");
write("super(value);");
write("}\n");
}
}
if (tag != null) {
String overrideAnnotationString = "@Override ";
if (isDirectAnyOrChoice((AsnTaggedType) typeDefinition)) {
writeSimpleEncodeFunction();
overrideAnnotationString = "";
}
write(
overrideAnnotationString
+ "public int encode(OutputStream reverseOS, boolean withTag) throws IOException {\n");
if (constructorParameters.length != 2 || !constructorParameters[0].equals("byte[]")) {
writeEncodingIfCodeIsNull();
}
write("int codeLength;\n");
if (tag.type == TagType.EXPLICIT) {
if (isDirectAnyOrChoice((AsnTaggedType) typeDefinition)) {
write("codeLength = super.encode(reverseOS);");
} else {
write("codeLength = super.encode(reverseOS, true);");
}
write("codeLength += BerLength.encodeLength(reverseOS, codeLength);");
} else {
write("codeLength = super.encode(reverseOS, false);");
}
write("if (withTag) {");
write("codeLength += tag.encode(reverseOS);");
write("}\n");
write("return codeLength;");
write("}\n");
if (isDirectAnyOrChoice((AsnTaggedType) typeDefinition)) {
writeSimpleDecodeFunction("true");
}
write(
overrideAnnotationString
+ "public int decode(InputStream is, boolean withTag) throws IOException {\n");
write("int codeLength = 0;\n");
write("if (withTag) {");
write("codeLength += tag.decodeAndCheck(is);");
write("}\n");
if (tag.type == TagType.EXPLICIT) {
write("BerLength length = new BerLength();");
write("codeLength += length.decode(is);\n");
if (isDirectAnyOrChoice((AsnTaggedType) typeDefinition)) {
write("codeLength += super.decode(is, null);");
} else {
write("codeLength += super.decode(is, true);");
}
write("codeLength += length.readEocIfIndefinite(is);\n");
} else {
write("codeLength += super.decode(is, false);\n");
}
write("return codeLength;");
write("}\n");
}
write("}");
}
private void writeEncodingIfCodeIsNull() throws IOException {
write("if (code != null) {");
write("reverseOS.write(code);");
write("if (withTag) {");
write("return tag.encode(reverseOS) + code.length;");
write("}");
write("return code.length;");
write("}\n");
}
private void writeChoiceEncodeFunction(
List componentTypes, boolean hasExplicitTag) throws IOException {
if (hasExplicitTag) {
writeSimpleEncodeFunction();
write("public int encode(OutputStream reverseOS, boolean withTag) throws IOException {\n");
} else {
write("@Override public int encode(OutputStream reverseOS) throws IOException {\n");
}
write("if (code != null) {");
write("reverseOS.write(code);");
if (hasExplicitTag) {
write("if (withTag) {");
write("return tag.encode(reverseOS) + code.length;");
write("}");
}
write("return code.length;");
write("}\n");
write("int codeLength = 0;");
for (int j = componentTypes.size() - 1; j >= 0; j--) {
if (isExplicit(getTag(componentTypes.get(j)))) {
write("int sublength;\n");
break;
}
}
for (int j = componentTypes.size() - 1; j >= 0; j--) {
AsnElementType componentType = componentTypes.get(j);
Tag componentTag = getTag(componentType);
write("if (" + getVariableName(componentType) + " != null) {");
String explicitEncoding = getExplicitEncodingParameter(componentType);
if (isExplicit(componentTag)) {
write(
"sublength = "
+ getVariableName(componentType)
+ ".encode(reverseOS"
+ explicitEncoding
+ ");");
write("codeLength += sublength;");
write("codeLength += BerLength.encodeLength(reverseOS, sublength);");
} else {
write(
"codeLength += "
+ getVariableName(componentType)
+ ".encode(reverseOS"
+ explicitEncoding
+ ");");
}
if (componentTag != null) {
writeEncodeTag(componentTag);
}
if (hasExplicitTag) {
write("codeLength += BerLength.encodeLength(reverseOS, codeLength);");
write("if (withTag) {");
write("codeLength += tag.encode(reverseOS);");
write("}");
}
write("return codeLength;");
write("}");
write("");
}
write("throw new IOException(\"Error encoding CHOICE: No element of CHOICE was selected.\");");
write("}\n");
}
private void writeSequenceOrSetEncodeFunction(
List componentTypes, boolean hasExplicitTag, boolean isSequence)
throws IOException {
write("public int encode(OutputStream reverseOS, boolean withTag) throws IOException {\n");
writeEncodingIfCodeIsNull();
write("int codeLength = 0;");
for (int j = componentTypes.size() - 1; j >= 0; j--) {
if (isExplicit(getTag(componentTypes.get(j)))) {
write("int sublength;\n");
break;
}
}
if (isSequence && accessExtended && extensibilityImplied) {
write("if (extensionBytes != null) {");
write("reverseOS.write(extensionBytes);");
write("codeLength += extensionBytes.length;");
write("}\n");
}
for (int j = componentTypes.size() - 1; j >= 0; j--) {
AsnElementType componentType = componentTypes.get(j);
Tag componentTag = getTag(componentType);
if (isOptional(componentType)) {
write("if (" + getVariableName(componentType) + " != null) {");
}
String explicitEncoding = getExplicitEncodingParameter(componentType);
if (isExplicit(componentTag)) {
write(
"sublength = "
+ getVariableName(componentType)
+ ".encode(reverseOS"
+ explicitEncoding
+ ");");
write("codeLength += sublength;");
write("codeLength += BerLength.encodeLength(reverseOS, sublength);");
} else {
write(
"codeLength += "
+ getVariableName(componentType)
+ ".encode(reverseOS"
+ explicitEncoding
+ ");");
}
if (componentTag != null) {
writeEncodeTag(componentTag);
}
if (isOptional(componentType)) {
write("}");
}
write("");
}
if (hasExplicitTag) {
write("codeLength += BerLength.encodeLength(reverseOS, codeLength);");
if (isSequence) {
write("reverseOS.write(0x30);");
} else {
write("reverseOS.write(0x31);");
}
write("codeLength++;\n");
}
write("codeLength += BerLength.encodeLength(reverseOS, codeLength);\n");
write("if (withTag) {");
write("codeLength += tag.encode(reverseOS);");
write("}\n");
write("return codeLength;\n");
write("}\n");
}
private void writeSequenceOfEncodeFunction(
AsnElementType componentType, boolean hasExplicitTag, boolean isSequence) throws IOException {
write("public int encode(OutputStream reverseOS, boolean withTag) throws IOException {\n");
writeEncodingIfCodeIsNull();
write("int codeLength = 0;");
write("for (int i = (seqOf.size() - 1); i >= 0; i--) {");
Tag componentTag = getTag(componentType);
String explicitEncoding = getExplicitEncodingParameter(componentType);
if (componentTag != null) {
if (componentTag.type == TagType.EXPLICIT) {
write("int sublength = seqOf.get(i).encode(reverseOS" + explicitEncoding + ");");
write("codeLength += sublength;");
write("codeLength += BerLength.encodeLength(reverseOS, sublength);");
} else {
write("codeLength += seqOf.get(i).encode(reverseOS" + explicitEncoding + ");");
}
writeEncodeTag(componentTag);
} else {
if (isDirectAnyOrChoice(componentType)) {
write("codeLength += seqOf.get(i).encode(reverseOS);");
} else {
write("codeLength += seqOf.get(i).encode(reverseOS, true);");
}
}
write("}\n");
if (hasExplicitTag) {
write("codeLength += BerLength.encodeLength(reverseOS, codeLength);");
if (isSequence) {
write("reverseOS.write(0x30);");
} else {
write("reverseOS.write(0x31);");
}
write("codeLength++;\n");
}
write("codeLength += BerLength.encodeLength(reverseOS, codeLength);\n");
write("if (withTag) {");
write("codeLength += tag.encode(reverseOS);");
write("}\n");
write("return codeLength;");
write("}\n");
}
private String getExplicitEncodingParameter(AsnTaggedType componentType) {
Tag tag = getTag(componentType);
if (tag != null && tag.type == TagType.IMPLICIT) {
return ", false";
} else {
if (isDirectAnyOrChoice(componentType)) {
return "";
} else {
return ", true";
}
}
}
private void writeSequenceDecodeMethod(List components, boolean hasExplicitTag)
throws IOException {
write("public int decode(InputStream is, boolean withTag) throws IOException {");
write("int tlByteCount = 0;");
write("int vByteCount = 0;");
if (containsUntaggedChoiceOrAny(components)) {
write("int numDecodedBytes;");
}
write("BerTag berTag = new BerTag();\n");
write("if (withTag) {");
write("tlByteCount += tag.decodeAndCheck(is);");
write("}\n");
if (hasExplicitTag) {
write("BerLength explicitTagLength = new BerLength();");
write("tlByteCount += explicitTagLength.decode(is);");
write("tlByteCount += BerTag.SEQUENCE.decodeAndCheck(is);\n");
}
write("BerLength length = new BerLength();");
write("tlByteCount += length.decode(is);");
write("int lengthVal = length.val;");
if (allOptionalOrDefault(components)) {
write("if (lengthVal == 0) {");
write("return tlByteCount;");
write("}");
}
write("vByteCount += berTag.decode(is);\n");
for (ComponentInfo component : components) {
if (component.isDirectChoiceOrAny && (component.tag == null)) {
writeSequenceComponentDecodeUntaggedChoiceOrAny(component);
} else {
writeSequenceComponentDecodeRegular(component);
write("");
}
}
if (extensibilityImplied) {
if (accessExtended) {
writeSequenceDecodeMethodAccessibleExtensionEnd(hasExplicitTag);
} else {
writeSequenceDecodeMethodExtensibleEnd(hasExplicitTag);
}
} else {
writeSequenceDecodeMethodNonExtensibleEnd(hasExplicitTag);
}
write("}\n");
}
private void writeSequenceDecodeMethodAccessibleExtensionEnd(boolean hasExplicitTag)
throws IOException {
write("if (lengthVal < 0) {");
write("if (!berTag.equals(0, 0, 0)) {");
write("ByteArrayOutputStream os = new ByteArrayOutputStream();");
write("while (!berTag.equals(0, 0, 0)) {");
write("berTag.encodeForwards(os);");
write("vByteCount += DecodeUtil.decodeUnknownComponent(is,os);");
write("vByteCount += berTag.decode(is);");
write("}");
write("extensionBytes = os.toByteArray();");
write("}");
write("vByteCount += BerLength.readEocByte(is);");
if (hasExplicitTag) {
write("vByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlByteCount + vByteCount;");
write("} else {");
write("ByteArrayOutputStream os = new ByteArrayOutputStream();");
write("while (vByteCount < lengthVal) {");
write("berTag.encodeForwards(os);");
write("vByteCount += DecodeUtil.decodeUnknownComponent(is, os);");
write("if (vByteCount == lengthVal) {");
write("extensionBytes = os.toByteArray();");
write("return tlByteCount + vByteCount;");
write("}");
write("vByteCount += berTag.decode(is);");
write("}");
write("}");
write(
"throw new IOException(\"Unexpected end of sequence, length tag: \" + lengthVal + \", bytes decoded: \" + vByteCount);");
}
private void writeSequenceDecodeMethodExtensibleEnd(boolean hasExplicitTag) throws IOException {
write("if (lengthVal < 0) {");
write("while (!berTag.equals(0, 0, 0)) {");
write("vByteCount += DecodeUtil.decodeUnknownComponent(is);");
write("vByteCount += berTag.decode(is);");
write("}");
write("vByteCount += BerLength.readEocByte(is);");
if (hasExplicitTag) {
write("vByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlByteCount + vByteCount;");
write("} else {");
write("while (vByteCount < lengthVal) {");
write("vByteCount += DecodeUtil.decodeUnknownComponent(is);");
write("if (vByteCount == lengthVal) {");
write("return tlByteCount + vByteCount;");
write("}");
write("vByteCount += berTag.decode(is);");
write("}");
write("}");
write(
"throw new IOException(\"Unexpected end of sequence, length tag: \" + lengthVal + \", bytes decoded: \" + vByteCount);");
}
private void writeSequenceDecodeMethodNonExtensibleEnd(boolean hasExplicitTag)
throws IOException {
write("if (lengthVal < 0) {");
write("if (!berTag.equals(0, 0, 0)) {");
write("throw new IOException(\"Decoded sequence has wrong end of contents octets\");");
write("}");
write("vByteCount += BerLength.readEocByte(is);");
if (hasExplicitTag) {
write("vByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlByteCount + vByteCount;");
write("}\n");
write(
"throw new IOException(\"Unexpected end of sequence, length tag: \" + lengthVal + \", bytes decoded: \" + vByteCount);\n");
}
private void writeChoiceDecodeMethod(List components, boolean hasExplicitTag)
throws IOException {
if (hasExplicitTag) {
writeSimpleDecodeFunction("true");
write("public int decode(InputStream is, boolean withTag) throws IOException {");
write("int tlvByteCount = 0;");
write("BerTag berTag = new BerTag();\n");
write("if (withTag) {");
write("tlvByteCount += tag.decodeAndCheck(is);");
write("}\n");
write("BerLength explicitTagLength = new BerLength();");
write("tlvByteCount += explicitTagLength.decode(is);");
write("tlvByteCount += berTag.decode(is);\n");
} else {
writeSimpleDecodeFunction("null");
write("public int decode(InputStream is, BerTag berTag) throws IOException {\n");
write("int tlvByteCount = 0;");
write("boolean tagWasPassed = (berTag != null);\n");
write("if (berTag == null) {");
write("berTag = new BerTag();");
write("tlvByteCount += berTag.decode(is);");
write("}\n");
}
if (containsUntaggedChoiceOrAny(components)) {
write("int numDecodedBytes;\n");
}
for (ComponentInfo component : components) {
if (component.isDirectChoiceOrAny && (component.tag == null)) {
writeChoiceComponentDecodeUntaggedChoiceOrAny(component, hasExplicitTag);
} else {
writeChoiceComponentDecodeRegular(component, hasExplicitTag);
}
}
if (!hasExplicitTag) {
write("if (tagWasPassed) {");
write("return 0;");
write("}\n");
}
write(
"throw new IOException(\"Error decoding CHOICE: Tag \" + berTag + \" matched to no item.\");");
write("}\n");
}
private void writeSetDecodeFunction(List components, boolean hasExplicitTag)
throws IOException {
write("public int decode(InputStream is, boolean withTag) throws IOException {");
write("int tlByteCount = 0;");
write("int vByteCount = 0;");
write("BerTag berTag = new BerTag();\n");
write("if (withTag) {");
write("tlByteCount += tag.decodeAndCheck(is);");
write("}\n");
if (hasExplicitTag) {
write("BerLength explicitTagLength = new BerLength();");
write("tlByteCount += explicitTagLength.decode(is);");
write("tlByteCount += BerTag.SET.decodeAndCheck(is);\n");
}
write("BerLength length = new BerLength();");
write("tlByteCount += length.decode(is);");
write("int lengthVal = length.val;\n");
if (allOptionalOrDefault(components)) {
write("if (lengthVal == 0) {");
write("return tlByteCount;");
write("}\n");
}
write("while (vByteCount < lengthVal || lengthVal < 0) {");
write("vByteCount += berTag.decode(is);");
boolean first = true;
for (ComponentInfo component : components) {
if (component.isDirectChoiceOrAny && (component.tag == null)) {
throw new IOException("choice or ANY within set has no explicit tag.");
} else {
writeSetComponentDecodeRegular(component, first);
}
first = false;
}
write("else if (lengthVal < 0 && berTag.equals(0, 0, 0)) {");
write("vByteCount += BerLength.readEocByte(is);");
if (hasExplicitTag) {
write("vByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlByteCount + vByteCount;");
write("}");
write("else {");
write("throw new IOException(\"Tag does not match any set component: \" + berTag);");
write("}");
write("}");
write("if (vByteCount != lengthVal) {");
write(
"throw new IOException(\"Length of set does not match length tag, length tag: \" + lengthVal + \", actual set length: \" + vByteCount);");
write("}");
if (hasExplicitTag) {
write("vByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlByteCount + vByteCount;");
write("}\n");
}
private void writeSequenceOrSetOfDecodeFunction(
ComponentInfo component, boolean hasExplicitTag, boolean isSequence) throws IOException {
write("public int decode(InputStream is, boolean withTag) throws IOException {");
write("int tlByteCount = 0;");
write("int vByteCount = 0;");
if (containsUntaggedChoiceOrAny(Collections.singletonList(component))) {
write("int numDecodedBytes;");
}
write("BerTag berTag = new BerTag();");
write("if (withTag) {");
write("tlByteCount += tag.decodeAndCheck(is);");
write("}\n");
if (hasExplicitTag) {
write("BerLength explicitTagLength = new BerLength();");
write("tlByteCount += explicitTagLength.decode(is);");
if (isSequence) {
write("tlByteCount += BerTag.SEQUENCE.decodeAndCheck(is);\n");
} else {
write("tlByteCount += BerTag.SET.decodeAndCheck(is);\n");
}
}
write("BerLength length = new BerLength();");
write("tlByteCount += length.decode(is);");
write("int lengthVal = length.val;\n");
write("while (vByteCount < lengthVal || lengthVal < 0) {");
write("vByteCount += berTag.decode(is);\n");
write("if (lengthVal < 0 && berTag.equals(0, 0, 0)) {");
write("vByteCount += BerLength.readEocByte(is);");
write("break;");
write("}\n");
if (component.isDirectChoiceOrAny && (component.tag == null)) {
writeSequenceOfComponentDecodeUntaggedChoiceOrAny(component);
} else {
writeSequenceOfComponentDecodeRegular(component);
}
write("}");
write("if (lengthVal >= 0 && vByteCount != lengthVal) {");
write(
"throw new IOException(\"Decoded SequenceOf or SetOf has wrong length. Expected \" + lengthVal + \" but has \" + vByteCount);\n");
write("}");
if (hasExplicitTag) {
write("vByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlByteCount + vByteCount;");
write("}\n");
}
private void writeSequenceComponentDecodeRegular(ComponentInfo component) throws IOException {
if (component.tag != null) {
write("if (berTag.equals(" + getBerTagParametersString(component.tag) + ")) {");
} else {
write("if (berTag.equals(" + component.className + ".tag)) {");
}
if (isExplicit(component.tag)) {
write("vByteCount += length.decode(is);");
}
write(component.variableName + " = new " + component.className + "();");
write(
"vByteCount += "
+ component.variableName
+ ".decode(is, "
+ getDecodeTagParameter(component)
+ ");");
if (isExplicit(component.tag)) {
write("vByteCount += length.readEocIfIndefinite(is);");
}
if (component.mayBeLast) {
writeReturnIfDefiniteLengthMatchesDecodedBytes();
}
write("vByteCount += berTag.decode(is);");
write("}");
if (!component.isOptionalOrDefault) {
writeElseThrowTagMatchingException();
}
}
private void writeSequenceOfComponentDecodeRegular(ComponentInfo component) throws IOException {
if (component.tag != null) {
write("if (!berTag.equals(" + getBerTagParametersString(component.tag) + ")) {");
} else {
write("if (!berTag.equals(" + component.className + ".tag)) {");
}
write("throw new IOException(\"Tag does not match mandatory sequence of/set of component.\");");
write("}");
if (isExplicit(component.tag)) {
write("vByteCount += length.decode(is);");
}
write(component.className + " element = new " + component.className + "();");
write("vByteCount += " + "element.decode(is, " + getDecodeTagParameter(component) + ");");
write("seqOf.add(element);");
if (isExplicit(component.tag)) {
write("vByteCount += length.readEocIfIndefinite(is);");
}
}
private void writeSetComponentDecodeRegular(ComponentInfo component, boolean first)
throws IOException {
String elseString = first ? "" : "else ";
if (component.tag != null) {
write(elseString + "if (berTag.equals(" + getBerTagParametersString(component.tag) + ")) {");
} else {
write(elseString + "if (berTag.equals(" + component.className + ".tag)) {");
}
if (isExplicit(component.tag)) {
write("vByteCount += length.decode(is);");
}
write(component.variableName + " = new " + component.className + "();");
write(
"vByteCount += "
+ component.variableName
+ ".decode(is, "
+ getDecodeTagParameter(component)
+ ");");
if (isExplicit(component.tag)) {
write("vByteCount += length.readEocIfIndefinite(is);");
}
write("}");
}
private void writeChoiceComponentDecodeRegular(ComponentInfo component, boolean taggedChoice)
throws IOException {
if (component.tag != null) {
write("if (berTag.equals(" + getBerTagParametersString(component.tag) + ")) {");
} else {
write("if (berTag.equals(" + component.className + ".tag)) {");
}
if (isExplicit(component.tag)) {
write("BerLength length = new BerLength();");
write("tlvByteCount += length.decode(is);");
}
write(component.variableName + " = new " + component.className + "();");
write(
"tlvByteCount += "
+ component.variableName
+ ".decode(is, "
+ getDecodeTagParameter(component)
+ ");");
if (isExplicit(component.tag)) {
write("tlvByteCount += length.readEocIfIndefinite(is);");
}
if (taggedChoice) {
write("tlvByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlvByteCount;");
write("}\n");
}
private void writeSequenceComponentDecodeUntaggedChoiceOrAny(ComponentInfo component)
throws IOException {
write(component.variableName + " = new " + component.className + "();");
write(
"numDecodedBytes = "
+ component.variableName
+ ".decode(is, "
+ getDecodeTagParameter(component)
+ ");");
write("if (numDecodedBytes != 0) {");
write("vByteCount += numDecodedBytes;");
if (component.mayBeLast) {
writeReturnIfDefiniteLengthMatchesDecodedBytes();
}
write("vByteCount += berTag.decode(is);");
write("}");
if (component.isOptionalOrDefault) {
write("else {");
write(component.variableName + " = null;");
write("}");
} else {
writeElseThrowTagMatchingException();
}
}
private void writeSequenceOfComponentDecodeUntaggedChoiceOrAny(ComponentInfo component)
throws IOException {
write(component.className + " element = new " + component.className + "();");
write("numDecodedBytes = " + "element.decode(is, " + getDecodeTagParameter(component) + ");");
write("if (numDecodedBytes == 0) {");
write("throw new IOException(\"Tag did not match\");");
write("}");
write("vByteCount += numDecodedBytes;");
write("seqOf.add(element);");
}
private void writeChoiceComponentDecodeUntaggedChoiceOrAny(
ComponentInfo component, boolean taggedChoice) throws IOException {
write(component.variableName + " = new " + component.className + "();");
write(
"numDecodedBytes = "
+ component.variableName
+ ".decode(is, "
+ getDecodeTagParameter(component)
+ ");");
write("if (numDecodedBytes != 0) {");
if (taggedChoice) {
write("tlvByteCount += explicitTagLength.readEocIfIndefinite(is);");
}
write("return tlvByteCount + numDecodedBytes;");
write("}");
write("else {");
write(component.variableName + " = null;");
write("}\n");
}
private boolean containsUntaggedChoiceOrAny(List components) {
for (ComponentInfo component : components) {
if (component.isDirectChoiceOrAny && (component.tag == null)) {
return true;
}
}
return false;
}
private String getDecodeTagParameter(ComponentInfo component) {
if (component.isDirectChoiceOrAny) {
return isExplicit(component.tag) ? "null" : "berTag";
} else {
return isExplicit(component.tag) ? "true" : "false";
}
}
private boolean allOptionalOrDefault(List componentTypes) {
return componentTypes.size() == 0
|| (componentTypes.get(0).mayBeLast && componentTypes.get(0).isOptionalOrDefault);
}
private void writeElseThrowTagMatchingException() throws IOException {
write("else {");
write("throw new IOException(\"Tag does not match mandatory sequence component.\");");
write("}");
}
private int getLastRequiredComponentIndex(List componentTypes) {
int lastNoneOptionalFieldIndex = -1;
for (int j = 0; j < componentTypes.size(); j++) {
AsnElementType componentType = componentTypes.get(componentTypes.size() - 1 - j);
if (!isOptional(componentType)) {
lastNoneOptionalFieldIndex = componentTypes.size() - 1 - j;
break;
}
}
return lastNoneOptionalFieldIndex;
}
private void writeReturnIfDefiniteLengthMatchesDecodedBytes() throws IOException {
write("if (lengthVal >= 0 && vByteCount == lengthVal) {");
write("return tlByteCount + vByteCount;");
write("}");
}
private void writeToStringFunction() throws IOException {
write("@Override public String toString() {");
write("StringBuilder sb = new StringBuilder();");
write("appendAsString(sb, 0);");
write("return sb.toString();");
write("}\n");
}
private void writeChoiceToStringFunction(List componentTypes) throws IOException {
writeToStringFunction();
write("public void appendAsString(StringBuilder sb, int indentLevel) {\n");
for (AsnElementType componentType : componentTypes) {
write("if (" + getVariableName(componentType) + " != null) {");
if (!isPrimitive(getUniversalType(componentType))) {
write("sb.append(\"" + getVariableName(componentType) + ": \");");
write(getVariableName(componentType) + ".appendAsString(sb, indentLevel + 1);");
} else {
write(
"sb.append(\""
+ getVariableName(componentType)
+ ": \").append("
+ getVariableName(componentType)
+ ");");
}
write("return;");
write("}\n");
}
write("sb.append(\"\");");
write("}\n");
}
private void writeSequenceOrSetToStringFunction(List componentTypes)
throws IOException {
writeToStringFunction();
write("public void appendAsString(StringBuilder sb, int indentLevel) {\n");
write("sb.append(\"{\");");
boolean checkIfFirstSelectedElement = componentTypes.size() > 1;
int j = 0;
for (AsnElementType componentType : componentTypes) {
if (isOptional(componentType)) {
if (j == 0 && componentTypes.size() > 1) {
write("boolean firstSelectedElement = true;");
}
write("if (" + getVariableName(componentType) + " != null) {");
}
if (j != 0) {
if (checkIfFirstSelectedElement) {
write("if (!firstSelectedElement) {");
}
write("sb.append(\",\\n\");");
if (checkIfFirstSelectedElement) {
write("}");
}
} else {
write("sb.append(\"\\n\");");
}
write("for (int i = 0; i < indentLevel + 1; i++) {");
write("sb.append(\"\\t\");");
write("}");
if (!isOptional(componentType)) {
write("if (" + getVariableName(componentType) + " != null) {");
}
if (!isPrimitive(getUniversalType(componentType))) {
write("sb.append(\"" + getVariableName(componentType) + ": \");");
write(getVariableName(componentType) + ".appendAsString(sb, indentLevel + 1);");
} else {
write(
"sb.append(\""
+ getVariableName(componentType)
+ ": \").append("
+ getVariableName(componentType)
+ ");");
}
if (!isOptional(componentType)) {
write("}");
write("else {");
write("sb.append(\"" + getVariableName(componentType) + ": \");");
write("}");
}
if (isOptional(componentType)) {
if (checkIfFirstSelectedElement && j != (componentTypes.size() - 1)) {
write("firstSelectedElement = false;");
}
write("}");
} else {
checkIfFirstSelectedElement = false;
}
write("");
j++;
}
write("sb.append(\"\\n\");");
write("for (int i = 0; i < indentLevel; i++) {");
write("sb.append(\"\\t\");");
write("}");
write("sb.append(\"}\");");
write("}\n");
}
private void writeSequenceOrSetOfToStringFunction(
String referencedTypeName, AsnElementType componentType) throws IOException {
writeToStringFunction();
write("public void appendAsString(StringBuilder sb, int indentLevel) {\n");
write("sb.append(\"{\\n\");");
write("for (int i = 0; i < indentLevel + 1; i++) {");
write("sb.append(\"\\t\");");
write("}");
write("if (seqOf == null) {");
write("sb.append(\"null\");");
write("}");
write("else {");
write("Iterator<" + referencedTypeName + "> it = seqOf.iterator();");
write("if (it.hasNext()) {");
if (!isPrimitive(getUniversalType(componentType))) {
write("it.next().appendAsString(sb, indentLevel + 1);");
} else {
write("sb.append(it.next());");
}
write("while (it.hasNext()) {");
write("sb.append(\",\\n\");");
write("for (int i = 0; i < indentLevel + 1; i++) {");
write("sb.append(\"\\t\");");
write("}");
if (!isPrimitive(getUniversalType(componentType))) {
write("it.next().appendAsString(sb, indentLevel + 1);");
} else {
write("sb.append(it.next());");
}
write("}");
write("}");
write("}\n");
write("sb.append(\"\\n\");");
write("for (int i = 0; i < indentLevel; i++) {");
write("sb.append(\"\\t\");");
write("}");
write("sb.append(\"}\");");
write("}\n");
}
private void addAutomaticTagsIfNeeded(List componentTypes) {
if (tagDefault != TagDefault.AUTOMATIC) {
return;
}
for (AsnElementType element : componentTypes) {
if (getTag(element) != null) {
return;
}
}
int i = 0;
for (AsnElementType element : componentTypes) {
element.tag = new AsnTag();
element.tag.classNumber = new AsnClassNumber();
element.tag.classNumber.num = i;
i++;
}
}
private void writeEncodeAndSaveFunction() throws IOException {
writeEncodeAndSaveFunction(false);
}
private void writeEncodeAndSaveFunction(boolean isTagless) throws IOException {
write("public void encodeAndSave(int encodingSizeGuess) throws IOException {");
write(
"ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess);");
if (isTagless) {
write("encode(reverseOS);");
} else {
write("encode(reverseOS, false);");
}
write("code = reverseOS.getArray();");
write("}\n");
}
private void writeEncodeTag(Tag tag) throws IOException {
int typeStructure;
if (tag.typeStructure == TypeStructure.CONSTRUCTED) {
typeStructure = BerTag.CONSTRUCTED;
} else {
typeStructure = BerTag.PRIMITIVE;
}
BerTag berTag = new BerTag(getTagClassId(tag.tagClass.toString()), typeStructure, tag.value);
write("// write tag: " + tag.tagClass + "_CLASS, " + tag.typeStructure + ", " + tag.value);
for (int i = (berTag.tagBytes.length - 1); i >= 0; i--) {
write("reverseOS.write(0x" + HexString.fromByte(berTag.tagBytes[i]) + ");");
}
write("codeLength += " + berTag.tagBytes.length + ";");
}
private int getTagClassId(String tagClass) {
switch (tagClass) {
case "UNIVERSAL":
return BerTag.UNIVERSAL_CLASS;
case "APPLICATION":
return BerTag.APPLICATION_CLASS;
case "CONTEXT":
return BerTag.CONTEXT_CLASS;
case "PRIVATE":
return BerTag.PRIVATE_CLASS;
default:
throw new IllegalStateException("unknown tag class: " + tagClass);
}
}
private String getVariableName(AsnElementType componentType) {
return cleanUpName(componentType.name);
}
private boolean isOptional(AsnElementType componentType) {
return (componentType.isOptional || componentType.isDefault);
}
private boolean isExplicit(Tag tag) {
return (tag != null) && (tag.type == TagType.EXPLICIT);
}
private void writeEncodeConstructor(String className, List componentTypes)
throws IOException {
if (componentTypes.isEmpty()) {
return;
}
StringBuilder line = new StringBuilder("public " + className + "(");
int j = 0;
for (AsnElementType componentType : componentTypes) {
if (j != 0) {
line.append(", ");
}
j++;
line.append(getClassName(componentType)).append(" ").append(cleanUpName(componentType.name));
}
write(line + ") {");
for (AsnElementType componentType : componentTypes) {
String elementName = cleanUpName(componentType.name);
write("this." + elementName + " = " + elementName + ";");
}
write("}\n");
}
private void writeEmptyConstructor(String className) throws IOException {
write("public " + className + "() {");
write("}\n");
write("public " + className + "(byte[] code) {");
write("this.code = code;");
write("}\n");
}
private void writeMembers(List componentTypes) throws IOException {
String accessModifierString = jaxbMode ? "private" : "public";
for (AsnElementType element : componentTypes) {
write(
accessModifierString
+ " "
+ element.className
+ " "
+ cleanUpName(element.name)
+ " = null;");
}
write("");
}
private boolean isInnerType(AsnElementType element) {
return (element.typeReference instanceof AsnConstructedType);
}
private void writeGetterAndSetter(List componentTypes) throws IOException {
for (AsnElementType element : componentTypes) {
String typeName = getClassName(element);
String getterName = cleanUpName("get" + capitalizeFirstCharacter(element.name));
String setterName = cleanUpName("set" + capitalizeFirstCharacter(element.name));
String variableName = cleanUpName(element.name);
write("public void " + setterName + "(" + typeName + " " + variableName + ") {");
write("this." + variableName + " = " + variableName + ";");
write("}\n");
write("public " + typeName + " " + getterName + "() {");
write("return " + variableName + ";");
write("}\n");
}
}
private void writeGetterForSeqOf(String referencedTypeName) throws IOException {
write(
"public List<"
+ referencedTypeName
+ "> get"
+ referencedTypeName.substring(referencedTypeName.lastIndexOf('.') + 1)
+ "() {");
write("if (seqOf == null) {");
write("seqOf = new ArrayList<>();");
write("}");
write("return seqOf;");
write("}\n");
}
private String getClassNameOfSequenceOfElement(
AsnElementType componentType, List listOfSubClassNames) {
String classNameOfSequenceElement = getClassNameOfSequenceOfElement(componentType);
for (String subClassName : listOfSubClassNames) {
if (classNameOfSequenceElement.equals(subClassName)) {
String moduleName = module.moduleIdentifier.name;
for (SymbolsFromModule symbols : this.module.importSymbolFromModuleList) {
if (symbols.symbolList.contains(classNameOfSequenceElement)) {
moduleName = symbols.modref;
break;
}
}
return basePackageName + moduleToPackageName(moduleName) + "." + classNameOfSequenceElement;
}
}
return classNameOfSequenceElement;
}
private String getClassNameOfSequenceOfElement(AsnElementType componentType) {
if (componentType.typeReference == null) {
return cleanUpName(componentType.definedType.typeName);
} else {
AsnType typeDefinition = componentType.typeReference;
return getClassNameOfSequenceOfTypeReference(typeDefinition);
}
}
private String getClassNameOfSequenceOfTypeReference(AsnType typeDefinition) {
if (typeDefinition instanceof AsnConstructedType) {
String subClassName;
if (typeDefinition instanceof AsnSequenceSet) {
if (((AsnSequenceSet) typeDefinition).isSequence) {
subClassName = "SEQUENCE";
} else {
subClassName = "SET";
}
} else if (typeDefinition instanceof AsnSequenceOf) {
if (((AsnSequenceOf) typeDefinition).isSequenceOf) {
subClassName = "SEQUENCEOF";
} else {
subClassName = "SETOF";
}
} else {
subClassName = "CHOICE";
}
return subClassName;
}
return getBerType(typeDefinition);
}
private String capitalizeFirstCharacter(String input) {
return input.substring(0, 1).toUpperCase() + input.substring(1);
}
private String getBerType(AsnType asnType) {
String fullClassName = asnType.getClass().getName();
String className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
if (className.equals("AsnCharacterString")) {
AsnCharacterString asnCharacterString = (AsnCharacterString) asnType;
if (asnCharacterString.stringtype.equals("ISO646String")) {
return "BerVisibleString";
} else if (asnCharacterString.stringtype.equals("T61String")) {
return "BerTeletexString";
}
return "Ber" + ((AsnCharacterString) asnType).stringtype;
}
return "Ber" + className.substring(3);
}
private String[] getConstructorParameters(AsnUniversalType typeDefinition) {
if (typeDefinition instanceof AsnInteger || typeDefinition instanceof AsnEnum) {
return new String[] {"BigInteger", "value"};
} else if (typeDefinition instanceof AsnReal) {
return new String[] {"double", "value"};
} else if (typeDefinition instanceof AsnBoolean) {
return new String[] {"boolean", "value"};
} else if (typeDefinition instanceof AsnObjectIdentifier) {
return new String[] {"int[]", "value"};
} else if (typeDefinition instanceof AsnBitString) {
return new String[] {"byte[]", "value", "int", "numBits"};
} else if (typeDefinition instanceof AsnOctetString
|| typeDefinition instanceof AsnCharacterString) {
return new String[] {"byte[]", "value"};
} else if (typeDefinition instanceof AsnNull) {
return new String[0];
} else if ((typeDefinition instanceof AsnSequenceSet)
|| (typeDefinition instanceof AsnChoice)) {
return getConstructorParametersFromConstructedElement((AsnConstructedType) typeDefinition);
} else if (typeDefinition instanceof AsnSequenceOf) {
return new String[] {
"List<"
+ getClassNameOfSequenceOfElement(((AsnSequenceOf) typeDefinition).componentType)
+ ">",
"seqOf"
};
} else if (typeDefinition instanceof AsnAny) {
return new String[] {"byte[]", "value"};
} else if (typeDefinition instanceof AsnEmbeddedPdv) {
return new String[0];
} else {
throw new IllegalStateException("type of unknown class: " + typeDefinition.name);
}
}
private String[] getConstructorParametersFromConstructedElement(
AsnConstructedType assignedTypeDefinition) {
List componentTypes;
if (assignedTypeDefinition instanceof AsnSequenceSet) {
componentTypes = ((AsnSequenceSet) assignedTypeDefinition).componentTypes;
} else {
componentTypes = ((AsnChoice) assignedTypeDefinition).componentTypes;
}
String[] constructorParameters = new String[componentTypes.size() * 2];
for (int j = 0; j < componentTypes.size(); j++) {
AsnElementType componentType = componentTypes.get(j);
constructorParameters[j * 2] = getClassName(componentType);
constructorParameters[j * 2 + 1] = cleanUpName(componentType.name);
}
return constructorParameters;
}
private AsnType followAndGetNextTaggedOrUniversalType(AsnType asnType, AsnModule module)
throws CompileException {
return followAndGetNextTaggedOrUniversalType(asnType, module, true);
}
private AsnType followAndGetNextTaggedOrUniversalType(
AsnType asnType, AsnModule module, boolean firstCall) throws CompileException {
if (asnType instanceof AsnTaggedType) {
if (!firstCall) {
return asnType;
}
AsnTaggedType taggedType = (AsnTaggedType) asnType;
if (taggedType.definedType != null) {
return followAndGetNextTaggedOrUniversalType(taggedType.definedType, module, false);
} else {
return taggedType.typeReference;
}
} else if (asnType instanceof AsnDefinedType) {
AsnDefinedType definedType = (AsnDefinedType) asnType;
if (definedType.isObjectClassField) {
AsnInformationObjectClass informationObjectClass =
getInformationObjectClass(definedType.moduleOrObjectClassReference, module);
if (informationObjectClass == null) {
throw new CompileException(
"no information object class of name \""
+ definedType.moduleOrObjectClassReference
+ "\" found");
}
for (AsnElementType elementType : informationObjectClass.elementList) {
if (elementType.name.equals(definedType.typeName)) {
return followAndGetNextTaggedOrUniversalType(elementType, module, true);
}
}
throw new IllegalStateException(
"Could not find field \""
+ definedType.typeName
+ "\" of information object class \""
+ definedType.moduleOrObjectClassReference
+ "\"");
} else {
return followAndGetNextTaggedOrUniversalType(definedType.typeName, module);
}
} else if (asnType instanceof AsnUniversalType) {
return asnType;
} else {
throw new IllegalStateException();
}
}
private AsnType followAndGetNextTaggedOrUniversalType(String typeName, AsnModule module)
throws CompileException {
AsnType asnType = module.typesByName.get(typeName);
if (asnType != null) {
return followAndGetNextTaggedOrUniversalType(asnType, module, false);
}
for (SymbolsFromModule symbolsFromModule : module.importSymbolFromModuleList) {
for (String importedTypeName : symbolsFromModule.symbolList) {
if (typeName.equals(importedTypeName)) {
return followAndGetNextTaggedOrUniversalType(
typeName, getAsnModule(symbolsFromModule.modref));
}
}
}
throw new IllegalStateException(
"Type definition \""
+ typeName
+ "\" was not found in module \""
+ module.moduleIdentifier.name
+ "\"");
}
private AsnModule getAsnModule(String moduleName) {
AsnModule asnModule = modulesByName.get(moduleName);
if (asnModule == null) {
throw new CompileException("Definition of imported module \"" + moduleName + "\" not found.");
}
return asnModule;
}
private boolean isDirectAnyOrChoice(AsnTaggedType taggedType) throws CompileException {
AsnType followedType = followAndGetNextTaggedOrUniversalType(taggedType, module);
return (followedType instanceof AsnAny) || (followedType instanceof AsnChoice);
}
private AsnUniversalType getUniversalType(AsnType asnType) {
return getUniversalType(asnType, module);
}
private AsnUniversalType getUniversalType(AsnType asnType, AsnModule module) {
while (true) {
if (!((asnType = followAndGetNextTaggedOrUniversalType(asnType, module))
instanceof AsnTaggedType)) {
break;
}
}
return (AsnUniversalType) asnType;
}
private boolean isPrimitive(AsnTaggedType asnTaggedType) {
AsnType asnType = asnTaggedType;
while ((asnType = followAndGetNextTaggedOrUniversalType(asnType, module))
instanceof AsnTaggedType) {
if (isExplicit(getTag((AsnTaggedType) asnType))) {
return false;
}
}
return isPrimitive((AsnUniversalType) asnType);
}
private boolean isPrimitiveOrRetaggedPrimitive(AsnType asnType) {
return isPrimitive(getUniversalType(asnType));
}
private boolean isPrimitive(AsnUniversalType asnType) {
return !(asnType instanceof AsnConstructedType || asnType instanceof AsnEmbeddedPdv);
}
private void writeClassHeader(String typeName, AsnModule module) throws IOException {
//noinspection ResultOfMethodCallIgnored
outputDirectory.mkdirs();
Writer fileWriter =
Files.newBufferedWriter(new File(outputDirectory, typeName + ".java").toPath(), UTF_8);
out = new BufferedWriter(fileWriter);
String versionString = "";
if (insertVersion) {
versionString = " v" + Compiler.VERSION;
}
write("/*");
write(
" * This class file was automatically generated by ASN1bean"
+ versionString
+ " (http://www.beanit.com)\n */\n");
write("package " + basePackageName + moduleToPackageName(module.moduleIdentifier.name) + ";\n");
write("import java.io.IOException;");
write("import java.io.EOFException;");
write("import java.io.InputStream;");
write("import java.io.OutputStream;");
write("import java.io.ByteArrayOutputStream;");
write("import java.util.List;");
write("import java.util.ArrayList;");
write("import java.util.Iterator;");
write("import java.io.UnsupportedEncodingException;");
write("import java.math.BigInteger;");
write("import java.io.Serializable;");
write("import com.beanit.asn1bean.ber.*;");
write("import com.beanit.asn1bean.ber.types.*;");
write("import com.beanit.asn1bean.ber.types.string.*;\n");
List importedClassesFromOtherModules = new ArrayList<>();
for (SymbolsFromModule symbolsFromModule : module.importSymbolFromModuleList) {
AsnModule importedModule = modulesByName.get(symbolsFromModule.modref);
for (String importedSymbol : symbolsFromModule.symbolList) {
if (Character.isUpperCase(importedSymbol.charAt(0))) {
if (importedModule.typesByName.get(importedSymbol) != null) {
importedClassesFromOtherModules.add(
moduleToPackageName(importedModule.moduleIdentifier.name)
+ "."
+ cleanUpName(importedSymbol)
+ ";");
}
}
}
}
Collections.sort(importedClassesFromOtherModules);
for (String modulePackage : importedClassesFromOtherModules) {
write("import " + basePackageName + modulePackage);
}
write("");
}
private void write(String line) throws IOException {
if (line.startsWith("}")) {
indentNum--;
}
for (int i = 0; i < indentNum; i++) {
out.write("\t");
}
out.write(line + "\n");
if (line.endsWith(" {") || line.endsWith(" {\n") || line.endsWith(" {\n\n")) {
indentNum++;
}
}
public enum TagClass {
UNIVERSAL,
APPLICATION,
CONTEXT,
PRIVATE
}
public enum TagType {
EXPLICIT,
IMPLICIT
}
public enum TypeStructure {
PRIMITIVE,
CONSTRUCTED
}
public static class Tag {
public int value;
public TagClass tagClass;
public TagType type;
public TypeStructure typeStructure;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy