summaryrefslogtreecommitdiffstats
path: root/src/net/gcdc/asn1/uper/EnumCoder.java
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/net/gcdc/asn1/uper/EnumCoder.java156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/net/gcdc/asn1/uper/EnumCoder.java b/src/net/gcdc/asn1/uper/EnumCoder.java
new file mode 100644
index 0000000..f86fe5f
--- /dev/null
+++ b/src/net/gcdc/asn1/uper/EnumCoder.java
@@ -0,0 +1,156 @@
+package net.gcdc.asn1.uper;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import net.gcdc.asn1.datatypes.Asn1Default;
+import net.gcdc.asn1.datatypes.IsExtension;
+
+class EnumCoder implements Decoder, Encoder {
+
+ @Override public <T> boolean canEncode(T obj, Annotation[] extraAnnotations) {
+ Class<?> type = obj.getClass();
+ return type.isEnum();
+ }
+
+ @Override public <T> void encode(BitBuffer bitbuffer, T obj, Annotation[] extraAnnotations) throws Asn1EncodingException {
+ Class<?> type = obj.getClass();
+ AnnotationStore annotations = new AnnotationStore(type.getAnnotations(), extraAnnotations);
+ String pos = String.format("%d.%d", bitbuffer.position()/8 , bitbuffer.position() % 8);
+ UperEncoder.logger.debug(String.format("Position %s ENUM",pos));
+ try {
+ int position = bitbuffer.position();
+
+ List<?> values = Arrays.asList(type.getEnumConstants());
+ int enumIndex = values.indexOf(obj);
+
+ if (!UperEncoder.hasExtensionMarker(annotations)) {
+ UperEncoder.logger.debug(String.format("enum without extension: index %d value %s, encoding index...", enumIndex,obj.toString()));
+ UperEncoder.encodeConstrainedInt(bitbuffer, enumIndex, 0, values.size() - 1);
+ return;
+ } else {
+ List<Object> valuesWithinExtensionRoot = new ArrayList<>();
+ List<Object> valuesOutsideExtensionRoot = new ArrayList<>();
+ for (Object c : type.getEnumConstants()) {
+ String field = c.toString();
+ boolean isExtension = false;
+ try {
+ isExtension = type.getField(field).isAnnotationPresent(IsExtension.class);
+ } catch (NoSuchFieldException e) {
+ throw new IllegalArgumentException("Illegal value for enum field " , e);
+ } catch (SecurityException e) {
+ throw new IllegalArgumentException("Illegal access restriction for enum field " , e);
+ }
+
+ if (!isExtension) {
+ valuesWithinExtensionRoot.add(c);
+ } else {
+ valuesOutsideExtensionRoot.add(c);
+ }
+ }
+
+ if (valuesWithinExtensionRoot.contains(obj)) {
+ UperEncoder.logger.debug(String.format("Extension indicator set to false"));
+ bitbuffer.put(false);
+ int index = valuesWithinExtensionRoot.indexOf(obj);
+ UperEncoder.encodeConstrainedInt(bitbuffer, index, 0, valuesWithinExtensionRoot.size() - 1);
+ UperEncoder.logger.debug(String.format("ENUM with extension: index %d value %s, encoded as root value <%s>", index, obj.toString(),
+ bitbuffer.toBooleanStringFromPosition(position)));
+ return;
+ } else {
+ //CG encode the index in the extension list as small integer
+ UperEncoder.logger.debug(String.format("Extension indicator set to true"));
+ bitbuffer.put(true);
+ int index = valuesOutsideExtensionRoot.indexOf(obj);
+
+ UperEncoder.encodeSmallInt(bitbuffer, index);
+ UperEncoder.logger.debug(String.format("ENUM with extension: index %d value %s, encoded as extension <%s>", index, obj.toString(),
+ bitbuffer.toBooleanStringFromPosition(position)));
+ }
+ }
+ } catch (Asn1EncodingException e) {
+ throw new Asn1EncodingException(type.getName(), e);
+ }
+ }
+
+ @Override public <T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations) {
+ return classOfT.isEnum();
+ }
+
+ @Override public <T> T decode(BitBuffer bitbuffer,
+ Class<T> classOfT, Field field,
+ Annotation[] extraAnnotations) {
+ AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), extraAnnotations);
+ UperEncoder.logger.debug("ENUM");
+ boolean extensionPresent = false;
+ if (UperEncoder.hasExtensionMarker(annotations)) {
+ extensionPresent = bitbuffer.get();
+ UperEncoder.logger.debug(String.format("with extension marker, %s" , extensionPresent ? "present" : "absent"));
+ }
+ T[] enumValues = classOfT.getEnumConstants();
+
+ int rootValues = 0;
+
+ boolean isExtension = false;
+ for (Object c : enumValues) {
+ String value = c.toString();
+ try {
+ isExtension = classOfT.getField(value).isAnnotationPresent(IsExtension.class);
+ } catch (NoSuchFieldException e) {
+ throw new IllegalArgumentException("Illegal value for extension field " , e);
+ } catch (SecurityException e) {
+ throw new IllegalArgumentException("Illegal value for extension field " , e);
+ }
+
+ if (!isExtension) rootValues++;
+ }
+
+ //
+ int index = 0;
+ if (!extensionPresent){
+ //root element
+ index = (int) UperEncoder.decodeConstrainedInt(bitbuffer,
+ UperEncoder.newRange(0, rootValues - 1, false));
+ } else {
+ //extension element, decode as small int without restriction
+ index = (int) UperEncoder.decodeSmallInt(bitbuffer);
+ //the encoded index is an index within the extensions list only
+ index = index + rootValues;
+ }
+
+ if (index > enumValues.length - 1 && extensionPresent) {
+ //this is an unknown extension
+ UperEncoder.logger.debug(String.format("Enum contains unknown extendion index %d" , index));
+ return null;
+ }
+ if (index > enumValues.length - 1 && !extensionPresent) {
+ //this should not happen
+ throw new IllegalArgumentException(
+ "decoded enum index " + index + " is larger then number of elements (0.."
+ + enumValues.length + ") in " + classOfT.getName());
+ }
+ T value = enumValues[index];
+ UperEncoder.logger.debug(String.format("Enum decoded as %s" , value.toString()));
+ return value;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T getDefault(Class<T> classOfT, Annotation[] extraAnnotations) {
+ AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), extraAnnotations);
+ Asn1Default defaultAnnotation = annotations.getAnnotation(Asn1Default.class);
+ if (defaultAnnotation == null) return null;
+
+ for (Object c : classOfT.getEnumConstants()) {
+ if (c.toString().equals(defaultAnnotation.value())) {
+ return (T) c;
+ }
+ }
+
+ return null;
+ }
+
+} \ No newline at end of file