【问题标题】:TIdMBCSEncoding.Create('ASCII') returns with MaxCharSize = 0 on LinuxTIdMBCSEncoding.Create('ASCII') 在 Linux 上返回 MaxCharSize = 0
【发布时间】:2012-07-26 10:03:21
【问题描述】:

我的环境是 i386 上的 Ubuntu 12.04 Linux。我可以看到只安装了 UTF-8 语言环境(/var/lib/locales/supported.d/local):

de_DE.UTF-8 UTF-8
en_US.UTF-8 UTF-8
~

现在的问题:

TIdIOHandler.InitComponent 调用 TIdTextEncoding.Default 进而调用 TIdMBCSEncoding.Create('ASCII')。

还有,这条线

FMaxCharSize := GetByteCount(PWideChar(@cValue[0]), 2);

被执行,并且 GetByteCount 返回零 - 这不应该发生(预期值为 1,因为 ASCII 是单字节编码)。

返回零值的地方是IdGlobal中的第2288行:

if iconv(FFromUTF16, @LCharsPtr, @LCharCount, @LBytesPtr, {$IFNDEF KYLIX}@{$ENDIF}LByteCount) = size_t(-1) then
begin
  Result := 0;
  Exit;
end;

这可能是由于缺少 UTF-16 语言环境造成的吗? (我在第一次尝试时没有成功安装 UTF-16 支持,也许 Linux 上的其他 Indy 用户也看到了这个问题)

【问题讨论】:

标签: linux delphi indy freepascal iconv


【解决方案1】:

Indy 目前没有充分处理 iconv() 错误,因为 iconv() 依赖于特定于平台的 errno 变量,这些变量很难在 Indy 中跨多个平台实现(如果 iconv()已实现直接返回其自己的错误代码)。不是所有的iconv()错误都是真正的失败,但是Indy还不知道,所以它把所有的错误都当作失败(至于GetByteCount()为什么在失败时返回0而不是引发异常,这是因为TIdTextEncoding是建模的在 Embarcadero 的 SysUtils.TEncoding 类之后,因此必须与其 API 兼容。这将在 Indy 11 中改变。

ICONV 应该在本地实现其字符集,因此操作系统中安装的位置无关紧要。在这种情况下,我怀疑 iconv() 无法将代码点 $10FFFD 从 UTF-16 转换为 TIdMBCSEncoding.Create() 中的 ASCII,因为它超出了 ASCII 范围,这是 Indy 需要查看 @ 的情况之一987654332@ 区分失败和部分转换,但目前没有这样做。

作为一种解决方法,您可以编辑 IdGlobal.pas 以使 TIdTextEncoding.Default 属性 getter 使用 TIdASCIIEncoding 类而不是 TIdMBCSEncoding 类,因为 Indy 有自己的不依赖于 ICONV 的 ASCII 实现。

{$IFDEF HAS_CLASSPROPERTIES}
class function TIdTextEncoding.GetDefault: TIdTextEncoding;
{$ELSE}
class function TIdTextEncoding.Default: TIdTextEncoding;
{$ENDIF}
var
  LEncoding: TIdTextEncoding;
begin
  if GIdDefaultEncoding = nil then
  begin
    {$IFDEF USE_ICONV}
    //LEncoding := TIdMBCSEncoding.Create('ASCII');
    LEncoding := TIdASCIIEncoding.Create;
    {$ELSE}
    ...

【讨论】:

  • 您可以尝试的另一种选择是TIdMBCSEncoding.Create('')。空字符串应该告诉 iconv 使用机器/操作系统相关的语言环境,这实际上是 TIdTextEncoding.Default 无论如何要表示的内容。但我怀疑在某些情况下,即使这样也会导致GetByteCount() 出现类似的故障。
  • 或者也可以尝试将字符集名称设置为 'ASCII//TRANSLIT' 而不仅仅是 'ASCII'。
  • 我刚刚在 Indy 的 SVN 中签入了新版本的 IdGlobal.pas。启用 iconv 时,它会声明新的 GIdIconvUseLocaleDependantAnsiEncoding、GIdIconvIgnoreIllegalChars 和 GIdIconvUseTransliteration 全局变量,并更新 TIdMBCSEncoding 构造函数以在无法计算 FMaxCharSize 时引发异常。
  • 将 GIdIconvUseTransliteration 设置为 True 已修复,非常感谢!
猜你喜欢
  • 2021-10-28
  • 2014-07-17
  • 1970-01-01
  • 2019-09-26
  • 2011-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多