Jelajahi Sumber

Support characters above U+00FF in a simpler, faster, and more flexible way.

And avoid TCharHelper.IsControl because (a) it may return different values on different Delphi versions and (b) the caller / .issig spec should have total control over what is considered a control character.

Jordan Russell 2 bulan lalu
induk
melakukan
756405e135
2 mengubah file dengan 24 tambahan dan 30 penghapusan
  1. 9 12
      Components/ISSigFunc.pas
  2. 15 18
      Components/StringScanner.pas

+ 9 - 12
Components/ISSigFunc.pas

@@ -82,6 +82,7 @@ const
 
   NonControlASCIICharsSet = [#32..#126];
   UTF8HighCharsSet = [#128..#244];
+  AllHighCharsSet = [#128..#255];
   DigitsSet = ['0'..'9'];
   HexDigitsSet = DigitsSet + ['a'..'f'];
 
@@ -117,18 +118,13 @@ end;
 
 function ConsumeLineValue(var SS: TStringScanner; const AIdent: String;
   var AValue: String; const AMinValueLength, AMaxValueLength: Integer;
-  const AAllowedChars: TSysCharSet = []; const ARequireQuotes: Boolean = False): Boolean;
-var
-  DisallowedChars: TSysCharSet;
+  const AAllowedChars: TSysCharSet; const AAllowAllCharsAboveFF: Boolean = False;
+  const ARequireQuotes: Boolean = False): Boolean;
 begin
   Result := False;
   if SS.Consume(AIdent) and SS.Consume(' ') and (not ARequireQuotes or SS.Consume('"')) then
-    if ARequireQuotes then
-      DisallowedChars := ['"']
-    else
-      DisallowedChars := [];
-    if SS.ConsumeMultiToString(AAllowedChars, DisallowedChars, AValue, AMinValueLength,
-       AMaxValueLength) > 0 then begin
+    if SS.ConsumeMultiToString(AAllowedChars, AValue, AAllowAllCharsAboveFF,
+       AMinValueLength, AMaxValueLength) > 0 then begin
       if not ARequireQuotes or SS.Consume('"') then begin
         { CRLF and LF line breaks are allowed (but not CR) }
         SS.Consume(#13);
@@ -245,9 +241,10 @@ begin
     Exit(vsrKeyNotFound);
 
   var SS := TStringScanner.Create(AText);
-  if not ConsumeLineValue(SS, 'format', TextValues.Format, 8, 8) or
+  if not ConsumeLineValue(SS, 'format', TextValues.Format, 8, 8, NonControlASCIICharsSet) or
      ((TextValues.Format <> 'issig-v1') and ((TextValues.Format <> 'issig-v2'))) or
-     ((TextValues.Format = 'issig-v2') and not ConsumeLineValue(SS, 'file-name', TextValues.FileName, 1, MaxInt, [], True)) or
+     ((TextValues.Format = 'issig-v2') and not ConsumeLineValue(SS, 'file-name', TextValues.FileName, 1, MaxInt,
+       (NonControlASCIICharsSet - ['"']) + AllHighCharsSet, True, True)) or
      not ConsumeLineValue(SS, 'file-size', TextValues.FileSize, 1, 16, DigitsSet) or
      not ConsumeLineValue(SS, 'file-hash', TextValues.FileHash, 64, 64, HexDigitsSet) or
      not ConsumeLineValue(SS, 'key-id', TextValues.KeyID, 64, 64, HexDigitsSet) or
@@ -411,7 +408,7 @@ begin
     Exit;
 
   var SS := TStringScanner.Create(AText);
-  if not ConsumeLineValue(SS, 'format', TextValues.Format, 16, 17) then
+  if not ConsumeLineValue(SS, 'format', TextValues.Format, 16, 17, NonControlASCIICharsSet) then
     Exit;
   var HasPrivateKey := False;
   if TextValues.Format = 'issig-private-key' then

+ 15 - 18
Components/StringScanner.pas

@@ -25,11 +25,12 @@ type
     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, ADisallowedChars: TSysCharSet; const AMinChars: Integer = 1;
-      const AMaxChars: Integer = MaxInt; const AAllowControl: Boolean = False): Integer;
-    function ConsumeMultiToString(const AAllowedChars, ADisallowedChars: TSysCharSet;
-      var ACapturedString: String; const AMinChars: Integer = 1;
-      const AMaxChars: Integer = MaxInt; const AAllowControl: Boolean = False): Integer;
+    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;
@@ -37,9 +38,6 @@ type
 
 implementation
 
-uses
-  Character;
-
 {$ZEROBASEDSTRINGS OFF}
 
 { TStringScanner }
@@ -71,10 +69,9 @@ begin
   Result := True;
 end;
 
-function TStringScanner.ConsumeMulti(const AAllowedChars, ADisallowedChars: TSysCharSet;
-  const AMinChars, AMaxChars: Integer; const AAllowControl: Boolean): Integer;
-{ AAllowedChars may be empty to allow all chars and ADisallowedChars may be empty to
-  disallow none }
+function TStringScanner.ConsumeMulti(const AAllowedChars: TSysCharSet;
+  const AAllowAllCharsAboveFF: Boolean = False; const AMinChars: Integer = 1;
+  const AMaxChars: Integer = MaxInt): Integer;
 begin
   if (AMinChars <= 0) or (AMinChars > AMaxChars) then
     raise Exception.Create('TStringScanner.ConsumeMulti: Invalid parameter');
@@ -85,9 +82,8 @@ begin
 
   Result := 0;
   while (Result < AMaxChars) and (Result < Remain) and
-     ((AAllowedChars = []) or CharInSet(FStr[FPosition + Result], AAllowedChars)) and
-     ((ADisallowedChars = []) or not CharInSet(FStr[FPosition + Result], ADisallowedChars)) and
-     (AAllowControl or not FStr[FPosition + Result].IsControl) do
+     (CharInSet(FStr[FPosition + Result], AAllowedChars) or
+      (AAllowAllCharsAboveFF and (Ord(FStr[FPosition + Result]) > $FF))) do
     Inc(Result);
 
   if Result < AMinChars then
@@ -96,11 +92,12 @@ begin
     Inc(FPosition, Result);
 end;
 
-function TStringScanner.ConsumeMultiToString(const AAllowedChars, ADisallowedChars: TSysCharSet;
-  var ACapturedString: String; const AMinChars, AMaxChars: Integer; const AAllowControl: Boolean): Integer;
+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, ADisallowedChars, AMinChars, AMaxChars, AAllowControl);
+  Result := ConsumeMulti(AAllowedChars, AAllowAllCharsAboveFF, AMinChars, AMaxChars);
   if Result > 0 then
     ACapturedString := Copy(FStr, StartPos, Result)
   else