summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/uic/barcode/asn1/uper/IntCoder.java')
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/IntCoder.java267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java b/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java
new file mode 100644
index 0000000..87b561b
--- /dev/null
+++ b/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java
@@ -0,0 +1,267 @@
+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.Asn1Integer;
+import org.uic.barcode.asn1.datatypes.IntMinValue;
+import org.uic.barcode.asn1.datatypes.IntRange;
+
+
+class IntCoder implements Encoder, Decoder {
+
+
+
+ @Override public <T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations) {
+ return classOfT == Asn1Integer.class ||
+ classOfT == Asn1BigInteger.class||
+ classOfT == BigInteger.class ||
+ classOfT == Long.class ||
+ classOfT == Integer.class ||
+ classOfT == Short.class ;
+ }
+
+
+ @Override public <T> T decode(BitBuffer bitbuffer,
+ Class<T> classOfT, Field field,
+ Annotation[] extraAnnotations) {
+ AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),extraAnnotations);
+ String pos = String.format("Position: %d.%d", bitbuffer.position()/8 , bitbuffer.position() % 8);
+ UperEncoder.logger.debug(String.format("%s: INTEGER",pos));
+ IntRange intRange = annotations.getAnnotation(IntRange.class);
+ IntMinValue minValue = annotations.getAnnotation(IntMinValue.class);
+
+
+ if (intRange == null) {
+ return decodeUnconstrainedInteger(bitbuffer, classOfT, extraAnnotations, minValue);
+ }
+ UperEncoder.logger.debug(String.format("Integer, range %d..%d", intRange.minValue(), intRange.maxValue()));
+ return decodeConstrainedInteger(bitbuffer, classOfT, intRange, extraAnnotations);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> T decodeConstrainedInteger(BitBuffer bitbuffer, Class<T> classOfT, IntRange intRange, Annotation[] extraAnnotations) {
+
+ long value = UperEncoder.decodeConstrainedInt(bitbuffer, intRange);
+ UperEncoder.logger.debug(String.format("decoded as %d", value));
+
+ try {
+ if (classOfT == Asn1BigInteger.class) {
+ return ((T) new Asn1BigInteger(value));
+ } else if (classOfT == Asn1Integer.class) {
+ return (T) new Asn1Integer(value);
+ } else if (classOfT == BigInteger.class) {
+ return (T) BigInteger.valueOf(value);
+ } else if (classOfT == Long.class) {
+ return (T) Long.valueOf(value);
+ } else if (classOfT == Integer.class) {
+ return (T) Integer.valueOf(Long.valueOf(value).intValue());
+ } else if (classOfT == Short.class) {
+ return (T) Short.valueOf(Long.valueOf(value).shortValue());
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException("size too small " + classOfT.getName() + ": " + e);
+ }
+
+ return null;
+
+
+ }
+
+ @Override public <T> boolean canEncode(T obj, Annotation[] extraAnnotations) {
+ return obj instanceof Asn1Integer ||
+ obj instanceof Asn1BigInteger ||
+ obj instanceof BigInteger ||
+ obj instanceof Long ||
+ obj instanceof Integer ||
+ obj instanceof Short;
+ }
+
+ @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);
+ IntMinValue minValue = annotations.getAnnotation(IntMinValue.class);
+ int position = bitbuffer.position();
+
+ //get value
+ if (range == null) {
+
+ try {
+ encodeUnconstrainedInteger(bitbuffer, obj, extraAnnotations,minValue);
+ } catch (Asn1EncodingException e) {
+ throw new Asn1EncodingException(" " + type.getSimpleName(), e);
+ } catch (Exception e1){
+ throw new Asn1EncodingException(" " + type.getSimpleName() + " - " + e1.getLocalizedMessage());
+ }
+ UperEncoder.logger.debug(String.format("INT(%s): %s", obj, bitbuffer.toBooleanStringFromPosition(position)));
+
+
+ } else {
+
+ try {
+
+ long value = 0;
+ if (obj instanceof BigInteger) {
+ try {
+ value = ((BigInteger) obj).longValue();
+ } catch (Exception e) {
+
+ UperEncoder.logger.debug("constrained BigInteger is too big for constrained int");
+ throw new Asn1EncodingException("constrained BigInteger is too big for constrained int" + type.getSimpleName());
+ }
+ } if (obj instanceof Asn1BigInteger) {
+ try {
+ value = ((Asn1BigInteger) obj).longValue();
+ } catch (Exception e) {
+
+ UperEncoder.logger.debug("constrained Asn1BigInteger is too big for constrained int");
+ throw new Asn1EncodingException("constrained Asn1BigInteger is too big for constrained int" + type.getSimpleName());
+ }
+ } if (obj instanceof Asn1Integer) {
+ try {
+ value = Asn1Integer.toLong((Asn1Integer) obj);
+ } catch (Exception e) {
+
+ UperEncoder.logger.debug("constrained BigInteger is too big for constrained int");
+ throw new Asn1EncodingException("constrained BigInteger is too big for constrained int" + type.getSimpleName());
+ }
+ } else if (obj instanceof Long) {
+ value = ((Long) obj).longValue();
+ } else if (obj instanceof Integer) {
+ value = ((Integer) obj).longValue();
+ } else if (obj instanceof Short) {
+ value = ((Short) obj).longValue();
+ }
+
+ UperEncoder.encodeConstrainedInt(bitbuffer, value, range.minValue(), range.maxValue(), range.hasExtensionMarker());
+ } catch (Asn1EncodingException e) {
+ throw new Asn1EncodingException(" " + type.getSimpleName(), e);
+ } catch (Exception e1){
+ throw new Asn1EncodingException(" " + type.getSimpleName() + " - " + e1.getLocalizedMessage());
+ }
+ UperEncoder.logger.debug(String.format("INT(%s): %s", obj, bitbuffer.toBooleanStringFromPosition(position)));
+ }
+ return;
+ }
+
+ private <T> void encodeUnconstrainedInteger(BitBuffer bitbuffer, Object obj, Annotation[] annotations, IntMinValue minValue) throws Asn1EncodingException {
+
+
+ BigInteger bint = null;
+ try {
+ if (obj instanceof BigInteger) {
+ bint = (BigInteger) obj;
+ } else if (obj instanceof Asn1BigInteger) {
+ bint = BigInteger.valueOf(((Asn1BigInteger) obj).longValue());
+ } else if (obj instanceof Asn1Integer) {
+ bint = BigInteger.valueOf(((Asn1Integer) obj).value());
+ } else if (obj instanceof Long) {
+ bint = BigInteger.valueOf(((Long) obj).longValue());
+ } else if (obj instanceof Integer) {
+ bint = BigInteger.valueOf(((Integer) obj).longValue());
+ } else if (obj instanceof Short) {
+ bint = BigInteger.valueOf(((Short) obj).longValue());
+ }
+ } catch (Exception e1){
+ throw new Asn1EncodingException(" " + obj.getClass().getSimpleName() + " - " + e1.getLocalizedMessage());
+ }
+
+
+ if (minValue != null) {
+ bint.subtract(BigInteger.valueOf(minValue.minValue()));
+ }
+
+ 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 INTEGER", e);
+ }
+ int position2 = bitbuffer.position();
+ for (byte b : array) {
+ bitbuffer.putByte(b);
+ }
+ UperEncoder.logger.debug(String.format("INTEGER Int(%s): len %s, val %s", bint.toString(),
+ bitbuffer.toBooleanString(position1, position2 - position1),
+ bitbuffer.toBooleanStringFromPosition(position2)));
+ return;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T decodeUnconstrainedInteger(BitBuffer bitbuffer, Class<T> classOfT, Annotation[] extraAnnotations,IntMinValue minValue) {
+ 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());
+ if (minValue != null) {
+ resultValue.add(BigInteger.valueOf(minValue.minValue()));
+ }
+
+ UperEncoder.logger.debug(String.format("INTEGER Decoded as %s", resultValue));
+
+ try {
+ if (classOfT == Asn1BigInteger.class) {
+ return (T) new Asn1BigInteger(resultValue);
+ } else if (classOfT == BigInteger.class) {
+ return (T) resultValue;
+ } else if (classOfT == Long.class) {
+ return (T) Long.valueOf(resultValue.longValueExact());
+ } else if (classOfT == Integer.class) {
+ return (T) Integer.valueOf(resultValue.intValueExact());
+ } else if (classOfT == Short.class) {
+ return (T) Short.valueOf(resultValue.shortValueExact());
+ }
+ } catch (Exception e){
+ UperEncoder.logger.debug(String.format("INTEGER Decoded as %s is too big for data type", resultValue));
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @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);
+
+ try {
+ if (classOfT == Asn1BigInteger.class) {
+ return ((T) new Asn1BigInteger(value));
+ } else if (classOfT == BigInteger.class) {
+ return (T) BigInteger.valueOf(value);
+ } else if (classOfT == Long.class) {
+ return (T) Long.valueOf(value);
+ } else if (classOfT == Integer.class) {
+ return (T) Integer.valueOf(Long.valueOf(value).intValue());
+ } else if (classOfT == Short.class) {
+ return (T) Short.valueOf(Long.valueOf(value).shortValue());
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException("size too small " + classOfT.getName() + ": " + e);
+ }
+
+ return null;
+ }
+
+} \ No newline at end of file