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