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