This project has retired. For details please refer to its
Attic page.
Base64 xref
1/*2 * Licensed to the Apache Software Foundation (ASF) under one3 * or more contributor license agreements. See the NOTICE file4 * distributed with this work for additional information5 * regarding copyright ownership. The ASF licenses this file6 * to you under the Apache License, Version 2.0 (the7 * "License"); you may not use this file except in compliance8 * with the License. You may obtain a copy of the License at9 *10 * http://www.apache.org/licenses/LICENSE-2.011 *12 * Unless required by applicable law or agreed to in writing,13 * software distributed under the License is distributed on an14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY15 * KIND, either express or implied. See the License for the16 * specific language governing permissions and limitations17 * under the License.18 */19package org.apache.chemistry.opencmis.commons.impl;
2021/**22 * <p>23 * Encodes and decodes to and from Base64 notation.24 * </p>25 * <p>26 * Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.27 * </p>28 * 29 * @author Robert Harder30 * @author rob@iharder.net31 * @version 2.3.732 */33publicclass Base64 {
3435/* ******** P U B L I C F I E L D S ******** */3637/** No options specified. Value is zero. */38publicstaticfinalint NO_OPTIONS = 0;
3940/** Specify encoding in first bit. Value is one. */41publicstaticfinalint ENCODE = 1;
4243/** Specify decoding in first bit. Value is zero. */44publicstaticfinalint DECODE = 0;
4546/** Specify that data should be gzip-compressed in second bit. Value is two. */47publicstaticfinalint GZIP = 2;
4849/**50 * Specify that gzipped data should <em>not</em> be automatically gunzipped.51 */52publicstaticfinalint DONT_GUNZIP = 4;
5354/** Do break lines when encoding. Value is 8. */55publicstaticfinalint DO_BREAK_LINES = 8;
5657/**58 * Encode using Base64-like encoding that is URL- and Filename-safe as59 * described in Section 4 of RFC3548: <a60 * href="http://www.faqs.org/rfcs/rfc3548.html"61 * >http://www.faqs.org/rfcs/rfc3548.html</a>. It is important to note that62 * data encoded this way is <em>not</em> officially valid Base64, or at the63 * very least should not be called Base64 without also specifying that is64 * was encoded using the URL- and Filename-safe dialect.65 */66publicstaticfinalint URL_SAFE = 16;
6768/**69 * Encode using the special "ordered" dialect of Base64 described here: <a70 * href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-71 * 1940.html</a>.72 */73publicstaticfinalint ORDERED = 32;
7475/* ******** P R I V A T E F I E L D S ******** */7677/** Maximum line length (76) of Base64 output. */78privatestaticfinalint MAX_LINE_LENGTH = 76;
7980/** The equals sign (=) as a byte. */81privatestaticfinal byte EQUALS_SIGN = (byte) '=';
8283/** The new line character (\n) as a byte. */84privatestaticfinal byte NEW_LINE = (byte) '\n';
8586/** Preferred encoding. */87privatestaticfinal String PREFERRED_ENCODING = "US-ASCII";
8889privatestaticfinal byte WHITE_SPACE_ENC = -5; // Indicates white space in90// encoding91privatestaticfinal byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in92// encoding9394/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */9596/** The 64 valid Base64 values. */97/*98 * Host platform me be something funny like EBCDIC, so we hardcode these99 * values.100 */101privatestaticfinal byte[] _STANDARD_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E',
102 (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
103 (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
104 (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
105 (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
106 (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
107 (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
108 (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/' };
109110/**111 * Translates a Base64 value to either its 6-bit reconstruction value or a112 * negative number indicating some other meaning.113 **/114privatestaticfinal byte[] _STANDARD_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal115// 0116// -117// 8118 -5, -5, // Whitespace: Tab and Linefeed119 -9, -9, // Decimal 11 - 12120 -5, // Whitespace: Carriage Return121 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 -122// 26123 -9, -9, -9, -9, -9, // Decimal 27 - 31124 -5, // Whitespace: Space125 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42126 62, // Plus sign at decimal 43127 -9, -9, -9, // Decimal 44 - 46128 63, // Slash at decimal 47129 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine130 -9, -9, -9, // Decimal 58 - 60131 -1, // Equals sign at decimal 61132 -9, -9, -9, // Decimal 62 - 64133 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through134// 'N'135 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O'136// through 'Z'137 -9, -9, -9, -9, -9, -9, // Decimal 91 - 96138 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a'139// through 'm'140 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n'141// through 'z'142 -9, -9, -9, -9, -9 // Decimal 123 - 127143 , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 -144// 139145 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 -146// 152147 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 -148// 165149 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 -150// 178151 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 -152// 191153 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 -154// 204155 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 -156// 217157 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 -158// 230159 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 -160// 243161 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255162 };
163164/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */165166/**167 * Used in the URL- and Filename-safe dialect described in Section 4 of168 * RFC3548: <a169 * href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org170 * /rfcs/rfc3548.html</a>. Notice that the last two bytes become "hyphen"171 * and "underscore" instead of "plus" and "slash."172 */173privatestaticfinal byte[] _URL_SAFE_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E',
174 (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
175 (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
176 (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
177 (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
178 (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
179 (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
180 (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_' };
181182/**183 * Used in decoding URL- and Filename-safe dialects of Base64.184 */185privatestaticfinal byte[] _URL_SAFE_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal186// 0187// -188// 8189 -5, -5, // Whitespace: Tab and Linefeed190 -9, -9, // Decimal 11 - 12191 -5, // Whitespace: Carriage Return192 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 -193// 26194 -9, -9, -9, -9, -9, // Decimal 27 - 31195 -5, // Whitespace: Space196 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42197 -9, // Plus sign at decimal 43198 -9, // Decimal 44199 62, // Minus sign at decimal 45200 -9, // Decimal 46201 -9, // Slash at decimal 47202 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine203 -9, -9, -9, // Decimal 58 - 60204 -1, // Equals sign at decimal 61205 -9, -9, -9, // Decimal 62 - 64206 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through207// 'N'208 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O'209// through 'Z'210 -9, -9, -9, -9, // Decimal 91 - 94211 63, // Underscore at decimal 95212 -9, // Decimal 96213 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a'214// through 'm'215 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n'216// through 'z'217 -9, -9, -9, -9, -9 // Decimal 123 - 127218 , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 -219// 139220 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 -221// 152222 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 -223// 165224 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 -225// 178226 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 -227// 191228 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 -229// 204230 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 -231// 217232 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 -233// 230234 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 -235// 243236 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255237 };
238239/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */240241/**242 * I don't get the point of this technique, but someone requested it, and it243 * is described here: <a244 * href="http://www.faqs.org/qa/rfcc-1940.html">http://245 * www.faqs.org/qa/rfcc-1940.html</a>.246 */247privatestaticfinal byte[] _ORDERED_ALPHABET = { (byte) '-', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
248 (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C',
249 (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
250 (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
251 (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) '_', (byte) 'a', (byte) 'b', (byte) 'c',
252 (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l',
253 (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
254 (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z' };
255256/**257 * Used in decoding the "ordered" dialect of Base64.258 */259privatestaticfinal byte[] _ORDERED_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal260// 0261// -262// 8263 -5, -5, // Whitespace: Tab and Linefeed264 -9, -9, // Decimal 11 - 12265 -5, // Whitespace: Carriage Return266 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 -267// 26268 -9, -9, -9, -9, -9, // Decimal 27 - 31269 -5, // Whitespace: Space270 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42271 -9, // Plus sign at decimal 43272 -9, // Decimal 44273 0, // Minus sign at decimal 45274 -9, // Decimal 46275 -9, // Slash at decimal 47276 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine277 -9, -9, -9, // Decimal 58 - 60278 -1, // Equals sign at decimal 61279 -9, -9, -9, // Decimal 62 - 64280 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A'281// through 'M'282 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N'283// through 'Z'284 -9, -9, -9, -9, // Decimal 91 - 94285 37, // Underscore at decimal 95286 -9, // Decimal 96287 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a'288// through 'm'289 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n'290// through 'z'291 -9, -9, -9, -9, -9 // Decimal 123 - 127292 , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128293// - 139294 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 -295// 152296 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 -297// 165298 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 -299// 178300 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 -301// 191302 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 -303// 204304 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 -305// 217306 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 -307// 230308 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 -309// 243310 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255311 };
312313/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */314315/**316 * Returns one of the _SOMETHING_ALPHABET byte arrays depending on the317 * options specified. It's possible, though silly, to specify ORDERED318 * <b>and</b> URLSAFE in which case one of them will be picked, though there319 * is no guarantee as to which one will be picked.320 */321privatestaticfinal byte[] getAlphabet(int options) {
322if ((options & URL_SAFE) == URL_SAFE) {
323return _URL_SAFE_ALPHABET;
324 } elseif ((options & ORDERED) == ORDERED) {
325return _ORDERED_ALPHABET;
326 } else {
327return _STANDARD_ALPHABET;
328 }
329 } // end getAlphabet330331/**332 * Returns one of the _SOMETHING_DECODABET byte arrays depending on the333 * options specified. It's possible, though silly, to specify ORDERED and334 * URL_SAFE in which case one of them will be picked, though there is no335 * guarantee as to which one will be picked.336 */337privatestaticfinal byte[] getDecodabet(int options) {
338if ((options & URL_SAFE) == URL_SAFE) {
339return _URL_SAFE_DECODABET;
340 } elseif ((options & ORDERED) == ORDERED) {
341return _ORDERED_DECODABET;
342 } else {
343return _STANDARD_DECODABET;
344 }
345 } // end getAlphabet346347/** Defeats instantiation. */348private Base64() {
349 }
350351/* ******** E N C O D I N G M E T H O D S ******** */352353/**354 * Encodes up to the first three bytes of array <var>threeBytes</var> and355 * returns a four-byte array in Base64 notation. The actual number of356 * significant bytes in your array is given by <var>numSigBytes</var>. The357 * array <var>threeBytes</var> needs only be as big as358 * <var>numSigBytes</var>. Code can reuse a byte array by passing a359 * four-byte array as <var>b4</var>.360 * 361 * @param b4362 * A reusable byte array to reduce array instantiation363 * @param threeBytes364 * the array to convert365 * @param numSigBytes366 * the number of significant bytes in your array367 * @return four byte array in Base64 notation.368 * @since 1.5.1369 */370privatestatic byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes, int options) {
371 encode3to4(threeBytes, 0, numSigBytes, b4, 0, options);
372return b4;
373 } // end encode3to4374375/**376 * <p>377 * Encodes up to three bytes of the array <var>source</var> and writes the378 * resulting four Base64 bytes to <var>destination</var>. The source and379 * destination arrays can be manipulated anywhere along their length by380 * specifying <var>srcOffset</var> and <var>destOffset</var>. This method381 * does not check to make sure your arrays are large enough to accomodate382 * <var>srcOffset</var> + 3 for the <var>source</var> array or383 * <var>destOffset</var> + 4 for the <var>destination</var> array. The384 * actual number of significant bytes in your array is given by385 * <var>numSigBytes</var>.386 * </p>387 * <p>388 * This is the lowest level of the encoding methods with all possible389 * parameters.390 * </p>391 * 392 * @param source393 * the array to convert394 * @param srcOffset395 * the index where conversion begins396 * @param numSigBytes397 * the number of significant bytes in your array398 * @param destination399 * the array to hold the conversion400 * @param destOffset401 * the index where output will be put402 * @return the <var>destination</var> array403 * @since 1.3404 */405privatestatic byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset,
406int options) {
407408 byte[] ALPHABET = getAlphabet(options);
409410// 1 2 3411// 01234567890123456789012345678901 Bit position412// --------000000001111111122222222 Array position from threeBytes413// --------| || || || | Six bit groups to index ALPHABET414// >>18 >>12 >> 6 >> 0 Right shift necessary415// 0x3f 0x3f 0x3f Additional AND416417// Create buffer with zero-padding if there are only one or two418// significant bytes passed in the array.419// We have to shift left 24 in order to flush out the 1's that appear420// when Java treats a value as negative that is cast from a byte to an421// int.422int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
423 | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
424 | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
425426switch (numSigBytes) {
427case 3:
428 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
429 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
430 destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
431 destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
432return destination;
433434case 2:
435 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
436 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
437 destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
438 destination[destOffset + 3] = EQUALS_SIGN;
439return destination;
440441case 1:
442 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
443 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
444 destination[destOffset + 2] = EQUALS_SIGN;
445 destination[destOffset + 3] = EQUALS_SIGN;
446return destination;
447448default:
449return destination;
450 } // end switch451 } // end encode3to4452453/**454 * Performs Base64 encoding on the <code>raw</code> ByteBuffer, writing it455 * to the <code>encoded</code> ByteBuffer. This is an experimental feature.456 * Currently it does not pass along any options (such as457 * {@link #DO_BREAK_LINES} or {@link #GZIP}.458 * 459 * @param raw460 * input buffer461 * @param encoded462 * output buffer463 * @since 2.3464 */465publicstaticvoid encode(java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded) {
466 byte[] raw3 = new byte[3];
467 byte[] enc4 = new byte[4];
468469while (raw.hasRemaining()) {
470int rem = Math.min(3, raw.remaining());
471 raw.get(raw3, 0, rem);
472 Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS);
473 encoded.put(enc4);
474 } // end input remaining475 }
476477/**478 * Performs Base64 encoding on the <code>raw</code> ByteBuffer, writing it479 * to the <code>encoded</code> CharBuffer. This is an experimental feature.480 * Currently it does not pass along any options (such as481 * {@link #DO_BREAK_LINES} or {@link #GZIP}.482 * 483 * @param raw484 * input buffer485 * @param encoded486 * output buffer487 * @since 2.3488 */489publicstaticvoid encode(java.nio.ByteBuffer raw, java.nio.CharBuffer encoded) {
490 byte[] raw3 = new byte[3];
491 byte[] enc4 = new byte[4];
492493while (raw.hasRemaining()) {
494int rem = Math.min(3, raw.remaining());
495 raw.get(raw3, 0, rem);
496 Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS);
497for (int i = 0; i < 4; i++) {
498 encoded.put((char) (enc4[i] & 0xFF));
499 }
500 } // end input remaining501 }
502503/**504 * Serializes an object and returns the Base64-encoded version of that505 * serialized object.506 * 507 * <p>508 * As of v 2.3, if the object cannot be serialized or there is another509 * error, the method will throw an java.io.IOException. <b>This is new to510 * v2.3!</b> In earlier versions, it just returned a null value, but in511 * retrospect that's a pretty poor way to handle it.512 * </p>513 * 514 * The object is not GZip-compressed before being encoded.515 * 516 * @param serializableObject517 * The object to encode518 * @return The Base64-encoded object519 * @throws java.io.IOException520 * if there is an error521 * @throws NullPointerException522 * if serializedObject is null523 * @since 1.4524 */525publicstatic String encodeObject(java.io.Serializable serializableObject) throws java.io.IOException {
526return encodeObject(serializableObject, NO_OPTIONS);
527 } // end encodeObject528529/**530 * Serializes an object and returns the Base64-encoded version of that531 * serialized object.532 * 533 * <p>534 * As of v 2.3, if the object cannot be serialized or there is another535 * error, the method will throw an java.io.IOException. <b>This is new to536 * v2.3!</b> In earlier versions, it just returned a null value, but in537 * retrospect that's a pretty poor way to handle it.538 * </p>539 * 540 * The object is not GZip-compressed before being encoded.541 * <p>542 * Example options:543 * 544 * <pre>545 * GZIP: gzip-compresses object before encoding it.546 * DO_BREAK_LINES: break lines at 76 characters547 * </pre>548 * <p>549 * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or550 * <p>551 * Example:552 * <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>553 * 554 * @param serializableObject555 * The object to encode556 * @param options557 * Specified options558 * @return The Base64-encoded object559 * @see Base64#GZIP560 * @see Base64#DO_BREAK_LINES561 * @throws java.io.IOException562 * if there is an error563 * @since 2.0564 */565publicstatic String encodeObject(java.io.Serializable serializableObject, int options) throws java.io.IOException {
566567if (serializableObject == null) {
568thrownew NullPointerException("Cannot serialize a null object.");
569 } // end if: null570571// Streams572 java.io.ByteArrayOutputStream baos = null;
573 java.io.OutputStream b64os = null;
574 java.util.zip.GZIPOutputStream gzos = null;
575 java.io.ObjectOutputStream oos = null;
576577try {
578// ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream579 baos = new java.io.ByteArrayOutputStream();
580 b64os = new Base64.OutputStream(baos, ENCODE | options);
581if ((options & GZIP) != 0) {
582// Gzip583 gzos = new java.util.zip.GZIPOutputStream(b64os);
584 oos = new java.io.ObjectOutputStream(gzos);
585 } else {
586// Not gzipped587 oos = new java.io.ObjectOutputStream(b64os);
588 }
589 oos.writeObject(serializableObject);
590 } // end try591catch (java.io.IOException e) {
592// Catch it and then throw it immediately so that593// the finally{} block is called for cleanup.594throw e;
595 } // end catch596finally {
597try {
598 oos.close();
599 } catch (Exception e) {
600 }
601try {
602 gzos.close();
603 } catch (Exception e) {
604 }
605try {
606 b64os.close();
607 } catch (Exception e) {
608 }
609try {
610 baos.close();
611 } catch (Exception e) {
612 }
613 } // end finally614615// Return value according to relevant encoding.616try {
617returnnew String(baos.toByteArray(), PREFERRED_ENCODING);
618 } // end try619catch (java.io.UnsupportedEncodingException uue) {
620// Fall back to some Java default621returnnew String(baos.toByteArray());
622 } // end catch623624 } // end encode625626/**627 * Encodes a byte array into Base64 notation. Does not GZip-compress data.628 * 629 * @param source630 * The data to convert631 * @return The data in Base64-encoded form632 * @throws NullPointerException633 * if source array is null634 * @since 1.4635 */636publicstatic String encodeBytes(byte[] source) {
637// Since we're not going to have the GZIP encoding turned on,638// we're not going to have an java.io.IOException thrown, so639// we should not force the user to have to catch it.640 String encoded = null;
641try {
642 encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
643 } catch (java.io.IOException ex) {
644 assert false : ex.getMessage();
645 } // end catch646 assert encoded != null;
647return encoded;
648 } // end encodeBytes649650/**651 * Encodes a byte array into Base64 notation.652 * <p>653 * Example options:654 * 655 * <pre>656 * GZIP: gzip-compresses object before encoding it.657 * DO_BREAK_LINES: break lines at 76 characters658 * <i>Note: Technically, this makes your encoding non-compliant.</i>659 * </pre>660 * <p>661 * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or662 * <p>663 * Example:664 * <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>665 * 666 * 667 * <p>668 * As of v 2.3, if there is an error with the GZIP stream, the method will669 * throw an java.io.IOException. <b>This is new to v2.3!</b> In earlier670 * versions, it just returned a null value, but in retrospect that's a671 * pretty poor way to handle it.672 * </p>673 * 674 * 675 * @param source676 * The data to convert677 * @param options678 * Specified options679 * @return The Base64-encoded data as a String680 * @see Base64#GZIP681 * @see Base64#DO_BREAK_LINES682 * @throws java.io.IOException683 * if there is an error684 * @throws NullPointerException685 * if source array is null686 * @since 2.0687 */688publicstatic String encodeBytes(byte[] source, int options) throws java.io.IOException {
689return encodeBytes(source, 0, source.length, options);
690 } // end encodeBytes691692/**693 * Encodes a byte array into Base64 notation. Does not GZip-compress data.694 * 695 * <p>696 * As of v 2.3, if there is an error, the method will throw an697 * java.io.IOException. <b>This is new to v2.3!</b> In earlier versions, it698 * just returned a null value, but in retrospect that's a pretty poor way to699 * handle it.700 * </p>701 * 702 * 703 * @param source704 * The data to convert705 * @param off706 * Offset in array where conversion should begin707 * @param len708 * Length of data to convert709 * @return The Base64-encoded data as a String710 * @throws NullPointerException711 * if source array is null712 * @throws IllegalArgumentException713 * if source array, offset, or length are invalid714 * @since 1.4715 */716publicstatic String encodeBytes(byte[] source, int off, int len) {
717// Since we're not going to have the GZIP encoding turned on,718// we're not going to have an java.io.IOException thrown, so719// we should not force the user to have to catch it.720 String encoded = null;
721try {
722 encoded = encodeBytes(source, off, len, NO_OPTIONS);
723 } catch (java.io.IOException ex) {
724 assert false : ex.getMessage();
725 } // end catch726 assert encoded != null;
727return encoded;
728 } // end encodeBytes729730/**731 * Encodes a byte array into Base64 notation.732 * <p>733 * Example options:734 * 735 * <pre>736 * GZIP: gzip-compresses object before encoding it.737 * DO_BREAK_LINES: break lines at 76 characters738 * <i>Note: Technically, this makes your encoding non-compliant.</i>739 * </pre>740 * <p>741 * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or742 * <p>743 * Example:744 * <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>745 * 746 * 747 * <p>748 * As of v 2.3, if there is an error with the GZIP stream, the method will749 * throw an java.io.IOException. <b>This is new to v2.3!</b> In earlier750 * versions, it just returned a null value, but in retrospect that's a751 * pretty poor way to handle it.752 * </p>753 * 754 * 755 * @param source756 * The data to convert757 * @param off758 * Offset in array where conversion should begin759 * @param len760 * Length of data to convert761 * @param options762 * Specified options763 * @return The Base64-encoded data as a String764 * @see Base64#GZIP765 * @see Base64#DO_BREAK_LINES766 * @throws java.io.IOException767 * if there is an error768 * @throws NullPointerException769 * if source array is null770 * @throws IllegalArgumentException771 * if source array, offset, or length are invalid772 * @since 2.0773 */774publicstatic String encodeBytes(byte[] source, int off, int len, int options) throws java.io.IOException {
775 byte[] encoded = encodeBytesToBytes(source, off, len, options);
776777// Return value according to relevant encoding.778try {
779returnnew String(encoded, PREFERRED_ENCODING);
780 } // end try781catch (java.io.UnsupportedEncodingException uue) {
782returnnew String(encoded);
783 } // end catch784785 } // end encodeBytes786787/**788 * Similar to {@link #encodeBytes(byte[])} but returns a byte array instead789 * of instantiating a String. This is more efficient if you're working with790 * I/O streams and have large data sets to encode.791 * 792 * 793 * @param source794 * The data to convert795 * @return The Base64-encoded data as a byte[] (of ASCII characters)796 * @throws NullPointerException797 * if source array is null798 * @since 2.3.1799 */800publicstatic byte[] encodeBytesToBytes(byte[] source) {
801 byte[] encoded = null;
802try {
803 encoded = encodeBytesToBytes(source, 0, source.length, Base64.NO_OPTIONS);
804 } catch (java.io.IOException ex) {
805 assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
806 }
807return encoded;
808 }
809810/**811 * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns a byte812 * array instead of instantiating a String. This is more efficient if you're813 * working with I/O streams and have large data sets to encode.814 * 815 * 816 * @param source817 * The data to convert818 * @param off819 * Offset in array where conversion should begin820 * @param len821 * Length of data to convert822 * @param options823 * Specified options824 * @return The Base64-encoded data as a String825 * @see Base64#GZIP826 * @see Base64#DO_BREAK_LINES827 * @throws java.io.IOException828 * if there is an error829 * @throws NullPointerException830 * if source array is null831 * @throws IllegalArgumentException832 * if source array, offset, or length are invalid833 * @since 2.3.1834 */835publicstatic byte[] encodeBytesToBytes(byte[] source, int off, int len, int options) throws java.io.IOException {
836837if (source == null) {
838thrownew NullPointerException("Cannot serialize a null array.");
839 } // end if: null840841if (off < 0) {
842thrownew IllegalArgumentException("Cannot have negative offset: " + off);
843 } // end if: off < 0844845if (len < 0) {
846thrownew IllegalArgumentException("Cannot have length offset: " + len);
847 } // end if: len < 0848849if (off + len > source.length) {
850thrownew IllegalArgumentException(String.format(
851"Cannot have offset of %d and length of %d with array of length %d", off, len, source.length));
852 } // end if: off < 0853854// Compress?855if ((options & GZIP) != 0) {
856 java.io.ByteArrayOutputStream baos = null;
857 java.util.zip.GZIPOutputStream gzos = null;
858 Base64.OutputStream b64os = null;
859860try {
861// GZip -> Base64 -> ByteArray862 baos = new java.io.ByteArrayOutputStream();
863 b64os = new Base64.OutputStream(baos, ENCODE | options);
864 gzos = new java.util.zip.GZIPOutputStream(b64os);
865866 gzos.write(source, off, len);
867 gzos.close();
868 } // end try869catch (java.io.IOException e) {
870// Catch it and then throw it immediately so that871// the finally{} block is called for cleanup.872throw e;
873 } // end catch874finally {
875try {
876 gzos.close();
877 } catch (Exception e) {
878 }
879try {
880 b64os.close();
881 } catch (Exception e) {
882 }
883try {
884 baos.close();
885 } catch (Exception e) {
886 }
887 } // end finally888889return baos.toByteArray();
890 } // end if: compress891892// Else, don't compress. Better not to use streams at all then.893else {
894boolean breakLines = (options & DO_BREAK_LINES) != 0;
895896// int len43 = len * 4 / 3;897// byte[] outBuff = new byte[ ( len43 ) // Main 4:3898// + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding899// + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines900// Try to determine more precisely how big the array needs to be.901// If we get it right, we don't have to do an array copy, and902// we save a bunch of memory.903int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); // Bytes needed904// for actual905// encoding906if (breakLines) {
907 encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline908// characters909 }
910 byte[] outBuff = new byte[encLen];
911912int d = 0;
913int e = 0;
914int len2 = len - 2;
915int lineLength = 0;
916for (; d < len2; d += 3, e += 4) {
917 encode3to4(source, d + off, 3, outBuff, e, options);
918919 lineLength += 4;
920if (breakLines && lineLength >= MAX_LINE_LENGTH) {
921 outBuff[e + 4] = NEW_LINE;
922 e++;
923 lineLength = 0;
924 } // end if: end of line925 } // en dfor: each piece of array926927if (d < len) {
928 encode3to4(source, d + off, len - d, outBuff, e, options);
929 e += 4;
930 } // end if: some padding needed931932// Only resize array if we didn't guess it right.933if (e <= outBuff.length - 1) {
934// If breaking lines and the last byte falls right at935// the line length (76 bytes per line), there will be936// one extra byte, and the array will need to be resized.937// Not too bad of an estimate on array size, I'd say.938 byte[] finalOut = new byte[e];
939 System.arraycopy(outBuff, 0, finalOut, 0, e);
940// System.err.println("Having to resize array from " +941// outBuff.length + " to " + e );942return finalOut;
943 } else {
944// System.err.println("No need to resize array.");945return outBuff;
946 }
947948 } // end else: don't compress949950 } // end encodeBytesToBytes951952/* ******** D E C O D I N G M E T H O D S ******** */953954/**955 * Decodes four bytes from array <var>source</var> and writes the resulting956 * bytes (up to three of them) to <var>destination</var>. The source and957 * destination arrays can be manipulated anywhere along their length by958 * specifying <var>srcOffset</var> and <var>destOffset</var>. This method959 * does not check to make sure your arrays are large enough to accomodate960 * <var>srcOffset</var> + 4 for the <var>source</var> array or961 * <var>destOffset</var> + 3 for the <var>destination</var> array. This962 * method returns the actual number of bytes that were converted from the963 * Base64 encoding.964 * <p>965 * This is the lowest level of the decoding methods with all possible966 * parameters.967 * </p>968 * 969 * 970 * @param source971 * the array to convert972 * @param srcOffset973 * the index where conversion begins974 * @param destination975 * the array to hold the conversion976 * @param destOffset977 * the index where output will be put978 * @param options979 * alphabet type is pulled from this (standard, url-safe,980 * ordered)981 * @return the number of decoded bytes converted982 * @throws NullPointerException983 * if source or destination arrays are null984 * @throws IllegalArgumentException985 * if srcOffset or destOffset are invalid or there is not enough986 * room in the array.987 * @since 1.3988 */989privatestaticint decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset, int options) {
990991// Lots of error checking and exception throwing992if (source == null) {
993thrownew NullPointerException("Source array was null.");
994 } // end if995if (destination == null) {
996thrownew NullPointerException("Destination array was null.");
997 } // end if998if (srcOffset < 0 || srcOffset + 3 >= source.length) {
999thrownew IllegalArgumentException(String.format(
1000"Source array with length %d cannot have offset of %d and still process four bytes.",
1001 source.length, srcOffset));
1002 } // end if1003if (destOffset < 0 || destOffset + 2 >= destination.length) {
1004thrownew IllegalArgumentException(String.format(
1005"Destination array with length %d cannot have offset of %d and still store three bytes.",
1006 destination.length, destOffset));
1007 } // end if10081009 byte[] DECODABET = getDecodabet(options);
10101011// Example: Dk==1012if (source[srcOffset + 2] == EQUALS_SIGN) {
1013// Two ways to do the same thing. Don't know which way I like best.1014// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 61015// )1016// | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );1017int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
1018 | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
10191020 destination[destOffset] = (byte) (outBuff >>> 16);
1021return 1;
1022 }
10231024// Example: DkL=1025elseif (source[srcOffset + 3] == EQUALS_SIGN) {
1026// Two ways to do the same thing. Don't know which way I like best.1027// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 61028// )1029// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )1030// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );1031int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
1032 | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
1033 | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
10341035 destination[destOffset] = (byte) (outBuff >>> 16);
1036 destination[destOffset + 1] = (byte) (outBuff >>> 8);
1037return 2;
1038 }
10391040// Example: DkLE1041else {
1042// Two ways to do the same thing. Don't know which way I like best.1043// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 61044// )1045// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )1046// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )1047// | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );1048int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
1049 | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
1050 | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF));
10511052 destination[destOffset] = (byte) (outBuff >> 16);
1053 destination[destOffset + 1] = (byte) (outBuff >> 8);
1054 destination[destOffset + 2] = (byte) (outBuff);
10551056return 3;
1057 }
1058 } // end decodeToBytes10591060/**1061 * Low-level access to decoding ASCII characters in the form of a byte1062 * array. <strong>Ignores GUNZIP option, if it's set.</strong> This is not1063 * generally a recommended method, although it is used internally as part of1064 * the decoding process. Special case: if len = 0, an empty array is1065 * returned. Still, if you need more speed and reduced memory footprint (and1066 * aren't gzipping), consider this method.1067 * 1068 * @param source1069 * The Base64 encoded data1070 * @return decoded data1071 * @since 2.3.11072 */1073publicstatic byte[] decode(byte[] source) throws java.io.IOException {
1074 byte[] decoded = null;
1075// try {1076 decoded = decode(source, 0, source.length, Base64.NO_OPTIONS);
1077// } catch( java.io.IOException ex ) {1078// assert false :1079// "IOExceptions only come from GZipping, which is turned off: " +1080// ex.getMessage();1081// }1082return decoded;
1083 }
10841085/**1086 * Low-level access to decoding ASCII characters in the form of a byte1087 * array. <strong>Ignores GUNZIP option, if it's set.</strong> This is not1088 * generally a recommended method, although it is used internally as part of1089 * the decoding process. Special case: if len = 0, an empty array is1090 * returned. Still, if you need more speed and reduced memory footprint (and1091 * aren't gzipping), consider this method.1092 * 1093 * @param source1094 * The Base64 encoded data1095 * @param off1096 * The offset of where to begin decoding1097 * @param len1098 * The length of characters to decode1099 * @param options1100 * Can specify options such as alphabet type to use1101 * @return decoded data1102 * @throws java.io.IOException1103 * If bogus characters exist in source data1104 * @since 1.31105 */1106publicstatic byte[] decode(byte[] source, int off, int len, int options) throws java.io.IOException {
11071108// Lots of error checking and exception throwing1109if (source == null) {
1110thrownew NullPointerException("Cannot decode null source array.");
1111 } // end if1112if (off < 0 || off + len > source.length) {
1113thrownew IllegalArgumentException(String.format(
1114"Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off,
1115 len));
1116 } // end if11171118if (len == 0) {
1119returnnew byte[0];
1120 } elseif (len < 4) {
1121thrownew IllegalArgumentException(
1122"Base64-encoded string must have at least four characters, but length specified was " + len);
1123 } // end if11241125 byte[] DECODABET = getDecodabet(options);
11261127int len34 = len * 3 / 4; // Estimate on array size1128 byte[] outBuff = new byte[len34]; // Upper limit on size of output1129int outBuffPosn = 0; // Keep track of where we're writing11301131 byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating1132// white space1133int b4Posn = 0; // Keep track of four byte input buffer1134int i = 0; // Source array counter1135 byte sbiDecode = 0; // Special value from DECODABET11361137for (i = off; i < off + len; i++) { // Loop through source11381139 sbiDecode = DECODABET[source[i] & 0xFF];
11401141// White space, Equals sign, or legit Base64 character1142// Note the values such as -5 and -9 in the1143// DECODABETs at the top of the file.1144if (sbiDecode >= WHITE_SPACE_ENC) {
1145if (sbiDecode >= EQUALS_SIGN_ENC) {
1146 b4[b4Posn++] = source[i]; // Save non-whitespace1147if (b4Posn > 3) { // Time to decode?1148 outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options);
1149 b4Posn = 0;
11501151// If that was the equals sign, break out of 'for' loop1152if (source[i] == EQUALS_SIGN) {
1153break;
1154 } // end if: equals sign1155 } // end if: quartet built1156 } // end if: equals sign or better1157 } // end if: white space, equals sign or better1158else {
1159// There's a bad input character in the Base64 stream.1160thrownew java.io.IOException(String.format(
1161"Bad Base64 input character decimal %d in array position %d", ((int) source[i]) & 0xFF, i));
1162 } // end else:1163 } // each input character11641165 byte[] out = new byte[outBuffPosn];
1166 System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
1167return out;
1168 } // end decode11691170/**1171 * Decodes data from Base64 notation, automatically detecting1172 * gzip-compressed data and decompressing it.1173 * 1174 * @param s1175 * the string to decode1176 * @return the decoded data1177 * @throws java.io.IOException1178 * If there is a problem1179 * @since 1.41180 */1181publicstatic byte[] decode(String s) throws java.io.IOException {
1182return decode(s, NO_OPTIONS);
1183 }
11841185/**1186 * Decodes data from Base64 notation, automatically detecting1187 * gzip-compressed data and decompressing it.1188 * 1189 * @param s1190 * the string to decode1191 * @param options1192 * encode options such as URL_SAFE1193 * @return the decoded data1194 * @throws java.io.IOException1195 * if there is an error1196 * @throws NullPointerException1197 * if <tt>s</tt> is null1198 * @since 1.41199 */1200publicstatic byte[] decode(String s, int options) throws java.io.IOException {
12011202if (s == null) {
1203thrownew NullPointerException("Input string was null.");
1204 } // end if12051206 byte[] bytes;
1207try {
1208 bytes = s.getBytes(PREFERRED_ENCODING);
1209 } // end try1210catch (java.io.UnsupportedEncodingException uee) {
1211 bytes = s.getBytes();
1212 } // end catch1213// </change>12141215// Decode1216 bytes = decode(bytes, 0, bytes.length, options);
12171218// Check to see if it's gzip-compressed1219// GZIP Magic Two-Byte Number: 0x8b1f (35615)1220boolean dontGunzip = (options & DONT_GUNZIP) != 0;
1221if ((bytes != null) && (bytes.length >= 4) && (!dontGunzip)) {
12221223int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
1224if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) {
1225 java.io.ByteArrayInputStream bais = null;
1226 java.util.zip.GZIPInputStream gzis = null;
1227 java.io.ByteArrayOutputStream baos = null;
1228 byte[] buffer = new byte[2048];
1229int length = 0;
12301231try {
1232 baos = new java.io.ByteArrayOutputStream();
1233 bais = new java.io.ByteArrayInputStream(bytes);
1234 gzis = new java.util.zip.GZIPInputStream(bais);
12351236while ((length = gzis.read(buffer)) >= 0) {
1237 baos.write(buffer, 0, length);
1238 } // end while: reading input12391240// No error? Get new bytes.1241 bytes = baos.toByteArray();
12421243 } // end try1244catch (java.io.IOException e) {
1245 e.printStackTrace();
1246// Just return originally-decoded bytes1247 } // end catch1248finally {
1249try {
1250 baos.close();
1251 } catch (Exception e) {
1252 }
1253try {
1254 gzis.close();
1255 } catch (Exception e) {
1256 }
1257try {
1258 bais.close();
1259 } catch (Exception e) {
1260 }
1261 } // end finally12621263 } // end if: gzipped1264 } // end if: bytes.length >= 212651266return bytes;
1267 } // end decode12681269/**1270 * Attempts to decode Base64 data and deserialize a Java Object within.1271 * Returns <tt>null</tt> if there was an error.1272 * 1273 * @param encodedObject1274 * The Base64 data to decode1275 * @return The decoded and deserialized object1276 * @throws NullPointerException1277 * if encodedObject is null1278 * @throws java.io.IOException1279 * if there is a general error1280 * @throws ClassNotFoundException1281 * if the decoded object is of a class that cannot be found by1282 * the JVM1283 * @since 1.51284 */1285publicstatic Object decodeToObject(String encodedObject) throws java.io.IOException,
1286 java.lang.ClassNotFoundException {
1287return decodeToObject(encodedObject, NO_OPTIONS, null);
1288 }
12891290/**1291 * Attempts to decode Base64 data and deserialize a Java Object within.1292 * Returns <tt>null</tt> if there was an error. If <tt>loader</tt> is not1293 * null, it will be the class loader used when deserializing.1294 * 1295 * @param encodedObject1296 * The Base64 data to decode1297 * @param options1298 * Various parameters related to decoding1299 * @param loader1300 * Optional class loader to use in deserializing classes.1301 * @return The decoded and deserialized object1302 * @throws NullPointerException1303 * if encodedObject is null1304 * @throws java.io.IOException1305 * if there is a general error1306 * @throws ClassNotFoundException1307 * if the decoded object is of a class that cannot be found by1308 * the JVM1309 * @since 2.3.41310 */1311publicstatic Object decodeToObject(String encodedObject, int options, final ClassLoader loader)
1312throws java.io.IOException, java.lang.ClassNotFoundException {
13131314// Decode and gunzip if necessary1315 byte[] objBytes = decode(encodedObject, options);
13161317 java.io.ByteArrayInputStream bais = null;
1318 java.io.ObjectInputStream ois = null;
1319 Object obj = null;
13201321try {
1322 bais = new java.io.ByteArrayInputStream(objBytes);
13231324// If no custom class loader is provided, use Java's builtin OIS.1325if (loader == null) {
1326 ois = new java.io.ObjectInputStream(bais);
1327 } // end if: no loader provided13281329// Else make a customized object input stream that uses1330// the provided class loader.1331else {
1332 ois = new java.io.ObjectInputStream(bais) {
1333 @Override
1334public Class<?> resolveClass(java.io.ObjectStreamClass streamClass) throws java.io.IOException,
1335 ClassNotFoundException {
1336 Class<?> c = Class.forName(streamClass.getName(), false, loader);
1337if (c == null) {
1338returnsuper.resolveClass(streamClass);
1339 } else {
1340return c; // Class loader knows of this class.1341 } // end else: not null1342 } // end resolveClass1343 }; // end ois1344 } // end else: no custom class loader13451346 obj = ois.readObject();
1347 } // end try1348catch (java.io.IOException e) {
1349throw e; // Catch and throw in order to execute finally{}1350 } // end catch1351catch (java.lang.ClassNotFoundException e) {
1352throw e; // Catch and throw in order to execute finally{}1353 } // end catch1354finally {
1355try {
1356 bais.close();
1357 } catch (Exception e) {
1358 }
1359try {
1360 ois.close();
1361 } catch (Exception e) {
1362 }
1363 } // end finally13641365return obj;
1366 } // end decodeObject13671368/**1369 * Convenience method for encoding data to a file.1370 * 1371 * <p>1372 * As of v 2.3, if there is a error, the method will throw an1373 * java.io.IOException. <b>This is new to v2.3!</b> In earlier versions, it1374 * just returned false, but in retrospect that's a pretty poor way to handle1375 * it.1376 * </p>1377 * 1378 * @param dataToEncode1379 * byte array of data to encode in base64 form1380 * @param filename1381 * Filename for saving encoded data1382 * @throws java.io.IOException1383 * if there is an error1384 * @throws NullPointerException1385 * if dataToEncode is null1386 * @since 2.11387 */1388publicstaticvoid encodeToFile(byte[] dataToEncode, String filename) throws java.io.IOException {
13891390if (dataToEncode == null) {
1391thrownew NullPointerException("Data to encode was null.");
1392 } // end iff13931394 Base64.OutputStream bos = null;
1395try {
1396 bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.ENCODE);
1397 bos.write(dataToEncode);
1398 } // end try1399catch (java.io.IOException e) {
1400throw e; // Catch and throw to execute finally{} block1401 } // end catch: java.io.IOException1402finally {
1403try {
1404 bos.close();
1405 } catch (Exception e) {
1406 }
1407 } // end finally14081409 } // end encodeToFile14101411/**1412 * Convenience method for decoding data to a file.1413 * 1414 * <p>1415 * As of v 2.3, if there is a error, the method will throw an1416 * java.io.IOException. <b>This is new to v2.3!</b> In earlier versions, it1417 * just returned false, but in retrospect that's a pretty poor way to handle1418 * it.1419 * </p>1420 * 1421 * @param dataToDecode1422 * Base64-encoded data as a string1423 * @param filename1424 * Filename for saving decoded data1425 * @throws java.io.IOException1426 * if there is an error1427 * @since 2.11428 */1429publicstaticvoid decodeToFile(String dataToDecode, String filename) throws java.io.IOException {
14301431 Base64.OutputStream bos = null;
1432try {
1433 bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.DECODE);
1434 bos.write(dataToDecode.getBytes(PREFERRED_ENCODING));
1435 } // end try1436catch (java.io.IOException e) {
1437throw e; // Catch and throw to execute finally{} block1438 } // end catch: java.io.IOException1439finally {
1440try {
1441 bos.close();
1442 } catch (Exception e) {
1443 }
1444 } // end finally14451446 } // end decodeToFile14471448/**1449 * Convenience method for reading a base64-encoded file and decoding it.1450 * 1451 * <p>1452 * As of v 2.3, if there is a error, the method will throw an1453 * java.io.IOException. <b>This is new to v2.3!</b> In earlier versions, it1454 * just returned false, but in retrospect that's a pretty poor way to handle1455 * it.1456 * </p>1457 * 1458 * @param filename1459 * Filename for reading encoded data1460 * @return decoded byte array1461 * @throws java.io.IOException1462 * if there is an error1463 * @since 2.11464 */1465publicstatic byte[] decodeFromFile(String filename) throws java.io.IOException {
14661467 byte[] decodedData = null;
1468 Base64.InputStream bis = null;
1469try {
1470// Set up some useful variables1471 java.io.File file = new java.io.File(filename);
1472 byte[] buffer = null;
1473int length = 0;
1474int numBytes = 0;
14751476// Check for size of file1477if (file.length() > Integer.MAX_VALUE) {
1478thrownew java.io.IOException("File is too big for this convenience method (" + file.length()
1479 + " bytes).");
1480 } // end if: file too big for int index1481 buffer = new byte[(int) file.length()];
14821483// Open a stream1484 bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)),
1485 Base64.DECODE);
14861487// Read until done1488while ((numBytes = bis.read(buffer, length, 4096)) >= 0) {
1489 length += numBytes;
1490 } // end while14911492// Save in a variable to return1493 decodedData = new byte[length];
1494 System.arraycopy(buffer, 0, decodedData, 0, length);
14951496 } // end try1497catch (java.io.IOException e) {
1498throw e; // Catch and release to execute finally{}1499 } // end catch: java.io.IOException1500finally {
1501try {
1502 bis.close();
1503 } catch (Exception e) {
1504 }
1505 } // end finally15061507return decodedData;
1508 } // end decodeFromFile15091510/**1511 * Convenience method for reading a binary file and base64-encoding it.1512 * 1513 * <p>1514 * As of v 2.3, if there is a error, the method will throw an1515 * java.io.IOException. <b>This is new to v2.3!</b> In earlier versions, it1516 * just returned false, but in retrospect that's a pretty poor way to handle1517 * it.1518 * </p>1519 * 1520 * @param filename1521 * Filename for reading binary data1522 * @return base64-encoded string1523 * @throws java.io.IOException1524 * if there is an error1525 * @since 2.11526 */1527publicstatic String encodeFromFile(String filename) throws java.io.IOException {
15281529 String encodedData = null;
1530 Base64.InputStream bis = null;
1531try {
1532// Set up some useful variables1533 java.io.File file = new java.io.File(filename);
1534 byte[] buffer = new byte[Math.max((int) (file.length() * 1.4 + 1), 40)]; // Need1535// max()1536// for1537// math1538// on1539// small1540// files1541// (v2.2.1);1542// Need1543// +11544// for1545// a1546// few1547// corner1548// cases1549// (v2.3.5)1550int length = 0;
1551int numBytes = 0;
15521553// Open a stream1554 bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)),
1555 Base64.ENCODE);
15561557// Read until done1558while ((numBytes = bis.read(buffer, length, 4096)) >= 0) {
1559 length += numBytes;
1560 } // end while15611562// Save in a variable to return1563 encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING);
15641565 } // end try1566catch (java.io.IOException e) {
1567throw e; // Catch and release to execute finally{}1568 } // end catch: java.io.IOException1569finally {
1570try {
1571 bis.close();
1572 } catch (Exception e) {
1573 }
1574 } // end finally15751576return encodedData;
1577 } // end encodeFromFile15781579/**1580 * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.1581 * 1582 * @param infile1583 * Input file1584 * @param outfile1585 * Output file1586 * @throws java.io.IOException1587 * if there is an error1588 * @since 2.21589 */1590publicstaticvoid encodeFileToFile(String infile, String outfile) throws java.io.IOException {
15911592 String encoded = Base64.encodeFromFile(infile);
1593 java.io.OutputStream out = null;
1594try {
1595 out = new java.io.BufferedOutputStream(new java.io.FileOutputStream(outfile));
1596 out.write(encoded.getBytes("US-ASCII")); // Strict, 7-bit output.1597 } // end try1598catch (java.io.IOException e) {
1599throw e; // Catch and release to execute finally{}1600 } // end catch1601finally {
1602try {
1603 out.close();
1604 } catch (Exception ex) {
1605 }
1606 } // end finally1607 } // end encodeFileToFile16081609/**1610 * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.1611 * 1612 * @param infile1613 * Input file1614 * @param outfile1615 * Output file1616 * @throws java.io.IOException1617 * if there is an error1618 * @since 2.21619 */1620publicstaticvoid decodeFileToFile(String infile, String outfile) throws java.io.IOException {
16211622 byte[] decoded = Base64.decodeFromFile(infile);
1623 java.io.OutputStream out = null;
1624try {
1625 out = new java.io.BufferedOutputStream(new java.io.FileOutputStream(outfile));
1626 out.write(decoded);
1627 } // end try1628catch (java.io.IOException e) {
1629throw e; // Catch and release to execute finally{}1630 } // end catch1631finally {
1632try {
1633 out.close();
1634 } catch (Exception ex) {
1635 }
1636 } // end finally1637 } // end decodeFileToFile16381639/* ******** I N N E R C L A S S I N P U T S T R E A M ******** */16401641/**1642 * A {@link Base64.InputStream} will read data from another1643 * <tt>java.io.InputStream</tt>, given in the constructor, and encode/decode1644 * to/from Base64 notation on the fly.1645 * 1646 * @see Base641647 * @since 1.31648 */1649publicstaticclassInputStreamextends java.io.FilterInputStream {
16501651privateboolean encode; // Encoding or decoding1652privateint position; // Current position in the buffer1653private byte[] buffer; // Small buffer holding converted data1654privateint bufferLength; // Length of buffer (3 or 4)1655privateint numSigBytes; // Number of meaningful bytes in the buffer1656privateint lineLength;
1657privateboolean breakLines; // Break lines at less than 80 characters1658privateint options; // Record options used to create the stream.1659private byte[] decodabet; // Local copies to avoid extra method calls16601661/**1662 * Constructs a {@link Base64.InputStream} in DECODE mode.1663 * 1664 * @param in1665 * the <tt>java.io.InputStream</tt> from which to read data.1666 * @since 1.31667 */1668publicInputStream(java.io.InputStream in) {
1669this(in, DECODE);
1670 } // end constructor16711672/**1673 * Constructs a {@link Base64.InputStream} in either ENCODE or DECODE1674 * mode.1675 * <p>1676 * Valid options:1677 * 1678 * <pre>1679 * ENCODE or DECODE: Encode or Decode as data is read.1680 * DO_BREAK_LINES: break lines at 76 characters1681 * (only meaningful when encoding)</i>1682 * </pre>1683 * <p>1684 * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>1685 * 1686 * 1687 * @param in1688 * the <tt>java.io.InputStream</tt> from which to read data.1689 * @param options1690 * Specified options1691 * @see Base64#ENCODE1692 * @see Base64#DECODE1693 * @see Base64#DO_BREAK_LINES1694 * @since 2.01695 */1696publicInputStream(java.io.InputStream in, int options) {
16971698super(in);
1699this.options = options; // Record for later1700this.breakLines = (options & DO_BREAK_LINES) > 0;
1701this.encode = (options & ENCODE) > 0;
1702this.bufferLength = encode ? 4 : 3;
1703this.buffer = new byte[bufferLength];
1704this.position = -1;
1705this.lineLength = 0;
1706this.decodabet = getDecodabet(options);
1707 } // end constructor17081709/**1710 * Reads enough of the input stream to convert to/from Base64 and1711 * returns the next byte.1712 * 1713 * @return next byte1714 * @since 1.31715 */1716 @Override
1717publicint read() throws java.io.IOException {
17181719// Do we need to get data?1720if (position < 0) {
1721if (encode) {
1722 byte[] b3 = new byte[3];
1723int numBinaryBytes = 0;
1724for (int i = 0; i < 3; i++) {
1725int b = in.read();
17261727// If end of stream, b is -1.1728if (b >= 0) {
1729 b3[i] = (byte) b;
1730 numBinaryBytes++;
1731 } else {
1732break; // out of for loop1733 } // end else: end of stream17341735 } // end for: each needed input byte17361737if (numBinaryBytes > 0) {
1738 encode3to4(b3, 0, numBinaryBytes, buffer, 0, options);
1739 position = 0;
1740 numSigBytes = 4;
1741 } // end if: got data1742else {
1743return -1; // Must be end of stream1744 } // end else1745 } // end if: encoding17461747// Else decoding1748else {
1749 byte[] b4 = new byte[4];
1750int i = 0;
1751for (i = 0; i < 4; i++) {
1752// Read four "meaningful" bytes:1753int b = 0;
1754do {
1755 b = in.read();
1756 } while (b >= 0 && decodabet[b & 0x7f] <= WHITE_SPACE_ENC);
17571758if (b < 0) {
1759break; // Reads a -1 if end of stream1760 } // end if: end of stream17611762 b4[i] = (byte) b;
1763 } // end for: each needed input byte17641765if (i == 4) {
1766 numSigBytes = decode4to3(b4, 0, buffer, 0, options);
1767 position = 0;
1768 } // end if: got four characters1769elseif (i == 0) {
1770return -1;
1771 } // end else if: also padded correctly1772else {
1773// Must have broken out from above.1774thrownew java.io.IOException("Improperly padded Base64 input.");
1775 } // end17761777 } // end else: decode1778 } // end else: get data17791780// Got data?1781if (position >= 0) {
1782// End of relevant data?1783if ( /* !encode && */position >= numSigBytes) {1784return -1;
1785 } // end if: got data17861787if (encode && breakLines && lineLength >= MAX_LINE_LENGTH) {
1788 lineLength = 0;
1789return '\n';
1790 } // end if1791else {
1792 lineLength++; // This isn't important when decoding1793// but throwing an extra "if" seems1794// just as wasteful.17951796int b = buffer[position++];
17971798if (position >= bufferLength) {
1799 position = -1;
1800 } // end if: end18011802return b & 0xFF; // This is how you "cast" a byte that's1803// intended to be unsigned.1804 } // end else1805 } // end if: position >= 018061807// Else error1808else {
1809thrownew java.io.IOException("Error in Base64 code reading stream.");
1810 } // end else1811 } // end read18121813/**1814 * Calls {@link #read()} repeatedly until the end of stream is reached1815 * or <var>len</var> bytes are read. Returns number of bytes read into1816 * array or -1 if end of stream is encountered.1817 * 1818 * @param dest1819 * array to hold values1820 * @param off1821 * offset for array1822 * @param len1823 * max number of bytes to read into array1824 * @return bytes read into array or -1 if end of stream is encountered.1825 * @since 1.31826 */1827 @Override
1828publicint read(byte[] dest, int off, int len) throws java.io.IOException {
1829int i;
1830int b;
1831for (i = 0; i < len; i++) {
1832 b = read();
18331834if (b >= 0) {
1835 dest[off + i] = (byte) b;
1836 } elseif (i == 0) {
1837return -1;
1838 } else {
1839break; // Out of 'for' loop1840 } // Out of 'for' loop1841 } // end for: each byte read1842return i;
1843 } // end read18441845 } // end inner class InputStream18461847/* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */18481849/**1850 * A {@link Base64.OutputStream} will write data to another1851 * <tt>java.io.OutputStream</tt>, given in the constructor, and1852 * encode/decode to/from Base64 notation on the fly.1853 * 1854 * @see Base641855 * @since 1.31856 */1857publicstaticclassOutputStreamextends java.io.FilterOutputStream {
18581859privateboolean encode;
1860privateint position;
1861private byte[] buffer;
1862privateint bufferLength;
1863privateint lineLength;
1864privateboolean breakLines;
1865private byte[] b4; // Scratch used in a few places1866privateboolean suspendEncoding;
1867privateint options; // Record for later1868private byte[] decodabet; // Local copies to avoid extra method calls18691870/**1871 * Constructs a {@link Base64.OutputStream} in ENCODE mode.1872 * 1873 * @param out1874 * the <tt>java.io.OutputStream</tt> to which data will be1875 * written.1876 * @since 1.31877 */1878publicOutputStream(java.io.OutputStream out) {
1879this(out, ENCODE);
1880 } // end constructor18811882/**1883 * Constructs a {@link Base64.OutputStream} in either ENCODE or DECODE1884 * mode.1885 * <p>1886 * Valid options:1887 * 1888 * <pre>1889 * ENCODE or DECODE: Encode or Decode as data is read.1890 * DO_BREAK_LINES: don't break lines at 76 characters1891 * (only meaningful when encoding)</i>1892 * </pre>1893 * <p>1894 * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>1895 * 1896 * @param out1897 * the <tt>java.io.OutputStream</tt> to which data will be1898 * written.1899 * @param options1900 * Specified options.1901 * @see Base64#ENCODE1902 * @see Base64#DECODE1903 * @see Base64#DO_BREAK_LINES1904 * @since 1.31905 */1906publicOutputStream(java.io.OutputStream out, int options) {
1907super(out);
1908this.breakLines = (options & DO_BREAK_LINES) != 0;
1909this.encode = (options & ENCODE) != 0;
1910this.bufferLength = encode ? 3 : 4;
1911this.buffer = new byte[bufferLength];
1912this.position = 0;
1913this.lineLength = 0;
1914this.suspendEncoding = false;
1915this.b4 = new byte[4];
1916this.options = options;
1917this.decodabet = getDecodabet(options);
1918 } // end constructor19191920/**1921 * Writes the byte to the output stream after converting to/from Base641922 * notation. When encoding, bytes are buffered three at a time before1923 * the output stream actually gets a write() call. When decoding, bytes1924 * are buffered four at a time.1925 * 1926 * @param theByte1927 * the byte to write1928 * @since 1.31929 */1930 @Override
1931publicvoid write(int theByte) throws java.io.IOException {
1932// Encoding suspended?1933if (suspendEncoding) {
1934this.out.write(theByte);
1935return;
1936 } // end if: supsended19371938// Encode?1939if (encode) {
1940 buffer[position++] = (byte) theByte;
1941if (position >= bufferLength) { // Enough to encode.19421943this.out.write(encode3to4(b4, buffer, bufferLength, options));
19441945 lineLength += 4;
1946if (breakLines && lineLength >= MAX_LINE_LENGTH) {
1947this.out.write(NEW_LINE);
1948 lineLength = 0;
1949 } // end if: end of line19501951 position = 0;
1952 } // end if: enough to output1953 } // end if: encoding19541955// Else, Decoding1956else {
1957// Meaningful Base64 character?1958if (decodabet[theByte & 0x7f] > WHITE_SPACE_ENC) {
1959 buffer[position++] = (byte) theByte;
1960if (position >= bufferLength) { // Enough to output.19611962int len = Base64.decode4to3(buffer, 0, b4, 0, options);
1963 out.write(b4, 0, len);
1964 position = 0;
1965 } // end if: enough to output1966 } // end if: meaningful base64 character1967elseif (decodabet[theByte & 0x7f] != WHITE_SPACE_ENC) {
1968thrownew java.io.IOException("Invalid character in Base64 data.");
1969 } // end else: not white space either1970 } // end else: decoding1971 } // end write19721973/**1974 * Calls {@link #write(int)} repeatedly until <var>len</var> bytes are1975 * written.1976 * 1977 * @param theBytes1978 * array from which to read bytes1979 * @param off1980 * offset for array1981 * @param len1982 * max number of bytes to read into array1983 * @since 1.31984 */1985 @Override
1986publicvoid write(byte[] theBytes, int off, int len) throws java.io.IOException {
1987// Encoding suspended?1988if (suspendEncoding) {
1989this.out.write(theBytes, off, len);
1990return;
1991 } // end if: supsended19921993for (int i = 0; i < len; i++) {
1994 write(theBytes[off + i]);
1995 } // end for: each byte written19961997 } // end write19981999/**2000 * Method added by PHIL. [Thanks, PHIL. -Rob] This pads the buffer2001 * without closing the stream.2002 * 2003 * @throws java.io.IOException2004 * if there's an error.2005 */2006publicvoid flushBase64() throws java.io.IOException {
2007if (position > 0) {
2008if (encode) {
2009 out.write(encode3to4(b4, buffer, position, options));
2010 position = 0;
2011 } // end if: encoding2012else {
2013thrownew java.io.IOException("Base64 input not properly padded.");
2014 } // end else: decoding2015 } // end if: buffer partially full20162017 } // end flush20182019/**2020 * Flushes and closes (I think, in the superclass) the stream.2021 * 2022 * @since 1.32023 */2024 @Override
2025publicvoid close() throws java.io.IOException {
2026// 1. Ensure that pending characters are written2027 flushBase64();
20282029// 2. Actually close the stream2030// Base class both flushes and closes.2031super.close();
20322033 buffer = null;
2034 out = null;
2035 } // end close20362037/**2038 * Suspends encoding of the stream. May be helpful if you need to embed2039 * a piece of base64-encoded data in a stream.2040 * 2041 * @throws java.io.IOException2042 * if there's an error flushing2043 * @since 1.5.12044 */2045publicvoid suspendEncoding() throws java.io.IOException {
2046 flushBase64();
2047this.suspendEncoding = true;
2048 } // end suspendEncoding20492050/**2051 * Resumes encoding of the stream. May be helpful if you need to embed a2052 * piece of base64-encoded data in a stream.2053 * 2054 * @since 1.5.12055 */2056publicvoid resumeEncoding() {
2057this.suspendEncoding = false;
2058 } // end resumeEncoding20592060 } // end inner class OutputStream20612062 } // end class Base64