1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @author Vladimir N. Molotkov, Stepan M. Mishura
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @version $Revision$
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.security.asn1;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 types encoded with BER (X.690)
32f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class BerInputStream {
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
385c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    private final InputStream in;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected byte[] buffer;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The position in the buffer.
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Next read must place data into the buffer from this offset
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int offset = 0;
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
485c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * The buffer increment size.
495c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * Must be reasonable big to reallocate memory not to often.
505c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * Primary is used for decoding indefinite length encoding
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
525c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    private static final int BUF_INCREASE_SIZE = 1024 * 16;
535c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson
545c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** Indicates indefinite length of the current type */
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected static final int INDEFINIT_LENGTH = -1;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
575c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** Current decoded tag */
585c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    public int tag;
595c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson
605c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** Current decoded length */
615c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    protected int length;
625c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson
635c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** Current decoded content */
645c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    public Object content;
655c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson
665c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** Current decoded tag offset */
675c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    protected int tagOffset;
685c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson
695c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** Current decoded content offset */
705c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    protected int contentOffset;
715c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BerInputStream(byte[] encoded) throws IOException {
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(encoded, 0, encoded.length);
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
81f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
825c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @param encoded bytes array to be decoded
835c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @param offset the encoding offset
845c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @param expectedLength expected length of full encoding, this includes
855c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     *     identifier, length an content octets
865c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     */
875c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    public BerInputStream(byte[] encoded, int offset, int expectedLength) throws IOException {
885c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson        this.in = null;
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.buffer = encoded;
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.offset = offset;
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        next();
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // compare expected and decoded length
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != INDEFINIT_LENGTH
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                && (offset + expectedLength) != (this.offset + this.length)) {
97897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Wrong content length");
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
103f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Allocates initial buffer of default size
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BerInputStream(InputStream in) throws IOException {
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(in, BUF_INCREASE_SIZE);
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
112f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param initialSize the internal buffer initial size
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BerInputStream(InputStream in, int initialSize) throws IOException {
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.in = in;
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buffer = new byte[initialSize];
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        next();
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != INDEFINIT_LENGTH) {
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // input stream has definite length encoding
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check allocated length to avoid further reallocations
1242f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes            if (buffer.length < (length + offset)) {
1252f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                byte[] newBuffer = new byte[length + offset];
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                System.arraycopy(buffer, 0, newBuffer, 0, offset);
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer = newBuffer;
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            isIndefinedLength = true;
131897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Decoding indefinite length encoding is not supported");
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this stream to initial state.
137f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
1385c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @param encoded a new bytes array to be decoded
1395c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @throws IOException if an error occurs
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final void reset(byte[] encoded) throws IOException {
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buffer = encoded;
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        next();
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes next encoded type.
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Initializes tag, length, tagOffset and contentOffset variables
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return next decoded tag
1515c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @throws IOException if error occured
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int next() throws IOException {
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        tagOffset = offset;
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // read tag
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        tag = read();
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // read length
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        length = read();
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != 0x80) { // definite form
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // long or short length form
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((length & 0x80) != 0) { // long form
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int numOctets = length & 0x7F;
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (numOctets > 5) {
167897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                    throw new ASN1Exception("Too long encoding at [" + tagOffset + "]"); //FIXME message
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // collect this value length
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                length = read();
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                for (int i = 1; i < numOctets; i++) {
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    int ch = read();
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    length = (length << 8) + ch;//read();
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (length > 0xFFFFFF) {
178897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                    throw new ASN1Exception("Too long encoding at [" + tagOffset + "]"); //FIXME message
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else { //indefinite form
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            length = INDEFINIT_LENGTH;
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        contentOffset = offset;
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return tag;
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the length of the encoding
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static int getLength(byte[] encoding) {
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = encoding[1] & 0xFF;
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int numOctets = 0;
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((length & 0x80) != 0) { // long form
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            numOctets = length & 0x7F;
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // collect this value length
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            length = encoding[2] & 0xFF;
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 3; i < numOctets + 2; i++) {
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                length = (length << 8) + (encoding[i] & 0xFF);
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //    tag length long_form content
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return 1 + 1 + numOctets + length;
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 bitstring type
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readBitString() throws IOException {
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_BITSTRING) {
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length == 0) {
215897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                throw new ASN1Exception("ASN.1 Bitstring: wrong length. Tag at [" + tagOffset + "]");
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // content: check unused bits
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[contentOffset] > 7) {
2225c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset
2235c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                        + "]. A number of unused bits MUST be in range 0 to 7");
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length == 1 && buffer[contentOffset] != 0) {
2275c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset
2285c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                        + "]. For empty string unused bits MUST be 0");
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_BITSTRING) {
232897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Decoding constructed ASN.1 bitstring  type is not provided");
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
234897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("bitstring");
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Enumerated type
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readEnumerated() throws IOException {
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_ENUM) {
243897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("enumerated");
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length == 0) {
2485c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson            throw new ASN1Exception("ASN.1 enumerated: wrong length for identifier at ["
2495c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                    + tagOffset + "]");
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded content
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length > 1) {
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int bits = buffer[contentOffset] & 0xFF;
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[contentOffset + 1] < 0) {
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bits += 0x100;
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (bits == 0 || bits == 0x1FF) {
2625c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                throw new ASN1Exception("ASN.1 enumerated: wrong content at [" + contentOffset
2635c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                        + "]. An integer MUST be encoded in minimum number of octets");
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 boolean type
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readBoolean() throws IOException {
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_BOOLEAN) {
273897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("boolean");
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != 1) {
278897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Wrong length for ASN.1 boolean at [" + tagOffset + "]");
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2845c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** The last choice index */
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int choiceIndex;
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2875c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    /** Keeps last decoded: year, month, day, hour, minute, second, millisecond */
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int[] times;
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 GeneralizedTime type
292f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
2935c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @throws IOException if error occured
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readGeneralizedTime() throws IOException {
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_GENERALIZEDTIME) {
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME: any other optimizations?
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME store string somewhere to allow a custom time type perform
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // additional checks
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check syntax: the last char MUST be Z
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[offset - 1] != 'Z') {
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // FIXME support only format that is acceptable for DER
305897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                throw new ASN1Exception("ASN.1 GeneralizedTime: encoded format is not implemented");
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check syntax: MUST be YYYYMMDDHHMMSS[(./,)DDD]'Z'
3095c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson            if (length != 15 && (length < 17 || length > 19)) {
3105c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                throw new ASN1Exception("ASN.1 GeneralizedTime wrongly encoded at ["
3115c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                        + contentOffset + "]");
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check content: milliseconds
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length > 16) {
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                byte char14 = buffer[contentOffset + 14];
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (char14 != '.' && char14 != ',') {
3185c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                    throw new ASN1Exception("ASN.1 GeneralizedTime wrongly encoded at ["
3195c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson                            + contentOffset + "]");
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (times == null) {
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times = new int[7];
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[0] = strToInt(contentOffset, 4); // year
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[1] = strToInt(contentOffset + 4, 2); // month
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[2] = strToInt(contentOffset + 6, 2); // day
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[3] = strToInt(contentOffset + 8, 2); // hour
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[4] = strToInt(contentOffset + 10, 2); // minute
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[5] = strToInt(contentOffset + 12, 2); // second
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length > 16) {
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // FIXME optimize me
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[6] = strToInt(contentOffset + 15, length - 16);
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (length == 17) {
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    times[6] = times[6] * 100;
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (length == 18) {
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    times[6] = times[6] * 10;
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME check all values for valid numbers!!!
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) {
346897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Decoding constructed ASN.1 GeneralizedTime type is not supported");
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
348897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("GeneralizedTime");
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 UTCTime type
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
3555c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @throws IOException if an I/O error occurs or the end of the stream is reached
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readUTCTime() throws IOException {
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_UTCTIME) {
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            switch (length) {
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_HM:
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_HMS:
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_LOCAL_HM:
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_LOCAL_HMS:
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // FIXME only coordinated universal time formats are supported
366897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                throw new ASN1Exception("ASN.1 UTCTime: local time format is not supported");
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            default:
368897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                throw new ASN1Exception("ASN.1 UTCTime: wrong length, identifier at " + tagOffset);
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME: any other optimizations?
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME store string somewhere to allow a custom time type perform
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // additional checks
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check syntax: the last char MUST be Z
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[offset - 1] != 'Z') {
379f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception("ASN.1 UTCTime wrongly encoded at ["
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        + contentOffset + ']');
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (times == null) {
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times = new int[7];
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[0] = strToInt(contentOffset, 2); // year
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (times[0] > 49) {
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[0] += 1900;
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[0] += 2000;
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[1] = strToInt(contentOffset + 2, 2); // month
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[2] = strToInt(contentOffset + 4, 2); // day
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[3] = strToInt(contentOffset + 6, 2); // hour
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[4] = strToInt(contentOffset + 8, 2); // minute
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length == ASN1UTCTime.UTC_HMS) {
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[5] = strToInt(contentOffset + 10, 2); // second
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME check all time values for valid numbers!!!
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_UTCTIME) {
405897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Decoding constructed ASN.1 UTCTime type is not supported");
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
407897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("UTCTime");
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int strToInt(int off, int count) throws ASN1Exception {
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int result = 0;
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = off, end = off + count; i < end; i++) {
4145c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson            int c = buffer[i] - 48;
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (c < 0 || c > 9) {
416897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                throw new ASN1Exception("Time encoding has invalid char");
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = result * 10 + c;
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Integer type
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readInteger() throws IOException {
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_INTEGER) {
428897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("integer");
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length < 1) {
433897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Wrong length for ASN.1 integer at [" + tagOffset + "]");
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded content
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length > 1) {
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte firstByte = buffer[offset - length];
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte secondByte = (byte) (buffer[offset - length + 1] & 0x80);
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (firstByte == 0 && secondByte == 0 || firstByte == (byte) 0xFF
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    && secondByte == (byte) 0x80) {
445897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                throw new ASN1Exception("Wrong content for ASN.1 integer at [" + (offset - length) + "]. An integer MUST be encoded in minimum number of octets");
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Octetstring type
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readOctetString() throws IOException {
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_OCTETSTRING) {
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_OCTETSTRING) {
457897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Decoding constructed ASN.1 octet string type is not supported");
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
459897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("octetstring");
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
463897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes    private ASN1Exception expected(String what) throws ASN1Exception {
464897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes        throw new ASN1Exception("ASN.1 " + what + " identifier expected at [" + tagOffset + "], got " + Integer.toHexString(tag));
465897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes    }
466897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int oidElement;
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 ObjectIdentifier type
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readOID() throws IOException {
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_OID) {
474897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("OID");
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length < 1) {
479897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Wrong length for ASN.1 object identifier at [" + tagOffset + "]");
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check content: last encoded byte (8th bit MUST be zero)
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((buffer[offset - 1] & 0x80) != 0) {
486897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Wrong encoding at [" + (offset - 1) + "]");
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        oidElement = 1;
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < length; i++, ++oidElement) {
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while ((buffer[contentOffset + i] & 0x80) == 0x80) {
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                i++;
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Sequence type
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSequence(ASN1Sequence sequence) throws IOException {
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SEQUENCE) {
502897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("sequence");
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int begOffset = offset;
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int endOffset = begOffset + length;
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ASN1Type[] type = sequence.type;
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int i = 0;
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (isVerify) {
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; (offset < endOffset) && (i < type.length); i++) {
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (!type[i].checkTag(tag)) {
518f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    // check whether it is optional component or not
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
520897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                        throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]");
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    i++;
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                type[i].decode(this);
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check the rest of components
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; i < type.length; i++) {
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!sequence.OPTIONAL[i]) {
531897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                    throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]");
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int seqTagOffset = tagOffset; //store tag offset
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Object[] values = new Object[type.length];
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; (offset < endOffset) && (i < type.length); i++) {
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (!type[i].checkTag(tag)) {
543f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    // check whether it is optional component or not
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
545897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                        throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]");
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // sets default value
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (sequence.DEFAULT[i] != null) {
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        values[i] = sequence.DEFAULT[i];
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    i++;
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                values[i] = type[i].decode(this);
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check the rest of components
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; i < type.length; i++) {
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!sequence.OPTIONAL[i]) {
560897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                    throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]");
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (sequence.DEFAULT[i] != null) {
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    values[i] = sequence.DEFAULT[i];
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            content = values;
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            tagOffset = seqTagOffset; //retrieve tag offset
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset != endOffset) {
572897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Wrong encoding at [" + begOffset + "]. Content's length and encoded length are not the same");
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 SequenceOf type
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSequenceOf(ASN1SequenceOf sequenceOf) throws IOException {
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SEQUENCEOF) {
581897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("sequenceOf");
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        decodeValueCollection(sequenceOf);
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Set type
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSet(ASN1Set set) throws IOException {
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SET) {
592897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("set");
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
595897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes        throw new ASN1Exception("Decoding ASN.1 Set type is not supported");
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 SetOf type
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSetOf(ASN1SetOf setOf) throws IOException {
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SETOF) {
603897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("setOf");
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        decodeValueCollection(setOf);
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6095c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson    private void decodeValueCollection(ASN1ValueCollection collection) throws IOException {
610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int begOffset = offset;
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int endOffset = begOffset + length;
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ASN1Type type = collection.type;
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (isVerify) {
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (endOffset > offset) {
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                type.decode(this);
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int seqTagOffset = tagOffset; //store tag offset
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6235c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson            ArrayList<Object> values = new ArrayList<Object>();
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (endOffset > offset) {
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                values.add(type.decode(this));
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
62921f21e9f56ab8c9abfd8728473533fcaafafeac0Jesse Wilson            values.trimToSize();
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            content = values;
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            tagOffset = seqTagOffset; //retrieve tag offset
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset != endOffset) {
636897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Wrong encoding at [" + begOffset + "]. Content's length and encoded length are not the same");
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 String type
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
6435c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson     * @throws IOException if an I/O error occurs or the end of the stream is reached
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readString(ASN1StringType type) throws IOException {
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == type.id) {
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == type.constrId) {
649897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Decoding constructed ASN.1 string type is not provided");
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
651897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw expected("string");
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns encoded array.
657f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
658f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * MUST be invoked after decoding corresponding ASN.1 notation
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public byte[] getEncoded() {
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] encoded = new byte[offset - tagOffset];
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(buffer, tagOffset, encoded, 0, encoded.length);
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return encoded;
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns internal buffer used for decoding
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final byte[] getBuffer() {
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return buffer;
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns length of the current content for decoding
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getLength() {
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return length;
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the current offset
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getOffset() {
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return offset;
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns end offset for the current encoded type
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getEndOffset() {
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return offset + length;
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns start offset for the current encoded type
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getTagOffset() {
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return tagOffset;
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates verify or store mode.
703f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * In store mode a decoded content is stored in a newly allocated
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * appropriate object. The <code>content</code> variable holds
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * a reference to the last created object.
707f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * In verify mode a decoded content is not stored.
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // FIXME it is used only for one case
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // decoding PCKS#8 Private Key Info notation
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // remove this option because it does decoding more complex
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean isVerify;
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets verify mode.
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final void setVerify() {
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        isVerify = true;
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates defined or indefined reading mode for associated InputStream.
724f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This mode is defined by reading a length
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for a first ASN.1 type from InputStream.
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean isIndefinedLength;
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reads the next encoded byte from the encoded input stream.
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int read() throws IOException {
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset == buffer.length) {
735897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Unexpected end of encoding");
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in == null) {
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return buffer[offset++] & 0xFF;
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int octet = in.read();
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (octet == -1) {
743897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                throw new ASN1Exception("Unexpected end of encoding");
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
745f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer[offset++] = (byte) octet;
747f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return octet;
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reads the next encoded content from the encoded input stream.
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The method MUST be used for reading a primitive encoded content.
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readContent() throws IOException {
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset + length > buffer.length) {
758897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes            throw new ASN1Exception("Unexpected end of encoding");
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in == null) {
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset += length;
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
7642f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes            int bytesRead = in.read(buffer, offset, length);
7652f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes
7662f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes            if (bytesRead != length) {
7672f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                // if input stream didn't return all data at once
7682f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                // try to read it in several blocks
7692f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                int c = bytesRead;
7702f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                do {
7712f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    if (c < 1 || bytesRead > length) {
772897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes                        throw new ASN1Exception("Failed to read encoded content");
7732f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    }
7742f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    c = in.read(buffer, offset + bytesRead, length - bytesRead);
7752f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    bytesRead += c;
7762f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                } while (bytesRead != length);
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
7782f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset += length;
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reallocates the buffer in order to make it
785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * exactly the size of data it contains
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void compactBuffer() {
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset != buffer.length) {
789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] newBuffer = new byte[offset];
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // restore buffer content
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(buffer, 0, newBuffer, 0, offset);
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // set new buffer
793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer = newBuffer;
794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Object[][] pool;
797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void put(Object key, Object entry) {
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pool == null) {
800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool = new Object[2][10];
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int i = 0;
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (; i < pool[0].length && pool[0][i] != null; i++) {
805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (pool[0][i] == key) {
806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                pool[1][i] = entry;
807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (i == pool[0].length) {
812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Object[][] newPool = new Object[pool[0].length * 2][2];
813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(pool[0], 0, newPool[0], 0, pool[0].length);
814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(pool[1], 0, newPool[1], 0, pool[0].length);
815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool = newPool;
816adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
817adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool[0][i] = key;
818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool[1][i] = entry;
819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
820adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
821adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Object get(Object key) {
823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pool == null) {
824adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
826adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < pool[0].length; i++) {
828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (pool[0][i] == key) {
829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return pool[1][i];
830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
831adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
832adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
833adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
834adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
835