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