DerInputBuffer.java revision 51b1b6997fd3f980076b8081f7f1165ccc2a4008
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.ByteArrayInputStream;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.IOException;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.OutputStream;
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.math.BigInteger;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Date;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.util.calendar.CalendarDate;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.util.calendar.CalendarSystem;
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DER input buffer ... this is the main abstraction in the DER library
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * which actively works with the "untyped byte stream" abstraction.  It
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * does so with impunity, since it's not intended to be exposed to
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * anyone who could violate the "typed value stream" DER model and hence
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * corrupt the input stream of DER values.
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author David Brownell
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiclass DerInputBuffer extends ByteArrayInputStream implements Cloneable {
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    DerInputBuffer(byte[] buf) { super(buf); }
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    DerInputBuffer(byte[] buf, int offset, int len) {
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        super(buf, offset, len);
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    DerInputBuffer dup() {
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            DerInputBuffer retval = (DerInputBuffer)clone();
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            retval.mark(Integer.MAX_VALUE);
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return retval;
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (CloneNotSupportedException e) {
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IllegalArgumentException(e.toString());
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    byte[] toByteArray() {
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int     len = available();
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len <= 0)
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[]  retval = new byte[len];
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        System.arraycopy(buf, pos, retval, 0, len);
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return retval;
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    int peek() throws IOException {
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pos >= count)
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("out of data");
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return buf[pos];
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Compares this DerInputBuffer for equality with the specified
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * object.
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean equals(Object other) {
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (other instanceof DerInputBuffer)
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return equals((DerInputBuffer)other);
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return false;
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    boolean equals(DerInputBuffer other) {
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (this == other)
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return true;
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int max = this.available();
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (other.available() != max)
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return false;
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < max; i++) {
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (this.buf[this.pos + i] != other.buf[other.pos + i]) {
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return false;
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return true;
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a hashcode for this DerInputBuffer.
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a hashcode for this DerInputBuffer.
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int hashCode() {
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int retval = 0;
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int len = available();
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int p = pos;
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < len; i++)
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            retval += buf[p + i] * i;
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return retval;
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    void truncate(int len) throws IOException {
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("insufficient data");
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        count = pos + len;
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the integer which takes up the specified number
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of bytes in this buffer as a BigInteger.
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use.
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param makePositive whether to always return a positive value,
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *   irrespective of actual encoding
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer as a BigInteger.
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    BigInteger getBigInteger(int len, boolean makePositive) throws IOException {
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of integer");
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == 0) {
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid encoding: zero length Int value");
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] bytes = new byte[len];
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        System.arraycopy(buf, pos, bytes, 0, len);
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        skip(len);
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (makePositive) {
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new BigInteger(1, bytes);
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new BigInteger(bytes);
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the integer which takes up the specified number
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of bytes in this buffer.
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IOException if the result is not within the valid
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range for integer, i.e. between Integer.MIN_VALUE and
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Integer.MAX_VALUE.
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use.
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer.
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getInteger(int len) throws IOException {
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        BigInteger result = getBigInteger(len, false);
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (result.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) {
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Integer below minimum valid value");
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (result.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Integer exceeds maximum valid value");
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return result.intValue();
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the bit string which takes up the specified
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * number of bytes in this buffer.
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public byte[] getBitString(int len) throws IOException {
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of bit string");
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == 0) {
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid encoding: zero length bit string");
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int numOfPadBits = buf[pos];
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((numOfPadBits < 0) || (numOfPadBits > 7)) {
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid number of padding bits");
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // minus the first byte which indicates the number of padding bits
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] retval = new byte[len - 1];
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        System.arraycopy(buf, pos + 1, retval, 0, len - 1);
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (numOfPadBits != 0) {
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // get rid of the padding bits
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            retval[len - 2] &= (0xff << numOfPadBits);
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        skip(len);
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return retval;
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the bit string which takes up the rest of this buffer.
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    byte[] getBitString() throws IOException {
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getBitString(available());
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the bit string which takes up the rest of this buffer.
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The bit string need not be byte-aligned.
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    BitArray getUnalignedBitString() throws IOException {
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pos >= count)
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Just copy the data into an aligned, padded octet buffer,
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * and consume the rest of the buffer.
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int len = available();
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int unusedBits = buf[pos] & 0xff;
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (unusedBits > 7 ) {
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid value for unused bits: " + unusedBits);
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] bits = new byte[len - 1];
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // number of valid bits
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int length = (bits.length == 0) ? 0 : bits.length * 8 - unusedBits;
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        System.arraycopy(buf, pos + 1, bits, 0, len - 1);
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        BitArray bitArray = new BitArray(length, bits);
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        pos = count;
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return bitArray;
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the UTC Time value that takes up the specified number
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of bytes in this buffer.
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Date getUTCTime(int len) throws IOException {
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER UTC Time");
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len < 11 || len > 17)
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER UTC Time length error");
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getTime(len, false);
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the Generalized Time value that takes up the specified
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * number of bytes in this buffer.
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Date getGeneralizedTime(int len) throws IOException {
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER Generalized Time");
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len < 13 || len > 23)
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER Generalized Time length error");
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getTime(len, true);
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Private helper routine to extract time from the der value.
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param generalized true if Generalized Time is to be read, false
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * if UTC Time is to be read.
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Date getTime(int len, boolean generalized) throws IOException {
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * UTC time encoded as ASCII chars:
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmZ
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmssZ
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmm+hhmm
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmm-hhmm
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmss+hhmm
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmss-hhmm
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * UTC Time is broken in storing only two digits of year.
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * If YY < 50, we assume 20YY;
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * if YY >= 50, we assume 19YY, as per RFC 3280.
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Generalized time has a four-digit year and allows any
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * precision specified in ISO 8601. However, for our purposes,
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * we will only allow the same format as UTC time, except that
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * fractional seconds (millisecond precision) are supported.
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int year, month, day, hour, minute, second, millis;
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String type = null;
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (generalized) {
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            type = "Generalized";
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year = 1000 * Character.digit((char)buf[pos++], 10);
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += 100 * Character.digit((char)buf[pos++], 10);
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += 10 * Character.digit((char)buf[pos++], 10);
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += Character.digit((char)buf[pos++], 10);
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            len -= 2; // For the two extra YY
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            type = "UTC";
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year = 10 * Character.digit((char)buf[pos++], 10);
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += Character.digit((char)buf[pos++], 10);
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (year < 50)              // origin 2000
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                year += 2000;
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            else
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                year += 1900;   // origin 1900
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        month = 10 * Character.digit((char)buf[pos++], 10);
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        month += Character.digit((char)buf[pos++], 10);
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        day = 10 * Character.digit((char)buf[pos++], 10);
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        day += Character.digit((char)buf[pos++], 10);
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hour = 10 * Character.digit((char)buf[pos++], 10);
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hour += Character.digit((char)buf[pos++], 10);
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        minute = 10 * Character.digit((char)buf[pos++], 10);
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        minute += Character.digit((char)buf[pos++], 10);
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        len -= 10; // YYMMDDhhmm
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * We allow for non-encoded seconds, even though the
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * IETF-PKIX specification says that the seconds should
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * always be encoded even if it is zero.
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        millis = 0;
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > 2 && len < 12) {
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            second = 10 * Character.digit((char)buf[pos++], 10);
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            second += Character.digit((char)buf[pos++], 10);
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            len -= 2;
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // handle fractional seconds (if present)
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (buf[pos] == '.' || buf[pos] == ',') {
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                len --;
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                pos++;
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // handle upto milisecond precision only
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int precision = 0;
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int peek = pos;
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                while (buf[peek] != 'Z' &&
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                       buf[peek] != '+' &&
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                       buf[peek] != '-') {
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    peek++;
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    precision++;
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                switch (precision) {
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                case 3:
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 100 * Character.digit((char)buf[pos++], 10);
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 10 * Character.digit((char)buf[pos++], 10);
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += Character.digit((char)buf[pos++], 10);
36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                case 2:
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 100 * Character.digit((char)buf[pos++], 10);
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 10 * Character.digit((char)buf[pos++], 10);
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                case 1:
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 100 * Character.digit((char)buf[pos++], 10);
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                default:
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        throw new IOException("Parse " + type +
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            " time, unsupported precision for seconds value");
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                len -= precision;
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            second = 0;
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (month == 0 || day == 0
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            || month > 12 || day > 31
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            || hour >= 24 || minute >= 60 || second >= 60)
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Parse " + type + " time, invalid format");
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Generalized time can theoretically allow any precision,
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * but we're not supporting that.
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CalendarSystem gcal = CalendarSystem.getGregorianCalendar();
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CalendarDate date = gcal.newCalendarDate(null); // no time zone
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        date.setDate(year, month, day);
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        date.setTimeOfDay(hour, minute, second, millis);
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        long time = gcal.getTime(date);
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (! (len == 1 || len == 5))
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Parse " + type + " time, invalid offset");
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int hr, min;
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        switch (buf[pos++]) {
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case '+':
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr = 10 * Character.digit((char)buf[pos++], 10);
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr += Character.digit((char)buf[pos++], 10);
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min = 10 * Character.digit((char)buf[pos++], 10);
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min += Character.digit((char)buf[pos++], 10);
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (hr >= 24 || min >= 60)
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Parse " + type + " time, +hhmm");
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            time -= ((hr * 60) + min) * 60 * 1000;
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case '-':
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr = 10 * Character.digit((char)buf[pos++], 10);
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr += Character.digit((char)buf[pos++], 10);
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min = 10 * Character.digit((char)buf[pos++], 10);
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min += Character.digit((char)buf[pos++], 10);
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (hr >= 24 || min >= 60)
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Parse " + type + " time, -hhmm");
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            time += ((hr * 60) + min) * 60 * 1000;
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case 'Z':
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        default:
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Parse " + type + " time, garbage offset");
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new Date(time);
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
434