Board index » off-topic » BitStreamUnit
Paul Nicholls
Delphi Developer |
BitStreamUnit2006-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. |