/* * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the Motorola, Inc. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package javax.obex; import java.io.InputStream; import java.io.IOException; /** * This object provides an input stream to the Operation objects used in this * package. * @hide */ public final class PrivateInputStream extends InputStream { private BaseStream mParent; private byte[] mData; private int mIndex; private boolean mOpen; /** * Creates an input stream for the Operation to read from * @param p the connection this input stream is for */ public PrivateInputStream(BaseStream p) { mParent = p; mData = new byte[0]; mIndex = 0; mOpen = true; } /** * Returns the number of bytes that can be read (or skipped over) from this * input stream without blocking by the next caller of a method for this * input stream. The next caller might be the same thread or or another * thread. * @return the number of bytes that can be read from this input stream * without blocking * @throws IOException if an I/O error occurs */ @Override public synchronized int available() throws IOException { ensureOpen(); return mData.length - mIndex; } /** * Reads the next byte of data from the input stream. The value byte is * returned as an int in the range 0 to 255. If no byte is available because * the end of the stream has been reached, the value -1 is returned. This * method blocks until input data is available, the end of the stream is * detected, or an exception is thrown. * @return the byte read from the input stream or -1 if it reaches the end of * stream * @throws IOException if an I/O error occurs */ @Override public synchronized int read() throws IOException { ensureOpen(); while (mData.length == mIndex) { if (!mParent.continueOperation(true, true)) { return -1; } } return (mData[mIndex++] & 0xFF); } @Override public int read(byte[] b) throws IOException { return read(b, 0, b.length); } @Override public synchronized int read(byte[] b, int offset, int length) throws IOException { if (b == null) { throw new IOException("buffer is null"); } if ((offset | length) < 0 || length > b.length - offset) { throw new ArrayIndexOutOfBoundsException("index outof bound"); } ensureOpen(); int currentDataLength = mData.length - mIndex; int remainReadLength = length; int offset1 = offset; int result = 0; while (currentDataLength <= remainReadLength) { System.arraycopy(mData, mIndex, b, offset1, currentDataLength); mIndex += currentDataLength; offset1 += currentDataLength; result += currentDataLength; remainReadLength -= currentDataLength; if (!mParent.continueOperation(true, true)) { return result == 0 ? -1 : result; } currentDataLength = mData.length - mIndex; } if (remainReadLength > 0) { System.arraycopy(mData, mIndex, b, offset1, remainReadLength); mIndex += remainReadLength; result += remainReadLength; } return result; } /** * Allows the OperationImpl thread to add body data to the * input stream. * @param body the data to add to the stream * @param start the start of the body to array to copy */ public synchronized void writeBytes(byte[] body, int start) { int length = (body.length - start) + (mData.length - mIndex); byte[] temp = new byte[length]; System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex); System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start); mData = temp; mIndex = 0; notifyAll(); } /** * Verifies that this stream is open * @throws IOException if the stream is not open */ private void ensureOpen() throws IOException { mParent.ensureOpen(); if (!mOpen) { throw new IOException("Input stream is closed"); } } /** * Closes the input stream. If the input stream is already closed, do * nothing. * @throws IOException this will never happen */ @Override public void close() throws IOException { mOpen = false; mParent.streamClosed(true); } }