001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.codec.binary; 019 020 import java.io.FilterOutputStream; 021 import java.io.IOException; 022 import java.io.OutputStream; 023 024 /** 025 * Abstract superclass for Base-N output streams. 026 * 027 * @since 1.5 028 */ 029 public class BaseNCodecOutputStream extends FilterOutputStream { 030 031 private final boolean doEncode; 032 033 private final BaseNCodec baseNCodec; 034 035 private final byte[] singleByte = new byte[1]; 036 037 public BaseNCodecOutputStream(OutputStream out, BaseNCodec basedCodec, boolean doEncode) { 038 super(out); 039 this.baseNCodec = basedCodec; 040 this.doEncode = doEncode; 041 } 042 043 /** 044 * Writes the specified <code>byte</code> to this output stream. 045 * 046 * @param i 047 * source byte 048 * @throws IOException 049 * if an I/O error occurs. 050 */ 051 public void write(int i) throws IOException { 052 singleByte[0] = (byte) i; 053 write(singleByte, 0, 1); 054 } 055 056 /** 057 * Writes <code>len</code> bytes from the specified <code>b</code> array starting at <code>offset</code> to this 058 * output stream. 059 * 060 * @param b 061 * source byte array 062 * @param offset 063 * where to start reading the bytes 064 * @param len 065 * maximum number of bytes to write 066 * 067 * @throws IOException 068 * if an I/O error occurs. 069 * @throws NullPointerException 070 * if the byte array parameter is null 071 * @throws IndexOutOfBoundsException 072 * if offset, len or buffer size are invalid 073 */ 074 public void write(byte b[], int offset, int len) throws IOException { 075 if (b == null) { 076 throw new NullPointerException(); 077 } else if (offset < 0 || len < 0) { 078 throw new IndexOutOfBoundsException(); 079 } else if (offset > b.length || offset + len > b.length) { 080 throw new IndexOutOfBoundsException(); 081 } else if (len > 0) { 082 if (doEncode) { 083 baseNCodec.encode(b, offset, len); 084 } else { 085 baseNCodec.decode(b, offset, len); 086 } 087 flush(false); 088 } 089 } 090 091 /** 092 * Flushes this output stream and forces any buffered output bytes to be written out to the stream. If propogate is 093 * true, the wrapped stream will also be flushed. 094 * 095 * @param propogate 096 * boolean flag to indicate whether the wrapped OutputStream should also be flushed. 097 * @throws IOException 098 * if an I/O error occurs. 099 */ 100 private void flush(boolean propogate) throws IOException { 101 int avail = baseNCodec.available(); 102 if (avail > 0) { 103 byte[] buf = new byte[avail]; 104 int c = baseNCodec.readResults(buf, 0, avail); 105 if (c > 0) { 106 out.write(buf, 0, c); 107 } 108 } 109 if (propogate) { 110 out.flush(); 111 } 112 } 113 114 /** 115 * Flushes this output stream and forces any buffered output bytes to be written out to the stream. 116 * 117 * @throws IOException 118 * if an I/O error occurs. 119 */ 120 public void flush() throws IOException { 121 flush(true); 122 } 123 124 /** 125 * Closes this output stream and releases any system resources associated with the stream. 126 * 127 * @throws IOException 128 * if an I/O error occurs. 129 */ 130 public void close() throws IOException { 131 // Notify encoder of EOF (-1). 132 if (doEncode) { 133 baseNCodec.encode(singleByte, 0, -1); 134 } else { 135 baseNCodec.decode(singleByte, 0, -1); 136 } 137 flush(); 138 out.close(); 139 } 140 141 }