diff options
author | CGantert345 <57003061+CGantert345@users.noreply.github.com> | 2021-02-25 11:02:26 +0100 |
---|---|---|
committer | CGantert345 <57003061+CGantert345@users.noreply.github.com> | 2021-02-25 11:02:26 +0100 |
commit | 425bd35c736b7e1c0dbe5b3f9162e195b3be6018 (patch) | |
tree | bc4668aa125fb0a15518d464a1738c6b05e56d07 /src/net/gcdc/asn1/uper/UperEncoder.java | |
parent | issuerOnLine changed from int to Integer as it is optional (diff) | |
download | UIC-barcode-1.2.tar UIC-barcode-1.2.tar.gz UIC-barcode-1.2.tar.bz2 UIC-barcode-1.2.tar.lz UIC-barcode-1.2.tar.xz UIC-barcode-1.2.tar.zst UIC-barcode-1.2.zip |
Diffstat (limited to 'src/net/gcdc/asn1/uper/UperEncoder.java')
-rw-r--r-- | src/net/gcdc/asn1/uper/UperEncoder.java | 721 |
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; - } - - - - -} |