151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
2c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak * Copyright (c) 1996, 2016, 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
74c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak    // BEGIN Android-added: Added getPos & getSlice, needed for APK parsing
75ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    int getPos() {
76ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        return pos;
77ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    }
78ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin
79ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    byte[] getSlice(int startPos, int size) {
80ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        byte[] result = new byte[size];
81ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        System.arraycopy(buf, startPos, result, 0, size);
82ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin        return result;
83ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin    }
84c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak    // END Android-added: Added getPos & getSlice, needed for APK parsing
85ddde3e18b22acdaecb883794f5c8e21f0b87bf2fAlex Klyubin
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    int peek() throws IOException {
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pos >= count)
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("out of data");
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return buf[pos];
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Compares this DerInputBuffer for equality with the specified
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * object.
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean equals(Object other) {
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (other instanceof DerInputBuffer)
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return equals((DerInputBuffer)other);
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return false;
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    boolean equals(DerInputBuffer other) {
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (this == other)
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return true;
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int max = this.available();
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (other.available() != max)
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return false;
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < max; i++) {
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (this.buf[this.pos + i] != other.buf[other.pos + i]) {
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return false;
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return true;
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a hashcode for this DerInputBuffer.
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a hashcode for this DerInputBuffer.
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int hashCode() {
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int retval = 0;
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int len = available();
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int p = pos;
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < len; i++)
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            retval += buf[p + i] * i;
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return retval;
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    void truncate(int len) throws IOException {
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("insufficient data");
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        count = pos + len;
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the integer which takes up the specified number
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of bytes in this buffer as a BigInteger.
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use.
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param makePositive whether to always return a positive value,
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *   irrespective of actual encoding
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer as a BigInteger.
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    BigInteger getBigInteger(int len, boolean makePositive) throws IOException {
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of integer");
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == 0) {
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid encoding: zero length Int value");
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] bytes = new byte[len];
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        System.arraycopy(buf, pos, bytes, 0, len);
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        skip(len);
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
162c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak        // check to make sure no extra leading 0s for DER
163c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak        if (len >= 2 && (bytes[0] == 0) && (bytes[1] >= 0)) {
164c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak            throw new IOException("Invalid encoding: redundant leading 0s");
165c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak        }
166c96ac066cc6335ac107e79a3b40175a3d741263ePrzemyslaw Szczepaniak
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (makePositive) {
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new BigInteger(1, bytes);
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new BigInteger(bytes);
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the integer which takes up the specified number
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of bytes in this buffer.
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IOException if the result is not within the valid
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range for integer, i.e. between Integer.MIN_VALUE and
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Integer.MAX_VALUE.
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use.
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the integer.
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getInteger(int len) throws IOException {
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        BigInteger result = getBigInteger(len, false);
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (result.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) {
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Integer below minimum valid value");
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (result.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Integer exceeds maximum valid value");
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return result.intValue();
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the bit string which takes up the specified
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * number of bytes in this buffer.
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public byte[] getBitString(int len) throws IOException {
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of bit string");
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == 0) {
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid encoding: zero length bit string");
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int numOfPadBits = buf[pos];
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((numOfPadBits < 0) || (numOfPadBits > 7)) {
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid number of padding bits");
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // minus the first byte which indicates the number of padding bits
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] retval = new byte[len - 1];
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        System.arraycopy(buf, pos + 1, retval, 0, len - 1);
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (numOfPadBits != 0) {
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // get rid of the padding bits
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            retval[len - 2] &= (0xff << numOfPadBits);
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        skip(len);
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return retval;
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the bit string which takes up the rest of this buffer.
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    byte[] getBitString() throws IOException {
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getBitString(available());
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the bit string which takes up the rest of this buffer.
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The bit string need not be byte-aligned.
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    BitArray getUnalignedBitString() throws IOException {
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pos >= count)
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Just copy the data into an aligned, padded octet buffer,
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * and consume the rest of the buffer.
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int len = available();
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int unusedBits = buf[pos] & 0xff;
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (unusedBits > 7 ) {
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Invalid value for unused bits: " + unusedBits);
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        byte[] bits = new byte[len - 1];
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // number of valid bits
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int length = (bits.length == 0) ? 0 : bits.length * 8 - unusedBits;
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        System.arraycopy(buf, pos + 1, bits, 0, len - 1);
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        BitArray bitArray = new BitArray(length, bits);
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        pos = count;
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return bitArray;
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the UTC Time value that takes up the specified number
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of bytes in this buffer.
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Date getUTCTime(int len) throws IOException {
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER UTC Time");
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len < 11 || len > 17)
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER UTC Time length error");
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getTime(len, false);
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the Generalized Time value that takes up the specified
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * number of bytes in this buffer.
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Date getGeneralizedTime(int len) throws IOException {
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > available())
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("short read of DER Generalized Time");
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len < 13 || len > 23)
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("DER Generalized Time length error");
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getTime(len, true);
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Private helper routine to extract time from the der value.
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param len the number of bytes to use
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param generalized true if Generalized Time is to be read, false
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * if UTC Time is to be read.
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Date getTime(int len, boolean generalized) throws IOException {
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * UTC time encoded as ASCII chars:
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmZ
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmssZ
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmm+hhmm
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmm-hhmm
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmss+hhmm
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *       YYMMDDhhmmss-hhmm
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * UTC Time is broken in storing only two digits of year.
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * If YY < 50, we assume 20YY;
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * if YY >= 50, we assume 19YY, as per RFC 3280.
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         *
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Generalized time has a four-digit year and allows any
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * precision specified in ISO 8601. However, for our purposes,
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * we will only allow the same format as UTC time, except that
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * fractional seconds (millisecond precision) are supported.
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int year, month, day, hour, minute, second, millis;
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String type = null;
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (generalized) {
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            type = "Generalized";
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year = 1000 * Character.digit((char)buf[pos++], 10);
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += 100 * Character.digit((char)buf[pos++], 10);
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += 10 * Character.digit((char)buf[pos++], 10);
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += Character.digit((char)buf[pos++], 10);
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            len -= 2; // For the two extra YY
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            type = "UTC";
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year = 10 * Character.digit((char)buf[pos++], 10);
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            year += Character.digit((char)buf[pos++], 10);
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (year < 50)              // origin 2000
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                year += 2000;
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            else
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                year += 1900;   // origin 1900
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        month = 10 * Character.digit((char)buf[pos++], 10);
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        month += Character.digit((char)buf[pos++], 10);
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        day = 10 * Character.digit((char)buf[pos++], 10);
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        day += Character.digit((char)buf[pos++], 10);
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hour = 10 * Character.digit((char)buf[pos++], 10);
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hour += Character.digit((char)buf[pos++], 10);
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        minute = 10 * Character.digit((char)buf[pos++], 10);
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        minute += Character.digit((char)buf[pos++], 10);
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        len -= 10; // YYMMDDhhmm
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * We allow for non-encoded seconds, even though the
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * IETF-PKIX specification says that the seconds should
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * always be encoded even if it is zero.
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        millis = 0;
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len > 2 && len < 12) {
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            second = 10 * Character.digit((char)buf[pos++], 10);
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            second += Character.digit((char)buf[pos++], 10);
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            len -= 2;
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // handle fractional seconds (if present)
36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (buf[pos] == '.' || buf[pos] == ',') {
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                len --;
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                pos++;
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // handle upto milisecond precision only
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int precision = 0;
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int peek = pos;
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                while (buf[peek] != 'Z' &&
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                       buf[peek] != '+' &&
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                       buf[peek] != '-') {
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    peek++;
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    precision++;
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                switch (precision) {
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                case 3:
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 100 * Character.digit((char)buf[pos++], 10);
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 10 * Character.digit((char)buf[pos++], 10);
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += Character.digit((char)buf[pos++], 10);
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                case 2:
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 100 * Character.digit((char)buf[pos++], 10);
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 10 * Character.digit((char)buf[pos++], 10);
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                case 1:
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    millis += 100 * Character.digit((char)buf[pos++], 10);
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                default:
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        throw new IOException("Parse " + type +
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            " time, unsupported precision for seconds value");
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                len -= precision;
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            second = 0;
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (month == 0 || day == 0
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            || month > 12 || day > 31
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            || hour >= 24 || minute >= 60 || second >= 60)
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Parse " + type + " time, invalid format");
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Generalized time can theoretically allow any precision,
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * but we're not supporting that.
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CalendarSystem gcal = CalendarSystem.getGregorianCalendar();
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CalendarDate date = gcal.newCalendarDate(null); // no time zone
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        date.setDate(year, month, day);
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        date.setTimeOfDay(hour, minute, second, millis);
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        long time = gcal.getTime(date);
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /*
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (! (len == 1 || len == 5))
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Parse " + type + " time, invalid offset");
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int hr, min;
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        switch (buf[pos++]) {
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case '+':
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr = 10 * Character.digit((char)buf[pos++], 10);
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr += Character.digit((char)buf[pos++], 10);
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min = 10 * Character.digit((char)buf[pos++], 10);
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min += Character.digit((char)buf[pos++], 10);
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (hr >= 24 || min >= 60)
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Parse " + type + " time, +hhmm");
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            time -= ((hr * 60) + min) * 60 * 1000;
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case '-':
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr = 10 * Character.digit((char)buf[pos++], 10);
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hr += Character.digit((char)buf[pos++], 10);
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min = 10 * Character.digit((char)buf[pos++], 10);
43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            min += Character.digit((char)buf[pos++], 10);
43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (hr >= 24 || min >= 60)
43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Parse " + type + " time, -hhmm");
43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            time += ((hr * 60) + min) * 60 * 1000;
44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case 'Z':
44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        default:
44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Parse " + type + " time, garbage offset");
44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new Date(time);
44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
451