📄 fscodec.java
字号:
/*
* FSCodec.java
* Transform Utilities
*
* Copyright (c) 2001-2006 Flagstone Software Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Flagstone Software Ltd. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.flagstone.transform.util;
/**
* @deprecated FSCoded is replaced by FSCoder from com.flagstone.transform so
* there is only one class for reading and writing data.
*
* FSCodec is a similar to Java stream classes, allowing words and bit fields to be read
* and written from an internal array of bytes. FSCodec supports both little-endian
* and big-endian byte ordering. The primary use of the class is to support post-processing
* of sound files loaded using the FSSoundConstructor class where the encoded sound samples
* contain bits fields. For example compressing 16-bit, byte-aligned sound samples to the
* ADPCM format. However the class may be used in any situation where data must be encoded
* or decoded to an array of bytes.
*
* The FSCodec class maintains an internal pointer which points to the next bit in the internal
* array where data will be read or written. When calculating an offset in bytes to jump to
* simply multiply the offset by 8 for the correct bit position. The class provides accessor
* methods, getPosition() and setPosition() to change the location of the internal pointer.
*
* When writing to an array the size of the array is changed dynamically should a write
* operation cause a buffer overflow. For reads if an overflow results then the bits/bytes
* that overflowed will be set to zero, rather than throwing an exception. The eof() method
* can be used to determine whether the end of the buffer has been reached.
*/
public class FSCodec
{
/**
* Identifies that multibyte words are stored in little-endian format with the least
* significant byte in a word stored first.
*/
public static final int LITTLE_ENDIAN = 0;
/**
* Identifies that multibyte words are stored in big-endian format with the most
* significant byte in a word stored first.
*/
public static final int BIG_ENDIAN = 1;
private int byteOrder = LITTLE_ENDIAN;
private byte[] data = null;
private int ptr = 0;
private int end = 0;
/**
* Constructs and FSCodec object containing an array of bytes with the specified byte
* ordering.
*
* @param order the byte-order for words, either FSCodec.LITTLE_ENDIAN or FSCodec.BIG_ENDIAN.
* @param bytes an array of bytes where the data will be read or written.
*/
public FSCodec(int order, byte[] bytes)
{
byteOrder = order;
data = new byte[bytes.length];
System.arraycopy(bytes, 0, data, 0, bytes.length);
end = data.length << 3;
}
/**
* Constructs and FSCodec object containing an array of bytes with the specified byte
* ordering.
*
* @param order the byte-order for words, either FSCodec.LITTLE_ENDIAN or FSCodec.BIG_ENDIAN.
* @param size the size of the internal buffer to be created.
*/
public FSCodec(int order, int size)
{
byteOrder = order;
data = new byte[size];
end = data.length << 3;
}
/**
* Returns a copy of the array of bytes.
*
* @return a copy of the internal buffer.
*/
public byte[] getData()
{
int length = (ptr + 7) >> 3;
byte[] bytes = new byte[length];
System.arraycopy(data, 0, bytes, 0, length);
return bytes;
}
/**
* Sets the array of bytes used to read or write data to. The size of the array must be
* calculated in advance to avoid buffer overflows.
*
* @param bytes a byte array that will be used as the internal buffer.
*/
public void setData(byte[] bytes)
{
data = bytes;
ptr = 0;
end = data.length << 3;
}
/**
* Sets the array of bytes used to read or write data to. The byte-order for words read
* or written is also specified. The size of the array must be calculated in advance to
* avoid buffer overflows.
*
* @param order the byte-order for words, either FSCodec.LITTLE_ENDIAN or FSCodec.BIG_ENDIAN.
* @param bytes a byte array that will be used as the internal buffer.
*/
public void setData(int order, byte[] bytes)
{
byteOrder = order;
data = bytes;
ptr = 0;
end = data.length << 3;
}
/**
* Returns the offset, in bits, from the start of the buffer where the next value will be
* read or written.
*
* @return the offset in bits where the next value will be read or written.
*/
public int getPosition()
{
return ptr;
}
/**
* Sets the offset, in bits, from the start of the buffer where the next value will be
* read or written. If the offset falls outside of the bits range supported by the buffer
* then the pointer is clamped to either the start or end of the buffer.
*
* @param offset the offset in bits from the start of the array of bytes.
*/
public void setPosition(int offset)
{
if (offset < 0)
ptr = 0;
else if (offset > end)
ptr = end;
else
ptr = offset;
}
/**
* Moves the internal pointer forward so it is aligned on a byte boundary. All word
* values read and written to the internal buffer must be byte-aligned.
*/
public void alignToByte()
{
ptr = (ptr+7) & ~7;
}
/**
* Returns true of the internal pointer is at the end of the buffer.
*
* @return true if the pointer is at the end of the buffer, false otherwise.
*/
public boolean eof()
{
return ptr >= end;
}
/**
* Searches the internal buffer for a bit pattern and advances the pointer to
* the start of the bit field, returning true to signal a successful search.
* If the bit pattern cannot be found then the method returns false and the
* position of the internal pointer is not changed.
*
* The step, in bits, added to the pointer can be specified, allowing the
* number of bits being searched to be independent of the location in the
* internal buffer. This is useful for example when searching for a bit
* field that begins on a byte or word boundary.
*
* @param value an integer containing the bit patter to search for.
* @param numberOfBits least significant n bits in the value to search for.
* @param step the increment in bits to add to the internal pointer as the buffer
* is searched.
* @return true if the pattern was found, false otherwise.
*/
public boolean findBits(int value, int numberOfBits, int step)
{
boolean found = false;
int start = ptr;
int val = 0;
if (numberOfBits < 1 || numberOfBits > 32)
throw new IllegalArgumentException("Number of bits must be in the range 1..32.");
for (; ptr < end; ptr += step)
{
val = readBits(numberOfBits, false);
ptr -= numberOfBits;
if (val == value)
{
found = true;
break;
}
}
if (found == false)
ptr = start;
return found;
}
/**
* Searches the internal buffer for a word and advances the pointer to the location
* where the word was found, returning true to signal a successful search. The
* search will begin on the next byte boundary. If word cannot be found then the
* method returns false and the position of the internal pointer is not changed.
*
* Specifying the number of bytes in the search value allows word of either 8, 16,
* 24 or 32 bits to be searched for. Searches for words are performed faster than
* using the findBits() method.
*
* @param value an integer containing the word to search for.
* @param numberOfBytes least significant n bytes in the value to search for.
* @param step the increment in bits to add to the internal pointer as the buffer
* is searched.
* @return true if the pattern was found, false otherwise.
*/
public boolean findWord(int value, int numberOfBytes, int step)
{
boolean found = false;
int start = ptr;
int val = 0;
if (numberOfBytes < 1 || numberOfBytes > 4)
throw new IllegalArgumentException("Number of bytes must be in the range 1..4.");
if ((ptr & 7) > 0)
ptr = (ptr+7) & ~7;
for (; ptr < end; ptr += step)
{
val = readWord(numberOfBytes, false);
ptr -= (numberOfBytes*8);
if (val == value)
{
found = true;
break;
}
}
if (found == false)
ptr = start;
return found;
}
/**
* Read a bit field from the internal buffer.
*
* If a buffer overflow occurs then the number of bits which cause the overflow will
* be set to zero.
*
* @param numberOfBits the number of bits to read.
* @param signed a boolean flag indicating whether the value read should be sign extended.
* @return the value read.
*/
public int readBits(int numberOfBits, boolean signed)
{
int value = 0;
if (numberOfBits < 1 || numberOfBits > 32)
throw new IllegalArgumentException("Number of bits must be in the range 1..32.");
int index = ptr >> 3;
int base = (data.length - index > 4) ? 0 : (4 - (data.length - index))*8;
for (int i=32; i>base; i-=8, index++)
value |= (data[index] & 0x000000FF) << (i-8);
value <<= ptr % 8;
if (signed)
value >>= 32 - numberOfBits;
else
value >>>= 32 - numberOfBits;
ptr += numberOfBits;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -