xref: /aosp_15_r20/external/obex/src/com/android/obex/PrivateOutputStream.java (revision ff33b0cc4d4457a0bf8b25e5c2b4726ad6df5d1d)
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