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