数年没发帖了,上来特别提醒DELPHI用户注意这个问题。在调用System.ZLib.ZDecompressStream时,某些情况可能陷入死循环,无法退出。
procedure ZDecompressStream(inStream, outStream: TStream);
const
  bufferSize = 32768;
var
  zstream: TZStreamRec;
  zresult: Integer;
  inBuffer: TBytes;
  outBuffer: TBytes;
  inSize: Integer;
  outSize: Integer;
begin
  SetLength(inBuffer, BufferSize);
  SetLength(outBuffer, BufferSize);
  FillChar(zstream, SizeOf(TZStreamRec), 0);  ZDecompressCheck(InflateInit(zstream));  try
    inSize := inStream.Read(inBuffer, bufferSize);
    while inSize > 0 do
    begin
      zstream.next_in := @inBuffer[0];
      zstream.avail_in := inSize;      repeat
        zstream.next_out := @outBuffer[0];
        zstream.avail_out := bufferSize;        ZDecompressCheckWithoutBufferError(inflate(zstream, Z_NO_FLUSH));        outSize := bufferSize - zstream.avail_out;        outStream.Write(outBuffer, outSize);
      until (zstream.avail_in = 0) and (zstream.avail_out > 0);      inSize := inStream.Read(inBuffer, bufferSize);
    end;    repeat
      zstream.next_out := @outBuffer[0];
      zstream.avail_out := bufferSize;      zresult := ZDecompressCheckWithoutBufferError(inflate(zstream, Z_FINISH));  <--------------      outSize := bufferSize - zstream.avail_out;      outStream.Write(outBuffer, outSize);
    until (zresult = Z_STREAM_END) and (zstream.avail_out > 0);
  finally
    ZDecompressCheck(inflateEnd(zstream));
  end;
end;
function ZDecompressCheckWithoutBufferError(code: Integer): Integer; overload;
begin
  Result := code;  if code < 0 then
    if (code <> Z_BUF_ERROR) then <------------罪魁祸首
     raise EZDecompressionError.Create(string(_z_errmsg[2 - code]));
end;尚不清楚XE 10.2.3的ZLib代码为什么在code = Z_BUF_ERROR的时候,不抛出异常。导致的后果是一直在repeat中死循环。

解决方案 »

  1.   

    再看DELPHI 2010的ZLib库,完全OK
    procedure ZDecompressStream(inStream, outStream: TStream);
    const
      bufferSize = 32768;
    var
      zstream: TZStreamRec;
      zresult: Integer;
      inBuffer: array[0..bufferSize - 1] of AnsiChar;
      outBuffer: array[0..bufferSize - 1] of AnsiChar;
      inSize: Integer;
      outSize: Integer;
    begin
      FillChar(zstream, SizeOf(TZStreamRec), 0);  ZCompressCheck(InflateInit(zstream));  inSize := inStream.Read(inBuffer, bufferSize);  while inSize > 0 do
      begin
        zstream.next_in := inBuffer;
        zstream.avail_in := inSize;    repeat
          zstream.next_out := outBuffer;
          zstream.avail_out := bufferSize;      ZCompressCheck(inflate(zstream, Z_NO_FLUSH));      // outSize := zstream.next_out - outBuffer;
          outSize := bufferSize - zstream.avail_out;      outStream.Write(outBuffer, outSize);
        until (zstream.avail_in = 0) and (zstream.avail_out > 0);    inSize := inStream.Read(inBuffer, bufferSize);
      end;  repeat
        zstream.next_out := outBuffer;
        zstream.avail_out := bufferSize;    zresult := ZCompressCheck(inflate(zstream, Z_FINISH));    // outSize := zstream.next_out - outBuffer;
        outSize := bufferSize - zstream.avail_out;    outStream.Write(outBuffer, outSize);
      until (zresult = Z_STREAM_END) and (zstream.avail_out > 0);  ZCompressCheck(inflateEnd(zstream));
    end;
    function ZCompressCheck(code: Integer): Integer;
    begin
      result := code;  if code < 0 then
      begin
        raise EZCompressionError.Create(_z_errmsg[2 - code]);
      end;
    end;function ZDecompressCheck(code: Integer): Integer;
    begin
      Result := code;  if code < 0 then
      begin
        raise EZDecompressionError.Create(_z_errmsg[2 - code]);
      end;
    end;
      

  2.   

    也欢迎你贴不同DELPHI版本的ZLib函数代码出来,看看哪些版本可能存在这个问题。
      

  3.   

     if (code <> Z_BUF_ERROR) then <------------罪魁祸首
         raise EZDecompressionError.Create(string(_z_errmsg[2 - code]));  上面应当是if code = Z_BUF_ERROR)  then
      raise EZDecompressionError.Create(string(_z_errmsg[2 - code]));  
    逻辑上才行得通
      

  4.   

    Z_BUF_ERROR只是一个警告,而不是一个错误,意思是解压缩后的数据块的大小超过了缓冲区的大小了,但解压缩还能正常进行。
    你的问题估计是其他原因导致的。
      

  5.   

    没有BUG,ZDecompressCheckWithoutBufferError,就是忽略Z_BUF_ERROR
      

  6.   

    旧版本里面不排除Z_BUF_ERROR这个警告信息才是BUG。现在Delphi 10.3里面的Indy idCompressorZLib.pas还有这个BUG
      

  7.   

    QuickReport 5.06 Pro Delphi XE8   这个控件在xe8中稳定 吗?初学者。谢谢!
      

  8.   

    COPY Code Examples  代码,TZCompressionStream生成的zip,7Z居然说是无效的文件。
      

  9.   

    那只是zlib压缩后输出的二进制数据,不代表ZIP文件格式,ZIP除了压缩算法之外还有自己的文件格式(文件头),你把zip文件的文件头删掉看看7zip能不能识别?