Back to the Main Page
ByteArrayBuilder
Like StringBuilder but using an array of bytes.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
public class ByteArrayBuilder {
private byte[] bytes;
/**
* Constructs a byte array builder with no bytes in it and an initial
* capacity of 0 bytes.
*
*/
public ByteArrayBuilder() {
bytes = new byte[0];
}
/**
* Constructs a byte array builder with an initial value of bytes.
* It does not use the incoming array object.
*
* @param bytes The initial bytes value.
*/
public ByteArrayBuilder(byte[] bytes) {
this.bytes = new byte[bytes.length];
System.arraycopy(bytes, 0, this.bytes, 0, bytes.length);
}
/**
* Constructs a byte array builder with an initial value of bytes from a
* string.
* It does not use in incoming String at all.
*
* @param s The initial string value.
*/
public ByteArrayBuilder(String s) {
this(s.getBytes());
}
/**
* Append a new byte to the end.
*
* @param b The new bytes to be added.
*/
public void append(byte b) {
append(bytes.length, new byte[]{b});
}
/**
* Append a new array of bytes to the end.
*
* @param b The new array of bytes to be added.
*/
public void append(byte[] b) {
append(bytes.length, b, b.length);
}
/**
* Append a part of a new array of bytes to the end.
*
* @param b The new array of bytes to be added.
* @param l The number of bytes from the new array of bytes to include.
*/
public void append(byte[] b, int l) {
append(bytes.length, b, l);
}
/**
* Append a fixed length from a new array of bytes at the offset.
*
* @param offset where to insert this new array.
* @param b The new array of bytes.
*/
public void append(int offset, byte[] b) {
append(offset, b, b.length);
}
/**
* Append a part of a new array of bytes at the offset.
*
* @param offset where to insert this new array.
* @param b The new array of bytes.
* @param l The number of bytes from the new array of bytes.
*/
public void append(int offset, byte[] b, int l) {
int startPoint = offset;
if (startPoint > bytes.length) {
startPoint = bytes.length;
}
byte[] newBytes = new byte[bytes.length + l];
System.arraycopy(bytes, 0, newBytes, 0, startPoint);
System.arraycopy(b, 0, newBytes, startPoint, l);
System.arraycopy(bytes, startPoint, newBytes, startPoint + l, bytes.length - startPoint);
bytes = newBytes;
}
/**
* Append a new String to the end.
*
* @param s The new string to be added.
*/
public void append(String s) {
byte[] b = s.getBytes();
append(bytes.length, b, b.length);
}
/**
* Insert a new String at the offset.
*
* @param offset where to insert this new string.
* @param s The new string to be added.
*/
public void append(int offset, String s) {
byte[] b = s.getBytes();
append(offset, b, b.length);
}
/**
* Insert part of new String at the offset.
*
* @param offset where to insert this new string.
* @param s The new string to be added.
* @param l The number of bytes from the new string.
*/
public void append(int offset, String s, int l) {
byte[] b = s.getBytes();
append(offset, b, l);
}
/**
* Append another ByteArrayBuilder at the end.
*
* @param ba The new ByteArrayBuilder to be added.
*/
public void append(ByteArrayBuilder ba) {
byte[] b = ba.getBytes();
append(bytes.length, b, b.length);
}
/**
* Append another ByteArrayBuilder at the offset.
*
* @param offset where to insert this new ByteArrayBuilder.
* @param ba The new ByteArrayBuilder to be added
*/
public void append(int offset, ByteArrayBuilder ba) {
byte[] b = ba.getBytes();
append(offset, b, b.length);
}
/**
* Append part another ByteArrayBuilder at the offset.
*
* @param offset where to insert this new array.
* @param ba The new ByteArrayBuilder to be added.
* @param l The number of bytes from the new ByteArrayBuilder.
*/
public void append(int offset, ByteArrayBuilder ba, int l) {
byte[] b = ba.getBytes();
append(offset, b, l);
}
/**
* Fill the array with count number of bytes at the end.
*
* @param b The byte to fill with.
* @param count the number of bytes to fill.
*/
public void fill(byte b, int count) {
fill(bytes.length, b, count);
}
/**
* Fill the array with count number of bytes at the offset.
*
* @param offset where to insert this new fill of bytes.
* @param b The byte to fill with.
* @param count the number of bytes to fill.
*/
public void fill(int offset, byte b, int count) {
byte[] bs = new byte[count];
for (int i = 0; i < count; i++) {
bs[i] = b;
}
append(offset, bs);
}
/**
* Fill the array with count number of chars at the end.
*
* @param c The char to fill with.
* @param count the number of bytes to fill.
*/
public void fill(char c, int count) {
fill(bytes.length, c, count);
}
/**
* Fill the array with count number of chars at the end.
*
* @param offset where to insert this new char.
* @param c The char to fill with.
* @param count the number of bytes to fill.
*/
public void fill(int offset, char c, int count) {
byte[] bs = new byte[count];
for (int i = 0; i < count; i++) {
bs[i] = (byte) c;
}
append(offset, bs);
}
/**
* Fill the array with count number of Strings at the end.
*
* @param s The string to fill with.
* @param count the number of bytes to fill.
*/
public void fill(String s, int count) {
fill(bytes.length, s, count);
}
private static String SPACE = " ";
/**
* Fill the array with count number of Strings at the offset.
* If the string is empty or null, a space is used.
* The count is the number of times the whole string is used.
*
* @param offset where to insert this new string.
* @param s The string to fill with.
* @param count the number of strings to fill.
*/
public void fill(int offset, String s, int count) {
byte[] sb = s != null && !s.isEmpty() ? s.getBytes() : SPACE.getBytes();
byte[] bs = new byte[sb.length * count];
for (int i = 0; i < count; i++) {
System.arraycopy(sb, 0, bs, i * sb.length, sb.length);
}
append(offset, bs);
}
private int correctFrom(int from, int to) {
int f = from;
if (to < from) {
f = to;
}
if (f < 0) {
f = 0;
}
if (f > bytes.length) {
f = bytes.length;
}
return f;
}
private int correctTo(int from, int to) {
int t = to;
if (to < from) {
t = from;
}
if (t < 0) {
t = 0;
}
if (t > bytes.length) {
t = bytes.length;
}
return t;
}
private void remove(int from, int to) {
int f = correctFrom(from, to);
int t = correctTo(from, to);
int shift = t - f;
byte[] newBytes = new byte[bytes.length - shift];
System.arraycopy(bytes, 0, newBytes, 0, f);
System.arraycopy(bytes, t, newBytes, f, bytes.length - t);
bytes = newBytes;
}
/**
* Remove a byte from the at from.
*
* @param from byte to be removed from.
*/
public void removeByte(int from) {
remove(from, from + 1);
}
/**
* Remove byes from the array starting at from and ending at to.
* Like strings/string builders, this will remove from 'from' to 'to' - 1.
* e.g.
* [A,B,C,D].remove(2, 4) = ['A','D'].
* so you can remove to the result of a found call and not loose the found part.
*
*
* @param from remove bytes from here.
* @param to remove bytes to here.
*/
public void removeBytes(int from, int to) {
remove(from, to);
}
/**
* Replace part of the bytes with a string.
*
* @param s the string to place the after removal from 'from' to 'to'.
* @param from replace from here
* @param to to here
*/
public void replace(String s, int from, int to) {
remove(from, to);
append(from, s);
}
/**
* Replace part of the bytes with another array of bytes.
*
* @param b the new array of bytes to place the after removal from 'from' to 'to'.
* @param from remove from here
* @param to remove to
*/
public void replace(byte[] b, int from, int to) {
remove(from, to);
append(from, b, b.length);
}
/**
* Replace part of the bytes with part of another array of bytes.
*
* @param b the new array of bytes to place the after removal from 'from' to 'to'.
* @param from remove from here
* @param to remove to
* @param l The number of bytes from the new array of bytes.
*/
public void replace(byte[] b, int from, int to, int l) {
remove(from, to);
append(from, b, l);
}
/**
* Replace a string with another string.
*
* @param s The string to be replaced
* @param r The String to be added
*/
public void replace(String s, String r) {
int from = indexOf(s);
int to = from + s.length();
replace(r.getBytes(), from, to, r.length());
}
/**
* Replace a byte array with another byte array.
*
* @param b The array of bytes to be replaced
* @param r The array of bytes to be added
*/
public void replace(byte[] b, byte[] r) {
int from = indexOf(b);
int to = from + b.length;
replace(r, from, to, r.length);
}
/**
* Replace a ByteArrayBuilder content with another ByteArrayBuilder content.
*
* @param ba The ByteArrayBuilder content to be replaced.
* @param r The ByteArrayBuilder content to be added.
*/
public void replace(ByteArrayBuilder ba, ByteArrayBuilder r) {
int from = indexOf(ba);
int to = from + ba.size();
replace(r.getBytes(), from, to, r.length());
}
/**
* Replace all string a with string r.
*
* @param s The string to be replaced.
* @param r The string to be added.
*/
public void replaceAll(String s, String r) {
while (indexOf(s) > -1) {
replace(s, r);
}
}
/**
* Replace all byte array a with byte array r.
*
* @param b The array to be replaced.
* @param r The array to be added.
*/
public void replaceAll(byte[] b, byte[] r) {
while (indexOf(b) > -1) {
replace(b, r);
}
}
/**
* Replace all ByteArrayBuilder ba content with ByteArrayBuilder r content.
*
* @param ba The ByteArrayBuilder content to be replaced.
* @param r The ByteArrayBuilder content to be added.
*/
public void replaceAll(ByteArrayBuilder ba, ByteArrayBuilder r) {
while (indexOf(ba) > -1) {
replace(ba, r);
}
}
/**
* Find the first instance of a string.
*
* @param s The string to search for.
* @return the index of the string.
*/
public int indexOf(String s) {
return indexOf(s.getBytes(), 0);
}
/**
* Find the first instance of a string on or after index.
*
* @param s The string to search for.
* @param index the starting point.
* @return
*/
public int indexOf(String s, int index) {
return indexOf(s.getBytes(), index);
}
/**
* Find the first instance of a byte array.
*
* @param b The byte array to search for.
* @return the index of the byte array.
*/
public int indexOf(byte[] b) {
return indexOf(b, 0);
}
/**
* Find the first instance of a ByteArrayBuilder content.
*
* @param ba the ByteArrayBuilder whose content we ar looking for.
* @return the index of the ByteArrayBuilder content.
*/
public int indexOf(ByteArrayBuilder ba) {
return indexOf(ba.getBytes(), 0);
}
/**
* Find the first instance of a ByteArrayBuilder content on or after index.
*
* @param ba the ByteArrayBuilder whose content we ar looking for.
* @param index the starting point.
* @return the index of the ByteArrayBuilder content.
*/
public int indexOf(ByteArrayBuilder ba, int index) {
return indexOf(ba.getBytes(), index);
}
/**
* Find the last instance of a string.
*
* @param s The string to search for.
* @return the index of the string.
*/
public int lastIndexOf(String s) {
return lastIndexOf(s.getBytes(), bytes.length - 1);
}
/**
* Find the last instance of a string on or before index.
*
* @param s The string to search for.
* @param index The starting point.
* @return the index of the string.
*/
public int lastIndexOf(String s, int index) {
return lastIndexOf(s.getBytes(), index);
}
/**
* Find the last instance of a byte array.
*
* @param b The byte array to search for.
* @return the index of the byte array.
*/
public int lastIndexOf(byte[] b) {
return lastIndexOf(b, bytes.length - 1);
}
/**
* Find the last instance of a ByteArrayBuilder content.
*
* @param ba The ByteArrayBuilder content to search for.
* @return the index of the ByteArrayBuilder content.
*/
public int lastIndexOf(ByteArrayBuilder ba) {
return lastIndexOf(ba.getBytes(), 0);
}
/**
* Find the last instance of a ByteArrayBuilder content.
*
* @param ba The ByteArrayBuilder content to search for.
* @param index The starting point.
* @return the index of the ByteArrayBuilder content.
*/
public int lastIndexOf(ByteArrayBuilder ba, int index) {
return lastIndexOf(ba.getBytes(), index);
}
/**
* Returns a subset of this content.
* From start to end inclusive.
*
* @param from the start point
* @param to the end point
* @return An array of those bytes
*/
public byte[] subset(int from, int to) {
int f = correctFrom(from, to);
int t = correctTo(from, to);
byte[] res = new byte[t - f];
System.arraycopy(bytes, f, res, 0, t - f);
return res;
}
/**
* Returns a subset of this content.
* From start to the end of the content.
*
* @param from the start point
* @return An array of those bytes
*/
public byte[] subset(int from) {
return subset(from, size());
}
private boolean isWhiteSpace(byte b) {
return Character.isWhitespace(b);
}
/**
* Returns a new trimmed version of the contents in a ByteArrayBuilder.
* This removes white space from the front and the end.
*
* @return The new, trimmed version.
*/
public ByteArrayBuilder trim() {
if (isBlank()) {
return new ByteArrayBuilder();
}
int firstNoneWhiteSpace = -1;
int lastNoneWhiteSpace = bytes.length;
while (isWhiteSpace(byteAt(++firstNoneWhiteSpace))) {}
while (isWhiteSpace(byteAt(--lastNoneWhiteSpace))) {}
return buildByteArray(firstNoneWhiteSpace, lastNoneWhiteSpace + 1);
}
/**
* Check to see in this is empty.
*
* @return true if it is empty or false if it isn't.
*/
public boolean isEmpty() {
return bytes.length == 0;
}
/**
* Check to see in this only has white space.
*
* @return true if it is blank or false if it isn't.
*/
public boolean isBlank() {
for (byte b : getBytes()) {
if (!isWhiteSpace(b)) {
return false;
}
}
return true;
}
/**
* Returns a string that is the sub string of this.
* Starting at from and ending at to inclusive.
*
* @param from the start.
* @param to the end.
* @return a string.
*/
public String substring(int from, int to) {
return new String(subset(from, to));
}
/**
* Returns a string that is the sub string of this.
* Starting at from and ending at the end inclusive.
*
* @param from the start.
* @return a string.
*/
public String substring(int from) {
return new String(subset(from));
}
/**
* Returns the index of a byte array.
* Starting from index.
*
* @param b the array of bytes to search for
* @param index the starting point
* @return
*/
public int indexOf(byte[] b, int index) {
for (int i = index; i <= (bytes.length - b.length); i++) {
boolean found = true;
int j = 0;
while (found && (j < b.length)) {
found &= (b[j] == bytes[i + j]);
j++;
}
if (found) {
return i;
}
}
return -1;
}
/**
* Returns the last index of a byte array.
* Starting from index.
*
* @param b the array of bytes to search for
* @param index the starting point
* @return
*/
public int lastIndexOf(byte[] b, int index) {
for (int i = index - b.length + 1; i >= 0; i--) {
boolean found = true;
int j = 0;
while (found && (j < b.length)) {
found &= (b[j] == bytes[i + j]);
j++;
}
if (found) {
return i;
}
}
return -1;
}
/**
* Returns true if the string is present in this.
*
* @param s The string to search for.
* @return true if it is there, false if not.
*/
public boolean contains(String s) {
return contains(s.getBytes());
}
/**
* Returns true if the ByteArrayBuilder content is present in this.
*
* @param ba The ByteArrayBuilder whose content we are searching for.
* @return true if it is there, false if not.
*/
public boolean contains(ByteArrayBuilder ba) {
return contains(ba.getBytes());
}
/**
* Returns true if the byte array is present in this.
*
* @param b The byte array we are searching for.
* @return true if it is there, false if not.
*/
public boolean contains(byte[] b) {
return indexOf(b) > -1;
}
/**
* Returns the count of the times the string is in this.
* From 'from' to 'to' inclusive.
*
* @param s The string to search for.
* @param fromIndex starting from here.
* @param toIndex ending here.
* @return the number of times the value is found.
*/
public int count(String s, int fromIndex, int toIndex) {
return count(s.getBytes(), fromIndex, toIndex);
}
/**
* Returns the count of the times the ByteArrayBuilder content is in this.
* From 'from' to 'to' inclusive.
*
* @param ba The ByteArrayBuilder content to search for.
* @param fromIndex starting from here.
* @param toIndex ending here.
* @return the number of times the value is found.
*/
public int count(ByteArrayBuilder ba, int fromIndex, int toIndex) {
return count(ba.getBytes(), fromIndex, toIndex);
}
/**
* Returns the count of the times the string is in this.
* From 'from' to the end inclusive.
*
* @param s The string to search for.
* @param fromIndex starting from here.
* @return the number of times the value is found.
*/
public int count(String s, int fromIndex) {
return count(s.getBytes(), fromIndex, size());
}
/**
* Returns the count of the times the ByteArrayBuilder content is in this.
* From 'from' to the end inclusive.
*
* @param ba The ByteArrayBuilder content to search for.
* @param fromIndex starting from here.
* @return the number of times the value is found.
*/
public int count(ByteArrayBuilder ba, int fromIndex) {
return count(ba.getBytes(), fromIndex, size());
}
/**
* Returns the count of the times the string is in this.
*
* @param s The string to search for.
* @return the number of times the value is found.
*/
public int count(String s) {
return count(s.getBytes(), 0, size());
}
/**
* Returns the count of the times the ByteArrayBuilder content is in this.
*
* @param ba The ByteArrayBuilder content to search for.
* @return the number of times the value is found.
*/
public int count(ByteArrayBuilder ba) {
return count(ba.getBytes(), 0, size());
}
/**
* Returns the count of the times the ByteArrayBuilder content is in this.
*
* @param b The byte array to search for.
* @return the number of times the value is found.
*/
public int count(byte[] b) {
return count(b, 0, size());
}
/**
* Returns the count of the times the ByteArrayBuilder content is in this.
*
* @param b The byte array to search for.
* @param fromIndex starting from here.
* @return the number of times the value is found.
*/
public int count(byte[] b, int fromIndex) {
return count(b, fromIndex, size());
}
/**
* Returns the count of the times the ByteArrayBuilder content is in this.
*
* @param b The byte array to search for.
* @param fromIndex starting from here.
* @param toIndex ending here.
* @return the number of times the value is found.
*/
public int count(byte[] b, int fromIndex, int toIndex) {
int count = 0;
int i = fromIndex;
while ((i < toIndex) && (i > -1)) {
i = indexOf(b, i);
if ((i < toIndex) && (i > -1)) {
count++;
i++;
}
}
return count;
}
/**
* Build a new ByteArrayBuilder from a part of this one.
* From 'from' to 'to' inclusive. Its contents are
* new, so it doesn't interfere with this one.
*
* @param from stating point.
* @param to ending point.
* @return a new ByteArrayBuilder.
*/
public ByteArrayBuilder buildByteArray(int from, int to) {
return new ByteArrayBuilder(subset(from, to));
}
/**
* Build a new ByteArrayBuilder from a part of this one.
* From 'from' to the end. Its contents are
* new, so it doesn't interfere with this one.
*
* @param from stating point.
* @return a new ByteArrayBuilder.
*/
public ByteArrayBuilder buildByteArray(int from) {
return new ByteArrayBuilder(subset(from));
}
/**
* Write the contents to a stream.
*
* @param stream The stream to write the contents to.
* @throws IOException if something goes wrong.
*/
public void write(OutputStream stream) throws IOException {
stream.write(bytes);
}
/**
* Reads the contents to a stream.
*
* @param stream The stream to read the contents from.
* @throws IOException if something goes wrong.
*/
public void read(InputStream stream) throws IOException {
byte[] b = new byte[10240]; // 10K at a time...
int r;
while ((r = stream.read(b)) > -1) {
append(b, r);
}
}
/**
* Return the char at a given index.
*
* @param index The index we are interested in.
* @return the char at that index.
*/
public char charAt(int index) {
if ((index > 0) && (index < bytes.length)) {
return (char) bytes[index];
}
return 0xffff;
}
/**
* Return the byte at a given index.
*
* @param index The index we are interested in.
* @return the byte at that index.
*/
public byte byteAt(int index) {
if ((index >= 0) && (index < bytes.length)) {
return bytes[index];
}
return -1;
}
/**
* Returns the content as a string.
*
* @return the string that has this content.
*/
@Override
public String toString() {
return new String(bytes);
}
/**
* Returns the content as a string for a specific character set.
*
* @param charset The character set to use.
* @return the string that has this content.
*/
public String toString(Charset charset) {
return new String(bytes, charset);
}
/**
* Returns how big the array is.
* same as length() as this is an object and an array of objects.
*
* @return the size of the array.
*/
public int size() {
return bytes.length;
}
/**
* Returns how big the array is.
* same as size() as this is an object and an array of objects.
*
* @return the size of the array.
*/
public int length() {
return bytes.length;
}
/**
* Return just the contents as an array.
*
* @return The array of bytes.
*/
public byte[] getBytes() {
return bytes;
}
private ByteArrayBuilder getByteArraySegment(byte[] divider, int segmentIndex) {
int segment = 0;
int segmentPartStart = 0;
while (segment < segmentIndex) {
segmentPartStart = indexOf(divider, segmentPartStart) + divider.length;
segment++;
}
int segmentPartEnd = indexOf(divider, segmentPartStart);
if (segmentPartEnd != -1) {
return buildByteArray(segmentPartStart, segmentPartEnd);
}
return buildByteArray(segmentPartStart);
}
/**
* Splits this into separate ByteArrayBuilders based on the string.
* This will be an array of new ByteArrayBuilders.
*
* @param s The string separator.
* @return an array of ByteArrayBuilder.
*/
public ByteArrayBuilder[] split(String s) {
return split(s.getBytes());
}
/**
* Splits this into separate ByteArrayBuilders based on the content of a ByteArrayBuilder.
* This will be an array of new ByteArrayBuilders.
*
* @param ba the ByteArrayBuilder separator.
* @return an array of ByteArrayBuilder.
*/
public ByteArrayBuilder[] split(ByteArrayBuilder ba) {
return split(ba.getBytes());
}
/**
* Splits this into separate ByteArrayBuilders based on the byte array.
* This will be an array of new ByteArrayBuilders.
*
* @param b the byte array builder separator.
* @return
*/
public ByteArrayBuilder[] split(byte[] b) {
int entryCount = count(b);
if (entryCount > 0) {
ByteArrayBuilder[] byteArrays = new ByteArrayBuilder[entryCount + 1];
for (int segmentIndex = 0; segmentIndex < entryCount + 1; segmentIndex++) {
byteArrays[segmentIndex] = getByteArraySegment(b, segmentIndex);
}
return byteArrays;
}
return new ByteArrayBuilder[]{buildByteArray(0)};
}
/**
* Load content from a file.
*
* @param file The file to load.
* @throws IOException If anything goes wrong.
*/
public void loadFrom(File file) throws IOException {
bytes = new byte[0];
appendFrom(file);
}
/**
* Append content from a file.
*
* @param file The file to load.
* @throws IOException If anything goes wrong.
*/
public void appendFrom(File file) throws IOException {
try (FileInputStream fis = new FileInputStream(file)) {
byte[] b = new byte[10240];
int r;
while ((r = fis.read(b)) > -1) {
append(b, r);
}
}
}
/**
* Checks to see if the this content equals the string.
*
* @param s The string to check against.
* @return true if it is false if not.
*/
public boolean equals(String s) {
return equals(s.getBytes());
}
/**
* Checks to see if the this content equals the content of another ByteArrayBuilder.
*
* @param ba The ByteArrayBuilder to check against.
* @return true if it is false if not.
*/
public boolean equals(ByteArrayBuilder ba) {
return equals(ba.getBytes());
}
/**
* Checks to see if the this content equals the byte array.
*
* @param b The ByteArrayBuilder to check against.
* @return true if it is false if not.
*/
public boolean equals(byte[] b) {
if (length() != b.length) {
return false;
}
for (int i = 0; i < length(); i++) {
if (bytes[i] != b[i]) {
return false;
}
}
return true;
}
/**
* Checks to see if the this content equals another object.
*
* @param obj The object to check.
* @return true if it is, false if it isn't.
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof byte[] b) {
return equals(b);
}
if (obj instanceof ByteArrayBuilder ba) {
return equals(ba);
}
if (obj instanceof String s) {
return equals(s);
}
return false;
}
/**
* As part of the equals thing.
*
* @return The hash code of the contents.
*/
@Override
public int hashCode() {
return Arrays.hashCode(bytes);
}
}
Back to the Main Page