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