// Deprecated: use dbitmem and dbitmem_le
{$MODE OBJFPC}
unit dbitstream;

interface

uses
  dtypes;

type
  TRead = function (var Buffer; Count: LongInt): LongInt of object;
  TWrite = function (var Buffer; Count: LongInt): LongInt of object;

PBitReader = ^TBitReader;
TBitReader = object
private
  FRead: TRead;
  FByte: Byte;
  FBitsRest: LongInt;
  FEOS: Boolean;
  procedure LoadNextByte;
public
  procedure Init(ReadFunc: TRead);
  procedure Reinit(ReadFunc: TRead);
  procedure Done;
  // Is it any bit?
  function EOS: Boolean;
  // Read single bit
  function ReadBit: LongInt;
  // How many bits in current Byte
  property BitsRest: LongInt read FBitsRest;
public
  // Read bits from current Byte
  function ReadRest: Byte;
  function ReadRest(Count: LongInt): Byte;
  // Utils
  function ReadUint(Bits: LongInt; var V: TUint32): Boolean;
end;

implementation

procedure TBitReader.LoadNextByte;
begin
  if FRead(FByte, 1) > 0 then begin
    FBitsRest := 8;
  end else begin
    FEOS := True;
    FBitsRest := 0;
  end;
end;

procedure TBitReader.Init(ReadFunc: TRead);
begin
  FRead := ReadFunc;
  FEOS := False;
  LoadNextByte;
end;

procedure TBitReader.Reinit(ReadFunc: TRead);
begin
  Done;
  Init(ReadFunc);
end;

procedure TBitReader.Done;
begin
end;

function TBitReader.EOS: Boolean;
begin
  Result := FEOS and (FBitsRest = 0);
end;

function TBitReader.ReadBit: LongInt;
begin
  if FBitsRest = 0 then begin
    if FEOS then
      Exit(0);
    LoadNextByte;
    if FEOS then
      Exit(0);
  end;
  Dec(FBitsRest);
  Result := (FByte shr FBitsRest) and 1;
  if FBitsRest = 0 then
    LoadNextByte;
end;

function TBitReader.ReadRest: Byte;
begin
  Result := FByte and ((1 shl FBitsRest) - 1);
  LoadNextByte;
end;

function TBitReader.ReadRest(Count: LongInt): Byte;
begin
  Result := (FByte and ((1 shl (FBitsRest)) - 1));
  if Count < FBitsRest then
    Result := Result shr (FBitsRest - Count);
  Dec(FBitsRest, Count);
  if FBitsRest <= 0 then
    LoadNextByte;
end;

function TBitReader.ReadUint(Bits: LongInt; var V: TUint32): Boolean;
var
  R: Byte;
  B: LongInt;
begin
  if EOS then
    Exit(False);
  V := 0;
  while Bits > 0 do begin
    B := BitsRest;
    if B > Bits then begin
      V := (V shl Bits) + ReadRest(Bits);
      Exit(True);
    end else begin
      V := (V shl B) + ReadRest;
      if EOS then
        Exit(False);
      Dec(Bits, B);
    end;
  end;
  Exit(True);
end;

end.
