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 35 import java.io.InputStream; 36 import java.io.IOException; 37 38 /** 39 * This object provides an input stream to the Operation objects used in this 40 * package. 41 * @hide 42 */ 43 public final class PrivateInputStream extends InputStream { 44 45 private BaseStream mParent; 46 47 private byte[] mData; 48 49 private int mIndex; 50 51 private boolean mOpen; 52 53 /** 54 * Creates an input stream for the <code>Operation</code> to read from 55 * @param p the connection this input stream is for 56 */ 57 public PrivateInputStream(BaseStream p) { 58 mParent = p; 59 mData = new byte[0]; 60 mIndex = 0; 61 mOpen = true; 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. 69 * @return the number of bytes that can be read from this input stream 70 * without blocking 71 * @throws IOException if an I/O error occurs 72 */ 73 @Override 74 public synchronized int available() throws IOException { 75 ensureOpen(); 76 return mData.length - mIndex; 77 } 78 79 /** 80 * Reads the next byte of data from the input stream. The value byte is 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 87 * @throws IOException if an I/O error occurs 88 */ 89 @Override 90 public synchronized int read() throws IOException { 91 ensureOpen(); 92 while (mData.length == mIndex) { 93 if (!mParent.continueOperation(true, true)) { 94 return -1; 95 } 96 } 97 return (mData[mIndex++] & 0xFF); 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) { 109 throw new IOException("buffer is null"); 110 } 111 if ((offset | length) < 0 || length > b.length - offset) { 112 throw new ArrayIndexOutOfBoundsException("index outof bound"); 113 } 114 ensureOpen(); 115 116 int currentDataLength = mData.length - mIndex; 117 int remainReadLength = length; 118 int offset1 = offset; 119 int result = 0; 120 121 while (currentDataLength <= remainReadLength) { 122 System.arraycopy(mData, mIndex, b, offset1, currentDataLength); 123 mIndex += currentDataLength; 124 offset1 += currentDataLength; 125 result += currentDataLength; 126 remainReadLength -= currentDataLength; 127 128 if (!mParent.continueOperation(true, true)) { 129 return result == 0 ? -1 : result; 130 } 131 currentDataLength = mData.length - mIndex; 132 } 133 if (remainReadLength > 0) { 134 System.arraycopy(mData, mIndex, b, offset1, remainReadLength); 135 mIndex += remainReadLength; 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. 144 * @param body the data to add to the stream 145 * @param start the start of the body to array to copy 146 */ 147 public synchronized void writeBytes(byte[] body, int start) { 148 149 int length = (body.length - start) + (mData.length - mIndex); 150 byte[] temp = new byte[length]; 151 152 System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex); 153 System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start); 154 155 mData = temp; 156 mIndex = 0; 157 notifyAll(); 158 } 159 160 /** 161 * Verifies that this stream is open 162 * @throws IOException if the stream is not open 163 */ 164 private void ensureOpen() throws IOException { 165 mParent.ensureOpen(); 166 if (!mOpen) { 167 throw new IOException("Input stream is closed"); 168 } 169 } 170 171 /** 172 * Closes the input stream. If the input stream is already closed, do 173 * nothing. 174 * @throws IOException this will never happen 175 */ 176 @Override 177 public void close() throws IOException { 178 mOpen = false; 179 mParent.streamClosed(true); 180 } 181 } 182