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 import com.google.common.io.BaseEncoding; 24 25 import java.nio.ByteBuffer; 26 import java.util.Collection; 27 import java.util.Objects; 28 29 /** 30 * Implements ASN.1 functionality. 31 * 32 */ 33 public class Asn1OctetString extends Asn1Object { 34 private static final BaseEncoding HEX = BaseEncoding.base16(); 35 private static final Collection<Asn1Tag> possibleFirstTags = 36 ImmutableList.of(Asn1Tag.OCTET_STRING); 37 38 private int minimumSize = 0; 39 private Integer maximumSize = null; // null == unbounded. 40 private byte[] value; 41 getPossibleFirstTags()42 public static Collection<Asn1Tag> getPossibleFirstTags() { 43 return possibleFirstTags; 44 } 45 setMinSize(int min)46 protected void setMinSize(int min) { 47 minimumSize = min; 48 } 49 setMaxSize(int max)50 protected void setMaxSize(int max) { 51 maximumSize = max; 52 } 53 getValue()54 public byte[] getValue() { 55 return value; 56 } 57 setValue(byte[] value)58 public void setValue(byte[] value) { 59 this.value = value; 60 } 61 getDefaultTag()62 @Override Asn1Tag getDefaultTag() { 63 return Asn1Tag.OCTET_STRING; 64 } 65 getBerValueLength()66 @Override int getBerValueLength() { 67 Objects.requireNonNull(value, "No value set."); 68 return value.length; 69 } 70 encodeBerValue(ByteBuffer buf)71 @Override void encodeBerValue(ByteBuffer buf) { 72 Objects.requireNonNull(value, "No value set."); 73 buf.put(value); 74 } 75 decodeBerValue(ByteBuffer buf)76 @Override void decodeBerValue(ByteBuffer buf) { 77 value = getRemaining(buf); 78 } 79 encodePerImpl(boolean aligned)80 private Iterable<BitStream> encodePerImpl(boolean aligned) { 81 Objects.requireNonNull(value, "No value set."); 82 Preconditions.checkState( 83 maximumSize == null || value.length <= maximumSize, "Too large %s", 84 value.length); 85 if (maximumSize == null) { 86 if (aligned) { 87 return PerAlignedUtils.encodeSemiConstrainedLengthOfBytes(value); 88 } else { 89 return PerUnalignedUtils.encodeSemiConstrainedLengthOfBytes(value); 90 } 91 } else if (minimumSize == maximumSize) { 92 if (maximumSize == 0) { 93 return ImmutableList.of(); 94 } 95 if (maximumSize < SIXTYFOUR_K) { 96 BitStream result = new BitStream(); 97 for (int i = 0; i < maximumSize; i++) { 98 result.appendByte(value[i]); 99 } 100 if (aligned && maximumSize > 2) { 101 result.setBeginByteAligned(); 102 } 103 return ImmutableList.of(result); 104 } 105 } 106 if (aligned) { 107 return PerAlignedUtils.encodeConstrainedLengthOfBytes( 108 value, minimumSize, maximumSize); 109 } else { 110 return PerUnalignedUtils.encodeConstrainedLengthOfBytes( 111 value, minimumSize, maximumSize); 112 } 113 } 114 encodePerUnaligned()115 @Override public Iterable<BitStream> encodePerUnaligned() { 116 return encodePerImpl(false); 117 } 118 encodePerAligned()119 @Override public Iterable<BitStream> encodePerAligned() { 120 return encodePerImpl(true); 121 } 122 decodePerImpl(BitStreamReader reader, boolean aligned)123 private void decodePerImpl(BitStreamReader reader, boolean aligned) { 124 if (maximumSize == null) { 125 if (aligned) { 126 value = PerAlignedUtils.decodeSemiConstrainedLengthOfBytes(reader); 127 } else { 128 value = PerUnalignedUtils.decodeSemiConstrainedLengthOfBytes(reader); 129 } 130 return; 131 } else if (minimumSize == maximumSize) { 132 value = new byte[maximumSize]; 133 if (maximumSize == 0) { 134 return; 135 } 136 if (maximumSize < SIXTYFOUR_K) { 137 if (aligned && maximumSize > 2) { 138 reader.spoolToByteBoundary(); 139 } 140 for (int i = 0; i < maximumSize; i++) { 141 value[i] = reader.readByte(); 142 } 143 return; 144 } 145 } 146 if (aligned) { 147 value = PerAlignedUtils.decodeConstrainedLengthOfBytes( 148 reader, minimumSize, maximumSize); 149 } else { 150 value = PerUnalignedUtils.decodeConstrainedLengthOfBytes( 151 reader, minimumSize, maximumSize); 152 } 153 } 154 decodePerUnaligned(BitStreamReader reader)155 @Override public void decodePerUnaligned(BitStreamReader reader) { 156 decodePerImpl(reader, false); 157 } 158 decodePerAligned(BitStreamReader reader)159 @Override public void decodePerAligned(BitStreamReader reader) { 160 decodePerImpl(reader, true); 161 } 162 toString()163 @Override public String toString() { 164 return toIndentedString(""); 165 } 166 toIndentedString(String indent)167 public String toIndentedString(String indent) { 168 return getTypeName() + " = [ " + (value == null ? "<null>" : HEX.encode(value)) + " ];\n"; 169 } 170 getTypeName()171 protected String getTypeName() { 172 return ""; 173 } 174 } 175