IdZLibCompressorBase.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.21 3/5/2005 3:33:54 PM JPMugaas
  18. Fix for some compiler warnings having to do with TStream.Read being platform
  19. specific. This was fixed by changing the Compressor API to use TIdStreamVCL
  20. instead of TStream. I also made appropriate adjustments to other units for
  21. this.
  22. Rev 1.20 3/4/2005 12:36:58 PM JPMugaas
  23. Removed some compiler warnings.
  24. Rev 1.19 9/16/2004 3:24:08 AM JPMugaas
  25. TIdFTP now compresses to the IOHandler and decompresses from the IOHandler.
  26. Noted some that the ZLib code is based was taken from ZLibEx.
  27. Rev 1.18 9/12/2004 7:49:06 PM JPMugaas
  28. Removed an abstract method that was removed from the descendant to prevent a
  29. warning. It was part of an idea i had that hasn't yet developed due to
  30. another obsticle.
  31. Rev 1.17 9/11/2004 10:58:10 AM JPMugaas
  32. FTP now decompresses output directly to the IOHandler.
  33. Rev 1.16 7/18/2004 3:01:44 PM DSiders
  34. Added localization comments.
  35. Rev 1.15 6/15/2004 6:33:50 PM JPMugaas
  36. Bug fix for RaidenFTPD and ShareIt FTP Server. Since we now specifically
  37. look for the ZLIB headers, we pass the Window Bits value as negative
  38. DecompressFTPDeflate. I have verified this on RaidenFTPD and ShareIt.
  39. Note that there is an inconsistancy in the FTP Deflate drafts
  40. http://community.roxen.com/developers/idocs/drafts/draft-preston-ftpext-deflat
  41. e-02.html
  42. and
  43. http://community.roxen.com/developers/idocs/drafts/draft-preston-ftpext-deflat
  44. e-00.html
  45. Rev 1.14 6/14/2004 6:14:42 PM JPMugaas
  46. A fix from Bas. RaidenFTPD 1455 (http://www.raidenftpd.com) was sending the
  47. 2 byte header, the compression methods flags
  48. while ShareIt (www.noisette-software.com/products/windows/ShareIt/) was not
  49. doing so.
  50. Rev 1.13 2004.05.20 11:37:22 AM czhower
  51. IdStreamVCL
  52. Rev 1.12 2/15/2004 6:56:44 AM JPMugaas
  53. GZip decompression should now work again.
  54. Rev 1.11 2/15/2004 6:22:26 AM JPMugaas
  55. Fixed some parameter errors.
  56. Rev 1.10 2/14/2004 9:59:48 PM JPMugaas
  57. Reworked the API. There is now a separate API for the Inflate_ and
  58. InflateInit2_ functions as well as separate functions for DeflateInit_ and
  59. DeflateInit2_. This was required for FTP. The API also includes an optional
  60. output stream for the servers.
  61. Rev 1.9 2/12/2004 11:35:00 PM JPMugaas
  62. FTP Deflate preliminary support. Work still needs to be done for upload and
  63. downloading.
  64. Rev 1.8 2/12/2004 11:11:24 AM JPMugaas
  65. Added methods for HTTP Compression and decompression using RFC 1950. I have
  66. verified these.
  67. Rev 1.7 2004.02.03 5:45:48 PM czhower
  68. Name changes
  69. Rev 1.6 10/25/2003 06:52:26 AM JPMugaas
  70. Updated for new API changes and tried to restore some functionality.
  71. Rev 1.5 10/24/2003 05:04:54 PM JPMugaas
  72. SHould work as before.
  73. Rev 1.4 2003.10.24 10:43:14 AM czhower
  74. TIdSTream to dos
  75. Rev 1.3 10/7/2003 10:07:08 PM GGrieve
  76. Get HTTP compiling for DotNet
  77. Rev 1.2 7/13/2003 10:57:30 PM BGooijen
  78. Fixed GZip and Deflate decoding
  79. Rev 1.1 7/13/2003 11:30:56 AM JPMugaas
  80. Stub methods for Deflate and inflate methods if needed.
  81. Rev 1.0 7/13/2003 11:08:38 AM JPMugaas
  82. classes for ZLib compression.
  83. }
  84. unit IdZLibCompressorBase;
  85. interface
  86. {$i IdCompilerDefines.inc}
  87. uses
  88. Classes,
  89. IdBaseComponent,
  90. IdIOHandler;
  91. type
  92. TIdCompressionLevel = 0..9;
  93. TIdZLibCompressorBase = class(TIdBaseComponent)
  94. protected
  95. //this is to prevent ZLib compression where a dynamically load
  96. //of ZLib fails.
  97. function GetIsReady : Boolean; virtual;
  98. public
  99. //these call the standard InflateInit and DeflateInit
  100. procedure DeflateStream(AInStream, AOutStream : TStream;
  101. const ALevel : TIdCompressionLevel=0); virtual; abstract;
  102. procedure InflateStream(AInStream, AOutStream : TStream); virtual; abstract;
  103. //VAdler32 is for the benefit of people needing the Adler32 for uncompressed data
  104. //these call the standard InflateInit2 and DeflateInit2
  105. procedure CompressStream(AInStream, AOutStream : TStream;
  106. const ALevel : TIdCompressionLevel;
  107. const AWindowBits, AMemLevel, AStrategy: Integer); virtual; abstract;
  108. procedure DecompressStream(AInStream, AOutStream : TStream;
  109. const AWindowBits : Integer); virtual; abstract;
  110. procedure DecompressDeflateStream(AInStream, AOutStream : TStream); virtual;
  111. //RFC 1950 complient input and output
  112. procedure CompressFTPDeflate(AInStream, AOutStream : TStream;
  113. const ALevel, AWindowBits, AMemLevel, AStrategy: Integer);
  114. procedure CompressFTPToIO(AInStream : TStream; AIOHandler : TIdIOHandler;
  115. const ALevel, AWindowBits, AMemLevel, AStrategy: Integer); virtual; abstract;
  116. procedure DecompressFTPFromIO(AIOHandler : TIdIOHandler; AOutputStream : TStream;
  117. const AWindowBits : Integer); virtual; abstract;
  118. procedure DecompressFTPDeflate(AInStream, AOutStream : TStream;
  119. const AWindowBits : Integer);
  120. procedure CompressHTTPDeflate(AInStream, AOutStream : TStream;
  121. const ALevel : TIdCompressionLevel);
  122. procedure DecompressHTTPDeflate(AInStream, AOutStream : TStream);
  123. //RFC 1952 complient input and output
  124. procedure DecompressGZipStream(AInStream, AOutStream : TStream); virtual;
  125. property IsReady : Boolean read GetIsReady;
  126. end;
  127. TIdZLibCompressorBaseClass = class of TIdZLibCompressorBase;
  128. implementation
  129. uses
  130. IdException,
  131. IdGlobal, SysUtils;
  132. procedure TIdZLibCompressorBase.DecompressGZipStream(AInStream, AOutStream : TStream);
  133. procedure GotoDataStart;
  134. var
  135. LFlags: Byte;
  136. LExtra: array[0..1] of Byte;
  137. LNullFindChar: Byte;
  138. begin
  139. //skip id1,id2,CompressionMethod (id1 should=31, id2=139, CM should=8)
  140. AInStream.Seek(3, soCurrent);
  141. //read Flag
  142. AInStream.ReadBuffer(LFlags, 1);
  143. //skip mtime,xfl,os
  144. AInStream.Seek(6, soCurrent);
  145. // at pos 10 now
  146. if (LFlags and $4) = $4 then begin // FEXTRA
  147. AInStream.ReadBuffer(LExtra, 2);
  148. AInStream.Seek(BytesToUInt16(LExtra), soCurrent);
  149. end;
  150. if (LFlags and $8) = $8 then begin // FNAME
  151. repeat
  152. AInStream.ReadBuffer(LNullFindChar, 1);
  153. until LNullFindChar = 0;
  154. end;
  155. if (LFlags and $10) = $10 then begin // FCOMMENT
  156. repeat
  157. AInStream.ReadBuffer(LNullFindChar, 1);
  158. until LNullFindChar = 0;
  159. end;
  160. if (LFlags and $2) = $2 then begin // FHCRC
  161. AInStream.Seek(2, soCurrent); // CRC16
  162. end;
  163. end;
  164. var
  165. LBytes : array[0..1] of Byte;
  166. begin
  167. Assert(AInStream<>nil);
  168. GotoDataStart;
  169. AInStream.Seek(-2, soCurrent);
  170. LBytes[0] := $78; //7=32K blocks, 8=deflate
  171. LBytes[1] := $9C;
  172. AInStream.WriteBuffer(LBytes, 2);
  173. AInStream.Seek(-2, soCurrent);
  174. AInStream.Size := AInStream.Size - 8; // remove the CRC32 and the size
  175. InflateStream(AInStream, AOutStream);
  176. end;
  177. procedure TIdZLibCompressorBase.DecompressDeflateStream(AInStream, AOutStream : TStream);
  178. begin
  179. AInStream.Seek(10, soCurrent); // skip junk at front
  180. InflateStream(AInStream, AOutStream);
  181. end;
  182. procedure TIdZLibCompressorBase.DecompressFTPDeflate(AInStream, AOutStream : TStream; const AWindowBits : Integer);
  183. var
  184. LWinBits : Integer;
  185. begin
  186. {
  187. This is a workaround for some clients and servers that do not send decompression
  188. headers. The reason is that there's an inconsistancy in Internet Drafts for ZLIB
  189. compression. One says to include the headers while an older one says do not
  190. include the headers.
  191. }
  192. LWinBits := AWindowBits ;
  193. {
  194. windowBits can also be greater than 15 for optional gzip decoding. Add
  195. 32 to windowBits to enable zlib and gzip decoding with automatic header
  196. detection, or add 16 to decode only the gzip format (the zlib format will
  197. return a Z_DATA_ERROR).
  198. }
  199. if LWinBits > 0 then begin
  200. LWinBits := Abs(LWinBits) + 32;
  201. end;
  202. DecompressStream(AInStream,AOutStream,LWinBits);
  203. end;
  204. procedure TIdZLibCompressorBase.CompressFTPDeflate(AInStream, AOutStream : TStream;
  205. const ALevel, AWindowBits, AMemLevel, AStrategy: Integer);
  206. begin
  207. CompressStream(AInStream, AOutStream, ALevel, AWindowBits, AMemLevel, AStrategy);
  208. end;
  209. procedure TIdZLibCompressorBase.CompressHTTPDeflate(AInStream, AOutStream : TStream; const ALevel : TIdCompressionLevel);
  210. begin
  211. DeflateStream(AInStream, AOutStream, ALevel);
  212. end;
  213. procedure TIdZLibCompressorBase.DecompressHTTPDeflate(AInStream, AOutStream : TStream);
  214. var
  215. LBCmp : Byte;
  216. LFlags : Byte;
  217. LDict : array[0..3] of Byte;
  218. LOrgPos : Int64;
  219. begin
  220. LOrgPos := AInStream.Position;
  221. AInStream.ReadBuffer(LBCmp, 1);
  222. AInStream.ReadBuffer(LFlags, 1);
  223. if (((LBCmp * 256) + LFlags) mod 31) <> 0 then begin
  224. raise EIdException.Create('Error - invalid header'); {do not localize} // TODO: add a resource string, and create a new Exception class for this
  225. end;
  226. AInStream.ReadBuffer(LDict, 4);
  227. AInStream.Position := LOrgPos;
  228. InflateStream(AInStream, AOutStream);
  229. AInStream.Position := LOrgPos;
  230. end;
  231. function TIdZLibCompressorBase.GetIsReady: Boolean;
  232. begin
  233. Result := True;
  234. end;
  235. end.