| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- (* _ _
- * | |__ _ __ ___ ___ | | __
- * | '_ \| '__/ _ \ / _ \| |/ /
- * | |_) | | | (_) | (_) | <
- * |_.__/|_| \___/ \___/|_|\_\
- *
- * Microframework which helps to develop web Pascal applications.
- *
- * Copyright (c) 2012-2020 Silvio Clecio <[email protected]>
- *
- * Brook framework is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Brook framework 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. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Brook framework; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
- { Contains classes for reading text line by line from a string, stream or file. }
- unit BrookReader;
- {$I BrookDefines.inc}
- interface
- uses
- RTLConsts,
- SysUtils,
- Classes,
- BrookExtra;
- type
- { Abstract class for line reader. }
- TBrookTextReader = class abstract
- protected
- function GetEncoding: TEncoding; virtual; abstract;
- procedure SetEncoding(AValue: TEncoding); virtual; abstract;
- public
- { Resets the reader to its initial state. }
- procedure Reset; virtual; abstract;
- { Closes the reader. }
- procedure Close; virtual; abstract;
- { Checks if the reader has reached the End-Of-File.
- @returns(@True if the reader has reached the End-Of-File.) }
- function IsEOF: Boolean; virtual; abstract;
- { Reads a line as bytes.
- @param(ALine[out] Line read as bytes.) }
- procedure ReadBytes(out ALine: TBytes); overload; virtual; abstract;
- { Reads a line returning it as bytes.
- @returns(Line read as bytes.) }
- function ReadBytes: TBytes; overload; virtual; abstract;
- { Reads a line as static string.
- @param(ALine[out] read as static string.) }
- procedure Read(out ALine: string); overload; virtual; abstract;
- { Read a line returning it as a static string.
- @returns(Line read as static string.) }
- function Read: string; overload; virtual; abstract;
- { @True if the reader has reached the End-Of-File. }
- property EOF: Boolean read IsEOF;
- { Character encoding determined during reading. }
- property Encoding: TEncoding read GetEncoding write SetEncoding;
- end;
- { Line reader which uses stream as source of lines. }
- TBrookStreamReader = class(TBrookTextReader)
- private
- FStream: TStream;
- FEncoding: TEncoding;
- FBuffer: TBytes;
- FBufferRead: Integer;
- FBufferPosition: Integer;
- FOwnsStream: Boolean;
- protected
- function GetEncoding: TEncoding; override;
- function GetOwnsStream: Boolean; virtual;
- function GetStream: TStream; virtual;
- procedure SetEncoding(AValue: TEncoding); override;
- procedure SetOwnsStream(AValue: Boolean); virtual;
- procedure FillBuffer; virtual;
- property BufferRead: Integer read FBufferRead write FBufferRead;
- property BufferPosition: Integer read FBufferPosition write FBufferPosition;
- property Buffer: TBytes read FBuffer write FBuffer;
- public
- { Creates an instance of @code(TBrookStreamReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AStream[in] Stream to be read line by line.)
- @param(ABufferSize[in] Buffer size for the line reading.)
- @param(AOwnsStream[in] If @True the stream is freed on @code(Destroy).) }
- constructor Create(AEncoding: TEncoding; AStream: TStream;
- ABufferSize: Cardinal; AOwnsStream: Boolean); reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStreamReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AStream[in] Stream to be read line by line.) }
- constructor Create(AEncoding: TEncoding; AStream: TStream);
- reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStreamReader)
- @param(AStream[in] Stream to be read line by line.) }
- constructor Create(AStream: TStream); reintroduce; overload; virtual;
- { Destroys an instance of @code(TBrookStreamReader). }
- destructor Destroy; override;
- { Resets the cursor to the beginning of the stream. }
- procedure Reset; override;
- { Frees the stream if property @code(OwnsStream) is @True. }
- procedure Close; override;
- { Checks if the reader has reached the End-Of-File.
- @returns(@True if the stream has reached the End-Of-File.) }
- function IsEOF: Boolean; override;
- { Reads a line as bytes.
- @param(ALine[out] Line read as bytes.) }
- procedure ReadBytes(out ALine: TBytes); overload; override;
- { Reads a line returning it as bytes.
- @returns(Line read as bytes.) }
- function ReadBytes: TBytes; overload; override;
- { Reads a line as static string.
- @param(ALine[out] read as static string.) }
- procedure Read(out ALine: string); overload; override;
- { Read a line returning it as a static string.
- @returns(Line read as static string.) }
- function Read: string; overload; override;
- { Source stream containing the lines to be read. }
- property Stream: TStream read GetStream;
- { If @True the stream is freed on @code(Destroy). }
- property OwnsStream: Boolean read GetOwnsStream write SetOwnsStream;
- end;
- { Base proxied line reader. }
- TBrookBaseReader = class(TBrookTextReader)
- protected
- procedure SetEncoding(AValue: TEncoding); override;
- procedure SetProxyReader(AValue: TBrookTextReader); virtual; abstract;
- function GetEncoding: TEncoding; override;
- function GetProxyReader: TBrookTextReader; virtual; abstract;
- property ProxyReader: TBrookTextReader read GetProxyReader
- write SetProxyReader;
- public
- { Destroys an instance of @code(TBrookBaseReader). }
- destructor Destroy; override;
- { Resets the reader to its initial state. }
- procedure Reset; override;
- { Closes the reader. }
- procedure Close; override;
- { Checks if the reader has reached the End-Of-File.
- @returns(@True if the reader has reached the End-Of-File.) }
- function IsEOF: Boolean; override;
- { Reads a line as bytes.
- @param(ALine[out] Line read as bytes.) }
- procedure ReadBytes(out ALine: TBytes); overload; override;
- { Reads a line returning it as bytes.
- @returns(Line read as bytes.) }
- function ReadBytes: TBytes; overload; override;
- { Read a line as a static string.
- @param(ALine[out] read as static string.) }
- procedure Read(out ALine: string); overload; override;
- { Reads a line returning it as static string.
- @returns(Line read as static string.) }
- function Read: string; overload; override;
- end;
- { String line reader. }
- TBrookStringReader = class(TBrookBaseReader)
- private
- FProxyReader: TBrookTextReader;
- protected
- procedure SetProxyReader(AValue: TBrookTextReader); override;
- function GetProxyReader: TBrookTextReader; override;
- public
- { Creates an instance of @code(TBrookStringReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AString[in] String to be read line by line.)
- @param(ABufferSize[in] Buffer size for the line reading.) }
- constructor Create(AEncoding: TEncoding; const AString: string;
- ABufferSize: Integer); reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStringReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AString[in] String to be read line by line.) }
- constructor Create(AEncoding: TEncoding; const AString: string);
- reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStringReader)
- @param(AString[in] String to be read line by line.) }
- constructor Create(const AString: string); reintroduce; overload; virtual;
- end;
- { File line reader. }
- TBrookFileReader = class(TBrookBaseReader)
- private
- FProxyReader: TBrookTextReader;
- protected
- procedure SetProxyReader(AValue: TBrookTextReader); override;
- function GetProxyReader: TBrookTextReader; override;
- public
- { Creates an instance of @code(TBrookStringReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AFileName[in] File to be read line by line.)
- @param(AMode[in] Open mode and (possibly) a share mode OR-ed together.)
- @param(ARights[in] Permission bits with which to create the file on Linux.)
- @param(ABufferSize[in] Buffer size for the line reading.) }
- constructor Create(AEncoding: TEncoding; const AFileName: TFileName;
- AMode: Word; ARights: Cardinal;
- ABufferSize: Integer); reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStringReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AFileName[in] File to be read line by line.)
- @param(AMode[in] Open mode and (possibly) a share mode OR-ed together.)
- @param(ABufferSize[in] Buffer size for the line reading.) }
- constructor Create(AEncoding: TEncoding; const AFileName: TFileName;
- AMode: Word; ABufferSize: Integer); reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStringReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AFileName[in] File to be read line by line.)
- @param(ABufferSize[in] Buffer size for the line reading.) }
- constructor Create(AEncoding: TEncoding; const AFileName: TFileName;
- ABufferSize: Integer); reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStringReader)
- @param(AEncoding[in] Character encoding determined during reading.)
- @param(AFileName[in] File to be read line by line.) }
- constructor Create(AEncoding: TEncoding;
- const AFileName: TFileName); reintroduce; overload; virtual;
- { Creates an instance of @code(TBrookStringReader)
- @param(AFileName[in] File to be read line by line.) }
- constructor Create(
- const AFileName: TFileName); reintroduce; overload; virtual;
- end;
- implementation
- { TBrookStreamReader }
- constructor TBrookStreamReader.Create(AEncoding: TEncoding; AStream: TStream;
- ABufferSize: Cardinal; AOwnsStream: Boolean);
- begin
- inherited Create;
- if not Assigned(AStream) then
- raise EArgumentNilException.CreateFmt(SParamIsNil, ['AStream']);
- FEncoding := AEncoding;
- FStream := AStream;
- FOwnsStream := AOwnsStream;
- if ABufferSize >= BROOK_MIN_BUFFER_SIZE then
- SetLength(FBuffer, ABufferSize)
- else
- SetLength(FBuffer, BROOK_MIN_BUFFER_SIZE);
- end;
- constructor TBrookStreamReader.Create(AEncoding: TEncoding; AStream: TStream);
- begin
- Create(AEncoding, AStream, BROOK_BUFFER_SIZE, False);
- end;
- constructor TBrookStreamReader.Create(AStream: TStream);
- begin
- Create(TEncoding.UTF8, AStream);
- end;
- destructor TBrookStreamReader.Destroy;
- begin
- Close;
- inherited Destroy;
- end;
- procedure TBrookStreamReader.FillBuffer;
- begin
- FBufferRead := FStream.Read(FBuffer[0], Pred(Length(FBuffer)));
- FBuffer[FBufferRead] := 0;
- FBufferPosition := 0;
- end;
- function TBrookStreamReader.GetEncoding: TEncoding;
- begin
- Result := FEncoding;
- end;
- function TBrookStreamReader.GetOwnsStream: Boolean;
- begin
- Result := FOwnsStream;
- end;
- function TBrookStreamReader.GetStream: TStream;
- begin
- Result := FStream;
- end;
- procedure TBrookStreamReader.SetEncoding(AValue: TEncoding);
- begin
- FEncoding := AValue;
- end;
- procedure TBrookStreamReader.SetOwnsStream(AValue: Boolean);
- begin
- FOwnsStream := AValue;
- end;
- procedure TBrookStreamReader.Reset;
- begin
- FBufferRead := 0;
- FBufferPosition := 0;
- if Assigned(FStream) then
- FStream.Seek(0, TSeekOrigin.soBeginning);
- end;
- procedure TBrookStreamReader.Close;
- begin
- if FOwnsStream then
- begin
- FStream.Free;
- FStream := nil;
- end;
- end;
- function TBrookStreamReader.IsEOF: Boolean;
- begin
- if not Assigned(FStream) then
- Exit(True);
- Result := FBufferPosition >= FBufferRead;
- if Result then
- begin
- FillBuffer;
- Result := FBufferRead = 0;
- end;
- end;
- procedure TBrookStreamReader.ReadBytes(out ALine: TBytes);
- var
- VBuf: PByte;
- VPos, VLen, VCount: Integer;
- begin
- VPos := FBufferPosition;
- ALine := nil;
- repeat
- VBuf := @FBuffer[FBufferPosition];
- while (FBufferPosition < FBufferRead) and not (VBuf^ in [10, 13]) do
- begin
- Inc(VBuf);
- Inc(FBufferPosition);
- end;
- if FBufferPosition = FBufferRead then
- begin
- VCount := FBufferPosition - VPos;
- if VCount > 0 then
- begin
- VLen := Length(ALine);
- SetLength(ALine, VLen + VCount);
- Move(FBuffer[VPos], ALine[VLen], VCount);
- end;
- FillBuffer;
- VPos := FBufferPosition;
- end;
- until (FBufferPosition = FBufferRead) or (VBuf^ in [10, 13]);
- VCount := FBufferPosition - VPos;
- if VCount > 0 then
- begin
- VLen := Length(ALine);
- SetLength(ALine, VLen + VCount);
- Move(FBuffer[VPos], ALine[VLen], VCount);
- end;
- if (VBuf^ in [10, 13]) and (FBufferPosition < FBufferRead) then
- begin
- Inc(FBufferPosition);
- if VBuf^ = 13 then
- begin
- if FBufferPosition = FBufferRead then
- FillBuffer;
- if (FBufferPosition < FBufferRead) and (FBuffer[FBufferPosition] = 10) then
- Inc(FBufferPosition);
- end;
- end;
- end;
- function TBrookStreamReader.ReadBytes: TBytes;
- begin
- ReadBytes(Result);
- end;
- procedure TBrookStreamReader.Read(out ALine: string);
- begin
- ALine :=
- {$IFDEF FPC}string({$ENDIF}FEncoding.GetString(ReadBytes){$IFDEF FPC}){$ENDIF};
- end;
- function TBrookStreamReader.Read: string;
- begin
- Read(Result);
- end;
- { TBrookBaseReader }
- destructor TBrookBaseReader.Destroy;
- begin
- ProxyReader.Free;
- ProxyReader := nil;
- inherited Destroy;
- end;
- procedure TBrookBaseReader.SetEncoding(AValue: TEncoding);
- begin
- ProxyReader.Encoding := AValue;
- end;
- function TBrookBaseReader.GetEncoding: TEncoding;
- begin
- Result := ProxyReader.Encoding;
- end;
- procedure TBrookBaseReader.Reset;
- begin
- ProxyReader.Reset;
- end;
- procedure TBrookBaseReader.Close;
- begin
- ProxyReader.Close;
- end;
- function TBrookBaseReader.IsEOF: Boolean;
- begin
- Result := ProxyReader.IsEOF;
- end;
- procedure TBrookBaseReader.ReadBytes(out ALine: TBytes);
- begin
- ProxyReader.ReadBytes(ALine);
- end;
- function TBrookBaseReader.ReadBytes: TBytes;
- begin
- ProxyReader.ReadBytes(Result);
- end;
- procedure TBrookBaseReader.Read(out ALine: string);
- begin
- ProxyReader.Read(ALine);
- end;
- function TBrookBaseReader.Read: string;
- begin
- ProxyReader.Read(Result);
- end;
- { TBrookStringReader }
- constructor TBrookStringReader.Create(AEncoding: TEncoding;
- const AString: string; ABufferSize: Integer);
- var
- VStream: TStream;
- begin
- inherited Create;
- {$IFNDEF FPC}
- if Assigned(AEncoding) then
- VStream := TStringStream.Create(AString, AEncoding)
- else
- {$ENDIF}
- VStream := TStringStream.Create(AString);
- FProxyReader := TBrookStreamReader.Create(AEncoding, VStream,
- ABufferSize, True);
- end;
- constructor TBrookStringReader.Create(AEncoding: TEncoding;
- const AString: string);
- begin
- Create(AEncoding, AString, BROOK_BUFFER_SIZE);
- end;
- constructor TBrookStringReader.Create(const AString: string);
- begin
- Create(TEncoding.UTF8, AString);
- end;
- procedure TBrookStringReader.SetProxyReader(AValue: TBrookTextReader);
- begin
- FProxyReader := AValue;
- end;
- function TBrookStringReader.GetProxyReader: TBrookTextReader;
- begin
- Result := FProxyReader;
- end;
- { TBrookFileReader }
- constructor TBrookFileReader.Create(AEncoding: TEncoding;
- const AFileName: TFileName; AMode: Word; ARights: Cardinal;
- ABufferSize: Integer);
- begin
- inherited Create;
- FProxyReader := TBrookStreamReader.Create(AEncoding,
- TFileStream.Create(AFileName, AMode, ARights), ABufferSize, True);
- end;
- constructor TBrookFileReader.Create(AEncoding: TEncoding;
- const AFileName: TFileName; AMode: Word; ABufferSize: Integer);
- begin
- Create(AEncoding, AFileName, AMode, BROOK_FILE_RIGHTS, ABufferSize);
- end;
- constructor TBrookFileReader.Create(AEncoding: TEncoding;
- const AFileName: TFileName; ABufferSize: Integer);
- begin
- Create(AEncoding, AFileName, fmOpenRead or fmShareDenyWrite, ABufferSize);
- end;
- constructor TBrookFileReader.Create(AEncoding: TEncoding;
- const AFileName: TFileName);
- begin
- Create(AEncoding, AFileName, BROOK_BUFFER_SIZE);
- end;
- constructor TBrookFileReader.Create(const AFileName: TFileName);
- begin
- Create(TEncoding.UTF8, AFileName);
- end;
- procedure TBrookFileReader.SetProxyReader(AValue: TBrookTextReader);
- begin
- FProxyReader := AValue;
- end;
- function TBrookFileReader.GetProxyReader: TBrookTextReader;
- begin
- Result := FProxyReader;
- end;
- end.
|