367 lines
11 KiB
Plaintext
367 lines
11 KiB
Plaintext
|
unit IdIDN;
|
||
|
{
|
||
|
This file is part of the Indy (Internet Direct) project, and is offered
|
||
|
under the dual-licensing agreement described on the Indy website.
|
||
|
(http://www.indyproject.org/)
|
||
|
|
||
|
Copyright:
|
||
|
(c) 1993-2012, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
|
||
|
|
||
|
Original Author: J. Peter Mugaas
|
||
|
|
||
|
This file uses the "Windows Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1"
|
||
|
|
||
|
There is a download for some Windows versions at:
|
||
|
|
||
|
http://www.microsoft.com/en-us/download/details.aspx?id=734
|
||
|
|
||
|
for Windows XP and that SDK includes a package of run-time libraries that might
|
||
|
need to be redistributed to Windows XP users.
|
||
|
|
||
|
On some later Windows versions, this is redistributable is not needed.
|
||
|
|
||
|
For Windows 8, we do not use this.
|
||
|
|
||
|
From: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
|
||
|
|
||
|
"On Windows 8 Consumer Preview and Windows Server "8" Beta, the getaddrinfo
|
||
|
function provides support for IRI or Internationalized Domain Name (IDN) parsing
|
||
|
applied to the name passed in the pNodeName parameter. Winsock performs
|
||
|
Punycode/IDN encoding and conversion. This behavior can be disabled using the
|
||
|
AI_DISABLE_IDN_ENCODING flag discussed below.
|
||
|
|
||
|
}
|
||
|
interface
|
||
|
|
||
|
{$I IdCompilerDefines.inc}
|
||
|
|
||
|
uses
|
||
|
IdGlobal
|
||
|
{$IFDEF WIN32_OR_WIN64}
|
||
|
, Windows
|
||
|
{$ENDIF}
|
||
|
;
|
||
|
|
||
|
{$IFDEF WIN32_OR_WIN64}
|
||
|
|
||
|
{
|
||
|
|
||
|
}
|
||
|
// ==++==
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All Rights Reserved
|
||
|
//
|
||
|
// ==++==
|
||
|
|
||
|
// IdnDl.h
|
||
|
//
|
||
|
// WARNING: This .DLL is downlevel only.
|
||
|
//
|
||
|
// This file contains the downlevel versions of the scripts APIs
|
||
|
//
|
||
|
// 06 Jun 2005 Shawn Steele Initial Implementation
|
||
|
const
|
||
|
{$EXTERNALSYM VS_ALLOW_LATIN}
|
||
|
VS_ALLOW_LATIN = $0001;
|
||
|
{$EXTERNALSYM GSS_ALLOW_INHERITED_COMMON}
|
||
|
GSS_ALLOW_INHERITED_COMMON = $0001;
|
||
|
|
||
|
type
|
||
|
{$EXTERNALSYM DownlevelGetLocaleScripts_LPFN}
|
||
|
DownlevelGetLocaleScripts_LPFN = function (
|
||
|
lpLocaleName : LPCWSTR; // Locale Name
|
||
|
lpScripts : LPWSTR; // Output buffer for scripts
|
||
|
cchScripts : Integer // size of output buffer
|
||
|
) : Integer stdcall;
|
||
|
{$EXTERNALSYM DownlevelGetStringScripts_LPFN}
|
||
|
DownlevelGetStringScripts_LPFN = function (
|
||
|
dwFlags : DWORD; // optional behavior flags
|
||
|
lpString : LPCWSTR; // Unicode character input string
|
||
|
cchString : Integer; // size of input string
|
||
|
lpScripts : LPWSTR; // Script list output string
|
||
|
cchScripts : Integer // size of output string
|
||
|
) : Integer stdcall;
|
||
|
{$EXTERNALSYM DownlevelVerifyScripts_LPFN}
|
||
|
DownlevelVerifyScripts_LPFN = function (
|
||
|
dwFlags : DWORD; // optional behavior flags
|
||
|
lpLocaleScripts : LPCWSTR; // Locale list of scripts string
|
||
|
cchLocaleScripts : Integer; // size of locale script list string
|
||
|
lpTestScripts : LPCWSTR; // test scripts string
|
||
|
cchTestScripts : Integer // size of test list string
|
||
|
) : BOOL stdcall;
|
||
|
|
||
|
// Normalization.h
|
||
|
// Copyright 2002 Microsoft
|
||
|
//
|
||
|
// Excerpted from LH winnls.h
|
||
|
type
|
||
|
{$EXTERNALSYM NORM_FORM}
|
||
|
NORM_FORM = DWORD;
|
||
|
|
||
|
const
|
||
|
{$EXTERNALSYM NormalizationOther}
|
||
|
NormalizationOther = 0; // Not supported
|
||
|
{$EXTERNALSYM NormalizationC}
|
||
|
NormalizationC = $1; // Each base plus combining characters to the canonical precomposed equivalent.
|
||
|
{$EXTERNALSYM NormalizationD}
|
||
|
NormalizationD = $2; // Each precomposed character to its canonical decomposed equivalent.
|
||
|
{$EXTERNALSYM NormalizationKC}
|
||
|
NormalizationKC = $5; // Each base plus combining characters to the canonical precomposed
|
||
|
// equivalents and all compatibility characters to their equivalents.
|
||
|
{$EXTERNALSYM NormalizationKD}
|
||
|
NormalizationKD = $6; // Each precomposed character to its canonical decomposed equivalent
|
||
|
// and all compatibility characters to their equivalents.
|
||
|
|
||
|
//
|
||
|
// IDN (International Domain Name) Flags
|
||
|
//
|
||
|
const
|
||
|
{$EXTERNALSYM IDN_ALLOW_UNASSIGNED}
|
||
|
IDN_ALLOW_UNASSIGNED = $01; // Allow unassigned "query" behavior per RFC 3454
|
||
|
{$EXTERNALSYM IDN_USE_STD3_ASCII_RULES}
|
||
|
IDN_USE_STD3_ASCII_RULES = $02; // Enforce STD3 ASCII restrictions for legal characters
|
||
|
|
||
|
type
|
||
|
//
|
||
|
// Windows API Normalization Functions
|
||
|
//
|
||
|
{$EXTERNALSYM NormalizeString_LPFN}
|
||
|
NormalizeString_LPFN = function ( NormForm : NORM_FORM;
|
||
|
lpString : LPCWSTR; cwLength : Integer) : DWORD stdcall;
|
||
|
{$EXTERNALSYM IsNormalizedString_LPFN}
|
||
|
IsNormalizedString_LPFN = function ( NormForm : NORM_FORM;
|
||
|
lpString : LPCWSTR; cwLength : Integer ) : BOOL stdcall;
|
||
|
//
|
||
|
// IDN (International Domain Name) Functions
|
||
|
//
|
||
|
{$EXTERNALSYM IdnToAscii_LPFN}
|
||
|
IdnToAscii_LPFN = function(dwFlags : DWORD;
|
||
|
lpUnicodeCharStr : LPCWSTR;
|
||
|
cchUnicodeChar : Integer;
|
||
|
lpNameprepCharStr : LPWSTR;
|
||
|
cchNameprepChar : Integer ) : Integer stdcall;
|
||
|
{$EXTERNALSYM IdnToNameprepUnicode_LPFN}
|
||
|
IdnToNameprepUnicode_LPFN = function (dwFlags : DWORd;
|
||
|
lpUnicodeCharStr : LPCWSTR;
|
||
|
cchUnicodeChar : Integer;
|
||
|
lpASCIICharStr : LPWSTR;
|
||
|
cchASCIIChar : Integer) : Integer stdcall;
|
||
|
{$EXTERNALSYM IdnToUnicode_LPFN}
|
||
|
IdnToUnicode_LPFN = function (dwFlags : DWORD;
|
||
|
lpASCIICharSt : LPCWSTR;
|
||
|
cchASCIIChar : Integer;
|
||
|
lpUnicodeCharStr : LPWSTR;
|
||
|
cchUnicodeChar : Integer) : Integer stdcall;
|
||
|
|
||
|
var
|
||
|
{$EXTERNALSYM DownlevelGetLocaleScripts}
|
||
|
DownlevelGetLocaleScripts : DownlevelGetLocaleScripts_LPFN = nil;
|
||
|
{$EXTERNALSYM DownlevelGetStringScripts}
|
||
|
DownlevelGetStringScripts : DownlevelGetStringScripts_LPFN = nil;
|
||
|
{$EXTERNALSYM DownlevelVerifyScripts}
|
||
|
DownlevelVerifyScripts : DownlevelVerifyScripts_LPFN = nil;
|
||
|
|
||
|
{$EXTERNALSYM IsNormalizedString}
|
||
|
IsNormalizedString : IsNormalizedString_LPFN = nil;
|
||
|
{$EXTERNALSYM NormalizeString}
|
||
|
NormalizeString : NormalizeString_LPFN = nil;
|
||
|
{$EXTERNALSYM IdnToUnicode}
|
||
|
IdnToUnicode : IdnToUnicode_LPFN = nil;
|
||
|
{$EXTERNALSYM IdnToNameprepUnicode}
|
||
|
IdnToNameprepUnicode : IdnToNameprepUnicode_LPFN = nil;
|
||
|
{$EXTERNALSYM IdnToAscii}
|
||
|
IdnToAscii : IdnToAscii_LPFN = nil;
|
||
|
|
||
|
const
|
||
|
LibNDL = 'IdnDL.dll';
|
||
|
LibNormaliz = 'Normaliz.dll';
|
||
|
|
||
|
fn_DownlevelGetLocaleScripts = 'DownlevelGetLocaleScripts';
|
||
|
fn_DownlevelGetStringScripts = 'DownlevelGetStringScripts';
|
||
|
fn_DownlevelVerifyScripts = 'DownlevelVerifyScripts';
|
||
|
|
||
|
fn_IsNormalizedString = 'IsNormalizedString';
|
||
|
fn_NormalizeString = 'NormalizeString';
|
||
|
fn_IdnToUnicode = 'IdnToUnicode';
|
||
|
fn_IdnToNameprepUnicode = 'IdnToNameprepUnicode';
|
||
|
fn_IdnToAscii = 'IdnToAscii';
|
||
|
|
||
|
{$ENDIF} // {$IFDEF WIN32_OR_WIN64}
|
||
|
|
||
|
function UseIDNAPI : Boolean;
|
||
|
function IDNToPunnyCode(const AIDN : TIdUnicodeString) : String;
|
||
|
function PunnyCodeToIDN(const APunnyCode : String) : TIdUnicodeString;
|
||
|
|
||
|
procedure InitIDNLibrary;
|
||
|
procedure CloseIDNLibrary;
|
||
|
|
||
|
implementation
|
||
|
|
||
|
{$IFDEF WIN32_OR_WIN64}
|
||
|
|
||
|
uses
|
||
|
SysUtils;
|
||
|
|
||
|
var
|
||
|
hIdnDL : THandle = 0;
|
||
|
hNormaliz : THandle = 0;
|
||
|
|
||
|
function UseIDNAPI : Boolean;
|
||
|
begin
|
||
|
Result := not IndyCheckWindowsVersion(6, 2);
|
||
|
if Result then begin
|
||
|
Result := Assigned( IdnToAscii ) and Assigned( IdnToUnicode );
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function PunnyCodeToIDN(const APunnyCode : String) : TIdUnicodeString;
|
||
|
var
|
||
|
{$IFNDEF STRING_IS_UNICODE}
|
||
|
LTemp: TIdUnicodeString;
|
||
|
{$ENDIF}
|
||
|
LIDN : TIdUnicodeString;
|
||
|
Len : Integer;
|
||
|
begin
|
||
|
Result := '';
|
||
|
if Assigned(IdnToUnicode) then
|
||
|
begin
|
||
|
{$IFNDEF STRING_IS_UNICODE}
|
||
|
LTemp := TIdUnicodeString(APunnyCode); // explicit convert to Unicode
|
||
|
{$ENDIF}
|
||
|
Len := IdnToUnicode(0,
|
||
|
{$IFDEF STRING_IS_UNICODE}
|
||
|
PIdWideChar(APunnyCode), Length(APunnyCode)
|
||
|
{$ELSE}
|
||
|
PIdWideChar(LTemp), Length(LTemp)
|
||
|
{$ENDIF},
|
||
|
nil, 0);
|
||
|
if Len = 0 then begin
|
||
|
IndyRaiseLastError;
|
||
|
end;
|
||
|
SetLength(LIDN, Len);
|
||
|
Len := IdnToUnicode(0,
|
||
|
{$IFDEF STRING_IS_UNICODE}
|
||
|
PIdWideChar(APunnyCode), Length(APunnyCode)
|
||
|
{$ELSE}
|
||
|
PIdWideChar(LTemp), Length(LTemp)
|
||
|
{$ENDIF},
|
||
|
PIdWideChar(LIDN), Len);
|
||
|
if Len = 0 then begin
|
||
|
IndyRaiseLastError;
|
||
|
end;
|
||
|
Result := LIDN;
|
||
|
end else begin
|
||
|
// TODO: manual implementation here ...
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function IDNToPunnyCode(const AIDN : TIdUnicodeString) : String;
|
||
|
var
|
||
|
LPunnyCode : TIdUnicodeString;
|
||
|
Len : Integer;
|
||
|
begin
|
||
|
Result := '';
|
||
|
if Assigned(IdnToAscii) then
|
||
|
begin
|
||
|
Len := IdnToAscii(0, PIdWideChar(AIDN), Length(AIDN), nil, 0);
|
||
|
if Len = 0 then begin
|
||
|
IndyRaiseLastError;
|
||
|
end;
|
||
|
SetLength(LPunnyCode, Len);
|
||
|
Len := IdnToAscii(0, PIdWideChar(AIDN), Length(AIDN), PIdWideChar(LPunnyCode), Len);
|
||
|
if Len = 0 then begin
|
||
|
IndyRaiseLastError;
|
||
|
end;
|
||
|
{$IFDEF STRING_IS_ANSI}
|
||
|
Result := AnsiString(LPunnyCode); // explicit convert to Ansi (no data loss because content is ASCII)
|
||
|
{$ELSE}
|
||
|
Result := LPunnyCode;
|
||
|
{$ENDIF}
|
||
|
end else
|
||
|
begin
|
||
|
// TODO: manual implementation here ...
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure InitIDNLibrary;
|
||
|
begin
|
||
|
if hIdnDL = 0 then
|
||
|
begin
|
||
|
hIdnDL := SafeLoadLibrary(LibNDL);
|
||
|
if hIdnDL <> 0 then
|
||
|
begin
|
||
|
DownlevelGetLocaleScripts := GetProcAddress(hIdnDL, fn_DownlevelGetLocaleScripts);
|
||
|
DownlevelGetStringScripts := GetProcAddress(hIdnDL, fn_DownlevelGetStringScripts);
|
||
|
DownlevelVerifyScripts := GetProcAddress(hIdnDL, fn_DownlevelVerifyScripts);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if hNormaliz = 0 then
|
||
|
begin
|
||
|
hNormaliz := SafeLoadLibrary(LibNormaliz);
|
||
|
if hNormaliz <> 0 then
|
||
|
begin
|
||
|
IdnToUnicode := GetProcAddress(hNormaliz, fn_IdnToUnicode);
|
||
|
IdnToNameprepUnicode := GetProcAddress(hNormaliz, fn_IdnToNameprepUnicode);
|
||
|
IdnToAscii := GetProcAddress(hNormaliz, fn_IdnToAscii);
|
||
|
IsNormalizedString := GetProcAddress(hNormaliz,fn_IsNormalizedString);
|
||
|
NormalizeString := GetProcAddress(hNormaliz, fn_NormalizeString);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure CloseIDNLibrary;
|
||
|
var
|
||
|
h : THandle;
|
||
|
begin
|
||
|
h := InterlockedExchangeTHandle(hIdnDL, 0);
|
||
|
if h <> 0 then begin
|
||
|
FreeLibrary(h);
|
||
|
end;
|
||
|
|
||
|
h := InterlockedExchangeTHandle(hNormaliz, 0);
|
||
|
if h <> 0 then begin
|
||
|
FreeLibrary(h);
|
||
|
end;
|
||
|
|
||
|
IsNormalizedString := nil;
|
||
|
NormalizeString := nil;
|
||
|
|
||
|
IdnToUnicode := nil;
|
||
|
IdnToNameprepUnicode := nil;
|
||
|
IdnToAscii := nil;
|
||
|
end;
|
||
|
|
||
|
{$ELSE}
|
||
|
|
||
|
function UseIDNAPI : Boolean;
|
||
|
begin
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
function IDNToPunnyCode(const AIDN : TIdUnicodeString) : String;
|
||
|
begin
|
||
|
Todo('IDNToPunnyCode() is not implemented for this platform');
|
||
|
end;
|
||
|
|
||
|
function PunnyCodeToIDN(const APunnyCode : String) : TIdUnicodeString;
|
||
|
begin
|
||
|
Todo('PunnyCodeToIDN() is not implemented for this platform');
|
||
|
end;
|
||
|
|
||
|
procedure InitIDNLibrary;
|
||
|
begin
|
||
|
end;
|
||
|
|
||
|
procedure CloseIDNLibrary;
|
||
|
begin
|
||
|
end;
|
||
|
|
||
|
{$ENDIF} // {$IFDEF WIN32_OR_WIN64}
|
||
|
|
||
|
initialization
|
||
|
finalization
|
||
|
CloseIDNLibrary;
|
||
|
|
||
|
end.
|