-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package be.nikiroo.utils.streams;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * An OutputStream that does Base64 encoding on the data written to
- * it, writing the resulting data to another OutputStream.
- */
-public class Base64OutputStream extends FilterOutputStream {
- private final Base64.Coder coder;
- private final int flags;
-
- private byte[] buffer = null;
- private int bpos = 0;
-
- private static byte[] EMPTY = new byte[0];
-
- /**
- * Performs Base64 encoding on the data written to the stream,
- * writing the encoded data to another OutputStream.
- *
- * @param out the OutputStream to write the encoded data to
- */
- public Base64OutputStream(OutputStream out) {
- this(out, true);
- }
-
- /**
- * Performs Base64 encoding or decoding on the data written to the
- * stream, writing the encoded/decoded data to another
- * OutputStream.
- *
- * @param out the OutputStream to write the encoded data to
- * @param encode true to encode, false to decode
- *
- * @hide
- */
- public Base64OutputStream(OutputStream out, boolean encode) {
- super(out);
- this.flags = Base64.NO_WRAP;
- if (encode) {
- coder = new Base64.Encoder(flags, null);
- } else {
- coder = new Base64.Decoder(flags, null);
- }
- }
-
- public void write(int b) throws IOException {
- // To avoid invoking the encoder/decoder routines for single
- // bytes, we buffer up calls to write(int) in an internal
- // byte array to transform them into writes of decently-sized
- // arrays.
-
- if (buffer == null) {
- buffer = new byte[1024];
- }
- if (bpos >= buffer.length) {
- // internal buffer full; write it out.
- internalWrite(buffer, 0, bpos, false);
- bpos = 0;
- }
- buffer[bpos++] = (byte) b;
- }
-
- /**
- * Flush any buffered data from calls to write(int). Needed
- * before doing a write(byte[], int, int) or a close().
- */
- private void flushBuffer() throws IOException {
- if (bpos > 0) {
- internalWrite(buffer, 0, bpos, false);
- bpos = 0;
- }
- }
-
- public void write(byte[] b, int off, int len) throws IOException {
- if (len <= 0) return;
- flushBuffer();
- internalWrite(b, off, len, false);
- }
-
- public void close() throws IOException {
- IOException thrown = null;
- try {
- flushBuffer();
- internalWrite(EMPTY, 0, 0, true);
- } catch (IOException e) {
- thrown = e;
- }
-
- try {
- if ((flags & Base64.NO_CLOSE) == 0) {
- out.close();
- } else {
- out.flush();
- }
- } catch (IOException e) {
- if (thrown != null) {
- thrown = e;
- }
- }
-
- if (thrown != null) {
- throw thrown;
- }
- }
-
- /**
- * Write the given bytes to the encoder/decoder.
- *
- * @param finish true if this is the last batch of input, to cause
- * encoder/decoder state to be finalized.
- */
- private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
- coder.output = embiggen(coder.output, coder.maxOutputSize(len));
- if (!coder.process(b, off, len, finish)) {
- throw new IOException("bad base-64");
- }
- out.write(coder.output, 0, coder.op);
- }
-
- /**
- * If b.length is at least len, return b. Otherwise return a new
- * byte array of length len.
- */
- private byte[] embiggen(byte[] b, int len) {
- if (b == null || b.length < len) {
- return new byte[len];
- } else {
- return b;
- }
- }
-}