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