001: /*
002: *
003: * The contents of this file are subject to the Netscape Public
004: * License Version 1.1 (the "License"); you may not use this file
005: * except in compliance with the License. You may obtain a copy of
006: * the License at http://www.mozilla.org/NPL/
007: *
008: * Software distributed under the License is distributed on an "AS
009: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
010: * implied. See the License for the specific language governing
011: * rights and limitations under the License.
012: *
013: * The Original Code is mozilla.org code.
014: *
015: * The Initial Developer of the Original Code is Netscape
016: * Communications Corporation. Portions created by Netscape are
017: * Copyright (C) 1999 Netscape Communications Corporation. All
018: * Rights Reserved.
019: *
020: * Contributor(s):
021: */
022:
023: package org.infozone.tools;
024:
025: import java.io.ByteArrayOutputStream;
026:
027: /**
028: * Base 64 text to byte decoded. To produce the binary array from
029: * base 64 encoding call {@link #translate} for each sequence of
030: * characters and {@link #getByteArray} to mark closure of the
031: * character stream and retrieve the binary contents.
032: *
033: * @author Based on code from the Mozilla Directory SDK
034: */
035: public final class MimeBase64Decoder {
036:
037: private ByteArrayOutputStream out = new ByteArrayOutputStream();
038:
039: private byte token[] = new byte[4]; // input buffer
040: private byte bytes[] = new byte[3]; // output buffer
041: private int token_length = 0; // input buffer length
042:
043: static private final byte NUL = 127; // must be out of range 0-64
044: static private final byte EOF = 126; // must be out of range 0-64
045:
046: static private final byte map[] = { NUL, NUL, NUL, NUL, NUL, NUL,
047: NUL, NUL, // 000-007
048: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 010-017
049: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 020-027
050: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 030-037
051: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 040-047 !"#$%&'
052: NUL, NUL, NUL, 62, NUL, NUL, NUL, 63, // 050-057 ()*+,-./
053: 52, 53, 54, 55, 56, 57, 58, 59, // 060-067 01234567
054: 60, 61, NUL, NUL, NUL, EOF, NUL, NUL, // 070-077 89:;<=>?
055:
056: NUL, 0, 1, 2, 3, 4, 5, 6, // 100-107 @ABCDEFG
057: 7, 8, 9, 10, 11, 12, 13, 14, // 110-117 HIJKLMNO
058: 15, 16, 17, 18, 19, 20, 21, 22, // 120-127 PQRSTUVW
059: 23, 24, 25, NUL, NUL, NUL, NUL, NUL, // 130-137 XYZ[\]^_
060: NUL, 26, 27, 28, 29, 30, 31, 32, // 140-147 `abcdefg
061: 33, 34, 35, 36, 37, 38, 39, 40, // 150-157 hijklmno
062: 41, 42, 43, 44, 45, 46, 47, 48, // 160-167 pqrstuvw
063: 49, 50, 51, NUL, NUL, NUL, NUL, NUL, // 170-177 xyz{|}~
064:
065: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 200-207
066: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 210-217
067: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 220-227
068: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 230-237
069: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 240-247
070: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 250-257
071: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 260-267
072: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 270-277
073:
074: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 300-307
075: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 310-317
076: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 320-327
077: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 330-337
078: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 340-347
079: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 350-357
080: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 360-367
081: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 370-377
082: };
083:
084: // Fast routine that assumes full 4-char tokens with no '=' in them.
085: //
086: private void decode_token() {
087: int num = ((token[0] << 18) | (token[1] << 12)
088: | (token[2] << 6) | (token[3]));
089:
090: bytes[0] = (byte) (0xFF & (num >> 16));
091: bytes[1] = (byte) (0xFF & (num >> 8));
092: bytes[2] = (byte) (0xFF & num);
093:
094: out.write(bytes, 0, 3);
095: }
096:
097: // Hairier routine that deals with the final token, which can have fewer
098: // than four characters, and that might be padded with '='.
099: //
100: private final void decode_final_token() {
101:
102: byte b0 = token[0];
103: byte b1 = token[1];
104: byte b2 = token[2];
105: byte b3 = token[3];
106:
107: int eq_count = 0;
108:
109: if (b0 == EOF) {
110: b0 = 0;
111: eq_count++;
112: }
113: if (b1 == EOF) {
114: b1 = 0;
115: eq_count++;
116: }
117: if (b2 == EOF) {
118: b2 = 0;
119: eq_count++;
120: }
121: if (b3 == EOF) {
122: b3 = 0;
123: eq_count++;
124: }
125:
126: int num = ((b0 << 18) | (b1 << 12) | (b2 << 6) | (b3));
127:
128: // eq_count will be 0, 1, or 2.
129: // No "=" padding means 4 bytes mapped to 3, the normal case,
130: // not handled in this routine.
131: // "xxx=" means 3 bytes mapped to 2.
132: // "xx==" means 2 bytes mapped to 1.
133: // "x===" can't happen, because "x" would then be encoding
134: // only 6 bits, not 8, the minimum possible.
135:
136: out.write((byte) (num >> 16)); // byte 1, count = 0 or 1 or 2
137: if (eq_count <= 1) {
138: out.write((byte) ((num >> 8) & 0xFF)); // byte 2, count = 0 or 1
139: if (eq_count == 0) {
140: out.write((byte) (num & 0xFF)); // byte 3, count = 0
141: }
142: }
143: }
144:
145: public final void translate(char[] ch) {
146: translate(ch, 0, ch.length);
147: }
148:
149: public final void translate(char[] ch, int offset, int length) {
150:
151: if (token == null) // already saw eof marker?
152: return;
153:
154: for (int i = offset; i < offset + length; i++) {
155: byte t = map[(ch[i] & 0xff)];
156:
157: if (t == EOF) {
158: eof();
159: } else if (t != NUL) {
160: token[token_length++] = t;
161: }
162: if (token_length == 4) {
163: decode_token();
164: token_length = 0;
165: }
166: }
167: }
168:
169: private void eof() {
170: if (token != null && token_length != 0) {
171: while (token_length < 4)
172: token[token_length++] = EOF;
173: decode_final_token();
174: }
175: token_length = 0;
176: token = new byte[4];
177: bytes = new byte[3];
178: }
179:
180: public byte[] getByteArray() {
181: eof();
182: return out.toByteArray();
183: }
184: }
|