fpc/packages/fcl-xml/src/xmliconv.pas
michael aecbef27b2 * Patch from Sergei Gorelkin:
* Changed the design of input decoders so they process data by chunks
    instead of char-by-char. It is much faster, and allows supporting
    external pluggable decoders.
  + Interface for external decoders.
  * ResolvePredefined() is rewritten so it doesn't call CompareMem five
    times do determine a single char.
  * ParseCharRef renamed to ParseRef, because it parses entity refs as
    well.
  * Added guard conditions to prevent integer overflows in ParseRef.
  * ContextPush(TXMLCharSource) merged into Initialize().

  xmliconv.pas is a new unit, containing an libiconv-based decoder. It depends on existing iconvenc package, and
  thus supports all platforms that are supported by iconvenc.

  xmliconv_windows.pas is the variation that allows to use libiconv functionality on Windows (It would require
  the iconv.dll to be distributed with the application, but since I haven't succeeded yet in writing a native
  Windows decoder, this is better than nothing).

git-svn-id: trunk@12582 -
2009-01-22 21:53:30 +00:00

79 lines
1.9 KiB
ObjectPascal

{
This file is part of the Free Component Library
libiconv-based XML decoder.
Copyright (c) 2009 by Sergei Gorelkin, sergei_gorelkin@mail.ru
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
unit xmliconv;
interface
implementation
uses
xmlread, iconvenc, unixtype, baseunix, initc;
const
{$ifdef FPC_LITTLE_ENDIAN}
utf16_encoding = 'UTF-16LE';
{$else FPC_LITTLE_ENDIAN}
utf16_encoding = 'UTF-16BE';
{$endif FPC_LITTLE_ENDIAN}
function Iconv_Decode(Context: Pointer; InBuf: PChar; var InCnt: Cardinal; OutBuf: PWideChar; var OutCnt: Cardinal): Integer; stdcall;
var
OutChars: size_t;
InChars: size_t;
begin
OutChars := OutCnt * sizeof(WideChar);
InChars := InCnt;
Result := iconv(Context, @InBuf, @InChars, @OutBuf, @OutChars);
InCnt := InChars;
OutCnt := OutChars div sizeof(WideChar);
if Result = -1 then
begin
case cerrno of
// when iconv reports insufficient input or output space, still return
// a positive number of converted chars
ESysE2BIG, ESysEINVAL:
Result := OutCnt - (OutChars div sizeof(WideChar));
else
Result := -cerrno;
end;
end;
end;
procedure Iconv_Cleanup(Context: Pointer); stdcall;
begin
iconv_close(Context);
end;
function GetIconvDecoder(const AEncoding: string; out Decoder: TDecoder): Boolean; stdcall;
var
f: iconv_t;
begin
f := iconv_open(utf16_encoding, PChar(AEncoding));
if f <> Pointer(-1) then
begin
Decoder.Context := f;
Decoder.Decode := @Iconv_Decode;
Decoder.Cleanup := @Iconv_Cleanup;
Result := True;
end
else
Result := False;
end;
initialization
RegisterDecoder(@GetIconvDecoder);
end.