diff options
Diffstat (limited to '')
-rw-r--r-- | src/net/gcdc/asn1/uper/EnumCoder.java | 156 |
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 |