1/*
2 * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.ssl;
27
28import java.io.*;
29import java.nio.*;
30
31/**
32 * A simple InputStream which uses ByteBuffers as it's backing store.
33 * <P>
34 * The only IOException should come if the InputStream has been closed.
35 * All other IOException should not occur because all the data is local.
36 * Data reads on an exhausted ByteBuffer returns a -1.
37 *
38 * @author  Brad Wetmore
39 */
40class ByteBufferInputStream extends InputStream {
41
42    ByteBuffer bb;
43
44    ByteBufferInputStream(ByteBuffer bb) {
45        this.bb = bb;
46    }
47
48    /**
49     * Returns a byte from the ByteBuffer.
50     *
51     * Increments position().
52     */
53    public int read() throws IOException {
54
55        if (bb == null) {
56            throw new IOException("read on a closed InputStream");
57        }
58
59        if (bb.remaining() == 0) {
60            return -1;
61        }
62        return bb.get();
63    }
64
65    /**
66     * Returns a byte array from the ByteBuffer.
67     *
68     * Increments position().
69     */
70    public int read(byte b[]) throws IOException {
71
72        if (bb == null) {
73            throw new IOException("read on a closed InputStream");
74        }
75
76        return read(b, 0, b.length);
77    }
78
79    /**
80     * Returns a byte array from the ByteBuffer.
81     *
82     * Increments position().
83     */
84    public int read(byte b[], int off, int len) throws IOException {
85
86        if (bb == null) {
87            throw new IOException("read on a closed InputStream");
88        }
89
90        if (b == null) {
91            throw new NullPointerException();
92        } else if (off < 0 || len < 0 || len > b.length - off) {
93            throw new IndexOutOfBoundsException();
94        } else if (len == 0) {
95            return 0;
96        }
97
98        int length = Math.min(bb.remaining(), len);
99        if (length == 0) {
100            return -1;
101        }
102
103        bb.get(b, off, length);
104        return length;
105    }
106
107    /**
108     * Skips over and discards <code>n</code> bytes of data from this input
109     * stream.
110     */
111    public long skip(long n) throws IOException {
112
113        if (bb == null) {
114            throw new IOException("skip on a closed InputStream");
115        }
116
117        if (n <= 0) {
118            return 0;
119        }
120
121        /*
122         * ByteBuffers have at most an int, so lose the upper bits.
123         * The contract allows this.
124         */
125        int nInt = (int) n;
126        int skip = Math.min(bb.remaining(), nInt);
127
128        bb.position(bb.position() + skip);
129
130        return nInt;
131    }
132
133    /**
134     * Returns the number of bytes that can be read (or skipped over)
135     * from this input stream without blocking by the next caller of a
136     * method for this input stream.
137     */
138    public int available() throws IOException {
139
140        if (bb == null) {
141            throw new IOException("available on a closed InputStream");
142        }
143
144        return bb.remaining();
145    }
146
147    /**
148     * Closes this input stream and releases any system resources associated
149     * with the stream.
150     *
151     * @exception  IOException  if an I/O error occurs.
152     */
153    public void close() throws IOException {
154        bb = null;
155    }
156
157    /**
158     * Marks the current position in this input stream.
159     */
160    public synchronized void mark(int readlimit) {}
161
162    /**
163     * Repositions this stream to the position at the time the
164     * <code>mark</code> method was last called on this input stream.
165     */
166    public synchronized void reset() throws IOException {
167        throw new IOException("mark/reset not supported");
168    }
169
170    /**
171     * Tests if this input stream supports the <code>mark</code> and
172     * <code>reset</code> methods.
173     */
174    public boolean markSupported() {
175        return false;
176    }
177}
178