{ $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.