Browse Source

* TStreamReader (TTextReader) implementation by Sylvio Clecio (bug ID 28075)

git-svn-id: trunk@31022 -
michael 10 years ago
parent
commit
b36386baf0
2 changed files with 322 additions and 1 deletions
  1. 321 1
      packages/fcl-base/src/streamex.pp
  2. 1 0
      rtl/objpas/rtlconst.inc

+ 321 - 1
packages/fcl-base/src/streamex.pp

@@ -1,10 +1,35 @@
+{
+    This file is part of the Free Component Library.
+
+    Copyright (c) 2015 by:
+
+      . Michael Van Canneyt [email protected]
+      . Silvio Clecio github.com/silvioprog
+
+    Text reader classes.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
 {$mode objfpc}
 {$h+}
 unit streamex;
 
 Interface
 
-uses Classes;
+uses
+  Classes, SysUtils, RtlConsts;
+
+const
+  MIN_BUFFER_SIZE = 128;
+  BUFFER_SIZE = 4096;
+  FILE_RIGHTS = 438;
 
 type
 
@@ -58,6 +83,78 @@ type
       property Position: LongInt read GetPosition write SetPosition;
    end;
 
+   { TTextReader }
+
+   TTextReader = class(TObject)
+   public
+     constructor Create; virtual;
+     procedure Reset; virtual; abstract;
+     procedure Close; virtual; abstract;
+     function IsEof: Boolean; virtual; abstract;
+     procedure ReadLine(out AString: string); virtual; abstract; overload;
+     function ReadLine: string; virtual; abstract; overload;
+     property Eof: Boolean read IsEof;
+   end;
+
+   { TStreamReader }
+
+   TStreamReader = class(TTextReader)
+   private
+     FBufferRead: Integer;
+     FBufferPosition: Integer;
+     FOwnsStream: Boolean;
+     FStream: TStream;
+     FBuffer: array of Byte;
+     procedure FillBuffer;
+   public
+     constructor Create(AStream: TStream; ABufferSize: Integer;
+       AOwnsStream: Boolean); virtual;
+     constructor Create(AStream: TStream); virtual;
+     destructor Destroy; override;
+     procedure Reset; override;
+     procedure Close; override;
+     function IsEof: Boolean; override;
+     procedure ReadLine(out AString: string); override; overload;
+     function ReadLine: string; override; overload;
+     property BaseStream: TStream read FStream;
+     property OwnsStream: Boolean read FOwnsStream write FOwnsStream;
+   end;
+
+   { TStringReader }
+
+   TStringReader = class(TTextReader)
+   private
+     FReader: TTextReader;
+   public
+     constructor Create(const AString: string; ABufferSize: Integer); virtual;
+     constructor Create(const AString: string); virtual;
+     destructor Destroy; override;
+     procedure Reset; override;
+     procedure Close; override;
+     function IsEof: Boolean; override;
+     procedure ReadLine(out AString: string); override; overload;
+     function ReadLine: string; override; overload;
+   end;
+
+   { TFileReader }
+
+   TFileReader = class(TTextReader)
+   private
+     FReader: TTextReader;
+   public
+     constructor Create(const AFileName: TFileName; AMode: Word;
+       ARights: Cardinal; ABufferSize: Integer); virtual;
+     constructor Create(const AFileName: TFileName; AMode: Word;
+       ABufferSize: Integer); virtual;
+     constructor Create(const AFileName: TFileName; ABufferSize: Integer); virtual;
+     constructor Create(const AFileName: TFileName); virtual;
+     destructor Destroy; override;
+     procedure Reset; override;
+     procedure Close; override;
+     function IsEof: Boolean; override;
+     procedure ReadLine(out AString: string); override; overload;
+     function ReadLine: string; override; overload;
+   end;
 
   TStreamHelper = class helper for TStream
                      function  ReadWordLE :word;
@@ -192,7 +289,230 @@ begin
    GetDriver.WriteValue(Value);
 end;
 
+{ TTextReader }
+
+constructor TTextReader.Create;
+begin
+  inherited Create;
+end;
+
+{ TStreamReader }
+
+constructor TStreamReader.Create(AStream: TStream; ABufferSize: Integer;
+  AOwnsStream: Boolean);
+begin
+  inherited Create;
+  if not Assigned(AStream) then
+    raise EArgumentException.CreateFmt(SParamIsNil, ['AStream']);
+  FStream := AStream;
+  FOwnsStream := AOwnsStream;
+  if ABufferSize >= MIN_BUFFER_SIZE then
+    SetLength(FBuffer, ABufferSize)
+  else
+    SetLength(FBuffer, MIN_BUFFER_SIZE);
+end;
+
+constructor TStreamReader.Create(AStream: TStream);
+begin
+  Create(AStream, BUFFER_SIZE, False);
+end;
+
+destructor TStreamReader.Destroy;
+begin
+  Close;
+  inherited Destroy;
+end;
+
+procedure TStreamReader.FillBuffer;
+begin
+  FBufferRead := FStream.Read(FBuffer[0], Pred(Length(FBuffer)));
+  FBuffer[FBufferRead] := 0;
+  FBufferPosition := 0;
+end;
+
+procedure TStreamReader.Reset;
+begin
+  FBufferRead := 0;
+  FBufferPosition := 0;
+  if Assigned(FStream) then
+    FStream.Seek(0, 0);
+end;
+
+procedure TStreamReader.Close;
+begin
+  if FOwnsStream then
+  begin
+    FStream.Free;
+    FStream := nil;
+  end;
+end;
+
+function TStreamReader.IsEof: Boolean;
+begin
+  if not Assigned(FStream) then
+    Exit(True);
+  Result := FBufferPosition >= FBufferRead;
+  if Result then
+  begin
+    FillBuffer;
+    Result := FBufferRead = 0;
+  end;
+end;
+
+procedure TStreamReader.ReadLine(out AString: string);
+var
+  VPByte: PByte;
+  VPosition, VStrLength, VLength: Integer;
+begin
+  VPosition := FBufferPosition;
+  SetLength(AString, 0);
+  repeat
+    VPByte := @FBuffer[FBufferPosition];
+    while (FBufferPosition < FBufferRead) and not (VPByte^ in [10, 13]) do
+    begin
+      Inc(VPByte);
+      Inc(FBufferPosition);
+    end;
+    if FBufferPosition = FBufferRead then
+    begin
+      VLength := FBufferPosition - VPosition;
+      if VLength > 0 then
+      begin
+        VStrLength := Length(AString);
+        SetLength(AString, VStrLength + VLength);
+        Move(FBuffer[VPosition], AString[Succ(VStrLength)], VLength);
+      end;
+      FillBuffer;
+      VPosition := FBufferPosition;
+    end;
+  until (FBufferPosition = FBufferRead) or (VPByte^ in [10, 13]);
+  VLength := FBufferPosition - VPosition;
+  if VLength > 0 then
+  begin
+    VStrLength := Length(AString);
+    SetLength(AString, VStrLength + VLength);
+    Move(FBuffer[VPosition], AString[Succ(VStrLength)], VLength);
+  end;
+  if (VPByte^ in [10, 13]) and (FBufferPosition < FBufferRead) then
+  begin
+    Inc(FBufferPosition);
+    if VPByte^ = 13 then
+    begin
+      if FBufferPosition = FBufferRead then
+        FillBuffer;
+      if (FBufferPosition < FBufferRead) and (FBuffer[FBufferPosition] = 10) then
+        Inc(FBufferPosition);
+    end;
+  end;
+end;
+
+function TStreamReader.ReadLine: string;
+begin
+  ReadLine(Result);
+end;
+
+{ TStringReader }
+
+constructor TStringReader.Create(const AString: string; ABufferSize: Integer);
+begin
+  inherited Create;
+  FReader := TStreamReader.Create(TStringStream.Create(AString), ABufferSize, True);
+end;
+
+constructor TStringReader.Create(const AString: string);
+begin
+  Create(AString, BUFFER_SIZE);
+end;
+
+destructor TStringReader.Destroy;
+begin
+  FReader.Free;
+  inherited Destroy;
+end;
+
+procedure TStringReader.Reset;
+begin
+  FReader.Reset;
+end;
+
+procedure TStringReader.Close;
+begin
+  FReader.Close;
+end;
+
+function TStringReader.IsEof: Boolean;
+begin
+  Result := FReader.IsEof;
+end;
+
+procedure TStringReader.ReadLine(out AString: string);
+begin
+  FReader.ReadLine(AString);
+end;
+
+function TStringReader.ReadLine: string;
+begin
+  ReadLine(Result);
+end;
+
+{ TFileReader }
+
+constructor TFileReader.Create(const AFileName: TFileName; AMode: Word;
+  ARights: Cardinal; ABufferSize: Integer);
+begin
+  inherited Create;
+  FReader := TStreamReader.Create(TFileStream.Create(AFileName, AMode, ARights),
+    ABufferSize, True);
+end;
+
+constructor TFileReader.Create(const AFileName: TFileName; AMode: Word;
+  ABufferSize: Integer);
+begin
+  Create(AFileName, AMode, FILE_RIGHTS, ABufferSize);
+end;
+
+constructor TFileReader.Create(const AFileName: TFileName; ABufferSize: Integer);
+begin
+  Create(AFileName, fmOpenRead or fmShareDenyWrite, ABufferSize);
+end;
+
+constructor TFileReader.Create(const AFileName: TFileName);
+begin
+  Create(AFileName, BUFFER_SIZE);
+end;
+
+destructor TFileReader.Destroy;
+begin
+  FReader.Free;
+  inherited Destroy;
+end;
+
+procedure TFileReader.Reset;
+begin
+  FReader.Reset;
+end;
+
+procedure TFileReader.Close;
+begin
+  FReader.Close;
+end;
+
+function TFileReader.IsEof: Boolean;
+begin
+  Result := FReader.IsEof;
+end;
+
+procedure TFileReader.ReadLine(out AString: string);
+begin
+  FReader.ReadLine(AString);
+end;
+
+function TFileReader.ReadLine: string;
+begin
+  ReadLine(Result);
+end;
 
+{ TStreamHelper }
 
 function TStreamHelper.readwordLE:word;
 begin

+ 1 - 0
rtl/objpas/rtlconst.inc

@@ -139,6 +139,7 @@ ResourceString
   SImageReadFail                = 'The ImageList data could not be read from stream';
   SImageWriteFail               = 'The ImageList data could not be written to stream';
   SIndexOutOfRange              = 'Grid index out of range';
+  SParamIsNil                   = 'Parameter %s cannot be nil';
   SIniFileWriteError            = 'Unable to write to "%s"';
   SInsertLineError              = 'Line could not be inserted';
   SInvalidActionCreation        = 'Invalid action creation';