IdIconv.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. unit IdIconv;
  2. interface
  3. {$I IdCompilerDefines.inc}
  4. uses
  5. {$IFDEF FPC}
  6. DynLibs,
  7. {$ENDIF}
  8. IdCTypes,
  9. IdException
  10. {$IFDEF USE_BASEUNIX}
  11. ,UnixType
  12. {$ENDIF}
  13. {$IFDEF WINDOWS}
  14. ,Windows
  15. {$ENDIF}
  16. ;
  17. {.$DEFINE STATICLOAD_ICONV}
  18. //These should be defined in libc.pas.
  19. type
  20. {$IFDEF WINDOWS}
  21. {$EXTERNALSYM SIZE_T}
  22. {$IFDEF CPU64}
  23. size_t = QWord;
  24. {$ELSE}
  25. size_t = DWord;
  26. {$ENDIF}
  27. Psize_t = ^size_t;
  28. {$ENDIF}
  29. Piconv_t = ^iconv_t;
  30. iconv_t = Pointer;
  31. {$IFNDEF STATICLOAD_ICONV}
  32. // This function is a possible cancellation points and therefore not
  33. // marked with __THROW. */
  34. //extern iconv_t iconv_open (__const char *__tocode, __const char *__fromcode);
  35. TIdiconv_open = function (__tocode : PAnsiChar; __fromcode : PAnsiChar) : iconv_t; cdecl;
  36. ///* Convert at most *INBYTESLEFT bytes from *INBUF according to the
  37. // code conversion algorithm specified by CD and place up to
  38. // *OUTBYTESLEFT bytes in buffer at *OUTBUF. */
  39. //extern size_t iconv (iconv_t __cd, char **__restrict __inbuf,
  40. // size_t *__restrict __inbytesleft,
  41. // char **__restrict __outbuf,
  42. // size_t *__restrict __outbytesleft);
  43. TIdiconv = function (__cd : iconv_t; __inbuf : PPAnsiChar;
  44. __inbytesleft : Psize_t;
  45. __outbuf : PPAnsiChar;
  46. __outbytesleft : Psize_t ) : size_t; cdecl;
  47. // This function is a possible cancellation points and therefore not
  48. // marked with __THROW. */
  49. //extern int iconv_close (iconv_t __cd);
  50. TIdiconv_close = function (__cd : iconv_t) : TIdC_INT; cdecl;
  51. type
  52. EIdIconvStubError = class(EIdException)
  53. protected
  54. FError : LongWord;
  55. FErrorMessage : String;
  56. FTitle : String;
  57. public
  58. constructor Build(const ATitle : String; AError : LongWord);
  59. property Error : LongWord read FError;
  60. property ErrorMessage : String read FErrorMessage;
  61. property Title : String read FTitle;
  62. end;
  63. var
  64. iconv_open : TIdiconv_open = nil;
  65. iconv : TIdiconv = nil;
  66. iconv_close : TIdiconv_close = nil;
  67. {$ENDIF}
  68. {$IFDEF WIN32_OR_WIN64}
  69. //errno.h constants that are needed for this and possibly other API's.
  70. //It's here only because it seems to be the most sensible place to put it.
  71. //These are defined in other operating systems.
  72. const
  73. {$EXTERNALSYM EPERM}
  74. EPERM = 1;
  75. {$EXTERNALSYM ENOENT}
  76. ENOENT = 2;
  77. {$EXTERNALSYM ESRCH}
  78. ESRCH = 3;
  79. {$EXTERNALSYM EINTR}
  80. EINTR = 4;
  81. {$EXTERNALSYM EIO}
  82. EIO = 5;
  83. {$EXTERNALSYM ENXIO}
  84. ENXIO = 6;
  85. {$EXTERNALSYM E2BIG}
  86. E2BIG = 7;
  87. {$EXTERNALSYM ENOEXEC}
  88. ENOEXEC = 8;
  89. {$EXTERNALSYM EBADF}
  90. EBADF = 9;
  91. {$EXTERNALSYM ECHILD}
  92. ECHILD = 10;
  93. {$EXTERNALSYM EAGAIN}
  94. EAGAIN = 11;
  95. {$EXTERNALSYM ENOMEM}
  96. ENOMEM = 12;
  97. {$EXTERNALSYM EACCES}
  98. EACCES = 13;
  99. {$EXTERNALSYM EFAULT}
  100. EFAULT = 14;
  101. {$EXTERNALSYM EBUSY}
  102. EBUSY = 16;
  103. {$EXTERNALSYM EEXIST}
  104. EEXIST = 17;
  105. {$EXTERNALSYM EXDEV}
  106. EXDEV = 18;
  107. {$EXTERNALSYM ENODEV}
  108. ENODEV = 19;
  109. {$EXTERNALSYM ENOTDIR}
  110. ENOTDIR = 20;
  111. {$EXTERNALSYM EISDIR}
  112. EISDIR = 21;
  113. {$EXTERNALSYM EINVAL}
  114. EINVAL = 22;
  115. {$EXTERNALSYM ENFILE}
  116. ENFILE = 23;
  117. {$EXTERNALSYM EMFILE}
  118. EMFILE = 24;
  119. {$EXTERNALSYM ENOTTY}
  120. ENOTTY = 25;
  121. {$EXTERNALSYM EFBIG}
  122. EFBIG = 27;
  123. {$EXTERNALSYM ENOSPC}
  124. ENOSPC = 28;
  125. {$EXTERNALSYM ESPIPE}
  126. ESPIPE = 29;
  127. {$EXTERNALSYM EROFS}
  128. EROFS = 30;
  129. {$EXTERNALSYM EMLINK}
  130. EMLINK = 31;
  131. {$EXTERNALSYM EPIPE}
  132. EPIPE = 32;
  133. {$EXTERNALSYM EDOM}
  134. EDOM = 33;
  135. {$EXTERNALSYM ERANGE}
  136. ERANGE = 34;
  137. {$EXTERNALSYM EDEADLK}
  138. EDEADLK = 36;
  139. {$EXTERNALSYM ENAMETOOLONG}
  140. ENAMETOOLONG = 38;
  141. {$EXTERNALSYM ENOLCK}
  142. ENOLCK = 39;
  143. {$EXTERNALSYM ENOSYS}
  144. ENOSYS = 40;
  145. {$EXTERNALSYM ENOTEMPTY}
  146. ENOTEMPTY = 41;
  147. {$EXTERNALSYM EILSEQ}
  148. EILSEQ = 42;
  149. type
  150. EIdMSVCRTStubError = class(EIdException)
  151. protected
  152. FError : TIdC_INT;
  153. FErrorMessage : String;
  154. FTitle : String;
  155. public
  156. constructor Build(const ATitle : String; AError : TIdC_INT);
  157. property Error : TIdC_INT read FError;
  158. property ErrorMessage : String read FErrorMessage;
  159. property Title : String read FTitle;
  160. end;
  161. {$ENDIF}
  162. const
  163. FN_ICONV_OPEN = 'iconv_open'; {Do not localize}
  164. FN_ICONV = 'iconv'; {Do not localize}
  165. FN_ICONV_CLOSE = 'iconv_close'; {Do not localize}
  166. {$IFDEF UNIX}
  167. LIBC = 'libc.so.6'; {Do not localize}
  168. LICONV = 'libiconv.so'; {Do not localize}
  169. {$ELSE}
  170. // TODO: support static linking, such as via the "win_iconv" library
  171. {$IFDEF WINDOWS}
  172. //http://yukihiro.nakadaira.googlepages.com/ seems to use the iconv.dll name.
  173. LICONV = 'iconv.dll'; {Do not localize}
  174. LICONV_ALT = 'libiconv.dll'; {Do not localize}
  175. LIBMSVCRTL = 'msvcrt.dll'; {Do not localize}
  176. {$ENDIF}
  177. {$ENDIF}
  178. function Load : Boolean;
  179. procedure Unload;
  180. function Loaded : Boolean;
  181. {$IFDEF STATICLOAD_ICONV}
  182. function iconv_open(__tocode : PAnsiChar; __fromcode : PAnsiChar) : iconv_t; cdecl;
  183. external LICONV name FN_ICONV_OPEN;
  184. function iconv(__cd : iconv_t; __inbuf : PPAnsiChar;
  185. __inbytesleft : Psize_t;
  186. __outbuf : PPAnsiChar;
  187. __outbytesleft : Psize_t ) : size_t; cdecl;
  188. external LICONV name FN_ICONV;
  189. function iconv_close(__cd : iconv_t) : TIdC_INT; cdecl;
  190. external LICONV name FN_ICONV_CLOSE;
  191. {$ENDIF}
  192. {
  193. From http://gettext.sourceforge.net/
  194. Dynamic linking to iconv
  195. Note that the iconv function call in libiconv stores its error, if it fails,
  196. in the stdc library's errno. iconv.dll links to msvcrt.dll, and stores the error
  197. in its exported errno symbol (this is actually a memory location with an
  198. exported accessor function). If your code does not link against msvcrt.dll, you
  199. may wish to import this accessor function specifically to get iconv failure
  200. codes. This is particularly important for Visual C++ projects, which are likely
  201. to link to msvcrtd.dll in Debug configuration, rather than msvcrt.dll. I have
  202. written a C++ wrapper for iconv use, which does this, and I will be adding it to
  203. WinMerge (on sourceforge) shortly.
  204. }
  205. {$IFDEF WIN32_OR_WIN64}
  206. var
  207. errno : function : PIdC_INT; cdecl;
  208. function errnoStr(const AErrNo : TIdC_INT) : String;
  209. {$ENDIF}
  210. implementation
  211. {$IFNDEF STATICLOAD_ICONV}
  212. uses
  213. IdResourceStrings, SysUtils;
  214. var
  215. hIconv: THandle = 0;
  216. {$ENDIF}
  217. {$IFDEF WIN32_OR_WIN64}
  218. var
  219. hmsvcrt : THandle = 0;
  220. function Stub_errno : PIdC_INT; cdecl; forward;
  221. {$ENDIF}
  222. {$IFNDEF STATICLOAD_ICONV}
  223. constructor EIdIconvStubError.Build(const ATitle : String; AError : LongWord);
  224. begin
  225. FTitle := ATitle;
  226. FError := AError;
  227. if AError = 0 then begin
  228. inherited Create(ATitle);
  229. end else
  230. begin
  231. FErrorMessage := SysUtils.SysErrorMessage(AError);
  232. inherited Create(ATitle + ': ' + FErrorMessage); {Do not Localize}
  233. end;
  234. end;
  235. function Fixup(const AName: string): Pointer;
  236. begin
  237. if hIconv = 0 then begin
  238. if not Load then begin
  239. raise EIdIconvStubError.Build(Format(RSIconvCallError, [AName]), 0);
  240. end;
  241. end;
  242. Result := GetProcAddress(hIconv, PChar(AName));
  243. {
  244. IMPORTANT!!!
  245. GNU libiconv for Win32 might be compiled with the LIBICONV_PLUG define.
  246. If that's the case, we will have to load the functions with a "lib" prefix.
  247. IOW, CYA!!!
  248. }
  249. if Result = nil then begin
  250. Result := GetProcAddress(hIconv, PChar('lib'+AName));
  251. if Result = nil then begin
  252. raise EIdIconvStubError.Build(Format(RSIconvCallError, [AName]), 10022);
  253. end;
  254. end;
  255. end;
  256. {stubs that automatically load the iconv library and then fixup the functions.}
  257. function Stub_iconv_open(__tocode : PAnsiChar; __fromcode : PAnsiChar) : iconv_t; cdecl;
  258. begin
  259. iconv_open := Fixup(FN_ICONV_OPEN);
  260. Result := iconv_open(__tocode, __fromcode);
  261. end;
  262. function stub_iconv(__cd : iconv_t; __inbuf : PPAnsiChar;
  263. __inbytesleft : Psize_t;
  264. __outbuf : PPAnsiChar;
  265. __outbytesleft : Psize_t ) : size_t; cdecl;
  266. begin
  267. iconv := Fixup(FN_ICONV);
  268. Result := iconv(__cd,__inbuf,__inbytesleft,__outbuf,__outbytesleft);
  269. end;
  270. function stub_iconv_close(__cd : iconv_t) : TIdC_INT; cdecl;
  271. begin
  272. iconv_close := Fixup(FN_ICONV_CLOSE);
  273. Result := iconv_close(__cd);
  274. end;
  275. {end stub sections}
  276. {$ENDIF}
  277. procedure InitializeStubs;
  278. begin
  279. {$IFNDEF STATICLOAD_ICONV}
  280. iconv_open := Stub_iconv_open;
  281. iconv := Stub_iconv;
  282. iconv_close := Stub_iconv_close;
  283. {$ENDIF}
  284. {$IFDEF WIN32_OR_WIN64}
  285. errno := Stub_errno;
  286. {$ENDIF}
  287. end;
  288. function Load : Boolean;
  289. {$IFDEF STATICLOAD_ICONV}
  290. {$IFDEF USE_INLINE} inline; {$ENDIF}
  291. {$ENDIF}
  292. begin
  293. {$IFDEF STATICLOAD_ICONV}
  294. Result := True;
  295. {$ELSE}
  296. if not Loaded then begin
  297. //In Windows, you should use SafeLoadLibrary instead of the LoadLibrary API
  298. //call because LoadLibrary messes with the FPU control word.
  299. {$IFDEF WINDOWS}
  300. hIconv := SafeLoadLibrary(LICONV);
  301. if hIconv = 0 then begin
  302. hIconv := SafeLoadLibrary(LICONV_ALT);
  303. end;
  304. {$ELSE}
  305. {$IFDEF UNIX}
  306. hIconv := LoadLibrary(LICONV);
  307. if hIconv = 0 then begin
  308. hIconv := LoadLibrary(LIBC);
  309. end;
  310. {$ELSE}
  311. hIconv := LoadLibrary(LICONV);
  312. {$ENDIF}
  313. {$ENDIF}
  314. Result := Loaded;
  315. end;
  316. {$ENDIF}
  317. end;
  318. procedure Unload;
  319. {$IFDEF USE_INLINE} inline; {$ENDIF}
  320. begin
  321. {$IFNDEF STATICLOAD_ICONV}
  322. if Loaded then begin
  323. FreeLibrary(hIconv);
  324. hIconv := 0;
  325. end;
  326. {$ENDIF}
  327. {$IFDEF WIN32_OR_WIN64}
  328. if hmsvcrt <> 0 then begin
  329. FreeLibrary(hmsvcrt);
  330. hmsvcrt := 0;
  331. end;
  332. {$ENDIF}
  333. InitializeStubs;
  334. end;
  335. function Loaded : Boolean;
  336. {$IFDEF USE_INLINE} inline; {$ENDIF}
  337. begin
  338. {$IFDEF STATICLOAD_ICONV}
  339. Result := True;
  340. {$ELSE}
  341. Result := (hIconv <> 0);
  342. {$ENDIF}
  343. end;
  344. {$IFDEF WIN32_OR_WIN64}
  345. const
  346. FN_errno = '_errno';
  347. constructor EIdMSVCRTStubError.Build(const ATitle : String; AError : TIdC_INT);
  348. begin
  349. FTitle := ATitle;
  350. FError := AError;
  351. if AError = 0 then begin
  352. inherited Create(ATitle);
  353. end else
  354. begin
  355. FErrorMessage := errnoStr(AError);
  356. inherited Create(ATitle + ': ' + FErrorMessage); {Do not Localize}
  357. end;
  358. end;
  359. function errnoStr(const AErrNo : TIdC_INT) : String;
  360. {$IFDEF USE_INLINE} inline; {$ENDIF}
  361. begin
  362. case AErrNo of
  363. EPERM : Result := 'EPERM';
  364. ENOENT : Result := 'ENOENT';
  365. ESRCH : Result := 'ESRCH';
  366. EINTR : Result := 'EINTR';
  367. EIO : Result := 'EIO';
  368. ENXIO : Result := 'ENXIO';
  369. E2BIG : Result := 'E2BIG';
  370. ENOEXEC : Result := 'ENOEXEC';
  371. EBADF : Result := 'EBADF';
  372. ECHILD : Result := 'ECHILD';
  373. EAGAIN : Result := 'EAGAIN';
  374. ENOMEM : Result := 'ENOMEM';
  375. EACCES : Result := 'EACCES';
  376. EFAULT : Result := 'EFAULT';
  377. EBUSY : Result := 'EBUSY';
  378. EEXIST : Result := 'EEXIST';
  379. EXDEV : Result := 'EXDEV';
  380. ENODEV : Result := 'ENODEV';
  381. ENOTDIR : Result := 'ENOTDIR';
  382. EISDIR : Result := 'EISDIR';
  383. EINVAL : Result := 'EINVAL';
  384. ENFILE : Result := 'ENFILE';
  385. EMFILE : Result := 'EMFILE';
  386. ENOTTY : Result := 'ENOTTY';
  387. EFBIG : Result := 'EFBIG';
  388. ENOSPC : Result := 'ENOSPC';
  389. ESPIPE : Result := 'ESPIPE';
  390. EROFS : Result := 'EROFS';
  391. EMLINK : Result := 'EMLINK';
  392. EPIPE : Result := 'EPIPE';
  393. EDOM : Result := 'EDOM';
  394. ERANGE : Result := 'ERANGE';
  395. EDEADLK : Result := 'EDEADLK';
  396. ENAMETOOLONG : Result := 'ENAMETOOLONG';
  397. ENOLCK : Result := 'ENOLCK';
  398. ENOSYS : Result := 'ENOSYS';
  399. ENOTEMPTY : Result := 'ENOTEMPTY';
  400. EILSEQ : Result := 'EILSEQ';
  401. else
  402. Result := '';
  403. end;
  404. end;
  405. function Stub_errno : PIdC_INT; cdecl;
  406. begin
  407. if hmsvcrt = 0 then begin
  408. hmsvcrt := SafeLoadLibrary(LIBMSVCRTL);
  409. if hmsvcrt = 0 then begin
  410. raise EIdMSVCRTStubError.Build('Failed to load ' + LIBMSVCRTL, 0);
  411. end;
  412. errno := GetProcAddress(hmsvcrt, PChar(FN_errno));
  413. if not Assigned(errno) then begin
  414. errno := Stub_errno;
  415. raise EIdMSVCRTStubError.Build('Failed to load ' + FN_errno + ' in ' + LIBMSVCRTL, 0);
  416. end;
  417. end;
  418. Result := errno();
  419. end;
  420. {$ENDIF}
  421. initialization
  422. InitializeStubs;
  423. finalization
  424. Unload;
  425. end.