19439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/*
29439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc.
39439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
49439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * All rights reserved.
59439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
69439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Redistribution and use in source and binary forms, with or without
79439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * modification, are permitted provided that the following conditions are met:
89439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
99439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions of source code must retain the above copyright notice,
109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer.
119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice,
139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer in the documentation
149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * and/or other materials provided with the distribution.
159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors
179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * may be used to endorse or promote products derived from this software
189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * without specific prior written permission.
199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * POSSIBILITY OF SUCH DAMAGE.
319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypackage javax.obex;
349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
352e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.InputStream;
362e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.IOException;
379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/**
399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * This object provides an input stream to the Operation objects used in this
409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * package.
412e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide
429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
433998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunpublic final class PrivateInputStream extends InputStream {
449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
453998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private BaseStream mParent;
469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
473998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private byte[] mData;
489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
493998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private int mIndex;
509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
513998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mOpen;
529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates an input stream for the <code>Operation</code> to read from
559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param p the connection this input stream is for
569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public PrivateInputStream(BaseStream p) {
583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent = p;
593998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mData = new byte[0];
603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mIndex = 0;
613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOpen = true;
629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Returns the number of bytes that can be read (or skipped over) from this
669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * input stream without blocking by the next caller of a method for this
679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * input stream. The next caller might be the same thread or or another
689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * thread.
699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the number of bytes that can be read from this input stream
7005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         without blocking
712e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an I/O error occurs
729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized int available() throws IOException {
759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
763998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return mData.length - mIndex;
779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Reads the next byte of data from the input stream. The value byte is
8105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * returned as an int in the range 0 to 255. If no byte is available because
8205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * the end of the stream has been reached, the value -1 is returned. This
8305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * method blocks until input data is available, the end of the stream is
8405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * detected, or an exception is thrown.
8505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @return the byte read from the input stream or -1 if it reaches the end of
8605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         stream
872e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an I/O error occurs
889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized int read() throws IOException {
919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
923998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        while (mData.length == mIndex) {
933998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (!mParent.continueOperation(true, true)) {
949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return -1;
959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
973998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return (mData[mIndex++] & 0xFF);
989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
1019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public int read(byte[] b) throws IOException {
1029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return read(b, 0, b.length);
1039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
1069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized int read(byte[] b, int offset, int length) throws IOException {
1079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (b == null) {
1093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            throw new IOException("buffer is null");
1109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((offset | length) < 0 || length > b.length - offset) {
1129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new ArrayIndexOutOfBoundsException("index outof bound");
1139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
1159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        int currentDataLength = mData.length - mIndex;
1179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int remainReadLength = length;
1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int offset1 = offset;
1199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int result = 0;
1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        while (currentDataLength <= remainReadLength) {
1223998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            System.arraycopy(mData, mIndex, b, offset1, currentDataLength);
1233998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mIndex += currentDataLength;
1249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            offset1 += currentDataLength;
1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result += currentDataLength;
1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            remainReadLength -= currentDataLength;
1279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1283998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (!mParent.continueOperation(true, true)) {
1299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return result == 0 ? -1 : result;
1309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
1313998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            currentDataLength = mData.length - mIndex;
1329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (remainReadLength > 0) {
1343998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            System.arraycopy(mData, mIndex, b, offset1, remainReadLength);
1353998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mIndex += remainReadLength;
1369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result += remainReadLength;
1379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
1399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Allows the <code>OperationImpl</code> thread to add body data to the
1439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * input stream.
1449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param body the data to add to the stream
1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param start the start of the body to array to copy
1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized void writeBytes(byte[] body, int start) {
1489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1493998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        int length = (body.length - start) + (mData.length - mIndex);
1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] temp = new byte[length];
1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex);
1533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start);
1549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1553998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mData = temp;
1563998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mIndex = 0;
1579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        notifyAll();
1589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Verifies that this stream is open
1622e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if the stream is not open
1639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void ensureOpen() throws IOException {
1653998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent.ensureOpen();
1663998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (!mOpen) {
1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IOException("Input stream is closed");
1689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
17205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Closes the input stream. If the input stream is already closed, do
1739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * nothing.
1742e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException this will never happen
1759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
1779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void close() throws IOException {
1783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOpen = false;
1793998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent.streamClosed(true);
1809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly}
182