001: package org.methodize.nntprss.util;
002:
003: /* -----------------------------------------------------------
004: * nntp//rss - a bridge between the RSS world and NNTP clients
005: * Copyright (c) 2002, 2003 Jason Brome. All Rights Reserved.
006: *
007: * email: nntprss@methodize.org
008: * mail: Methodize Solutions
009: * PO Box 3865
010: * Grand Central Station
011: * New York NY 10163
012: *
013: * This file is part of nntp//rss
014: *
015: * nntp//rss is free software; you can redistribute it
016: * and/or modify it under the terms of the GNU General
017: * Public License as published by the Free Software Foundation;
018: * either version 2 of the License, or (at your option) any
019: * later version.
020: *
021: * This program is distributed in the hope that it will be
022: * useful, but WITHOUT ANY WARRANTY; without even the implied
023: * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
024: * PURPOSE. See the GNU General Public License for more
025: * details.
026: *
027: * You should have received a copy of the GNU General Public
028: * License along with this program; if not, write to the
029: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
030: * Boston, MA 02111-1307 USA
031: * ----------------------------------------------------- */
032:
033: /**
034: *
035: * Base64 encoding class - decoding not required for nntp//rss
036: *
037: * Based upon Public Domain Base64 class from Robert Harder
038: * See: http://iharder.sourceforge.net/base64/
039: *
040: * @author Robert Harder
041: * @author rob@iharder.net
042: * @version 1.4
043: */
044: public class Base64 {
045:
046: /** Specify encoding (value is <tt>true</tt>). */
047: public final static boolean ENCODE = true;
048:
049: /** Maximum line length (76) of Base64 output. */
050: private final static int MAX_LINE_LENGTH = 76;
051:
052: /** The equals sign (=) as a byte. */
053: private final static byte EQUALS_SIGN = (byte) '=';
054:
055: /** The new line character (\n) as a byte. */
056: private final static byte NEW_LINE = (byte) '\n';
057:
058: /** The 64 valid Base64 values. */
059: private final static byte[] ALPHABET = { (byte) 'A', (byte) 'B',
060: (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
061: (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
062: (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q',
063: (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V',
064: (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a',
065: (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
066: (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k',
067: (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p',
068: (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
069: (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
070: (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4',
071: (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9',
072: (byte) '+', (byte) '/' };
073:
074: /**
075: * Translates a Base64 value to either its 6-bit reconstruction value
076: * or a negative number indicating some other meaning.
077: **/
078: private final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9,
079: -9, -9, -9, // Decimal 0 - 8
080: -5, -5, // Whitespace: Tab and Linefeed
081: -9, -9, // Decimal 11 - 12
082: -5, // Whitespace: Carriage Return
083: -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
084: -9, -9, -9, -9, -9, // Decimal 27 - 31
085: -5, // Whitespace: Space
086: -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
087: 62, // Plus sign at decimal 43
088: -9, -9, -9, // Decimal 44 - 46
089: 63, // Slash at decimal 47
090: 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
091: -9, -9, -9, // Decimal 58 - 60
092: -1, // Equals sign at decimal 61
093: -9, -9, -9, // Decimal 62 - 64
094: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
095: // Letters 'A' through 'N'
096: 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
097: // Letters 'O' through 'Z'
098: -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
099: 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
100: // Letters 'a' through 'm'
101: 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
102: // Letters 'n' through 'z'
103: -9, -9, -9, -9 // Decimal 123 - 126
104: /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
105: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
106: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
107: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
108: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
109: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
110: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
111: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
112: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
113: -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
114: };
115:
116: private final static byte BAD_ENCODING = -9; // Indicates error in encoding
117: private final static byte WHITE_SPACE_ENC = -5;
118: // Indicates white space in encoding
119: private final static byte EQUALS_SIGN_ENC = -1;
120:
121: // Indicates equals sign in encoding
122:
123: /** Defeats instantiation. */
124: private Base64() {
125: }
126:
127: /* ******** E N C O D I N G M E T H O D S ******** */
128:
129: /**
130: * Encodes the first three bytes of array <var>threeBytes</var>
131: * and returns a four-byte array in Base64 notation.
132: *
133: * @param threeBytes the array to convert
134: * @return four byte array in Base64 notation.
135: * @since 1.3
136: */
137: private static byte[] encode3to4(byte[] threeBytes) {
138: return encode3to4(threeBytes, 3);
139: } // end encodeToBytes
140:
141: /**
142: * Encodes up to the first three bytes of array <var>threeBytes</var>
143: * and returns a four-byte array in Base64 notation.
144: * The actual number of significant bytes in your array is
145: * given by <var>numSigBytes</var>.
146: * The array <var>threeBytes</var> needs only be as big as
147: * <var>numSigBytes</var>.
148: *
149: * @param threeBytes the array to convert
150: * @param numSigBytes the number of significant bytes in your array
151: * @return four byte array in Base64 notation.
152: * @since 1.3
153: */
154: private static byte[] encode3to4(byte[] threeBytes, int numSigBytes) {
155: byte[] dest = new byte[4];
156: encode3to4(threeBytes, 0, numSigBytes, dest, 0);
157: return dest;
158: }
159:
160: /**
161: * Encodes up to three bytes of the array <var>source</var>
162: * and writes the resulting four Base64 bytes to <var>destination</var>.
163: * The source and destination arrays can be manipulated
164: * anywhere along their length by specifying
165: * <var>srcOffset</var> and <var>destOffset</var>.
166: * This method does not check to make sure your arrays
167: * are large enough to accomodate <var>srcOffset</var> + 3 for
168: * the <var>source</var> array or <var>destOffset</var> + 4 for
169: * the <var>destination</var> array.
170: * The actual number of significant bytes in your array is
171: * given by <var>numSigBytes</var>.
172: *
173: * @param source the array to convert
174: * @param srcOffset the index where conversion begins
175: * @param numSigBytes the number of significant bytes in your array
176: * @param destination the array to hold the conversion
177: * @param destOffset the index where output will be put
178: * @return the <var>destination</var> array
179: * @since 1.3
180: */
181: private static byte[] encode3to4(byte[] source, int srcOffset,
182: int numSigBytes, byte[] destination, int destOffset) {
183: // 1 2 3
184: // 01234567890123456789012345678901 Bit position
185: // --------000000001111111122222222 Array position from threeBytes
186: // --------| || || || | Six bit groups to index ALPHABET
187: // >>18 >>12 >> 6 >> 0 Right shift necessary
188: // 0x3f 0x3f 0x3f Additional AND
189:
190: // Create buffer with zero-padding if there are only one or two
191: // significant bytes passed in the array.
192: // We have to shift left 24 in order to flush out the 1's that appear
193: // when Java treats a value as negative that is cast from a byte to an int.
194: int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8)
195: : 0)
196: | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16)
197: : 0)
198: | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24)
199: : 0);
200:
201: switch (numSigBytes) {
202: case 3:
203: destination[destOffset] = ALPHABET[(inBuff >>> 18)];
204: destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
205: destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
206: destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
207: return destination;
208:
209: case 2:
210: destination[destOffset] = ALPHABET[(inBuff >>> 18)];
211: destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
212: destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
213: destination[destOffset + 3] = EQUALS_SIGN;
214: return destination;
215:
216: case 1:
217: destination[destOffset] = ALPHABET[(inBuff >>> 18)];
218: destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
219: destination[destOffset + 2] = EQUALS_SIGN;
220: destination[destOffset + 3] = EQUALS_SIGN;
221: return destination;
222:
223: default:
224: return destination;
225: } // end switch
226: } // end encode3to4
227:
228: /**
229: * Encodes a byte array into Base64 notation.
230: * Equivalen to calling
231: * <code>encodeBytes( source, 0, source.length )</code>
232: *
233: * @param source The data to convert
234: * @since 1.4
235: */
236: public static String encodeBytes(byte[] source) {
237: return encodeBytes(source, true);
238: } // end encodeBytes
239:
240: /**
241: * Encodes a byte array into Base64 notation.
242: * Equivalen to calling
243: * <code>encodeBytes( source, 0, source.length )</code>
244: *
245: * @param source The data to convert
246: * @param breakLines Break lines at 80 characters or less.
247: * @since 1.4
248: */
249: public static String encodeBytes(byte[] source, boolean breakLines) {
250: return encodeBytes(source, 0, source.length, breakLines);
251: } // end encodeBytes
252:
253: /**
254: * Encodes a byte array into Base64 notation.
255: *
256: * @param source The data to convert
257: * @param off Offset in array where conversion should begin
258: * @param len Length of data to convert
259: * @param breakLines Break lines at 80 characters or less.
260: * @since 1.4
261: */
262: public static String encodeBytes(byte[] source, int off, int len,
263: boolean breakLines) {
264: int len43 = len * 4 / 3;
265: byte[] outBuff = new byte[(len43) // Main 4:3
266: + ((len % 3) > 0 ? 4 : 0) // Account for padding
267: + (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)]; // New lines
268: int d = 0;
269: int e = 0;
270: int len2 = len - 2;
271: int lineLength = 0;
272: for (; d < len2; d += 3, e += 4) {
273: encode3to4(source, d + off, 3, outBuff, e);
274:
275: lineLength += 4;
276: if (breakLines && lineLength == MAX_LINE_LENGTH) {
277: outBuff[e + 4] = NEW_LINE;
278: e++;
279: lineLength = 0;
280: } // end if: end of line
281: } // en dfor: each piece of array
282:
283: if (d < len) {
284: encode3to4(source, d + off, len - d, outBuff, e);
285: e += 4;
286: } // end if: some padding needed
287:
288: return new String(outBuff, 0, e);
289: } // end encodeBytes
290:
291: } // end class Base64
|