UNIT BeRoStream;

INTERFACE

TYPE PData=^TData;
     TData=PACKED ARRAY[0..1024*1024*1024] OF BYTE;

     PDataBuffer=^TDataBuffer;
     TDataBuffer=PACKED ARRAY[1..8192] OF BYTE;

     TBeRoStream=CLASS
      PRIVATE
       fPosition,fSize,fInMemorySize:INTEGER;
       fData:PData;
       fBitBuffer:LONGWORD;
       fBitBufferSize:BYTE;
       PROCEDURE Resize(NewSize:INTEGER);
       FUNCTION GetString:STRING;
       PROCEDURE SetString(Value:STRING);
       FUNCTION GetByte(BytePosition:INTEGER):BYTE;
       PROCEDURE SetByte(BytePosition:INTEGER;Value:BYTE);
      PUBLIC
       CONSTRUCTOR Create;
       DESTRUCTOR Destroy; OVERRIDE;
       FUNCTION Assign(Src:TBeRoStream):INTEGER;
       FUNCTION Append(Src:TBeRoStream):INTEGER;
       FUNCTION AppendFrom(Src:TBeRoStream;Counter:INTEGER):INTEGER;
       PROCEDURE Clear; VIRTUAL;
       FUNCTION Read(VAR Buf;Count:INTEGER):INTEGER; VIRTUAL;
       FUNCTION ReadAt(Position:INTEGER;VAR Buf;Count:INTEGER):INTEGER; VIRTUAL;
       FUNCTION Write(CONST Buf;Count:INTEGER):INTEGER; VIRTUAL;
       FUNCTION Seek(APosition:INTEGER):INTEGER; VIRTUAL;
       FUNCTION Position:INTEGER; VIRTUAL;
       FUNCTION Size:INTEGER; VIRTUAL;
       PROCEDURE SetSize(NewSize:INTEGER);
       FUNCTION ReadByte:BYTE;
       FUNCTION ReadWord:WORD;
       FUNCTION ReadDWord:LONGWORD;
       FUNCTION ReadLine:STRING;
       FUNCTION ReadString:STRING;
       PROCEDURE WriteByte(Value:BYTE);
       PROCEDURE WriteByteCount(Value:BYTE;Count:INTEGER);
       PROCEDURE WriteWord(Value:WORD);
       PROCEDURE WriteDWord(Value:LONGWORD);
       PROCEDURE WriteShortInt(Value:SHORTINT);
       PROCEDURE WriteSmallInt(Value:SMALLINT);
       PROCEDURE WriteLongInt(Value:LONGINT);
       PROCEDURE WriteInt64(Value:INT64);
       PROCEDURE WriteBoolean(Value:BOOLEAN);
       PROCEDURE WriteLine(Line:STRING);
       PROCEDURE WriteString(S:STRING);
       PROCEDURE WriteDataString(S:STRING);
       PROCEDURE ResetBits;
       FUNCTION ReadBit:BOOLEAN;
       FUNCTION ReadBits(BitsCount:BYTE):LONGWORD;
       FUNCTION ReadBitsSigned(BitsCount:BYTE):LONGINT;
       PROCEDURE WriteBit(Value:BOOLEAN);
       PROCEDURE WriteBits(Value:LONGWORD;BitsCount:BYTE);
       PROCEDURE WriteBitsSigned(Value:LONGINT;BitsCount:BYTE);
       PROCEDURE FlushBits;
       PROPERTY Text:STRING READ GetString WRITE SetString;
       PROPERTY Bytes[BytePosition:INTEGER]:BYTE READ GetByte WRITE SetByte; DEFAULT;
       PROPERTY BitsInBuffer:BYTE READ fBitBufferSize;
     END;

     TBeRoMemoryStream=CLASS(TBeRoStream)
     END;

     TBeRoFileStream=CLASS(TBeRoStream)
      PRIVATE
       fFile:FILE;
      PUBLIC
       CONSTRUCTOR Create(FileName:STRING);
       CONSTRUCTOR CreateNew(FileName:STRING);
       DESTRUCTOR Destroy; OVERRIDE;
       FUNCTION Read(VAR Buf;Count:INTEGER):INTEGER; OVERRIDE;
       FUNCTION Write(CONST Buf;Count:INTEGER):INTEGER; OVERRIDE;
       FUNCTION Seek(APosition:INTEGER):INTEGER; OVERRIDE;
       FUNCTION Position:INTEGER; OVERRIDE;
       FUNCTION Size:INTEGER; OVERRIDE;
     END;

