IdIconv.pas 12 KB

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