com.addthis.basis.util.LessBytes.java Source code

Java tutorial

Introduction

Here is the source code for com.addthis.basis.util.LessBytes.java

Source

/*
 * 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');
    }
}