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