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 
20 import static android.location.cts.asn1.base.PerAlignedUtils.SIXTEEN_K;
21 import static android.location.cts.asn1.base.PerAlignedUtils.SIXTYFOUR_K;
22 import com.google.common.collect.ImmutableList;
23 
24 import java.math.BigInteger;
25 import java.util.Arrays;
26 
27 /**
28  * Basic algorithms for Unaligned PER encoding and decoding, ASN.1 X.691-0207.
29  *
30  */
31 public class PerUnalignedUtils {
32   /**
33    * Encodes whole numbers up to 64K range according to X.691-0207, 10.5.
34    */
encodeConstrainedWholeNumber( int value, int minimumValue, int maximumValue)35   public static BitStream encodeConstrainedWholeNumber(
36       int value, int minimumValue, int maximumValue) {
37     int normalizedValue = value - minimumValue;
38     // Note: range here means one less than in ASN.1 X.691-0207, 10.5.
39     int range = maximumValue - minimumValue;
40     return encodeNormalizedConstrainedWholeNumber(normalizedValue, range);
41   }
42 
43   /**
44    * Encodes the difference between the actual value and the minimum allowed
45    * value, the {@code normalizedValue}, for whole numbers up to 64K range
46    * according to X.691-0207, 10.5.
47    *
48    * <p>Note: range here means one less than in ASN.1 X.691-0207, 10.5., i.e.
49    * here it is the difference between the maximum allowed value and the minimum
50    * allowed value.
51    */
encodeNormalizedConstrainedWholeNumber( long normalizedValue, long range)52   public static BitStream encodeNormalizedConstrainedWholeNumber(
53       long normalizedValue, long range) {
54     BitStream result = new BitStream();
55     int bits = leastBitsToEncodeLong(range);
56     for (int i = bits - 1; i >= 0; --i) {
57       result.appendBit((normalizedValue >> i & 1) != 0);
58     }
59     return result;
60   }
61 
decodeConstrainedWholeNumber( BitStreamReader reader, int minimumValue, int maximumValue)62   public static int decodeConstrainedWholeNumber(
63       BitStreamReader reader, int minimumValue, int maximumValue) {
64     // Note: range here means one less than in ASN.1 X.691-0207, 10.5.
65     long range = (long) maximumValue - (long) minimumValue;
66     long normalizedResult =
67         decodeNormalizedConstrainedWholeNumber(reader, range);
68     return (int) normalizedResult + minimumValue;
69   }
70 
71   /**
72    * Decodes the difference between the actual value and the minimum allowed
73    * value for whole numbers up to 64K range according to X.691-0207, 10.5.
74    *
75    * <p>Note: range here means one less than in ASN.1 X.691-0207, 10.5., i.e.
76    * here it is the difference between the maximum allowed value and the minimum
77    * allowed value.
78    */
decodeNormalizedConstrainedWholeNumber( BitStreamReader reader, long range)79   public static long decodeNormalizedConstrainedWholeNumber(
80       BitStreamReader reader, long range) {
81     long result = 0;
82     int bits = leastBitsToEncodeLong(range);
83     for (int i = 0; i < bits; ++i) {
84       result <<= 1;
85       result |= reader.readBit() ? 1 : 0;
86     }
87     return result;
88   }
89 
leastBitsToEncodeLong(long value)90   private static int leastBitsToEncodeLong(long value) {
91     for (int bits = 1; bits < 64; bits++) {
92       if (value < (1L << bits)) {
93         return bits;
94       }
95     }
96     return 64;
97   }
98 
encodeNormallySmallWholeNumber(int value)99   public static Iterable<BitStream> encodeNormallySmallWholeNumber(int value) {
100     if (value < 64) {
101       BitStream result = new BitStream();
102       result.appendBit(false);
103       result.appendLowBits(6, (byte) value);
104       return ImmutableList.of(result);
105     }
106     throw new UnsupportedOperationException("normally small numbers >= 64 "
107                                             + "unimplemented");
108   }
109 
decodeNormallySmallWholeNumber(BitStreamReader reader)110   public static int decodeNormallySmallWholeNumber(BitStreamReader reader) {
111     if (reader.readBit()) {
112       throw new UnsupportedOperationException("normally small numbers >= 64 "
113                                               + "unimplemented");
114     }
115     return reader.readLowBits(6) & 0xFF;
116   }
117 
118   /**
119    * Encodes length determinant for a constrained length byte[] according to
120    * X.691-0207, 10.9.3.3 and up.
121    */
encodeConstrainedLengthOfBytes( byte[] bytes, int minimumLength, int maximumLength)122   public static Iterable<BitStream> encodeConstrainedLengthOfBytes(
123       byte[] bytes, int minimumLength, int maximumLength) {
124     if (maximumLength >= SIXTYFOUR_K) {
125       return encodeSemiConstrainedLengthOfBytes(bytes);
126     }
127 
128     BitStream lengthDeterminant = encodeConstrainedWholeNumber(
129         bytes.length, minimumLength, maximumLength);
130     if (bytes.length == 0) {
131       return ImmutableList.of(lengthDeterminant);
132     }
133     BitStream value = new BitStream();
134     for (byte aByte : bytes) {
135       value.appendByte(aByte);
136     }
137     return ImmutableList.of(lengthDeterminant, value);
138   }
139 
140   /**
141    * Decodes a constrained length byte[] with length determinant according to
142    * X.691-0207, 10.9.3.3 and up.
143    */
decodeConstrainedLengthOfBytes( BitStreamReader reader, int minimumLength, int maximumLength)144   public static byte[] decodeConstrainedLengthOfBytes(
145       BitStreamReader reader, int minimumLength, int maximumLength) {
146     if (maximumLength >= SIXTYFOUR_K) {
147       return decodeSemiConstrainedLengthOfBytes(reader);
148     }
149     int length = decodeConstrainedWholeNumber(
150         reader, minimumLength, maximumLength);
151     if (length == 0) {
152       return new byte[0];
153     }
154     byte[] result = new byte[length];
155     for (int i = 0; i < length; i++) {
156       result[i] = reader.readByte();
157     }
158     return result;
159   }
160 
161   /**
162    * Encodes length determinant for a semi-constrained length byte[] according
163    * to X.691-0207, 10.9.3.5.
164    */
encodeSemiConstrainedLengthOfBytes( byte[] bytes)165   public static Iterable<BitStream> encodeSemiConstrainedLengthOfBytes(
166       byte[] bytes) {
167     int n = bytes.length;
168     if (n < SIXTEEN_K) {
169       BitStream result = encodeSemiConstrainedLength(n);
170       for (byte b : bytes) {
171         result.appendByte(b);
172       }
173       return ImmutableList.of(result);
174     }
175     throw new UnsupportedOperationException("Arrays > 16K unimplemented.");
176   }
177 
178   /**
179    * Decodes length determinant for a semi-constrained length byte[] according
180    * to X.691-0207, 10.9.3.5.
181    */
decodeSemiConstrainedLengthOfBytes( BitStreamReader reader)182   public static byte[] decodeSemiConstrainedLengthOfBytes(
183       BitStreamReader reader) {
184     int length = decodeSemiConstrainedLength(reader);
185     byte[] result = new byte[length];
186     for (int i = 0; i < length; i++) {
187       result[i] = reader.readByte();
188     }
189     return result;
190   }
191 
192   /**
193    * Encodes non-negative numbers according to X.691-0207, 10.3.
194    */
encodeBigNonNegativeWholeNumber(BigInteger bigInteger)195   public static byte[] encodeBigNonNegativeWholeNumber(BigInteger bigInteger) {
196     byte[] twosComplement = bigInteger.toByteArray();
197     return twosComplement[0] == 0
198            ? Arrays.copyOfRange(twosComplement, 1, twosComplement.length)
199            : twosComplement;
200   }
201 
202   /**
203     * Decodes non-negative numbers according to X.691-0207, 10.3.
204     */
decodeBigNonNegativeWholeNumber(byte[] encoded)205    public static BigInteger decodeBigNonNegativeWholeNumber(byte[] encoded) {
206     return new BigInteger(1, encoded);
207   }
208 
209   /**
210    * Encodes length determinant according to X.691-0207, 10.9.3.6.
211    */
encodeSemiConstrainedLength(int value)212   public static BitStream encodeSemiConstrainedLength(int value) {
213     if (value <= 127) {
214       BitStream result = new BitStream();
215       result.appendBit(false);
216       result.appendLowBits(7, (byte) value);
217       return result;
218     } else if (value < SIXTEEN_K) {
219       BitStream result = new BitStream();
220       result.appendBit(true);
221       result.appendBit(false);
222       result.appendLowBits(6, (byte) (value >>> 8));
223       result.appendByte((byte) (value & 0xFF));
224       return result;
225     }
226     throw new UnsupportedOperationException("Length values > " +
227                                              SIXTEEN_K + "unimplemented");
228   }
229 
230   /**
231    * Decodes length determinant according to X.691-0207, 10.9.3.6.
232    */
decodeSemiConstrainedLength(BitStreamReader reader)233   public static int decodeSemiConstrainedLength(BitStreamReader reader) {
234     if (!reader.readBit()) {
235       return reader.readLowBits(7);
236     } else if (!reader.readBit()) {
237       return (reader.readLowBits(6) << 8) + (reader.readByte() & 0xFF);
238     } else {
239       throw new UnsupportedOperationException("Length values > " +
240                                                SIXTEEN_K + "unimplemented");
241     }
242   }
243 
244   /*
245    * Encodes an Asn1Object into a  Open type field (X.691-0207, 10.2), used
246    * mostly for encoding Sequence and SetOf extension additions. A decode method
247    * hasn't been added as the extension additions should decoded
248    * by their relevent Asn1Object decoders.
249    */
encodeOpenTypeField(Asn1Object object)250   public static Iterable<BitStream> encodeOpenTypeField(Asn1Object object){
251     PacketBuilder packetBuilder = new PacketBuilder();
252     packetBuilder.appendAll(object.encodePerUnaligned());
253     return encodeSemiConstrainedLengthOfBytes(packetBuilder.getPaddedBytes());
254   }
255 
decodeOpenTypeField( BitStreamReader reader, Asn1Object asn1Object)256   public static Asn1Object decodeOpenTypeField(
257                               BitStreamReader reader, Asn1Object asn1Object) {
258     byte [] encodedBytes = decodeSemiConstrainedLengthOfBytes(reader);
259     asn1Object.decodePerUnaligned(new BitStreamReader(encodedBytes));
260     return asn1Object;
261   }
262 }
263