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.IOException; |
| 36 | import java.io.OutputStream; |
| 37 | import java.io.ByteArrayOutputStream; |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 38 | |
| 39 | /** |
| 40 | * This object provides an output stream to the Operation objects used in this |
| 41 | * package. |
Nick Pelly | 2e0da96 | 2009-06-30 16:28:54 -0700 | [diff] [blame] | 42 | * @hide |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 43 | */ |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 44 | public final class PrivateOutputStream extends OutputStream { |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 45 | |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 46 | private BaseStream mParent; |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 47 | |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 48 | private ByteArrayOutputStream mArray; |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 49 | |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 50 | private boolean mOpen; |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 51 | |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 52 | private int mMaxPacketSize; |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 53 | |
| 54 | /** |
| 55 | * Creates an empty <code>PrivateOutputStream</code> to write to. |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 56 | * @param p the connection that this stream runs over |
| 57 | */ |
| 58 | public PrivateOutputStream(BaseStream p, int maxSize) { |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 59 | mParent = p; |
| 60 | mArray = new ByteArrayOutputStream(); |
| 61 | mMaxPacketSize = maxSize; |
Tao Liejun | 05ff98bb | 2009-07-13 15:57:11 -0700 | [diff] [blame] | 62 | mOpen = true; |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | /** |
| 66 | * Determines how many bytes have been written to the output stream. |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 67 | * @return the number of bytes written to the output stream |
| 68 | */ |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 69 | public int size() { |
| 70 | return mArray.size(); |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | /** |
Tao Liejun | 05ff98bb | 2009-07-13 15:57:11 -0700 | [diff] [blame] | 74 | * Writes the specified byte to this output stream. The general contract for |
| 75 | * write is that one byte is written to the output stream. The byte to be |
| 76 | * written is the eight low-order bits of the argument b. The 24 high-order |
| 77 | * bits of b are ignored. |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 78 | * @param b the byte to write |
Nick Pelly | 2e0da96 | 2009-06-30 16:28:54 -0700 | [diff] [blame] | 79 | * @throws IOException if an I/O error occurs |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 80 | */ |
| 81 | @Override |
| 82 | public synchronized void write(int b) throws IOException { |
| 83 | ensureOpen(); |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 84 | mParent.ensureNotDone(); |
| 85 | mArray.write(b); |
| 86 | if (mArray.size() == mMaxPacketSize) { |
| 87 | mParent.continueOperation(true, false); |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 88 | } |
| 89 | } |
| 90 | |
| 91 | @Override |
| 92 | public void write(byte[] buffer) throws IOException { |
| 93 | write(buffer, 0, buffer.length); |
| 94 | } |
| 95 | |
| 96 | @Override |
| 97 | public synchronized void write(byte[] buffer, int offset, int count) throws IOException { |
| 98 | int offset1 = offset; |
| 99 | int remainLength = count; |
| 100 | |
| 101 | if (buffer == null) { |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 102 | throw new IOException("buffer is null"); |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 103 | } |
| 104 | if ((offset | count) < 0 || count > buffer.length - offset) { |
| 105 | throw new IndexOutOfBoundsException("index outof bound"); |
| 106 | } |
| 107 | |
| 108 | ensureOpen(); |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 109 | mParent.ensureNotDone(); |
Erik Ljungberg | a9c4c59 | 2011-05-20 12:39:18 +0200 | [diff] [blame] | 110 | while ((mArray.size() + remainLength) >= mMaxPacketSize) { |
| 111 | int bufferLeft = mMaxPacketSize - mArray.size(); |
| 112 | mArray.write(buffer, offset1, bufferLeft); |
| 113 | offset1 += bufferLeft; |
| 114 | remainLength -= bufferLeft; |
| 115 | mParent.continueOperation(true, false); |
| 116 | } |
| 117 | if (remainLength > 0) { |
| 118 | mArray.write(buffer, offset1, remainLength); |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 119 | } |
| 120 | } |
| 121 | |
| 122 | /** |
| 123 | * Reads the bytes that have been written to this stream. |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 124 | * @param size the size of the array to return |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 125 | * @return the byte array that is written |
| 126 | */ |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 127 | public synchronized byte[] readBytes(int size) { |
| 128 | if (mArray.size() > 0) { |
| 129 | byte[] temp = mArray.toByteArray(); |
| 130 | mArray.reset(); |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 131 | byte[] result = new byte[size]; |
| 132 | System.arraycopy(temp, 0, result, 0, size); |
| 133 | if (temp.length != size) { |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 134 | mArray.write(temp, size, temp.length - size); |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 135 | } |
| 136 | return result; |
| 137 | } else { |
| 138 | return null; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * Verifies that this stream is open |
Nick Pelly | 2e0da96 | 2009-06-30 16:28:54 -0700 | [diff] [blame] | 144 | * @throws IOException if the stream is not open |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 145 | */ |
| 146 | private void ensureOpen() throws IOException { |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 147 | mParent.ensureOpen(); |
| 148 | if (!mOpen) { |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 149 | throw new IOException("Output stream is closed"); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | /** |
Tao Liejun | 05ff98bb | 2009-07-13 15:57:11 -0700 | [diff] [blame] | 154 | * Closes the output stream. If the input stream is already closed, do |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 155 | * nothing. |
Nick Pelly | 2e0da96 | 2009-06-30 16:28:54 -0700 | [diff] [blame] | 156 | * @throws IOException this will never happen |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 157 | */ |
| 158 | @Override |
| 159 | public void close() throws IOException { |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 160 | mOpen = false; |
| 161 | mParent.streamClosed(false); |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | /** |
| 165 | * Determines if the connection is closed |
Tao Liejun | 05ff98bb | 2009-07-13 15:57:11 -0700 | [diff] [blame] | 166 | * @return <code>true</code> if the connection is closed; <code>false</code> |
| 167 | * if the connection is open |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 168 | */ |
Tao Liejun | 3998bf0 | 2009-07-02 19:29:09 +0800 | [diff] [blame] | 169 | public boolean isClosed() { |
| 170 | return !mOpen; |
Nick Pelly | 9439a7f | 2009-06-30 12:04:36 -0700 | [diff] [blame] | 171 | } |
| 172 | } |