summaryrefslogtreecommitdiffstats
path: root/src/org/uic/barcode/asn1/uper/BigIntCoder.java
blob: 94e4b05a36155ac30e20fe3747848280ee4f8b17 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package org.uic.barcode.asn1.uper;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.math.BigInteger;

import org.uic.barcode.asn1.datatypes.Asn1BigInteger;
import org.uic.barcode.asn1.datatypes.Asn1Default;
import org.uic.barcode.asn1.datatypes.IntRange;

class BigIntCoder implements Encoder, Decoder {

    @Override public <T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations) {
        return Asn1BigInteger.class.isAssignableFrom(classOfT);
    }

    @Override public <T> T decode(BitBuffer bitbuffer,
            Class<T> classOfT, Field f,
            Annotation[] extraAnnotations) {
        AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),
                extraAnnotations);
    	
    	String pos = String.format("%d.%d", bitbuffer.position()/8 , bitbuffer.position() % 8);
        UperEncoder.logger.debug(String.format("Position %s BIG INT",pos));
        IntRange intRange = annotations.getAnnotation(IntRange.class);
        if (intRange != null && intRange.maxValue() > 0) { 
        	throw new UnsupportedOperationException("Big int with upper range is not supported yet"); 
        }

        int lengthInOctets = (int) UperEncoder.decodeLengthDeterminant(bitbuffer);
        BitBuffer valueBits = ByteBitBuffer.allocate(lengthInOctets * 8);
        for (int i = 0; i < lengthInOctets * 8; i++) {
            valueBits.put(bitbuffer.get());
        }
        valueBits.flip();
        BigInteger resultValue = new BigInteger(+1, valueBits.array());
        UperEncoder.logger.debug(String.format("big int Decoded as %s", resultValue));
        
        
        //CG support for int range
        if (intRange != null){
        	resultValue.add(BigInteger.valueOf(intRange.minValue()));
        }
        
        
        return UperEncoder.instantiate(classOfT, resultValue);
    }

    @Override public <T> boolean canEncode(T obj, Annotation[] extraAnnotations) {
        return obj instanceof Asn1BigInteger;
    }

    @Override public <T> void encode(BitBuffer bitbuffer, T obj, Annotation[] extraAnnotations) throws Asn1EncodingException {
        Class<?> type = obj.getClass();
        AnnotationStore annotations = new AnnotationStore(type.getAnnotations(), extraAnnotations);
        IntRange range = annotations.getAnnotation(IntRange.class);
        
        //CG implementation with lower range limit added
        BigInteger bint = ((Asn1BigInteger) obj).toBigInteger();
        if (range != null) { 
       		throw new UnsupportedOperationException("Asn1 BigInteger with range is not supported"); 
        }
        byte[] array = bint.toByteArray();
        int lengthInOctets = array.length;
        int position1 = bitbuffer.position();
        try {
            UperEncoder.encodeLengthDeterminant(bitbuffer, lengthInOctets);
        } catch (Asn1EncodingException e) {
            throw new Asn1EncodingException(" length determinant of " + type.getName(), e);
        }
        int position2 = bitbuffer.position();
        for (byte b : array) {
            bitbuffer.putByte(b);
        }
        UperEncoder.logger.debug(String.format("Big Int(%s): len %s, val %s", obj,
                 bitbuffer.toBooleanString(position1, position2 - position1),
                 bitbuffer.toBooleanStringFromPosition(position2)));
        return;
    }

	@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;
	        //check whether the class has a constructor for numeric types
	        String valueString = defaultAnnotation.value();
	        long value = Long.parseLong(valueString);
	        UperEncoder.logger.debug(String.format("Default INTEGER: %d",value ));
	        
	        @SuppressWarnings("unchecked")
			T t = (T) new Asn1BigInteger(value);
			return t;

	}

}