restemplate/indy/Protocols/IdZLibCompressorBase.pas

325 lines
9.9 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.21 3/5/2005 3:33:54 PM JPMugaas
Fix for some compiler warnings having to do with TStream.Read being platform
specific. This was fixed by changing the Compressor API to use TIdStreamVCL
instead of TStream. I also made appropriate adjustments to other units for
this.
Rev 1.20 3/4/2005 12:36:58 PM JPMugaas
Removed some compiler warnings.
Rev 1.19 9/16/2004 3:24:08 AM JPMugaas
TIdFTP now compresses to the IOHandler and decompresses from the IOHandler.
Noted some that the ZLib code is based was taken from ZLibEx.
Rev 1.18 9/12/2004 7:49:06 PM JPMugaas
Removed an abstract method that was removed from the descendant to prevent a
warning. It was part of an idea i had that hasn't yet developed due to
another obsticle.
Rev 1.17 9/11/2004 10:58:10 AM JPMugaas
FTP now decompresses output directly to the IOHandler.
Rev 1.16 7/18/2004 3:01:44 PM DSiders
Added localization comments.
Rev 1.15 6/15/2004 6:33:50 PM JPMugaas
Bug fix for RaidenFTPD and ShareIt FTP Server. Since we now specifically
look for the ZLIB headers, we pass the Window Bits value as negative
DecompressFTPDeflate. I have verified this on RaidenFTPD and ShareIt.
Note that there is an inconsistancy in the FTP Deflate drafts
http://community.roxen.com/developers/idocs/drafts/draft-preston-ftpext-deflat
e-02.html
and
http://community.roxen.com/developers/idocs/drafts/draft-preston-ftpext-deflat
e-00.html
Rev 1.14 6/14/2004 6:14:42 PM JPMugaas
A fix from Bas. RaidenFTPD 1455 (http://www.raidenftpd.com) was sending the
2 byte header, the compression methods flags
while ShareIt (www.noisette-software.com/products/windows/ShareIt/) was not
doing so.
Rev 1.13 2004.05.20 11:37:22 AM czhower
IdStreamVCL
Rev 1.12 2/15/2004 6:56:44 AM JPMugaas
GZip decompression should now work again.
Rev 1.11 2/15/2004 6:22:26 AM JPMugaas
Fixed some parameter errors.
Rev 1.10 2/14/2004 9:59:48 PM JPMugaas
Reworked the API. There is now a separate API for the Inflate_ and
InflateInit2_ functions as well as separate functions for DeflateInit_ and
DeflateInit2_. This was required for FTP. The API also includes an optional
output stream for the servers.
Rev 1.9 2/12/2004 11:35:00 PM JPMugaas
FTP Deflate preliminary support. Work still needs to be done for upload and
downloading.
Rev 1.8 2/12/2004 11:11:24 AM JPMugaas
Added methods for HTTP Compression and decompression using RFC 1950. I have
verified these.
Rev 1.7 2004.02.03 5:45:48 PM czhower
Name changes
Rev 1.6 10/25/2003 06:52:26 AM JPMugaas
Updated for new API changes and tried to restore some functionality.
Rev 1.5 10/24/2003 05:04:54 PM JPMugaas
SHould work as before.
Rev 1.4 2003.10.24 10:43:14 AM czhower
TIdSTream to dos
Rev 1.3 10/7/2003 10:07:08 PM GGrieve
Get HTTP compiling for DotNet
Rev 1.2 7/13/2003 10:57:30 PM BGooijen
Fixed GZip and Deflate decoding
Rev 1.1 7/13/2003 11:30:56 AM JPMugaas
Stub methods for Deflate and inflate methods if needed.
Rev 1.0 7/13/2003 11:08:38 AM JPMugaas
classes for ZLib compression.
}
unit IdZLibCompressorBase;
interface
{$i IdCompilerDefines.inc}
uses
Classes,
IdBaseComponent,
IdStream,
IdIOHandler;
type
TIdCompressionLevel = 0..9;
TIdZLibCompressorBase = class(TIdBaseComponent)
protected
//this is to prevent ZLib compression where a dynamically load
//of ZLib fails.
function GetIsReady : Boolean; virtual;
public
//these call the standard InflateInit and DeflateInit
procedure DeflateStream(AInStream, AOutStream : TStream;
const ALevel : TIdCompressionLevel=0); virtual; abstract;
procedure InflateStream(AInStream, AOutStream : TStream); virtual; abstract;
//VAdler32 is for the benefit of people needing the Adler32 for uncompressed data
//these call the standard InflateInit2 and DeflateInit2
procedure CompressStream(AInStream, AOutStream : TStream;
const ALevel : TIdCompressionLevel;
const AWindowBits, AMemLevel, AStrategy: Integer); virtual; abstract;
procedure DecompressStream(AInStream, AOutStream : TStream;
const AWindowBits : Integer); virtual; abstract;
procedure DecompressDeflateStream(AInStream, AOutStream : TStream); virtual;
//RFC 1950 complient input and output
procedure CompressFTPDeflate(AInStream, AOutStream : TStream;
const ALevel, AWindowBits, AMemLevel, AStrategy: Integer);
procedure CompressFTPToIO(AInStream : TStream; AIOHandler : TIdIOHandler;
const ALevel, AWindowBits, AMemLevel, AStrategy: Integer); virtual; abstract;
procedure DecompressFTPFromIO(AIOHandler : TIdIOHandler; AOutputStream : TStream;
const AWindowBits : Integer); virtual; abstract;
procedure DecompressFTPDeflate(AInStream, AOutStream : TStream;
const AWindowBits : Integer);
procedure CompressHTTPDeflate(AInStream, AOutStream : TStream;
const ALevel : TIdCompressionLevel);
procedure DecompressHTTPDeflate(AInStream, AOutStream : TStream);
//RFC 1952 complient input and output
procedure DecompressGZipStream(AInStream, AOutStream : TStream); virtual;
property IsReady : Boolean read GetIsReady;
end;
TIdZLibCompressorBaseClass = class of TIdZLibCompressorBase;
implementation
uses
IdException,
IdGlobal, SysUtils;
procedure TIdZLibCompressorBase.DecompressGZipStream(AInStream, AOutStream : TStream);
procedure GotoDataStart;
var
LFlags: TIdBytes; //used as a byte
LExtra: TIdBytes; //used as a word
LNullFindChar: TIdBytes; //used as char
begin
SetLength(LFlags,1);
SetLength(LExtra,2);
SetLength(LNullFindChar,1);
//skip id1,id2,CompressionMethod (id1 should=31, id2=139, CM should=8)
TIdStreamHelper.Seek(AInStream, 3, soCurrent);
//read Flag
TIdStreamHelper.ReadBytes(AInStream, LFlags, 1);
//skip mtime,xfl,os
TIdStreamHelper.Seek(AInStream, 6, soCurrent);
// at pos 10 now
if (LFlags[0] and $4) = $4 then begin // FEXTRA
TIdStreamHelper.ReadBytes(AInStream, LExtra, 2);
TIdStreamHelper.Seek(AInStream, BytesToUInt16(LExtra), soCurrent);
end;
if (LFlags[0] and $8) = $8 then begin // FNAME
repeat
TIdStreamHelper.ReadBytes(AInStream, LNullFindChar, 1);
until LNullFindChar[0] = 0;
end;
if (LFlags[0] and $10) = $10 then begin // FCOMMENT
repeat
TIdStreamHelper.ReadBytes(AInStream, LNullFindChar, 1);
until LNullFindChar[0] = 0;
end;
if (LFlags[0] and $2) = $2 then begin // FHCRC
TIdStreamHelper.Seek(AInStream, 2, soCurrent); // CRC16
end;
end;
var
LBytes : TIdBytes;
begin
Assert(AInStream<>nil);
GotoDataStart;
TIdStreamHelper.Seek(AInStream, -2, soCurrent);
SetLength(LBytes, 2);
LBytes[0] := $78; //7=32K blocks, 8=deflate
LBytes[1] := $9C;
TIdStreamHelper.Write(AInStream, LBytes, 2);
TIdStreamHelper.Seek(AInStream, -2, soCurrent);
AInStream.size := AInStream.size - 8; // remove the CRC32 and the size
InflateStream(AInStream, AOutStream);
end;
procedure TIdZLibCompressorBase.DecompressDeflateStream(AInStream, AOutStream : TStream);
begin
TIdStreamHelper.Seek(AInStream, 10, soCurrent); // skip junk at front
InflateStream(AInStream, AOutStream);
end;
procedure TIdZLibCompressorBase.DecompressFTPDeflate(AInStream, AOutStream : TStream; const AWindowBits : Integer);
var
LWinBits : Integer;
begin
{
This is a workaround for some clients and servers that do not send decompression
headers. The reason is that there's an inconsistancy in Internet Drafts for ZLIB
compression. One says to include the headers while an older one says do not
include the headers.
}
LWinBits := AWindowBits ;
{
windowBits can also be greater than 15 for optional gzip decoding. Add
32 to windowBits to enable zlib and gzip decoding with automatic header
detection, or add 16 to decode only the gzip format (the zlib format will
return a Z_DATA_ERROR).
}
if LWinBits > 0 then begin
LWinBits := Abs(LWinBits) + 32;
end;
DecompressStream(AInStream,AOutStream,LWinBits);
end;
procedure TIdZLibCompressorBase.CompressFTPDeflate(AInStream, AOutStream : TStream;
const ALevel, AWindowBits, AMemLevel, AStrategy: Integer);
begin
CompressStream(AInStream, AOutStream, ALevel, AWindowBits, AMemLevel, AStrategy);
end;
procedure TIdZLibCompressorBase.CompressHTTPDeflate(AInStream, AOutStream : TStream; const ALevel : TIdCompressionLevel);
begin
DeflateStream(AInStream, AOutStream, ALevel);
end;
procedure TIdZLibCompressorBase.DecompressHTTPDeflate(AInStream, AOutStream : TStream);
var
LBCmp : TIdBytes; //used as Byte
LFlags : TIdBytes; //used as Byte
LDict : TIdBytes; //used as Cardinal
LOrgPos : TIdStreamSize;
begin
SetLength(LBCmp, 1);
SetLength(LFlags, 1);
SetLength(LDict, 4);
LOrgPos := AInStream.Position;
TIdStreamHelper.ReadBytes(AInStream, LBCmp, 1);
TIdStreamHelper.ReadBytes(AInStream, LFlags, 1);
if (((LBCmp[0] * 256) + LFlags[0]) mod 31) <> 0 then begin
raise EIdException.Create('Error - invalid header'); {do not localize}
end;
TIdStreamHelper.ReadBytes(AInStream, LDict, 4);
AInStream.Position := LOrgPos;
InflateStream(AInStream, AOutStream);
AInStream.Position := LOrgPos;
end;
function TIdZLibCompressorBase.GetIsReady: Boolean;
begin
Result := True;
end;
end.