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 com.google.common.base.Preconditions;
     20 import com.google.common.collect.ImmutableList;
     21 
     22 import java.nio.ByteBuffer;
     23 import java.util.Collection;
     24 import java.util.LinkedList;
     25 
     26 /**
     27  * Implements ASN.1 functionality.
     28  *
     29  */
     30 public abstract class Asn1SequenceOf<T extends Asn1Object> extends Asn1Object {
     31   private static final Collection<Asn1Tag> possibleFirstTags =
     32       ImmutableList.of(Asn1Tag.SEQUENCE);
     33 
     34   protected LinkedList<T> sequence = new LinkedList<T>();
     35   private int minimumSize = 0;
     36   private Integer maximumSize = null; // Null is unbounded.
     37 
     38   public static Collection<Asn1Tag> getPossibleFirstTags() {
     39     return possibleFirstTags;
     40   }
     41 
     42   protected void setMinSize(int min) {
     43     minimumSize = min;
     44   }
     45 
     46   protected void setMaxSize(int max) {
     47     maximumSize = max;
     48   }
     49 
     50   public void add(T component) {
     51     sequence.addLast(component);
     52   }
     53 
     54   public Iterable<T> getValues() {
     55     return sequence;
     56   }
     57 
     58   public abstract T createAndAddValue();
     59 
     60   @Override Asn1Tag getDefaultTag() {
     61     return Asn1Tag.SEQUENCE;
     62   }
     63 
     64   @Override boolean isConstructed() {
     65     return true;
     66   }
     67 
     68   @Override int getBerValueLength() {
     69     int length = 0;
     70     for (Asn1Object component : sequence) {
     71       length += component.getBerLength();
     72     }
     73     return length;
     74   }
     75 
     76   @Override void encodeBerValue(ByteBuffer buf) {
     77     for (Asn1Object component : sequence) {
     78       component.encodeBer(buf);
     79     }
     80   }
     81 
     82   @Override void decodeBerValue(ByteBuffer buf) {
     83     while (buf.hasRemaining()) {
     84       Asn1Tag tag = Asn1Tag.readTag(buf);
     85       int valueLength = Asn1Tag.readLength(buf);
     86       T value = createAndAddValue();
     87       if (value.getTag() != null) {
     88         checkTag(tag, value.getTag());
     89         if (!value.isTagImplicit()) {
     90           // read inner tag + length
     91           checkTag(value.getDefaultTag(), Asn1Tag.readTag(buf));
     92           valueLength = Asn1Tag.readLength(buf);
     93         }
     94       } else {
     95         checkTag(tag, value.getDefaultTag());
     96       }
     97       ByteBuffer subBuf = ByteBuffer.wrap(buf.array(), buf.position(), valueLength);
     98       value.decodeBerValue(subBuf);
     99       if (subBuf.hasRemaining()) {
    100         throw new IllegalArgumentException("child failed to consume all input");
    101       }
    102       buf.position(buf.position() + valueLength);
    103     }
    104   }
    105 
    106   private Iterable<BitStream> encodePerImpl(boolean aligned) {
    107     Preconditions.checkState(sequence.size() >= minimumSize,
    108                              "Too few components.");
    109     Preconditions.checkState(maximumSize == null
    110                              || sequence.size() <= maximumSize,
    111                              "Too many components.");
    112     ImmutableList.Builder<BitStream> listBuilder = ImmutableList.builder();
    113     if (maximumSize == null || maximumSize >= PerAlignedUtils.SIXTYFOUR_K) {
    114       if (aligned) {
    115         listBuilder.add(PerAlignedUtils.encodeSemiConstrainedLength(sequence.size()));
    116       } else {
    117         listBuilder.add(PerUnalignedUtils.encodeSemiConstrainedLength(sequence.size()));
    118       }
    119     } else if (maximumSize != minimumSize) {
    120       if (aligned) {
    121         listBuilder.add(
    122             PerAlignedUtils.encodeSmallConstrainedWholeNumber(
    123                 sequence.size(), minimumSize, maximumSize));
    124       } else {
    125         listBuilder.add(
    126             PerUnalignedUtils.encodeConstrainedWholeNumber(
    127                 sequence.size(), minimumSize, maximumSize));
    128       }
    129     }
    130     for (Asn1Object component : sequence) {
    131       if (aligned) {
    132         listBuilder.addAll(component.encodePerAligned());
    133       } else {
    134         listBuilder.addAll(component.encodePerUnaligned());
    135       }
    136     }
    137     return listBuilder.build();
    138   }
    139 
    140   @Override public Iterable<BitStream> encodePerUnaligned() {
    141     return encodePerImpl(false);
    142   }
    143 
    144   @Override public Iterable<BitStream> encodePerAligned() {
    145     return encodePerImpl(true);
    146   }
    147 
    148   private void decodePerImpl(BitStreamReader reader, boolean aligned) {
    149     int size = minimumSize;
    150     if (maximumSize == null || maximumSize >= PerAlignedUtils.SIXTYFOUR_K) {
    151       if (aligned) {
    152         size = PerAlignedUtils.decodeSemiConstrainedLength(reader);
    153       } else {
    154         size = PerUnalignedUtils.decodeSemiConstrainedLength(reader);
    155       }
    156     } else if (maximumSize != minimumSize) {
    157       if (aligned) {
    158         size = PerAlignedUtils.decodeSmallConstrainedWholeNumber(
    159             reader, minimumSize, maximumSize);
    160       } else {
    161         size = PerUnalignedUtils.decodeConstrainedWholeNumber(
    162             reader, minimumSize, maximumSize);
    163       }
    164     }
    165     for (int i = 0; i < size; i++) {
    166       T value = createAndAddValue();
    167       if (aligned) {
    168         value.decodePerAligned(reader);
    169       } else {
    170         value.decodePerUnaligned(reader);
    171       }
    172     }
    173   }
    174 
    175   @Override public void decodePerUnaligned(BitStreamReader reader) {
    176     decodePerImpl(reader, false);
    177   }
    178 
    179   @Override public void decodePerAligned(BitStreamReader reader) {
    180     decodePerImpl(reader, true);
    181   }
    182 }
    183