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 static android.location.cts.asn1.base.PerAlignedUtils.SIXTYFOUR_K; 20 21 import com.google.common.base.Preconditions; 22 import com.google.common.collect.ImmutableList; 23 24 import java.math.BigInteger; 25 import java.nio.ByteBuffer; 26 import java.util.Collection; 27 28 import javax.annotation.Nullable; 29 30 /** 31 * Implements ASN.1 functionality. 32 * 33 */ 34 public class Asn1Integer extends Asn1Object { 35 private static final Collection<Asn1Tag> possibleFirstTags = 36 ImmutableList.of(Asn1Tag.INTEGER); 37 38 private BigInteger minimumValue = null; // null == unbounded. 39 private BigInteger maximumValue = null; // null == unbounded. 40 private BigInteger value; 41 getPossibleFirstTags()42 public static Collection<Asn1Tag> getPossibleFirstTags() { 43 return possibleFirstTags; 44 } 45 getDefaultTag()46 @Override Asn1Tag getDefaultTag() { 47 return Asn1Tag.INTEGER; 48 } 49 50 /** 51 * Sets the allowed range of values. A null for either parameter means that 52 * the value is unbounded in that direction. 53 */ setValueRange(@ullable String minimum, @Nullable String maximum)54 protected void setValueRange(@Nullable String minimum, 55 @Nullable String maximum) { 56 minimumValue = minimum == null ? null : new BigInteger(minimum); 57 maximumValue = maximum == null ? null : new BigInteger(maximum); 58 } 59 encodeNormalizedIntegerWithRangeAligned( BigInteger normalizedValue, BigInteger range)60 private Iterable<BitStream> encodeNormalizedIntegerWithRangeAligned( 61 BigInteger normalizedValue, BigInteger range) { 62 if (range.compareTo(BigInteger.valueOf(SIXTYFOUR_K)) < 0) { 63 BitStream result = PerAlignedUtils.encodeNormalizedSmallConstrainedWholeNumber( 64 normalizedValue.intValue(), range.intValue()); 65 return ImmutableList.of(result); 66 } else { 67 return PerAlignedUtils.encodeConstrainedLengthOfBytes( 68 PerAlignedUtils.encodeBigNonNegativeWholeNumber(normalizedValue), 69 1, 70 PerAlignedUtils.encodeBigNonNegativeWholeNumber(range).length); 71 } 72 } 73 encodeNormalizedIntegerWithRangeUnaligned( BigInteger normalizedValue, BigInteger range)74 private Iterable<BitStream> encodeNormalizedIntegerWithRangeUnaligned( 75 BigInteger normalizedValue, BigInteger range) { 76 BitStream result = PerUnalignedUtils.encodeNormalizedConstrainedWholeNumber( 77 normalizedValue.longValue(), range.longValue()); 78 return ImmutableList.of(result); 79 } 80 validateValue()81 private void validateValue() { 82 Preconditions.checkNotNull(value, "No value set."); 83 Preconditions.checkState( 84 minimumValue == null || value.compareTo(minimumValue) >= 0, 85 "Too small value %s", value); 86 Preconditions.checkState( 87 maximumValue == null || value.compareTo(maximumValue) <= 0, 88 "Too large value %s", value); 89 } 90 getBerValueLength()91 @Override int getBerValueLength() { 92 if (value.equals(BigInteger.ZERO)) { 93 // BER requires 0 be encoded with one or more zero octets 94 return 1; 95 } else { 96 return (value.bitLength() >> 3) + 1; 97 } 98 } 99 encodeBerValue(ByteBuffer buf)100 @Override void encodeBerValue(ByteBuffer buf) { 101 if (value.equals(BigInteger.ZERO)) { 102 buf.put((byte) 0); 103 } else { 104 buf.put(value.toByteArray()); 105 } 106 } 107 decodeBerValue(ByteBuffer buf)108 @Override void decodeBerValue(ByteBuffer buf) { 109 value = new BigInteger(getRemaining(buf)); 110 } 111 encodePerImpl(boolean aligned)112 private Iterable<BitStream> encodePerImpl(boolean aligned) { 113 validateValue(); 114 if (maximumValue != null && minimumValue != null) { 115 // Encodes a constrained whole numbers according to X.691-0207, 10.5. 116 BigInteger normalizedValue = value.subtract(minimumValue); 117 BigInteger range = maximumValue.subtract(minimumValue); 118 return aligned 119 ? encodeNormalizedIntegerWithRangeAligned(normalizedValue, range) 120 : encodeNormalizedIntegerWithRangeUnaligned(normalizedValue, range); 121 } else if (minimumValue != null) { 122 // Encodes a semi-constrained whole numbers according to X.691-0207, 10.7. 123 return aligned 124 ? PerAlignedUtils.encodeSemiConstrainedLengthOfBytes( 125 PerAlignedUtils.encodeBigNonNegativeWholeNumber(value.subtract(minimumValue))) 126 : PerUnalignedUtils.encodeSemiConstrainedLengthOfBytes( 127 PerUnalignedUtils.encodeBigNonNegativeWholeNumber(value.subtract(minimumValue))); 128 } else { 129 // Encodes an unconstrained whole number according to X.691-0207, 10.8. 130 return aligned 131 ? PerAlignedUtils.encodeUnconstrainedLengthOfBytes(value.toByteArray()) 132 : PerUnalignedUtils.encodeSemiConstrainedLengthOfBytes(value.toByteArray()); 133 } 134 } 135 encodePerUnaligned()136 @Override public Iterable<BitStream> encodePerUnaligned() { 137 return encodePerImpl(false); 138 } 139 encodePerAligned()140 @Override public Iterable<BitStream> encodePerAligned() { 141 return encodePerImpl(true); 142 } 143 setInteger(BigInteger value)144 public void setInteger(BigInteger value) { 145 this.value = value; 146 } 147 setInteger(BigInteger value, boolean validateValue)148 public void setInteger(BigInteger value, boolean validateValue) { 149 this.value = value; 150 if (validateValue) { 151 validateValue(); 152 } 153 } 154 getInteger()155 public BigInteger getInteger() { 156 return value; 157 } 158 decodeNormalizedIntegerWithRangeAligned( BitStreamReader reader, BigInteger range)159 private BigInteger decodeNormalizedIntegerWithRangeAligned( 160 BitStreamReader reader, BigInteger range) { 161 if (range.compareTo(BigInteger.valueOf(SIXTYFOUR_K)) < 0) { 162 int normalizedIntValue = PerAlignedUtils.decodeNormalizedSmallConstrainedWholeNumber( 163 reader, range.intValue()); 164 return BigInteger.valueOf(normalizedIntValue); 165 } else { 166 return PerAlignedUtils.decodeBigNonNegativeWholeNumber( 167 PerAlignedUtils.decodeConstrainedLengthOfBytes( 168 reader, 1, 169 PerAlignedUtils.encodeBigNonNegativeWholeNumber(range).length)); 170 } 171 } 172 decodeNormalizedIntegerWithRangeUnaligned( BitStreamReader reader, BigInteger range)173 private BigInteger decodeNormalizedIntegerWithRangeUnaligned( 174 BitStreamReader reader, BigInteger range) { 175 long normalizedIntValue = 176 PerUnalignedUtils.decodeNormalizedConstrainedWholeNumber( 177 reader, range.longValue()); 178 return BigInteger.valueOf(normalizedIntValue); 179 } 180 decodePerImpl(BitStreamReader reader, boolean aligned)181 private void decodePerImpl(BitStreamReader reader, boolean aligned) { 182 if (maximumValue != null && minimumValue != null) { 183 // Decodes a constrained whole numbers according to X.691-0207, 10.5. 184 BigInteger range = maximumValue.subtract(minimumValue); 185 BigInteger normalizedValue = aligned 186 ? decodeNormalizedIntegerWithRangeAligned(reader, range) 187 : decodeNormalizedIntegerWithRangeUnaligned(reader, range); 188 value = minimumValue.add(normalizedValue); 189 } else if (minimumValue != null) { 190 // Decodes a semi-constrained whole numbers according to X.691-0207, 10.7. 191 byte[] intBytes = aligned 192 ? PerAlignedUtils.decodeSemiConstrainedLengthOfBytes(reader) 193 : PerUnalignedUtils.decodeSemiConstrainedLengthOfBytes(reader); 194 value = new BigInteger(convertPositiveToSigned(intBytes)).add(minimumValue); 195 } else { 196 // Decodes an unconstrained whole number according to X.691-0207, 10.8. 197 value = new BigInteger(aligned 198 ? PerAlignedUtils.decodeUnconstrainedLengthOfBytes(reader) 199 : PerUnalignedUtils.decodeSemiConstrainedLengthOfBytes(reader)); 200 } 201 } 202 convertPositiveToSigned(byte[] rawData)203 private byte[] convertPositiveToSigned(byte[] rawData) { 204 if ((rawData[0] & 0x80) != 0) { 205 byte[] data = new byte[rawData.length + 1]; 206 System.arraycopy(rawData, 0, data, 1, rawData.length); 207 return data; 208 } else { 209 return rawData; 210 } 211 } 212 decodePerUnaligned(BitStreamReader reader)213 @Override public void decodePerUnaligned(BitStreamReader reader) { 214 decodePerImpl(reader, false); 215 } 216 decodePerAligned(BitStreamReader reader)217 @Override public void decodePerAligned(BitStreamReader reader) { 218 decodePerImpl(reader, true); 219 } 220 } 221