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