Clover coverage report - Maven Clover report
Coverage timestamp: Sun Aug 20 2006 04:01:04 PDT
file stats: LOC: 201   Methods: 13
NCLOC: 93   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
UUEncoderStream.java 50% 84.4% 69.2% 75.7%
coverage coverage
 1    /**
 2    *
 3    * Copyright 2003-2004 The Apache Software Foundation
 4    *
 5    * Licensed under the Apache License, Version 2.0 (the "License");
 6    * you may not use this file except in compliance with the License.
 7    * You may obtain a copy of the License at
 8    *
 9    * http://www.apache.org/licenses/LICENSE-2.0
 10    *
 11    * Unless required by applicable law or agreed to in writing, software
 12    * distributed under the License is distributed on an "AS IS" BASIS,
 13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14    * See the License for the specific language governing permissions and
 15    * limitations under the License.
 16    */
 17   
 18    package org.apache.geronimo.mail.util;
 19   
 20    import java.io.FilterOutputStream;
 21    import java.io.IOException;
 22    import java.io.OutputStream;
 23    import java.io.PrintStream;
 24   
 25    /**
 26    * An implementation of a FilterOutputStream that encodes the
 27    * stream data in UUencoding format. This version does the
 28    * encoding "on the fly" rather than encoding a single block of
 29    * data. Since this version is intended for use by the MimeUtilty class,
 30    * it also handles line breaks in the encoded data.
 31    */
 32    public class UUEncoderStream extends FilterOutputStream {
 33   
 34    // default values included on the "begin" prefix of the data stream.
 35    protected static final int DEFAULT_MODE = 644;
 36    protected static final String DEFAULT_NAME = "encoder.buf";
 37   
 38    protected static final int MAX_CHARS_PER_LINE = 45;
 39   
 40    // the configured name on the "begin" command.
 41    protected String name;
 42    // the configured mode for the "begin" command.
 43    protected int mode;
 44   
 45    // since this is a filtering stream, we need to wait until we have the first byte written for encoding
 46    // to write out the "begin" marker. A real pain, but necessary.
 47    protected boolean beginWritten = false;
 48   
 49   
 50    // our encoder utility class.
 51    protected UUEncoder encoder = new UUEncoder();
 52   
 53    // Data is generally written out in 45 character lines, so we're going to buffer that amount before
 54    // asking the encoder to process this.
 55   
 56    // the buffered byte count
 57    protected int bufferedBytes = 0;
 58   
 59    // we'll encode this part once it is filled up.
 60    protected byte[] buffer = new byte[45];
 61   
 62    /**
 63    * Create a Base64 encoder stream that wraps a specifed stream
 64    * using the default line break size.
 65    *
 66    * @param out The wrapped output stream.
 67    */
 68  5 public UUEncoderStream(OutputStream out) {
 69  5 this(out, DEFAULT_NAME, DEFAULT_MODE);
 70    }
 71   
 72   
 73    /**
 74    * Create a Base64 encoder stream that wraps a specifed stream
 75    * using the default line break size.
 76    *
 77    * @param out The wrapped output stream.
 78    * @param name The filename placed on the "begin" command.
 79    */
 80  0 public UUEncoderStream(OutputStream out, String name) {
 81  0 this(out, name, DEFAULT_MODE);
 82    }
 83   
 84   
 85  5 public UUEncoderStream(OutputStream out, String name, int mode) {
 86  5 super(out);
 87    // fill in the name and mode information.
 88  5 this.name = name;
 89  5 this.mode = mode;
 90    }
 91   
 92   
 93  10 private void checkBegin() throws IOException {
 94  10 if (!beginWritten) {
 95    // grumble...OutputStream doesn't directly support writing String data. We'll wrap this in
 96    // a PrintStream() to accomplish the task of writing the begin command.
 97   
 98  5 PrintStream writer = new PrintStream(out);
 99    // write out the stream with a CRLF marker
 100  5 writer.print("begin " + mode + " " + name + "\r\n");
 101  5 writer.flush();
 102  5 beginWritten = true;
 103    }
 104    }
 105   
 106  5 private void writeEnd() throws IOException {
 107  5 PrintStream writer = new PrintStream(out);
 108    // write out the stream with a CRLF marker
 109  5 writer.print("\nend\r\n");
 110  5 writer.flush();
 111    }
 112   
 113  10 private void flushBuffer() throws IOException {
 114    // make sure we've written the begin marker first
 115  10 checkBegin();
 116    // ask the encoder to encode and write this out.
 117  10 if (bufferedBytes != 0) {
 118  10 encoder.encode(buffer, 0, bufferedBytes, out);
 119    // reset the buffer count
 120  10 bufferedBytes = 0;
 121    }
 122    }
 123   
 124  5 private int bufferSpace() {
 125  5 return MAX_CHARS_PER_LINE - bufferedBytes;
 126    }
 127   
 128  5 private boolean isBufferFull() {
 129  5 return bufferedBytes >= MAX_CHARS_PER_LINE;
 130    }
 131   
 132   
 133    // in order for this to work, we need to override the 3 different signatures for write
 134   
 135  0 public void write(int ch) throws IOException {
 136    // store this in the buffer.
 137  0 buffer[bufferedBytes++] = (byte)ch;
 138   
 139    // if we filled this up, time to encode and write to the output stream.
 140  0 if (isBufferFull()) {
 141  0 flushBuffer();
 142    }
 143    }
 144   
 145  0 public void write(byte [] data) throws IOException {
 146  0 write(data, 0, data.length);
 147    }
 148   
 149  5 public void write(byte [] data, int offset, int length) throws IOException {
 150    // first check to see how much space we have left in the buffer, and copy that over
 151  5 int copyBytes = Math.min(bufferSpace(), length);
 152   
 153  5 System.arraycopy(buffer, bufferedBytes, data, offset, copyBytes);
 154  5 bufferedBytes += copyBytes;
 155  5 offset += copyBytes;
 156  5 length -= copyBytes;
 157   
 158    // if we filled this up, time to encode and write to the output stream.
 159  5 if (isBufferFull()) {
 160  5 flushBuffer();
 161    }
 162   
 163    // we've flushed the leading part up to the line break. Now if we have complete lines
 164    // of data left, we can have the encoder process all of these lines directly.
 165  5 if (length >= MAX_CHARS_PER_LINE) {
 166  5 int fullLinesLength = (length / MAX_CHARS_PER_LINE) * MAX_CHARS_PER_LINE;
 167    // ask the encoder to encode and write this out.
 168  5 encoder.encode(data, offset, fullLinesLength, out);
 169  5 offset += fullLinesLength;
 170  5 length -= fullLinesLength;
 171    }
 172   
 173    // ok, now we're down to a potential trailing bit we need to move into the
 174    // buffer for later processing.
 175   
 176  5 if (length > 0) {
 177  5 System.arraycopy(buffer, 0, data, offset, length);
 178  5 bufferedBytes += length;
 179  5 offset += length;
 180  5 length -= length;
 181    }
 182    }
 183   
 184  5 public void flush() throws IOException {
 185    // flush any unencoded characters we're holding.
 186  5 flushBuffer();
 187    // write out the data end marker
 188  5 writeEnd();
 189    // and flush the output stream too so that this data is available.
 190  5 out.flush();
 191    }
 192   
 193  0 public void close() throws IOException {
 194    // flush all of the streams and close the target output stream.
 195  0 flush();
 196  0 out.close();
 197    }
 198   
 199    }
 200   
 201