/* Copyright (c) 2003, 2004 The Regents of the University of Michigan, Trustees of Indiana University,
* Board of Trustees of the Leland Stanford, Jr., University, and The MIT Corporation
*
* Licensed under the Educational Community License Version 1.0 (the "License");
* By obtaining, using and/or copying this Original Work, you agree that you have read,
* understand, and will comply with the terms and conditions of the Educational Community License.
* You may obtain a copy of the License at:
*
* http://cvs.sakaiproject.org/licenses/license_1_0.html
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package de.rub.syssec.saaf.misc;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.Arrays;
import org.apache.http.util.ByteArrayBuffer;
/**
* Byte utilities.
*
* Some methods copied from http://www.java2s.com/Code/Java/Collections-Data-Structure/
* Doesthisbytearraybeginwithmatcharraycontent.htm
*
*/
public class ByteUtils {
/**
* Does this byte array begin with match array content?
*
* @param source
* Byte array to examine
* @param match
* Byte array to locate in <code>source</code>
* @return true If the starting bytes are equal
*/
public static boolean startsWith(byte[] source, byte[] match) {
return startsWith(source, 0, match);
}
/**
* Does this byte array begin with match array content? The check is NOT case sensitive!
*
* @param source
* Byte array to examine
* @param offset
* An offset into the <code>source</code> array
* @param match
* Byte array to locate in <code>source</code>
* @return true If the starting bytes are equal
*/
public static boolean startsWith(byte[] source, int offset, byte[] match) {
if (match.length > (source.length - offset)) {
return false;
}
for (int i = 0; i < match.length; i++) {
if (source[offset + i] != match[i]) {
// ignore cases
if (source[offset + i] >= 65 && source[offset + i] <= 90
&& source[offset + i] + 32 == match[i]) {
continue;
} else if (source[offset + i] >= 97
&& source[offset + i] <= 122
&& source[offset + i] - 32 == match[i]) {
continue;
} else
return false;
}
}
return true;
}
public static boolean endsWith(byte[] source, char c) {
return endsWith(source, new byte[] { (byte) c });
}
/**
* Does this byte array end with match array content? The check is NOT case sensitive!
*/
public static boolean endsWith(byte[] source, byte[] match) {
if (match.length > (source.length)) {
return false;
}
for (int i = 0; i < match.length; i++) {
if (match[i] != source[source.length - match.length + i]) {
if (match[i] >= 65
&& match[i] <= 90
&& match[i] + 32 == source[source.length - match.length
+ i]) {
continue;
} else if (match[i] >= 97
&& match[i] <= 122
&& match[i] - 32 == source[source.length - match.length
+ i]) {
continue;
}
return false;
}
}
return true;
}
/**
* Does the source array equal the match array?
*
* @param source
* Byte array to examine
* @param offset
* An offset into the <code>source</code> array
* @param match
* Byte array to locate in <code>source</code>
* @return true If the two arrays are equal
*/
public static boolean equals(byte[] source, byte[] match) {
if (match.length != source.length) {
return false;
}
return startsWith(source, 0, match);
}
/**
* Copies bytes from the source byte array to the destination array
*
* @param source
* The source array
* @param srcBegin
* Index of the first source byte to copy
* @param srcEnd
* Index after the last source byte to copy
* @param destination
* The destination array
* @param dstBegin
* The starting offset in the destination array
*/
public static void getBytes(byte[] source, int srcBegin, int srcEnd,
byte[] destination, int dstBegin) {
System.arraycopy(source, srcBegin, destination, dstBegin, srcEnd
- srcBegin);
}
/**
* Return a new byte array containing a sub-portion of the source array
*
* @param srcBegin
* The beginning index (inclusive)
* @param srcEnd
* The ending index (exclusive)
* @return The new, populated byte array
*/
public static byte[] subbytes(byte[] source, int srcBegin, int srcEnd) {
byte destination[];
destination = new byte[srcEnd - srcBegin];
getBytes(source, srcBegin, srcEnd, destination, 0);
return destination;
}
/**
* Return a new byte array containing a sub-portion of the source array
*
* @param srcBegin
* The beginning index (inclusive)
* @return The new, populated byte array
*/
public static byte[] subbytes(byte[] source, int srcBegin) {
return subbytes(source, srcBegin, source.length);
}
/**
* Return the array as a printable string.
*
* @param buffer
* @param breakLines Insert \n in returned String if CRLF was found
* @return
*/
public static String dumpArray(byte[] buffer, boolean breakLines) {
StringBuilder sb = new StringBuilder();
boolean lastOneIsR = false;
for (byte b : buffer) {
if (b >= 32 && b <= 126)
sb.append(new String(new byte[] { b }));
else if (b == 10) {
sb.append("\\n");
if (lastOneIsR) {
if (breakLines)
sb.append("\n");
lastOneIsR = false;
}
} else if (b == 13) {
sb.append("\\r");
lastOneIsR = true;
} else if (b == 0)
sb.append("\\0");
else
sb.append("?");
}
return sb.toString();
}
/**
* Read a line from an inputstream into a byte buffer. A line might end with a LF or an CRLF. CR's are accepted inside a line and
* are not understood as a beginning new line. This should work therefore on Mac OS X, Unix, Linux and Windows.
*
* See http://en.wikipedia.org/wiki/Newline for more.
*
* @param in the inputstream
* @param maxSize the maximum amount of bytes to read until a CRLF or LF is reached, a value of zero or smaller disables a limit (use w/ care!)
* @return the buffer where read bytes are appended, this buffer will not contain any CR's or or CRLF's at the end of the array. Null is
* returned if EOF is reached.
* @throws IOException if something is wrong w/ the stream or the maxSize is reached
*/
public static byte[] parseLine(BufferedInputStream in, int maxSize) throws IOException {
ByteArrayBuffer bab = new ByteArrayBuffer(512);
int b;
while (true) {
if (!(maxSize <= 0 || bab.length() <= maxSize)) {
throw new IOException("Maximal bytearraybuffer size of "+maxSize+" exceeded!");
}
b = in.read();
if (b == -1) {
if (bab.isEmpty()) {
// we have nothing read yet and could nothing read, we will therefore return 'null' as this
// indicates EOF.
return null;
}
else {
// return what we got so far
return bab.toByteArray();
}
}
// CRLF case
if (b == '\r') { // check if we find a \n
int next = in.read();
if (b == -1) {
// EOF; return what we got
return bab.toByteArray();
}
else if (next == '\n') { // we did
in.mark(-1); // rest mark
return bab.toByteArray(); // return the line without CRLF
} else {
// found no CRLF but only a CR and some other byte, so we need to add both to the buffer and proceed
bab.append('\r');
bab.append(b);
}
}
// LF case
else if (b == '\n') { // we found a LF and therefore the end of a line
return bab.toByteArray();
}
else { // we just found a byte which is happily appended
bab.append(b);
}
}
}
/**
* http://stackoverflow.com/questions/80476/how-to-concatenate-two-arrays-in
* -java
*
* @param <T>
* @param first
* @param rest
* @return
*/
public static byte[] concatAll(byte[] first, byte[]... rest) {
int totalLength = first.length;
for (byte[] array : rest) {
totalLength += array.length;
}
byte[] result = Arrays.copyOf(first, totalLength);
int offset = first.length;
for (byte[] array : rest) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
return result;
}
/**
* Checks if pattern is contained in source. This is just a wrapped KMP indexOf().
* @param source
* @param pattern
* @return
*/
public static boolean contains(byte[] source, byte[] pattern) {
return KMP.indexOf(source, pattern) < 0 ? false : true;
}
/**
* Checks if pattern is contained in source. This is just a wrapped KMP indexOf().
* @param source
* @param pattern
* @return
*/
public static boolean contains(byte[] source, char c) {
return KMP.indexOf(source, new byte[] {(byte)c}) < 0 ? false : true;
}
public static int indexOf(byte[] source, char c) {
return indexOf(source, c, 0);
}
public static int indexOf(byte[] source, char c, int offset) {
for (int i = offset; i < source.length; i++) {
if (source[i] == c) return i;
}
return -1;
}
/**
* Searches forwards
* @param source
* @param c
* @return
*/
public static int indexOfReverse(byte[] source, char c) {
return indexOfReverse(source, c, source.length-1);
}
/**
* Searches backwards
*/
public static int indexOfReverse(byte[] source, char c, int offset) {
for (int i = offset; i >= 0; i--) {
if (source[i] == c) return i;
}
return -1;
}
/**
* Get the first part of the array until a chosen char is found.
* @param source
* @param c the char to split at
* @param offset the offest of source
* @return
*/
public static byte[] splitAtFirstOccurence(byte[] source, char c, int offset) {
int index = indexOf(source, c, offset);
if (index < 0) return source;
else {
return subbytes(source, 0, index);
}
}
/**
* Get the last part of the array until a chosen char is found, the char is searched from the end to the beginning of source.
* @param source
* @param c
* @param offset the offest of source, from the beginning, NOT the end.
* @return
*/
public static byte[] splitAtLastOccurence(byte[] source, char c, int offset) {
int index = indexOfReverse(source, c, offset);
if (index < 0) return source;
else {
return subbytes(source, index, source.length);
}
}
}