synaicnv.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 001.001.002 |
  3. |==============================================================================|
  4. | Content: ICONV support for Win32, OS/2, Linux and .NET |
  5. |==============================================================================|
  6. | Copyright (c)2004-2013, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c)2004-2013. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): |
  40. | Tomas Hajny (OS2 support) |
  41. |==============================================================================|
  42. | History: see HISTORY.HTM from distribution package |
  43. | (Found at URL: http://www.ararat.cz/synapse/) |
  44. |==============================================================================}
  45. {$IFDEF FPC}
  46. {$MODE DELPHI}
  47. {$ENDIF}
  48. {$H+}
  49. //old Delphi does not have MSWINDOWS define.
  50. {$IFDEF WIN32}
  51. {$IFNDEF MSWINDOWS}
  52. {$DEFINE MSWINDOWS}
  53. {$ENDIF}
  54. {$ENDIF}
  55. {:@abstract(LibIconv support)
  56. This unit is Pascal interface to LibIconv library for charset translations.
  57. LibIconv is loaded dynamicly on-demand. If this library is not found in system,
  58. requested LibIconv function just return errorcode.
  59. }
  60. unit synaicnv;
  61. interface
  62. uses
  63. {$IFDEF CIL}
  64. System.Runtime.InteropServices,
  65. System.Text,
  66. {$ENDIF}
  67. synafpc,
  68. {$IFNDEF MSWINDOWS}
  69. {$IFNDEF FPC}
  70. Libc,
  71. {$ENDIF}
  72. SysUtils;
  73. {$ELSE}
  74. Windows;
  75. {$ENDIF}
  76. const
  77. {$IFNDEF MSWINDOWS}
  78. {$IFDEF OS2}
  79. DLLIconvName = 'iconv.dll';
  80. {$ELSE OS2}
  81. DLLIconvName = 'libiconv.so';
  82. {$ENDIF OS2}
  83. {$ELSE}
  84. DLLIconvName = 'iconv.dll';
  85. {$ENDIF}
  86. type
  87. size_t = Cardinal;
  88. {$IFDEF CIL}
  89. iconv_t = IntPtr;
  90. {$ELSE}
  91. iconv_t = Pointer;
  92. {$ENDIF}
  93. argptr = iconv_t;
  94. var
  95. iconvLibHandle: TLibHandle = 0;
  96. function SynaIconvOpen(const tocode, fromcode: Ansistring): iconv_t;
  97. function SynaIconvOpenTranslit(const tocode, fromcode: Ansistring): iconv_t;
  98. function SynaIconvOpenIgnore(const tocode, fromcode: Ansistring): iconv_t;
  99. function SynaIconv(cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer;
  100. function SynaIconvClose(var cd: iconv_t): integer;
  101. function SynaIconvCtl(cd: iconv_t; request: integer; argument: argptr): integer;
  102. function IsIconvloaded: Boolean;
  103. function InitIconvInterface: Boolean;
  104. function DestroyIconvInterface: Boolean;
  105. const
  106. ICONV_TRIVIALP = 0; // int *argument
  107. ICONV_GET_TRANSLITERATE = 1; // int *argument
  108. ICONV_SET_TRANSLITERATE = 2; // const int *argument
  109. ICONV_GET_DISCARD_ILSEQ = 3; // int *argument
  110. ICONV_SET_DISCARD_ILSEQ = 4; // const int *argument
  111. implementation
  112. uses SyncObjs;
  113. {$IFDEF CIL}
  114. [DllImport(DLLIconvName, CharSet = CharSet.Ansi,
  115. SetLastError = False, CallingConvention= CallingConvention.cdecl,
  116. EntryPoint = 'libiconv_open')]
  117. function _iconv_open(tocode: string; fromcode: string): iconv_t; external;
  118. [DllImport(DLLIconvName, CharSet = CharSet.Ansi,
  119. SetLastError = False, CallingConvention= CallingConvention.cdecl,
  120. EntryPoint = 'libiconv')]
  121. function _iconv(cd: iconv_t; var inbuf: IntPtr; var inbytesleft: size_t;
  122. var outbuf: IntPtr; var outbytesleft: size_t): size_t; external;
  123. [DllImport(DLLIconvName, CharSet = CharSet.Ansi,
  124. SetLastError = False, CallingConvention= CallingConvention.cdecl,
  125. EntryPoint = 'libiconv_close')]
  126. function _iconv_close(cd: iconv_t): integer; external;
  127. [DllImport(DLLIconvName, CharSet = CharSet.Ansi,
  128. SetLastError = False, CallingConvention= CallingConvention.cdecl,
  129. EntryPoint = 'libiconvctl')]
  130. function _iconvctl(cd: iconv_t; request: integer; argument: argptr): integer; external;
  131. {$ELSE}
  132. type
  133. Ticonv_open = function(tocode: pAnsichar; fromcode: pAnsichar): iconv_t; cdecl;
  134. Ticonv = function(cd: iconv_t; var inbuf: pointer; var inbytesleft: size_t;
  135. var outbuf: pointer; var outbytesleft: size_t): size_t; cdecl;
  136. Ticonv_close = function(cd: iconv_t): integer; cdecl;
  137. Ticonvctl = function(cd: iconv_t; request: integer; argument: argptr): integer; cdecl;
  138. var
  139. _iconv_open: Ticonv_open = nil;
  140. _iconv: Ticonv = nil;
  141. _iconv_close: Ticonv_close = nil;
  142. _iconvctl: Ticonvctl = nil;
  143. {$ENDIF}
  144. var
  145. IconvCS: TCriticalSection;
  146. Iconvloaded: boolean = false;
  147. function SynaIconvOpen (const tocode, fromcode: Ansistring): iconv_t;
  148. begin
  149. {$IFDEF CIL}
  150. try
  151. Result := _iconv_open(tocode, fromcode);
  152. except
  153. on Exception do
  154. Result := iconv_t(-1);
  155. end;
  156. {$ELSE}
  157. if InitIconvInterface and Assigned(_iconv_open) then
  158. Result := _iconv_open(PAnsiChar(tocode), PAnsiChar(fromcode))
  159. else
  160. Result := iconv_t(-1);
  161. {$ENDIF}
  162. end;
  163. function SynaIconvOpenTranslit (const tocode, fromcode: Ansistring): iconv_t;
  164. begin
  165. Result := SynaIconvOpen(tocode + '//IGNORE//TRANSLIT', fromcode);
  166. end;
  167. function SynaIconvOpenIgnore (const tocode, fromcode: Ansistring): iconv_t;
  168. begin
  169. Result := SynaIconvOpen(tocode + '//IGNORE', fromcode);
  170. end;
  171. function SynaIconv (cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer;
  172. var
  173. {$IFDEF CIL}
  174. ib, ob: IntPtr;
  175. ibsave, obsave: IntPtr;
  176. l: integer;
  177. {$ELSE}
  178. ib, ob: Pointer;
  179. {$ENDIF}
  180. ix, ox: size_t;
  181. begin
  182. {$IFDEF CIL}
  183. l := Length(inbuf) * 4;
  184. ibsave := IntPtr.Zero;
  185. obsave := IntPtr.Zero;
  186. try
  187. ibsave := Marshal.StringToHGlobalAnsi(inbuf);
  188. obsave := Marshal.AllocHGlobal(l);
  189. ib := ibsave;
  190. ob := obsave;
  191. ix := Length(inbuf);
  192. ox := l;
  193. _iconv(cd, ib, ix, ob, ox);
  194. Outbuf := Marshal.PtrToStringAnsi(obsave, l);
  195. setlength(Outbuf, l - ox);
  196. Result := Length(inbuf) - ix;
  197. finally
  198. Marshal.FreeCoTaskMem(ibsave);
  199. Marshal.FreeHGlobal(obsave);
  200. end;
  201. {$ELSE}
  202. if InitIconvInterface and Assigned(_iconv) then
  203. begin
  204. setlength(Outbuf, Length(inbuf) * 4);
  205. ib := Pointer(inbuf);
  206. ob := Pointer(Outbuf);
  207. ix := Length(inbuf);
  208. ox := Length(Outbuf);
  209. _iconv(cd, ib, ix, ob, ox);
  210. setlength(Outbuf, cardinal(Length(Outbuf)) - ox);
  211. Result := Cardinal(Length(inbuf)) - ix;
  212. end
  213. else
  214. begin
  215. Outbuf := '';
  216. Result := 0;
  217. end;
  218. {$ENDIF}
  219. end;
  220. function SynaIconvClose(var cd: iconv_t): integer;
  221. begin
  222. if cd = iconv_t(-1) then
  223. begin
  224. Result := 0;
  225. Exit;
  226. end;
  227. {$IFDEF CIL}
  228. try;
  229. Result := _iconv_close(cd)
  230. except
  231. on Exception do
  232. Result := -1;
  233. end;
  234. cd := iconv_t(-1);
  235. {$ELSE}
  236. if InitIconvInterface and Assigned(_iconv_close) then
  237. Result := _iconv_close(cd)
  238. else
  239. Result := -1;
  240. cd := iconv_t(-1);
  241. {$ENDIF}
  242. end;
  243. function SynaIconvCtl (cd: iconv_t; request: integer; argument: argptr): integer;
  244. begin
  245. {$IFDEF CIL}
  246. Result := _iconvctl(cd, request, argument)
  247. {$ELSE}
  248. if InitIconvInterface and Assigned(_iconvctl) then
  249. Result := _iconvctl(cd, request, argument)
  250. else
  251. Result := 0;
  252. {$ENDIF}
  253. end;
  254. function InitIconvInterface: Boolean;
  255. begin
  256. IconvCS.Enter;
  257. try
  258. if not IsIconvloaded then
  259. begin
  260. {$IFDEF CIL}
  261. IconvLibHandle := 1;
  262. {$ELSE}
  263. IconvLibHandle := LoadLibrary(PChar(DLLIconvName));
  264. {$ENDIF}
  265. if (IconvLibHandle <> 0) then
  266. begin
  267. {$IFNDEF CIL}
  268. _iconv_open := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_open')));
  269. _iconv := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv')));
  270. _iconv_close := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_close')));
  271. _iconvctl := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconvctl')));
  272. {$ENDIF}
  273. Result := True;
  274. Iconvloaded := True;
  275. end
  276. else
  277. begin
  278. //load failed!
  279. if IconvLibHandle <> 0 then
  280. begin
  281. {$IFNDEF CIL}
  282. FreeLibrary(IconvLibHandle);
  283. {$ENDIF}
  284. IconvLibHandle := 0;
  285. end;
  286. Result := False;
  287. end;
  288. end
  289. else
  290. //loaded before...
  291. Result := true;
  292. finally
  293. IconvCS.Leave;
  294. end;
  295. end;
  296. function DestroyIconvInterface: Boolean;
  297. begin
  298. IconvCS.Enter;
  299. try
  300. Iconvloaded := false;
  301. if IconvLibHandle <> 0 then
  302. begin
  303. {$IFNDEF CIL}
  304. FreeLibrary(IconvLibHandle);
  305. {$ENDIF}
  306. IconvLibHandle := 0;
  307. end;
  308. {$IFNDEF CIL}
  309. _iconv_open := nil;
  310. _iconv := nil;
  311. _iconv_close := nil;
  312. _iconvctl := nil;
  313. {$ENDIF}
  314. finally
  315. IconvCS.Leave;
  316. end;
  317. Result := True;
  318. end;
  319. function IsIconvloaded: Boolean;
  320. begin
  321. Result := IconvLoaded;
  322. end;
  323. initialization
  324. begin
  325. IconvCS:= TCriticalSection.Create;
  326. end;
  327. finalization
  328. begin
  329. {$IFNDEF CIL}
  330. DestroyIconvInterface;
  331. {$ENDIF}
  332. IconvCS.Free;
  333. end;
  334. end.