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

org.eclipse.persistence.internal.oxm.conversion.Base64 Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*******************************************************************************
 * Copyright (c) 1998 -2014 Oracle and/or its affiliates. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     Oracle - initial API and implementation from Oracle TopLink
 ******************************************************************************/
package org.eclipse.persistence.internal.oxm.conversion;

import java.util.BitSet;

/**
 * INTERNAL: 
 * 

Purpose: Convert to/from XML base64Binary.

*/ public class Base64 { private static final byte[] Base64EncMap; private static final byte[] Base64DecMap; private static final byte PADDING = 127; // Class Initializer static { // rfc-2045: Base64 Alphabet Base64EncMap = initEncodeMap(); Base64DecMap = initDecodeMap(); } private static byte[] initEncodeMap() { byte[] map = new byte[64]; int i; for (i = 0; i < 26; i++) { map[i] = (byte) ('A' + i); } for (i = 26; i < 52; i++) { map[i] = (byte) ('a' + (i - 26)); } for (i = 52; i < 62; i++) { map[i] = (byte) ('0' + (i - 52)); } map[62] = '+'; map[63] = '/'; return map; } private static byte[] initDecodeMap() { byte[] map = new byte[128]; int i; for (i = 0; i < 128; i++) { map[i] = -1; } for (i = 'A'; i <= 'Z'; i++) { map[i] = (byte) (i - 'A'); } for (i = 'a'; i <= 'z'; i++) { map[i] = (byte) (i - 'a' + 26); } for (i = '0'; i <= '9'; i++) { map[i] = (byte) (i - '0' + 52); } map['+'] = 62; map['/'] = 63; map['='] = PADDING; return map; } /** * Base64 constructor comment. */ private Base64() { } /** * computes the length of binary data speculatively. * *

* Our requirement is to create byte[] of the exact length to store the binary data. * If we do this in a straight-forward way, it takes two passes over the data. * Experiments show that this is a non-trivial overhead (35% or so is spent on * the first pass in calculating the length.) * *

* So the approach here is that we compute the length speculatively, without looking * at the whole contents. The obtained speculative value is never less than the * actual length of the binary data, but it may be bigger. So if the speculation * goes wrong, we'll pay the cost of reallocation and buffer copying. * *

* If the base64 text is tightly packed with no indentation nor illegal char * (like what most web services produce), then the speculation of this method * will be correct, so we get the performance benefit. */ private static int guessLength(byte[] data) { final int len = data.length; // compute the tail '=' chars int j = len - 1; for (; j >= 0; j--) { byte code = Base64DecMap[data[j]]; if (code == PADDING) continue; if (code == -1) // most likely this base64 data is indented. go with the upper bound return data.length / 4 * 3; break; } j++; // data.charAt(j) is now at some base64 char, so +1 to make it the size int padSize = len - j; if (padSize > 2) // something is wrong with base64. be safe and go with the upper bound return data.length / 4 * 3; // so far this base64 looks like it's unindented tightly packed base64. // take a chance and create an array with the expected size return data.length / 4 * 3 - padSize; } /** * base64Binary data is likely to be long, and decoding requires * each character to be accessed twice (once for counting length, another * for decoding.) * * This method decodes the given byte[] using the base64-encoding * specified in RFC-2045 (Section 6.8). * * @param data the base64-encoded data. * @return the decoded data. */ public static byte[] base64Decode(byte[] data) { final int buflen = guessLength(data); final byte[] out = new byte[buflen]; int o = 0; final int len = data.length; int i; final byte[] quadruplet = new byte[4]; int q = 0; // convert each quadruplet to three bytes. for (i = 0; i < len; i++) { byte ch = data[i]; byte v = Base64DecMap[ch]; if (v != -1) quadruplet[q++] = v; if (q == 4) { // quadruplet is now filled. out[o++] = (byte) ((quadruplet[0] << 2) | (quadruplet[1] >> 4)); if (quadruplet[2] != PADDING) out[o++] = (byte) ((quadruplet[1] << 4) | (quadruplet[2] >> 2)); if (quadruplet[3] != PADDING) out[o++] = (byte) ((quadruplet[2] << 6) | (quadruplet[3])); q = 0; } } if (buflen == o) // speculation worked out to be OK return out; // we overestimated, so need to create a new buffer byte[] nb = new byte[o]; System.arraycopy(out, 0, nb, 0, o); return nb; } /** * This method encodes the given byte[] using the base64-encoding * specified in RFC-2045 (Section 6.8). * * @param data the data * @return the base64-encoded data */ public static byte[] base64Encode(byte[] data) { if (data == null) { return null; } int sidx; int didx; byte[] dest = new byte[((data.length + 2) / 3) * 4]; // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion for (sidx = 0, didx = 0; sidx < (data.length - 2); sidx += 3) { dest[didx++] = Base64EncMap[(data[sidx] >>> 2) & 077]; dest[didx++] = Base64EncMap[((data[sidx + 1] >>> 4) & 017) | ((data[sidx] << 4) & 077)]; dest[didx++] = Base64EncMap[((data[sidx + 2] >>> 6) & 003) | ((data[sidx + 1] << 2) & 077)]; dest[didx++] = Base64EncMap[data[sidx + 2] & 077]; } if (sidx < data.length) { dest[didx++] = Base64EncMap[(data[sidx] >>> 2) & 077]; if (sidx < (data.length - 1)) { dest[didx++] = Base64EncMap[((data[sidx + 1] >>> 4) & 017) | ((data[sidx] << 4) & 077)]; dest[didx++] = Base64EncMap[(data[sidx + 1] << 2) & 077]; } else { dest[didx++] = Base64EncMap[(data[sidx] << 4) & 077]; } } // add padding for (; didx < dest.length; didx++) { dest[didx] = (byte)'='; } return dest; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy