1*ff33b0ccSKyunglyul Hyun /* 2*ff33b0ccSKyunglyul Hyun * Copyright (c) 2008-2009, Motorola, Inc. 3*ff33b0ccSKyunglyul Hyun * 4*ff33b0ccSKyunglyul Hyun * All rights reserved. 5*ff33b0ccSKyunglyul Hyun * 6*ff33b0ccSKyunglyul Hyun * Redistribution and use in source and binary forms, with or without 7*ff33b0ccSKyunglyul Hyun * modification, are permitted provided that the following conditions are met: 8*ff33b0ccSKyunglyul Hyun * 9*ff33b0ccSKyunglyul Hyun * - Redistributions of source code must retain the above copyright notice, 10*ff33b0ccSKyunglyul Hyun * this list of conditions and the following disclaimer. 11*ff33b0ccSKyunglyul Hyun * 12*ff33b0ccSKyunglyul Hyun * - Redistributions in binary form must reproduce the above copyright notice, 13*ff33b0ccSKyunglyul Hyun * this list of conditions and the following disclaimer in the documentation 14*ff33b0ccSKyunglyul Hyun * and/or other materials provided with the distribution. 15*ff33b0ccSKyunglyul Hyun * 16*ff33b0ccSKyunglyul Hyun * - Neither the name of the Motorola, Inc. nor the names of its contributors 17*ff33b0ccSKyunglyul Hyun * may be used to endorse or promote products derived from this software 18*ff33b0ccSKyunglyul Hyun * without specific prior written permission. 19*ff33b0ccSKyunglyul Hyun * 20*ff33b0ccSKyunglyul Hyun * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21*ff33b0ccSKyunglyul Hyun * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*ff33b0ccSKyunglyul Hyun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*ff33b0ccSKyunglyul Hyun * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24*ff33b0ccSKyunglyul Hyun * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25*ff33b0ccSKyunglyul Hyun * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26*ff33b0ccSKyunglyul Hyun * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27*ff33b0ccSKyunglyul Hyun * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28*ff33b0ccSKyunglyul Hyun * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29*ff33b0ccSKyunglyul Hyun * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30*ff33b0ccSKyunglyul Hyun * POSSIBILITY OF SUCH DAMAGE. 31*ff33b0ccSKyunglyul Hyun */ 32*ff33b0ccSKyunglyul Hyun 33*ff33b0ccSKyunglyul Hyun package com.android.obex; 34*ff33b0ccSKyunglyul Hyun 35*ff33b0ccSKyunglyul Hyun import java.io.ByteArrayOutputStream; 36*ff33b0ccSKyunglyul Hyun import java.io.IOException; 37*ff33b0ccSKyunglyul Hyun import java.io.OutputStream; 38*ff33b0ccSKyunglyul Hyun 39*ff33b0ccSKyunglyul Hyun /** 40*ff33b0ccSKyunglyul Hyun * This object provides an output stream to the Operation objects used in this 41*ff33b0ccSKyunglyul Hyun * package. 42*ff33b0ccSKyunglyul Hyun */ 43*ff33b0ccSKyunglyul Hyun public final class PrivateOutputStream extends OutputStream { 44*ff33b0ccSKyunglyul Hyun 45*ff33b0ccSKyunglyul Hyun private BaseStream mParent; 46*ff33b0ccSKyunglyul Hyun 47*ff33b0ccSKyunglyul Hyun private ByteArrayOutputStream mArray; 48*ff33b0ccSKyunglyul Hyun 49*ff33b0ccSKyunglyul Hyun private boolean mOpen; 50*ff33b0ccSKyunglyul Hyun 51*ff33b0ccSKyunglyul Hyun private int mMaxPacketSize; 52*ff33b0ccSKyunglyul Hyun 53*ff33b0ccSKyunglyul Hyun /** 54*ff33b0ccSKyunglyul Hyun * Creates an empty <code>PrivateOutputStream</code> to write to. 55*ff33b0ccSKyunglyul Hyun * @param p the connection that this stream runs over 56*ff33b0ccSKyunglyul Hyun */ PrivateOutputStream(BaseStream p, int maxSize)57*ff33b0ccSKyunglyul Hyun public PrivateOutputStream(BaseStream p, int maxSize) { 58*ff33b0ccSKyunglyul Hyun mParent = p; 59*ff33b0ccSKyunglyul Hyun mArray = new ByteArrayOutputStream(); 60*ff33b0ccSKyunglyul Hyun mMaxPacketSize = maxSize; 61*ff33b0ccSKyunglyul Hyun mOpen = true; 62*ff33b0ccSKyunglyul Hyun } 63*ff33b0ccSKyunglyul Hyun 64*ff33b0ccSKyunglyul Hyun /** 65*ff33b0ccSKyunglyul Hyun * Determines how many bytes have been written to the output stream. 66*ff33b0ccSKyunglyul Hyun * @return the number of bytes written to the output stream 67*ff33b0ccSKyunglyul Hyun */ size()68*ff33b0ccSKyunglyul Hyun public int size() { 69*ff33b0ccSKyunglyul Hyun return mArray.size(); 70*ff33b0ccSKyunglyul Hyun } 71*ff33b0ccSKyunglyul Hyun 72*ff33b0ccSKyunglyul Hyun /** 73*ff33b0ccSKyunglyul Hyun * Writes the specified byte to this output stream. The general contract for 74*ff33b0ccSKyunglyul Hyun * write is that one byte is written to the output stream. The byte to be 75*ff33b0ccSKyunglyul Hyun * written is the eight low-order bits of the argument b. The 24 high-order 76*ff33b0ccSKyunglyul Hyun * bits of b are ignored. 77*ff33b0ccSKyunglyul Hyun * @param b the byte to write 78*ff33b0ccSKyunglyul Hyun * @throws IOException if an I/O error occurs 79*ff33b0ccSKyunglyul Hyun */ 80*ff33b0ccSKyunglyul Hyun @Override write(int b)81*ff33b0ccSKyunglyul Hyun public synchronized void write(int b) throws IOException { 82*ff33b0ccSKyunglyul Hyun ensureOpen(); 83*ff33b0ccSKyunglyul Hyun mParent.ensureNotDone(); 84*ff33b0ccSKyunglyul Hyun mArray.write(b); 85*ff33b0ccSKyunglyul Hyun if (mArray.size() == mMaxPacketSize) { 86*ff33b0ccSKyunglyul Hyun mParent.continueOperation(true, false); 87*ff33b0ccSKyunglyul Hyun } 88*ff33b0ccSKyunglyul Hyun } 89*ff33b0ccSKyunglyul Hyun 90*ff33b0ccSKyunglyul Hyun @Override write(byte[] buffer)91*ff33b0ccSKyunglyul Hyun public void write(byte[] buffer) throws IOException { 92*ff33b0ccSKyunglyul Hyun write(buffer, 0, buffer.length); 93*ff33b0ccSKyunglyul Hyun } 94*ff33b0ccSKyunglyul Hyun 95*ff33b0ccSKyunglyul Hyun @Override write(byte[] buffer, int offset, int count)96*ff33b0ccSKyunglyul Hyun public synchronized void write(byte[] buffer, int offset, int count) throws IOException { 97*ff33b0ccSKyunglyul Hyun int offset1 = offset; 98*ff33b0ccSKyunglyul Hyun int remainLength = count; 99*ff33b0ccSKyunglyul Hyun 100*ff33b0ccSKyunglyul Hyun if (buffer == null) { 101*ff33b0ccSKyunglyul Hyun throw new IOException("buffer is null"); 102*ff33b0ccSKyunglyul Hyun } 103*ff33b0ccSKyunglyul Hyun if ((offset | count) < 0 || count > buffer.length - offset) { 104*ff33b0ccSKyunglyul Hyun throw new IndexOutOfBoundsException("index outof bound"); 105*ff33b0ccSKyunglyul Hyun } 106*ff33b0ccSKyunglyul Hyun 107*ff33b0ccSKyunglyul Hyun ensureOpen(); 108*ff33b0ccSKyunglyul Hyun mParent.ensureNotDone(); 109*ff33b0ccSKyunglyul Hyun while ((mArray.size() + remainLength) >= mMaxPacketSize) { 110*ff33b0ccSKyunglyul Hyun int bufferLeft = mMaxPacketSize - mArray.size(); 111*ff33b0ccSKyunglyul Hyun mArray.write(buffer, offset1, bufferLeft); 112*ff33b0ccSKyunglyul Hyun offset1 += bufferLeft; 113*ff33b0ccSKyunglyul Hyun remainLength -= bufferLeft; 114*ff33b0ccSKyunglyul Hyun mParent.continueOperation(true, false); 115*ff33b0ccSKyunglyul Hyun } 116*ff33b0ccSKyunglyul Hyun if (remainLength > 0) { 117*ff33b0ccSKyunglyul Hyun mArray.write(buffer, offset1, remainLength); 118*ff33b0ccSKyunglyul Hyun } 119*ff33b0ccSKyunglyul Hyun } 120*ff33b0ccSKyunglyul Hyun 121*ff33b0ccSKyunglyul Hyun /** 122*ff33b0ccSKyunglyul Hyun * Reads the bytes that have been written to this stream. 123*ff33b0ccSKyunglyul Hyun * @param size the size of the array to return 124*ff33b0ccSKyunglyul Hyun * @return the byte array that is written 125*ff33b0ccSKyunglyul Hyun */ readBytes(int size)126*ff33b0ccSKyunglyul Hyun public synchronized byte[] readBytes(int size) { 127*ff33b0ccSKyunglyul Hyun if (mArray.size() > 0) { 128*ff33b0ccSKyunglyul Hyun byte[] temp = mArray.toByteArray(); 129*ff33b0ccSKyunglyul Hyun mArray.reset(); 130*ff33b0ccSKyunglyul Hyun byte[] result = new byte[size]; 131*ff33b0ccSKyunglyul Hyun System.arraycopy(temp, 0, result, 0, size); 132*ff33b0ccSKyunglyul Hyun if (temp.length != size) { 133*ff33b0ccSKyunglyul Hyun mArray.write(temp, size, temp.length - size); 134*ff33b0ccSKyunglyul Hyun } 135*ff33b0ccSKyunglyul Hyun return result; 136*ff33b0ccSKyunglyul Hyun } else { 137*ff33b0ccSKyunglyul Hyun return null; 138*ff33b0ccSKyunglyul Hyun } 139*ff33b0ccSKyunglyul Hyun } 140*ff33b0ccSKyunglyul Hyun 141*ff33b0ccSKyunglyul Hyun /** 142*ff33b0ccSKyunglyul Hyun * Verifies that this stream is open 143*ff33b0ccSKyunglyul Hyun * @throws IOException if the stream is not open 144*ff33b0ccSKyunglyul Hyun */ ensureOpen()145*ff33b0ccSKyunglyul Hyun private void ensureOpen() throws IOException { 146*ff33b0ccSKyunglyul Hyun mParent.ensureOpen(); 147*ff33b0ccSKyunglyul Hyun if (!mOpen) { 148*ff33b0ccSKyunglyul Hyun throw new IOException("Output stream is closed"); 149*ff33b0ccSKyunglyul Hyun } 150*ff33b0ccSKyunglyul Hyun } 151*ff33b0ccSKyunglyul Hyun 152*ff33b0ccSKyunglyul Hyun /** 153*ff33b0ccSKyunglyul Hyun * Closes the output stream. If the input stream is already closed, do 154*ff33b0ccSKyunglyul Hyun * nothing. 155*ff33b0ccSKyunglyul Hyun * @throws IOException this will never happen 156*ff33b0ccSKyunglyul Hyun */ 157*ff33b0ccSKyunglyul Hyun @Override close()158*ff33b0ccSKyunglyul Hyun public void close() throws IOException { 159*ff33b0ccSKyunglyul Hyun mOpen = false; 160*ff33b0ccSKyunglyul Hyun mParent.streamClosed(false); 161*ff33b0ccSKyunglyul Hyun } 162*ff33b0ccSKyunglyul Hyun 163*ff33b0ccSKyunglyul Hyun /** 164*ff33b0ccSKyunglyul Hyun * Determines if the connection is closed 165*ff33b0ccSKyunglyul Hyun * @return <code>true</code> if the connection is closed; <code>false</code> 166*ff33b0ccSKyunglyul Hyun * if the connection is open 167*ff33b0ccSKyunglyul Hyun */ isClosed()168*ff33b0ccSKyunglyul Hyun public boolean isClosed() { 169*ff33b0ccSKyunglyul Hyun return !mOpen; 170*ff33b0ccSKyunglyul Hyun } 171*ff33b0ccSKyunglyul Hyun } 172