diff options
Diffstat (limited to 'src/net/gcdc/asn1/uper/ChoiceCoder.java')
-rw-r--r-- | src/net/gcdc/asn1/uper/ChoiceCoder.java | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/net/gcdc/asn1/uper/ChoiceCoder.java b/src/net/gcdc/asn1/uper/ChoiceCoder.java new file mode 100644 index 0000000..4e258a5 --- /dev/null +++ b/src/net/gcdc/asn1/uper/ChoiceCoder.java @@ -0,0 +1,161 @@ +package net.gcdc.asn1.uper; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import net.gcdc.asn1.datatypes.Choice; +import net.gcdc.asn1.uper.UperEncoder.Asn1ContainerFieldSorter; + +class ChoiceCoder 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(Choice.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); + UperEncoder.logger.debug("CHOICE"); + int nonNullIndex = 0; + Field nonNullField = null; + Object nonNullFieldValue = null; + int currentIndex = 0; + Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(type); + try { + for (Field f : sorter.ordinaryFields) { + if (f.get(obj) != null) { + nonNullIndex = currentIndex; + nonNullFieldValue = f.get(obj); + nonNullField = f; + break; + } + currentIndex++; + } + if (nonNullFieldValue != null) { + if (UperEncoder.hasExtensionMarker(annotations)) { + boolean extensionBit = false; + UperEncoder.logger.debug(String.format("with extension marker, set to %s", extensionBit)); + bitbuffer.put(extensionBit); + } + if (sorter.ordinaryFields.size() > 1) { // Encode index only if more than one. + UperEncoder.logger.debug(String.format("with chosen element indexed %d", nonNullIndex)); + UperEncoder.encodeConstrainedInt(bitbuffer, nonNullIndex, 0, + sorter.ordinaryFields.size() - 1); + } + UperEncoder.encode2(bitbuffer, nonNullFieldValue, nonNullField.getAnnotations()); + return; + } else if (UperEncoder.hasExtensionMarker(annotations)) { + //CG encoding of extension fields + currentIndex = 0; + for (Field f : sorter.extensionFields) { + if (f.get(obj) != null) { + nonNullIndex = currentIndex; + nonNullFieldValue = f.get(obj); + nonNullField = f; + break; + } + currentIndex++; + } + if (nonNullField == null) { + UperEncoder.logger.debug(String.format("without choice of extension")); + return; + } + boolean extensionBit = true; + UperEncoder.logger.debug(String.format("with extension marker, set to <%s>", extensionBit)); + bitbuffer.put(extensionBit); + + //CG encode extension values + //Always encode index of the element + UperEncoder.logger.debug(String.format("with chosen extension element indexed %d", nonNullIndex)); + + //encode small integer even with value 0 + UperEncoder.encodeSmallInt(bitbuffer, nonNullIndex); + + //Encode as open field + UperEncoder.encodeAsOpenType(bitbuffer, nonNullFieldValue, nonNullField.getAnnotations()); + return; + } else { + throw new IllegalArgumentException("Not Extension and All ordinary fields of Choice are null"); + } + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalArgumentException("can't encode " + obj, e); + } catch (Asn1EncodingException e) { + throw new Asn1EncodingException("." + type.getName(), e); + } + } + + @Override public <T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations) { + AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), + extraAnnotations); + return annotations.getAnnotation(Choice.class) != null; + } + + @Override public <T> T decode(BitBuffer bitbuffer, + Class<T> classOfT, Field field1, + Annotation[] extraAnnotations) { + AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),extraAnnotations); + UperEncoder.logger.debug(String.format("CHOICE: %s", classOfT.getName())); + T result = UperEncoder.instantiate(classOfT); + Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(classOfT); + + // Reset all fields, since default constructor initializes one. + for (Field f : sorter.allFields) { + try { + f.set(result, null); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalArgumentException("can't decode " + classOfT, e); + } + } + if (UperEncoder.hasExtensionMarker(annotations)) { + UperEncoder.logger.debug("with extension marker"); + boolean extensionPresent = bitbuffer.get(); + if (extensionPresent) { + //CG extension support added + int i = (int) UperEncoder.decodeSmallInt(bitbuffer); + UperEncoder.logger.debug(String.format("extension with index %d is present",i)); + Field field = sorter.extensionFields.size() > i ? sorter.extensionFields.get(i) : null; + Class<?> classOfElement = field != null ? field.getType() : null; + if (field != null) { + try { + Object decodedValue = UperEncoder.decodeAsOpenType(bitbuffer, classOfElement,field, field.getAnnotations()); + if (field != null) { + field.set(result, decodedValue); + } + return result; + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalArgumentException("can't decode " + classOfT, e); + } + } else { + //CG skip the unknown extension element + UperEncoder.decodeSkipUnknownElement(bitbuffer, classOfT.getSimpleName()); + return null; + } + //throw new UnsupportedOperationException("choice extension is not implemented yet"); + } else { + UperEncoder.logger.debug(String.format("no extension present")); + //no extension is present + //We already consumed the bit, keep processing as if there were no extension. + } + } + int index = (int) UperEncoder.decodeConstrainedInt(bitbuffer, + UperEncoder.newRange(0, sorter.ordinaryFields.size() - 1, false)); + Field f = sorter.ordinaryFields.get(index); + UperEncoder.logger.debug(String.format("CHOICE: selected %s", f.getName())); + Object fieldValue = UperEncoder.decodeAny(bitbuffer, f.getType(),f, f.getAnnotations()); + try { + f.set(result, fieldValue); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalArgumentException("can't decode " + classOfT, e); + } + return result; + } + + @Override + public <T> T getDefault(Class<T> classOfT, Annotation[] extraAnnotations) { + throw new IllegalArgumentException("Default Choice not yet implemented"); + } + +}
\ No newline at end of file |