【问题标题】:Inno Setup Pascal Script - Reading UTF-16 fileInno Setup Pascal 脚本 - 读取 UTF-16 文件
【发布时间】:2017-02-12 03:20:03
【问题描述】:

我有一个从 Resource Hacker 导出的 .inf 文件。该文件采用 UTF-16 LE 编码。

EXTRALARGELEGENDSII_INI TEXTFILE "Data.bin"

LARGEFONTSLEGENDSII_INI TEXTFILE "Data_2.bin"

NORMALLEGENDSII_INI TEXTFILE "Data_3.bin"

THEMES_INI TEXTFILE "Data_4.bin" 

当我使用 LoadStringFromFile function 加载它时:

procedure LoadResources;
var
  RESOURCE_INFO: AnsiString;
begin
  LoadStringFromFile(ExpandConstant('{tmp}\SKINRESOURCE - INFO.inf'), RESOURCE_INFO);
  Log(String(RESOURCE_INFO));
end;

我在调试输出中得到了这个:

E

请告诉我如何解决这个问题。

提前致谢。

【问题讨论】:

    标签: inno-setup utf-16 pascalscript


    【解决方案1】:

    文件采用 UTF-16 LE 编码。

    LoadStringFromFile 不支持任何 Unicode 编码。它将文件按原样加载到字节数组中(AnsiString 被有效地用作字节数组)。

    由于 Unicode string(在 Unicode version of Inno Setup - Inno Setup 6 的唯一版本)实际上使用 UTF-16 LE 编码,您只需将字节数组按位复制到 (Unicode) string。并修剪UTF-16 LE BOM (FEFF)。

    procedure RtlMoveMemory(Dest: string; Source: PAnsiChar; Len: Integer);
      external 'RtlMoveMemory@kernel32.dll stdcall';
    
    function LoadStringFromUTF16LEFile(FileName: string; var S: string): Boolean;
    var
      A: AnsiString;
    begin
      Result := LoadStringFromFile(FileName, A);
      if Result then
      begin
        SetLength(S, Length(A) div 2);
        RtlMoveMemory(S, A, Length(S) * 2);
        { Trim BOM, if any }
        if (Length(S) >= 1) and (Ord(S[1]) = $FEFF) then
          Delete(S, 1, 1);
      end;
    end;
    

    另见:

    【讨论】:

      【解决方案2】:

      您尝试记录的文件似乎是 Windows Unicode (UTF-16LE) 编码的文本文件。

      您可以使用iConv 命令行并将您的文件转换为 Windows UTF-8 编码文件。

      LoadStringFromFile Support Function 不能很好地加载 Unicode 字符串,它只支持加载 ANSI 和 UTF-8 编码的文本文件。

      Inno Setup Compiler Debug Output 停止记录文本文件,因为它找到了一个无法加载的字符 (NULL),这就是为什么即使 LoadStringFromFile 完全加载文本文件,编译器调试输出中也只会得到“E” .


      您需要下载 iConv 的安装程序,如下图所示,以获得 iConv 可执行文件和一些用于字符编码之间转换的 DLL。

      下载后,安装 GnuWin32 (LibIconv for Windows) 并进入安装文件夹。

      将以下四个文件复制到安装文件夹“bin”的子目录中。

      他们是:

      libcharset1.dll

      libiconv2.dll

      iconv.exe

      libintl3.dll

      将这些文件复制到存储 Inno 设置项目文件的目录。

      然后使用以下代码进行转换。

      [Files]
      Source: "libcharset1.dll"; Flags: dontcopy
      Source: "iconv.exe"; Flags: dontcopy
      Source: "libiconv2.dll"; Flags: dontcopy
      Source: "libintl3.dll"; Flags: dontcopy
      
      [Code]
      function InitializeSetup(): Boolean
      var
        ErrorCode: Integer;
      begin
        ExtractTemporaryFile('iconv.exe');
        ExtractTemporaryFile('libcharset1.dll');
        ExtractTemporaryFile('libintl3.dll');
        ExtractTemporaryFile('libiconv2.dll');
        ShellExec('Open', ExpandConstant('CMD.exe'), ExpandConstant('/C iConv -f UTF-16LE -t UTF-8 < SKINRESOURCE-INFO.inf > SKINRESOURCE-INFO-ANSI.inf'), ExpandConstant('{tmp}'), SW_HIDE, ewWaitUntilTerminated, ErrorCode); 
        DeleteFile(ExpandConstant('{tmp}\SKINRESOURCE-INFO.inf')); 
      

      现在LoadStringFromFile 应该正确加载文本文件,因为它现在具有 Windows UTF-8 编码。

      如果您使用的是 Unicode Inno Setup,您也可以在将其转换为 Unicode 字符串(如 Log(String(RESOURCE_INFO)))后对其进行记录。

      【讨论】:

      • 谢谢!像魅力一样工作!
      • 1) 为什么选择 ANSI?这样会丢失 Unicode 字符。使用 UTF-8! 2) 请注意,ANSI 与 Windows-1252 不同。使用的 ANSI 编码因 Windows 配置而异。因此,如果您显式转换为 Windows-1252,但使用配置的 ANSI 编码加载文件,则最终会出现混乱,除非文件仅使用 ASCII 字符。 3)您可以use PowerShell to convert encoding,无需第三方工具。但无论如何,您甚至不需要任何外部工具。您可以在 Pascal 脚本中进行转换。
      • @MartinPrikryl 已更正为 UTF-8。我忘记了PowerShell。 :-(
      • 4) LoadStringFromFile 在找到 NULL 字符时停止加载文本文件是不正确的。 LoadStringFromFile 总是完全加载文件。只有 Inno Setup Compiler Debug Output 窗格在 NULL 字符处停止。看我的回答。
      • 查看我的更新答案,了解加载 UTF-16 LE 文件的函数。
      猜你喜欢
      • 1970-01-01
      • 2013-01-22
      • 2021-01-21
      • 2011-08-13
      • 1970-01-01
      • 1970-01-01
      • 2016-08-18
      • 2022-06-22
      • 1970-01-01
      相关资源
      最近更新 更多