Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.location.cts.asn1.base;
     18 
     19 import com.google.common.base.Preconditions;
     20 import com.google.common.collect.ImmutableList;
     21 
     22 import java.math.BigInteger;
     23 import java.util.Arrays;
     24 
     25 /**
     26  * Basic algorithms for aligned PER encoding and decoding, ASN.1 X.691-0207.
     27  *
     28  */
     29 public class PerAlignedUtils {
     30 
     31   public static final int ONE_K = 1024;
     32   public static final int SIXTEEN_K = 16 * ONE_K;
     33   public static final int SIXTYFOUR_K = 64 * ONE_K;
     34 
     35 
     36   /**
     37    * Encodes whole numbers up to 64K range according to X.691-0207, 10.5.
     38    */
     39   public static BitStream encodeSmallConstrainedWholeNumber(int value,
     40                                                             int minimumValue,
     41                                                             int maximumValue) {
     42     int normalizedValue = value - minimumValue;
     43     // Note: range here means one less than in ASN.1 X.691-0207, 10.5.
     44     int range = maximumValue - minimumValue;
     45     return encodeNormalizedSmallConstrainedWholeNumber(normalizedValue, range);
     46   }
     47 
     48   /**
     49    * Encodes the difference between the actual value and the minimum allowed
     50    * value, the {@code normalizedValue}, for whole numbers up to 64K range
     51    * according to X.691-0207, 10.5.
     52    *
     53    * <p>Note: range here means one less than in ASN.1 X.691-0207, 10.5., i.e.
     54    * here it is the difference between the maximum allowed value and the minimum
     55    * allowed value.
     56    */
     57   public static BitStream encodeNormalizedSmallConstrainedWholeNumber(
     58       int normalizedValue, int range) {
     59     Preconditions.checkArgument(range < SIXTYFOUR_K, "range >= 64K");
     60     Preconditions.checkArgument(normalizedValue >= 0,
     61                                 "negative normalized value");
     62     BitStream result = new BitStream();
     63     if (range == 0) {
     64       return result;
     65     }
     66     if (range < 128) {
     67       result.appendLowBits(leastBitsToEncode((byte) range),
     68                            (byte) normalizedValue);
     69       return result;
     70     }
     71     if (range >= 255) {
     72       result.setBeginByteAligned();
     73     }
     74     if (range < 256) {
     75       result.appendByte((byte) (normalizedValue));
     76       return result;
     77     }
     78     result.appendByte((byte) ((normalizedValue & 0xFF00) >>> 8));
     79     result.appendByte((byte) (normalizedValue & 0x00FF));
     80     return result;
     81   }
     82 
     83   /**
     84    * Decodes whole numbers up to 64K range according to X.691-0207, 10.5.
     85    */
     86   public static int decodeSmallConstrainedWholeNumber(BitStreamReader reader,
     87                                                       int minimumValue,
     88                                                       int maximumValue) {
     89     // Note: range here means one less than in ASN.1 X.691-0207, 10.5.
     90     int range = maximumValue - minimumValue;
     91     int normalizedResult =
     92         decodeNormalizedSmallConstrainedWholeNumber(reader, range);
     93     return normalizedResult + minimumValue;
     94   }
     95 
     96   /**
     97    * Decodes the difference between the actual value and the minimum allowed
     98    * value for whole numbers up to 64K range according to X.691-0207, 10.5.
     99    *
    100    * <p>Note: range here means one less than in ASN.1 X.691-0207, 10.5., i.e.
    101    * here it is the difference between the maximum allowed value and the minimum
    102    * allowed value.
    103    */
    104   public static int decodeNormalizedSmallConstrainedWholeNumber(
    105       BitStreamReader reader, int range) {
    106     if (range < 0) {
    107       throw new IllegalArgumentException("range < 0");
    108     }
    109     if (range >= SIXTYFOUR_K) {
    110       throw new IllegalArgumentException("range >= 64K");
    111     }
    112     if (range == 0) {
    113       return 0;
    114     }
    115     if (range < 128) {
    116       return reader.readLowBits(leastBitsToEncode((byte) range));
    117     }
    118     if (range >= 255) {
    119       reader.spoolToByteBoundary();
    120     }
    121     if (range < 256) {
    122       return (reader.readByte() & 0xFF);
    123     }
    124     return ((reader.readByte() & 0xFF) << 8)
    125         + (reader.readByte() & 0xFF);
    126   }
    127 
    128   private static int leastBitsToEncode(byte value) {
    129     int unsignedByte = value & 0xFF;
    130     for (int bits = 1; bits < 8; bits++) {
    131       if (unsignedByte < (1 << bits)) {
    132         return bits;
    133       }
    134     }
    135     return 8;
    136   }
    137 
    138   public static Iterable<BitStream> encodeNormallySmallWholeNumber(int value) {
    139     if (value < 64) {
    140       BitStream result = new BitStream();
    141       result.appendBit(false);
    142       result.appendLowBits(6, (byte) value);
    143       return ImmutableList.of(result);
    144     }
    145     throw new UnsupportedOperationException("normally small numbers >= 64 "
    146                                             + "unimplemented");
    147   }
    148 
    149   public static int decodeNormallySmallWholeNumber(BitStreamReader reader) {
    150     if (reader.readBit()) {
    151       throw new UnsupportedOperationException("normally small numbers >= 64 "
    152                                               + "unimplemented");
    153     }
    154     return reader.readLowBits(6) & 0xFF;
    155   }
    156 
    157   /**
    158    * Encodes length determinant for a constrained length byte[] according to
    159    * X.691-0207, 10.9.3.3 and up.
    160    */
    161   public static Iterable<BitStream> encodeConstrainedLengthOfBytes(
    162       byte[] bytes, int minimumLength, int maximumLength) {
    163     if (maximumLength >= SIXTYFOUR_K) {
    164       return encodeSemiConstrainedLengthOfBytes(bytes);
    165     }
    166 
    167     BitStream lengthDeterminant = encodeSmallConstrainedWholeNumber(
    168         bytes.length, minimumLength, maximumLength);
    169     if (bytes.length == 0) {
    170       return ImmutableList.of(lengthDeterminant);
    171     }
    172     BitStream value = new BitStream();
    173     value.setBeginByteAligned();
    174     for (byte aByte : bytes) {
    175       value.appendByte(aByte);
    176     }
    177     return ImmutableList.of(lengthDeterminant, value);
    178 
    179   }
    180 
    181   /**
    182    * Decodes a constrained length byte[] with length determinant according to
    183    * X.691-0207, 10.9.3.3 and up.
    184    */
    185   public static byte[] decodeConstrainedLengthOfBytes(
    186       BitStreamReader reader, int minimumLength, int maximumLength) {
    187     if (maximumLength >= SIXTYFOUR_K) {
    188       return decodeSemiConstrainedLengthOfBytes(reader);
    189     }
    190     int length = decodeSmallConstrainedWholeNumber(
    191         reader, minimumLength, maximumLength);
    192     if (length == 0) {
    193       return new byte[0];
    194     }
    195     byte[] result = new byte[length];
    196     reader.spoolToByteBoundary();
    197     for (int i = 0; i < length; i++) {
    198       result[i] = reader.readByte();
    199     }
    200     return result;
    201   }
    202 
    203   /**
    204    * Encodes length determinant for a semi-constrained length byte[] according
    205    * to X.691-0207, 10.9.3.5.
    206    */
    207   public static Iterable<BitStream> encodeSemiConstrainedLengthOfBytes(
    208       byte[] bytes) {
    209     int n = bytes.length;
    210     if (n < SIXTEEN_K) {
    211       BitStream result = encodeSemiConstrainedLength(n);
    212       result.setBeginByteAligned();
    213       for (byte b : bytes) {
    214         result.appendByte(b);
    215       }
    216       return ImmutableList.of(result);
    217     }
    218     throw new UnsupportedOperationException("Arrays > 16K unimplemented.");
    219   }
    220   /**
    221    * Encodes length determinant for a semi-constrained length byte[] according
    222    * to X.691-0207, 10.9.3.5.
    223    */
    224   public static Iterable<BitStream> encodeUnconstrainedLengthOfBytes(
    225       byte[] bytes) {
    226     // Length for unconsrtained and semiconstrained integers is encoded by the
    227     // same rules.
    228     return encodeSemiConstrainedLengthOfBytes(bytes);
    229   }
    230   /**
    231    * Decodes length determinant for a semi-constrained length byte[] according
    232    * to X.691-0207, 10.9.3.5.
    233    */
    234   public static byte[] decodeSemiConstrainedLengthOfBytes(
    235       BitStreamReader reader) {
    236     reader.spoolToByteBoundary();
    237     int length = decodeSemiConstrainedLength(reader);
    238     byte[] result = new byte[length];
    239     for (int i = 0; i < length; i++) {
    240       result[i] = reader.readByte();
    241     }
    242     return result;
    243   }
    244   /**
    245    * Decodes length determinant for a semi-constrained length byte[] according
    246    * to X.691-0207, 10.9.3.5.
    247    */
    248   public static byte[] decodeUnconstrainedLengthOfBytes(
    249       BitStreamReader reader) {
    250     // Length for unconsrtained and semiconstrained integers is encoded by the
    251     // same rules.
    252     return decodeSemiConstrainedLengthOfBytes(reader);
    253   }
    254   /**
    255    * Encodes non-negative numbers according to X.691-0207, 10.3.
    256    */
    257   public static byte[] encodeBigNonNegativeWholeNumber(BigInteger bigInteger) {
    258     byte[] twosComplement = bigInteger.toByteArray();
    259     return twosComplement[0] == 0
    260            ? Arrays.copyOfRange(twosComplement, 1, twosComplement.length)
    261            : twosComplement;
    262   }
    263 
    264   /**
    265     * Decodes non-negative numbers according to X.691-0207, 10.3.
    266     */
    267    public static BigInteger decodeBigNonNegativeWholeNumber(byte[] encoded) {
    268     return new BigInteger(1, encoded);
    269   }
    270 
    271   /**
    272    * Encodes length determinant according to X.691-0207, 10.9.3.6.
    273    */
    274   public static BitStream encodeSemiConstrainedLength(int value) {
    275     if (value <= 127) {
    276       BitStream result = new BitStream();
    277       result.setBeginByteAligned();
    278       result.appendBit(false);
    279       result.appendLowBits(7, (byte) value);
    280       return result;
    281     } else if (value < SIXTEEN_K) {
    282       BitStream result = new BitStream();
    283       result.setBeginByteAligned();
    284       result.appendBit(true);
    285       result.appendBit(false);
    286       result.appendLowBits(6, (byte) (value >>> 8));
    287       result.appendByte((byte) (value & 0xFF));
    288       return result;
    289     }
    290     throw new UnsupportedOperationException("Length values > " +
    291                                              SIXTEEN_K + "unimplemented");
    292   }
    293 
    294   /**
    295    * Decodes length determinant according to X.691-0207, 10.9.3.6.
    296    */
    297   public static int decodeSemiConstrainedLength(BitStreamReader reader) {
    298     reader.spoolToByteBoundary();
    299     if (!reader.readBit()) {
    300       return reader.readLowBits(7);
    301     } else if (!reader.readBit()) {
    302       return (reader.readLowBits(6) << 8) + (reader.readByte() & 0xFF);
    303     } else {
    304       throw new UnsupportedOperationException("Length values > " +
    305                                                SIXTEEN_K + "unimplemented");
    306     }
    307   }
    308 
    309   /*
    310    * Encodes an Asn1Object into a  Open type field (X.691-0207, 10.2), used
    311    * mostly for encoding Sequence and SetOf extension additions. A decode method
    312    * hasn't been added as the extension additions should decoded
    313    * by their relevent Asn1Object decoders.
    314    */
    315   public static Iterable<BitStream> encodeOpenTypeField(
    316                                                     Asn1Object object){
    317     PacketBuilder packetBuilder = new PacketBuilder();
    318     packetBuilder.appendAll(object.encodePerAligned());
    319     return encodeSemiConstrainedLengthOfBytes(packetBuilder.getPaddedBytes());
    320   }
    321 
    322   public static Asn1Object decodeOpenTypeField(
    323                               BitStreamReader reader, Asn1Object asn1Object) {
    324     byte [] encodedBytes = decodeSemiConstrainedLengthOfBytes(reader);
    325     asn1Object.decodePerAligned(new BitStreamReader(encodedBytes));
    326     return asn1Object;
    327   }
    328 }
    329