001: // Base64Encoder.java
002: // $Id: Base64Encoder.java,v 1.9 2002/07/31 00:00:26 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1996.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.tools.codec;
007:
008: import java.io.ByteArrayInputStream;
009: import java.io.ByteArrayOutputStream;
010: import java.io.IOException;
011: import java.io.InputStream;
012: import java.io.OutputStream;
013: import java.io.PrintStream;
014: import java.io.UnsupportedEncodingException;
015:
016: /**
017: * BASE64 encoder implementation.
018: * This object takes as parameter an input stream and an output stream. It
019: * encodes the input stream, using the BASE64 encoding rules, as defined
020: * in <a href="http://ds.internic.net/rfc/rfc1521.txt">MIME specification</a>
021: * and emit the resulting data to the output stream.
022: * @see org.w3c.tools.codec.Base64Decoder
023: */
024:
025: public class Base64Encoder {
026: private static final int BUFFER_SIZE = 1024;
027: private static byte encoding[] = {
028: (byte) 'A',
029: (byte) 'B',
030: (byte) 'C',
031: (byte) 'D',
032: (byte) 'E',
033: (byte) 'F',
034: (byte) 'G',
035: (byte) 'H', // 0-7
036: (byte) 'I',
037: (byte) 'J',
038: (byte) 'K',
039: (byte) 'L',
040: (byte) 'M',
041: (byte) 'N',
042: (byte) 'O',
043: (byte) 'P', // 8-15
044: (byte) 'Q', (byte) 'R',
045: (byte) 'S',
046: (byte) 'T',
047: (byte) 'U',
048: (byte) 'V',
049: (byte) 'W',
050: (byte) 'X', // 16-23
051: (byte) 'Y', (byte) 'Z', (byte) 'a',
052: (byte) 'b',
053: (byte) 'c',
054: (byte) 'd',
055: (byte) 'e',
056: (byte) 'f', // 24-31
057: (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j',
058: (byte) 'k',
059: (byte) 'l',
060: (byte) 'm',
061: (byte) 'n', // 32-39
062: (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's',
063: (byte) 't',
064: (byte) 'u',
065: (byte) 'v', // 40-47
066: (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0',
067: (byte) '1', (byte) '2',
068: (byte) '3', // 48-55
069: (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8',
070: (byte) '9', (byte) '+', (byte) '/', // 56-63
071: (byte) '=' // 64
072: };
073:
074: InputStream in = null;
075: OutputStream out = null;
076: boolean stringp = false;
077:
078: private final int get1(byte buf[], int off) {
079: return (buf[off] & 0xfc) >> 2;
080: }
081:
082: private final int get2(byte buf[], int off) {
083: return ((buf[off] & 0x3) << 4) | ((buf[off + 1] & 0xf0) >>> 4);
084: }
085:
086: private final int get3(byte buf[], int off) {
087: return ((buf[off + 1] & 0x0f) << 2)
088: | ((buf[off + 2] & 0xc0) >>> 6);
089: }
090:
091: private static final int get4(byte buf[], int off) {
092: return buf[off + 2] & 0x3f;
093: }
094:
095: /**
096: * Process the data: encode the input stream to the output stream.
097: * This method runs through the input stream, encoding it to the output
098: * stream.
099: * @exception IOException If we weren't able to access the input stream or
100: * the output stream.
101: */
102:
103: public void process() throws IOException {
104: byte buffer[] = new byte[BUFFER_SIZE];
105: int got = -1;
106: int off = 0;
107: int count = 0;
108: while ((got = in.read(buffer, off, BUFFER_SIZE - off)) > 0) {
109: if ((got + off) >= 3) {
110: got += off;
111: off = 0;
112: while (off + 3 <= got) {
113: int c1 = get1(buffer, off);
114: int c2 = get2(buffer, off);
115: int c3 = get3(buffer, off);
116: int c4 = get4(buffer, off);
117: switch (count) {
118: case 73:
119: out.write(encoding[c1]);
120: out.write(encoding[c2]);
121: out.write(encoding[c3]);
122: out.write('\n');
123: out.write(encoding[c4]);
124: count = 1;
125: break;
126: case 74:
127: out.write(encoding[c1]);
128: out.write(encoding[c2]);
129: out.write('\n');
130: out.write(encoding[c3]);
131: out.write(encoding[c4]);
132: count = 2;
133: break;
134: case 75:
135: out.write(encoding[c1]);
136: out.write('\n');
137: out.write(encoding[c2]);
138: out.write(encoding[c3]);
139: out.write(encoding[c4]);
140: count = 3;
141: break;
142: case 76:
143: out.write('\n');
144: out.write(encoding[c1]);
145: out.write(encoding[c2]);
146: out.write(encoding[c3]);
147: out.write(encoding[c4]);
148: count = 4;
149: break;
150: default:
151: out.write(encoding[c1]);
152: out.write(encoding[c2]);
153: out.write(encoding[c3]);
154: out.write(encoding[c4]);
155: count += 4;
156: break;
157: }
158: off += 3;
159: }
160: // Copy remaining bytes to beginning of buffer:
161: for (int i = 0; i < 3; i++)
162: buffer[i] = (i < got - off) ? buffer[off + i]
163: : ((byte) 0);
164: off = got - off;
165: } else {
166: // Total read amount is less then 3 bytes:
167: off += got;
168: }
169: }
170: // Manage the last bytes, from 0 to off:
171: switch (off) {
172: case 1:
173: out.write(encoding[get1(buffer, 0)]);
174: out.write(encoding[get2(buffer, 0)]);
175: out.write('=');
176: out.write('=');
177: break;
178: case 2:
179: out.write(encoding[get1(buffer, 0)]);
180: out.write(encoding[get2(buffer, 0)]);
181: out.write(encoding[get3(buffer, 0)]);
182: out.write('=');
183: }
184: return;
185: }
186:
187: /**
188: * Encode the content of this encoder, as a string.
189: * This methods encode the String content, that was provided at creation
190: * time, following the BASE64 rules, as specified in the rfc1521.
191: * @return A String, reprenting the encoded content of the input String.
192: */
193:
194: public String processString() {
195: if (!stringp)
196: throw new RuntimeException(this .getClass().getName()
197: + "[processString]" + "invalid call (not a String)");
198: try {
199: process();
200: } catch (IOException e) {
201: }
202: return ((ByteArrayOutputStream) out).toString();
203: }
204:
205: /**
206: * Create a new Base64 encoder, to encode the given string.
207: * @param input The String to be encoded.
208: */
209:
210: public Base64Encoder(String input) {
211: byte bytes[];
212: try {
213: bytes = input.getBytes("ISO-8859-1");
214: } catch (UnsupportedEncodingException ex) {
215: throw new RuntimeException(this .getClass().getName()
216: + "[Constructor] Unable to convert"
217: + "properly char to bytes");
218: }
219: this .stringp = true;
220: this .in = new ByteArrayInputStream(bytes);
221: this .out = new ByteArrayOutputStream();
222: }
223:
224: /**
225: * Create a new Base64 encoder, encoding input to output.
226: * @param in The input stream to be encoded.
227: * @param out The output stream, to write encoded data to.
228: */
229:
230: public Base64Encoder(InputStream in, OutputStream out) {
231: this .in = in;
232: this .out = out;
233: this .stringp = false;
234: }
235:
236: /**
237: * Testing the encoder.
238: * Run with one argument, prints the encoded version of it.
239: */
240:
241: public static void main(String args[]) {
242: if (args.length != 1) {
243: System.out.println("Base64Encoder <string>");
244: System.exit(0);
245: }
246: Base64Encoder b = new Base64Encoder(args[0]);
247: System.out.println("[" + b.processString() + "]");
248: // joe:eoj -> am9lOmVvag==
249: // 12345678:87654321 -> MTIzNDU2Nzg6ODc2NTQzMjE=
250: }
251: }
|