PrivateInputStream.java revision 9439a7fe517b858bc5e5c654b459315e4722feb2
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.*;
36
37/**
38 * This object provides an input stream to the Operation objects used in this
39 * package.
40 *
41 * OPTIMIZATION: Include the other read() methods defined in InputStream.
42 *
43 * @version 0.3 November 28, 2008
44 */
45public class PrivateInputStream extends InputStream {
46
47    private BaseStream parent;
48
49    private byte[] data;
50
51    private int index;
52
53    private boolean isOpen;
54
55    public PrivateInputStream() {
56
57    }
58
59    /**
60     * Creates an input stream for the <code>Operation</code> to read from
61     *
62     * @param p the connection this input stream is for
63     */
64    public PrivateInputStream(BaseStream p) {
65        parent = p;
66        data = new byte[0];
67        index = 0;
68        isOpen = true;
69    }
70
71    /**
72     * Returns the number of bytes that can be read (or skipped over) from this
73     * input stream without blocking by the next caller of a method for this
74     * input stream. The next caller might be the same thread or or another
75     * thread.
76     *
77     * @return the number of bytes that can be read from this input stream
78     * without blocking
79     *
80     * @exception IOException if an I/O error occurs
81     */
82    @Override
83    public synchronized int available() throws IOException {
84        ensureOpen();
85        return data.length - index;
86    }
87
88    /**
89     * Reads the next byte of data from the input stream. The value byte is
90     * returned as an int in the range 0 to 255. If no byte is available
91     * because the end of the stream has been reached, the value -1 is
92     * returned. This method blocks until input data is available, the end of
93     * the stream is detected, or an exception is thrown.
94     *
95     * @return the byte read from the input stream or -1 if it reaches the end
96     * of stream
97     *
98     * @exception IOException if an I/O error occurs
99     */
100    @Override
101    public synchronized int read() throws IOException {
102        ensureOpen();
103        while (data.length == index) {
104            if (!parent.continueOperation(true, true)) {
105                return -1;
106            }
107        }
108        return (data[index++] & 0xFF);
109    }
110
111    @Override
112    public int read(byte[] b) throws IOException {
113        return read(b, 0, b.length);
114    }
115
116    @Override
117    public synchronized int read(byte[] b, int offset, int length) throws IOException {
118
119        if (b == null) {
120            throw new NullPointerException("buffer is null");
121        }
122        if ((offset | length) < 0 || length > b.length - offset) {
123            throw new ArrayIndexOutOfBoundsException("index outof bound");
124        }
125        ensureOpen();
126
127        int currentDataLength = data.length - index;
128        int remainReadLength = length;
129        int offset1 = offset;
130        int result = 0;
131
132        while (currentDataLength <= remainReadLength) {
133            System.arraycopy(data, index, b, offset1, currentDataLength);
134            index += currentDataLength;
135            offset1 += currentDataLength;
136            result += currentDataLength;
137            remainReadLength -= currentDataLength;
138
139            if (!parent.continueOperation(true, true)) {
140                return result == 0 ? -1 : result;
141            }
142            currentDataLength = data.length - index;
143        }
144        if (remainReadLength > 0) {
145            System.arraycopy(data, index, b, offset1, remainReadLength);
146            index += remainReadLength;
147            result += remainReadLength;
148        }
149        return result;
150    }
151
152    /**
153     * Allows the <code>OperationImpl</code> thread to add body data to the
154     * input stream.
155     *
156     * @param body the data to add to the stream
157     *
158     * @param start the start of the body to array to copy
159     */
160    public synchronized void writeBytes(byte[] body, int start) {
161
162        int length = (body.length - start) + (data.length - index);
163        byte[] temp = new byte[length];
164
165        System.arraycopy(data, index, temp, 0, data.length - index);
166        System.arraycopy(body, start, temp, data.length - index, body.length - start);
167
168        data = temp;
169        index = 0;
170        notifyAll();
171    }
172
173    /**
174     * Verifies that this stream is open
175     *
176     * @exception IOException if the stream is not open
177     */
178    private void ensureOpen() throws IOException {
179        parent.ensureOpen();
180        if (!isOpen) {
181            throw new IOException("Input stream is closed");
182        }
183    }
184
185    /**
186     * Closes the input stream.  If the input stream is already closed, do
187     * nothing.
188     *
189     * @exception IOException this will never happen
190     */
191    @Override
192    public void close() throws IOException {
193        isOpen = false;
194        parent.streamClosed(true);
195    }
196}
197