All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.icefaces.impl.util.Base64 Maven / Gradle / Ivy

There is a newer version: 4.3.0
Show newest version
/*
 * Copyright 2004-2014 ICEsoft Technologies Canada Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS
 * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package org.icefaces.impl.util;

/**
 * This Base64 is a utility class for encoding using the Base64
 * encoding. 

*

* The Base64 encoding is designed to represent arbitrary sequences of octets in * a form that need to be humanly readable. The encoding and decoding algorithms * are simple, but the encoded data are consitently only about 33% larger than * the unencoded data.

*

* For more complete information about the Base64 encoding, please read MIME (Multipurpose * Internet Mail Extensions) Part One (Section 5.2).

*/ public class Base64 { private static final byte[] BASE64_ALPHABET_ARRAY = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; private static final byte[] BASE64_FOR_URL_ALPHABET_ARRAY = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' }; private static final byte PAD = '='; /** * Encodes the specified bytes using the Base64 encoding.

* * @param bytes the bytes to be encoded. * @return the Base64-encoded bytes. * @see #encode(String) */ public static byte[] encode(byte[] bytes) { return encode(bytes, BASE64_ALPHABET_ARRAY, true); } /** * Encodes the specified string using the Base64 encoding.

* * @param string the string to be encoded. * @return the Base64-encoded string. * @see #encode(byte[]) */ public static String encode(String string) { if (string == null) { return null; } return new String(encode(string.getBytes())); } /** * Encodes the specified bytes using the Base64 encoding for * URL usage.

* * @param bytes the bytes to be encoded. * @return the Base64-encoded bytes for URL usage. */ public static byte[] encodeForURL(byte[] bytes) { return encode(bytes, BASE64_FOR_URL_ALPHABET_ARRAY, false); } private static byte[] encode( byte[] bytes, byte[] alphabetArray, boolean usePadding) { if (bytes == null) { return null; } else if (bytes.length == 0) { return bytes; } int _length = bytes.length; int _remainder = _length % 3; byte[] _bytes; if (usePadding) { _bytes = new byte[(_length + 2) / 3 * 4]; } else { _bytes = new byte[ ((_length + 2) / 3 * 4) - (_remainder != 0 ? 3 - _remainder : 0)]; } _length -= _remainder; int _group; int _i; int _index = 0; for (_i = 0; _i < _length;) { _group = (bytes[_i++] & 0xFF) << 16 | (bytes[_i++] & 0xFF) << 8 | bytes[_i++] & 0xFF; _bytes[_index++] = alphabetArray[_group >>> 18]; _bytes[_index++] = alphabetArray[_group >>> 12 & 0x3F]; _bytes[_index++] = alphabetArray[_group >>> 6 & 0x3F]; _bytes[_index++] = alphabetArray[_group & 0x3F]; } switch (_remainder) { case 0: break; case 1: _group = (bytes[_i] & 0xFF) << 4; _bytes[_index++] = alphabetArray[_group >>> 6]; if (usePadding) { _bytes[_index++] = alphabetArray[_group & 0x3F]; _bytes[_index++] = PAD; _bytes[_index] = PAD; } else { _bytes[_index] = alphabetArray[_group & 0x3F]; } break; case 2: _group = ((bytes[_i++] & 0xFF) << 8 | (bytes[_i] & 0xFF)) << 2; _bytes[_index++] = alphabetArray[_group >>> 12]; _bytes[_index++] = alphabetArray[_group >>> 6 & 0x3F]; if (usePadding) { _bytes[_index++] = alphabetArray[_group & 0x3F]; _bytes[_index] = PAD; } else { _bytes[_index] = alphabetArray[_group & 0x3F]; } break; default: // this should never happen. } return _bytes; } // // Base64 decoding utility, extracted from Apache Commons Codec 1.8 // private static final int DECODE_SIZE = 3; private static final int BYTES_PER_ENCODED_BLOCK = 4; private static final int BITS_PER_ENCODED_BYTE = 6; private static final int MASK_8BITS = 0xff; private static final int EOF = -1; private static final byte[] DECODE_TABLE = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; public static byte[] decode(final String pArray) { return decode(getBytesUtf8(pArray)); } public static byte[] decode(final byte[] pArray) { if (pArray == null || pArray.length == 0) { return pArray; } final Context context = new Context(); decode(pArray, 0, pArray.length, context); decode(pArray, 0, EOF, context); // Notify decoder of EOF. final byte[] result = new byte[context.pos]; readResults(result, 0, result.length, context); return result; } private static void decode(final byte[] in, int inPos, final int inAvail, final Context context) { if (context.eof) { return; } if (inAvail < 0) { context.eof = true; } for (int i = 0; i < inAvail; i++) { final byte[] buffer = ensureBufferSize(DECODE_SIZE, context); final byte b = in[inPos++]; if (b == PAD) { // We're done. context.eof = true; break; } else { if (b >= 0 && b < DECODE_TABLE.length) { final int result = DECODE_TABLE[b]; if (result >= 0) { context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK; context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result; if (context.modulus == 0) { buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS); buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS); } } } } } // Two forms of EOF as far as base64 decoder is concerned: actual // EOF (-1) and first time '=' character is encountered in stream. // This approach makes the '=' padding characters completely optional. if (context.eof && context.modulus != 0) { final byte[] buffer = ensureBufferSize(DECODE_SIZE, context); // We have some spare bits remaining // Output all whole multiples of 8 bits and ignore the rest switch (context.modulus) { // case 0 : // impossible, as excluded above case 1 : // 6 bits - ignore entirely // TODO not currently tested; perhaps it is impossible? break; case 2 : // 12 bits = 8 + 4 context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); break; case 3 : // 18 bits = 8 + 8 + 2 context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); break; default: throw new IllegalStateException("Impossible modulus "+context.modulus); } } } private static byte[] ensureBufferSize(final int size, final Context context){ if ((context.buffer == null) || (context.buffer.length < context.pos + size)){ return resizeBuffer(context); } return context.buffer; } private static byte[] resizeBuffer(final Context context) { if (context.buffer == null) { context.buffer = new byte[8192]; context.pos = 0; context.readPos = 0; } else { final byte[] b = new byte[context.buffer.length * 2]; System.arraycopy(context.buffer, 0, b, 0, context.buffer.length); context.buffer = b; } return context.buffer; } private static int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) { if (context.buffer != null) { final int len = Math.min(available(context), bAvail); System.arraycopy(context.buffer, context.readPos, b, bPos, len); context.readPos += len; if (context.readPos >= context.pos) { context.buffer = null; // so hasData() will return false, and this method can return -1 } return len; } return context.eof ? EOF : 0; } private static int available(final Context context) { return context.buffer != null ? context.pos - context.readPos : 0; } private static byte[] getBytesUtf8(final String string) { byte[] bytes; try { bytes = string.getBytes("UTF-8"); } catch (java.io.UnsupportedEncodingException e) { bytes = new byte[0]; } return bytes; } private static class Context { int ibitWorkArea; long lbitWorkArea; byte[] buffer; int pos; int readPos; boolean eof; int currentLinePos; int modulus; Context() {} @SuppressWarnings("boxing") // OK to ignore boxing here @Override public String toString() { return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " + "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), java.util.Arrays.toString(buffer), currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy