Неверный результат TIdURI.URLDecode при использовании модуля LazUTF8 - PullRequest
0 голосов
/ 11 февраля 2019

В Free Pascal 3.0.4 эта тестовая программа корректно пишет ÄÖÜ

program FPCTest;

uses IdURI;

begin
  WriteLn(TIdURI.URLDecode('%C3%84%C3%96%C3%9C'));
  ReadLn;
end.

Однако, если используется модуль LazUTF8 (как описано здесь ),он пишет ???

program FPCTest;

uses IdURI, LazUTF8;

begin
  WriteLn(TIdURI.URLDecode('%C3%84%C3%96%C3%9C'));
  ReadLn;
end.

Как я могу исправить эту ошибку декодирования для программ, которые используют LazUTF8?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Когда тип String является псевдонимом для AnsiString 1 , большая часть функциональности Indy предоставляет дополнительные параметры / свойства, позволяющие пользователям контролировать, какие кодировки ANSI используются при передаче значений AnsiString.в операциях, которые выполняют AnsiString<->byte преобразования.

1: Delphi pre-2009 и FreePascal / Lazarus, когда {$ModeSwitch UnicodeStrings} и {$Mode DelphiUnicode} не используются (к вашему сведению, Indy 11 будет их использовать!).

В большинстве случаев кодирование байтов Indy по умолчанию - ASCII (поскольку многие из интернет-протоколов, которые Indy реализует изначально, поддерживают только ASCII - отдельные компоненты Indy обновляются до UTF в зависимости от протокола), хотя некоторыевместо этого вещи используют кодовую страницу / кодировку ОС по умолчанию.

Байтовая кодировка Indy по умолчанию может быть изменена во время выполнения путем установки глобальной переменной GIdDefaultTextEncoding в единице IdGlobal, например:

GIdDefaultTextEncoding := encUTF8;

Но в этой конкретной ситуации TIdURI.URLEncode() не использует GIdDefaultTextEncoding, но имеет дополнительный параметр ADestEncoding, который можно использовать для указания определенногоc байтовое кодирование для возвращенного AnsiString (в дополнение к необязательному параметру AByteEncoding для указания байтового кодирования проанализированных URL-октетов - UTF-8 по умолчанию), например:

TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
  {$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding_UTF8{$ENDIF}
)

Вышебудет обрабатывать октеты с кодировкой URL как UTF-8, а затем возвращать эти данные как есть в кодировке UTF-8 AnsiString.

Если вы не укажете выходную кодировку для ADestEncoding, URLDecode() по умолчанию для ОС по умолчанию.Если вы хотите, чтобы вместо него использовалось GIdDefaultTextEncoding, укажите IndyTextEncoding_Default в параметре ADestEncoding:

TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
  {$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding_Default{$ENDIF}
)

Другой вариант - использовать функцию IndyTextEncoding(CodePage) для ADestEncoding, передав ей FreePascalDefaultSystemCodePage переменная, для которой пакет LazUtils устанавливает CP_UTF8 2 :

TIdURI.URLDecode('%C3%84%C3%96%C3%9C'
  {$IFNDEF FPC_UNICODESTRINGS}, IndyTextEncoding_UTF8, IndyTextEncoding(DefaultSystemCodePage){$ENDIF}
)

2: у меня открыто билет в системе отслеживания проблем Indy для добавления поддержки DefaultSystemCodePage при компиляции для FreePascal / Lazarus.

0 голосов
/ 11 февраля 2019

С этим изменением в строках 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}

Примечания

Это изменение предполагает, что модуль LazUTF8used всегда , и изменение исходного кода Indy необходимо применять каждый раз, когда используется новая версия.

Также я не нашел способа исправить код TIdURI.URLDe так, чтобы он работал с LazUTF8 и без него.

...