package net.gcdc.asn1.uper; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayDeque; import java.util.Deque; import net.gcdc.asn1.datatypes.Asn1Default; import net.gcdc.asn1.datatypes.Asn1SequenceOf; import net.gcdc.asn1.datatypes.Sequence; import net.gcdc.asn1.uper.UperEncoder.Asn1ContainerFieldSorter; class SequenceCoder implements Decoder, Encoder { @Override public boolean canEncode(T obj, Annotation[] extraAnnotations) { Class type = obj.getClass(); AnnotationStore annotations = new AnnotationStore(type.getAnnotations(), extraAnnotations); return annotations.getAnnotation(Sequence.class) != null; } @Override public 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: SEQUENCE %s", pos, type.getSimpleName())); Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(type); try { if (UperEncoder.hasExtensionMarker(annotations)) { boolean extensionsPresent = !sorter.extensionFields.isEmpty() && UperEncoder.hasNonNullExtensions(obj, sorter); UperEncoder.logger.debug(String.format("with extension marker, %s extensions, extensionBit: <%s>", extensionsPresent ? "with" : "without", extensionsPresent)); bitbuffer.put(extensionsPresent); } // Bitmask for optional fields. for (Field f : sorter.optionalOrdinaryFields) { boolean fieldPresent = isPresent(f, f.get(obj)); UperEncoder.logger.debug(String.format("with optional field %s %s, presence encoded as bit <%s>", f.getName(), fieldPresent ? "present" : "absent", fieldPresent)); bitbuffer.put(fieldPresent); // null means the field is absent. } // All ordinary fields (fields within extension root). for (Field f : sorter.ordinaryFields) { //CG do not include default values if (UperEncoder.isMandatory(f) || isPresent(f,f.get(obj))) { pos = String.format("Position: %d.%d", bitbuffer.position()/8 , bitbuffer.position() % 8); UperEncoder.logger.debug(String.format("%s: Field %s", pos, f.getName())); try { UperEncoder.encode2(bitbuffer, f.get(obj), f.getAnnotations()); } catch (Asn1EncodingException e) { throw new Asn1EncodingException("." + f.getName(), e); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Illegal value for field " + f.getName(), e); } } } // Extension fields. if (UperEncoder.hasExtensionMarker(annotations) && !sorter.extensionFields.isEmpty() && UperEncoder.hasNonNullExtensions(obj, sorter)) { // Total extensions count. int numExtensions = sorter.extensionFields.size(); UperEncoder.logger.debug(String.format("continuing sequence : %d extension(s) are present, encoding length determinant for them...", numExtensions)); UperEncoder.encodeLengthOfBitmask(bitbuffer, numExtensions); // Bitmask for present extensions. for (Field f : sorter.extensionFields) { boolean fieldIsPresent = isPresent(f,f.get(obj)); UperEncoder.logger.debug(String.format("Extension %s is %s, presence encoded as <%s>", f.getName(), fieldIsPresent ? "present" : "absent", fieldIsPresent ? "1" : "0")); bitbuffer.put(fieldIsPresent); } // Values of extensions themselves. for (Field f : sorter.extensionFields) { //CG do not encode default values if (UperEncoder.isMandatory(f) || isPresent(f,f.get(obj))) { UperEncoder.logger.debug(String.format("Encoding extension field %s", f.getName())); try { UperEncoder.encodeAsOpenType(bitbuffer, f.get(obj), f.getAnnotations()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Illegal value for extension field " + f.getName(), e); } } } } } catch (IllegalArgumentException | IllegalAccessException e) { throw new IllegalArgumentException("can't encode " + obj, e); } sorter.revertAccess(); } @SuppressWarnings("unchecked") protected boolean isPresent(Field f, Object fieldObject){ if (fieldObject == null) return false; boolean fieldPresent = fieldObject != null; if (fieldObject instanceof Asn1SequenceOf) { if (((Asn1SequenceOf)fieldObject).size() == 0){ //CG do not encode optional empty sequences fieldPresent = false; } } if (fieldObject instanceof String) { if (((String)fieldObject).length() == 0){ //CG do not encode optional empty sequences fieldPresent = false; } } //CG DEFAULT VALUES if (fieldPresent && UperEncoder.isDefault(f,fieldObject)) { UperEncoder.logger.debug(String.format("Field %s has default value", f.getName())); fieldPresent = false; } //CG No ASN1 if (UperEncoder.isNotAsn1(f)) { fieldPresent = false; } return fieldPresent; } @Override public boolean canDecode(Class classOfT, Annotation[] extraAnnotations) { AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), extraAnnotations); return annotations.getAnnotation(Sequence.class) != null; } @Override public T decode(BitBuffer bitbuffer, Class classOfT,Field f1, Annotation[] extraAnnotations) { UperEncoder.logger.debug(String.format("decode SEQUENCE %s",classOfT.getSimpleName())); AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),extraAnnotations); T result = UperEncoder.instantiate(classOfT); Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(classOfT); boolean hasExtensionMarker = UperEncoder.hasExtensionMarker(annotations); boolean extensionPresent = false; if (hasExtensionMarker) { extensionPresent = bitbuffer.get(); UperEncoder.logger.debug(String.format("with extension marker, extension %s", extensionPresent ? "present!" : "absent")); } // Bitmask for optional fields. Deque optionalFieldsMask = new ArrayDeque<>(sorter.optionalOrdinaryFields.size()); for (Field f : sorter.optionalOrdinaryFields) { optionalFieldsMask.add(bitbuffer.get()); UperEncoder.logger.debug(String.format("with optional field %s %s" , f.getName() , optionalFieldsMask.getLast() ? "present" : "absent")); } // All ordinary fields (fields within extension root). for (Field f : sorter.ordinaryFields) { if (!UperEncoder.isTestInstrumentation(f) && (UperEncoder.isMandatory(f) || (UperEncoder.isOptional(f) && optionalFieldsMask.pop()))) { UperEncoder.logger.debug(String.format("Field : %s", f.getName())); try { f.set(result, UperEncoder.decodeAny(bitbuffer,f.getType(),f, f.getAnnotations())); } catch (IllegalAccessException e) { throw new IllegalArgumentException("can't access 'set method' for field " + f + " of class " + classOfT + " " + e, e); } } else { //CG might have a default value if (f.getAnnotation(Asn1Default.class) != null) { try { UperEncoder.logger.debug(String.format(String.format("Retrieve default for element : %s",f.getName()))); f.set(result,UperEncoder.getDefault(f.getType(),f.getAnnotations())); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("can't decode " + classOfT, e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("can't decode " + classOfT, e); } } } } if (!hasExtensionMarker) { //done sorter.revertAccess(); return result; } // Possible extensions int numExtensions = 0; if (UperEncoder.hasExtensionMarker(annotations)){ if (extensionPresent) { // Number of extensions. numExtensions = (int) UperEncoder.decodeLengthOfBitmask(bitbuffer); UperEncoder.logger.debug(String.format("sequence has %d extension(s)", numExtensions)); // Bitmask for extensions. boolean[] bitmaskValueIsPresent = new boolean[numExtensions]; for (int i = 0; i < numExtensions; i++) { bitmaskValueIsPresent[i] = bitbuffer.get(); UperEncoder.logger.debug(String.format("extension %s is %s", i, bitmaskValueIsPresent[i] ? "present" : "absent")); } // Values. UperEncoder.logger.debug("decoding extensions values..."); for (int i = 0; i < numExtensions; i++) { UperEncoder.logger.debug(String.format("sequence extension %s %s", i, bitmaskValueIsPresent[i] ? "present" : "absent")); if (bitmaskValueIsPresent[i]) { UperEncoder.logger.debug(String.format("decoding extension %d...", 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); } } catch (IllegalArgumentException | IllegalAccessException e) { throw new IllegalArgumentException("can't decode " + classOfT, e); } } else { //CG skip the unknown extension element UperEncoder.decodeSkipUnknownElement(bitbuffer, classOfT.getSimpleName()); } } else { //CG the absent extension filed might have a default value Field field = sorter.extensionFields.size() > i ? sorter.extensionFields.get(i) : null; Class classOfElement = field != null ? field.getType() : null; if (field != null && field.getAnnotation(Asn1Default.class) != null) { try { field.set(result,UperEncoder.getDefault(classOfElement,field.getAnnotations())); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("can't decode " + classOfElement.getSimpleName(), e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("can't decode " + classOfElement.getSimpleName(), e); } UperEncoder.logger.debug(String.format("Default set for %s", field.getName())); } } }//end of loop on present extension fields } else { //CG there is an extension marker but the extension is not present // then there sill might be an element with a default value for (Field field : sorter.extensionFields) { if ( numExtensions <= sorter.extensionFields.indexOf(field)) { if (field.getAnnotation(Asn1Default.class) != null) { Class classOfElement = field != null ? field.getType() : null; try { field.set(result,UperEncoder.getDefault(classOfElement, field.getAnnotations())); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("can't decode default" + classOfElement.getSimpleName(), e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("can't decode default" + classOfElement.getSimpleName(), e); } } } } } // end of extension handling } sorter.revertAccess(); return result; } @Override public T getDefault(Class classOfT, Annotation[] annotations) { throw new IllegalArgumentException("Default Sequence not yet implemented"); } }