home *** CD-ROM | disk | FTP | other *** search
/ Freelog 11 / Freelog011.iso / Bas / Compression / ZLib / contrib / delphi2 / zlib.pas < prev    next >
Pascal/Delphi Source File  |  1998-06-19  |  17KB  |  535 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {       Delphi Supplemental Components                  }
  4. {       ZLIB Data Compression Interface Unit            }
  5. {                                                       }
  6. {       Copyright (c) 1997 Borland International        }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. { Modified for zlib 1.1.3 by Davide Moretti <dave@rimini.com }
  11.  
  12. unit zlib;
  13.  
  14. interface
  15.  
  16. uses Sysutils, Classes;
  17.  
  18. type
  19.   TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer;
  20.   TFree = procedure (AppData, Block: Pointer);
  21.  
  22.   // Internal structure.  Ignore.
  23.   TZStreamRec = packed record
  24.     next_in: PChar;       // next input byte
  25.     avail_in: Integer;    // number of bytes available at next_in
  26.     total_in: Integer;    // total nb of input bytes read so far
  27.  
  28.     next_out: PChar;      // next output byte should be put here
  29.     avail_out: Integer;   // remaining free space at next_out
  30.     total_out: Integer;   // total nb of bytes output so far
  31.  
  32.     msg: PChar;           // last error message, NULL if no error
  33.     internal: Pointer;    // not visible by applications
  34.  
  35.     zalloc: TAlloc;       // used to allocate the internal state
  36.     zfree: TFree;         // used to free the internal state
  37.     AppData: Pointer;     // private data object passed to zalloc and zfree
  38.  
  39.     data_type: Integer;   //  best guess about the data type: ascii or binary
  40.     adler: Integer;       // adler32 value of the uncompressed data
  41.     reserved: Integer;    // reserved for future use
  42.   end;
  43.  
  44.   // Abstract ancestor class
  45.   TCustomZlibStream = class(TStream)
  46.   private
  47.     FStrm: TStream;
  48.     FStrmPos: Integer;
  49.     FOnProgress: TNotifyEvent;
  50.     FZRec: TZStreamRec;
  51.     FBuffer: array [Word] of Char;
  52.   protected
  53.     procedure Progress(Sender: TObject); dynamic;
  54.     property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
  55.     constructor Create(Strm: TStream);
  56.   end;
  57.  
  58. { TCompressionStream compresses data on the fly as data is written to it, and
  59.   stores the compressed data to another stream.
  60.  
  61.   TCompressionStream is write-only and strictly sequential. Reading from the
  62.   stream will raise an exception. Using Seek to move the stream pointer
  63.   will raise an exception.
  64.  
  65.   Output data is cached internally, written to the output stream only when
  66.   the internal output buffer is full.  All pending output data is flushed
  67.   when the stream is destroyed.
  68.  
  69.   The Position property returns the number of uncompressed bytes of
  70.   data that have been written to the stream so far.
  71.  
  72.   CompressionRate returns the on-the-fly percentage by which the original
  73.   data has been compressed:  (1 - (CompressedBytes / UncompressedBytes)) * 100
  74.   If raw data size = 100 and compressed data size = 25, the CompressionRate
  75.   is 75%
  76.  
  77.   The OnProgress event is called each time the output buffer is filled and
  78.   written to the output stream.  This is useful for updating a progress
  79.   indicator when you are writing a large chunk of data to the compression
  80.   stream in a single call.}
  81.  
  82.  
  83.   TCompressionLevel = (clNone, clFastest, clDefault, clMax);
  84.  
  85.   TCompressionStream = class(TCustomZlibStream)
  86.   private
  87.     function GetCompressionRate: Single;
  88.   public
  89.     constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
  90.     destructor Destroy; override;
  91.     function Read(var Buffer; Count: Longint): Longint; override;
  92.     function Write(const Buffer; Count: Longint): Longint; override;
  93.     function Seek(Offset: Longint; Origin: Word): Longint; override;
  94.     property CompressionRate: Single read GetCompressionRate;
  95.     property OnProgress;
  96.   end;
  97.  
  98. { TDecompressionStream decompresses data on the fly as data is read from it.
  99.  
  100.   Compressed data comes from a separate source stream.  TDecompressionStream
  101.   is read-only and unidirectional; you can seek forward in the stream, but not
  102.   backwards.  The special case of setting the stream position to zero is
  103.   allowed.  Seeking forward decompresses data until the requested position in
  104.   the uncompressed data has been reached.  Seeking backwards, seeking relative
  105.   to the end of the stream, requesting the size of the stream, and writing to
  106.   the stream will raise an exception.
  107.  
  108.   The Position property returns the number of bytes of uncompressed data that
  109.   have been read from the stream so far.
  110.  
  111.   The OnProgress event is called each time the internal input buffer of
  112.   compressed data is exhausted and the next block is read from the input stream.
  113.   This is useful for updating a progress indicator when you are reading a
  114.   large chunk of data from the decompression stream in a single call.}
  115.  
  116.   TDecompressionStream = class(TCustomZlibStream)
  117.   public
  118.     constructor Create(Source: TStream);
  119.     destructor Destroy; override;
  120.     function Read(var Buffer; Count: Longint): Longint; override;
  121.     function Write(const Buffer; Count: Longint): Longint; override;
  122.     function Seek(Offset: Longint; Origin: Word): Longint; override;
  123.     property OnProgress;
  124.   end;
  125.  
  126.  
  127.  
  128. { CompressBuf compresses data, buffer to buffer, in one call.
  129.    In: InBuf = ptr to compressed data
  130.        InBytes = number of bytes in InBuf
  131.   Out: OutBuf = ptr to newly allocated buffer containing decompressed data
  132.        OutBytes = number of bytes in OutBuf   }
  133. procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
  134.                       out OutBuf: Pointer; out OutBytes: Integer);
  135.  
  136.  
  137. { DecompressBuf decompresses data, buffer to buffer, in one call.
  138.    In: InBuf = ptr to compressed data
  139.        InBytes = number of bytes in InBuf
  140.        OutEstimate = zero, or est. size of the decompressed data
  141.   Out: OutBuf = ptr to newly allocated buffer containing decompressed data
  142.        OutBytes = number of bytes in OutBuf   }
  143. procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
  144.  OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
  145.  
  146. const
  147.   zlib_version = '1.1.3';
  148.  
  149. type
  150.   EZlibError = class(Exception);
  151.   ECompressionError = class(EZlibError);
  152.   EDecompressionError = class(EZlibError);
  153.  
  154. function adler32(adler: Integer; buf: PChar; len: Integer): Integer;
  155.  
  156. implementation
  157.  
  158. const
  159.   Z_NO_FLUSH      = 0;
  160.   Z_PARTIAL_FLUSH = 1;
  161.   Z_SYNC_FLUSH    = 2;
  162.   Z_FULL_FLUSH    = 3;
  163.   Z_FINISH        = 4;
  164.  
  165.   Z_OK            = 0;
  166.   Z_STREAM_END    = 1;
  167.   Z_NEED_DICT     = 2;
  168.   Z_ERRNO         = (-1);
  169.   Z_STREAM_ERROR  = (-2);
  170.   Z_DATA_ERROR    = (-3);
  171.   Z_MEM_ERROR     = (-4);
  172.   Z_BUF_ERROR     = (-5);
  173.   Z_VERSION_ERROR = (-6);
  174.  
  175.   Z_NO_COMPRESSION       =   0;
  176.   Z_BEST_SPEED           =   1;
  177.   Z_BEST_COMPRESSION     =   9;
  178.   Z_DEFAULT_COMPRESSION  = (-1);
  179.  
  180.   Z_FILTERED            = 1;
  181.   Z_HUFFMAN_ONLY        = 2;
  182.   Z_DEFAULT_STRATEGY    = 0;
  183.  
  184.   Z_BINARY   = 0;
  185.   Z_ASCII    = 1;
  186.   Z_UNKNOWN  = 2;
  187.  
  188.   Z_DEFLATED = 8;
  189.  
  190.   _z_errmsg: array[0..9] of PChar = (
  191.     'need dictionary',      // Z_NEED_DICT      (2)
  192.     'stream end',           // Z_STREAM_END     (1)
  193.     '',                     // Z_OK             (0)
  194.     'file error',           // Z_ERRNO          (-1)
  195.     'stream error',         // Z_STREAM_ERROR   (-2)
  196.     'data error',           // Z_DATA_ERROR     (-3)
  197.     'insufficient memory',  // Z_MEM_ERROR      (-4)
  198.     'buffer error',         // Z_BUF_ERROR      (-5)
  199.     'incompatible version', // Z_VERSION_ERROR  (-6)
  200.     ''
  201.   );
  202.  
  203. {$L deflate.obj}
  204. {$L inflate.obj}
  205. {$L inftrees.obj}
  206. {$L trees.obj}
  207. {$L adler32.obj}
  208. {$L infblock.obj}
  209. {$L infcodes.obj}
  210. {$L infutil.obj}
  211. {$L inffast.obj}
  212.  
  213. procedure _tr_init; external;
  214. procedure _tr_tally; external;
  215. procedure _tr_flush_block; external;
  216. procedure _tr_align; external;
  217. procedure _tr_stored_block; external;
  218. function adler32; external;
  219. procedure inflate_blocks_new; external;
  220. procedure inflate_blocks; external;
  221. procedure inflate_blocks_reset; external;
  222. procedure inflate_blocks_free; external;
  223. procedure inflate_set_dictionary; external;
  224. procedure inflate_trees_bits; external;
  225. procedure inflate_trees_dynamic; external;
  226. procedure inflate_trees_fixed; external;
  227. procedure inflate_codes_new; external;
  228. procedure inflate_codes; external;
  229. procedure inflate_codes_free; external;
  230. procedure _inflate_mask; external;
  231. procedure inflate_flush; external;
  232. procedure inflate_fast; external;
  233.  
  234. procedure _memset(P: Pointer; B: Byte; count: Integer);cdecl;
  235. begin
  236.   FillChar(P^, count, B);
  237. end;
  238.  
  239. procedure _memcpy(dest, source: Pointer; count: Integer);cdecl;
  240. begin
  241.   Move(source^, dest^, count);
  242. end;
  243.  
  244.  
  245.  
  246. // deflate compresses data
  247. function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
  248.   recsize: Integer): Integer; external;
  249. function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
  250. function deflateEnd(var strm: TZStreamRec): Integer; external;
  251.  
  252. // inflate decompresses data
  253. function inflateInit_(var strm: TZStreamRec; version: PChar;
  254.   recsize: Integer): Integer; external;
  255. function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
  256. function inflateEnd(var strm: TZStreamRec): Integer; external;
  257. function inflateReset(var strm: TZStreamRec): Integer; external;
  258.  
  259.  
  260. function zcalloc(AppData: Pointer; Items, Size: Integer): Pointer;
  261. begin
  262.   GetMem(Result, Items*Size);
  263. end;
  264.  
  265. procedure zcfree(AppData, Block: Pointer);
  266. begin
  267.   FreeMem(Block);
  268. end;
  269.  
  270. function zlibCheck(code: Integer): Integer;
  271. begin
  272.   Result := code;
  273.   if code < 0 then
  274.     raise EZlibError.Create('error');    //!!
  275. end;
  276.  
  277. function CCheck(code: Integer): Integer;
  278. begin
  279.   Result := code;
  280.   if code < 0 then
  281.     raise ECompressionError.Create('error'); //!!
  282. end;
  283.  
  284. function DCheck(code: Integer): Integer;
  285. begin
  286.   Result := code;
  287.   if code < 0 then
  288.     raise EDecompressionError.Create('error');  //!!
  289. end;
  290.  
  291. procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
  292.                       out OutBuf: Pointer; out OutBytes: Integer);
  293. var
  294.   strm: TZStreamRec;
  295.   P: Pointer;
  296. begin
  297.   FillChar(strm, sizeof(strm), 0);
  298.   OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
  299.   GetMem(OutBuf, OutBytes);
  300.   try
  301.     strm.next_in := InBuf;
  302.     strm.avail_in := InBytes;
  303.     strm.next_out := OutBuf;
  304.     strm.avail_out := OutBytes;
  305.     CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
  306.     try
  307.       while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
  308.       begin
  309.         P := OutBuf;
  310.         Inc(OutBytes, 256);
  311.         ReallocMem(OutBuf, OutBytes);
  312.         strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
  313.         strm.avail_out := 256;
  314.       end;
  315.     finally
  316.       CCheck(deflateEnd(strm));
  317.     end;
  318.     ReallocMem(OutBuf, strm.total_out);
  319.     OutBytes := strm.total_out;
  320.   except
  321.     FreeMem(OutBuf);
  322.     raise
  323.   end;
  324. end;
  325.  
  326.  
  327. procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
  328.   OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
  329. var
  330.   strm: TZStreamRec;
  331.   P: Pointer;
  332.   BufInc: Integer;
  333. begin
  334.   FillChar(strm, sizeof(strm), 0);
  335.   BufInc := (InBytes + 255) and not 255;
  336.   if OutEstimate = 0 then
  337.     OutBytes := BufInc
  338.   else
  339.     OutBytes := OutEstimate;
  340.   GetMem(OutBuf, OutBytes);
  341.   try
  342.     strm.next_in := InBuf;
  343.     strm.avail_in := InBytes;
  344.     strm.next_out := OutBuf;
  345.     strm.avail_out := OutBytes;
  346.     DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
  347.     try
  348.       while DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END do
  349.       begin
  350.         P := OutBuf;
  351.         Inc(OutBytes, BufInc);
  352.         ReallocMem(OutBuf, OutBytes);
  353.         strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
  354.         strm.avail_out := BufInc;
  355.       end;
  356.     finally
  357.       DCheck(inflateEnd(strm));
  358.     end;
  359.     ReallocMem(OutBuf, strm.total_out);
  360.     OutBytes := strm.total_out;
  361.   except
  362.     FreeMem(OutBuf);
  363.     raise
  364.   end;
  365. end;
  366.  
  367.  
  368. // TCustomZlibStream
  369.  
  370. constructor TCustomZLibStream.Create(Strm: TStream);
  371. begin
  372.   inherited Create;
  373.   FStrm := Strm;
  374.   FStrmPos := Strm.Position;
  375. end;
  376.  
  377. procedure TCustomZLibStream.Progress(Sender: TObject);
  378. begin
  379.   if Assigned(FOnProgress) then FOnProgress(Sender);
  380. end;
  381.  
  382.  
  383. // TCompressionStream
  384.  
  385. constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
  386.   Dest: TStream);
  387. const
  388.   Levels: array [TCompressionLevel] of ShortInt =
  389.     (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
  390. begin
  391.   inherited Create(Dest);
  392.   FZRec.next_out := FBuffer;
  393.   FZRec.avail_out := sizeof(FBuffer);
  394.   CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
  395. end;
  396.  
  397. destructor TCompressionStream.Destroy;
  398. begin
  399.   FZRec.next_in := nil;
  400.   FZRec.avail_in := 0;
  401.   try
  402.     if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
  403.     while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
  404.       and (FZRec.avail_out = 0) do
  405.     begin
  406.       FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
  407.       FZRec.next_out := FBuffer;
  408.       FZRec.avail_out := sizeof(FBuffer);
  409.     end;
  410.     if FZRec.avail_out < sizeof(FBuffer) then
  411.       FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
  412.   finally
  413.     deflateEnd(FZRec);
  414.   end;
  415.   inherited Destroy;
  416. end;
  417.  
  418. function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
  419. begin
  420.   raise ECompressionError.Create('Invalid stream operation');
  421. end;
  422.  
  423. function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
  424. begin
  425.   FZRec.next_in := @Buffer;
  426.   FZRec.avail_in := Count;
  427.   if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
  428.   while (FZRec.avail_in > 0) do
  429.   begin
  430.     CCheck(deflate(FZRec, 0));
  431.     if FZRec.avail_out = 0 then
  432.     begin
  433.       FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
  434.       FZRec.next_out := FBuffer;
  435.       FZRec.avail_out := sizeof(FBuffer);
  436.       FStrmPos := FStrm.Position;
  437.       Progress(Self);
  438.     end;
  439.   end;
  440.   Result := Count;
  441. end;
  442.  
  443. function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
  444. begin
  445.   if (Offset = 0) and (Origin = soFromCurrent) then
  446.     Result := FZRec.total_in
  447.   else
  448.     raise ECompressionError.Create('Invalid stream operation');
  449. end;
  450.  
  451. function TCompressionStream.GetCompressionRate: Single;
  452. begin
  453.   if FZRec.total_in = 0 then
  454.     Result := 0
  455.   else
  456.     Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
  457. end;
  458.  
  459.  
  460. // TDecompressionStream
  461.  
  462. constructor TDecompressionStream.Create(Source: TStream);
  463. begin
  464.   inherited Create(Source);
  465.   FZRec.next_in := FBuffer;
  466.   FZRec.avail_in := 0;
  467.   DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
  468. end;
  469.  
  470. destructor TDecompressionStream.Destroy;
  471. begin
  472.   inflateEnd(FZRec);
  473.   inherited Destroy;
  474. end;
  475.  
  476. function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
  477. begin
  478.   FZRec.next_out := @Buffer;
  479.   FZRec.avail_out := Count;
  480.   if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
  481.   while (FZRec.avail_out > 0) do
  482.   begin
  483.     if FZRec.avail_in = 0 then
  484.     begin
  485.       FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
  486.       if FZRec.avail_in = 0 then
  487.         begin
  488.           Result := Count - FZRec.avail_out;
  489.           Exit;
  490.         end;
  491.       FZRec.next_in := FBuffer;
  492.       FStrmPos := FStrm.Position;
  493.       Progress(Self);
  494.     end;
  495.     DCheck(inflate(FZRec, 0));
  496.   end;
  497.   Result := Count;
  498. end;
  499.  
  500. function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
  501. begin
  502.   raise EDecompressionError.Create('Invalid stream operation');
  503. end;
  504.  
  505. function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
  506. var
  507.   I: Integer;
  508.   Buf: array [0..4095] of Char;
  509. begin
  510.   if (Offset = 0) and (Origin = soFromBeginning) then
  511.   begin
  512.     DCheck(inflateReset(FZRec));
  513.     FZRec.next_in := FBuffer;
  514.     FZRec.avail_in := 0;
  515.     FStrm.Position := 0;
  516.     FStrmPos := 0;
  517.   end
  518.   else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
  519.           ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
  520.   begin
  521.     if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
  522.     if Offset > 0 then
  523.     begin
  524.       for I := 1 to Offset div sizeof(Buf) do
  525.         ReadBuffer(Buf, sizeof(Buf));
  526.       ReadBuffer(Buf, Offset mod sizeof(Buf));
  527.     end;
  528.   end
  529.   else
  530.     raise EDecompressionError.Create('Invalid stream operation');
  531.   Result := FZRec.total_out;
  532. end;
  533.  
  534. end.
  535.