IdZLibCompressorBase.pas 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. IdStream,
  91. IdIOHandler;
  92. type
  93. TIdCompressionLevel = 0..9;
  94. TIdZLibCompressorBase = class(TIdBaseComponent)
  95. protected
  96. //this is to prevent ZLib compression where a dynamically load
  97. //of ZLib fails.
  98. function GetIsReady : Boolean; virtual;
  99. public
  100. //these call the standard InflateInit and DeflateInit
  101. procedure DeflateStream(AInStream, AOutStream : TStream;
  102. const ALevel : TIdCompressionLevel=0); virtual; abstract;
  103. procedure InflateStream(AInStream, AOutStream : TStream); virtual; abstract;
  104. //VAdler32 is for the benefit of people needing the Adler32 for uncompressed data
  105. //these call the standard InflateInit2 and DeflateInit2
  106. procedure CompressStream(AInStream, AOutStream : TStream;
  107. const ALevel : TIdCompressionLevel;
  108. const AWindowBits, AMemLevel, AStrategy: Integer); virtual; abstract;
  109. procedure DecompressStream(AInStream, AOutStream : TStream;
  110. const AWindowBits : Integer); virtual; abstract;
  111. procedure DecompressDeflateStream(AInStream, AOutStream : TStream); virtual;
  112. //RFC 1950 complient input and output
  113. procedure CompressFTPDeflate(AInStream, AOutStream : TStream;
  114. const ALevel, AWindowBits, AMemLevel, AStrategy: Integer);
  115. procedure CompressFTPToIO(AInStream : TStream; AIOHandler : TIdIOHandler;
  116. const ALevel, AWindowBits, AMemLevel, AStrategy: Integer); virtual; abstract;
  117. procedure DecompressFTPFromIO(AIOHandler : TIdIOHandler; AOutputStream : TStream;
  118. const AWindowBits : Integer); virtual; abstract;
  119. procedure DecompressFTPDeflate(AInStream, AOutStream : TStream;
  120. const AWindowBits : Integer);
  121. procedure CompressHTTPDeflate(AInStream, AOutStream : TStream;
  122. const ALevel : TIdCompressionLevel);
  123. procedure DecompressHTTPDeflate(AInStream, AOutStream : TStream);
  124. //RFC 1952 complient input and output
  125. procedure DecompressGZipStream(AInStream, AOutStream : TStream); virtual;
  126. property IsReady : Boolean read GetIsReady;
  127. end;
  128. TIdZLibCompressorBaseClass = class of TIdZLibCompressorBase;
  129. implementation
  130. uses
  131. IdException,
  132. IdGlobal, SysUtils;
  133. procedure TIdZLibCompressorBase.DecompressGZipStream(AInStream, AOutStream : TStream);
  134. procedure GotoDataStart;
  135. var
  136. LFlags: TIdBytes; //used as a byte
  137. LExtra: TIdBytes; //used as a word
  138. LNullFindChar: TIdBytes; //used as char
  139. begin
  140. SetLength(LFlags,1);
  141. SetLength(LExtra,2);
  142. SetLength(LNullFindChar,1);
  143. //skip id1,id2,CompressionMethod (id1 should=31, id2=139, CM should=8)
  144. TIdStreamHelper.Seek(AInStream, 3, soCurrent);
  145. //read Flag
  146. TIdStreamHelper.ReadBytes(AInStream, LFlags, 1);
  147. //skip mtime,xfl,os
  148. TIdStreamHelper.Seek(AInStream, 6, soCurrent);
  149. // at pos 10 now
  150. if (LFlags[0] and $4) = $4 then begin // FEXTRA
  151. TIdStreamHelper.ReadBytes(AInStream, LExtra, 2);
  152. TIdStreamHelper.Seek(AInStream, BytesToUInt16(LExtra), soCurrent);
  153. end;
  154. if (LFlags[0] and $8) = $8 then begin // FNAME
  155. repeat
  156. TIdStreamHelper.ReadBytes(AInStream, LNullFindChar, 1);
  157. until LNullFindChar[0] = 0;
  158. end;
  159. if (LFlags[0] and $10) = $10 then begin // FCOMMENT
  160. repeat
  161. TIdStreamHelper.ReadBytes(AInStream, LNullFindChar, 1);
  162. until LNullFindChar[0] = 0;
  163. end;
  164. if (LFlags[0] and $2) = $2 then begin // FHCRC
  165. TIdStreamHelper.Seek(AInStream, 2, soCurrent); // CRC16
  166. end;
  167. end;
  168. var
  169. LBytes : TIdBytes;
  170. begin
  171. Assert(AInStream<>nil);
  172. GotoDataStart;
  173. TIdStreamHelper.Seek(AInStream, -2, soCurrent);
  174. SetLength(LBytes, 2);
  175. LBytes[0] := $78; //7=32K blocks, 8=deflate
  176. LBytes[1] := $9C;
  177. TIdStreamHelper.Write(AInStream, LBytes, 2);
  178. TIdStreamHelper.Seek(AInStream, -2, soCurrent);
  179. AInStream.size := AInStream.size - 8; // remove the CRC32 and the size
  180. InflateStream(AInStream, AOutStream);
  181. end;
  182. procedure TIdZLibCompressorBase.DecompressDeflateStream(AInStream, AOutStream : TStream);
  183. begin
  184. TIdStreamHelper.Seek(AInStream, 10, soCurrent); // skip junk at front
  185. InflateStream(AInStream, AOutStream);
  186. end;
  187. procedure TIdZLibCompressorBase.DecompressFTPDeflate(AInStream, AOutStream : TStream; const AWindowBits : Integer);
  188. var
  189. LWinBits : Integer;
  190. begin
  191. {
  192. This is a workaround for some clients and servers that do not send decompression
  193. headers. The reason is that there's an inconsistancy in Internet Drafts for ZLIB
  194. compression. One says to include the headers while an older one says do not
  195. include the headers.
  196. }
  197. LWinBits := AWindowBits ;
  198. {
  199. windowBits can also be greater than 15 for optional gzip decoding. Add
  200. 32 to windowBits to enable zlib and gzip decoding with automatic header
  201. detection, or add 16 to decode only the gzip format (the zlib format will
  202. return a Z_DATA_ERROR).
  203. }
  204. if LWinBits > 0 then begin
  205. LWinBits := Abs(LWinBits) + 32;
  206. end;
  207. DecompressStream(AInStream,AOutStream,LWinBits);
  208. end;
  209. procedure TIdZLibCompressorBase.CompressFTPDeflate(AInStream, AOutStream : TStream;
  210. const ALevel, AWindowBits, AMemLevel, AStrategy: Integer);
  211. begin
  212. CompressStream(AInStream, AOutStream, ALevel, AWindowBits, AMemLevel, AStrategy);
  213. end;
  214. procedure TIdZLibCompressorBase.CompressHTTPDeflate(AInStream, AOutStream : TStream; const ALevel : TIdCompressionLevel);
  215. begin
  216. DeflateStream(AInStream, AOutStream, ALevel);
  217. end;
  218. procedure TIdZLibCompressorBase.DecompressHTTPDeflate(AInStream, AOutStream : TStream);
  219. var
  220. LBCmp : TIdBytes; //used as Byte
  221. LFlags : TIdBytes; //used as Byte
  222. LDict : TIdBytes; //used as Cardinal
  223. LOrgPos : TIdStreamSize;
  224. begin
  225. SetLength(LBCmp, 1);
  226. SetLength(LFlags, 1);
  227. SetLength(LDict, 4);
  228. LOrgPos := AInStream.Position;
  229. TIdStreamHelper.ReadBytes(AInStream, LBCmp, 1);
  230. TIdStreamHelper.ReadBytes(AInStream, LFlags, 1);
  231. if (((LBCmp[0] * 256) + LFlags[0]) mod 31) <> 0 then begin
  232. raise EIdException.Create('Error - invalid header'); {do not localize} // TODO: add a resource string, and create a new Exception class for this
  233. end;
  234. TIdStreamHelper.ReadBytes(AInStream, LDict, 4);
  235. AInStream.Position := LOrgPos;
  236. InflateStream(AInStream, AOutStream);
  237. AInStream.Position := LOrgPos;
  238. end;
  239. function TIdZLibCompressorBase.GetIsReady: Boolean;
  240. begin
  241. Result := True;
  242. end;
  243. end.