iconvenc.pas 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2000 by Marco van de Voort([email protected])
  4. member of the Free Pascal development team
  5. libiconv header translation + a helper routine
  6. http://wiki.freepascal.org/iconvenc
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright. (LGPL)
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. }
  13. unit iconvenc;
  14. interface
  15. {$mode objfpc}{$H+}
  16. {DEFINE LOADDYNAMIC}
  17. uses
  18. baseunix,
  19. {$ifdef LOADDYNAMIC}
  20. dl,
  21. {$endif}
  22. initc;
  23. const
  24. n = 1;
  25. type
  26. piconv_t = ^iconv_t;
  27. iconv_t = pointer;
  28. Ticonv_open = function(__tocode: pchar; __fromcode: pchar): iconv_t; cdecl;
  29. Ticonv = function(__cd: iconv_t; __inbuf: ppchar; __inbytesleft: psize_t; __outbuf: ppchar; __outbytesleft: psize_t): size_t; cdecl;
  30. Ticonv_close = function(__cd: iconv_t): cint; cdecl;
  31. {$IFNDEF LOADDYNAMIC}
  32. {$ifndef Linux} // and other OSes with iconv in libc.
  33. {$linklib iconv}
  34. {$endif}
  35. function iconv_open(__tocode: pchar; __fromcode: pchar): iconv_t; cdecl; external;
  36. function iconv (__cd: iconv_t; __inbuf: ppchar; __inbytesleft: psize_t; __outbuf: ppchar; __outbytesleft: psize_t): size_t; cdecl; external;
  37. function iconv_close (__cd: iconv_t): cint; cdecl; external;
  38. var
  39. IconvLibFound: boolean = False;
  40. {$ELSE}
  41. var
  42. iconv_lib: pointer;
  43. iconv_open: Ticonv_open;
  44. iconv: Ticonv;
  45. iconv_close: Ticonv_close;
  46. IconvLibFound: boolean = true;
  47. function TryLoadLib(LibName: string; var error: string): boolean; // can be used to load non standard libname
  48. {$endif}
  49. function Iconvert(s: string; var res: string; FromEncoding, ToEncoding: string): cint;
  50. function InitIconv(var error: string): boolean;
  51. implementation
  52. {$IFDEF LOADDYNAMIC}
  53. function TryLoadLib(LibName: string; var error: string): boolean;
  54. function resolvesymbol (var funcptr; symbol: string): Boolean;
  55. begin
  56. pointer(funcptr) := pointer(dlsym(iconv_lib, pchar(symbol)));
  57. result := assigned(pointer(funcptr));
  58. if not result then
  59. error := error+#13#10+dlerror();
  60. end;
  61. var
  62. res: boolean;
  63. begin
  64. result := false;
  65. Error := Error+#13#10'Trying '+LibName;
  66. iconv_lib := dlopen(pchar(libname), RTLD_NOW);
  67. if Assigned(iconv_lib) then
  68. begin
  69. result := true;
  70. result := result and resolvesymbol(pointer(iconv),'iconv');
  71. result := result and resolvesymbol(pointer(iconv_open),'iconv_open');
  72. result := result and resolvesymbol(pointer(iconv_close),'iconv_close');
  73. // if not res then
  74. // dlclose(iconv_lib);
  75. end else
  76. error:=error+#13#10+dlerror();
  77. end;
  78. {$ENDIF}
  79. function InitIconv(var error: string): boolean;
  80. begin
  81. result := true;
  82. {$ifdef LOADDYNAMIC}
  83. error := '';
  84. if not TryLoadLib('libc.so.6', error) then
  85. if not TryLoadLib('libiconv.so', error) then
  86. result := false;
  87. {$endif}
  88. iconvlibfound := iconvlibfound or result;
  89. end;
  90. function Iconvert(S: string; var Res: string; FromEncoding, ToEncoding: string): cint;
  91. var
  92. InLen, OutLen, Offset: size_t;
  93. Src, Dst: pchar;
  94. H: iconv_t;
  95. lerr: cint;
  96. iconvres: size_t;
  97. begin
  98. H := iconv_open(PChar(ToEncoding), PChar(FromEncoding));
  99. if not assigned(H) then
  100. begin
  101. Res := S;
  102. exit(-1);
  103. end;
  104. try
  105. SetLength(Res, Length(S));
  106. InLen := Length(S);
  107. OutLen := Length(Res);
  108. Src := PChar(S);
  109. Dst := PChar(Res);
  110. while InLen > 0 do
  111. begin
  112. iconvres := iconv(H, @Src, @InLen, @Dst, @OutLen);
  113. if iconvres = size_t(-1) then
  114. begin
  115. lerr := cerrno;
  116. if lerr = ESysEILSEQ then // unknown char, skip
  117. begin
  118. Dst^ := Src^;
  119. Inc(Src);
  120. Inc(Dst);
  121. Dec(InLen);
  122. Dec(OutLen);
  123. end
  124. else
  125. if lerr = ESysE2BIG then
  126. begin
  127. Offset := Dst - PChar(Res);
  128. SetLength(Res, Length(Res)+InLen*2+5); // 5 is minimally one utf-8 char
  129. Dst := PChar(Res) + Offset;
  130. OutLen := Length(Res) - Offset;
  131. end
  132. else
  133. exit(-1)
  134. end;
  135. end;
  136. // iconv has a buffer that needs flushing, specially if the last char is not #0
  137. iconv(H, nil, nil, @Dst, @Outlen);
  138. // trim output buffer
  139. SetLength(Res, Length(Res) - Outlen);
  140. finally
  141. iconv_close(H);
  142. end;
  143. Result := 0;
  144. end;
  145. end.