org.apache.dubbo.common.io.Bytes Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dubbo Show documentation
Show all versions of dubbo Show documentation
The all in one project of dubbo
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.dubbo.common.io;
import org.apache.dubbo.common.utils.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
/**
* CodecUtils.
*/
public class Bytes {
private static final String C64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; //default base64.
private static final char[] BASE16 = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}, BASE64 = C64.toCharArray();
private static final int MASK4 = 0x0f, MASK6 = 0x3f, MASK8 = 0xff;
private static final Map DECODE_TABLE_MAP = new ConcurrentHashMap();
private static ThreadLocal MD = new ThreadLocal();
private Bytes() {
}
/**
* byte array copy.
*
* @param src src.
* @param length new length.
* @return new byte array.
*/
public static byte[] copyOf(byte[] src, int length) {
byte[] dest = new byte[length];
System.arraycopy(src, 0, dest, 0, Math.min(src.length, length));
return dest;
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] short2bytes(short v) {
byte[] ret = {0, 0};
short2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void short2bytes(short v, byte[] b) {
short2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void short2bytes(short v, byte[] b, int off) {
b[off + 1] = (byte) v;
b[off + 0] = (byte) (v >>> 8);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] int2bytes(int v) {
byte[] ret = {0, 0, 0, 0};
int2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void int2bytes(int v, byte[] b) {
int2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void int2bytes(int v, byte[] b, int off) {
b[off + 3] = (byte) v;
b[off + 2] = (byte) (v >>> 8);
b[off + 1] = (byte) (v >>> 16);
b[off + 0] = (byte) (v >>> 24);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] float2bytes(float v) {
byte[] ret = {0, 0, 0, 0};
float2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void float2bytes(float v, byte[] b) {
float2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void float2bytes(float v, byte[] b, int off) {
int i = Float.floatToIntBits(v);
b[off + 3] = (byte) i;
b[off + 2] = (byte) (i >>> 8);
b[off + 1] = (byte) (i >>> 16);
b[off + 0] = (byte) (i >>> 24);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] long2bytes(long v) {
byte[] ret = {0, 0, 0, 0, 0, 0, 0, 0};
long2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void long2bytes(long v, byte[] b) {
long2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void long2bytes(long v, byte[] b, int off) {
b[off + 7] = (byte) v;
b[off + 6] = (byte) (v >>> 8);
b[off + 5] = (byte) (v >>> 16);
b[off + 4] = (byte) (v >>> 24);
b[off + 3] = (byte) (v >>> 32);
b[off + 2] = (byte) (v >>> 40);
b[off + 1] = (byte) (v >>> 48);
b[off + 0] = (byte) (v >>> 56);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] double2bytes(double v) {
byte[] ret = {0, 0, 0, 0, 0, 0, 0, 0};
double2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void double2bytes(double v, byte[] b) {
double2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void double2bytes(double v, byte[] b, int off) {
long j = Double.doubleToLongBits(v);
b[off + 7] = (byte) j;
b[off + 6] = (byte) (j >>> 8);
b[off + 5] = (byte) (j >>> 16);
b[off + 4] = (byte) (j >>> 24);
b[off + 3] = (byte) (j >>> 32);
b[off + 2] = (byte) (j >>> 40);
b[off + 1] = (byte) (j >>> 48);
b[off + 0] = (byte) (j >>> 56);
}
/**
* to short.
*
* @param b byte array.
* @return short.
*/
public static short bytes2short(byte[] b) {
return bytes2short(b, 0);
}
/**
* to short.
*
* @param b byte array.
* @param off offset.
* @return short.
*/
public static short bytes2short(byte[] b, int off) {
return (short) (((b[off + 1] & 0xFF) << 0) +
((b[off + 0]) << 8));
}
/**
* to int.
*
* @param b byte array.
* @return int.
*/
public static int bytes2int(byte[] b) {
return bytes2int(b, 0);
}
/**
* to int.
*
* @param b byte array.
* @param off offset.
* @return int.
*/
public static int bytes2int(byte[] b, int off) {
return ((b[off + 3] & 0xFF) << 0) +
((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
((b[off + 0]) << 24);
}
/**
* to int.
*
* @param b byte array.
* @return int.
*/
public static float bytes2float(byte[] b) {
return bytes2float(b, 0);
}
/**
* to int.
*
* @param b byte array.
* @param off offset.
* @return int.
*/
public static float bytes2float(byte[] b, int off) {
int i = ((b[off + 3] & 0xFF) << 0) +
((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
((b[off + 0]) << 24);
return Float.intBitsToFloat(i);
}
/**
* to long.
*
* @param b byte array.
* @return long.
*/
public static long bytes2long(byte[] b) {
return bytes2long(b, 0);
}
/**
* to long.
*
* @param b byte array.
* @param off offset.
* @return long.
*/
public static long bytes2long(byte[] b, int off) {
return ((b[off + 7] & 0xFFL) << 0) +
((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) +
(((long) b[off + 0]) << 56);
}
/**
* to long.
*
* @param b byte array.
* @return double.
*/
public static double bytes2double(byte[] b) {
return bytes2double(b, 0);
}
/**
* to long.
*
* @param b byte array.
* @param off offset.
* @return double.
*/
public static double bytes2double(byte[] b, int off) {
long j = ((b[off + 7] & 0xFFL) << 0) +
((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) +
(((long) b[off + 0]) << 56);
return Double.longBitsToDouble(j);
}
/**
* to hex string.
*
* @param bs byte array.
* @return hex string.
*/
public static String bytes2hex(byte[] bs) {
return bytes2hex(bs, 0, bs.length);
}
/**
* to hex string.
*
* @param bs byte array.
* @param off offset.
* @param len length.
* @return hex string.
*/
public static String bytes2hex(byte[] bs, int off, int len) {
if (off < 0) {
throw new IndexOutOfBoundsException("bytes2hex: offset < 0, offset is " + off);
}
if (len < 0) {
throw new IndexOutOfBoundsException("bytes2hex: length < 0, length is " + len);
}
if (off + len > bs.length) {
throw new IndexOutOfBoundsException("bytes2hex: offset + length > array length.");
}
byte b;
int r = off, w = 0;
char[] cs = new char[len * 2];
for (int i = 0; i < len; i++) {
b = bs[r++];
cs[w++] = BASE16[b >> 4 & MASK4];
cs[w++] = BASE16[b & MASK4];
}
return new String(cs);
}
/**
* from hex string.
*
* @param str hex string.
* @return byte array.
*/
public static byte[] hex2bytes(String str) {
return hex2bytes(str, 0, str.length());
}
/**
* from hex string.
*
* @param str hex string.
* @param off offset.
* @param len length.
* @return byte array.
*/
public static byte[] hex2bytes(final String str, final int off, int len) {
if ((len & 1) == 1) {
throw new IllegalArgumentException("hex2bytes: ( len & 1 ) == 1.");
}
if (off < 0) {
throw new IndexOutOfBoundsException("hex2bytes: offset < 0, offset is " + off);
}
if (len < 0) {
throw new IndexOutOfBoundsException("hex2bytes: length < 0, length is " + len);
}
if (off + len > str.length()) {
throw new IndexOutOfBoundsException("hex2bytes: offset + length > array length.");
}
int num = len / 2, r = off, w = 0;
byte[] b = new byte[num];
for (int i = 0; i < num; i++) {
b[w++] = (byte) (hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)));
}
return b;
}
/**
* to base64 string.
*
* @param b byte array.
* @return base64 string.
*/
public static String bytes2base64(byte[] b) {
return bytes2base64(b, 0, b.length, BASE64);
}
/**
* to base64 string.
*
* @param b byte array.
* @return base64 string.
*/
public static String bytes2base64(byte[] b, int offset, int length) {
return bytes2base64(b, offset, length, BASE64);
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code string(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, String code) {
return bytes2base64(b, 0, b.length, code);
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code string(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, int offset, int length, String code) {
if (code.length() < 64) {
throw new IllegalArgumentException("Base64 code length < 64.");
}
return bytes2base64(b, offset, length, code.toCharArray());
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, char[] code) {
return bytes2base64(b, 0, b.length, code);
}
/**
* to base64 string.
*
* @param bs byte array.
* @param off offset.
* @param len length.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(final byte[] bs, final int off, final int len, final char[] code) {
if (off < 0) {
throw new IndexOutOfBoundsException("bytes2base64: offset < 0, offset is " + off);
}
if (len < 0) {
throw new IndexOutOfBoundsException("bytes2base64: length < 0, length is " + len);
}
if (off + len > bs.length) {
throw new IndexOutOfBoundsException("bytes2base64: offset + length > array length.");
}
if (code.length < 64) {
throw new IllegalArgumentException("Base64 code length < 64.");
}
boolean pad = code.length > 64; // has pad char.
int num = len / 3, rem = len % 3, r = off, w = 0;
char[] cs = new char[num * 4 + (rem == 0 ? 0 : pad ? 4 : rem + 1)];
for (int i = 0; i < num; i++) {
int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8, b3 = bs[r++] & MASK8;
cs[w++] = code[b1 >> 2];
cs[w++] = code[(b1 << 4) & MASK6 | (b2 >> 4)];
cs[w++] = code[(b2 << 2) & MASK6 | (b3 >> 6)];
cs[w++] = code[b3 & MASK6];
}
if (rem == 1) {
int b1 = bs[r++] & MASK8;
cs[w++] = code[b1 >> 2];
cs[w++] = code[(b1 << 4) & MASK6];
if (pad) {
cs[w++] = code[64];
cs[w++] = code[64];
}
} else if (rem == 2) {
int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8;
cs[w++] = code[b1 >> 2];
cs[w++] = code[(b1 << 4) & MASK6 | (b2 >> 4)];
cs[w++] = code[(b2 << 2) & MASK6];
if (pad) {
cs[w++] = code[64];
}
}
return new String(cs);
}
/**
* from base64 string.
*
* @param str base64 string.
* @return byte array.
*/
public static byte[] base642bytes(String str) {
return base642bytes(str, 0, str.length());
}
/**
* from base64 string.
*
* @param str base64 string.
* @param offset offset.
* @param length length.
* @return byte array.
*/
public static byte[] base642bytes(String str, int offset, int length) {
return base642bytes(str, offset, length, C64);
}
/**
* from base64 string.
*
* @param str base64 string.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(String str, String code) {
return base642bytes(str, 0, str.length(), code);
}
/**
* from base64 string.
*
* @param str base64 string.
* @param off offset.
* @param len length.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(final String str, final int off, final int len, final String code) {
if (off < 0) {
throw new IndexOutOfBoundsException("base642bytes: offset < 0, offset is " + off);
}
if (len < 0) {
throw new IndexOutOfBoundsException("base642bytes: length < 0, length is " + len);
}
if (len == 0) {
return new byte[0];
}
if (off + len > str.length()) {
throw new IndexOutOfBoundsException("base642bytes: offset + length > string length.");
}
if (code.length() < 64) {
throw new IllegalArgumentException("Base64 code length < 64.");
}
int rem = len % 4;
if (rem == 1) {
throw new IllegalArgumentException("base642bytes: base64 string length % 4 == 1.");
}
int num = len / 4, size = num * 3;
if (code.length() > 64) {
if (rem != 0) {
throw new IllegalArgumentException("base642bytes: base64 string length error.");
}
char pc = code.charAt(64);
if (str.charAt(off + len - 2) == pc) {
size -= 2;
--num;
rem = 2;
} else if (str.charAt(off + len - 1) == pc) {
size--;
--num;
rem = 3;
}
} else {
if (rem == 2) {
size++;
} else if (rem == 3) {
size += 2;
}
}
int r = off, w = 0;
byte[] b = new byte[size], t = decodeTable(code);
for (int i = 0; i < num; i++) {
int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)];
int c3 = t[str.charAt(r++)], c4 = t[str.charAt(r++)];
b[w++] = (byte) ((c1 << 2) | (c2 >> 4));
b[w++] = (byte) ((c2 << 4) | (c3 >> 2));
b[w++] = (byte) ((c3 << 6) | c4);
}
if (rem == 2) {
int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)];
b[w++] = (byte) ((c1 << 2) | (c2 >> 4));
} else if (rem == 3) {
int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)], c3 = t[str.charAt(r++)];
b[w++] = (byte) ((c1 << 2) | (c2 >> 4));
b[w++] = (byte) ((c2 << 4) | (c3 >> 2));
}
return b;
}
/**
* from base64 string.
*
* @param str base64 string.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(String str, char[] code) {
return base642bytes(str, 0, str.length(), code);
}
/**
* from base64 string.
*
* @param str base64 string.
* @param off offset.
* @param len length.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(final String str, final int off, final int len, final char[] code) {
if (off < 0) {
throw new IndexOutOfBoundsException("base642bytes: offset < 0, offset is " + off);
}
if (len < 0) {
throw new IndexOutOfBoundsException("base642bytes: length < 0, length is " + len);
}
if (len == 0) {
return new byte[0];
}
if (off + len > str.length()) {
throw new IndexOutOfBoundsException("base642bytes: offset + length > string length.");
}
if (code.length < 64) {
throw new IllegalArgumentException("Base64 code length < 64.");
}
int rem = len % 4;
if (rem == 1) {
throw new IllegalArgumentException("base642bytes: base64 string length % 4 == 1.");
}
int num = len / 4, size = num * 3;
if (code.length > 64) {
if (rem != 0) {
throw new IllegalArgumentException("base642bytes: base64 string length error.");
}
char pc = code[64];
if (str.charAt(off + len - 2) == pc) {
size -= 2;
--num;
rem = 2;
} else if (str.charAt(off + len - 1) == pc) {
size--;
--num;
rem = 3;
}
} else {
if (rem == 2) {
size++;
} else if (rem == 3) {
size += 2;
}
}
int r = off, w = 0;
byte[] b = new byte[size];
for (int i = 0; i < num; i++) {
int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++));
int c3 = indexOf(code, str.charAt(r++)), c4 = indexOf(code, str.charAt(r++));
b[w++] = (byte) ((c1 << 2) | (c2 >> 4));
b[w++] = (byte) ((c2 << 4) | (c3 >> 2));
b[w++] = (byte) ((c3 << 6) | c4);
}
if (rem == 2) {
int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++));
b[w++] = (byte) ((c1 << 2) | (c2 >> 4));
} else if (rem == 3) {
int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++)), c3 = indexOf(code, str.charAt(r++));
b[w++] = (byte) ((c1 << 2) | (c2 >> 4));
b[w++] = (byte) ((c2 << 4) | (c3 >> 2));
}
return b;
}
/**
* zip.
*
* @param bytes source.
* @return compressed byte array.
* @throws IOException
*/
public static byte[] zip(byte[] bytes) throws IOException {
UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream();
OutputStream os = new DeflaterOutputStream(bos);
try {
os.write(bytes);
} finally {
os.close();
bos.close();
}
return bos.toByteArray();
}
/**
* unzip.
*
* @param bytes compressed byte array.
* @return byte uncompressed array.
* @throws IOException
*/
public static byte[] unzip(byte[] bytes) throws IOException {
UnsafeByteArrayInputStream bis = new UnsafeByteArrayInputStream(bytes);
UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream();
InputStream is = new InflaterInputStream(bis);
try {
IOUtils.write(is, bos);
return bos.toByteArray();
} finally {
is.close();
bis.close();
bos.close();
}
}
/**
* get md5.
*
* @param str input string.
* @return MD5 byte array.
*/
public static byte[] getMD5(String str) {
return getMD5(str.getBytes());
}
/**
* get md5.
*
* @param source byte array source.
* @return MD5 byte array.
*/
public static byte[] getMD5(byte[] source) {
MessageDigest md = getMessageDigest();
return md.digest(source);
}
/**
* get md5.
*
* @param file file source.
* @return MD5 byte array.
*/
public static byte[] getMD5(File file) throws IOException {
InputStream is = new FileInputStream(file);
try {
return getMD5(is);
} finally {
is.close();
}
}
/**
* get md5.
*
* @param is input stream.
* @return MD5 byte array.
*/
public static byte[] getMD5(InputStream is) throws IOException {
return getMD5(is, 1024 * 8);
}
private static byte hex(char c) {
if (c <= '9') {
return (byte) (c - '0');
}
if (c >= 'a' && c <= 'f') {
return (byte) (c - 'a' + 10);
}
if (c >= 'A' && c <= 'F') {
return (byte) (c - 'A' + 10);
}
throw new IllegalArgumentException("hex string format error [" + c + "].");
}
private static int indexOf(char[] cs, char c) {
for (int i = 0, len = cs.length; i < len; i++) {
if (cs[i] == c) {
return i;
}
}
return -1;
}
private static byte[] decodeTable(String code) {
int hash = code.hashCode();
byte[] ret = DECODE_TABLE_MAP.get(hash);
if (ret == null) {
if (code.length() < 64) {
throw new IllegalArgumentException("Base64 code length < 64.");
}
// create new decode table.
ret = new byte[128];
for (int i = 0; i < 128; i++) // init table.
{
ret[i] = -1;
}
for (int i = 0; i < 64; i++) {
ret[code.charAt(i)] = (byte) i;
}
DECODE_TABLE_MAP.put(hash, ret);
}
return ret;
}
private static byte[] getMD5(InputStream is, int bs) throws IOException {
MessageDigest md = getMessageDigest();
byte[] buf = new byte[bs];
while (is.available() > 0) {
int read, total = 0;
do {
if ((read = is.read(buf, total, bs - total)) <= 0) {
break;
}
total += read;
}
while (total < bs);
md.update(buf);
}
return md.digest();
}
private static MessageDigest getMessageDigest() {
MessageDigest ret = MD.get();
if (ret == null) {
try {
ret = MessageDigest.getInstance("MD5");
MD.set(ret);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
return ret;
}
}