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.collect.ImmutableList;
20 
21 import java.math.BigInteger;
22 import java.nio.ByteBuffer;
23 import java.util.Collection;
24 import java.util.Objects;
25 
26 /**
27  */
28 public abstract class Asn1Enumerated extends Asn1Object {
29   private static final Collection<Asn1Tag> possibleFirstTags =
30       ImmutableList.of(Asn1Tag.ENUMERATED);
31 
32   private Value value;
33 
34   public interface Value {
getAssignedValue()35     int getAssignedValue();
isExtensionValue()36     boolean isExtensionValue();
ordinal()37     int ordinal(); // Standard enum method.
38   }
39 
getPossibleFirstTags()40   public static Collection<Asn1Tag> getPossibleFirstTags() {
41     return possibleFirstTags;
42   }
43 
getValue()44   public Value getValue() {
45     return value;
46   }
47 
setValue(Value value)48   public void setValue(Value value) {
49     this.value = value;
50   }
51 
isExtensible()52   protected abstract boolean isExtensible();
53 
54   /**
55    * Returns the ordinal:th value in size order.
56    */
lookupValue(int ordinal)57   protected abstract Value lookupValue(int ordinal);
58 
59   /**
60    * Returns the ordinal:th extension value in size order.
61    */
lookupExtensionValue(int ordinal)62   protected abstract Value lookupExtensionValue(int ordinal);
63 
64   /**
65    * Returns the number of distinct values (not counting extensions).
66    */
getValueCount()67   protected abstract int getValueCount();
68 
getDefaultTag()69   @Override Asn1Tag getDefaultTag() {
70     return Asn1Tag.ENUMERATED;
71   }
72 
getBerValueLength()73   @Override int getBerValueLength() {
74     return asAsn1Integer().getBerValueLength();
75   }
76 
encodeBerValue(ByteBuffer buf)77   @Override void encodeBerValue(ByteBuffer buf) {
78     asAsn1Integer().encodeBerValue(buf);
79   }
80 
decodeBerValue(ByteBuffer buf)81   @Override void decodeBerValue(ByteBuffer buf) {
82     Asn1Integer ai = new Asn1Integer();
83     ai.decodeBerValue(buf);
84     value = lookupValue(ai.getInteger().intValue());
85   }
86 
asAsn1Integer()87   private Asn1Integer asAsn1Integer() {
88     Objects.requireNonNull(value, "No value set.");
89     Asn1Integer ai = new Asn1Integer();
90     ai.setInteger(BigInteger.valueOf(value.getAssignedValue()));
91     return ai;
92   }
93 
encodePerImpl(boolean aligned)94   private Iterable<BitStream> encodePerImpl(boolean aligned) {
95     ImmutableList.Builder<BitStream> builder = ImmutableList.builder();
96     if (isExtensible()) {
97       BitStream extensionMarker = new BitStream();
98       extensionMarker.appendBit(value.isExtensionValue());
99       builder.add(extensionMarker);
100     }
101     if (value.isExtensionValue()) {
102       if (aligned) {
103         builder.addAll(
104             PerAlignedUtils.encodeNormallySmallWholeNumber(value.ordinal()));
105       } else {
106         builder.addAll(
107             PerUnalignedUtils.encodeNormallySmallWholeNumber(value.ordinal()));
108       }
109     } else {
110       // Note that it is NOT guaranteed in the asn1 spec that the root values
111       // are sorted in order. However, asn12j sorts them for us.
112       if (aligned) {
113         builder.add(
114             PerAlignedUtils.encodeSmallConstrainedWholeNumber(
115                 value.ordinal(), 0, getValueCount() - 1));
116       } else {
117         builder.add(
118             PerUnalignedUtils.encodeConstrainedWholeNumber(
119                 value.ordinal(), 0, getValueCount() - 1));
120       }
121     }
122     return builder.build();
123   }
124 
encodePerUnaligned()125   @Override public Iterable<BitStream> encodePerUnaligned() {
126     return encodePerImpl(false);
127   }
128 
encodePerAligned()129   @Override public Iterable<BitStream> encodePerAligned() {
130     return encodePerImpl(true);
131   }
132 
decodePerImpl(BitStreamReader reader, boolean aligned)133   private void decodePerImpl(BitStreamReader reader, boolean aligned) {
134     if (isExtensible() && reader.readBit()) {
135       if (aligned) {
136         value = lookupExtensionValue(PerAlignedUtils.decodeNormallySmallWholeNumber(reader));
137       } else {
138         value = lookupExtensionValue(PerUnalignedUtils.decodeNormallySmallWholeNumber(reader));
139       }
140     } else {
141       if (aligned) {
142         value = lookupValue(
143             PerAlignedUtils.decodeSmallConstrainedWholeNumber(
144                 reader, 0, getValueCount() - 1));
145       } else {
146         value = lookupValue(
147             PerUnalignedUtils.decodeConstrainedWholeNumber(
148                 reader, 0, getValueCount() - 1));
149       }
150     }
151   }
152 
decodePerUnaligned(BitStreamReader reader)153   @Override public void decodePerUnaligned(BitStreamReader reader) {
154     decodePerImpl(reader, false);
155   }
156 
decodePerAligned(BitStreamReader reader)157   @Override public void decodePerAligned(BitStreamReader reader) {
158     decodePerImpl(reader, true);
159   }
160 }
161