IdIDN.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. unit IdIDN;
  2. {
  3. This file is part of the Indy (Internet Direct) project, and is offered
  4. under the dual-licensing agreement described on the Indy website.
  5. (http://www.indyproject.org/)
  6. Copyright:
  7. (c) 1993-2012, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  8. Original Author: J. Peter Mugaas
  9. This file uses the "Windows Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1"
  10. There is a download for some Windows versions at:
  11. http://www.microsoft.com/en-us/download/details.aspx?id=734
  12. for Windows XP and that SDK includes a package of run-time libraries that might
  13. need to be redistributed to Windows XP users.
  14. On some later Windows versions, this is redistributable is not needed.
  15. For Windows 8, we do not use this.
  16. From: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
  17. "On Windows 8 Consumer Preview and Windows Server "8" Beta, the getaddrinfo
  18. function provides support for IRI or Internationalized Domain Name (IDN) parsing
  19. applied to the name passed in the pNodeName parameter. Winsock performs
  20. Punycode/IDN encoding and conversion. This behavior can be disabled using the
  21. AI_DISABLE_IDN_ENCODING flag discussed below.
  22. }
  23. interface
  24. {$I IdCompilerDefines.inc}
  25. uses
  26. IdGlobal
  27. {$IFDEF WIN32_OR_WIN64}
  28. , Windows
  29. {$ENDIF}
  30. ;
  31. {$IFDEF WIN32_OR_WIN64}
  32. {
  33. }
  34. // ==++==
  35. //
  36. // Copyright (c) Microsoft Corporation. All Rights Reserved
  37. //
  38. // ==++==
  39. // IdnDl.h
  40. //
  41. // WARNING: This .DLL is downlevel only.
  42. //
  43. // This file contains the downlevel versions of the scripts APIs
  44. //
  45. // 06 Jun 2005 Shawn Steele Initial Implementation
  46. const
  47. {$EXTERNALSYM VS_ALLOW_LATIN}
  48. VS_ALLOW_LATIN = $0001;
  49. {$EXTERNALSYM GSS_ALLOW_INHERITED_COMMON}
  50. GSS_ALLOW_INHERITED_COMMON = $0001;
  51. type
  52. {$EXTERNALSYM DownlevelGetLocaleScripts_LPFN}
  53. DownlevelGetLocaleScripts_LPFN = function (
  54. lpLocaleName : LPCWSTR; // Locale Name
  55. lpScripts : LPWSTR; // Output buffer for scripts
  56. cchScripts : Integer // size of output buffer
  57. ) : Integer stdcall;
  58. {$EXTERNALSYM DownlevelGetStringScripts_LPFN}
  59. DownlevelGetStringScripts_LPFN = function (
  60. dwFlags : DWORD; // optional behavior flags
  61. lpString : LPCWSTR; // Unicode character input string
  62. cchString : Integer; // size of input string
  63. lpScripts : LPWSTR; // Script list output string
  64. cchScripts : Integer // size of output string
  65. ) : Integer stdcall;
  66. {$EXTERNALSYM DownlevelVerifyScripts_LPFN}
  67. DownlevelVerifyScripts_LPFN = function (
  68. dwFlags : DWORD; // optional behavior flags
  69. lpLocaleScripts : LPCWSTR; // Locale list of scripts string
  70. cchLocaleScripts : Integer; // size of locale script list string
  71. lpTestScripts : LPCWSTR; // test scripts string
  72. cchTestScripts : Integer // size of test list string
  73. ) : BOOL stdcall;
  74. // Normalization.h
  75. // Copyright 2002 Microsoft
  76. //
  77. // Excerpted from LH winnls.h
  78. type
  79. {$EXTERNALSYM NORM_FORM}
  80. NORM_FORM = DWORD;
  81. const
  82. {$EXTERNALSYM NormalizationOther}
  83. NormalizationOther = 0; // Not supported
  84. {$EXTERNALSYM NormalizationC}
  85. NormalizationC = $1; // Each base plus combining characters to the canonical precomposed equivalent.
  86. {$EXTERNALSYM NormalizationD}
  87. NormalizationD = $2; // Each precomposed character to its canonical decomposed equivalent.
  88. {$EXTERNALSYM NormalizationKC}
  89. NormalizationKC = $5; // Each base plus combining characters to the canonical precomposed
  90. // equivalents and all compatibility characters to their equivalents.
  91. {$EXTERNALSYM NormalizationKD}
  92. NormalizationKD = $6; // Each precomposed character to its canonical decomposed equivalent
  93. // and all compatibility characters to their equivalents.
  94. //
  95. // IDN (International Domain Name) Flags
  96. //
  97. const
  98. {$EXTERNALSYM IDN_ALLOW_UNASSIGNED}
  99. IDN_ALLOW_UNASSIGNED = $01; // Allow unassigned "query" behavior per RFC 3454
  100. {$EXTERNALSYM IDN_USE_STD3_ASCII_RULES}
  101. IDN_USE_STD3_ASCII_RULES = $02; // Enforce STD3 ASCII restrictions for legal characters
  102. type
  103. //
  104. // Windows API Normalization Functions
  105. //
  106. {$EXTERNALSYM NormalizeString_LPFN}
  107. NormalizeString_LPFN = function ( NormForm : NORM_FORM;
  108. lpString : LPCWSTR; cwLength : Integer) : DWORD stdcall;
  109. {$EXTERNALSYM IsNormalizedString_LPFN}
  110. IsNormalizedString_LPFN = function ( NormForm : NORM_FORM;
  111. lpString : LPCWSTR; cwLength : Integer ) : BOOL stdcall;
  112. //
  113. // IDN (International Domain Name) Functions
  114. //
  115. {$EXTERNALSYM IdnToAscii_LPFN}
  116. IdnToAscii_LPFN = function(dwFlags : DWORD;
  117. lpUnicodeCharStr : LPCWSTR;
  118. cchUnicodeChar : Integer;
  119. lpNameprepCharStr : LPWSTR;
  120. cchNameprepChar : Integer ) : Integer stdcall;
  121. {$EXTERNALSYM IdnToNameprepUnicode_LPFN}
  122. IdnToNameprepUnicode_LPFN = function (dwFlags : DWORd;
  123. lpUnicodeCharStr : LPCWSTR;
  124. cchUnicodeChar : Integer;
  125. lpASCIICharStr : LPWSTR;
  126. cchASCIIChar : Integer) : Integer stdcall;
  127. {$EXTERNALSYM IdnToUnicode_LPFN}
  128. IdnToUnicode_LPFN = function (dwFlags : DWORD;
  129. lpASCIICharSt : LPCWSTR;
  130. cchASCIIChar : Integer;
  131. lpUnicodeCharStr : LPWSTR;
  132. cchUnicodeChar : Integer) : Integer stdcall;
  133. var
  134. {$EXTERNALSYM DownlevelGetLocaleScripts}
  135. DownlevelGetLocaleScripts : DownlevelGetLocaleScripts_LPFN = nil;
  136. {$EXTERNALSYM DownlevelGetStringScripts}
  137. DownlevelGetStringScripts : DownlevelGetStringScripts_LPFN = nil;
  138. {$EXTERNALSYM DownlevelVerifyScripts}
  139. DownlevelVerifyScripts : DownlevelVerifyScripts_LPFN = nil;
  140. {$EXTERNALSYM IsNormalizedString}
  141. IsNormalizedString : IsNormalizedString_LPFN = nil;
  142. {$EXTERNALSYM NormalizeString}
  143. NormalizeString : NormalizeString_LPFN = nil;
  144. {$EXTERNALSYM IdnToUnicode}
  145. IdnToUnicode : IdnToUnicode_LPFN = nil;
  146. {$EXTERNALSYM IdnToNameprepUnicode}
  147. IdnToNameprepUnicode : IdnToNameprepUnicode_LPFN = nil;
  148. {$EXTERNALSYM IdnToAscii}
  149. IdnToAscii : IdnToAscii_LPFN = nil;
  150. const
  151. LibNDL = 'IdnDL.dll';
  152. LibNormaliz = 'Normaliz.dll';
  153. fn_DownlevelGetLocaleScripts = 'DownlevelGetLocaleScripts';
  154. fn_DownlevelGetStringScripts = 'DownlevelGetStringScripts';
  155. fn_DownlevelVerifyScripts = 'DownlevelVerifyScripts';
  156. fn_IsNormalizedString = 'IsNormalizedString';
  157. fn_NormalizeString = 'NormalizeString';
  158. fn_IdnToUnicode = 'IdnToUnicode';
  159. fn_IdnToNameprepUnicode = 'IdnToNameprepUnicode';
  160. fn_IdnToAscii = 'IdnToAscii';
  161. {$ENDIF} // {$IFDEF WIN32_OR_WIN64}
  162. function UseIDNAPI : Boolean;
  163. function IDNToPunnyCode(const AIDN : TIdUnicodeString) : String;
  164. function PunnyCodeToIDN(const APunnyCode : String) : TIdUnicodeString;
  165. procedure InitIDNLibrary;
  166. procedure CloseIDNLibrary;
  167. implementation
  168. {$IFDEF WIN32_OR_WIN64}
  169. uses
  170. SysUtils;
  171. var
  172. hIdnDL : TIdLibHandle = IdNilHandle;
  173. hNormaliz : TIdLibHandle = IdNilHandle;
  174. function UseIDNAPI : Boolean;
  175. begin
  176. Result := not IndyCheckWindowsVersion(6, 2);
  177. if Result then begin
  178. Result := Assigned( IdnToAscii ) and Assigned( IdnToUnicode );
  179. end;
  180. end;
  181. function PunnyCodeToIDN(const APunnyCode : String) : TIdUnicodeString;
  182. var
  183. {$IFNDEF STRING_IS_UNICODE}
  184. LTemp: TIdUnicodeString;
  185. {$ENDIF}
  186. LIDN : TIdUnicodeString;
  187. Len : Integer;
  188. begin
  189. Result := '';
  190. if Assigned(IdnToUnicode) then
  191. begin
  192. {$IFNDEF STRING_IS_UNICODE}
  193. LTemp := TIdUnicodeString(APunnyCode); // explicit convert to Unicode
  194. {$ENDIF}
  195. Len := IdnToUnicode(0,
  196. {$IFDEF STRING_IS_UNICODE}
  197. PIdWideChar(APunnyCode), Length(APunnyCode)
  198. {$ELSE}
  199. PIdWideChar(LTemp), Length(LTemp)
  200. {$ENDIF},
  201. nil, 0);
  202. if Len = 0 then begin
  203. IndyRaiseLastError;
  204. end;
  205. SetLength(LIDN, Len);
  206. Len := IdnToUnicode(0,
  207. {$IFDEF STRING_IS_UNICODE}
  208. PIdWideChar(APunnyCode), Length(APunnyCode)
  209. {$ELSE}
  210. PIdWideChar(LTemp), Length(LTemp)
  211. {$ENDIF},
  212. PIdWideChar(LIDN), Len);
  213. if Len = 0 then begin
  214. IndyRaiseLastError;
  215. end;
  216. Result := LIDN;
  217. end else begin
  218. // TODO: manual implementation here ...
  219. end;
  220. end;
  221. function IDNToPunnyCode(const AIDN : TIdUnicodeString) : String;
  222. var
  223. LPunnyCode : TIdUnicodeString;
  224. Len : Integer;
  225. begin
  226. Result := '';
  227. if Assigned(IdnToAscii) then
  228. begin
  229. Len := IdnToAscii(0, PIdWideChar(AIDN), Length(AIDN), nil, 0);
  230. if Len = 0 then begin
  231. IndyRaiseLastError;
  232. end;
  233. SetLength(LPunnyCode, Len);
  234. Len := IdnToAscii(0, PIdWideChar(AIDN), Length(AIDN), PIdWideChar(LPunnyCode), Len);
  235. if Len = 0 then begin
  236. IndyRaiseLastError;
  237. end;
  238. {$IFDEF STRING_IS_ANSI}
  239. Result := AnsiString(LPunnyCode); // explicit convert to Ansi (no data loss because content is ASCII)
  240. {$ELSE}
  241. Result := LPunnyCode;
  242. {$ENDIF}
  243. end else
  244. begin
  245. // TODO: manual implementation here ...
  246. end;
  247. end;
  248. procedure InitIDNLibrary;
  249. begin
  250. if hIdnDL = IdNilHandle then
  251. begin
  252. hIdnDL := SafeLoadLibrary(LibNDL);
  253. if hIdnDL <> IdNilHandle then
  254. begin
  255. DownlevelGetLocaleScripts := LoadLibFunction(hIdnDL, fn_DownlevelGetLocaleScripts);
  256. DownlevelGetStringScripts := LoadLibFunction(hIdnDL, fn_DownlevelGetStringScripts);
  257. DownlevelVerifyScripts := LoadLibFunction(hIdnDL, fn_DownlevelVerifyScripts);
  258. end;
  259. end;
  260. if hNormaliz = IdNilHandle then
  261. begin
  262. hNormaliz := SafeLoadLibrary(LibNormaliz);
  263. if hNormaliz <> IdNilHandle then
  264. begin
  265. IdnToUnicode := LoadLibFunction(hNormaliz, fn_IdnToUnicode);
  266. IdnToNameprepUnicode := LoadLibFunction(hNormaliz, fn_IdnToNameprepUnicode);
  267. IdnToAscii := LoadLibFunction(hNormaliz, fn_IdnToAscii);
  268. IsNormalizedString := LoadLibFunction(hNormaliz,fn_IsNormalizedString);
  269. NormalizeString := LoadLibFunction(hNormaliz, fn_NormalizeString);
  270. end;
  271. end;
  272. end;
  273. procedure CloseIDNLibrary;
  274. var
  275. h : TIdLibHandle;
  276. begin
  277. h := InterlockedExchangeTLibHandle(hIdnDL, IdNilHandle);
  278. if h <> IdNilHandle then begin
  279. FreeLibrary(h);
  280. end;
  281. h := InterlockedExchangeTLibHandle(hNormaliz, IdNilHandle);
  282. if h <> IdNilHandle then begin
  283. FreeLibrary(h);
  284. end;
  285. IsNormalizedString := nil;
  286. NormalizeString := nil;
  287. IdnToUnicode := nil;
  288. IdnToNameprepUnicode := nil;
  289. IdnToAscii := nil;
  290. end;
  291. {$ELSE}
  292. function UseIDNAPI : Boolean;
  293. begin
  294. Result := False;
  295. end;
  296. function IDNToPunnyCode(const AIDN : TIdUnicodeString) : String;
  297. begin
  298. Todo('IDNToPunnyCode() is not implemented for this platform');
  299. end;
  300. function PunnyCodeToIDN(const APunnyCode : String) : TIdUnicodeString;
  301. begin
  302. Todo('PunnyCodeToIDN() is not implemented for this platform');
  303. end;
  304. procedure InitIDNLibrary;
  305. begin
  306. end;
  307. procedure CloseIDNLibrary;
  308. begin
  309. end;
  310. {$ENDIF} // {$IFDEF WIN32_OR_WIN64}
  311. initialization
  312. finalization
  313. CloseIDNLibrary;
  314. end.