summaryrefslogblamecommitdiffstats
path: root/src/net/gcdc/asn1/uper/ChoiceCoder.java
blob: 4e258a590a8d901172d557e06b29fcba3a6ac614 (plain) (tree)
































































































































































                                                                                                                                            
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");
	}

}