Base64OutputStream.java revision d2affae13dfdb116adaee1bb10aaaac80a885481
1d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/*
2d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Copyright (C) 2010 The Android Open Source Project
3d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *
4d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Licensed under the Apache License, Version 2.0 (the "License");
5d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * you may not use this file except in compliance with the License.
6d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * You may obtain a copy of the License at
7d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *
8d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *      http://www.apache.org/licenses/LICENSE-2.0
9d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *
10d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Unless required by applicable law or agreed to in writing, software
11d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * distributed under the License is distributed on an "AS IS" BASIS,
12d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * See the License for the specific language governing permissions and
14d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * limitations under the License.
15d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */
16d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
17d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerpackage android.util.base64;
18d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
19d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.FilterOutputStream;
20d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.IOException;
21d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerimport java.io.OutputStream;
22d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
23d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/**
24d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * An OutputStream that does either Base64 encoding or decoding on the
25d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * data written to it, writing the resulting data to another
26d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * OutputStream.
27d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */
28d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerpublic class Base64OutputStream extends FilterOutputStream {
29d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private final boolean encode;
30d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private final Base64.EncoderState estate;
31d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private final Base64.DecoderState dstate;
32d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private final int flags;
33d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
34d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private byte[] buffer = null;
35d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private int bpos = 0;
36d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
37d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private static byte[] EMPTY = new byte[0];
38d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
39d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
40d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Performs Base64 encoding on the data written to the stream,
41d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * writing the encoded data to another OutputStream.
42d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
43d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param out the OutputStream to write the encoded data to
44d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags bit flags for controlling the encoder; see the
45d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *        constants in {@link Base64}
46d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
47d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public Base64OutputStream(OutputStream out, int flags) {
48d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        this(out, flags, true);
49d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
50d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
51d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
52d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Performs Base64 encoding or decoding on the data written to the
53d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * stream, writing the encoded/decoded data to another
54d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * OutputStream.
55d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
56d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param out the OutputStream to write the encoded data to
57d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags bit flags for controlling the encoder; see the
58d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *        constants in {@link Base64}
59d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param encode true to encode, false to decode
60d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
61d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public Base64OutputStream(OutputStream out, int flags, boolean encode) {
62d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        super(out);
63d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        this.flags = flags;
64d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        this.encode = encode;
65d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if (encode) {
66d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            estate = new Base64.EncoderState(flags, null);
67d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            dstate = null;
68d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        } else {
69d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            estate = null;
70d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            dstate = new Base64.DecoderState(flags, null);
71d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
72d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
73d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
74d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public void write(int b) throws IOException {
75d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // To avoid invoking the encoder/decoder routines for single
76d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // bytes, we buffer up calls to write(int) in an internal
77d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // byte array to transform them into writes of decently-sized
78d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // arrays.
79d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
80d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if (buffer == null) {
81d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            buffer = new byte[1024];
82d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
83d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if (bpos >= buffer.length) {
84d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            // internal buffer full; write it out.
85d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            internalWrite(buffer, 0, bpos, false);
86d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            bpos = 0;
87d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
88d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        buffer[bpos++] = (byte) b;
89d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
90d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
91d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
92d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Flush any buffered data from calls to write(int).  Needed
93d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * before doing a write(byte[], int, int) or a close().
94d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
95d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private void flushBuffer() throws IOException {
96d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if (bpos > 0) {
97d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            internalWrite(buffer, 0, bpos, false);
98d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            bpos = 0;
99d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
100d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
101d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
102d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public void write(byte[] b, int off, int len) throws IOException {
103d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if (len <= 0) return;
104d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        flushBuffer();
105d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        internalWrite(b, off, len, false);
106d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
107d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
108d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public void close() throws IOException {
109d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        flushBuffer();
110d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        internalWrite(EMPTY, 0, 0, true);
111d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if ((flags & Base64.NO_CLOSE) == 0) {
112d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            out.close();
113d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        } else {
114d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            out.flush();
115d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
116d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
117d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
118d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
119d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Write the given bytes to the encoder/decoder.
120d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
121d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param finish true if this is the last batch of input, to cause
122d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *        encoder/decoder state to be finalized.
123d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
124d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
125d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if (encode) {
126d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            // len*8/5+10 is an overestimate of the most bytes the
127d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            // encoder can produce for len bytes of input.
128d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            estate.output = embiggen(estate.output, len*8/5+10);
129d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            Base64.encodeInternal(b, off, len, estate, finish);
130d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            out.write(estate.output, 0, estate.op);
131d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        } else {
132d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            // len*3/4+10 is an overestimate of the most bytes the
133d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            // decoder can produce for len bytes of input.
134d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            dstate.output = embiggen(dstate.output, len*3/4+10);
135d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            if (!Base64.decodeInternal(b, off, len, dstate, finish)) {
136d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                throw new IOException("bad base-64");
137d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            }
138d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            out.write(dstate.output, 0, dstate.op);
139d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
140d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
141d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
142d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
143d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * If b.length is at least len, return b.  Otherwise return a new
144d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * byte array of length len.
145d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
146d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private byte[] embiggen(byte[] b, int len) {
147d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        if (b == null || b.length < len) {
148d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            return new byte[len];
149d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        } else {
150d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            return b;
151d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
152d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
153d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker}
154