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.IOException;
362e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.OutputStream;
372e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.ByteArrayOutputStream;
389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/**
409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * This object provides an output stream to the Operation objects used in this
419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * package.
422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide
439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
443998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunpublic final class PrivateOutputStream extends OutputStream {
459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
463998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private BaseStream mParent;
479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private ByteArrayOutputStream mArray;
499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
503998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mOpen;
519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private int mMaxPacketSize;
539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates an empty <code>PrivateOutputStream</code> to write to.
569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param p the connection that this stream runs over
579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public PrivateOutputStream(BaseStream p, int maxSize) {
593998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent = p;
603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mArray = new ByteArrayOutputStream();
613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mMaxPacketSize = maxSize;
6205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun        mOpen = true;
639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Determines how many bytes have been written to the output stream.
679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the number of bytes written to the output stream
689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
693998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public int size() {
703998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return mArray.size();
719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Writes the specified byte to this output stream. The general contract for
7505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * write is that one byte is written to the output stream. The byte to be
7605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * written is the eight low-order bits of the argument b. The 24 high-order
7705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * bits of b are ignored.
789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param b the byte to write
792e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an I/O error occurs
809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized void write(int b) throws IOException {
839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent.ensureNotDone();
853998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mArray.write(b);
863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mArray.size() == mMaxPacketSize) {
873998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mParent.continueOperation(true, false);
889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void write(byte[] buffer) throws IOException {
939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        write(buffer, 0, buffer.length);
949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized void write(byte[] buffer, int offset, int count) throws IOException {
989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int offset1 = offset;
999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int remainLength = count;
1009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (buffer == null) {
1023998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            throw new IOException("buffer is null");
1039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((offset | count) < 0 || count > buffer.length - offset) {
1059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IndexOutOfBoundsException("index outof bound");
1069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
1093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent.ensureNotDone();
110a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg        while ((mArray.size() + remainLength) >= mMaxPacketSize) {
111a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg            int bufferLeft = mMaxPacketSize - mArray.size();
112a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg            mArray.write(buffer, offset1, bufferLeft);
113a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg            offset1 += bufferLeft;
114a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg            remainLength -= bufferLeft;
115a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg            mParent.continueOperation(true, false);
116a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg        }
117a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg        if (remainLength > 0) {
118a9c4c594ef29e097be8be0537657fa8d9529502eErik Ljungberg            mArray.write(buffer, offset1, remainLength);
1199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Reads the bytes that have been written to this stream.
1249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param size the size of the array to return
1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the byte array that is written
1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1273998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public synchronized byte[] readBytes(int size) {
1283998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mArray.size() > 0) {
1293998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            byte[] temp = mArray.toByteArray();
1303998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mArray.reset();
1319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            byte[] result = new byte[size];
1329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(temp, 0, result, 0, size);
1339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (temp.length != size) {
1343998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                mArray.write(temp, size, temp.length - size);
1359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
1369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return result;
1379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
1389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
1399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Verifies that this stream is open
1442e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if the stream is not open
1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void ensureOpen() throws IOException {
1473998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent.ensureOpen();
1483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (!mOpen) {
1499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IOException("Output stream is closed");
1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
15405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Closes the output stream. If the input stream is already closed, do
1559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * nothing.
1562e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException this will never happen
1579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
1599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void close() throws IOException {
1603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOpen = false;
1613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent.streamClosed(false);
1629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Determines if the connection is closed
16605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @return <code>true</code> if the connection is closed; <code>false</code>
16705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         if the connection is open
1689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1693998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public boolean isClosed() {
1703998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return !mOpen;
1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly}
173