Browse Source

ISSigTool: Make it work with Unicode filenames. Still stuff todo.

Martijn Laan 2 months ago
parent
commit
0f13e30589
2 changed files with 25 additions and 16 deletions
  1. 15 9
      Components/ISSigFunc.pas
  2. 10 7
      Components/StringScanner.pas

+ 15 - 9
Components/ISSigFunc.pas

@@ -80,7 +80,6 @@ uses
 const
 const
   ISSigTextFileLengthLimit = 500;
   ISSigTextFileLengthLimit = 500;
 
 
-  NonControlASCIICharsSet = [#32..#126];
   DigitsSet = ['0'..'9'];
   DigitsSet = ['0'..'9'];
   HexDigitsSet = DigitsSet + ['a'..'f'];
   HexDigitsSet = DigitsSet + ['a'..'f'];
 
 
@@ -113,7 +112,7 @@ end;
 
 
 function ConsumeLineValue(var SS: TStringScanner; const AIdent: String;
 function ConsumeLineValue(var SS: TStringScanner; const AIdent: String;
   var AValue: String; const AMinValueLength, AMaxValueLength: Integer;
   var AValue: String; const AMinValueLength, AMaxValueLength: Integer;
-  const AAllowedChars: TSysCharSet): Boolean;
+  const AAllowedChars: TSysCharSet = []): Boolean;
 begin
 begin
   Result := False;
   Result := False;
   if SS.Consume(AIdent) and SS.Consume(' ') then
   if SS.Consume(AIdent) and SS.Consume(' ') then
@@ -146,13 +145,20 @@ begin
   end;
   end;
 
 
   { Defense-in-depth: Reject any non-CRLF control characters up front, as well
   { Defense-in-depth: Reject any non-CRLF control characters up front, as well
-    as any non-ASCII characters (to avoid any possible issues with converting
-    invalid multibyte characters) }
+    as any non-ASCII and non-UTF8-high characters (to avoid any possible issues with
+    converting invalid multibyte characters) }
+  const NonControlASCIICharsSet = [#32..#126];
+  const UTF8HighCharsSet = [#128..#244];
   for var C in U do
   for var C in U do
-    if not (CharInSet(C, [#10, #13]) or CharInSet(C, NonControlASCIICharsSet)) then
+    if not (CharInSet(C, [#10, #13]) or CharInSet(C, NonControlASCIICharsSet) or
+            CharInSet(C, UTF8HighCharsSet)) then
       Exit('');
       Exit('');
+  { Do round-trip check to catch invalid sequences }
+  const UTF16Text = String(U);
+  if UTF8String(UTF16Text) <> U then
+    Exit('');
 
 
-  Result := String(U);
+  Result := UTF16Text;
 end;
 end;
 
 
 procedure ISSigSaveTextToFile(const AFilename, AText: String);
 procedure ISSigSaveTextToFile(const AFilename, AText: String);
@@ -218,9 +224,9 @@ begin
     Exit(vsrKeyNotFound);
     Exit(vsrKeyNotFound);
 
 
   var SS := TStringScanner.Create(AText);
   var SS := TStringScanner.Create(AText);
-  if not ConsumeLineValue(SS, 'format', TextValues.Format, 8, 8, NonControlASCIICharsSet) or
+  if not ConsumeLineValue(SS, 'format', TextValues.Format, 8, 8) or
      ((TextValues.Format <> 'issig-v1') and ((TextValues.Format <> 'issig-v2'))) 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, NonControlASCIICharsSet)) or
+     ((TextValues.Format = 'issig-v2') and not ConsumeLineValue(SS, 'file-name', TextValues.FileName, 1, MaxInt)) or
      not ConsumeLineValue(SS, 'file-size', TextValues.FileSize, 1, 16, DigitsSet) 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, 'file-hash', TextValues.FileHash, 64, 64, HexDigitsSet) or
      not ConsumeLineValue(SS, 'key-id', TextValues.KeyID, 64, 64, HexDigitsSet) or
      not ConsumeLineValue(SS, 'key-id', TextValues.KeyID, 64, 64, HexDigitsSet) or
@@ -384,7 +390,7 @@ begin
     Exit;
     Exit;
 
 
   var SS := TStringScanner.Create(AText);
   var SS := TStringScanner.Create(AText);
-  if not ConsumeLineValue(SS, 'format', TextValues.Format, 16, 17, NonControlASCIICharsSet) then
+  if not ConsumeLineValue(SS, 'format', TextValues.Format, 16, 17) then
     Exit;
     Exit;
   var HasPrivateKey := False;
   var HasPrivateKey := False;
   if TextValues.Format = 'issig-private-key' then
   if TextValues.Format = 'issig-private-key' then

+ 10 - 7
Components/StringScanner.pas

@@ -26,10 +26,10 @@ type
     function Consume(const C: Char): Boolean; overload;
     function Consume(const C: Char): Boolean; overload;
     function Consume(const S: String): Boolean; overload;
     function Consume(const S: String): Boolean; overload;
     function ConsumeMulti(const C: TSysCharSet; const AMinChars: Integer = 1;
     function ConsumeMulti(const C: TSysCharSet; const AMinChars: Integer = 1;
-      const AMaxChars: Integer = Maxint): Integer;
+      const AMaxChars: Integer = MaxInt; const AAllowControl: Boolean = False): Integer;
     function ConsumeMultiToString(const C: TSysCharSet;
     function ConsumeMultiToString(const C: TSysCharSet;
       var ACapturedString: String; const AMinChars: Integer = 1;
       var ACapturedString: String; const AMinChars: Integer = 1;
-      const AMaxChars: Integer = Maxint): Integer;
+      const AMaxChars: Integer = MaxInt; const AAllowControl: Boolean = False): Integer;
     property ReachedEnd: Boolean read GetReachedEnd;
     property ReachedEnd: Boolean read GetReachedEnd;
     property RemainingCount: Integer read GetRemainingCount;
     property RemainingCount: Integer read GetRemainingCount;
     property Str: String read FStr;
     property Str: String read FStr;
@@ -37,6 +37,9 @@ type
 
 
 implementation
 implementation
 
 
+uses
+  Character;
+
 {$ZEROBASEDSTRINGS OFF}
 {$ZEROBASEDSTRINGS OFF}
 
 
 { TStringScanner }
 { TStringScanner }
@@ -69,7 +72,7 @@ begin
 end;
 end;
 
 
 function TStringScanner.ConsumeMulti(const C: TSysCharSet;
 function TStringScanner.ConsumeMulti(const C: TSysCharSet;
-  const AMinChars: Integer = 1; const AMaxChars: Integer = Maxint): Integer;
+  const AMinChars, AMaxChars: Integer; const AAllowControl: Boolean): Integer;
 begin
 begin
   if (AMinChars <= 0) or (AMinChars > AMaxChars) then
   if (AMinChars <= 0) or (AMinChars > AMaxChars) then
     raise Exception.Create('TStringScanner.ConsumeMulti: Invalid parameter');
     raise Exception.Create('TStringScanner.ConsumeMulti: Invalid parameter');
@@ -80,7 +83,8 @@ begin
 
 
   Result := 0;
   Result := 0;
   while (Result < AMaxChars) and (Result < Remain) and
   while (Result < AMaxChars) and (Result < Remain) and
-     CharInSet(FStr[FPosition + Result], C) do
+     ((C = []) or CharInSet(FStr[FPosition + Result], C)) and
+     (AAllowControl or not FStr[FPosition + Result].IsControl) do
     Inc(Result);
     Inc(Result);
 
 
   if Result < AMinChars then
   if Result < AMinChars then
@@ -90,11 +94,10 @@ begin
 end;
 end;
 
 
 function TStringScanner.ConsumeMultiToString(const C: TSysCharSet;
 function TStringScanner.ConsumeMultiToString(const C: TSysCharSet;
-  var ACapturedString: String; const AMinChars: Integer = 1;
-  const AMaxChars: Integer = Maxint): Integer;
+  var ACapturedString: String; const AMinChars, AMaxChars: Integer; const AAllowControl: Boolean): Integer;
 begin
 begin
   const StartPos = FPosition;
   const StartPos = FPosition;
-  Result := ConsumeMulti(C, AMinChars, AMaxChars);
+  Result := ConsumeMulti(C, AMinChars, AMaxChars, AAllowControl);
   if Result > 0 then
   if Result > 0 then
     ACapturedString := Copy(FStr, StartPos, Result)
     ACapturedString := Copy(FStr, StartPos, Result)
   else
   else