IMPLEMENTATION

CONSTRUCTOR TBeRoStream.Create;
BEGIN
 INHERITED Create;
 fData:=NIL;
 REALLOCMEM(fData,0);
 fPosition:=0;
 fSize:=0;
 fInMemorySize:=0;
 ResetBits;
END;

DESTRUCTOR TBeRoStream.Destroy;
BEGIN
 REALLOCMEM(fData,0);
 fPosition:=0;
 fSize:=0;
 fInMemorySize:=0;
 INHERITED Destroy;
END;

FUNCTION TBeRoStream.Assign(Src:TBeRoStream):INTEGER;
VAR Remain,Count:INTEGER;
    Buf:TDataBuffer;
BEGIN
 Clear;
 RESULT:=0;
 Remain:=Src.Size;
 IF (Seek(0)<>0) OR (Src.Seek(0)<>0) THEN EXIT;
 WHILE Remain>=SIZEOF(TDataBuffer) DO BEGIN
  Count:=Src.Read(Buf,SIZEOF(TDataBuffer));
  INC(RESULT,Write(Buf,Count));
  DEC(Remain,SIZEOF(TDataBuffer));
 END;
 Count:=Src.Read(Buf,Remain);
 INC(RESULT,Write(Buf,Count));
END;

FUNCTION TBeRoStream.Append(Src:TBeRoStream):INTEGER;
VAR Remain,Count:INTEGER;
    Buf:TDataBuffer;
BEGIN
 Remain:=Src.Size;
 RESULT:=0;
 IF Src.Seek(0)<>0 THEN EXIT;
 WHILE Remain>=SIZEOF(TDataBuffer) DO BEGIN
  Count:=Src.Read(Buf,SIZEOF(TDataBuffer));
  INC(RESULT,Write(Buf,Count));
  DEC(Remain,SIZEOF(TDataBuffer));
 END;
 Count:=Src.Read(Buf,Remain);
 INC(RESULT,Write(Buf,Count));
END;

FUNCTION TBeRoStream.AppendFrom(Src:TBeRoStream;Counter:INTEGER):INTEGER;
VAR Remain,Count:INTEGER;
    Buf:TDataBuffer;
BEGIN
 RESULT:=0;
 Remain:=Counter;
 WHILE Remain>=SIZEOF(TDataBuffer) DO BEGIN
  Count:=Src.Read(Buf,SIZEOF(TDataBuffer));
  INC(RESULT,Write(Buf,Count));
  DEC(Remain,SIZEOF(TDataBuffer));
 END;
 Count:=Src.Read(Buf,Remain);
 INC(RESULT,Write(Buf,Count));
END;

PROCEDURE TBeRoStream.Clear;
BEGIN
 REALLOCMEM(fData,0);
 fPosition:=0;
 fSize:=0;
 fInMemorySize:=0;
END;

PROCEDURE TBeRoStream.Resize(NewSize:INTEGER);
VAR NewInMemorySize:INTEGER;
BEGIN
 fSize:=NewSize;
 NewInMemorySize:=((fSize DIV 65536)+1)*65536;
 IF fInMemorySize<>NewInMemorySize THEN BEGIN
  fInMemorySize:=NewInMemorySize;
  REALLOCMEM(fData,fInMemorySize);
 END;
 IF fPosition>fSize THEN fPosition:=fSize;
END;

FUNCTION TBeRoStream.Read(VAR Buf;Count:INTEGER):INTEGER;
VAR RealSize:INTEGER;
BEGIN
 RealSize:=Count;
 IF (fPosition+RealSize)>fSize THEN RealSize:=fSize-fPosition;
 IF RealSize>0 THEN BEGIN
  MOVE(fData^[fPosition],Buf,RealSize);
  INC(fPosition,RealSize);
 END;
 RESULT:=RealSize;
