使用单位 LazUTF8 时 TIdURI.URLDecode 的错误结果
Wrong result of TIdURI.URLDecode when unit LazUTF8 is used
使用 Free Pascal 3.0.4,此测试程序正确写入 ÄÖÜ
program FPCTest;
uses IdURI;
begin
WriteLn(TIdURI.URLDecode('%C3%84%C3%96%C3%9C'));
ReadLn;
end.
但是,如果使用单位 LazUTF8(如 here 所述),它会写入 ???
program FPCTest;
uses IdURI, LazUTF8;
begin
WriteLn(TIdURI.URLDecode('%C3%84%C3%96%C3%9C'));
ReadLn;
end.
如何解决使用 LazUTF8 的程序的解码错误?
在 TIdURI.URLDecode 行中进行此更改后,可以使用第 386ff 行 LazUTF8:
{$IFDEF FPC}
Result := string(AByteEncoding.GetString(LBytes));
{$ELSE}
{$IFDEF STRING_IS_ANSI}
EnsureEncoding(ADestEncoding, encOSDefault);
CheckByteEncoding(LBytes, AByteEncoding, ADestEncoding);
SetString(Result, PAnsiChar(LBytes), Length(LBytes));
{$ELSE}
Result := AByteEncoding.GetString(LBytes);
{$ENDIF}
{$ENDIF}
备注
此更改假定始终使用 LazUTF8 单元,并且每次使用新版本时都需要应用 Indy 源代码更改。
此外,我发现无法以适用于和不适用 LazUTF8 的方式修复 TIdURI.URLDecode。
当 String
类型是 AnsiString
1 的别名时,Indy 的许多功能公开了额外的 parameters/properties 让用户控制当在执行 AnsiString<->byte
转换的操作中传递 AnsiString
值时,使用 ANSI 编码。
1: Delphi pre-2009, FreePascal/Lazarus when {$ModeSwitch UnicodeStrings}
and {$Mode DelphiUnicode}
are not used (FYI, Indy 11 will use them !).
在大多数情况下,Indy 的默认字节编码是 ASCII(因为 Indy 实现的许多 Internet 协议最初只支持 ASCII - 各个 Indy 组件会根据协议将自己升级为 UTF),尽管有些东西使用 OS 默认 codepage/charset 而不是。
Indy 的默认字节编码可以在运行时通过在 IdGlobal
单元中设置全局 GIdDefaultTextEncoding
变量来更改,例如:
GIdDefaultTextEncoding := encUTF8;
但是,在这种特殊情况下,TIdURI.URLEncode()
不使用 GIdDefaultTextEncoding
,但它确实有一个可选的 ADestEncoding
参数,您可以使用该参数为returned AnsiString
(除了一个可选的 AByteEncoding
参数来指定已解析的 url 八位字节的字节编码 - 默认为 UTF-8),例如:
TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
{$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding_UTF8{$ENDIF}
)
上面的代码会将 url 编码的八位字节解析为 UTF-8,然后 return 该数据按原样解析为 UTF-8 编码 AnsiString
.
如果您没有为 ADestEncoding
指定输出编码,URLDecode()
默认为 OS 默认值。如果您希望它使用 GIdDefaultTextEncoding
,请在 ADestEncoding
参数中指定 IndyTextEncoding_Default
:
TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
{$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding_Default{$ENDIF}
)
另一种选择是对 ADestEncoding
使用 IndyTextEncoding(CodePage)
函数,将其传递给 FreePascal 的 DefaultSystemCodePage
变量,LazUtils
包将其设置为 CP_UTF8
2:
TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
{$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding(DefaultSystemCodePage){$ENDIF}
)
2:我在 Indy 的问题跟踪器中有 opened a ticket,以便在为 FreePascal/Lazarus 编译时添加对 DefaultSystemCodePage
的支持。
使用 Free Pascal 3.0.4,此测试程序正确写入 ÄÖÜ
program FPCTest;
uses IdURI;
begin
WriteLn(TIdURI.URLDecode('%C3%84%C3%96%C3%9C'));
ReadLn;
end.
但是,如果使用单位 LazUTF8(如 here 所述),它会写入 ???
program FPCTest;
uses IdURI, LazUTF8;
begin
WriteLn(TIdURI.URLDecode('%C3%84%C3%96%C3%9C'));
ReadLn;
end.
如何解决使用 LazUTF8 的程序的解码错误?
在 TIdURI.URLDecode 行中进行此更改后,可以使用第 386ff 行 LazUTF8:
{$IFDEF FPC}
Result := string(AByteEncoding.GetString(LBytes));
{$ELSE}
{$IFDEF STRING_IS_ANSI}
EnsureEncoding(ADestEncoding, encOSDefault);
CheckByteEncoding(LBytes, AByteEncoding, ADestEncoding);
SetString(Result, PAnsiChar(LBytes), Length(LBytes));
{$ELSE}
Result := AByteEncoding.GetString(LBytes);
{$ENDIF}
{$ENDIF}
备注
此更改假定始终使用 LazUTF8 单元,并且每次使用新版本时都需要应用 Indy 源代码更改。
此外,我发现无法以适用于和不适用 LazUTF8 的方式修复 TIdURI.URLDecode。
当 String
类型是 AnsiString
1 的别名时,Indy 的许多功能公开了额外的 parameters/properties 让用户控制当在执行 AnsiString<->byte
转换的操作中传递 AnsiString
值时,使用 ANSI 编码。
1: Delphi pre-2009, FreePascal/Lazarus when {$ModeSwitch UnicodeStrings}
and {$Mode DelphiUnicode}
are not used (FYI, Indy 11 will use them !).
在大多数情况下,Indy 的默认字节编码是 ASCII(因为 Indy 实现的许多 Internet 协议最初只支持 ASCII - 各个 Indy 组件会根据协议将自己升级为 UTF),尽管有些东西使用 OS 默认 codepage/charset 而不是。
Indy 的默认字节编码可以在运行时通过在 IdGlobal
单元中设置全局 GIdDefaultTextEncoding
变量来更改,例如:
GIdDefaultTextEncoding := encUTF8;
但是,在这种特殊情况下,TIdURI.URLEncode()
不使用 GIdDefaultTextEncoding
,但它确实有一个可选的 ADestEncoding
参数,您可以使用该参数为returned AnsiString
(除了一个可选的 AByteEncoding
参数来指定已解析的 url 八位字节的字节编码 - 默认为 UTF-8),例如:
TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
{$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding_UTF8{$ENDIF}
)
上面的代码会将 url 编码的八位字节解析为 UTF-8,然后 return 该数据按原样解析为 UTF-8 编码 AnsiString
.
如果您没有为 ADestEncoding
指定输出编码,URLDecode()
默认为 OS 默认值。如果您希望它使用 GIdDefaultTextEncoding
,请在 ADestEncoding
参数中指定 IndyTextEncoding_Default
:
TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
{$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding_Default{$ENDIF}
)
另一种选择是对 ADestEncoding
使用 IndyTextEncoding(CodePage)
函数,将其传递给 FreePascal 的 DefaultSystemCodePage
变量,LazUtils
包将其设置为 CP_UTF8
2:
TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
{$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding(DefaultSystemCodePage){$ENDIF}
)
2:我在 Indy 的问题跟踪器中有 opened a ticket,以便在为 FreePascal/Lazarus 编译时添加对 DefaultSystemCodePage
的支持。