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 getPossibleFirstTags()38 public static Collection<Asn1Tag> getPossibleFirstTags() { 39 return possibleFirstTags; 40 } 41 setMinSize(int min)42 protected void setMinSize(int min) { 43 minimumSize = min; 44 } 45 setMaxSize(int max)46 protected void setMaxSize(int max) { 47 maximumSize = max; 48 } 49 add(T component)50 public void add(T component) { 51 sequence.addLast(component); 52 } 53 getValues()54 public Iterable<T> getValues() { 55 return sequence; 56 } 57 createAndAddValue()58 public abstract T createAndAddValue(); 59 getDefaultTag()60 @Override Asn1Tag getDefaultTag() { 61 return Asn1Tag.SEQUENCE; 62 } 63 isConstructed()64 @Override boolean isConstructed() { 65 return true; 66 } 67 getBerValueLength()68 @Override int getBerValueLength() { 69 int length = 0; 70 for (Asn1Object component : sequence) { 71 length += component.getBerLength(); 72 } 73 return length; 74 } 75 encodeBerValue(ByteBuffer buf)76 @Override void encodeBerValue(ByteBuffer buf) { 77 for (Asn1Object component : sequence) { 78 component.encodeBer(buf); 79 } 80 } 81 decodeBerValue(ByteBuffer buf)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 encodePerImpl(boolean aligned)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 encodePerUnaligned()140 @Override public Iterable<BitStream> encodePerUnaligned() { 141 return encodePerImpl(false); 142 } 143 encodePerAligned()144 @Override public Iterable<BitStream> encodePerAligned() { 145 return encodePerImpl(true); 146 } 147 decodePerImpl(BitStreamReader reader, boolean aligned)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 decodePerUnaligned(BitStreamReader reader)175 @Override public void decodePerUnaligned(BitStreamReader reader) { 176 decodePerImpl(reader, false); 177 } 178 decodePerAligned(BitStreamReader reader)179 @Override public void decodePerAligned(BitStreamReader reader) { 180 decodePerImpl(reader, true); 181 } 182 } 183