1

我的环境是 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 用户也看到了这个问题)

4

1 回答 1

2

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

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

作为一种解决方法,您可以编辑 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}
    ...
于 2012-07-26T22:07:12.413 回答