restemplate/indy/System/IdIconv.pas

476 lines
13 KiB
Plaintext

unit IdIconv;
interface
{$I IdCompilerDefines.inc}
uses
{$IFDEF FPC}
DynLibs,
{$ENDIF}
IdCTypes,
IdException
{$IFDEF USE_BASEUNIX}
,UnixType
{$ENDIF}
{$IFDEF WINDOWS}
,Windows
{$ENDIF}
;
{.$DEFINE STATICLOAD_ICONV}
//These should be defined in libc.pas.
type
{$IFDEF WINDOWS}
{$EXTERNALSYM SIZE_T}
{$IFDEF CPU64}
size_t = QWord;
{$ELSE}
size_t = DWord;
{$ENDIF}
Psize_t = ^size_t;
{$ENDIF}
Piconv_t = ^iconv_t;
iconv_t = Pointer;
{$IFNDEF STATICLOAD_ICONV}
// This function is a possible cancellation points and therefore not
// marked with __THROW. */
//extern iconv_t iconv_open (__const char *__tocode, __const char *__fromcode);
TIdiconv_open = function (__tocode : PAnsiChar; __fromcode : PAnsiChar) : iconv_t; cdecl;
///* Convert at most *INBYTESLEFT bytes from *INBUF according to the
// code conversion algorithm specified by CD and place up to
// *OUTBYTESLEFT bytes in buffer at *OUTBUF. */
//extern size_t iconv (iconv_t __cd, char **__restrict __inbuf,
// size_t *__restrict __inbytesleft,
// char **__restrict __outbuf,
// size_t *__restrict __outbytesleft);
TIdiconv = function (__cd : iconv_t; __inbuf : PPAnsiChar;
__inbytesleft : Psize_t;
__outbuf : PPAnsiChar;
__outbytesleft : Psize_t ) : size_t; cdecl;
// This function is a possible cancellation points and therefore not
// marked with __THROW. */
//extern int iconv_close (iconv_t __cd);
TIdiconv_close = function (__cd : iconv_t) : TIdC_INT; cdecl;
type
EIdIconvStubError = class(EIdException)
protected
FError : LongWord;
FErrorMessage : String;
FTitle : String;
public
constructor Build(const ATitle : String; AError : LongWord);
property Error : LongWord read FError;
property ErrorMessage : String read FErrorMessage;
property Title : String read FTitle;
end;
var
iconv_open : TIdiconv_open = nil;
iconv : TIdiconv = nil;
iconv_close : TIdiconv_close = nil;
{$ENDIF}
{$IFDEF WIN32_OR_WIN64}
//errno.h constants that are needed for this and possibly other API's.
//It's here only because it seems to be the most sensible place to put it.
//These are defined in other operating systems.
const
{$EXTERNALSYM EPERM}
EPERM = 1;
{$EXTERNALSYM ENOENT}
ENOENT = 2;
{$EXTERNALSYM ESRCH}
ESRCH = 3;
{$EXTERNALSYM EINTR}
EINTR = 4;
{$EXTERNALSYM EIO}
EIO = 5;
{$EXTERNALSYM ENXIO}
ENXIO = 6;
{$EXTERNALSYM E2BIG}
E2BIG = 7;
{$EXTERNALSYM ENOEXEC}
ENOEXEC = 8;
{$EXTERNALSYM EBADF}
EBADF = 9;
{$EXTERNALSYM ECHILD}
ECHILD = 10;
{$EXTERNALSYM EAGAIN}
EAGAIN = 11;
{$EXTERNALSYM ENOMEM}
ENOMEM = 12;
{$EXTERNALSYM EACCES}
EACCES = 13;
{$EXTERNALSYM EFAULT}
EFAULT = 14;
{$EXTERNALSYM EBUSY}
EBUSY = 16;
{$EXTERNALSYM EEXIST}
EEXIST = 17;
{$EXTERNALSYM EXDEV}
EXDEV = 18;
{$EXTERNALSYM ENODEV}
ENODEV = 19;
{$EXTERNALSYM ENOTDIR}
ENOTDIR = 20;
{$EXTERNALSYM EISDIR}
EISDIR = 21;
{$EXTERNALSYM EINVAL}
EINVAL = 22;
{$EXTERNALSYM ENFILE}
ENFILE = 23;
{$EXTERNALSYM EMFILE}
EMFILE = 24;
{$EXTERNALSYM ENOTTY}
ENOTTY = 25;
{$EXTERNALSYM EFBIG}
EFBIG = 27;
{$EXTERNALSYM ENOSPC}
ENOSPC = 28;
{$EXTERNALSYM ESPIPE}
ESPIPE = 29;
{$EXTERNALSYM EROFS}
EROFS = 30;
{$EXTERNALSYM EMLINK}
EMLINK = 31;
{$EXTERNALSYM EPIPE}
EPIPE = 32;
{$EXTERNALSYM EDOM}
EDOM = 33;
{$EXTERNALSYM ERANGE}
ERANGE = 34;
{$EXTERNALSYM EDEADLK}
EDEADLK = 36;
{$EXTERNALSYM ENAMETOOLONG}
ENAMETOOLONG = 38;
{$EXTERNALSYM ENOLCK}
ENOLCK = 39;
{$EXTERNALSYM ENOSYS}
ENOSYS = 40;
{$EXTERNALSYM ENOTEMPTY}
ENOTEMPTY = 41;
{$EXTERNALSYM EILSEQ}
EILSEQ = 42;
type
EIdMSVCRTStubError = class(EIdException)
protected
FError : TIdC_INT;
FErrorMessage : String;
FTitle : String;
public
constructor Build(const ATitle : String; AError : TIdC_INT);
property Error : TIdC_INT read FError;
property ErrorMessage : String read FErrorMessage;
property Title : String read FTitle;
end;
{$ENDIF}
const
FN_ICONV_OPEN = 'iconv_open'; {Do not localize}
FN_ICONV = 'iconv'; {Do not localize}
FN_ICONV_CLOSE = 'iconv_close'; {Do not localize}
{$IFDEF UNIX}
LIBC = 'libc.so.6'; {Do not localize}
LICONV = 'libiconv.so'; {Do not localize}
{$ELSE}
// TODO: support static linking, such as via the "win_iconv" library
{$IFDEF WINDOWS}
//http://yukihiro.nakadaira.googlepages.com/ seems to use the iconv.dll name.
LICONV = 'iconv.dll'; {Do not localize}
LICONV_ALT = 'libiconv.dll'; {Do not localize}
LIBMSVCRTL = 'msvcrt.dll'; {Do not localize}
{$ENDIF}
{$ENDIF}
function Load : Boolean;
procedure Unload;
function Loaded : Boolean;
{$IFDEF STATICLOAD_ICONV}
function iconv_open(__tocode : PAnsiChar; __fromcode : PAnsiChar) : iconv_t; cdecl;
external LICONV name FN_ICONV_OPEN;
function iconv(__cd : iconv_t; __inbuf : PPAnsiChar;
__inbytesleft : Psize_t;
__outbuf : PPAnsiChar;
__outbytesleft : Psize_t ) : size_t; cdecl;
external LICONV name FN_ICONV;
function iconv_close(__cd : iconv_t) : TIdC_INT; cdecl;
external LICONV name FN_ICONV_CLOSE;
{$ENDIF}
{
From http://gettext.sourceforge.net/
Dynamic linking to iconv
Note that the iconv function call in libiconv stores its error, if it fails,
in the stdc library's errno. iconv.dll links to msvcrt.dll, and stores the error
in its exported errno symbol (this is actually a memory location with an
exported accessor function). If your code does not link against msvcrt.dll, you
may wish to import this accessor function specifically to get iconv failure
codes. This is particularly important for Visual C++ projects, which are likely
to link to msvcrtd.dll in Debug configuration, rather than msvcrt.dll. I have
written a C++ wrapper for iconv use, which does this, and I will be adding it to
WinMerge (on sourceforge) shortly.
}
{$IFDEF WIN32_OR_WIN64}
var
errno : function : PIdC_INT; cdecl;
function errnoStr(const AErrNo : TIdC_INT) : String;
{$ENDIF}
implementation
{$IFNDEF STATICLOAD_ICONV}
uses
IdResourceStrings, SysUtils;
var
{$IFDEF UNIX}
hIconv: HModule = nilhandle;
{$ELSE}
hIconv: THandle = 0;
{$ENDIF}
{$ENDIF}
{$IFDEF WIN32_OR_WIN64}
var
hmsvcrt : THandle = 0;
function Stub_errno : PIdC_INT; cdecl; forward;
{$ENDIF}
{$IFNDEF STATICLOAD_ICONV}
constructor EIdIconvStubError.Build(const ATitle : String; AError : LongWord);
begin
FTitle := ATitle;
FError := AError;
if AError = 0 then begin
inherited Create(ATitle);
end else
begin
FErrorMessage := SysUtils.SysErrorMessage(AError);
inherited Create(ATitle + ': ' + FErrorMessage); {Do not Localize}
end;
end;
function Fixup(const AName: string): Pointer;
begin
if hIconv = 0 then begin
if not Load then begin
raise EIdIconvStubError.Build(Format(RSIconvCallError, [AName]), 0);
end;
end;
Result := GetProcAddress(hIconv, PChar(AName));
{
IMPORTANT!!!
GNU libiconv for Win32 might be compiled with the LIBICONV_PLUG define.
If that's the case, we will have to load the functions with a "lib" prefix.
IOW, CYA!!!
}
if Result = nil then begin
Result := GetProcAddress(hIconv, PChar('lib'+AName));
if Result = nil then begin
raise EIdIconvStubError.Build(Format(RSIconvCallError, [AName]), 10022);
end;
end;
end;
{stubs that automatically load the iconv library and then fixup the functions.}
function Stub_iconv_open(__tocode : PAnsiChar; __fromcode : PAnsiChar) : iconv_t; cdecl;
begin
iconv_open := Fixup(FN_ICONV_OPEN);
Result := iconv_open(__tocode, __fromcode);
end;
function stub_iconv(__cd : iconv_t; __inbuf : PPAnsiChar;
__inbytesleft : Psize_t;
__outbuf : PPAnsiChar;
__outbytesleft : Psize_t ) : size_t; cdecl;
begin
iconv := Fixup(FN_ICONV);
Result := iconv(__cd,__inbuf,__inbytesleft,__outbuf,__outbytesleft);
end;
function stub_iconv_close(__cd : iconv_t) : TIdC_INT; cdecl;
begin
iconv_close := Fixup(FN_ICONV_CLOSE);
Result := iconv_close(__cd);
end;
{end stub sections}
{$ENDIF}
procedure InitializeStubs;
begin
{$IFNDEF STATICLOAD_ICONV}
iconv_open := Stub_iconv_open;
iconv := Stub_iconv;
iconv_close := Stub_iconv_close;
{$ENDIF}
{$IFDEF WIN32_OR_WIN64}
errno := Stub_errno;
{$ENDIF}
end;
function Load : Boolean;
{$IFDEF STATICLOAD_ICONV}
{$IFDEF USE_INLINE} inline; {$ENDIF}
{$ENDIF}
begin
{$IFDEF STATICLOAD_ICONV}
Result := True;
{$ELSE}
if not Loaded then begin
//In Windows, you should use SafeLoadLibrary instead of the LoadLibrary API
//call because LoadLibrary messes with the FPU control word.
{$IFDEF WINDOWS}
hIconv := SafeLoadLibrary(LICONV);
if hIconv = 0 then begin
hIconv := SafeLoadLibrary(LICONV_ALT);
end;
{$ELSE}
{$IFDEF UNIX}
hIconv := LoadLibrary(LICONV);
if hIconv = NilHandle then begin
hIconv := LoadLibrary(LIBC);
end;
{$ELSE}
hIconv := LoadLibrary(LICONV);
{$ENDIF}
{$ENDIF}
Result := Loaded;
end;
{$ENDIF}
end;
procedure Unload;
{$IFDEF USE_INLINE} inline; {$ENDIF}
begin
{$IFNDEF STATICLOAD_ICONV}
if Loaded then begin
FreeLibrary(hIconv);
hIconv := 0;
end;
{$ENDIF}
{$IFDEF WIN32_OR_WIN64}
if hmsvcrt <> 0 then begin
FreeLibrary(hmsvcrt);
hmsvcrt := 0;
end;
{$ENDIF}
InitializeStubs;
end;
function Loaded : Boolean;
{$IFDEF USE_INLINE} inline; {$ENDIF}
begin
{$IFDEF STATICLOAD_ICONV}
Result := True;
{$ELSE}
Result := (hIconv <> 0);
{$ENDIF}
end;
{$IFDEF WIN32_OR_WIN64}
const
FN_errno = '_errno';
constructor EIdMSVCRTStubError.Build(const ATitle : String; AError : TIdC_INT);
begin
FTitle := ATitle;
FError := AError;
if AError = 0 then begin
inherited Create(ATitle);
end else
begin
FErrorMessage := errnoStr(AError);
inherited Create(ATitle + ': ' + FErrorMessage); {Do not Localize}
end;
end;
function errnoStr(const AErrNo : TIdC_INT) : String;
{$IFDEF USE_INLINE} inline; {$ENDIF}
begin
case AErrNo of
EPERM : Result := 'EPERM';
ENOENT : Result := 'ENOENT';
ESRCH : Result := 'ESRCH';
EINTR : Result := 'EINTR';
EIO : Result := 'EIO';
ENXIO : Result := 'ENXIO';
E2BIG : Result := 'E2BIG';
ENOEXEC : Result := 'ENOEXEC';
EBADF : Result := 'EBADF';
ECHILD : Result := 'ECHILD';
EAGAIN : Result := 'EAGAIN';
ENOMEM : Result := 'ENOMEM';
EACCES : Result := 'EACCES';
EFAULT : Result := 'EFAULT';
EBUSY : Result := 'EBUSY';
EEXIST : Result := 'EEXIST';
EXDEV : Result := 'EXDEV';
ENODEV : Result := 'ENODEV';
ENOTDIR : Result := 'ENOTDIR';
EISDIR : Result := 'EISDIR';
EINVAL : Result := 'EINVAL';
ENFILE : Result := 'ENFILE';
EMFILE : Result := 'EMFILE';
ENOTTY : Result := 'ENOTTY';
EFBIG : Result := 'EFBIG';
ENOSPC : Result := 'ENOSPC';
ESPIPE : Result := 'ESPIPE';
EROFS : Result := 'EROFS';
EMLINK : Result := 'EMLINK';
EPIPE : Result := 'EPIPE';
EDOM : Result := 'EDOM';
ERANGE : Result := 'ERANGE';
EDEADLK : Result := 'EDEADLK';
ENAMETOOLONG : Result := 'ENAMETOOLONG';
ENOLCK : Result := 'ENOLCK';
ENOSYS : Result := 'ENOSYS';
ENOTEMPTY : Result := 'ENOTEMPTY';
EILSEQ : Result := 'EILSEQ';
else
Result := '';
end;
end;
function Stub_errno : PIdC_INT; cdecl;
begin
if hmsvcrt = 0 then begin
hmsvcrt := SafeLoadLibrary(LIBMSVCRTL);
if hmsvcrt = 0 then begin
raise EIdMSVCRTStubError.Build('Failed to load ' + LIBMSVCRTL, 0);
end;
errno := GetProcAddress(hmsvcrt, PChar(FN_errno));
if not Assigned(errno) then begin
errno := Stub_errno;
raise EIdMSVCRTStubError.Build('Failed to load ' + FN_errno + ' in ' + LIBMSVCRTL, 0);
end;
end;
Result := errno();
end;
{$ENDIF}
initialization
InitializeStubs;
finalization
Unload;
end.