Home | History | Annotate | Download | only in base
      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 
     42   public static Collection<Asn1Tag> getPossibleFirstTags() {
     43     return possibleFirstTags;
     44   }
     45 
     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    */
     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 
     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 
     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 
     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 
     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 
    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 
    108   @Override void decodeBerValue(ByteBuffer buf) {
    109     value = new BigInteger(getRemaining(buf));
    110   }
    111 
    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 
    136   @Override public Iterable<BitStream> encodePerUnaligned() {
    137     return encodePerImpl(false);
    138   }
    139 
    140   @Override public Iterable<BitStream> encodePerAligned() {
    141     return encodePerImpl(true);
    142   }
    143 
    144   public void setInteger(BigInteger value) {
    145     this.value = value;
    146   }
    147 
    148   public void setInteger(BigInteger value, boolean validateValue) {
    149     this.value = value;
    150     if (validateValue) {
    151       validateValue();
    152     }
    153   }
    154 
    155   public BigInteger getInteger() {
    156     return value;
    157   }
    158 
    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 
    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 
    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 
    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 
    213   @Override public void decodePerUnaligned(BitStreamReader reader) {
    214     decodePerImpl(reader, false);
    215   }
    216 
    217   @Override public void decodePerAligned(BitStreamReader reader) {
    218     decodePerImpl(reader, true);
    219   }
    220 }
    221