1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * @(#)UUEncoderStream.java 1.3 02/03/27 28 */ 29 30 31 32 package com.sun.xml.internal.messaging.saaj.packaging.mime.util; 33 34 import java.io.*; 35 36 /** 37 * This class implements a UUEncoder. It is implemented as 38 * a FilterOutputStream, so one can just wrap this class around 39 * any output stream and write bytes into this filter. The Encoding 40 * is done as the bytes are written out. 41 * 42 * @author John Mani 43 */ 44 45 public class UUEncoderStream extends FilterOutputStream { 46 private byte[] buffer; // cache of bytes that are yet to be encoded 47 private int bufsize = 0; // size of the cache 48 private boolean wrotePrefix = false; 49 50 protected String name; // name of file 51 protected int mode; // permissions mode 52 53 /** 54 * Create a UUencoder that encodes the specified input stream 55 * @param out the output stream 56 */ 57 public UUEncoderStream(OutputStream out) { 58 this(out, "encoder.buf", 644); 59 } 60 61 /** 62 * Create a UUencoder that encodes the specified input stream 63 * @param out the output stream 64 * @param name Specifies a name for the encoded buffer 65 */ 66 public UUEncoderStream(OutputStream out, String name) { 67 this(out, name, 644); 68 } 69 70 /** 71 * Create a UUencoder that encodes the specified input stream 72 * @param out the output stream 73 * @param name Specifies a name for the encoded buffer 74 * @param mode Specifies permission mode for the encoded buffer 75 */ 76 public UUEncoderStream(OutputStream out, String name, int mode) { 77 super(out); 78 this.name = name; 79 this.mode = mode; 80 buffer = new byte[45]; 81 } 82 83 /** 84 * Set up the buffer name and permission mode. 85 * This method has any effect only if it is invoked before 86 * you start writing into the output stream 87 */ 88 public void setNameMode(String name, int mode) { 89 this.name = name; 90 this.mode = mode; 91 } 92 93 public void write(byte[] b, int off, int len) throws IOException { 94 for (int i = 0; i < len; i++) 95 write(b[off + i]); 96 } 97 98 public void write(byte[] data) throws IOException { 99 write(data, 0, data.length); 100 } 101 102 public void write(int c) throws IOException { 103 /* buffer up characters till we get a line's worth, then encode 104 * and write them out. Max number of characters allowed per 105 * line is 45. 106 */ 107 buffer[bufsize++] = (byte)c; 108 if (bufsize == 45) { 109 writePrefix(); 110 encode(); 111 bufsize = 0; 112 } 113 } 114 115 public void flush() throws IOException { 116 if (bufsize > 0) { // If there's unencoded characters in the buffer 117 writePrefix(); 118 encode(); // .. encode them 119 } 120 writeSuffix(); 121 out.flush(); 122 } 123 124 public void close() throws IOException { 125 flush(); 126 out.close(); 127 } 128 129 /** 130 * Write out the prefix: "begin <mode> <name>" 131 */ 132 private void writePrefix() throws IOException { 133 if (!wrotePrefix) { 134 PrintStream ps = new PrintStream(out); 135 ps.println("begin " + mode + " " + name); 136 ps.flush(); 137 wrotePrefix = true; 138 } 139 } 140 141 /** 142 * Write a single line containing space and the suffix line 143 * containing the single word "end" (terminated by a newline) 144 */ 145 private void writeSuffix() throws IOException { 146 PrintStream ps = new PrintStream(out); 147 ps.println(" \nend"); 148 ps.flush(); 149 } 150 151 /** 152 * Encode a line. 153 * Start off with the character count, followed by the encoded atoms 154 * and terminate with LF. (or is it CRLF or the local line-terminator ?) 155 * Take three bytes and encodes them into 4 characters 156 * If bufsize if not a multiple of 3, the remaining bytes are filled 157 * with '1'. This insures that the last line won't end in spaces 158 * and potentiallly be truncated. 159 */ 160 private void encode() throws IOException { 161 byte a, b, c; 162 int c1, c2, c3, c4; 163 int i = 0; 164 165 // Start off with the count of characters in the line 166 out.write((bufsize & 0x3f) + ' '); 167 168 while (i < bufsize) { 169 a = buffer[i++]; 170 if (i < bufsize) { 171 b = buffer[i++]; 172 if (i < bufsize) 173 c = buffer[i++]; 174 else // default c to 1 175 c = 1; 176 } 177 else { // default b & c to 1 178 b = 1; 179 c = 1; 180 } 181 182 c1 = (a >>> 2) & 0x3f; 183 c2 = ((a << 4) & 0x30) | ((b >>> 4) & 0xf); 184 c3 = ((b << 2) & 0x3c) | ((c >>> 6) & 0x3); 185 c4 = c & 0x3f; 186 out.write(c1 + ' '); 187 out.write(c2 + ' '); 188 out.write(c3 + ' '); 189 out.write(c4 + ' '); 190 } 191 // Terminate with LF. (should it be CRLF or local line-terminator ?) 192 out.write('\n'); 193 } 194 195 /**** begin TEST program ***** 196 public static void main(String argv[]) throws Exception { 197 FileInputStream infile = new FileInputStream(argv[0]); 198 UUEncoderStream encoder = new UUEncoderStream(System.out); 199 int c; 200 201 while ((c = infile.read()) != -1) 202 encoder.write(c); 203 encoder.close(); 204 } 205 **** end TEST program *****/ 206 }