123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- unit StringScanner;
- {
- Inno Setup
- Copyright (C) 1997-2025 Jordan Russell
- Portions by Martijn Laan
- For conditions of distribution and use, see LICENSE.TXT.
- TStringScanner
- }
- interface
- uses
- SysUtils;
- type
- TStringScanner = record
- strict private
- FStr: String;
- FPosition: Integer;
- function GetReachedEnd: Boolean;
- function GetRemainingCount: Integer;
- public
- class function Create(const AString: String): TStringScanner; static;
- function Consume(const C: Char): Boolean; overload;
- function Consume(const S: String): Boolean; overload;
- function ConsumeMulti(const AAllowedChars: TSysCharSet;
- const AAllowAllCharsAboveFF: Boolean = False; const AMinChars: Integer = 1;
- const AMaxChars: Integer = MaxInt): Integer;
- function ConsumeMultiToString(const AAllowedChars: TSysCharSet;
- var ACapturedString: String; const AAllowAllCharsAboveFF: Boolean = False;
- const AMinChars: Integer = 1; const AMaxChars: Integer = MaxInt): Integer;
- property ReachedEnd: Boolean read GetReachedEnd;
- property RemainingCount: Integer read GetRemainingCount;
- property Str: String read FStr;
- end;
- implementation
- {$ZEROBASEDSTRINGS OFF}
- { TStringScanner }
- class function TStringScanner.Create(const AString: String): TStringScanner;
- begin
- Result.FPosition := 1;
- Result.FStr := AString;
- end;
- function TStringScanner.Consume(const C: Char): Boolean;
- begin
- Result := (GetRemainingCount > 0) and (FStr[FPosition] = C);
- if Result then
- Inc(FPosition);
- end;
- function TStringScanner.Consume(const S: String): Boolean;
- begin
- const SLen = Length(S);
- if SLen > GetRemainingCount then
- Exit(False);
- for var I := 0 to SLen-1 do
- if FStr[FPosition + I] <> S[I+1] then
- Exit(False);
- Inc(FPosition, SLen);
- Result := True;
- end;
- function TStringScanner.ConsumeMulti(const AAllowedChars: TSysCharSet;
- const AAllowAllCharsAboveFF: Boolean = False; const AMinChars: Integer = 1;
- const AMaxChars: Integer = MaxInt): Integer;
- begin
- { AMinChars may be 0; it functions the same as 1 }
- if (AMinChars < 0) or (AMinChars > AMaxChars) then
- raise Exception.Create('TStringScanner.ConsumeMulti: Invalid parameter');
- const Remain = GetRemainingCount;
- if Remain < AMinChars then
- Exit(0);
- Result := 0;
- while (Result < AMaxChars) and (Result < Remain) and
- (CharInSet(FStr[FPosition + Result], AAllowedChars) or
- (AAllowAllCharsAboveFF and (Ord(FStr[FPosition + Result]) > $FF))) do
- Inc(Result);
- if Result < AMinChars then
- Result := 0
- else
- Inc(FPosition, Result);
- end;
- function TStringScanner.ConsumeMultiToString(const AAllowedChars: TSysCharSet;
- var ACapturedString: String; const AAllowAllCharsAboveFF: Boolean = False;
- const AMinChars: Integer = 1; const AMaxChars: Integer = MaxInt): Integer;
- begin
- const StartPos = FPosition;
- Result := ConsumeMulti(AAllowedChars, AAllowAllCharsAboveFF, AMinChars, AMaxChars);
- if Result > 0 then
- ACapturedString := Copy(FStr, StartPos, Result)
- else
- ACapturedString := '';
- end;
- function TStringScanner.GetReachedEnd: Boolean;
- begin
- Result := (GetRemainingCount = 0);
- end;
- function TStringScanner.GetRemainingCount: Integer;
- begin
- { The "<= 0" check exists to protect against OOB reads in case someone calls
- into an instance that was never properly initialized (via Create).
- Inside TStringScanner, FStr[FPosition] must not be accessed unless
- GetRemainingCount is called first and returns a nonzero value. }
- const Len = Length(FStr);
- if (FPosition <= 0) or (FPosition > Len) then
- Result := 0
- else
- Result := Len - FPosition + 1;
- end;
- end.
|