DerInputStream.java revision ddde3e18b22acdaecb883794f5c8e21f0b87bf2f
151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.security.util;
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.InputStream;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.IOException;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.EOFException;
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Date;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Vector;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.math.BigInteger;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.DataInputStream;
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A DER input stream, used for parsing ASN.1 DER-encoded data such as
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * that found in X.509 certificates.  DER is a subset of BER/1, which has
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the advantage that it allows only a single encoding of primitive data.
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * (High level data such as dates still support many encodings.)  That is,
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * it uses the "Definite" Encoding Rules (DER) not the "Basic" ones (BER).
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <P>Note that, like BER/1, DER streams are streams of explicitly
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * tagged data values.  Accordingly, this programming interface does
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * not expose any variant of the java.io.InputStream interface, since
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * that kind of input stream holds untagged data values and using that
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * I/O model could prevent correct parsing of the DER data.
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <P>At this time, this class supports only a subset of the types of DER
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * data encodings which are defined.  That subset is sufficient for parsing
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * most X.509 certificates.
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author David Brownell
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author Amit Kapoor
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author Hemma Prafullchandra
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class DerInputStream {
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * This version only supports fully buffered DER.  This is easy to
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * work with, though if large objects are manipulated DER becomes
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * awkward to deal with.  That's where BER is useful, since BER
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * handles streaming data relatively well.
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    DerInputBuffer      buffer;
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** The DER tag of the value; one of the tag_ constants. */
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public byte         tag;
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Create a DER input stream from a data buffer.  The buffer is not
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * copied, it is shared.  Accordingly, the buffer should be treated
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * as read-only.
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param data the buffer from which to create the string (CONSUMED)
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DerInputStream(byte[] data) throws IOException {
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        init(data, 0, data.length);
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Create a DER input stream from part of a data buffer.
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The buffer is not copied, it is shared.  Accordingly, the
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * buffer should be treated as read-only.
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param data the buffer from which to create the string (CONSUMED)
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param offset the first index of <em>data</em> which will
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          be read as DER input in the new stream
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len how long a chunk of the buffer to use,
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          starting at "offset"
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DerInputStream(byte[] data, int offset, int len) throws IOException {
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        init(data, offset, len);
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * private helper routine
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void init(byte[] data, int offset, int len) throws IOException {
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((offset+2 > data.length) || (offset+len > data.length)) {
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Encoding bytes too short");
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // check for indefinite length encoding
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (DerIndefLenConverter.isIndefinite(data[offset+1])) {
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            byte[] inData = new byte[len];
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            System.arraycopy(data, offset, inData, 0, len);
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            DerIndefLenConverter derIn = new DerIndefLenConverter();
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer = new DerInputBuffer(derIn.convert(inData));
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer = new DerInputBuffer(data, offset, len);
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        buffer.mark(Integer.MAX_VALUE);
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    DerInputStream(DerInputBuffer buf) {
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        buffer = buf;
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        buffer.mark(Integer.MAX_VALUE);
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Creates a new DER input stream from part of this input stream.
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len how long a chunk of the current input stream to use,
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          starting at the current position.
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param do_skip true if the existing data in the input stream should
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          be skipped.  If this value is false, the next data read
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          on this stream and the newly created stream will be the
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          same.
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DerInputStream subStream(int len, boolean do_skip)
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    throws IOException {
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        DerInputBuffer  newbuf = buffer.dup();
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        newbuf.truncate(len);
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (do_skip) {
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer.skip(len);
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new DerInputStream(newbuf);
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return what has been written to this DerInputStream
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * as a byte array. Useful for debugging.
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public byte[] toByteArray() {
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.toByteArray();
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * PRIMITIVES -- these are "universal" ASN.1 simple types.
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *  INTEGER, ENUMERATED, BIT STRING, OCTET STRING, NULL
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *  OBJECT IDENTIFIER, SEQUENCE (OF), SET (OF)
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *  UTF8String, PrintableString, T61String, IA5String, UTCTime,
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *  GeneralizedTime, BMPString.
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Note: UniversalString not supported till encoder is available.
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get an integer from the input stream as an integer.
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer held in this DER input stream.
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getInteger() throws IOException {
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_Integer) {
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input, Integer tag error");
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.getInteger(getLength(buffer));
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a integer from the input stream as a BigInteger object.
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer held in this DER input stream.
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public BigInteger getBigInteger() throws IOException {
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_Integer) {
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input, Integer tag error");
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.getBigInteger(getLength(buffer), false);
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns an ASN.1 INTEGER value as a positive BigInteger.
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * This is just to deal with implementations that incorrectly encode
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * some values as negative.
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer held in this DER value as a BigInteger.
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public BigInteger getPositiveBigInteger() throws IOException {
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_Integer) {
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input, Integer tag error");
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.getBigInteger(getLength(buffer), true);
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get an enumerated from the input stream.
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer held in this DER input stream.
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getEnumerated() throws IOException {
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_Enumerated) {
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input, Enumerated tag error");
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.getInteger(getLength(buffer));
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a bit string from the input stream. Padded bits (if any)
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * will be stripped off before the bit string is returned.
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public byte[] getBitString() throws IOException {
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_BitString)
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input not an bit string");
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.getBitString(getLength(buffer));
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a bit string from the input stream.  The bit string need
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * not be byte-aligned.
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public BitArray getUnalignedBitString() throws IOException {
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_BitString)
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input not a bit string");
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int length = getLength(buffer) - 1;
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * First byte = number of excess bits in the last octet of the
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * representation.
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int validBits = length*8 - buffer.read();
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] repn = new byte[length];
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((length != 0) && (buffer.read(repn) != length))
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER bit string");
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new BitArray(validBits, repn);
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns an ASN.1 OCTET STRING from the input stream.
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public byte[] getOctetString() throws IOException {
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_OctetString)
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input not an octet string");
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int length = getLength(buffer);
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] retval = new byte[length];
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((length != 0) && (buffer.read(retval) != length))
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER octet string");
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return retval;
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the asked number of bytes from the input stream.
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void getBytes(byte[] val) throws IOException {
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((val.length != 0) && (buffer.read(val) != val.length)) {
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER octet string");
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Reads an encoded null value from the input stream.
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void getNull() throws IOException {
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_Null || buffer.read() != 0)
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("getNull, bad data");
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Reads an X.200 style Object Identifier from the stream.
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public ObjectIdentifier getOID() throws IOException {
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ObjectIdentifier(this);
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a sequence of encoded entities.  ASN.1 sequences are
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * ordered, and they are often used, like a "struct" in C or C++,
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to group data values.  They may have optional or context
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * specific values.
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param startLen guess about how long the sequence will be
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          (used to initialize an auto-growing data structure)
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return array of the values in the sequence
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DerValue[] getSequence(int startLen) throws IOException {
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        tag = (byte)buffer.read();
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (tag != DerValue.tag_Sequence)
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Sequence tag error");
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readVector(startLen);
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a set of encoded entities.  ASN.1 sets are unordered,
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * though DER may specify an order for some kinds of sets (such
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * as the attributes in an X.500 relative distinguished name)
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to facilitate binary comparisons of encoded values.
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param startLen guess about how large the set will be
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          (used to initialize an auto-growing data structure)
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return array of the values in the sequence
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DerValue[] getSet(int startLen) throws IOException {
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        tag = (byte)buffer.read();
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (tag != DerValue.tag_Set)
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Set tag error");
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readVector(startLen);
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a set of encoded entities.  ASN.1 sets are unordered,
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * though DER may specify an order for some kinds of sets (such
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * as the attributes in an X.500 relative distinguished name)
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to facilitate binary comparisons of encoded values.
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param startLen guess about how large the set will be
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          (used to initialize an auto-growing data structure)
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param implicit if true tag is assumed implicit.
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return array of the values in the sequence
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DerValue[] getSet(int startLen, boolean implicit)
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws IOException {
331ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        return getSet(
332ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            startLen,
333ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            implicit,
334ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            false); // no need to retain original encoded form
335ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    }
336ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin
337ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    public DerValue[] getSet(int startLen, boolean implicit,
338ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            boolean originalEncodedFormRetained)
339ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        throws IOException {
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        tag = (byte)buffer.read();
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!implicit) {
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (tag != DerValue.tag_Set) {
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Set tag error");
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
346ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        return (readVector(startLen, originalEncodedFormRetained));
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Read a "vector" of values ... set or sequence have the
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * same encoding, except for the initial tag, so both use
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * this same helper routine.
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    protected DerValue[] readVector(int startLen) throws IOException {
355ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        return readVector(
356ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            startLen,
357ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            false); // no need to retain original encoded form
358ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    }
359ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin
360ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    /*
361ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin     * Read a "vector" of values ... set or sequence have the
362ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin     * same encoding, except for the initial tag, so both use
363ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin     * this same helper routine.
364ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin     */
365ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    protected DerValue[] readVector(int startLen,
366ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            boolean originalEncodedFormRetained) throws IOException {
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        DerInputStream  newstr;
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte lenByte = (byte)buffer.read();
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int len = getLength((lenByte & 0xff), buffer);
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == -1) {
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           // indefinite length encoding found
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           int readLen = buffer.available();
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           int offset = 2;     // for tag and length bytes
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           byte[] indefData = new byte[readLen + offset];
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           indefData[0] = tag;
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           indefData[1] = lenByte;
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           DataInputStream dis = new DataInputStream(buffer);
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           dis.readFully(indefData, offset, readLen);
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           dis.close();
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           DerIndefLenConverter derIn = new DerIndefLenConverter();
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           buffer = new DerInputBuffer(derIn.convert(indefData));
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           if (tag != buffer.read())
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Indefinite length encoding" +
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        " not supported");
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           len = DerInputStream.getLength(buffer);
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == 0)
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // return empty array instead of null, which should be
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // used only for missing optionals
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new DerValue[0];
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Create a temporary stream from which to read the data,
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * unless it's not really needed.
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.available() == len)
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            newstr = this;
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            newstr = subStream(len, true);
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Pull values out of the stream.
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Vector<DerValue> vec = new Vector<DerValue>(startLen);
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        DerValue value;
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        do {
411ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin            value = new DerValue(newstr.buffer, originalEncodedFormRetained);
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            vec.addElement(value);
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } while (newstr.available() > 0);
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (newstr.available() != 0)
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("extra data at end of vector");
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Now stick them into the array we're returning.
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int             i, max = vec.size();
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        DerValue[]      retval = new DerValue[max];
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (i = 0; i < max; i++)
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            retval[i] = vec.elementAt(i);
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return retval;
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a single DER-encoded value from the input stream.
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * It can often be useful to pull a value from the stream
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * and defer parsing it.  For example, you can pull a nested
43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * sequence out with one call, and only examine its elements
43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * later when you really need to.
43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DerValue getDerValue() throws IOException {
43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new DerValue(buffer);
43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Read a string that was encoded as a UTF8String DER value.
44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getUTF8String() throws IOException {
44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readString(DerValue.tag_UTF8String, "UTF-8", "UTF8");
44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Read a string that was encoded as a PrintableString DER value.
45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getPrintableString() throws IOException {
45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readString(DerValue.tag_PrintableString, "Printable",
45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          "ASCII");
45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Read a string that was encoded as a T61String DER value.
45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getT61String() throws IOException {
46051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Works for common characters between T61 and ASCII.
46251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readString(DerValue.tag_T61String, "T61", "ISO-8859-1");
46451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Read a string that was encoded as a IA5tring DER value.
46851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getIA5String() throws IOException {
47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readString(DerValue.tag_IA5String, "IA5", "ASCII");
47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
47451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Read a string that was encoded as a BMPString DER value.
47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
47651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getBMPString() throws IOException {
47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readString(DerValue.tag_BMPString, "BMP",
47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          "UnicodeBigUnmarked");
47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
48051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
48251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Read a string that was encoded as a GeneralString DER value.
48351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getGeneralString() throws IOException {
48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return readString(DerValue.tag_GeneralString, "General",
48651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          "ASCII");
48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Private helper routine to read an encoded string from the input
49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * stream.
49251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param stringTag the tag for the type of string to read
49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param stringName a name to display in error messages
49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param enc the encoder to use to interpret the data. Should
49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * correspond to the stringTag above.
49651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private String readString(byte stringTag, String stringName,
49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                              String enc) throws IOException {
49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != stringTag)
50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input not a " +
50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                  stringName + " string");
50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int length = getLength(buffer);
50551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] retval = new byte[length];
50651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((length != 0) && (buffer.read(retval) != length))
50751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER " +
50851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                  stringName + " string");
50951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
51051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new String(retval, enc);
51151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
51251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
51351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
51451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a UTC encoded time value from the input stream.
51551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
51651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Date getUTCTime() throws IOException {
51751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_UtcTime)
51851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input, UTCtime tag invalid ");
51951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.getUTCTime(getLength(buffer));
52051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
52151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
52251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
52351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a Generalized encoded time value from the input stream.
52451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
52551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Date getGeneralizedTime() throws IOException {
52651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (buffer.read() != DerValue.tag_GeneralizedTime)
52751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER input, GeneralizedTime tag invalid ");
52851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.getGeneralizedTime(getLength(buffer));
52951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
53051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
53151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
53251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a byte from the input stream.
53351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
53451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // package private
53551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    int getByte() throws IOException {
53651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (0x00ff & buffer.read());
53751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
53851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
53951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int peekByte() throws IOException {
54051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buffer.peek();
54151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
54251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
54351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // package private
54451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    int getLength() throws IOException {
54551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getLength(buffer);
54651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
54751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
54851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
54951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a length from the input stream, allowing for at most 32 bits of
55051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * encoding to be used.  (Not the same as getting a tagged integer!)
55151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
55251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the length or -1 if indefinite length found.
55351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IOException on parsing error or unsupported lengths.
55451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
55551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static int getLength(InputStream in) throws IOException {
55651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getLength(in.read(), in);
55751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
55851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
55951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
56051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Get a length from the input stream, allowing for at most 32 bits of
56151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * encoding to be used.  (Not the same as getting a tagged integer!)
56251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
56351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the length or -1 if indefinite length found.
56451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IOException on parsing error or unsupported lengths.
56551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
56651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static int getLength(int lenByte, InputStream in) throws IOException {
56751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int value, tmp;
56851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
56951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        tmp = lenByte;
57051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
57151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value = tmp;
57251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {                     // long form or indefinite
57351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            tmp &= 0x07f;
57451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
57551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            /*
57651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski             * NOTE:  tmp == 0 indicates indefinite length encoded data.
57751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski             * tmp > 4 indicates more than 4Gb of data.
57851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski             */
57951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (tmp == 0)
58051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return -1;
58151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (tmp < 0 || tmp > 4)
58251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("DerInputStream.getLength(): lengthTag="
58351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    + tmp + ", "
58451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    + ((tmp < 0) ? "incorrect DER encoding." : "too big."));
58551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
58651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (value = 0; tmp > 0; tmp --) {
58751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                value <<= 8;
58851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                value += 0x0ff & in.read();
58951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
59051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
59151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return value;
59251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
59351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
59451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
59551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Mark the current position in the buffer, so that
59651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * a later call to <code>reset</code> will return here.
59751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
59851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void mark(int value) { buffer.mark(value); }
59951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
60051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
60151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
60251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return to the position of the last <code>mark</code>
60351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * call.  A mark is implicitly set at the beginning of
60451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * the stream when it is created.
60551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
60651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void reset() { buffer.reset(); }
60751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
60851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
60951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
61051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the number of bytes available for reading.
61151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * This is most useful for testing whether the stream is
61251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * empty.
61351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
61451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int available() { return buffer.available(); }
61551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
616