
org.refcodes.serial.ByteArraySequence Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refcodes-serial Show documentation
Show all versions of refcodes-serial Show documentation
Artifact providing generic (byte) serialization functionality including
a TTY-/COM-Port implementation of the serial framework as well as a (local)
loopback port.
The newest version!
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////
package org.refcodes.serial;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.refcodes.mixin.ConcatenateMode;
import org.refcodes.mixin.TruncateMode;
import org.refcodes.numerical.CrcAlgorithm;
import org.refcodes.numerical.Endianess;
/**
* A {@link ByteArraySequence} implements the {@link Sequence} interface by
* using chunks of byte arrays, therewith reducing array copy operations when
* working with byte fields. A {@link ByteArraySequence} is a one dimensional
* representation of a byte array of byte arrays (a two dimensional byte array).
* Each byte array inside the byte array (of byte arrays) is called a chunk.
* Using this technique we easily can create our {@link Sequence} instances
* consisting of many chunks while reducing the copying and concatenating
* efforts (and buffer allocations), providing for a low memory footprint.
*/
public class ByteArraySequence implements Sequence {
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
private byte[][] _chunks;
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Constructs an empty {@link ByteArraySequence}.
*/
public ByteArraySequence() {
_chunks = new byte[0][];
}
/**
* Constructs a {@link ByteArraySequence} from the provided byte.
*
* @param aByte The only byte out of which the {@link ByteArraySequence}
* consists.
*/
public ByteArraySequence( byte aByte ) {
_chunks = new byte[1][];
_chunks[0] = new byte[] { aByte };
}
/**
* Constructs a {@link ByteArraySequence} from the provided byte chunk.
*
* @param aBytes The only chunk out of which the {@link ByteArraySequence}
* consists.
*/
public ByteArraySequence( byte... aBytes ) {
_chunks = new byte[1][];
_chunks[0] = aBytes;
}
/**
* Constructs a {@link ByteArraySequence} from the provided byte chunks.
*
* @param aBytes The byte chunks (a two dimensional byte array) out of which
* the {@link ByteArraySequence} consists.
*/
public ByteArraySequence( byte[]... aBytes ) {
_chunks = aBytes;
}
/**
* Constructs a {@link ByteArraySequence} from the provided byte chunk.
*
* @param aBytes The only chunk out of which the {@link ByteArraySequence}
* consists.
* @param aOffset The offset from where to take the chunk data.
* @param aLength The number of bytes to take, beginning at the provided
* offset.
*/
public ByteArraySequence( byte[] aBytes, int aOffset, int aLength ) {
_chunks = new byte[1][];
_chunks[0] = Arrays.copyOfRange( aBytes, aOffset, aOffset + aLength );
}
/**
* Constructs a {@link ByteArraySequence} from the provided byte chunks.
*
* @param aBytes The byte chunks (many two dimensional byte arrays) out of
* which the {@link ByteArraySequence} consists.
*/
public ByteArraySequence( byte[][]... aBytes ) {
int theChunkCount = 0;
for ( byte[][] aByte : aBytes ) {
theChunkCount += aByte.length;
}
_chunks = new byte[theChunkCount][];
byte[][] eChunks;
int index = 0;
for ( byte[][] aByte : aBytes ) {
eChunks = aByte;
for ( byte[] eChunk : eChunks ) {
_chunks[index] = eChunk;
index++;
}
}
}
/**
* Constructs the {@link ByteArraySequence} from the content of the provided
* {@link InputStream}.
*
* @param aInputStream The {@link InputStream} from which's data to
* construct this instance.
*
* @throws IOException thrown in case reading from the {@link InputStream}
* caused problems.
*/
public ByteArraySequence( InputStream aInputStream ) throws IOException {
// ByteArrayOutputStream theByteOutputStream = new ByteArrayOutputStream();
// int eRead;
// byte[] theBuffer = new byte[BUFFER_SIZE];
// while ( (eRead = aInputStream.read( theBuffer, 0, theBuffer.length )) != -1 ) {
// theByteOutputStream.write( theBuffer, 0, eRead );
// }
// _chunks = new byte[0][];
// _chunks[0] = theByteOutputStream.toByteArray();
final ByteArrayOutputStream theByteOutputStream = new ByteArrayOutputStream();
int eByte;
while ( ( eByte = aInputStream.read() ) != -1 ) {
theByteOutputStream.write( eByte );
}
_chunks = new byte[1][];
_chunks[0] = theByteOutputStream.toByteArray();
}
/**
* Constructs a {@link ByteArraySequence} of the given initial length.
*
* @param aLength The initial length of the {@link Sequence}.
*/
public ByteArraySequence( int aLength ) {
_chunks = new byte[1][];
_chunks[0] = new byte[aLength];
}
/**
* Creates a new {@link Sequence} with the bytes from given
* {@link Sequence}.
*
* @param aSequence The {@link Sequence} from which to take the data.
*/
public ByteArraySequence( Sequence aSequence ) {
this( aSequence.getLength() );
for ( int i = 0; i < aSequence.getLength(); i++ ) {
setByteAt( i, aSequence.getByteAt( i ) );
}
}
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public void append( byte[] aBytes, int aOffset, int aLength ) {
if ( aOffset != 0 || aLength != aBytes.length ) {
final byte[] theBytes = new byte[aLength];
for ( int i = 0; i < theBytes.length; i++ ) {
theBytes[i] = aBytes[aOffset + i];
}
aBytes = theBytes;
}
final byte[][] theChunks = new byte[_chunks.length + 1][];
for ( int i = 0; i < _chunks.length; i++ ) {
theChunks[i] = _chunks[i];
}
theChunks[theChunks.length - 1] = aBytes;
_chunks = theChunks;
synchronized ( this ) {
notifyAll();
}
}
/**
* {@inheritDoc}
*/
@Override
public void append( Sequence aSequence ) {
if ( aSequence != null ) {
_chunks = toChunks( _chunks, toChunks( aSequence ) );
synchronized ( this ) {
notifyAll();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void empty() {
_chunks = new byte[0][];
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
final ByteArraySequence other = (ByteArraySequence) obj;
if ( !Arrays.deepEquals( _chunks, other._chunks ) ) {
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public byte getByteAt( int aIndex ) {
int offset = 0;
byte[] eChunk;
for ( byte[] _chunk : _chunks ) {
eChunk = _chunk;
if ( eChunk.length + offset > aIndex ) {
return eChunk[aIndex - offset];
}
offset += eChunk.length;
}
throw new IndexOutOfBoundsException( aIndex );
}
/**
* {@inheritDoc}
*/
@Override
public int getLength() {
if ( _chunks == null ) {
return -1;
}
int size = 0;
for ( byte[] _chunk : _chunks ) {
// if ( _chunks[i] != null ) {
size += _chunk.length;
// }
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode( _chunks );
return result;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator iterator() {
return new SequenceIterator();
}
/**
* {@inheritDoc}
*/
@Override
public void prepend( byte[] aBytes, int aOffset, int aLength ) {
if ( aOffset != 0 && aLength != aBytes.length ) {
final byte[] theBytes = new byte[aLength];
for ( int i = 0; i < theBytes.length; i++ ) {
theBytes[i] = aBytes[aOffset + i];
}
aBytes = theBytes;
}
final byte[][] theChunks = new byte[_chunks.length + 1][];
for ( int i = 0; i < _chunks.length; i++ ) {
theChunks[i + 1] = _chunks[i];
}
theChunks[0] = aBytes;
_chunks = theChunks;
synchronized ( this ) {
notifyAll();
}
}
/**
* {@inheritDoc}
*/
@Override
public void prepend( Sequence aSequence ) {
if ( aSequence != null ) {
_chunks = toChunks( toChunks( aSequence ), _chunks );
synchronized ( this ) {
notifyAll();
}
}
}
/**
* Replaces the content of this {@link Sequence} with the content of the
* given byte array.
*
* @param aBytes The byte array with which to replace the content.
*/
@Override
public void replace( byte[] aBytes ) {
_chunks = new byte[1][];
_chunks[0] = aBytes;
}
/**
* Replaces the content of this {@link Sequence} with the content of the
* given {@link Sequence}.
*
* @param aSequence The {@link Sequence} with which to replace the content.
*/
@Override
public void replace( Sequence aSequence ) {
if ( aSequence instanceof ByteArraySequence theSequence ) {
_chunks = theSequence._chunks;
}
else {
replace( aSequence.toBytes() );
}
}
/**
* {@inheritDoc} CAUTION: If possible, this method avoids array copying, so
* if the offset is 0 and the length the same as the byte array's length,
* then the given byte array is used internally!
*/
@Override
public void replace( byte[] aBytes, int aOffset, int aLength ) {
_chunks = new byte[1][];
if ( aOffset == 0 && aLength == aBytes.length ) {
_chunks[0] = aBytes;
}
else {
_chunks[0] = Arrays.copyOfRange( aBytes, aOffset, aOffset + aLength );
}
}
/**
* {@inheritDoc}
*/
@Override
public void replace( Sequence aSequence, int aOffset, int aLength ) {
if ( aOffset == 0 && aLength == aSequence.getLength() ) {
replace( aSequence );
}
else {
_chunks = new byte[1][];
_chunks[0] = aSequence.toBytes( aOffset, aLength );
}
}
/**
* {@inheritDoc}
*/
@Override
public void setByteAt( int aIndex, byte aByte ) {
int offset = 0;
byte[] eChunk;
for ( byte[] _chunk : _chunks ) {
eChunk = _chunk;
if ( eChunk.length + offset > aIndex ) {
eChunk[aIndex - offset] = aByte;
return;
}
offset += eChunk.length;
}
throw new IndexOutOfBoundsException( aIndex );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toAppend( byte... aBytes ) {
return toAppend( aBytes, 0, aBytes.length );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toAppend( byte[] aBytes, int aOffset, int aLength ) {
final byte[] theBytes = new byte[aLength];
for ( int i = 0; i < theBytes.length; i++ ) {
theBytes[i] = aBytes[aOffset + i];
}
final byte[][] theChunks = new byte[_chunks.length + 1][];
for ( int i = 0; i < _chunks.length; i++ ) {
theChunks[i] = _chunks[i].clone();
}
theChunks[theChunks.length - 1] = theBytes;
return new ByteArraySequence( theChunks );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toAppend( Sequence aSequence ) {
return toSequence( this, aSequence );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toClone() {
final byte[][] theClone = _chunks.clone();
for ( int i = 0; i < theClone.length; i++ ) {
theClone[i] = theClone[i].clone();
}
return new ByteArraySequence( theClone );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toConcatenate( ConcatenateMode aConcatenateMode, byte... aBytes ) {
return switch ( aConcatenateMode ) {
case PREPEND -> toPrepend( aBytes );
case APPEND -> toAppend( aBytes );
};
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toConcatenate( Sequence aSequence, ConcatenateMode aConcatenateMode ) {
return switch ( aConcatenateMode ) {
case PREPEND -> toPrepend( aSequence );
case APPEND -> toAppend( aSequence );
};
}
/**
* {@inheritDoc}
*/
@Override
public byte[] toCrcBytes( CrcAlgorithm aCrcAlgorithm, Endianess aEndianess ) {
long theChecksum = 0;
for ( int i = 0; i < getChunkCount(); i++ ) {
theChecksum = aCrcAlgorithm.toCrcChecksum( theChecksum, getChunkAt( i ) );
}
return aEndianess.toBytes( theChecksum, aCrcAlgorithm.getCrcWidth() );
}
/**
* {@inheritDoc}
*/
@Override
public byte[] toCrcBytes( long aCrcChecksum, CrcAlgorithm aCrcAlgorithm, Endianess aEndianess ) {
for ( int i = 0; i < getChunkCount(); i++ ) {
aCrcChecksum = aCrcAlgorithm.toCrcChecksum( aCrcChecksum, getChunkAt( i ) );
}
return aEndianess.toBytes( aCrcChecksum, aCrcAlgorithm.getCrcWidth() );
}
/**
* {@inheritDoc}
*/
@Override
public long toCrcChecksum( CrcAlgorithm aCrcAlgorithm ) {
long theChecksum = 0;
for ( int i = 0; i < getChunkCount(); i++ ) {
theChecksum = aCrcAlgorithm.toCrcChecksum( theChecksum, getChunkAt( i ) );
}
return theChecksum;
}
/**
* {@inheritDoc}
*/
@Override
public long toCrcChecksum( long aCrcChecksum, CrcAlgorithm aCrcAlgorithm ) {
for ( int i = 0; i < getChunkCount(); i++ ) {
aCrcChecksum = aCrcAlgorithm.toCrcChecksum( aCrcChecksum, getChunkAt( i ) );
}
return aCrcChecksum;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toPrepend( byte... aBytes ) {
return toAppend( aBytes, 0, aBytes.length );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toPrepend( byte[] aBytes, int aOffset, int aLength ) {
final byte[] theBytes = new byte[aLength];
for ( int i = 0; i < theBytes.length; i++ ) {
theBytes[i] = aBytes[aOffset + i];
}
final byte[][] theChunks = new byte[_chunks.length + 1][];
for ( int i = 0; i < _chunks.length; i++ ) {
theChunks[i + 1] = _chunks[i].clone();
}
theChunks[0] = theBytes;
return new ByteArraySequence( theChunks );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toPrepend( Sequence aSequence ) {
return toSequence( aSequence, this );
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toSequence( int aOffset, int aLength ) {
return new ByteArraySequence( toBytes( aOffset, aLength ) );
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getClass().getSimpleName() + " [length=" + getLength() + ", chunks=" + Arrays.toString( _chunks ) + "]";
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toTruncate( int aLength, TruncateMode aTruncateMode ) {
final ByteArraySequence theSequence = toClone().withTruncate( aLength, aTruncateMode );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toTruncateHead( int aLength ) {
final ByteArraySequence theSequence = toClone().withTruncateHead( aLength );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toTruncateTail( int aLength ) {
final ByteArraySequence theSequence = toClone().withTruncateTail( aLength );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toOverwrite( byte[] aBytes ) {
final ByteArraySequence theSequence = toClone().withOverwrite( aBytes );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toOverwrite( int aOffset, Sequence aSeqquence, int aBytesOffset, int aLength ) {
final ByteArraySequence theSequence = toClone().withOverwrite( aOffset, aSeqquence, aBytesOffset, aLength );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toOverwrite( int aOffset, byte[] aBytes, int aBytesOffset, int aLength ) {
final ByteArraySequence theSequence = toClone().withOverwrite( aOffset, aBytes, aBytesOffset, aLength );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toOverwrite( int aOffset, Sequence aSequence ) {
final ByteArraySequence theSequence = toClone().withOverwrite( aOffset, aSequence );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence toOverwrite( Sequence aSequence ) {
final ByteArraySequence theSequence = toClone().withOverwrite( aSequence );
return theSequence;
}
/**
* {@inheritDoc}
*/
@Override
public void truncateHead( int aLength ) {
if ( aLength >= getLength() ) {
_chunks = new byte[0][];
synchronized ( this ) {
notifyAll();
}
}
else if ( aLength > 0 ) {
final int theTruncatedLength = getLength() - aLength;
final List theChunks = new ArrayList<>();
int theLength = 0;
for ( int i = _chunks.length - 1; i > 0; i-- ) {
if ( theLength + _chunks[i].length <= theTruncatedLength ) {
theChunks.add( 0, _chunks[i] );
theLength += _chunks[i].length;
}
else {
break;
}
}
if ( theLength < theTruncatedLength ) {
final byte[] theLastChunk = toBytes( aLength, theTruncatedLength - theLength );
theChunks.add( 0, theLastChunk );
}
_chunks = theChunks.toArray( new byte[theChunks.size()][] );
synchronized ( this ) {
notifyAll();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void truncateTail( int aLength ) {
if ( aLength >= getLength() ) {
_chunks = new byte[0][];
synchronized ( this ) {
notifyAll();
}
}
else if ( aLength > 0 ) {
final int theTruncatedLength = getLength() - aLength;
final List theChunks = new ArrayList<>();
int theLength = 0;
for ( byte[] _chunk : _chunks ) {
if ( theLength + _chunk.length <= theTruncatedLength ) {
theChunks.add( _chunk );
theLength += _chunk.length;
}
else {
break;
}
}
if ( theLength < theTruncatedLength ) {
final byte[] theLastChunk = toBytes( theLength, theTruncatedLength - theLength );
theChunks.add( theLastChunk );
}
_chunks = theChunks.toArray( new byte[theChunks.size()][] );
synchronized ( this ) {
notifyAll();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withAppend( byte... aBytes ) {
append( aBytes );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withAppend( byte[] aBytes, int aOffset, int aLength ) {
append( aBytes, aOffset, aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withAppend( Sequence aSequence ) {
append( aSequence );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withConcatenate( ConcatenateMode aConcatenateMode, byte... aBytes ) {
concatenate( aConcatenateMode, aBytes );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withConcatenate( Sequence aSequence, ConcatenateMode aConcatenateMode ) {
prepend( aSequence );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withPrepend( byte... aBytes ) {
prepend( aBytes );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withPrepend( byte[] aBytes, int aOffset, int aLength ) {
prepend( aBytes, aOffset, aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withPrepend( Sequence aSequence ) {
prepend( aSequence );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withReplace( byte[] aBytes ) {
replace( aBytes );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withReplace( byte[] aBytes, int aOffset, int aLength ) {
replace( aBytes, aOffset, aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withReplace( Sequence aSequence ) {
replace( aSequence );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withReplace( Sequence aSequence, int aOffset, int aLength ) {
replace( aSequence, aOffset, aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withTruncate( int aLength, TruncateMode aTruncateMode ) {
truncate( aLength, aTruncateMode );
return this;
}
// /////////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withTruncateHead( int aLength ) {
truncateHead( aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withTruncateTail( int aLength ) {
truncateTail( aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withOverwrite( byte[] aBytes ) {
overwrite( aBytes );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withOverwrite( int aOffset, byte[] aBytes ) {
overwrite( aOffset, aBytes );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withOverwrite( int aOffset, byte[] aBytes, int aBytesOffset, int aLength ) {
overwrite( aOffset, aBytes, aBytesOffset, aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withOverwrite( int aOffset, Sequence aSequence ) {
overwrite( aOffset, aSequence );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withOverwrite( int aOffset, Sequence aSequence, int aSequenceOffset, int aLength ) {
overwrite( aOffset, aSequence, aSequenceOffset, aLength );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ByteArraySequence withOverwrite( Sequence aSequence ) {
overwrite( aSequence );
return this;
}
/**
* {@inheritDoc}
*/
@Override
public void writeTo( OutputStream aOutputStream ) throws IOException {
for ( byte[] aChunk : _chunks ) {
aOutputStream.write( aChunk );
}
}
/**
* Retrieves the chunk at the given index out of which the
* {@link ByteArraySequence} consists. The number of chunks can be
* determined with the {@link #getChunkCount()} method.
*
* @param aIndex The index of the chunk to retrieve.
*
* @return The chunks at the given index out of which this
* {@link ByteArraySequence} consists.
*
* @throws IndexOutOfBoundsException thrown in case the given index is out
* of bounds.
*/
byte[] getChunkAt( int aIndex ) {
return _chunks[aIndex];
}
/**
* Retrieves the number of chunks out of which this
* {@link ByteArraySequence} consists.
*
* @return The number of chunks.
*/
int getChunkCount() {
return _chunks.length;
}
/**
* Retrieves the chunks out of which the {@link ByteArraySequence} consists.
*
* @return The two dimensional byte array being the chunks out of which this
* {@link ByteArraySequence} consists.
*/
byte[][] getChunks() {
return _chunks;
}
/**
* Concatenates the provided chunks (two dimensional byte arrays) into one
* chunk
*
* @param aBytes The chunks to be concatenated.
*
* @return The concatenated chunks
*/
private static byte[][] toChunks( byte[][]... aBytes ) {
int length = 0;
for ( byte[][] aByte : aBytes ) {
length += aByte.length;
}
final byte[][] theChunks = new byte[length][];
byte[][] eChunks;
int index = 0;
for ( byte[][] aByte : aBytes ) {
eChunks = aByte;
for ( byte[] eChunk : eChunks ) {
theChunks[index] = eChunk;
index++;
}
}
return theChunks;
}
/**
* Converts the given {@link Sequence} to chunks. In case we already have a
* {@link ByteArraySequence}, then simply {@link #getChunks()} is returned.
*
* @param aSequence The {@link Sequence} to be converted.
*
* @return The according chunks.
*/
private static byte[][] toChunks( Sequence aSequence ) {
if ( aSequence instanceof ByteArraySequence ) {
return ( (ByteArraySequence) aSequence ).getChunks();
}
return new byte[][] { aSequence.toBytes() };
}
/**
* Removes any null values from the array.
*
* @param aSequences The array from which to remove null values.
*
* @return The normalized array.
*/
private static Sequence[] toNormalized( Sequence[] aSequences ) {
final List theSequences = new ArrayList<>();
for ( Sequence aSequence : aSequences ) {
if ( aSequence != null ) {
theSequences.add( aSequence );
}
}
return theSequences.toArray( new ByteArraySequence[theSequences.size()] );
}
/**
* Concatenates the provided {@link ByteArraySequence} elements into one
* {@link ByteArraySequence} element.
*
* @param aSequences The {@link ByteArraySequence} elements to be
* concatenated.
*
* @return The concatenated {@link ByteArraySequence}.
*/
private static ByteArraySequence toSequence( Sequence... aSequences ) {
aSequences = toNormalized( aSequences );
int length = 0;
ByteArraySequence eChunkSequence;
for ( Sequence aSequence : aSequences ) {
if ( aSequence instanceof ByteArraySequence ) {
eChunkSequence = (ByteArraySequence) aSequence;
length += eChunkSequence._chunks.length;
}
else {
length += 1;
}
}
final byte[][] theChunks = new byte[length][];
int index = 0;
for ( Sequence aSequence : aSequences ) {
if ( aSequence instanceof ByteArraySequence ) {
eChunkSequence = (ByteArraySequence) aSequence;
for ( int j = 0; j < eChunkSequence.getChunkCount(); j++ ) {
theChunks[index] = eChunkSequence._chunks[j].clone();
index++;
}
}
else {
theChunks[index] = aSequence.toBytes();
index++;
}
}
return new ByteArraySequence( theChunks );
}
// /////////////////////////////////////////////////////////////////////////
// INNER CLASSES:
// /////////////////////////////////////////////////////////////////////////
/**
* Implements the {@link Iterator} interface being appied to an instancoe of
* the {@link ByteArraySequence} type.
*/
public class SequenceIterator implements Iterator {
private int index = 0;
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return index < getLength();
}
/**
* {@inheritDoc}
*/
@Override
public Byte next() {
return getByteAt( index++ );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy