1f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun/* 2f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Copyright (C) 2016 The Android Open Source Project 3f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 4f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Licensed under the Apache License, Version 2.0 (the "License"); 5f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * you may not use this file except in compliance with the License. 6f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * You may obtain a copy of the License at 7f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 8f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * http://www.apache.org/licenses/LICENSE-2.0 9f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 10f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Unless required by applicable law or agreed to in writing, software 11f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * distributed under the License is distributed on an "AS IS" BASIS, 12f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * See the License for the specific language governing permissions and 14f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * limitations under the License. 15f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 16f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 17f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunpackage com.android.internal.telephony.uicc.asn1; 18f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 19f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunimport android.annotation.Nullable; 20f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 21f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunimport com.android.internal.telephony.uicc.IccUtils; 22f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 23f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunimport java.nio.charset.StandardCharsets; 24f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunimport java.util.ArrayList; 25f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunimport java.util.Collections; 26f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunimport java.util.List; 27f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 28f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun/** 29f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * This represents a primitive or constructed data defined by ASN.1. A constructed node can have 30f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * child nodes. A non-constructed node can have a value. This class is read-only. To build a node, 31f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * you can use the {@link #newBuilder(int)} method to get a {@link Builder} instance. This class is 32f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * not thread-safe. 33f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 34f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sunpublic final class Asn1Node { 35f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private static final int INT_BYTES = Integer.SIZE / Byte.SIZE; 36f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private static final List<Asn1Node> EMPTY_NODE_LIST = Collections.emptyList(); 37f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 38f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Bytes for boolean values. 39f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private static final byte[] TRUE_BYTES = new byte[] {-1}; 40f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private static final byte[] FALSE_BYTES = new byte[] {0}; 41f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 42f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 43f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * This class is used to build an Asn1Node instance of a constructed tag. This class is not 44f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * thread-safe. 45f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 46f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public static final class Builder { 47f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private final int mTag; 48f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private final List<Asn1Node> mChildren; 49f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 50f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private Builder(int tag) { 51f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (!isConstructedTag(tag)) { 52f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalArgumentException( 53f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun "Builder should be created for a constructed tag: " + tag); 54f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 55f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mTag = tag; 56f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mChildren = new ArrayList<>(); 57f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 58f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 59f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 60f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child from an existing node. 61f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 62f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 63f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IllegalArgumentException If the child is a non-existing node. 64f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 65f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChild(Asn1Node child) { 66f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mChildren.add(child); 67f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 68f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 69f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 70f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 71f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child from another builder. The child will be built with the call to this method, 72f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * and any changes to the child builder after the call to this method doesn't have effect. 73f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 74f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 75f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 76f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChild(Builder child) { 77f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mChildren.add(child.build()); 78f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 79f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 80f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 81f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 82f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds children from bytes. This method calls {@link Asn1Decoder} to verify the {@code 83f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * encodedBytes} and adds all nodes parsed from it as children. 84f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 85f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 86f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws InvalidAsn1DataException If the data bytes cannot be parsed. 87f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 88f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChildren(byte[] encodedBytes) throws InvalidAsn1DataException { 89f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Decoder subDecoder = new Asn1Decoder(encodedBytes, 0, encodedBytes.length); 90f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun while (subDecoder.hasNextNode()) { 91f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mChildren.add(subDecoder.nextNode()); 92f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 93f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 94f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 95f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 96f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 97f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child of non-constructed tag with an integer as the data. 98f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 99f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 100f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IllegalStateException If the {@code tag} is not constructed.. 101f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 102f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChildAsInteger(int tag, int value) { 103f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (isConstructedTag(tag)) { 104f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot set value of a constructed tag: " + tag); 105f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 106f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun byte[] dataBytes = IccUtils.signedIntToBytes(value); 107f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun addChild(new Asn1Node(tag, dataBytes, 0, dataBytes.length)); 108f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 109f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 110f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 111f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 112f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child of non-constructed tag with a string as the data. 113f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 114f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 115f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IllegalStateException If the {@code tag} is not constructed.. 116f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 117f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChildAsString(int tag, String value) { 118f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (isConstructedTag(tag)) { 119f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot set value of a constructed tag: " + tag); 120f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 121f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun byte[] dataBytes = value.getBytes(StandardCharsets.UTF_8); 122f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun addChild(new Asn1Node(tag, dataBytes, 0, dataBytes.length)); 123f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 124f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 125f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 126f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 127f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child of non-constructed tag with a byte array as the data. 128f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 129f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @param value The value will be owned by this node. 130f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 131f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IllegalStateException If the {@code tag} is not constructed.. 132f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 133f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChildAsBytes(int tag, byte[] value) { 134f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (isConstructedTag(tag)) { 135f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot set value of a constructed tag: " + tag); 136f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 137f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun addChild(new Asn1Node(tag, value, 0, value.length)); 138f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 139f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 140f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 141f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 142f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child of non-constructed tag with a byte array as the data from a hex string. 143f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 144f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 145f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IllegalStateException If the {@code tag} is not constructed.. 146f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 147f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChildAsBytesFromHex(int tag, String hex) { 148f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return addChildAsBytes(tag, IccUtils.hexStringToBytes(hex)); 149f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 150f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 151f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 152f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child of non-constructed tag with bits as the data. 153f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 154f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 155f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IllegalStateException If the {@code tag} is not constructed.. 156f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 157f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChildAsBits(int tag, int value) { 158f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (isConstructedTag(tag)) { 159f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot set value of a constructed tag: " + tag); 160f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 161f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Always allocate 5 bytes for simplicity. 162f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun byte[] dataBytes = new byte[INT_BYTES + 1]; 163f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Puts the integer into the byte[1-4]. 164f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun value = Integer.reverse(value); 165f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int dataLength = 0; 166f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun for (int i = 1; i < dataBytes.length; i++) { 167f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun dataBytes[i] = (byte) (value >> ((INT_BYTES - i) * Byte.SIZE)); 168f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (dataBytes[i] != 0) { 169f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun dataLength = i; 170f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 171f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 172f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun dataLength++; 173f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // The first byte is the number of trailing zeros of the last byte. 174f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun dataBytes[0] = IccUtils.countTrailingZeros(dataBytes[dataLength - 1]); 175f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun addChild(new Asn1Node(tag, dataBytes, 0, dataLength)); 176f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 177f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 178f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 179f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 180f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Adds a child of non-constructed tag with a boolean as the data. 181f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 182f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return This builder. 183f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IllegalStateException If the {@code tag} is not constructed.. 184f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 185f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Builder addChildAsBoolean(int tag, boolean value) { 186f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (isConstructedTag(tag)) { 187f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot set value of a constructed tag: " + tag); 188f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 189f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun addChild(new Asn1Node(tag, value ? TRUE_BYTES : FALSE_BYTES, 0, 1)); 190f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return this; 191f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 192f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 193f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** Builds the node. */ 194f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Asn1Node build() { 195f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return new Asn1Node(mTag, mChildren); 196f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 197f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 198f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 199f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private final int mTag; 200f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private final boolean mConstructed; 201f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Do not use this field directly in the methods other than the constructor and encoding 202f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // methods (e.g., toBytes()), but always use getChildren() instead. 203f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private final List<Asn1Node> mChildren; 204f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 205f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Byte array that actually holds the data. For a non-constructed node, this stores its actual 206f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // value. If the value is not set, this is null. For constructed node, this stores encoded data 207f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // of its children, which will be decoded on the first call to getChildren(). 208f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private @Nullable byte[] mDataBytes; 209f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Offset of the data in above byte array. 210f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private int mDataOffset; 211f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Length of the data in above byte array. If it's a constructed node, this is always the total 212f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // length of all its children. 213f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private int mDataLength; 214f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Length of the total bytes required to encode this node. 215f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private int mEncodedLength; 216f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 217f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 218f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Creates a new ASN.1 data node builder with the given tag. The tag is an encoded tag including 219f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * the tag class, tag number, and constructed mask. 220f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 221f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public static Builder newBuilder(int tag) { 222f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return new Builder(tag); 223f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 224f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 225f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private static boolean isConstructedTag(int tag) { 226f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Constructed mask is at the 6th bit. 227f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun byte[] tagBytes = IccUtils.unsignedIntToBytes(tag); 228f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return (tagBytes[0] & 0x20) != 0; 229f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 230f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 231f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private static int calculateEncodedBytesNumForLength(int length) { 232f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Constructed mask is at the 6th bit. 233f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int len = 1; 234f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (length > 127) { 235f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun len += IccUtils.byteNumForUnsignedInt(length); 236f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 237f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return len; 238f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 239f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 240f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 241f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Creates a node with given data bytes. If it is a constructed node, its children will be 242f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * parsed when they are visited. 243f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 244f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Node(int tag, @Nullable byte[] src, int offset, int length) { 245f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mTag = tag; 246f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Constructed mask is at the 6th bit. 247f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mConstructed = isConstructedTag(tag); 248f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mDataBytes = src; 249f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mDataOffset = offset; 250f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mDataLength = length; 251f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mChildren = mConstructed ? new ArrayList<Asn1Node>() : EMPTY_NODE_LIST; 252f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mEncodedLength = 253f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun IccUtils.byteNumForUnsignedInt(mTag) 254f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun + calculateEncodedBytesNumForLength(mDataLength) 255f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun + mDataLength; 256f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 257f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 258f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** Creates a constructed node with given children. */ 259f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private Asn1Node(int tag, List<Asn1Node> children) { 260f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mTag = tag; 261f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mConstructed = true; 262f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mChildren = children; 263f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 264f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mDataLength = 0; 265f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int size = children.size(); 266f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun for (int i = 0; i < size; i++) { 267f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mDataLength += children.get(i).mEncodedLength; 268f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 269f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mEncodedLength = 270f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun IccUtils.byteNumForUnsignedInt(mTag) 271f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun + calculateEncodedBytesNumForLength(mDataLength) 272f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun + mDataLength; 273f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 274f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 275f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public int getTag() { 276f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return mTag; 277f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 278f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 279f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public boolean isConstructed() { 280f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return mConstructed; 281f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 282f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 283f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 284f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Tests if a node has a child. 285f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 286f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @param tag The tag of an immediate child. 287f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @param tags The tags of lineal descendant. 288f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 289f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public boolean hasChild(int tag, int... tags) throws InvalidAsn1DataException { 290f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun try { 291f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun getChild(tag, tags); 292f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } catch (TagNotFoundException e) { 293f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return false; 294f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 295f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return true; 296f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 297f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 298f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 299f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Gets the first child node having the given {@code tag} and {@code tags}. 300f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 301f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @param tag The tag of an immediate child. 302f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @param tags The tags of lineal descendant. 303f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws TagNotFoundException If the child cannot be found. 304f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 305f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public Asn1Node getChild(int tag, int... tags) 306f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throws TagNotFoundException, InvalidAsn1DataException { 307f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (!mConstructed) { 308f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new TagNotFoundException(tag); 309f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 310f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int index = 0; 311f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Node node = this; 312f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun while (node != null) { 313f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun List<Asn1Node> children = node.getChildren(); 314f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int size = children.size(); 315f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Node foundChild = null; 316f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun for (int i = 0; i < size; i++) { 317f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Node child = children.get(i); 318f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (child.getTag() == tag) { 319f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun foundChild = child; 320f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun break; 321f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 322f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 323f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun node = foundChild; 324f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (index >= tags.length) { 325f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun break; 326f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 327f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun tag = tags[index++]; 328f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 329f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (node == null) { 330f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new TagNotFoundException(tag); 331f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 332f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return node; 333f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 334f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 335f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 336f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Gets all child nodes which have the given {@code tag}. 337f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 338f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return If this is primitive or no such children are found, an empty list will be returned. 339f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 340f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public List<Asn1Node> getChildren(int tag) 341f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throws TagNotFoundException, InvalidAsn1DataException { 342f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (!mConstructed) { 343f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return EMPTY_NODE_LIST; 344f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 345f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 346f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun List<Asn1Node> children = getChildren(); 347f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (children.isEmpty()) { 348f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return EMPTY_NODE_LIST; 349f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 350f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun List<Asn1Node> output = new ArrayList<>(); 351f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int size = children.size(); 352f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun for (int i = 0; i < size; i++) { 353f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Node child = children.get(i); 354f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (child.getTag() == tag) { 355f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun output.add(child); 356f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 357f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 358f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return output.isEmpty() ? EMPTY_NODE_LIST : output; 359f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 360f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 361f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 362f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Gets all child nodes of this node. If it's a constructed node having encoded data, it's 363f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * children will be decoded here. 364f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 365f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return If this is primitive, an empty list will be returned. Do not modify the returned list 366f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * directly. 367f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 368f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public List<Asn1Node> getChildren() throws InvalidAsn1DataException { 369f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (!mConstructed) { 370f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return EMPTY_NODE_LIST; 371f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 372f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 373f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes != null) { 374f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Decoder subDecoder = new Asn1Decoder(mDataBytes, mDataOffset, mDataLength); 375f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun while (subDecoder.hasNextNode()) { 376f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mChildren.add(subDecoder.nextNode()); 377f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 378f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mDataBytes = null; 379f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mDataOffset = 0; 380f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 381f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return mChildren; 382f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 383f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 384f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** @return Whether this node has a value. False will be returned for a constructed node. */ 385f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public boolean hasValue() { 386f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return !mConstructed && mDataBytes != null; 387f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 388f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 389f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 390f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return The data as an integer. If the data length is larger than 4, only the first 4 bytes 391f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * will be parsed. 392f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws InvalidAsn1DataException If the data bytes cannot be parsed. 393f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 394f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public int asInteger() throws InvalidAsn1DataException { 395f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mConstructed) { 396f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot get value of a constructed node."); 397f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 398f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes == null) { 399f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null."); 400f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 401f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun try { 402f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return IccUtils.bytesToInt(mDataBytes, mDataOffset, mDataLength); 403f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } catch (IllegalArgumentException | IndexOutOfBoundsException e) { 404f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e); 405f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 406f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 407f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 408f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 409f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return The data as a long variable which can be both positive and negative. If the data 410f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * length is larger than 8, only the first 8 bytes will be parsed. 411f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws InvalidAsn1DataException If the data bytes cannot be parsed. 412f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 413f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public long asRawLong() throws InvalidAsn1DataException { 414f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mConstructed) { 415f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot get value of a constructed node."); 416f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 417f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes == null) { 418f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null."); 419f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 420f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun try { 421f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return IccUtils.bytesToRawLong(mDataBytes, mDataOffset, mDataLength); 422f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } catch (IllegalArgumentException | IndexOutOfBoundsException e) { 423f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e); 424f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 425f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 426f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 427f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 428f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return The data as a string in UTF-8 encoding. 429f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws InvalidAsn1DataException If the data bytes cannot be parsed. 430f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 431f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public String asString() throws InvalidAsn1DataException { 432f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mConstructed) { 433f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot get value of a constructed node."); 434f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 435f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes == null) { 436f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null."); 437f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 438f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun try { 439f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return new String(mDataBytes, mDataOffset, mDataLength, StandardCharsets.UTF_8); 440f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } catch (IndexOutOfBoundsException e) { 441f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e); 442f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 443f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 444f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 445f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 446f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return The data as a byte array. 447f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws InvalidAsn1DataException If the data bytes cannot be parsed. 448f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 449f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public byte[] asBytes() throws InvalidAsn1DataException { 450f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mConstructed) { 451f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot get value of a constructed node."); 452f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 453f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes == null) { 454f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null."); 455f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 456f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun byte[] output = new byte[mDataLength]; 457f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun try { 458f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun System.arraycopy(mDataBytes, mDataOffset, output, 0, mDataLength); 459f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } catch (IndexOutOfBoundsException e) { 460f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e); 461f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 462f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return output; 463f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 464f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 465f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 466f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Gets the data as an integer for BIT STRING. DER actually stores the bits in a reversed order. 467f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * The returned integer here has the order fixed (first bit is at the lowest position). This 468f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * method currently only support at most 32 bits which fit in an integer. 469f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 470f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return The data as an integer. If this is constructed, a {@code null} will be returned. 471f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws InvalidAsn1DataException If the data bytes cannot be parsed. 472f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 473f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public int asBits() throws InvalidAsn1DataException { 474f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mConstructed) { 475f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot get value of a constructed node."); 476f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 477f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes == null) { 478f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null."); 479f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 480f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int bits; 481f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun try { 482f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun bits = IccUtils.bytesToInt(mDataBytes, mDataOffset + 1, mDataLength - 1); 483f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } catch (IllegalArgumentException | IndexOutOfBoundsException e) { 484f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e); 485f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 486f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun for (int i = mDataLength - 1; i < INT_BYTES; i++) { 487f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun bits <<= Byte.SIZE; 488f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 489f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return Integer.reverse(bits); 490f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 491f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 492f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 493f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @return The data as a boolean. 494f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws InvalidAsn1DataException If the data bytes cannot be parsed. 495f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 496f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public boolean asBoolean() throws InvalidAsn1DataException { 497f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mConstructed) { 498f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IllegalStateException("Cannot get value of a constructed node."); 499f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 500f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes == null) { 501f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null."); 502f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 503f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataLength != 1) { 504f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException( 505f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mTag, "Cannot parse data bytes as boolean: length=" + mDataLength); 506f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 507f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataOffset < 0 || mDataOffset >= mDataBytes.length) { 508f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException( 509f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mTag, 510f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun "Cannot parse data bytes.", 511f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun new ArrayIndexOutOfBoundsException(mDataOffset)); 512f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 513f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // ASN.1 has "true" as 0xFF. 514f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataBytes[mDataOffset] == -1) { 515f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return Boolean.TRUE; 516f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } else if (mDataBytes[mDataOffset] == 0) { 517f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return Boolean.FALSE; 518f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 519f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new InvalidAsn1DataException( 520f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun mTag, "Cannot parse data bytes as boolean: " + mDataBytes[mDataOffset]); 521f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 522f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 523f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** @return The number of required bytes for encoding this node in DER. */ 524f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public int getEncodedLength() { 525f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return mEncodedLength; 526f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 527f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 528f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** @return The number of required bytes for encoding this node's data in DER. */ 529f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public int getDataLength() { 530f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return mDataLength; 531f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 532f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 533f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** 534f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * Writes the DER encoded bytes of this node into a byte array. The number of written bytes is 535f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * {@link #getEncodedLength()}. 536f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * 537f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun * @throws IndexOutOfBoundsException If the {@code dest} doesn't have enough space to write. 538f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun */ 539f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public void writeToBytes(byte[] dest, int offset) { 540f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (offset < 0 || offset + mEncodedLength > dest.length) { 541f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun throw new IndexOutOfBoundsException( 542f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun "Not enough space to write. Required bytes: " + mEncodedLength); 543f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 544f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun write(dest, offset); 545f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 546f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 547f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** Writes the DER encoded bytes of this node into a new byte array. */ 548f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public byte[] toBytes() { 549f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun byte[] dest = new byte[mEncodedLength]; 550f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun write(dest, 0); 551f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return dest; 552f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 553f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 554f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** Gets a hex string representing the DER encoded bytes of this node. */ 555f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public String toHex() { 556f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return IccUtils.bytesToHexString(toBytes()); 557f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 558f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 559f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** Gets header (tag + length) as hex string. */ 560f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun public String getHeadAsHex() { 561f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun String headHex = IccUtils.bytesToHexString(IccUtils.unsignedIntToBytes(mTag)); 562f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataLength <= 127) { 563f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun headHex += IccUtils.byteToHex((byte) mDataLength); 564f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } else { 565f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun byte[] lenBytes = IccUtils.unsignedIntToBytes(mDataLength); 566f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun headHex += IccUtils.byteToHex((byte) (lenBytes.length | 0x80)); 567f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun headHex += IccUtils.bytesToHexString(lenBytes); 568f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 569f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return headHex; 570f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 571f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun 572f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun /** Returns the new offset where to write the next node data. */ 573f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun private int write(byte[] dest, int offset) { 574f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Writes the tag. 575f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun offset += IccUtils.unsignedIntToBytes(mTag, dest, offset); 576f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Writes the length. 577f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mDataLength <= 127) { 578f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun dest[offset++] = (byte) mDataLength; 579f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } else { 580f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Bytes required for encoding the length 581f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int lenLen = IccUtils.unsignedIntToBytes(mDataLength, dest, ++offset); 582f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun dest[offset - 1] = (byte) (lenLen | 0x80); 583f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun offset += lenLen; 584f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 585f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun // Writes the data. 586f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun if (mConstructed && mDataBytes == null) { 587f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun int size = mChildren.size(); 588f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun for (int i = 0; i < size; i++) { 589f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun Asn1Node child = mChildren.get(i); 590f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun offset = child.write(dest, offset); 591f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 592f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } else if (mDataBytes != null) { 593f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun System.arraycopy(mDataBytes, mDataOffset, dest, offset, mDataLength); 594f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun offset += mDataLength; 595f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 596f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun return offset; 597f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun } 598f77821db71423bf8632830d66c0790def700ceeeHolly Jiuyu Sun} 599