END;

FUNCTION TBeRoStream.ReadAt(Position:INTEGER;VAR Buf;Count:INTEGER):INTEGER;
BEGIN
 IF Seek(Position)=Position THEN BEGIN
  RESULT:=Read(Buf,Count);
 END ELSE BEGIN
  RESULT:=0;
 END;
END;

FUNCTION TBeRoStream.Write(CONST Buf;Count:INTEGER):INTEGER;
VAR RealSize,RemainSize:INTEGER;
BEGIN
 RealSize:=Count;
 IF (fPosition+RealSize)>fSize THEN RealSize:=fSize-fPosition;
 IF RealSize>0 THEN BEGIN
  MOVE(Buf,fData^[fPosition],RealSize);
  INC(fPosition,RealSize);
 END;
 RemainSize:=Count-RealSize;
 IF RemainSize>0 THEN BEGIN
  Resize(fSize+RemainSize);
  MOVE(Buf,fData^[fPosition],RemainSize);
  INC(fPosition,RemainSize);
 END ELSE BEGIN
  RemainSize:=0;
 END;
 RESULT:=RealSize+RemainSize;
END;

FUNCTION TBeRoStream.Seek(APosition:INTEGER):INTEGER;
VAR AltePos,RemainSize:INTEGER;
BEGIN
 fPosition:=APosition;
 IF fPosition<0 THEN fPosition:=0;
 IF fPosition>fSize THEN BEGIN
  AltePos:=fSize;
  RemainSize:=fPosition-fSize;
  IF RemainSize>0 THEN BEGIN
   Resize(fSize+RemainSize);
   FILLCHAR(fData^[AltePos],RemainSize,#0);
  END;
  RESULT:=fPosition;
 END ELSE BEGIN
  RESULT:=fPosition;
 END;
END;

FUNCTION TBeRoStream.Position:INTEGER;
BEGIN
 RESULT:=fPosition;
END;

FUNCTION TBeRoStream.Size:INTEGER;
BEGIN
 RESULT:=fSize;
END;

PROCEDURE TBeRoStream.SetSize(NewSize:INTEGER);
BEGIN
 fSize:=NewSize;
 IF fPosition>fSize THEN fPosition:=fSize;
 REALLOCMEM(fData,fSize);
END;

FUNCTION TBeRoStream.ReadByte:BYTE;
VAR B:BYTE;
BEGIN
 IF Read(B,1)<>1 THEN BEGIN
  RESULT:=0;
 END ELSE BEGIN
  RESULT:=B;
 END;
END;

FUNCTION TBeRoStream.ReadWord:WORD;
BEGIN
 RESULT:=ReadByte OR (ReadByte SHL 8);
END;

FUNCTION TBeRoStream.ReadDWord:LONGWORD;
BEGIN
 RESULT:=ReadWord OR (ReadWord SHL 16);
END;

FUNCTION TBeRoStream.ReadLine:STRING;
VAR C:CHAR;
BEGIN
 RESULT:='';
 WHILE Position<Size DO BEGIN
  Read(C,1);
  IF C=#10 THEN BEGIN
   BREAK;
  END ELSE IF C<>#13 THEN BEGIN
   RESULT:=RESULT+C;
  END;
 END;
END;

FUNCTION TBeRoStream.ReadString:STRING;
VAR L:LONGWORD;
BEGIN
 L:=ReadDWord;
 SETLENGTH(RESULT,L);
 Read(RESULT[1],L);
END;

PROCEDURE TBeRoStream.WriteByte(Value:BYTE);
BEGIN
 Write(Value,SIZEOF(BYTE));
END;

PROCEDURE TBeRoStream.WriteByteCount(Value:BYTE;Count:INTEGER);
VAR Counter:INTEGER;
BEGIN
 FOR Counter:=1 TO Count DO Write(Value,SIZEOF(BYTE));
END;

PROCEDURE TBeRoStream.WriteWord(Value:WORD);
BEGIN
 Write(Value,SIZEOF(WORD));
END;

PROCEDURE TBeRoStream.WriteDWord(Value:LONGWORD);
BEGIN
 Write(Value,SIZEOF(LONGWORD));
END;

PROCEDURE TBeRoStream.WriteShortInt(Value:SHORTINT);
BEGIN
 Write(Value,SIZEOF(SHORTINT));
END;

PROCEDURE TBeRoStream.WriteSmallInt(Value:SMALLINT);
BEGIN
 Write(Value,SIZEOF(SMALLINT));
END;

PROCEDURE TBeRoStream.WriteLongInt(Value:LONGINT);
BEGIN
 Write(Value,SIZEOF(LONGINT));
END;

PROCEDURE TBeRoStream.WriteInt64(Value:INT64);
BEGIN
 Write(Value,SIZEOF(INT64));
END;

PROCEDURE TBeRoStream.WriteBoolean(Value:BOOLEAN);
BEGIN
 IF Value THEN BEGIN
  WriteByte(1);
 END ELSE BEGIN
  WriteByte(0);
 END;
END;

PROCEDURE TBeRoStream.WriteLine(Line:STRING);
BEGIN
 IF LENGTH(Line)>0 THEN Write(Line[1],LENGTH(Line));
 Write(#13#10,2);
END;

PROCEDURE TBeRoStream.WriteString(S:STRING);
VAR L:LONGWORD;
BEGIN
 L:=LENGTH(S);
 IF L>0 THEN Write(S[1],L);
END;

PROCEDURE TBeRoStream.WriteDataString(S:STRING);
VAR L:LONGWORD;
BEGIN
 L:=LENGTH(S);
 WriteDWord(L);
 IF L>0 THEN Write(S[1],L);
END;

PROCEDURE TBeRoStream.ResetBits;
BEGIN
 fBitBuffer:=0;
 fBitBufferSize:=0;
END;

FUNCTION TBeRoStream.ReadBit:BOOLEAN;
BEGIN
 RESULT:=(ReadBits(1)<>0);
END;

FUNCTION TBeRoStream.ReadBits(BitsCount:BYTE):LONGWORD;
BEGIN
 WHILE fBitBufferSize<BitsCount DO BEGIN
  fBitBuffer:=(fBitBuffer SHL 8) OR ReadByte;
  INC(fBitBufferSize,8);
 END;
 RESULT:=(fBitBuffer SHR (fBitBufferSize-BitsCount)) AND ((1 SHL BitsCount)-1);
 DEC(fBitBufferSize,BitsCount);
END;

FUNCTION TBeRoStream.ReadBitsSigned(BitsCount:BYTE):LONGINT;
BEGIN
 RESULT:=0;
 IF BitsCount>1 THEN BEGIN
  IF ReadBits(1)<>0 THEN BEGIN
   RESULT:=-ReadBits(BitsCount-1);
  END ELSE BEGIN
   RESULT:=ReadBits(BitsCount-1);
  END;
 END;
END;

PROCEDURE TBeRoStream.WriteBit(Value:BOOLEAN);
BEGIN
 IF Value THEN BEGIN
  WriteBits(1,1);
 END ELSE BEGIN
  WriteBits(0,1);
 END;
END;

PROCEDURE TBeRoStream.WriteBits(Value:LONGWORD;BitsCount:BYTE);
BEGIN
 fBitBuffer:=(fBitBuffer SHL BitsCount) OR Value;
 INC(fBitBufferSize,BitsCount);
 WHILE fBitBufferSize>=8 DO BEGIN
  WriteByte((fBitBuffer SHR (fBitBufferSize-8)) AND $FF);
  DEC(fBitBufferSize,8);
 END;
END;

PROCEDURE TBeRoStream.WriteBitsSigned(Value:LONGINT;BitsCount:BYTE);
BEGIN
 IF BitsCount>1 THEN BEGIN
  IF Value<0 THEN BEGIN
   WriteBits(1,1);
   WriteBits(LONGWORD(0-Value),BitsCount-1);
  END ELSE BEGIN
   WriteBits(0,1);
   WriteBits(LONGWORD(Value),BitsCount-1);
  END;
 END;
END;

PROCEDURE TBeRoStream.FlushBits;
BEGIN
 IF fBitBufferSize>0 THEN BEGIN
  WriteByte(fBitBuffer SHL (8-fBitBufferSize));
 END;
 fBitBuffer:=0;
 fBitBufferSize:=0;
END;

FUNCTION TBeRoStream.GetString:STRING;
BEGIN
 Seek(0);
 IF Size>0 THEN BEGIN
  SETLENGTH(RESULT,Size);
  Read(RESULT[1],Size);
 END ELSE BEGIN
  RESULT:='';
 END;
END;

PROCEDURE TBeRoStream.SetString(Value:STRING);
BEGIN
 Clear;
 Write(Value[1],LENGTH(Value));
END;

FUNCTION TBeRoStream.GetByte(BytePosition:INTEGER):BYTE;
VAR AltePosition:INTEGER;
BEGIN
 AltePosition:=Position;
 Seek(BytePosition);
 Read(RESULT,SIZEOF(BYTE));
 Seek(AltePosition);
END;

PROCEDURE TBeRoStream.SetByte(BytePosition:INTEGER;Value:BYTE);
VAR AltePosition:INTEGER;
BEGIN
 AltePosition:=Position;
 Seek(BytePosition);
 Write(Value,SIZEOF(BYTE));
 Seek(AltePosition);
END;

CONSTRUCTOR TBeRoFileStream.Create(FileName:STRING);
BEGIN
 INHERITED Create;
 ASSIGNFILE(fFile,FileName);
 {$I-}RESET(fFile,1);{$I+}
 IF IOResult<>0 THEN BEGIN
 END;
END;

CONSTRUCTOR TBeRoFileStream.CreateNew(FileName:STRING);
BEGIN
 INHERITED Create;
 ASSIGNFILE(fFile,FileName);
 {$I-}REWRITE(fFile,1);{$I+}
 IF IOResult<>0 THEN BEGIN
 END;
END;

DESTRUCTOR TBeRoFileStream.Destroy;
BEGIN
 {$I-}CLOSEFILE(fFile);{$I+}
 IF IOResult<>0 THEN BEGIN
 END;
 INHERITED Destroy;
END;

FUNCTION TBeRoFileStream.Read(VAR Buf;Count:INTEGER):INTEGER;
VAR I:INTEGER;
BEGIN
 {$I-}BLOCKREAD(fFile,Buf,Count,I);{$I+}
 IF IOResult<>0 THEN BEGIN
  RESULT:=0;
  EXIT;
 END;
 {$I-}fPosition:=FILEPOS(fFile);{$I+}
 IF IOResult<>0 THEN BEGIN
  RESULT:=0;
  EXIT;
 END;
 RESULT:=I;
END;

FUNCTION TBeRoFileStream.Write(CONST Buf;Count:INTEGER):INTEGER;
VAR I:INTEGER;
BEGIN
 {$I-}BLOCKWRITE(fFile,Buf,Count,I);{$I+}
 IF IOResult<>0 THEN BEGIN
  RESULT:=0;
  EXIT;
 END;
 {$I-}fPosition:=FILEPOS(fFile);{$I+}
 IF IOResult<>0 THEN BEGIN
  RESULT:=0;
  EXIT
 END;
 RESULT:=I;
END;

FUNCTION TBeRoFileStream.Seek(APosition:INTEGER):INTEGER;
BEGIN
 IF APosition<=Size THEN BEGIN
  {$I-}System.SEEK(fFile,APosition);{$I+}
  IF IOResult<>0 THEN BEGIN
   RESULT:=0;
   EXIT;
  END;
 END;
 {$I-}RESULT:=FILEPOS(fFile);{$I+}
 IF IOResult<>0 THEN BEGIN
  RESULT:=0;
 END;
END;

FUNCTION TBeRoFileStream.Position:INTEGER;
BEGIN
 {$I-}RESULT:=FILEPOS(fFile);{$I+}
 IF IOResult<>0 THEN BEGIN
  RESULT:=0;
 END;
END;

FUNCTION TBeRoFileStream.Size:INTEGER;
BEGIN
 {$I-}RESULT:=FILESIZE(fFile);{$I+}
 IF IOResult<>0 THEN BEGIN
  RESULT:=-1;
 END;
END;

END.
