325 lines
9.9 KiB
Plaintext
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.
|