/*
* 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 com.addthis.basis.util;
import javax.annotation.Nullable;
import java.io.DataInput;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.String;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Arrays;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;
import com.google.common.net.UrlEscapers;
import com.google.common.primitives.UnsignedBytes;
public final class LessBytes {
private LessBytes() {}
/** @deprecated Use {@link StandardCharsets#UTF_8} */
@Deprecated
public static final Charset UTF8 = StandardCharsets.UTF_8;
// safety quick switch to old mode if we find problems
private static final boolean nativeURLCodec = System.getProperty("nativeURLCodec", "1").equals("1");
private static final byte[] emptyBytes = new byte[0];
/** Concatenate two byte arrays into one. */
public static byte[] cat(byte[] a, byte[] b) {
byte[] o = new byte[a.length + b.length];
System.arraycopy(a, 0, o, 0, a.length);
System.arraycopy(b, 0, o, a.length, b.length);
return o;
}
/** Concatenate three byte arrays into one. */
public static byte[] cat(byte[] a, byte[] b, byte[] c) {
byte[] o = new byte[a.length + b.length + c.length];
System.arraycopy(a, 0, o, 0, a.length);
System.arraycopy(b, 0, o, a.length, b.length);
System.arraycopy(c, 0, o, a.length + b.length, c.length);
return o;
}
/** Concatenate four byte arrays into one. */
public static byte[] cat(byte[] a, byte[] b, byte[] c, byte[] d) {
byte[] o = new byte[a.length + b.length + c.length + d.length];
System.arraycopy(a, 0, o, 0, a.length);
System.arraycopy(b, 0, o, a.length, b.length);
System.arraycopy(c, 0, o, a.length + b.length, c.length);
System.arraycopy(d, 0, o, a.length + b.length + c.length, d.length);
return o;
}
/** Concatenate five byte arrays into one. */
public static byte[] cat(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e) {
byte[] o = new byte[a.length + b.length + c.length + d.length + e.length];
System.arraycopy(a, 0, o, 0, a.length);
System.arraycopy(b, 0, o, a.length, b.length);
System.arraycopy(c, 0, o, a.length + b.length, c.length);
System.arraycopy(d, 0, o, a.length + b.length + c.length, d.length);
System.arraycopy(e, 0, o, a.length + b.length + c.length + d.length, e.length);
return o;
}
/**
* Replaces the first byte string in buf[] that matches pat[] with rep[].
* <p/>
* example: 'string 1234 foo bar dude', '1234', 'this is a test'
* returns: 'string this is a test foo bar dude'
* <p/>
* Does at most one replacement, and always creates a new byte[] if a match
* is found. The input arrays are not modified.
*
* @return new byte[] with replaced bytes or the original byte[] if no match
* is found
*/
public static byte[] replace(byte[] buf, byte[] pat, byte[] rep) {
int scanpos = 0;
int startoff = 0;
while (scanpos < buf.length) {
if (buf[scanpos] == pat[startoff]) {
if (++startoff == pat.length) {
// replace @ scanpos - startoff
byte[] out = new byte[buf.length - pat.length + rep.length];
Arrays.fill(out, (byte) '-');
System.arraycopy(buf, 0, out, 0, scanpos - startoff + 1);
System.arraycopy(rep, 0, out, scanpos - startoff + 1, rep.length);
System.arraycopy(buf, scanpos + 1, out,
(scanpos - startoff) + rep.length + 1,
((out.length - scanpos - rep.length) + pat.length) - 1);
return out;
}
} else {
startoff = 0;
}
scanpos++;
}
return buf;
}
/**
* Overwrites bytes in buf[] starting at pat[] with rep[]. At most one write
* of rep[] is performed. A new byte[] is never created. If rep[] is too
* long to write entirely, (eg. it is larger than buf[]), then a partial
* write will be performed.
* <p/>
* example: 'string 1234 foo bar dude', '1234', 'this is a test' yields
* returns: 'string this is a testr dude'
*
* @return true if a match for pat[] was found and bytes were replaced
*/
public static boolean overwrite(byte[] buf, byte[] pat, byte[] rep) {
for (int i = 0; i < buf.length; i++) {
for (int j = 0;
(j < pat.length) && ((i + j) < buf.length) && (buf[i + j] == pat[j]);
j++) {
if (j == (pat.length - 1)) {
for (int r = 0; (r < rep.length) && ((i + r) < buf.length); r++) {
buf[i + r] = rep[r];
}
return true;
}
}
}
return false;
}
/**
* True if the first byte array starts with the second.
* Analogous to String.startsWith(String).
*/
public static boolean startsWith(byte[] data, byte[] prefix) {
if (data.length >= prefix.length) {
for (int i = 0; i < prefix.length; i++) {
if (data[i] != prefix[i]) {
return false;
}
}
return true;
}
return false;
}
/** Represent an unsigned int in memory as a long. */
public static long toUnsignedInt(int i) {
return (((i >> 16) & 0xffffL) << 16) | (i & 0xffffL);
}
/**
* Create a mystery byte array from a String. This is similar to calling
* {@link String#getBytes(Charset)} with {@link StandardCharsets#UTF_8},
* but for some reason, it catches any exception that may occur, prints
* it to stderr, and then calls {@link String#getBytes()} -- this uses
* the default encoder for a given platform and therefore the encoding
* for the bytes returned is undefined.
*
* @deprecated Use {@link String#getBytes(Charset)} with
* {@link StandardCharsets#UTF_8} and use more explicit methods to
* handle the unusual retry logic herein.
*/
@Deprecated
public static byte[] toBytes(String s) {
try {
return s.getBytes(UTF8);
} catch (Exception ex) {
ex.printStackTrace();
return s.getBytes();
}
}
/**
* Create a String from a UTF-8 byte array. Almost the same as calling
* {@link String#String(byte[], Charset)} with
* {@link StandardCharsets#UTF_8}, but this method also randomly handles
* null parameters.
*
* @deprecated Use {@link String#String(byte[], Charset)} and handle any
* nulls (if needed) using more explicit or descriptive methods.
*/
@Nullable
@Deprecated
public static String toString(@Nullable byte[] b) {
return (b != null) ? new String(b, UTF8) : null;
}
/** Create an array of UTF-8 byte arrays from an array of Strings. */
public static byte[][] toByteArrays(String... strings) {
byte[][] bytes = new byte[strings.length][0];
for (int i = 0; i < strings.length; i++) {
bytes[i] = strings[i].getBytes(UTF8);
}
return bytes;
}
/** Create an array of Strings from an array of UTF-8 byte arrays. */
public static String[] toStrings(byte[][] bytes) {
String[] strings = new String[bytes.length];
for (int i = 0; i < bytes.length; i++) {
strings[i] = new String(bytes[i], UTF8);
}
return strings;
}
/**
* Convert an short to a byte[2].
*
* @deprecated Use {@link #writeShort(short, OutputStream)}
* or similar method instead. This method is terribly inefficient and
* is strongly indicative of code in need of refactoring. In case it
* is not obvious, creating an array involves creating an entire object
* including garbage collection pointers, byte alignment overhead, and
* is generally several times larger than any primitive. Given that
* the byte[]s created by this method are almost certainly transient in
* nature, this is not desirable.
*/
@Deprecated
public static byte[] toBytes(short val) {
byte[] data = new byte[2];
// these masks seem redundant with the shift and cast; applies to all similar methods
data[0] = (byte) ((val & 0xFF00) >> 8);
data[1] = (byte) ((val & 0x00FF) >> 0);
return data;
}
/**
* Convert 2 bytes to a short. If the byte array is longer than 2 bytes,
* then only the first two bytes are used, else if the byte array is less
* than two bytes, it just defaults to zero.
*
* @deprecated See {@link #toBytes(short)}, and also the defaulting
* behavior is dangerous.
*/
@Deprecated
public static short toShort(byte[] data) {
if ((data != null) && (data.length >= 2)) {
return (short) (((data[0] & 0xff) << 8) | (data[1] & 0xff));
} else {
return 0;
}
}
/**
* Convert char array to UTF-16 byte array.
*
* @deprecated UTF-16 is almost never a good choice for serialization, and
* since every other String/ Byte converter method uses UTF-8, and the
* name is equally generic, this is prone to confusion. If absolutely
* necessary, use {@link #toUtf16Bytes(char[])}.
*/
@Deprecated
public static byte[] toBytes(char[] c) {
return toUtf16Bytes(c);
}
/**
* Convert char array to UTF-16 byte array.
*
* UTF-16 is almost never a good choice for serialization, and there are
* plenty of standard, JDK provided methods to do so. The only possible
* advantage here is saving some small overhead on encoder/ decoder apis.
* However, for this case it is possible to use the high-efficiency
* {@link ByteBuffer#asCharBuffer()} and related APIs. If those cannot be
* used and if performance is important, consider another encoding scheme.
*
* @deprecated Prefer to use another encoding scheme (like UTF-8), or the
* JDK provided methods if performance is not important.
*/
@Deprecated
public static byte[] toUtf16Bytes(char[] c) {
byte[] b = new byte[c.length * 2];
for (int i = 0, j = 0; i < c.length; i++) {
b[j] = (byte) ((c[i] >> 8) & 0xff);
b[j + 1] = (byte) (c[i] & 0xff);
j += 2;
}
return b;
}
/**
* Convert UTF-16 byte array to char array.
*
* @deprecated See {@link #toBytes(char[])} and
* {@link #toCharsFromUtf16(byte[])}
*/
@Deprecated
public static char[] toChars(byte[] b) {
return toCharsFromUtf16(b);
}
/**
* Convert UTF-16 byte array to char array.
*
* @deprecated See {@link #toUtf16Bytes(char[])}.
*/
@Deprecated
public static char[] toCharsFromUtf16(byte[] b) {
char[] c = new char[b.length >> 1];
for (int i = 0, j = 0; i < c.length; i++) {
c[i] = (char) (((b[j++] << 8) & 0xff00) | (b[j++] & 0x00ff));
}
return c;
}
/**
* Convert an int array to bytes. This is the reverse of
* {@link #toInts(byte[])}.
* <p/>
* Example: {@code {0x00112233, 0x44556677}} will be converted to
* {@code {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}}.
*
* @deprecated This implementation is terribly inefficient, and in general,
* will never perform as well as eg. {@link ByteBuffer#asIntBuffer()}
* even if it was fixed up.
*/
@Deprecated
public static byte[] toBytes(int[] vals) {
byte[] bytes = new byte[vals.length * 4];
for (int i = 0; i < vals.length; i++) {
byte[] bytesForInt = toBytes(vals[i]);
System.arraycopy(bytesForInt, 0, bytes, i * 4, bytesForInt.length);
}
return bytes;
}
/**
* Convert a byte array to ints. This is the reverse of
* {@link #toBytes(int[])}.
* <p/>
* Example: {@code {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}}
* will be converted to {@code {0x00112233, 0x44556677}}.
*
* @deprecated See {@link #toBytes(int[])}. This implementation is better,
* but should still be replaced with {@link ByteBuffer#asIntBuffer()}
* or similar where possible.
*/
@Deprecated
public static int[] toInts(byte[] b) {
int[] ints = new int[b.length / 4];
for (int i = 0; i < ints.length; i++) {
ints[i] = toInt(b, i * 4, 0);
}
return ints;
}
/**
* Copy bytes from one array to the specified position in another, such that
* {@code target[offset]=source[0], target[offset+1]=source[1]} and so on...
*
* @param offset starting position in the target array to copy to. 0 means copy
* to the start.
* @deprecated Use {@link System#arraycopy(Object, int, Object, int, int)}.
*/
@Deprecated
public static void copy(byte[] source, byte[] target, int offset) {
System.arraycopy(source, 0, target, offset, source.length);
}
/**
* Convert String to char array. Exactly the same as calling
* {@link String#toCharArray()}.
*
* @deprecated Use {@link String#toCharArray()}. This has nothing
* to do with Bytes either.
*/
@Deprecated
public static char[] toChars(String s) {
return s.toCharArray();
}
/**
* Convert an int to a byte[4].
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static byte[] toBytes(int val) {
byte[] data = new byte[4];
data[0] = (byte) ((val & 0xFF000000) >> 24);
data[1] = (byte) ((val & 0x00FF0000) >> 16);
data[2] = (byte) ((val & 0x0000FF00) >> 8);
data[3] = (byte) ((val & 0x000000FF) >> 0);
return data;
}
/**
* Convert a long to a byte[8].
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static byte[] toBytes(long val) {
byte[] data = new byte[8];
data[0] = (byte) ((val & 0xFF00000000000000L) >> 56);
data[1] = (byte) ((val & 0x00FF000000000000L) >> 48);
data[2] = (byte) ((val & 0x0000FF0000000000L) >> 40);
data[3] = (byte) ((val & 0x000000FF00000000L) >> 32);
data[4] = (byte) ((val & 0x00000000FF000000L) >> 24);
data[5] = (byte) ((val & 0x0000000000FF0000L) >> 16);
data[6] = (byte) ((val & 0x000000000000FF00L) >> 8);
data[7] = (byte) ((val & 0x00000000000000FFL) >> 0);
return data;
}
/**
* Convert 4 bytes to an int or any smaller byte[] to a 0.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static int toInt(byte[] data) {
return toInt(data, 0);
}
/**
* Convert 4 bytes to an int or any smaller byte[] to a default value.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static int toInt(byte[] data, int defaultValue) {
return toInt(data, 0, defaultValue);
}
/**
* Convert 4 bytes of a byte[] to an int or any byte[] to a default value.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static int toInt(byte[] data, int off, int defaultValue) {
if ((data != null) && (data.length >= (off + 4))) {
return (data[off] & 0xff) << 24 |
((data[off + 1] & 0xff) << 16) |
((data[off + 2] & 0xff) << 8) |
((data[off + 3] & 0xff));
} else {
return defaultValue;
}
}
/**
* Convert 4 bytes to an unsigned long or any smaller byte[] to 0.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static long toUInt(byte[] data) {
return toUInt(data, 0L);
}
/**
* Convert 4 bytes to an unsigned long or any smaller byte[] to a
* default value.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static long toUInt(byte[] data, long def) {
return toUInt(data, 0, def);
}
/**
* Convert 4 bytes of a byte[] to an unsigned long or any byte[] to a
* default value.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static long toUInt(byte[] data, int off, long def) {
if (data != null && data.length >= off + 4) {
return (data[off] & 0xffL) << 24 |
((data[off + 1] & 0xffL) << 16) |
((data[off + 2] & 0xffL) << 8) |
((data[off + 3] & 0xffL));
} else {
return def;
}
}
/**
* Convert 8 bytes to a long or any smaller byte[] to 0.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static long toLong(byte[] data) {
return toLong(data, 0L);
}
/**
* Convert 8 bytes to a long or any smaller byte[] to a
* default value.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static long toLong(byte[] data, long def) {
return toLong(data, 0, def);
}
/**
* Convert 8 bytes of a byte[] to a long or any byte[] to a
* default value.
*
* @deprecated See {@link #toBytes(short)}.
*/
@Deprecated
public static long toLong(byte[] data, int off, long def) {
if (data != null && data.length >= 8 + off) {
return (data[off] & 0xffL) << 56 | ((data[off + 1] & 0xffL) << 48) |
((data[off + 2] & 0xffL) << 40) | ((data[off + 3] & 0xffL) << 32) |
((data[off + 4] & 0xffL) << 24) | ((data[off + 5] & 0xffL) << 16) |
((data[off + 6] & 0xffL) << 8) | ((data[off + 7] & 0xffL));
} else {
return def;
}
}
/**
* Write a variable length long to an OutputStream.
* Used by write[Bytes|String] and others to do length prefixing.
*/
public static void writeLength(long size, OutputStream os) throws IOException {
if (size < 0) {
throw new IllegalArgumentException("writeLength value must be >= 0: " + size);
}
if (size == 0) {
os.write(0);
return;
}
while (size > 0) {
if (size > 0x7f) {
os.write((int) (0x80 | (size & 0x7f)));
} else {
os.write((int) (size & 0x7f));
}
size >>= 7;
}
}
/**
* Read a variable length long from an InputStream.
* Used by read[Bytes|String] and others to do length prefixing.
*/
public static long readLength(InputStream in) throws IOException {
long size = 0;
long iter = 0;
long next = 0;
do {
next = in.read();
if (next < 0) {
throw new EOFException();
}
size |= ((next & 0x7f) << iter);
iter += 7;
} while ((next & 0x80) == 0x80);
return size;
}
/**
* Read the named primitive type from the input stream. This is an
* efficient API in theory, but it is implemented using methods that
* are deprecated for being wasteful, and can usually be replaced by
* (hopefully more efficient) direct usages of {@link DataInput}.
*
* @deprecated See {@link #toBytes(short)} and {@link DataInput}.
*/
@Deprecated
public static short readShort(InputStream in) throws IOException {
return toShort(readBytes(in, 2));
}
/**
* Read the named primitive type from the input stream.
*
* @deprecated See {@link #readShort(InputStream)}.
*/
@Deprecated
public static int readInt(InputStream in) throws IOException {
return toInt(readBytes(in, 4), -1);
}
/**
* Read the named primitive type from the input stream.
*
* @deprecated See {@link #readShort(InputStream)}.
*/
@Deprecated
public static long readUInt(InputStream in) throws IOException {
return toUInt(readBytes(in, 4), -1);
}
/**
* Read the named primitive type from the input stream.
*
* @deprecated See {@link #readShort(InputStream)}.
*/
@Deprecated
public static long readLong(InputStream in) throws IOException {
return toLong(readBytes(in, 8), -1);
}
/**
* Write the named primitive type from the input stream.
*
* @deprecated See {@link #readShort(InputStream)}.
*/
@Deprecated
public static void writeShort(short s, OutputStream os) throws IOException {
os.write(toBytes(s));
}
/**
* Write the named primitive type from the input stream.
*
* @deprecated See {@link #readShort(InputStream)}.
*/
@Deprecated
public static void writeInt(int i, OutputStream os) throws IOException {
os.write(toBytes(i));
}
/**
* Write the named primitive type from the input stream.
*
* @deprecated See {@link #readShort(InputStream)}.
*/
@Deprecated
public static void writeLong(long l, OutputStream os) throws IOException {
os.write(toBytes(l));
}
/**
* Write a byte array prefixed by a length field. The length field is
* a variable length long.
*/
public static void writeBytes(byte[] b, OutputStream os) throws IOException {
writeLength(b.length, os);
if (b.length > 0) {
os.write(b);
}
}
/**
* Write a byte array prefixed by a length field. The length field is
* a variable length long.
*/
public static void writeBytes(byte[] b, int off, int len, OutputStream os) throws IOException {
if (len > 0) {
writeLength(len, os);
os.write(b, off, len);
}
}
/**
* Write a char array prefixed by a length field. The length field is
* a variable length long. The char array is simply transformed into
* a byte[] first.
*
* @deprecated See {@link #toBytes(char[])} that this method uses.
*/
@Deprecated
public static void writeChars(char[] c, OutputStream os) throws IOException {
writeBytes(toBytes(c), os);
}
/**
* Read an InputStream to it's end and return as a byte array. Should only
* be used to represent a finite sub-array of unknown but limited length
* that is "null terminated" by the end of the InputStream.
*
* @deprecated Use {@link ByteStreams#toByteArray(InputStream)} from Guava.
*/
@Deprecated
public static byte[] readFully(InputStream in) throws IOException {
return ByteStreams.toByteArray(in);
}
/**
* Write all bytes from an InputStream to an OutputStream.
* Blocks until EOF is reached and all data has been written to OS.
*
* @deprecated Use {@link ByteStreams#copy(InputStream, OutputStream)}
* from Guava.
*/
@Deprecated
public static int writeFully(InputStream is, OutputStream os) throws IOException {
return (int) ByteStreams.copy(is, os);
}
/**
* Read a byte array prefixed by a length field. The length field must
* be a variable length int -- not a long since it is cast down to an int.
*
* @deprecated See {@link #readBytes(InputStream, int)} that this method
* uses, and prefer to use encoding with more consistent precision.
*/
@Nullable
@Deprecated
public static byte[] readBytes(InputStream in) throws IOException {
return readBytes(in, (int) readLength(in));
}
/**
* Read a char array prefixed by a length field. The length field must
* be a variable length long, and it must represent the number of bytes;
* not characters. This simply reads a byte[] and converts afterwards.
*
* @deprecated See {@link #writeChars(char[], OutputStream)} and
* {@link #toChars(byte[])} that this method uses.
* @throws NullPointerException if the length field appears negative
*/
@Deprecated
public static char[] readChars(InputStream in) throws IOException {
return toChars(readBytes(in, (int) readLength(in)));
}
/**
* Read a given number of bytes into a byte array.
*
* @return null if len is less than zero, otherwise a new byte[] of the
* specified length filled with bytes from the given InputStream
* @throws EOFException if the end of the InputStream was reached first
* @deprecated Use {@link ByteStreams#readFully(InputStream, byte[])}
* from Guava if possible. The edge cases aren't exactly the same, but
* it is not advised to rely on the inconsistent edge case handling
* provided herein anyway.
*/
@Nullable
@Deprecated
public static byte[] readBytes(InputStream in, int len) throws IOException {
if (len < 0) {
return null;
}
if (len == 0) {
return emptyBytes;
}
byte[] b = new byte[len];
ByteStreams.readFully(in, b);
return b;
}
/**
* Read len bytes from is into b, starting at off. same as
* InputStream.read(byte[], int, int) except that it keeps trying until len
* bytes have been read.
*
* @throws IOException if the stream threw an exception or if the end of
* stream was reached before len bytes could be read
* @deprecated Use
* {@link ByteStreams#readFully(InputStream, byte[], int, int)}
* from Guava.
*/
@Deprecated
public static void readBytes(InputStream is, byte[] b, int off, int len) throws IOException {
ByteStreams.readFully(is, b, off, len);
}
/**
* Write a String prefixed by a length field. The length field is a
* variable length long. This is the same as writing the length prefixed
* UTF-8 byte sequence representing the String.
*
* Writes out null values and empty Strings as size zero byte arrays.
*
* @deprecated See {@link #toBytes(String)} that this method uses.
*/
@Deprecated
public static void writeString(String str, OutputStream os) throws IOException {
writeBytes((str != null) ? toBytes(str) : emptyBytes, os);
}
/**
* Write a String prefixed by a length field, but using UTF-16 encoding.
*
* Writes out null values and empty Strings as size zero byte arrays.
*
* @deprecated See {@link #writeChars(char[], OutputStream)} that this
* method uses. Also, this makes a char[] copy and then just does
* UTF-16 encoding. That is pretty round-a-bout.
*/
@Deprecated
public static void writeCharString(String str, OutputStream os) throws IOException {
writeChars((str != null) ? str.toCharArray() : new char[0], os);
}
/**
* Read a UTF-8 String prefixed by a byte-length field. The length must be
* a variable length int.
*
* @deprecated See {@link #toString(byte[])} and
* {@link #readBytes(InputStream)} that this method uses.
*/
@Nullable
@Deprecated
public static String readString(InputStream in) throws IOException {
return toString(readBytes(in));
}
/**
* Read a UTF-8 String prefixed by a byte-length field with edge case handling.
* The length is a variable length long.
*
* @param emptyNull if true, zero-length byte arrays will be read as nulls.
* Otherwise, they are read as zero-length Strings.
* @deprecated See {@link #readBytes(InputStream)} and
* {@link #toString(byte[])} that this method uses.
*/
@Nullable
@Deprecated
public static String readString(InputStream in, boolean emptyNull) throws IOException {
byte[] b = readBytes(in);
if (b != null) {
if (b.length > 0) {
return toString(b);
} else {
return emptyNull ? null : toString(b);
}
} else {
throw new RuntimeException("Length field was likely negative; possible corruption");
}
}
/**
* Read a length-prefixed UTF-16 byte array in as a String.
*
* @deprecated See {@link #readChars(InputStream)} that this method uses.
*/
@Nullable
@Deprecated
public static String readCharString(InputStream in) throws IOException {
char[] ch = readChars(in);
if (ch != null) {
return new String(ch);
} else {
return null;
}
}
/**
* Makes Strings safe to use in URLs.
*
* @deprecated Use {@link UrlEscapers#urlFormParameterEscaper()}. This
* implementation was aggressively creating byte[]s for no reason.
*/
@Deprecated
public static String urlencode(String s) {
if (nativeURLCodec) {
try {
return URLEncoder.encode(s, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
}
return UrlEscapers.urlFormParameterEscaper().escape(s);
}
/**
* Optimized and works only for UTF-8 - but 2x faster than JDK implementation.
* Replaces URLDecoder.decode(val, "UTF-8").
*
* @deprecated Contrary to the previous javadoc, this method is rife with
* inefficiencies. The most prominent of which is a largely unnecessary
* string to byte[] conversion. If there are no better versions available
* still, then fix up this method.
*/
@Nullable
@Deprecated
public static String urldecode(String s) {
if ((s == null) || (!s.contains("%") && !s.contains("+"))) {
// nothing to decode
return s;
}
if (nativeURLCodec) {
try {
return URLDecoder.decode(s, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
}
byte[] c = toBytes(s);
int vcount = 0;
boolean changed = false;
for (int i = 0; i < c.length; i++) {
if (c[i] == '%' && i < c.length - 2) {
if (LessBytes.hex2dec(c[i + 1]) >= 0 && LessBytes.hex2dec(c[i + 2]) >= 0) {
vcount++;
}
} else if (c[i] == '+') {
c[i] = ' ';
changed = true;
}
}
if (vcount > 0) {
int pos = 0;
byte[] nc = new byte[c.length - vcount * 2];
for (int i = 0; i < c.length; i++) {
if (c[i] == '%' && i < c.length - 2) {
int hd1 = LessBytes.hex2dec(c[i + 1]);
int hd2 = LessBytes.hex2dec(c[i + 2]);
if (hd1 >= 0 && hd2 >= 0) {
nc[pos++] = (byte) (((hd1 << 4) | hd2) & 0xff);
i += 2;
} else {
nc[pos++] = c[i];
}
} else if (c[i] == '+') {
nc[pos++] = ' ';
} else {
nc[pos++] = c[i];
}
}
return new String(nc, 0, pos, UTF8);
} else if (changed) {
return new String(c, UTF8);
} else {
return s;
}
}
/**
* Turns 0-9,a-f into a value from 0-15. Helper method for urldecode().
*
* @deprecated not used by urldecode anymore, (although it probably should
* be). This method is public though, so deprecating instead of deleting.
*/
@Deprecated
public static int hex2dec(char c) {
c |= 0x20; // to lower
if (c >= 'a' && c <= 'f') {
return 10 + (c - 'a');
} else if (c >= 'A' && c <= 'F') {
return 10 + (c - 'A');
} else if (c >= '0' && c <= '9') {
return c - '0';
}
return -1;
}
/**
* Turns 0-9,a-f into a value from 0-15. Helper method for urldecode().
*
* @deprecated See {@link #urldecode(String)}.
*/
@Deprecated
public static int hex2dec(byte c) {
c |= 0x20; // to lower
if (c >= 'a' && c <= 'f') {
return 10 + (c - 'a');
} else if (c >= 'A' && c <= 'F') {
return 10 + (c - 'A');
} else if (c >= '0' && c <= '9') {
return c - '0';
}
return -1;
}
/**
* Reverse the bits in an integer. Exactly the same as calling
* {@link Integer#reverse(int)}, but faster. The trade-off here
* is that we are paying more memory, and less rapid calls will
* result in more cache misses and therefore probably worse performance.
*
* I did find another implementation that was just strictly better
* than the JDK version, but it is probably quite enough to leave this
* one here.
*/
// fastest method to reverse int bits (with 32 bit jvm)
public static int reverseBits(int v1) {
return
(BitReverseTable256[v1 & 0xff] << 24) |
(BitReverseTable256[(v1 >> 8) & 0xff] << 16) |
(BitReverseTable256[(v1 >> 16) & 0xff] << 8) |
(BitReverseTable256[(v1 >> 24) & 0xff]);
}
public static long reverseBits(long v1) {
return
((long) (BitReverseTable256[(int) v1 & 0xff]) << 56) |
((long) (BitReverseTable256[(int) (v1 >> 8) & 0xff]) << 48) |
((long) (BitReverseTable256[(int) (v1 >> 16) & 0xff]) << 40) |
((long) (BitReverseTable256[(int) (v1 >> 24) & 0xff]) << 32) |
((long) (BitReverseTable256[(int) (v1 >> 32) & 0xff]) << 24) |
((long) (BitReverseTable256[(int) (v1 >> 40) & 0xff]) << 16) |
((long) (BitReverseTable256[(int) (v1 >> 48) & 0xff]) << 8) |
((long) (BitReverseTable256[(int) (v1 >> 56) & 0xff]));
}
private static final int[] BitReverseTable256 =
{
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
/**
* Compares two byte arrays lexicographically where negative bytes are
* greater than positive ones.
*
* @deprecated Use {@link UnsignedBytes#lexicographicalComparator()}.
*/
@Deprecated
public static int compare(byte[] a, byte[] b) {
return UnsignedBytes.lexicographicalComparator().compare(a, b);
}
/**
* True if both arrays are of the same length and have equal content.
*
* @deprecated Use {@link Arrays#equals(byte[], byte[])}.
*/
@Deprecated
public static boolean equals(byte[] a, byte[] b) {
return Arrays.equals(a, b);
}
/** True if byte[] reference is either null or has a length of zero. */
public static boolean isEmpty(byte[] arr) {
return (arr == null) || (arr.length == 0);
}
/**
* Extract a subset of a byte array (like substring).
*
* @deprecated Use {@link Arrays#copyOfRange(byte[], int, int)}. Note
* that this method has slightly different arguments -- off + len versus
* start + end.
*/
@Deprecated
public static byte[] cut(byte[] src, int off, int len) {
return Arrays.copyOfRange(src, off, off + len);
}
/**
* Create a String with a single, repeated, char.
*
* @return String of the same length containing only supplied char
* @deprecated This method does not make any sense. Strings are immutable.
* Try using a StringBuilder, or a constant String. If you really need
* single-char same-length String clones, there is no need to call
* toCharArray to make a copy of the original, and it is unlikely
* you want to call such a method 'clear'.
*/
@Deprecated
public static String clear(String s, char ch) {
char[] c = s.toCharArray();
for (int i = 0; i < c.length; i++) {
c[i] = ch;
}
return new String(c);
}
/**
* Pad the String representation of a long with leading zeros.
*
* @deprecated Use either {@link String#format(String, Object...)} or
* {@link Strings#padStart(String, int, char)}. Also, this has little
* to do with Bytes.
*/
@Deprecated
public static String pad0(long val, int zeros) {
String sval = Long.toString(val);
return Strings.padStart(sval, zeros, '0');
}
}