/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.util;
import com.liferay.portal.kernel.io.ProtectedObjectInputStream;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author Brian Wing Shun Chan
*/
public class Base64 {
public static byte[] decode(String base64) {
if (Validator.isNull(base64)) {
return new byte[0];
}
int pad = 0;
for (int i = base64.length() - 1; base64.charAt(i) == CharPool.EQUAL;
i--) {
pad++;
}
int length = (base64.length() * 6) / 8 - pad;
byte[] raw = new byte[length];
int rawindex = 0;
for (int i = 0; i < base64.length(); i += 4) {
int block = getValue(base64.charAt(i)) << 18;
block += getValue(base64.charAt(i + 1)) << 12;
block += getValue(base64.charAt(i + 2)) << 6;
block += getValue(base64.charAt(i + 3));
for (int j = 0; j < 3 && rawindex + j < raw.length; j++) {
raw[rawindex + j] = (byte)(block >> 8 * (2 - j) & 0xff);
}
rawindex += 3;
}
return raw;
}
public static String encode(byte[] raw) {
return encode(raw, 0, raw.length);
}
public static String encode(byte[] raw, int offset, int length) {
int lastIndex = Math.min(raw.length, offset + length);
StringBuilder sb = new StringBuilder(
((lastIndex - offset) / 3 + 1) * 4);
for (int i = offset; i < lastIndex; i += 3) {
sb.append(encodeBlock(raw, i, lastIndex));
}
return sb.toString();
}
public static String fromURLSafe(String base64) {
return StringUtil.replace(
base64,
new char[] {CharPool.MINUS, CharPool.STAR, CharPool.UNDERLINE},
new char[] {CharPool.PLUS, CharPool.EQUAL, CharPool.SLASH});
}
public static String objectToString(Object o) {
if (o == null) {
return null;
}
UnsyncByteArrayOutputStream ubaos = new UnsyncByteArrayOutputStream(
32000);
try (ObjectOutputStream os = new ObjectOutputStream(ubaos)) {
os.writeObject(o);
}
catch (Exception e) {
_log.error(e, e);
}
return encode(ubaos.unsafeGetByteArray(), 0, ubaos.size());
}
public static Object stringToObject(String s) {
return _stringToObject(s, null, false);
}
public static Object stringToObject(String s, ClassLoader classLoader) {
return _stringToObject(s, classLoader, false);
}
public static Object stringToObjectSilent(String s) {
return _stringToObject(s, null, true);
}
public static Object stringToObjectSilent(
String s, ClassLoader classLoader) {
return _stringToObject(s, classLoader, true);
}
public static String toURLSafe(String base64) {
return StringUtil.replace(
base64, new char[] {CharPool.PLUS, CharPool.EQUAL, CharPool.SLASH},
new char[] {CharPool.MINUS, CharPool.STAR, CharPool.UNDERLINE});
}
protected static char[] encodeBlock(byte[] raw, int offset, int lastIndex) {
int block = 0;
int slack = lastIndex - offset - 1;
int end = slack < 2 ? slack : 2;
for (int i = 0; i <= end; i++) {
byte b = raw[offset + i];
int neuter = b >= 0 ? ((int)b) : b + 256;
block += neuter << 8 * (2 - i);
}
char[] base64 = new char[4];
for (int i = 0; i < 4; i++) {
int sixbit = block >>> 6 * (3 - i) & 0x3f;
base64[i] = getChar(sixbit);
}
if (slack < 1) {
base64[2] = CharPool.EQUAL;
}
if (slack < 2) {
base64[3] = CharPool.EQUAL;
}
return base64;
}
protected static char getChar(int sixbit) {
if ((sixbit >= 0) && (sixbit <= 25)) {
return (char)(65 + sixbit);
}
if ((sixbit >= 26) && (sixbit <= 51)) {
return (char)(97 + (sixbit - 26));
}
if ((sixbit >= 52) && (sixbit <= 61)) {
return (char)(48 + (sixbit - 52));
}
if (sixbit == 62) {
return CharPool.PLUS;
}
if (sixbit != 63) {
return CharPool.QUESTION;
}
return CharPool.SLASH;
}
protected static int getValue(char c) {
if ((c >= CharPool.UPPER_CASE_A) && (c <= CharPool.UPPER_CASE_Z)) {
return c - 65;
}
if ((c >= CharPool.LOWER_CASE_A) && (c <= CharPool.LOWER_CASE_Z)) {
return (c - 97) + 26;
}
if ((c >= CharPool.NUMBER_0) && (c <= CharPool.NUMBER_9)) {
return (c - 48) + 52;
}
if (c == CharPool.PLUS) {
return 62;
}
if (c == CharPool.SLASH) {
return 63;
}
if (c != CharPool.EQUAL) {
return -1;
}
return 0;
}
private static Object _stringToObject(
String s, ClassLoader classLoader, boolean silent) {
if (s == null) {
return null;
}
byte[] bytes = decode(s);
UnsyncByteArrayInputStream ubais = new UnsyncByteArrayInputStream(
bytes);
try {
ObjectInputStream is = null;
if (classLoader == null) {
is = new ProtectedObjectInputStream(ubais);
}
else {
is = new ProtectedClassLoaderObjectInputStream(
ubais, classLoader);
}
return is.readObject();
}
catch (Exception e) {
if (!silent) {
_log.error(e, e);
}
}
return null;
}
private static final Log _log = LogFactoryUtil.getLog(Base64.class);
}