diff options
Diffstat (limited to 'src/net/gcdc/asn1/uper/BitStringCoder.java')
-rw-r--r-- | src/net/gcdc/asn1/uper/BitStringCoder.java | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/net/gcdc/asn1/uper/BitStringCoder.java b/src/net/gcdc/asn1/uper/BitStringCoder.java new file mode 100644 index 0000000..e60c68e --- /dev/null +++ b/src/net/gcdc/asn1/uper/BitStringCoder.java @@ -0,0 +1,165 @@ +package net.gcdc.asn1.uper; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import net.gcdc.asn1.datatypes.Asn1VarSizeBitstring; +import net.gcdc.asn1.datatypes.Bitstring; +import net.gcdc.asn1.datatypes.FixedSize; +import net.gcdc.asn1.datatypes.SizeRange; +import net.gcdc.asn1.uper.UperEncoder.Asn1ContainerFieldSorter; + +class BitStringCoder implements Decoder, Encoder { + + @Override public <T> boolean canEncode(T obj, Annotation[] extraAnnotations) { + Class<?> type = obj.getClass(); + AnnotationStore annotations = new AnnotationStore(type.getAnnotations(), + extraAnnotations); + return annotations.getAnnotation(Bitstring.class) != null; + } + + @Override public <T> void encode(BitBuffer bitbuffer, T obj, Annotation[] extraAnnotations) throws Asn1EncodingException { + Class<?> type = obj.getClass(); + AnnotationStore annotations = new AnnotationStore(type.getAnnotations(), + extraAnnotations); + if (!(obj instanceof Asn1VarSizeBitstring)) { + if (UperEncoder.hasExtensionMarker(annotations)) { + throw new UnsupportedOperationException( + "Bitstring with extensions is not implemented yet"); + } + FixedSize size = type.getAnnotation(FixedSize.class); + int position = bitbuffer.position(); + if (size != null) { + Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(type); + if (sorter.ordinaryFields.size() != size.value()) { throw new AssertionError( + "Declared size (" + size.value() + + ") and number of fields (" + sorter.ordinaryFields.size() + + ") do not match!"); } + for (Field f : sorter.ordinaryFields) { + try { + bitbuffer.put(f.getBoolean(obj)); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalArgumentException("can't encode" + obj, e); + } + } + UperEncoder.logger.debug(String.format("BITSTRING %s, encoded as <%s>", obj.getClass().getName(), + bitbuffer.toBooleanStringFromPosition(position))); + return; + } else { + throw new UnsupportedOperationException( + "Bitstrings of variable size are not implemented yet"); + } + } else if (obj instanceof Asn1VarSizeBitstring) { + int position = bitbuffer.position(); + if (UperEncoder.hasExtensionMarker(annotations)) { throw new UnsupportedOperationException( + "Bitstring with extensions is not implemented yet"); } + Asn1VarSizeBitstring bitstring = (Asn1VarSizeBitstring) obj; + FixedSize fixedSize = annotations.getAnnotation(FixedSize.class); + SizeRange sizeRange = annotations.getAnnotation(SizeRange.class); + if (fixedSize != null) { + for (int i = 0; i < fixedSize.value(); i++) { + bitbuffer.put(bitstring.getBit(i)); + } + UperEncoder.logger.debug(String.format("BITSTRING %s: %s", obj.getClass().getName(), + bitbuffer.toBooleanStringFromPosition(position))); + return; + } else if (sizeRange != null) { + int position1 = bitbuffer.position(); + UperEncoder.encodeConstrainedInt(bitbuffer, bitstring.size(), sizeRange.minValue(), + sizeRange.maxValue()); + int position2 = bitbuffer.position(); + for (int i = 0; i < bitstring.size(); i++) { + bitbuffer.put(bitstring.getBit(i)); + } + UperEncoder.logger.debug(String.format("BITSTRING %s size %s: %S", obj.getClass().getName(), + bitbuffer.toBooleanString(position1, position2 - position1), + bitbuffer.toBooleanStringFromPosition(position2))); + return; + } else { + throw new IllegalArgumentException("Both SizeRange and FixedSize are null"); + } + } + } + + @Override public <T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations) { + AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), + extraAnnotations); + return annotations.getAnnotation(Bitstring.class) != null; + } + + @Override public <T> T decode(BitBuffer bitbuffer, + Class<T> classOfT, Field field, + Annotation[] extraAnnotations) { + AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), + extraAnnotations); + if (!Asn1VarSizeBitstring.class.isAssignableFrom(classOfT)) { + UperEncoder.logger.debug("Bitlist(fixed-size, all-named)"); + FixedSize fixedSize = annotations.getAnnotation(FixedSize.class); + if (fixedSize == null) { throw new UnsupportedOperationException( + "bitstrings of non-fixed size that do not extend Asn1VarSizeBitstring are not supported yet"); + } + Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(classOfT); + if (fixedSize.value() != sorter.ordinaryFields.size()) { throw new IllegalArgumentException( + "Fixed size annotation " + fixedSize.value() + + " does not match the number of fields " + + sorter.ordinaryFields.size() + " in " + classOfT.getName()); } + if (UperEncoder.hasExtensionMarker(annotations)) { + boolean extensionPresent = bitbuffer.get(); + if (extensionPresent) { throw new UnsupportedOperationException( + "extensions in fixed-size bitlist are not supported yet"); } + } + T result = UperEncoder.instantiate(classOfT); + for (Field f : sorter.ordinaryFields) { + boolean value = bitbuffer.get(); + UperEncoder.logger.debug(String.format("Field %s set to %s", f.getName(), value)); + try { + f.set(result, value); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalArgumentException("can't decode " + classOfT, e); + } + } + return result; + } else { + UperEncoder.logger.debug("Bitlist(var-size)"); + FixedSize fixedSize = annotations.getAnnotation(FixedSize.class); + SizeRange sizeRange = annotations.getAnnotation(SizeRange.class); + // We use reflection here to access protected method of Asn1VarSizeBitstring. + // Alternative would be to mandate BitSet constructors for all subclasses of + // Asn1VarSizeBitstring. + Method setBitMethod; + try { + setBitMethod = Asn1VarSizeBitstring.class.getDeclaredMethod("setBit", int.class, + boolean.class); + setBitMethod.setAccessible(true); + } catch (SecurityException | NoSuchMethodException e) { + throw new AssertionError("Can't find/access setBit " + e); + } + Long size = (fixedSize != null) ? fixedSize.value() : + (sizeRange != null) ? UperEncoder.decodeConstrainedInt(bitbuffer, + UperEncoder.intRangeFromSizeRange(sizeRange)) : + badSize(classOfT); + T result = UperEncoder.instantiate(classOfT); + for (int i = 0; i < size; i++) { + try { + setBitMethod.invoke(result, i, bitbuffer.get()); + } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { + throw new IllegalArgumentException("Can't invoke setBit", e); + } + } + return result; + } + } + + /** This function only throws an exception, to be used in ternary (a?b:c) expression. */ + static <T> Long badSize(Class<T> classOfT) { + throw new IllegalArgumentException("both size range and fixed size are null for " + + classOfT.getName()); + } + + @Override + public <T> T getDefault(Class<T> classOfT, Annotation[] extraAnnotations) { + throw new IllegalArgumentException("Default Sequence not yet implemented"); + } +}
\ No newline at end of file |