PrivateInputStream.java revision 2e0da96e757a977154063f980d3f4e1abd41cf09
1/*
2 * Copyright (c) 2008-2009, Motorola, Inc.
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * - Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * - Neither the name of the Motorola, Inc. nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package javax.obex;
34
35import java.io.InputStream;
36import java.io.IOException;
37
38/**
39 * This object provides an input stream to the Operation objects used in this
40 * package.
41 *
42 * OPTIMIZATION: Include the other read() methods defined in InputStream.
43 *
44 * @hide
45 */
46public class PrivateInputStream extends InputStream {
47
48    private BaseStream parent;
49
50    private byte[] data;
51
52    private int index;
53
54    private boolean isOpen;
55
56    public PrivateInputStream() {
57
58    }
59
60    /**
61     * Creates an input stream for the <code>Operation</code> to read from
62     *
63     * @param p the connection this input stream is for
64     */
65    public PrivateInputStream(BaseStream p) {
66        parent = p;
67        data = new byte[0];
68        index = 0;
69        isOpen = true;
70    }
71
72    /**
73     * Returns the number of bytes that can be read (or skipped over) from this
74     * input stream without blocking by the next caller of a method for this
75     * input stream. The next caller might be the same thread or or another
76     * thread.
77     *
78     * @return the number of bytes that can be read from this input stream
79     * without blocking
80     *
81     * @throws IOException if an I/O error occurs
82     */
83    @Override
84    public synchronized int available() throws IOException {
85        ensureOpen();
86        return data.length - index;
87    }
88
89    /**
90     * Reads the next byte of data from the input stream. The value byte is
91     * returned as an int in the range 0 to 255. If no byte is available
92     * because the end of the stream has been reached, the value -1 is
93     * returned. This method blocks until input data is available, the end of
94     * the stream is detected, or an exception is thrown.
95     *
96     * @return the byte read from the input stream or -1 if it reaches the end
97     * of stream
98     *
99     * @throws IOException if an I/O error occurs
100     */
101    @Override
102    public synchronized int read() throws IOException {
103        ensureOpen();
104        while (data.length == index) {
105            if (!parent.continueOperation(true, true)) {
106                return -1;
107            }
108        }
109        return (data[index++] & 0xFF);
110    }
111
112    @Override
113    public int read(byte[] b) throws IOException {
114        return read(b, 0, b.length);
115    }
116
117    @Override
118    public synchronized int read(byte[] b, int offset, int length) throws IOException {
119
120        if (b == null) {
121            throw new NullPointerException("buffer is null");
122        }
123        if ((offset | length) < 0 || length > b.length - offset) {
124            throw new ArrayIndexOutOfBoundsException("index outof bound");
125        }
126        ensureOpen();
127
128        int currentDataLength = data.length - index;
129        int remainReadLength = length;
130        int offset1 = offset;
131        int result = 0;
132
133        while (currentDataLength <= remainReadLength) {
134            System.arraycopy(data, index, b, offset1, currentDataLength);
135            index += currentDataLength;
136            offset1 += currentDataLength;
137            result += currentDataLength;
138            remainReadLength -= currentDataLength;
139
140            if (!parent.continueOperation(true, true)) {
141                return result == 0 ? -1 : result;
142            }
143            currentDataLength = data.length - index;
144        }
145        if (remainReadLength > 0) {
146            System.arraycopy(data, index, b, offset1, remainReadLength);
147            index += remainReadLength;
148            result += remainReadLength;
149        }
150        return result;
151    }
152
153    /**
154     * Allows the <code>OperationImpl</code> thread to add body data to the
155     * input stream.
156     *
157     * @param body the data to add to the stream
158     *
159     * @param start the start of the body to array to copy
160     */
161    public synchronized void writeBytes(byte[] body, int start) {
162
163        int length = (body.length - start) + (data.length - index);
164        byte[] temp = new byte[length];
165
166        System.arraycopy(data, index, temp, 0, data.length - index);
167        System.arraycopy(body, start, temp, data.length - index, body.length - start);
168
169        data = temp;
170        index = 0;
171        notifyAll();
172    }
173
174    /**
175     * Verifies that this stream is open
176     *
177     * @throws IOException if the stream is not open
178     */
179    private void ensureOpen() throws IOException {
180        parent.ensureOpen();
181        if (!isOpen) {
182            throw new IOException("Input stream is closed");
183        }
184    }
185
186    /**
187     * Closes the input stream.  If the input stream is already closed, do
188     * nothing.
189     *
190     * @throws IOException this will never happen
191     */
192    @Override
193    public void close() throws IOException {
194        isOpen = false;
195        parent.streamClosed(true);
196    }
197}
198