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