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.nio.ByteBuffer; 25 import java.util.BitSet; 26 import java.util.Collection; 27 28 /** 29 * Implements ASN.1 functionality. 30 * as an asn1 BIT STRING does. 31 * 32 * <P>This class is not thread-safe without external synchronization. 33 * 34 */ 35 public class Asn1BitString extends Asn1Object { 36 private static final Collection<Asn1Tag> possibleFirstTags = 37 ImmutableList.of(Asn1Tag.BIT_STRING); 38 39 private int minimumSize = 0; 40 private Integer maximumSize = null; // null == unbounded. 41 private BitSet value; 42 getPossibleFirstTags()43 public static Collection<Asn1Tag> getPossibleFirstTags() { 44 return possibleFirstTags; 45 } 46 setMinSize(int min)47 protected void setMinSize(int min) { 48 minimumSize = min; 49 } 50 setMaxSize(int max)51 protected void setMaxSize(int max) { 52 maximumSize = max; 53 } 54 getValue()55 public BitSet getValue() { 56 return value; 57 } 58 setValue(BitSet value)59 public void setValue(BitSet value) { 60 this.value = value; 61 } 62 getDefaultTag()63 @Override Asn1Tag getDefaultTag() { 64 return Asn1Tag.BIT_STRING; 65 } 66 getBerValueLength()67 @Override int getBerValueLength() { 68 Preconditions.checkNotNull(value, "No value set."); 69 // the +1 is for the extra leading octet indicating the number of unused bits in last octet 70 return (value.length() + 7) / 8 + 1; 71 } 72 encodeBerValue(ByteBuffer buf)73 @Override void encodeBerValue(ByteBuffer buf) { 74 Preconditions.checkNotNull(value, "No value set."); 75 Preconditions.checkState( 76 maximumSize == null || value.length() <= maximumSize, "Too large %s", 77 value.length()); 78 79 int bitsToEncode = Math.max(minimumSize, value.length()); 80 BitStream bitStream = new BitStream(); 81 for (int i = 0; i < bitsToEncode; i++) { 82 bitStream.appendBit(value.get(i)); 83 } 84 85 buf.put((byte) ((8 - (value.length() % 8)) % 8)); 86 buf.put(bitStream.getPaddedBytes()); 87 } 88 decodeBerValue(ByteBuffer buf)89 @Override void decodeBerValue(ByteBuffer buf) { 90 int unusedBits = buf.get() & 0xFF; 91 byte[] valueBytes = getRemaining(buf); 92 final int numBits = valueBytes.length * 8 - unusedBits; 93 value = new BitSet(numBits); 94 BitStreamReader reader = new BitStreamReader(valueBytes); 95 for (int i = 0; i < numBits; i++) { 96 value.set(i, reader.readBit()); 97 } 98 } 99 encodePerImpl(boolean aligned)100 private Iterable<BitStream> encodePerImpl(boolean aligned) { 101 Preconditions.checkNotNull(value, "No value set."); 102 Preconditions.checkState( 103 maximumSize == null || value.length() <= maximumSize, "Too large %s", 104 value.length()); 105 if (maximumSize == null) { 106 throw new UnsupportedOperationException("unconstrained unimplemented"); 107 } 108 109 if (minimumSize == maximumSize) { 110 if (maximumSize == 0) { 111 return ImmutableList.of(); 112 } 113 if (maximumSize < SIXTYFOUR_K) { 114 BitStream result = new BitStream(); 115 for (int i = 0; i < maximumSize; i++) { 116 result.appendBit(value.get(i)); 117 } 118 if (aligned && maximumSize > 16) { 119 result.setBeginByteAligned(); 120 } 121 return ImmutableList.of(result); 122 } 123 // Fall through to the general case. 124 } 125 126 if (maximumSize >= SIXTYFOUR_K) { 127 throw new UnsupportedOperationException("large set unimplemented"); 128 } 129 130 int bitsToEncode = Math.max(minimumSize, value.length()); 131 BitStream count = null; 132 if (aligned) { 133 count = PerAlignedUtils.encodeSmallConstrainedWholeNumber( 134 bitsToEncode, minimumSize, maximumSize); 135 } else { 136 count = PerUnalignedUtils.encodeConstrainedWholeNumber( 137 bitsToEncode, minimumSize, maximumSize); 138 } 139 BitStream result = new BitStream(); 140 if (aligned) { 141 result.setBeginByteAligned(); 142 } 143 for (int i = 0; i < bitsToEncode; i++) { 144 result.appendBit(value.get(i)); 145 } 146 return ImmutableList.of(count, result); 147 } 148 encodePerUnaligned()149 @Override public Iterable<BitStream> encodePerUnaligned() { 150 return encodePerImpl(false); 151 } 152 encodePerAligned()153 @Override public Iterable<BitStream> encodePerAligned() { 154 return encodePerImpl(true); 155 } 156 decodePerImpl(BitStreamReader reader, boolean aligned)157 private void decodePerImpl(BitStreamReader reader, boolean aligned) { 158 value = new BitSet(); 159 if (maximumSize == null) { 160 throw new UnsupportedOperationException("unconstrained unimplemented"); 161 } 162 163 if (minimumSize == maximumSize) { 164 if (maximumSize == 0) { 165 return; 166 } 167 if (maximumSize < SIXTYFOUR_K) { 168 if (aligned && maximumSize > 16) { 169 reader.spoolToByteBoundary(); 170 } 171 for (int i = 0; i < maximumSize; i++) { 172 value.set(i, reader.readBit()); 173 } 174 return; 175 } 176 // Fall through to the general case. 177 } 178 179 if (maximumSize >= SIXTYFOUR_K) { 180 throw new UnsupportedOperationException("large set unimplemented"); 181 } 182 183 int length = 0; 184 if (aligned) { 185 length = PerAlignedUtils.decodeSmallConstrainedWholeNumber( 186 reader, minimumSize, maximumSize); 187 reader.spoolToByteBoundary(); 188 } else { 189 length = PerUnalignedUtils.decodeConstrainedWholeNumber( 190 reader, minimumSize, maximumSize); 191 } 192 for (int i = 0; i < length; i++) { 193 value.set(i, reader.readBit()); 194 } 195 } 196 decodePerUnaligned(BitStreamReader reader)197 @Override public void decodePerUnaligned(BitStreamReader reader) { 198 decodePerImpl(reader, false); 199 } 200 decodePerAligned(BitStreamReader reader)201 @Override public void decodePerAligned(BitStreamReader reader) { 202 decodePerImpl(reader, true); 203 } 204 } 205