001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.util;
020:
021: import java.io.IOException;
022: import java.io.OutputStream;
023: import java.io.PrintStream;
024:
025: /**
026: * This class implements a Base64 Character encoder as specified in RFC1113.
027: * Unlike some other encoding schemes there is nothing in this encoding
028: * that indicates where a buffer starts or ends.
029: *
030: * This means that the encoded text will simply start with the first line
031: * of encoded text and end with the last line of encoded text.
032: *
033: * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
034: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
035: * @author Chuck McManis
036: * @version $Id: Base64EncoderStream.java 501495 2007-01-30 18:00:36Z dvholten $
037: */
038: public class Base64EncoderStream extends OutputStream {
039:
040: /** This array maps the 6 bit values to their characters */
041: private static final byte[] pem_array = {
042: // 0 1 2 3 4 5 6 7
043: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0
044: 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
045: 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
046: 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
047: 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
048: 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
049: 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
050: '4', '5', '6', '7', '8', '9', '+', '/' // 7
051: };
052:
053: byte[] atom = new byte[3];
054: int atomLen = 0;
055: byte[] encodeBuf = new byte[4];
056: int lineLen = 0;
057:
058: PrintStream out;
059: boolean closeOutOnClose;
060:
061: public Base64EncoderStream(OutputStream out) {
062: this .out = new PrintStream(out);
063: closeOutOnClose = true;
064: }
065:
066: public Base64EncoderStream(OutputStream out, boolean closeOutOnClose) {
067: this .out = new PrintStream(out);
068: this .closeOutOnClose = closeOutOnClose;
069: }
070:
071: public void close() throws IOException {
072: if (out != null) {
073: encodeAtom();
074: out.flush();
075: if (closeOutOnClose)
076: out.close();
077: out = null;
078: }
079: }
080:
081: /**
082: * This can't really flush out output since that may generate
083: * '=' chars which would indicate the end of the stream.
084: * Instead we flush out. You can only be sure all output is
085: * writen by closing this stream.
086: */
087: public void flush() throws IOException {
088: out.flush();
089: }
090:
091: public void write(int b) throws IOException {
092: atom[atomLen++] = (byte) b;
093: if (atomLen == 3)
094: encodeAtom();
095: }
096:
097: public void write(byte[] data) throws IOException {
098: encodeFromArray(data, 0, data.length);
099: }
100:
101: public void write(byte[] data, int off, int len) throws IOException {
102: encodeFromArray(data, off, len);
103: }
104:
105: /**
106: * enocodeAtom - Take three bytes of input and encode it as 4
107: * printable characters. Note that if the length in len is less
108: * than three is encodes either one or two '=' signs to indicate
109: * padding characters.
110: */
111: void encodeAtom() throws IOException {
112: byte a, b, c;
113:
114: switch (atomLen) {
115: case 0:
116: return;
117: case 1:
118: a = atom[0];
119: encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
120: encodeBuf[1] = pem_array[((a << 4) & 0x30)];
121: encodeBuf[2] = encodeBuf[3] = '=';
122: break;
123: case 2:
124: a = atom[0];
125: b = atom[1];
126: encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
127: encodeBuf[1] = pem_array[(((a << 4) & 0x30) | ((b >>> 4) & 0x0F))];
128: encodeBuf[2] = pem_array[((b << 2) & 0x3C)];
129: encodeBuf[3] = '=';
130: break;
131: default:
132: a = atom[0];
133: b = atom[1];
134: c = atom[2];
135: encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
136: encodeBuf[1] = pem_array[(((a << 4) & 0x30) | ((b >>> 4) & 0x0F))];
137: encodeBuf[2] = pem_array[(((b << 2) & 0x3C) | ((c >>> 6) & 0x03))];
138: encodeBuf[3] = pem_array[c & 0x3F];
139: }
140: if (lineLen == 64) {
141: out.println();
142: lineLen = 0;
143: }
144: out.write(encodeBuf);
145:
146: lineLen += 4;
147: atomLen = 0;
148: }
149:
150: /**
151: * enocodeAtom - Take three bytes of input and encode it as 4
152: * printable characters. Note that if the length in len is less
153: * than three is encodes either one or two '=' signs to indicate
154: * padding characters.
155: */
156: void encodeFromArray(byte[] data, int offset, int len)
157: throws IOException {
158: byte a, b, c;
159: if (len == 0)
160: return;
161:
162: // System.out.println("atomLen: " + atomLen +
163: // " len: " + len +
164: // " offset: " + offset);
165:
166: if (atomLen != 0) {
167: switch (atomLen) {
168: case 1:
169: atom[1] = data[offset++];
170: len--;
171: atomLen++;
172: if (len == 0)
173: return;
174: atom[2] = data[offset++];
175: len--;
176: atomLen++;
177: break;
178: case 2:
179: atom[2] = data[offset++];
180: len--;
181: atomLen++;
182: break;
183: default:
184: }
185: encodeAtom();
186: }
187:
188: while (len >= 3) {
189: a = data[offset++];
190: b = data[offset++];
191: c = data[offset++];
192:
193: encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
194: encodeBuf[1] = pem_array[(((a << 4) & 0x30) | ((b >>> 4) & 0x0F))];
195: encodeBuf[2] = pem_array[(((b << 2) & 0x3C) | ((c >>> 6) & 0x03))];
196: encodeBuf[3] = pem_array[c & 0x3F];
197: out.write(encodeBuf);
198:
199: lineLen += 4;
200: if (lineLen == 64) {
201: out.println();
202: lineLen = 0;
203: }
204:
205: len -= 3;
206: }
207:
208: switch (len) {
209: case 1:
210: atom[0] = data[offset];
211: break;
212: case 2:
213: atom[0] = data[offset];
214: atom[1] = data[offset + 1];
215: break;
216: default:
217: }
218: atomLen = len;
219: }
220:
221: }
|