summaryrefslogtreecommitdiffstats
path: root/src/net/gcdc/asn1/uper/UperEncoder.java
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/net/gcdc/asn1/uper/UperEncoder.java721
1 files changed, 0 insertions, 721 deletions
diff --git a/src/net/gcdc/asn1/uper/UperEncoder.java b/src/net/gcdc/asn1/uper/UperEncoder.java
deleted file mode 100644
index 30aa82b..0000000
--- a/src/net/gcdc/asn1/uper/UperEncoder.java
+++ /dev/null
@@ -1,721 +0,0 @@
-package net.gcdc.asn1.uper;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import logger.Logger;
-import logger.LoggerFactory;
-
-import net.gcdc.asn1.datatypes.Asn1Default;
-import net.gcdc.asn1.datatypes.Asn1Optional;
-import net.gcdc.asn1.datatypes.FieldOrder;
-import net.gcdc.asn1.datatypes.HasExtensionMarker;
-import net.gcdc.asn1.datatypes.IntRange;
-import net.gcdc.asn1.datatypes.IsExtension;
-import net.gcdc.asn1.datatypes.NoAsn1Field;
-import net.gcdc.asn1.datatypes.SizeRange;
-
-
-
-/** A "quick-and-dirty" implementation of ASN.1 encoder for UPER (Unaligned Packed Encoding Rules).
- *
- * @see ITU-T Recommendation <a
- * href="http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=x.691">X.691</a>
- *
- * TODO: Cover the rest of (useful) ASN.1 datatypes and PER-visible constraints,
- * write unit tests for them. Clean-up, do more refactoring.
- **/
-public final class UperEncoder {
- public final static Logger logger = LoggerFactory.getLogger("asnLogger");
-
- private final static int NUM_16K = 16384;
- @SuppressWarnings("unused")
- private final static int NUM_32K = 32768;
- @SuppressWarnings("unused")
- private final static int NUM_48K = 49152;
- @SuppressWarnings("unused")
- private final static int NUM_64K = 65536;
-
- private UperEncoder(){}
-
- public static <T> byte[] encode(T obj)
- throws IllegalArgumentException, UnsupportedOperationException {
- try {
- BitBuffer bitbuffer = ByteBitBuffer.createInfinite();
- encode2(bitbuffer, obj, new Annotation[] {});
- bitbuffer.flip();
- byte[] result = Arrays.copyOf(bitbuffer.array(), (bitbuffer.limit() + 7) / 8);
- return result;
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Can't encode " + obj.getClass().getName() + ": " + e, e);
- } catch (Asn1EncodingException e) {
- throw new IllegalArgumentException("Can't encode " + obj.getClass().getName() + ":" + e.getMessage(), e);
- }
- }
-
- public static <T> T decode(byte[] bytes, Class<T> classOfT) throws IllegalArgumentException,
- UnsupportedOperationException {
- BitBuffer bitQueue = bitBufferFromBinaryString(binaryStringFromBytes(bytes));
- T result = decodeAny(bitQueue, classOfT,null, new Annotation[] {});
- if (bitQueue.remaining() > 7) {
- throw new IllegalArgumentException("Can't fully decode "
- + classOfT.getName() + ", got (" + result.getClass().getName() + "): " + result
- + "; remaining " + bitQueue.remaining() + " bits: " + bitQueue);
- }
- return result;
- }
-
- public static <T> T decode(byte[] bytes, Class<T> classOfT, Field f) throws IllegalArgumentException,
- UnsupportedOperationException {
- BitBuffer bitQueue = bitBufferFromBinaryString(binaryStringFromBytes(bytes));
- T result = decodeAny(bitQueue, classOfT, f, new Annotation[] {});
- if (bitQueue.remaining() > 7) {
- throw new IllegalArgumentException("Can't fully decode "
- + classOfT.getName() + ", got (" + result.getClass().getName() + "): " + result
- + "; remaining " + bitQueue.remaining() + " bits: " + bitQueue);
- }
- return result;
- }
-
-
- static <T> void encode2(BitBuffer bitbuffer, T obj, Annotation[] extraAnnotations) throws Asn1EncodingException {
- for (Encoder e : encoders) {
- if (e.canEncode(obj, extraAnnotations)) {
- e.encode(bitbuffer, obj, extraAnnotations);
- return;
- }
- }
- logger.debug(String.format("Can't find encoder for %s",obj.getClass().getSimpleName()));
-
- throw new IllegalArgumentException("Can't find encoder for " + obj.getClass().getName()
- + " with extra annotations " + Arrays.asList(extraAnnotations));
- }
-
- static <T> T decodeAny(BitBuffer bitbuffer,Class<T> classOfT, Field f, Annotation[] extraAnnotations) {
-
- logger.debug(String.format(String.format("Decoding classOfT : %s",classOfT.getCanonicalName())));
-
- for (Decoder e : decoders) {
- if (e.canDecode(classOfT, extraAnnotations)) {
- return e.decode(bitbuffer, classOfT,f, extraAnnotations);
- }
- }
-
- logger.debug(String.format("Can't find decoder for %s",classOfT.getSimpleName()));
-
- throw new IllegalArgumentException("Can't find decoder for " + classOfT.getName()
- + " with extra annotations " + Arrays.asList(extraAnnotations));
- }
-
- static <T> T getDefault(Class<T> classOfT, Annotation[] annotations) {
- AnnotationStore annots = new AnnotationStore(classOfT.getAnnotations(), annotations);
- Asn1Default defaultAnnotation = annots.getAnnotation(Asn1Default.class);
-
- if (defaultAnnotation == null){
- return null;
- }
-
- Annotation[] defaultAnnots = new Annotation[] {defaultAnnotation};
-
- for (Decoder e : decoders) {
- if (e.canDecode(classOfT, defaultAnnots)) {
- return e.getDefault(classOfT, defaultAnnots);
- }
- }
- logger.debug(String.format("Can't find decoder for %s",classOfT.getSimpleName()));
-
- throw new IllegalArgumentException("Can't find default for " + classOfT.getName()
- + " with extra annotations " + defaultAnnotation.toString());
- }
-
- static IntRange newRange(
- final long minValue,
- final long maxValue,
- final boolean hasExtensionMarker) {
-
- return new IntRange() {
- @Override public Class<? extends Annotation> annotationType() {
- return IntRange.class;
- }
- @Override public long minValue() { return minValue; }
- @Override public long maxValue() { return maxValue; }
- @Override public boolean hasExtensionMarker() { return hasExtensionMarker; }
- };
- }
-
- static IntRange intRangeFromSizeRange(SizeRange sizeRange) {
- return newRange(sizeRange.minValue(), sizeRange.maxValue(), sizeRange.hasExtensionMarker());
- }
-
- private static List<Encoder> encoders = new ArrayList<>();
- private static List<Decoder> decoders = new ArrayList<>();
-
- static {
- encoders.add(new IntCoder());
- //encoders.add(new BigIntCoder());
- encoders.add(new ByteCoder());
- encoders.add(new BooleanCoder());
- encoders.add(new SequenceCoder());
- encoders.add(new ChoiceCoder());
- encoders.add(new EnumCoder());
- encoders.add(new BitStringCoder());
- encoders.add(new SeqOfCoder());
- encoders.add(new StringCoder());
-
- decoders.add(new IntCoder());
- //decoders.add(new BigIntCoder());
- decoders.add(new ByteCoder());
- decoders.add(new BooleanCoder());
- decoders.add(new SequenceCoder());
- decoders.add(new ChoiceCoder());
- decoders.add(new EnumCoder());
- decoders.add(new BitStringCoder());
- decoders.add(new SeqOfCoder());
- decoders.add(new StringCoder());
-
- }
-
-
- static <T> void encodeAsOpenType(
- BitBuffer bitbuffer, T obj, Annotation[] extraAnnotations)
- throws IllegalArgumentException, IllegalAccessException, Asn1EncodingException {
- logger.debug(String.format("OPEN TYPE for {%s}. Encoding preceedes length determinant" ,obj != null ? obj.getClass().getSimpleName() : "null"));
- BitBuffer tmpbuffer = ByteBitBuffer.createInfinite();
- encode2(tmpbuffer, obj, extraAnnotations);
- int numBytes = (tmpbuffer.position() + 7) / 8;
- logger.debug(String.format("Encoding open type length determinant (%d) for %s (will be inserted before the open type content)", numBytes, obj != null ? obj.getClass().getName() : "null" ));
- try {
- encodeLengthDeterminant(bitbuffer, numBytes);
- } catch (Asn1EncodingException e) {
- throw new Asn1EncodingException(" length of open type ", e);
- }
- tmpbuffer.flip();
- for (int i = 0; i < tmpbuffer.limit(); i++) {
- bitbuffer.put(tmpbuffer.get());
- }
- //CG padding bits to fill the byte: Open Types are wrapped in an OCTET STRING
- int paddingBits = numBytes*8 - tmpbuffer.limit();
- for (int i = 0; i < paddingBits; i++) {
- bitbuffer.put(false);
- }
-
- }
-
- static <T> T decodeAsOpenType(BitBuffer bitbuffer, Class<T> classOfT,Field f, Annotation[] extraAnnotations) {
- logger.debug(String.format("OPEN TYPE for %s. Encoding preceedes length determinant", classOfT != null ? classOfT.getName() : "null"));
- long numBytes = decodeLengthDeterminant(bitbuffer);
- BitBuffer openTypeBitBuffer = ByteBitBuffer.allocate((int)numBytes * 8);
- for (int i = 0; i < numBytes * 8; i++) {
- openTypeBitBuffer.put(bitbuffer.get());
- }
- openTypeBitBuffer.flip();
- if (classOfT != null) {
- T result = decodeAny(openTypeBitBuffer, classOfT, f, extraAnnotations);
- // Assert that padding bits are all 0.
- logger.debug(String.format("open type had padding bits"));
- for (int i = 0; i < openTypeBitBuffer.remaining(); i++) {
- boolean paddingBit = openTypeBitBuffer.get();
- logger.debug(String.format("padding bit %d was <%s>", i, paddingBit ? "1" : "0"));
- if (paddingBit) {
- throw new IllegalArgumentException("non-zero padding bit " + i + " for open type " + classOfT.getSimpleName()); }
- }
- return result;
- } else {
- return null;
- }
- }
-
- /*
- * skip an unknown extension element
- * - decode length
- * - skip the bytes according to the length
- */
- static void decodeSkipUnknownElement(BitBuffer bitbuffer, String name) {
- logger.debug(String.format("Skip unknown extension in %s. Encoding preceedes length determinant", name));
- long numBytes = decodeLengthDeterminant(bitbuffer);
- for (int i = 0; i < numBytes * 8; i++) {
- bitbuffer.get();
- }
- logger.debug(String.format(String.format("Skiped %d bytes", numBytes)));
- }
-
- static <T> boolean hasNonNullExtensions(
- T obj, Asn1ContainerFieldSorter sorter)
- throws IllegalArgumentException, IllegalAccessException {
- for (Field f : sorter.extensionFields) {
- //CG elements with default value will not be not included
- if (f.get(obj) != null && !isDefault(f,f.get(obj)) ) {
- return true;
- }
- }
- return false;
- }
-
- private static <T> Constructor<T> findConsturctor(Class<T> classOfT, Object... parameters) {
- @SuppressWarnings("unchecked")
- Constructor<T>[] declaredConstructors = (Constructor<T>[]) classOfT
- .getDeclaredConstructors();
- for (Constructor<T> c : declaredConstructors) {
- Class<?>[] parameterTypes = c.getParameterTypes();
- if (parameterTypes.length == parameters.length) {
- boolean constructorIsOk = true;
- for (int i = 0; i < parameters.length; i++) {
- if (!parameterTypes[i].isAssignableFrom(parameters[i].getClass())) {
- constructorIsOk = false;
- break;
- }
- }
- if (constructorIsOk) { return c; }
- }
- }
- Class<?>[] parameterTypes = new Class<?>[parameters.length];
- for (int i = 0; i < parameters.length; i++) {
- parameterTypes[i] = parameters[i].getClass();
- }
- throw new IllegalArgumentException("Can't get the " + parameters.length +
- "-argument constructor for parameter(s) "
- + Arrays.asList(parameters) +
- " of type(s) " + Arrays.asList(parameterTypes) + " for class "
- + classOfT.getName() + " (" + classOfT.getClass().getName() + " or " + Arrays.asList(classOfT.getClasses()) + ")" +
- ", all constructors: " + Arrays.asList(classOfT.getDeclaredConstructors()));
- }
-
- /** Instantiate a given class T using given parameters. */
- static <T> T instantiate(Class<T> classOfT, Object... parameters) {
- Class<?>[] parameterTypes = new Class<?>[parameters.length];
- for (int i = 0; i < parameters.length; i++) {
- parameterTypes[i] = parameters[i].getClass();
- }
- Constructor<T> constructor = findConsturctor(classOfT, parameters);
- boolean constructorIsAccessible = constructor.isAccessible();
- constructor.setAccessible(true);
- T result;
- try {
- result = constructor.newInstance(parameters);
- } catch (IllegalArgumentException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
- throw new IllegalArgumentException("Can't instantiate " + classOfT.getName(), e);
- }
- constructor.setAccessible(constructorIsAccessible);
- return result;
- }
-
- static long decodeConstrainedInt(BitBuffer bitqueue, IntRange intRange) {
- long lowerBound = intRange.minValue();
- long upperBound = intRange.maxValue();
- boolean hasExtensionMarker = intRange.hasExtensionMarker();
- if (upperBound < lowerBound) {
- throw new IllegalArgumentException("Lower bound " + lowerBound + " is larger that upper bound " + upperBound);
- }
- if (hasExtensionMarker) {
- boolean extensionIsActive = bitqueue.get();
- if (extensionIsActive) {
- //in extensions are encoded as uncontraint integers, thius an Asn1BigInteger type should be used(a lower range bound might be applied).
- throw new UnsupportedOperationException("int extension are not supported yet");
- }
- }
- final Long range = upperBound - lowerBound + 1;
- if (range == 1) {
- return lowerBound;
- }
- int bitlength = BigInteger.valueOf(range - 1).bitLength();
- logger.debug(String.format("This int will require %d bits, available %d" , bitlength, bitqueue.remaining()));
- BitBuffer relevantBits = ByteBitBuffer.allocate( ((bitlength + 7) / 8) * 8); // Full bytes.
- int numPaddingBits = (8 - (bitlength % 8)) % 8; // Leading padding 0-bits.
- for (int i = 0; i < numPaddingBits; i++) {
- relevantBits.put(false);
- }
- for (int i = 0; i < bitlength; i++) {
- relevantBits.put(bitqueue.get());
- }
- relevantBits.flip();
- final BigInteger big = new BigInteger(+1, relevantBits.array());
- final Long result = lowerBound + big.longValue();
- logger.debug(String.format("bits %s decoded as %d plus lower bound %d give %d",
- relevantBits.toBooleanStringFromPosition(0), big.longValue(), lowerBound, result));
- if ((result < intRange.minValue() || intRange.maxValue() < result)
- && !intRange.hasExtensionMarker()) {
- throw new AssertionError("Decoded value "
- + result + " is outside of range (" + intRange.minValue() + ".."
- + intRange.maxValue() + ")");
- }
- return result;
- }
-
-
- //CG Begin
- static boolean isDefault(Field f, Object obj) {
-
- if (f.getAnnotation(Asn1Default.class) != null) {
- String value = f.getAnnotation(Asn1Default.class).value();
- if (obj.toString().equals(value)){
- return true;
- }
- }
- return false;
-
- }
-
-
- public static boolean isNotAsn1(Field f) {
- return (f.getAnnotation(NoAsn1Field.class) != null);
- }
- //CG End
-
-
- static boolean hasExtensionMarker(AnnotationStore annotations) {
- return annotations.getAnnotation(HasExtensionMarker.class) != null;
- }
-
- private static boolean isExtension(Field f) {
- return f.getAnnotation(IsExtension.class) != null;
- }
-
- static boolean isMandatory(Field f) {
- return !isOptional(f);
- }
-
- static boolean isOptional(Field f) {
- //CG elements with default value are treated as optional as they are not encoded in case of the default value
- if (f.getAnnotation(Asn1Optional.class) != null ||
- f.getAnnotation(Asn1Default.class) != null) {
- return true;
- }
- return false;
- }
-
- static class Asn1ContainerFieldSorter {
- /** "Outside extension root" */
- List<Field> extensionFields = new ArrayList<>();
- List<Field> optionalExtensionFields = new ArrayList<>();
- List<Field> mandatoryExtensionField = new ArrayList<>();
- /** "Within extension root" */
- List<Field> ordinaryFields = new ArrayList<>();
- List<Field> mandatoryOrdinaryFields = new ArrayList<>();
- List<Field> optionalOrdinaryFields = new ArrayList<>();
- List<Field> allFields = new ArrayList<>(); // Excluding test instrumentation.
-
- Map<Field, Boolean> originalAccess = new HashMap<>();
-
- Asn1ContainerFieldSorter(Class<?> type) {
-
- /*
- *
- * sorting of the fields added to compensate the error
- * in the java SDK on android where getDeclaredFields does
- * not return the fields in the order of the class definition
- *
- */
- List<Field> fields = Arrays.asList(type.getDeclaredFields());
- Collections.sort(fields, new Comparator<Field>() {
- @Override
- public int compare(Field o1, Field o2) {
- FieldOrder ao1 = o1.getAnnotation(FieldOrder.class);
- FieldOrder ao2 = o2.getAnnotation(FieldOrder.class);
- int order1 = ao1 == null ? Integer.MAX_VALUE : ao1.order();
- int order2 = ao2 == null ? Integer.MAX_VALUE : ao2.order();
- if (order1 == Integer.MAX_VALUE || order2 == Integer.MAX_VALUE || order1 < 0 || order2 < 0 || order1 == order2) {
- logger.debug(String.format("field order error for %s",type.getSimpleName()));
- }
- return Integer.compare(order1, order2);
- }
- });
-
-
- for (Field f : fields) {
- if (isTestInstrumentation(f) || isNonAsn1Field(f) ) {
- continue;
- }
- originalAccess.put(f, f.isAccessible());
- f.setAccessible(true);
- if (isExtension(f)) {
- extensionFields.add(f);
- if (isOptional(f)) {
- optionalExtensionFields.add(f);
- } else {
- mandatoryExtensionField.add(f);
- }
- }
- else {
- ordinaryFields.add(f);
- }
- allFields.add(f);
- }
- for (Field f : ordinaryFields) {
- if (isMandatory(f)) {
- mandatoryOrdinaryFields.add(f);
- } else {
- optionalOrdinaryFields.add(f);
- }
- }
- }
-
- public void revertAccess() {
- for (Entry<Field, Boolean> entry : originalAccess.entrySet()) {
- entry.getKey().setAccessible(entry.getValue());
- }
- }
- }
-
- static boolean isTestInstrumentation(Field f) {
- return f.getName().startsWith("$");
- }
-
- static boolean isNonAsn1Field(Field f) {
- if (f.getAnnotation(NoAsn1Field.class) != null) {
- return true;
- }
- return false;
- }
-
- static void encodeLengthOfBitmask(BitBuffer bitbuffer, int n) throws Asn1EncodingException {
- try {
- if (n <= 63) {
- logger.debug(String.format("normally small length of bitmask, length %d <= 63 indicated as bit <0>", n));
- bitbuffer.put(false);
- encodeConstrainedInt(bitbuffer, n, 1, 63);
- return;
- } else {
- logger.debug(String.format("normally small length of bitmask, length %s > 63 indicated as bit <1>", n));
- bitbuffer.put(true);
- encodeLengthDeterminant(bitbuffer, n);
- return;
- }
- } catch (Asn1EncodingException e) {
- throw new Asn1EncodingException(" length of bitmask ", e);
- }
- }
-
- static void encodeSmallInt(BitBuffer bitbuffer, int n) throws Asn1EncodingException {
- try {
- if (n <= 63) {
- logger.debug(String.format("normally small length of bitmask, length %d <= 63 indicated as bit <0>", n));
- bitbuffer.put(false);
- encodeConstrainedInt(bitbuffer, n, 0, 63);
- return;
- } else {
- logger.debug(String.format("normally small length of bitmask, length %s > 63 indicated as bit <1>", n));
- bitbuffer.put(true);
- encodeLengthDeterminant(bitbuffer, n);
- return;
- }
- } catch (Asn1EncodingException e) {
- throw new Asn1EncodingException(" length of bitmask ", e);
- }
- }
-
- static void encodeLengthDeterminant(BitBuffer bitbuffer, int n) throws Asn1EncodingException {
- try {
- int position = bitbuffer.position();
- if (n < 128) {
- bitbuffer.put(false);
- encodeConstrainedInt(bitbuffer, n, 0, 127);
- logger.debug(String.format("Length determinant %d, encoded as <%s>", n, bitbuffer.toBooleanStringFromPosition(position)));
- if (bitbuffer.position() - position != 8) {
- throw new AssertionError("length determinant encoded not as 8 bits");
- }
- return;
- } else if (n < NUM_16K) {
- bitbuffer.put(true);
- bitbuffer.put(false);
- encodeConstrainedInt(bitbuffer, n, 0, NUM_16K - 1);
- logger.debug(String.format("Length determinant %d, encoded as 2bits+14bits: <%s>", n,bitbuffer.toBooleanStringFromPosition(position)));
- if (bitbuffer.position() - position != 16) {
- throw new AssertionError("length determinant encoded not as 16 bits");
- }
- return;
- } else {
- throw new UnsupportedOperationException("Length greater than 16K is not supported yet.");
- }
- } catch (Asn1EncodingException e) {
- throw new Asn1EncodingException(" length determinant ", e);
- }
-
- }
-
- static long decodeLengthOfBitmask(BitBuffer bitbuffer) {
- logger.debug("decoding length of bitmask");
- boolean isGreaterThan63 = bitbuffer.get();
- logger.debug(String.format("length determinant extension preamble size flag: preamble size > 63 is %s", isGreaterThan63));
- if (!isGreaterThan63) {
- Long result = decodeConstrainedInt(bitbuffer, newRange(1, 63, false));
- logger.debug(String.format("normally small length of bitmask, length <= 63, decoded as %d", result));
- return result;
- } else {
- logger.debug(String.format("normally small length of bitmask, length > 63, decoding as ordinary length determinant..."));
- return decodeLengthDeterminant(bitbuffer);
- }
- }
-
- static long decodeSmallInt(BitBuffer bitbuffer) {
- logger.debug("decoding small int");
- boolean isGreaterThan63 = bitbuffer.get();
- logger.debug(String.format("length determinant extension preamble size flag: preamble size > 63 is %s", isGreaterThan63));
- if (!isGreaterThan63) {
- Long result = decodeConstrainedInt(bitbuffer, newRange(0, 63, false));
- logger.debug(String.format("normally small length of bitmask, length <= 63, decoded as %d", result));
- return result;
- } else {
- logger.debug(String.format("normally small length of bitmask, length > 63, decoding as ordinary length determinant..."));
- return decodeLengthDeterminant(bitbuffer);
- }
- }
-
- static long decodeLengthDeterminant(BitBuffer bitbuffer) {
- boolean bit8 = bitbuffer.get();
- if (!bit8) { // then value is less than 128
- Long result = decodeConstrainedInt(bitbuffer, newRange(0, 127, false));
- logger.debug(String.format("length determinant, decoded as %d", result));
- return result;
- } else {
- boolean bit7 = bitbuffer.get();
- if (!bit7) { // then value is less than 16K
- Long result = decodeConstrainedInt(bitbuffer, newRange(0, NUM_16K - 1, false));
- logger.debug(String.format("length determinant, decoded as %d", result));
- return result;
- } else { // "Large" n
- logger.debug("lengthes longer than 16K are not supported yet.");
- throw new UnsupportedOperationException("lengthes longer than 16K are not supported yet.");
- }
- }
-
- }
-
- static void encodeConstrainedInt(
- final BitBuffer bitbuffer,
- final long value,
- final long lowerBound,
- final long upperBound) throws Asn1EncodingException {
- encodeConstrainedInt(bitbuffer, value, lowerBound, upperBound, false);
- }
-
- static void encodeConstrainedInt(
- final BitBuffer bitbuffer,
- final long value,
- final long lowerBound,
- final long upperBound,
- final boolean hasExtensionMarker
- ) throws Asn1EncodingException {
- if (upperBound < lowerBound) {
- throw new IllegalArgumentException("Lower bound "
- + lowerBound + " is larger than upper bound " + upperBound);
- }
- if (!hasExtensionMarker && (value < lowerBound || value > upperBound)) {
- throw new Asn1EncodingException(
- " Value " + value + " is outside of fixed range " +
- lowerBound + ".." + upperBound);
- }
- final Long range = upperBound - lowerBound + 1;
- final int position = bitbuffer.position();
- if (hasExtensionMarker) {
- boolean outsideOfRange = value < lowerBound || value > upperBound;
- logger.debug(String.format("constrained int with extension marker, %s extension range",outsideOfRange ? "outside" : "within", outsideOfRange ? "1" : "0"));
- bitbuffer.put(outsideOfRange);
- if (outsideOfRange) {
- throw new UnsupportedOperationException(
- "INT extensions are not supported yet");
- }
- }
- if (range == 1) {
- logger.debug("constrained int of empty range, resulting in empty encoding <>");
- return;
- }
- final BigInteger big = BigInteger.valueOf(value - lowerBound);
- final int numPaddingBits = BigInteger.valueOf(range - 1).bitLength() - big.bitLength();
- for (int i = 0; i < numPaddingBits; i++) {
- bitbuffer.put(false);
- }
- for (int i = big.bitLength() - 1; i >= 0; i--) {
- bitbuffer.put(big.testBit(i));
- }
- logger.debug(String.format("constrained int %d encoded as <%s>", value, bitbuffer.toBooleanStringFromPosition(position)));
- return;
- }
-
- public static byte[] bytesFromCollection(List<Boolean> bitlist) {
- int sizeBytes = (bitlist.size() + 7) / 8;
- byte[] result = new byte[sizeBytes];
- int byteId = 0;
- byte bitId = 7;
- logger.debug(String.format("byte: < %s >", bitlist));
- for (Boolean b : bitlist) {
- //logger.debug(String.format("bitId: %s, byteId: %s, value: %s", bitId, byteId, b));
- result[byteId] |= (b ? 1 : 0) << bitId;
- bitId--;
- if (bitId < 0) {
- bitId = 7;
- byteId++;
- }
- }
- int nZeros = sizeBytes * 8 - bitlist.size();
- String zeros = nZeros > 0 ? String.format("%0" + nZeros + "d", 0) : "";
- logger.debug(String.format("Padding bits (%d): <%s>", nZeros, zeros));
- return result;
- }
-
- final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
-
- public static String hexStringFromBytes(byte[] bytes) {
- char[] hexChars = new char[bytes.length * 2];
- for (int j = 0; j < bytes.length; j++) {
- int v = bytes[j] & 0xFF;
- hexChars[j * 2] = hexArray[v >>> 4];
- hexChars[j * 2 + 1] = hexArray[v & 0x0F];
- }
- return new String(hexChars);
- }
-
- public static byte[] bytesFromHexString(String s) {
- int len = s.length();
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
- + Character.digit(s.charAt(i + 1), 16));
- }
- return data;
- }
-
- public static String binaryStringFromBytes(byte[] bytes) {
- StringBuilder sb = new StringBuilder(bytes.length * Byte.SIZE);
- for (int i = 0; i < Byte.SIZE * bytes.length; i++)
- sb.append((bytes[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
- return sb.toString();
- }
-
- public static byte[] bytesFromBinaryString(String s) {
- int len = s.length();
- byte[] result = new byte[(len + Byte.SIZE - 1) / Byte.SIZE];
- char c;
- for (int i = 0; i < len; i++)
- if ((c = s.charAt(i)) == '1') result[i / Byte.SIZE] = (byte) (result[i / Byte.SIZE] | (0x80 >>> (i % Byte.SIZE)));
- else if (c != '0')
- throw new IllegalArgumentException();
- return result;
- }
-
- private static BitBuffer bitBufferFromBinaryString(String s) {
- ByteBitBuffer result = ByteBitBuffer.allocate(s.length());
- for (int i = 0; i < s.length(); i++) {
- if (s.charAt(i) != '1' && s.charAt(i) != '0') {
- throw new IllegalArgumentException("bad character in 'binary' string " + s.charAt(i));
- }
- result.put(s.charAt(i) == '1');
- }
- result.flip();
- return result;
- }
-
-
-
-
-}