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

uk.gov.gchq.gaffer.commonutil.ByteArrayEscapeUtils Maven / Gradle / Ivy

There is a newer version: 2.3.1
Show newest version
/*
 * Copyright 2016-2019 Crown Copyright
 *
 * 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 uk.gov.gchq.gaffer.commonutil;

import java.security.InvalidParameterException;
import java.util.Arrays;

/**
 * Removes the 0 byte from a byte array. Preserves ordering.
 */
public final class ByteArrayEscapeUtils {

    public static final byte DELIMITER = (byte) 0;
    public static final byte DELIMITER_PLUS_ONE = (byte) 1;
    private static final byte ESCAPE_CHAR = (byte) 1;
    private static final byte REPLACEMENT_CHAR = (byte) 2;

    private ByteArrayEscapeUtils() {
        // private to prevent this class being instantiated.
        // All methods are static and should be called directly.
    }

    /**
     * Escapes the provided byte[] so that it no longer contains the
     * Constants.DELIMITER character.
     * After escaping the byte[] the appendAfterEscaping[] is appended unescaped.
     *
     * @param bytes               the byte array to escape
     * @param appendAfterEscaping the bytes to append to the array after being escaped.
     * @return the escaped byte array
     */
    public static byte[] escape(final byte[] bytes, final byte... appendAfterEscaping) {
        final byte[] temp = new byte[(2 * bytes.length) + ((null == appendAfterEscaping) ? 0 : appendAfterEscaping.length)];
        int currentPosition = escape(bytes, temp, 0);
        if (null != appendAfterEscaping) {
            for (final byte b : appendAfterEscaping) {
                temp[currentPosition++] = b;
            }
        }
        return Arrays.copyOfRange(temp, 0, currentPosition);
    }

    private static int escape(final byte[] bytes, final byte[] temp, final int position) {
        int currentPosition = position;
        for (final byte b : bytes) {
            if (ESCAPE_CHAR == b) {
                temp[currentPosition++] = ESCAPE_CHAR;
                temp[currentPosition++] = REPLACEMENT_CHAR;
            } else if (DELIMITER == b) {
                temp[currentPosition++] = ESCAPE_CHAR;
                temp[currentPosition++] = ESCAPE_CHAR;
            } else {
                temp[currentPosition++] = b;
            }
        }
        return currentPosition;
    }

    /**
     * Unescapes the provided byte array - this should only be called on byte
     * arrays that have been through the {@code escape} method.
     *
     * @param bytes the byte array to unescape
     * @return the unescaped byte array
     */
    public static byte[] unEscape(final byte[] bytes) {
        return unEscapeByLength(bytes, 0, bytes.length);
    }

    /**
     * Unescapes the provided byte array - this should only be called on byte
     * arrays that have been through the {@code escape} method.
     *
     * @param allBytes The backing byte array which contains the subset to unEscape
     * @param start    The position to start the unEscape, inclusive.
     * @param end      The position to end the unEscape, exclusive
     * @return the unescaped byte array
     */
    public static byte[] unEscape(final byte[] allBytes, final int start, final int end) {
        return unEscapeByPosition(allBytes, start, end);
    }


    /**
     * Unescapes the provided byte array - this should only be called on byte
     * arrays that have been through the {@code escape} method.
     *
     * @param allBytes The backing byte array which contains the subset to unEscape
     * @param start    The position to start the unEscape, inclusive.
     * @param end      The position to end the unEscape, exclusive
     * @return the unescaped byte array
     */
    public static byte[] unEscapeByPosition(final byte[] allBytes, final int start, final int end) {
        return unEscapeByLength(allBytes, start, end - start);
    }

    /**
     * Unescapes the provided byte array - this should only be called on byte
     * arrays that have been through the {@code escape} method.
     *
     * @param allBytes The backing byte array which contains the subset to unEscape.
     * @param offset   The position to start the unEscape, inclusive
     * @param length   The length of bytes to unEscape
     * @return the unescaped byte array
     */
    public static byte[] unEscapeByLength(final byte[] allBytes, final int offset, final int length) {
        if (allBytes.length < offset + length) {
            throw new InvalidParameterException(String.format("unEscape parameters larger than allByte.length:%d, offset:%d, length:%d", allBytes.length, offset, length));
        }
        final byte[] temp = new byte[length];
        int currentPosition = 0;
        boolean isEscaped = false;

        for (int i = offset; i < allBytes.length && i < offset + length; i++) {
            byte b = allBytes[i];
            if (isEscaped) {
                if (REPLACEMENT_CHAR == b) {
                    temp[currentPosition++] = ESCAPE_CHAR;
                } else if (ESCAPE_CHAR == b) {
                    temp[currentPosition++] = DELIMITER;
                } else {
                    temp[currentPosition++] = b;
                }
                isEscaped = false;
            } else {
                if (ESCAPE_CHAR == b) {
                    isEscaped = true;
                } else {
                    temp[currentPosition++] = b;
                }
            }
        }
        final byte[] unEscaped = new byte[currentPosition];
        System.arraycopy(temp, 0, unEscaped, 0, currentPosition);
        return unEscaped;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy