BitStreamUnit


2006-12-08 09:37:44 AM
off-topic10
unit BitStreamUnit;
interface
uses
SysUtils,Classes;
const
DefaultZeroValue = 0.00001;
type
TBitStream = class
private
FArrayGrowthAmount: Integer;
FBitCount: LongWord;
FBitIndex: LongWord;
FDataArray: array of Byte;
public
constructor Create; overload;
constructor Create(var SourceData; Count: LongWord); overload;
destructor Destroy; override;
procedure Clear;
procedure Reset;
procedure UseData(var SourceData; Count: LongWord);
// each write/read function returns the number of bits written/read
// this stores a boolean value as a single bit (False=0/True=1)
function Write(Value: Boolean): Integer; overload;
// stores a number of bytes using the Byte overloaded Write method
function Write(var Buffer; Count: LongInt): Longint; overload;
// stores BitCount number of bits starting at StartBitIndex
(0,1,2,..n - 1)
// from the memory location starting at Value (LSB - MSB)
function WriteBits(var Value; StartBitIndex,BitCount: Integer): Integer;
function Write(var Value: AnsiString): Integer; overload; virtual;
// each half of the following ordinal values is checked to see if it
// is zero. If it is zero, then a 1 bit is written,
// else a 0 is written followed by the half data.
function Write(var Value: Byte): Integer; overload; virtual;
function Write(var Value: Shortint): Integer; overload; virtual;
function Write(var Value: Smallint): Integer; overload; virtual;
function Write(var Value: LongInt): Integer; overload; virtual;
function Write(var Value: Word): Integer; overload; virtual;
function Write(var Value: LongWord): Integer; overload; virtual;
// if any of the floating point values are closer to zero than
ZeroValue,
// then a 1 bit is written,
// else a 0 bit is written followed by the floating point data as bytes
function Write(var Value: Single; ZeroValue: Single = DefaultZeroValue):
Integer; overload; virtual;
function Write(var Value: Double; ZeroValue: Single = DefaultZeroValue):
Integer; overload; virtual;
function Write(var Value: Extended; ZeroValue: Single =
DefaultZeroValue): Integer; overload; virtual;
// retrieves a single bit from the stream (False=0/True=1) as a boolean
function Read(var Value: Boolean): Integer; overload;
// retrieves a number of bytes using the Byte overloaded Write method
function Read(var Buffer; Count: Longint): Longint; overload;
function ReadBits(var Value; StartBitIndex,BitCount: Integer): Integer;
function Read(var Value: AnsiString): Integer; overload; virtual;
// each half of the following ordinal values are decoded in the
opposite
// way as they were encoded in the Write methods.
function Read(var Value: Byte): Integer; overload; virtual;
function Read(var Value: Shortint): Integer; overload; virtual;
function Read(var Value: Smallint): Integer; overload; virtual;
function Read(var Value: LongInt): Integer; overload; virtual;
function Read(var Value: Word): Integer; overload; virtual;
function Read(var Value: LongWord): Integer; overload; virtual;
// each half of the following floating point values are decoded in the
// opposite way as they were encoded in the Write methods.
function Read(var Value: Single): Integer; overload; virtual;
function Read(var Value: Double): Integer; overload; virtual;
function Read(var Value: Extended): Integer; overload; virtual;
procedure LoadFromStream(const Stream: TStream);
procedure SaveToStream(const Stream: TStream);
procedure LoadFromFile(const FileName: AnsiString);
procedure SaveToFile(const FileName: AnsiString);
function Data: Pointer;
function NumberOfBitsUsed: LongWord;
function NumberOfBytesUsed: LongWord;
end;
implementation
constructor TBitStream.Create;
begin
inherited Create;
FArrayGrowthAmount := 50;
SetLength(FDataArray,0);
Clear;
end;
constructor TBitStream.Create(var SourceData; Count: LongWord);
begin
Create;
UseData(SourceData,Count);
end;
procedure TBitStream.UseData(var SourceData; Count: LongWord);
begin
SetLength(FDataArray,Count);
if(Count>0)then
Move(PByteArray(@SourceData)[0],FDataArray[0],Count);
FBitCount := Count shl 3;
Reset;
end;
destructor TBitStream.Destroy;
begin
FDataArray := nil;
inherited Destroy;
end;
procedure TBitStream.Clear;
begin
FBitIndex := 0;
FBitCount := 0;
end;
procedure TBitStream.Reset;
begin
FBitIndex := 0;
end;
function TBitStream.Data: Pointer;
begin
Result := nil;
if(High(FDataArray)>= 0)then
Result := @FDataArray[0];
end;
function TBitStream.NumberOfBitsUsed: LongWord;
begin
Result := FBitCount;
end;
function TBitStream.NumberOfBytesUsed: LongWord;
begin
Result := (FBitCount + 7) shr 3;
end;
procedure TBitStream.LoadFromStream(const Stream: TStream);
begin
Clear;
Stream.Read(FBitCount,SizeOf(FBitCount));
if(FBitCount>0)then
begin
if(NumberOfBytesUsed>High(FDataArray) + 1)then
SetLength(FDataArray,NumberOfBytesUsed);
Stream.Read(FDataArray[0],NumberOfBytesUsed);
end;
end;
procedure TBitStream.SaveToStream(const Stream: TStream);
begin
Stream.Write(FBitCount,SizeOf(FBitCount));
if(FBitCount>0)then
Stream.Write(FDataArray[0],NumberOfBytesUsed);
end;
procedure TBitStream.LoadFromFile(const FileName: AnsiString);
var
fs: TFileStream;
begin
fs := TFileStream.Create(FileName,fmOpenRead or fmShareDenyNone);
LoadFromStream(fs);
fs.Free;
end;
procedure TBitStream.SaveToFile(const FileName: AnsiString);
var
fs: TFileStream;
begin
fs := TFileStream.Create(FileName,fmCreate or fmShareDenyWrite);
SaveToStream(fs);
fs.Free;
end;
//---------------------TBitStream write
methods-------------------------------
function TBitStream.Write(var Buffer; Count: LongInt): Longint;
var
i: LongInt;
begin
Result := 0;
for i := 0 to Count - 1 do
Inc(Result,Write(PByteArray(@Buffer)[i]));
end;
function TBitStream.Write(Value: Boolean): Integer;
var
BitMask: Integer;
begin
if(FBitIndex + 1>= FBitCount)then
FBitCount := FBitIndex + 1;
if(NumberOfBytesUsed>High(FDataArray) + 1)then
// the data array isn't large enough so increase it
SetLength(FDataArray,High(FDataArray) + 1 + FArrayGrowthAmount);
// set the bit value at FBitIndex position to the appropriate value
BitMask := 1 shl (FBitIndex and 7);
case Value of
False : FDataArray[FBitIndex shr 3] := FDataArray[FBitIndex shr 3] and
($FF - BitMask);
True : FDataArray[FBitIndex shr 3] := FDataArray[FBitIndex shr 3] or
BitMask;
end;
Inc(FBitIndex);
Result := 1;
end;
function TBitStream.WriteBits(var Value; StartBitIndex,BitCount: Integer):
Integer;
var
BitIndex: Integer;
BitMask: Integer;
begin
Result := 0;
for BitIndex := StartBitIndex to (StartBitIndex + (BitCount - 1)) do
begin
BitMask := 1 shl (BitIndex and $7);
Inc(Result,Write(((PByteArray(@Value)[BitIndex shr 3]) and BitMask) <>
0));
end;
end;
function TBitStream.Write(var Value: AnsiString): Integer;
var
StrLen: LongWord;
i: Integer;
begin
Result := 0;
StrLen := Length(Value);
Inc(Result,Write(StrLen));
for i := 1 to StrLen do
begin
Inc(Result,Write(Byte(Value[i])));
end;
end;
function TBitStream.Write(var Value: Byte): Integer;
var
IgnoreHalfData: Boolean;
begin
Result := 0;
IgnoreHalfData := (Value and $0F) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,0,4));
IgnoreHalfData := (Value and $F0) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,4,4));
end;
function TBitStream.Write(var Value: Shortint): Integer;
var
IgnoreHalfData: Boolean;
begin
Result := 0;
IgnoreHalfData := (Value and $0F) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,0,4));
IgnoreHalfData := (Value and $F0) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,4,4));
end;
function TBitStream.Write(var Value: Smallint): Integer;
var
IgnoreHalfData: Boolean;
begin
Result := 0;
IgnoreHalfData := (Value and $0F) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,0,4));
IgnoreHalfData := (Value and $F0) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,4,4));
end;
function TBitStream.Write(var Value: LongInt): Integer;
var
IgnoreHalfData: Boolean;
begin
Result := 0;
IgnoreHalfData := (Value and $0000FFFF) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,0,16));
IgnoreHalfData := (Value and $FFFF0000) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,16,16));
end;
function TBitStream.Write(var Value: Word): Integer;
var
IgnoreHalfData: Boolean;
begin
Result := 0;
IgnoreHalfData := (Value and $00FF) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,0,8));
IgnoreHalfData := (Value and $FF00) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,8,8));
end;
function TBitStream.Write(var Value: LongWord): Integer;
var
IgnoreHalfData: Boolean;
begin
Result := 0;
IgnoreHalfData := (Value and $0000FFFF) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,0,16));
IgnoreHalfData := (Value and $FFFF0000) = 0;
Inc(Result,Write(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,WriteBits(Value,16,16));
end;
function TBitStream.Write(var Value: Single; ZeroValue: Single =
DefaultZeroValue): Integer;
var
IsZero: Boolean;
begin
Result := 0;
IsZero := Abs(Value) <= ZeroValue;
Inc(Result,Write(IsZero));
if(not IsZero)then
Inc(Result,WriteBits(Value,0,SizeOf(Value)*8));
end;
function TBitStream.Write(var Value: Double; ZeroValue: Single =
DefaultZeroValue): Integer;
var
IsZero: Boolean;
begin
Result := 0;
IsZero := Abs(Value) <= ZeroValue;
Inc(Result,Write(IsZero));
if(not IsZero)then
Inc(Result,WriteBits(Value,0,SizeOf(Value)*8));
end;
function TBitStream.Write(var Value: Extended; ZeroValue: Single =
DefaultZeroValue): Integer;
var
IsZero: Boolean;
begin
Result := 0;
IsZero := Abs(Value) <= ZeroValue;
Inc(Result,Write(IsZero));
if(not IsZero)then
Inc(Result,WriteBits(Value,0,SizeOf(Value)*8));
end;
//---------------------TBitStream read
methods--------------------------------
function TBitStream.Read(var Buffer; Count: Longint): Longint;
var
i: LongInt;
Value: Byte;
begin
Result := 0;
for i := 0 to Count - 1 do
begin
Inc(Result,Read(Value));
PByteArray(@Buffer)[i] := Value;
end;
end;
function TBitStream.Read(var Value: Boolean): Integer;
var
BitMask: Integer;
begin
Result := 0;
Value := False;
if(FBitIndex>= FBitCount)then
// at the end of the data array so can't read anymore bits
Exit;
// get the bit value at FBitIndex position
BitMask := 1 shl (FBitIndex and 7);
Value := (FDataArray[FBitIndex shr 3] and BitMask) <>0;
Inc(FBitIndex);
Result := 1;
end;
function TBitStream.ReadBits(var Value; StartBitIndex,BitCount: Integer):
Integer;
var
BValue: Boolean;
BitIndex,i: Integer;
BitMask: Integer;
begin
Result := 0;
BitIndex := StartBitIndex;
for i := 1 to BitCount do
begin
BitMask := 1 shl (BitIndex and $7);
Inc(Result,Read(BValue));
case BValue of
False : PByteArray(@Value)[BitIndex shr 3] :=
(PByteArray(@Value)[BitIndex shr 3] and ($FF - BitMask));
True : PByteArray(@Value)[BitIndex shr 3] :=
PByteArray(@Value)[BitIndex shr 3] or BitMask;
end;
Inc(BitIndex);
end;
end;
function TBitStream.Read(var Value: AnsiString): Integer;
var
StrLen: LongWord;
i: Integer;
begin
Result := 0;
Inc(Result,Read(StrLen));
SetLength(Value,StrLen);
for i := 1 to StrLen do
begin
Inc(Result,Read(Byte(Value[i])));
end;
end;
function TBitStream.Read(var Value: Byte): Integer;
var
IgnoreHalfData: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,0,4));
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,4,4));
end;
function TBitStream.Read(var Value: Shortint): Integer;
var
IgnoreHalfData: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,0,4));
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,4,4));
end;
function TBitStream.Read(var Value: Smallint): Integer;
var
IgnoreHalfData: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,0,8));
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,8,8));
end;
function TBitStream.Read(var Value: LongInt): Integer;
var
IgnoreHalfData: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,0,16));
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,16,16));
end;
function TBitStream.Read(var Value: Word): Integer;
var
IgnoreHalfData: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,0,8));
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,8,8));
end;
function TBitStream.Read(var Value: LongWord): Integer;
var
IgnoreHalfData: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,0,16));
Inc(Result,Read(IgnoreHalfData));
if(not IgnoreHalfData)then
Inc(Result,ReadBits(Value,16,16));
end;
function TBitStream.Read(var Value: Single): Integer;
var
IsZero: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IsZero));
if(not IsZero)then
Inc(Result,ReadBits(Value,0,SizeOf(Value)*8));
end;
function TBitStream.Read(var Value: Double): Integer;
var
IsZero: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IsZero));
if(not IsZero)then
Inc(Result,ReadBits(Value,0,SizeOf(Value)*8));
end;
function TBitStream.Read(var Value: Extended): Integer;
var
IsZero: Boolean;
begin
Value := 0;
Result := 0;
Inc(Result,Read(IsZero));
if(not IsZero)then
Inc(Result,ReadBits(Value,0,SizeOf(Value)*8));
end;
end.