001: ///////////////////////////////////////////////////////////////////////////////
002: //
003: // Copyright (C) 2003-@year@ by Thomas M. Hazel, MyOODB (www.myoodb.org)
004: //
005: // All Rights Reserved
006: //
007: // This program is free software; you can redistribute it and/or modify
008: // it under the terms of the GNU General Public License and GNU Library
009: // General Public License as published by the Free Software Foundation;
010: // either version 2, or (at your option) any later version.
011: //
012: // This program is distributed in the hope that it will be useful,
013: // but WITHOUT ANY WARRANTY; without even the implied warranty of
014: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: // GNU General Public License and GNU Library General Public License
016: // for more details.
017: //
018: // You should have received a copy of the GNU General Public License
019: // and GNU Library General Public License along with this program; if
020: // not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
021: // MA 02139, USA.
022: //
023: ///////////////////////////////////////////////////////////////////////////////
024: package org.myoodb.util;
025:
026: public final class MimeBase64 {
027: private int m_buf = 0;
028: private int m_buf_bytes = 0;
029: private int m_line_length = 0;
030: private char[] m_line = new char[74];
031: private StringBuilder m_strOut = new StringBuilder();
032: private java.io.ByteArrayOutputStream m_streamOut = new java.io.ByteArrayOutputStream();
033:
034: private byte[] m_token = new byte[4];
035: private byte[] m_bytes = new byte[3];
036: private int m_token_length = 0;
037:
038: private final static byte NUL = 127;
039: private final static byte EOF = 126;
040:
041: private final static char[] ENCODE_MAP = { 'A', 'B', 'C', 'D', 'E',
042: 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
043: 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
044: 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
045: 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
046: '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
047:
048: private final static byte[] DECODE_MAP = { NUL, NUL, NUL, NUL, NUL,
049: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
050: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
051: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
052: NUL, NUL, 62, NUL, NUL, NUL, 63, 52, 53, 54, 55, 56, 57,
053: 58, 59, 60, 61, NUL, NUL, NUL, EOF, NUL, NUL, NUL, 0, 1, 2,
054: 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
055: 19, 20, 21, 22, 23, 24, 25, NUL, NUL, NUL, NUL, NUL, NUL,
056: 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
057: 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NUL, NUL, NUL,
058: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
059: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
060: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
061: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
062: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
063: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
064: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
065: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
066: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
067: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
068: NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL };
069:
070: private final void encode_token() {
071: int i = m_line_length;
072: m_line[i] = ENCODE_MAP[0x3F & m_buf >> 18];
073: m_line[i + 1] = ENCODE_MAP[0x3F & m_buf >> 12];
074: m_line[i + 2] = ENCODE_MAP[0x3F & m_buf >> 6];
075: m_line[i + 3] = ENCODE_MAP[0x3F & m_buf];
076: m_line_length += 4;
077: m_buf = 0;
078: m_buf_bytes = 0;
079: }
080:
081: private final void encode_partial_token() {
082: int i = m_line_length;
083: m_line[i] = ENCODE_MAP[0x3F & m_buf >> 18];
084: m_line[i + 1] = ENCODE_MAP[0x3F & m_buf >> 12];
085:
086: if (m_buf_bytes == 1) {
087: m_line[i + 2] = '=';
088: } else {
089: m_line[i + 2] = ENCODE_MAP[0x3F & m_buf >> 6];
090: }
091:
092: if (m_buf_bytes <= 2) {
093: m_line[i + 3] = '=';
094: } else {
095: m_line[i + 3] = ENCODE_MAP[0x3F & m_buf];
096: }
097: m_line_length += 4;
098: m_buf = 0;
099: m_buf_bytes = 0;
100: }
101:
102: private final void flush_line() {
103: m_strOut.append(m_line, 0, m_line_length);
104: m_line_length = 0;
105: }
106:
107: public final void translate(byte[] in) {
108: int in_length = in.length;
109:
110: for (int i = 0; i < in_length; i++) {
111: if (m_buf_bytes == 0) {
112: m_buf = m_buf & 0x00FFFF | in[i] << 16;
113: } else if (m_buf_bytes == 1) {
114: m_buf = m_buf & 0xFF00FF | in[i] << 8 & 0x00FFFF;
115: } else {
116: m_buf = m_buf & 0xFFFF00 | in[i] & 0x0000FF;
117: }
118:
119: if (++m_buf_bytes == 3) {
120: encode_token();
121: if (m_line_length >= 72) {
122: flush_line();
123: }
124: }
125:
126: if (i == (in_length - 1)) {
127: if (m_buf_bytes > 0 && m_buf_bytes < 3) {
128: encode_partial_token();
129: }
130: if (m_line_length > 0) {
131: flush_line();
132: }
133: }
134: }
135:
136: for (int i = 0; i < m_line.length; i++) {
137: m_line[i] = 0;
138: }
139: }
140:
141: public char[] getCharArray() {
142: char[] ch;
143:
144: if (m_buf_bytes != 0) {
145: encode_partial_token();
146: }
147: flush_line();
148: for (int i = 0; i < m_line.length; i++) {
149: m_line[i] = 0;
150: }
151: ch = new char[m_strOut.length()];
152: m_strOut.getChars(0, m_strOut.length(), ch, 0);
153: return ch;
154: }
155:
156: private void decode_token() {
157: int num = m_token[0] << 18 | m_token[1] << 12 | m_token[2] << 6
158: | m_token[3];
159:
160: m_bytes[0] = (byte) (0xFF & num >> 16);
161: m_bytes[1] = (byte) (0xFF & num >> 8);
162: m_bytes[2] = (byte) (0xFF & num);
163:
164: m_streamOut.write(m_bytes, 0, 3);
165: }
166:
167: private final void decode_final_token() {
168:
169: byte b0 = m_token[0];
170: byte b1 = m_token[1];
171: byte b2 = m_token[2];
172: byte b3 = m_token[3];
173:
174: int eq_count = 0;
175:
176: if (b0 == EOF) {
177: b0 = 0;
178: eq_count++;
179: }
180: if (b1 == EOF) {
181: b1 = 0;
182: eq_count++;
183: }
184: if (b2 == EOF) {
185: b2 = 0;
186: eq_count++;
187: }
188: if (b3 == EOF) {
189: b3 = 0;
190: eq_count++;
191: }
192:
193: int num = b0 << 18 | b1 << 12 | b2 << 6 | b3;
194:
195: m_streamOut.write((byte) (num >> 16));
196: if (eq_count <= 1) {
197: m_streamOut.write((byte) (num >> 8 & 0xFF));
198: if (eq_count == 0) {
199: m_streamOut.write((byte) (num & 0xFF));
200: }
201: }
202: }
203:
204: private void eof() {
205: if (m_token != null && m_token_length != 0) {
206: while (m_token_length < 4) {
207: m_token[m_token_length++] = EOF;
208: }
209: decode_final_token();
210: }
211: m_token_length = 0;
212: m_token = new byte[4];
213: m_bytes = new byte[3];
214: }
215:
216: public final void translate(char[] ch) {
217: translate(ch, 0, ch.length);
218: }
219:
220: public final void translate(char[] ch, int offset, int length) {
221: if (m_token == null) {
222: return;
223: }
224:
225: for (int i = offset; i < offset + length; i++) {
226: byte t = DECODE_MAP[ch[i] & 0xff];
227:
228: if (t == EOF) {
229: eof();
230: } else {
231: if (t != NUL) {
232: m_token[m_token_length++] = t;
233: }
234: }
235: if (m_token_length == 4) {
236: decode_token();
237: m_token_length = 0;
238: }
239: }
240: }
241:
242: public byte[] getByteArray() {
243: eof();
244: return m_streamOut.toByteArray();
245: }
246: }
|