Search code examples
indyindy10

compressing TIdMemoryBufferStream with TIdCompressorZLib


i am asking about the possibility of compressing TIdMemoryBufferStream Using TIdCompressorZLib how can it be done properly using the following code

procedure TClientThread.SendBuffer(Buffer: TIdBytes; BufferSize: Cardinal);
Var
Strm: TIdMemoryBufferStream;
IdCompressorZLib : TIdCompressorZLib;
begin

Strm := TIdMemoryBufferStream.Create(PByte(Buffer), BufferSize);
IdCompressorZLib := TIdCompressorZLib.Create(nil);
try
// then can't figure what the right process to do 
FTCP.Socket.WriteLn('Stream');
FTCP.Socket.LargeStream := True;
FTCP.Socket.Write(Strm, 0, True);
finally
FreeAndNil(Strm);
FreeAndNil(IdCompressorZLib);
end;

end;

i am not sure about the right process that needs to be done

as example should i create another variable as StrmB then calling the compress to it ?


Solution

  • The TIdCompressorZLib component is intended to be used only with the Compressor property of the TIdHTTP and TIdFTP components.

    For general purpose compression over a TCP connection, you can assign a TIdCompressionIntercept component to the TCP connection's IOHandler.Intercept property, eg:

    var
      Compressor : TIdCompressionIntercept;
    begin
      Compressor := TIdCompressionIntercept.Create(nil);
      try
        Compressor.CompressionLevel := 9;
        FTCP.Socket.Intercept := Compressor;
        try
          // any data written here will be compressed....
        finally
          FTCP.Socket.Intercept := nil;
        end;
      finally
        Compressor.Free;
      end;
    end;
    

    However, since you are sending the byte size of the compressed data (by setting the AWriteByteCount parameter to True in TIdIOHandler.Write(TStream)), that will not work with the compression intercept.

    Indy's IdZLib unit has a TCompressionStream class, and various ...CompressStream/Ex() functions, that you can use instead, eg:

    procedure TClientThread.SendBuffer(Buffer: TIdBytes; BufferSize: Cardinal);
    var
      Strm: TMemoryStream;
      Compressor : TCompressionStream;
    begin
      Strm := TMemoryStream.Create;
      try
        Compressor := TCompressionStream.Create(clMax, Strm, False);
        try
          WriteTIdBytesToStream(Compressor, Buffer, BufferSize);
        finally
          Compressor.Free;
        end;
    
        FTCP.Socket.WriteLn('Stream');
        FTCP.Socket.LargeStream := True;
        FTCP.Socket.Write(Strm, 0, True);
      finally
        Strm.Free;
      end;
    end;
    

    Or:

    procedure TClientThread.SendBuffer(Buffer: TIdBytes; BufferSize: Cardinal);
    var
      InStrm: TIdMemoryBufferStream;
      OutStrm: TMemoryStream;
    begin
      OutStrm := TMemoryStream.Create;
      try
        InStrm := TIdMemoryBufferStream.Create(PByte(Buffer), BufferSize);
        try
          CompressStreamEx(InStrm, OutStrm, clMax, zsZLib);
        finally
          InStrm.Free;
        end;
    
        FTCP.Socket.WriteLn('Stream');
        FTCP.Socket.LargeStream := True;
        FTCP.Socket.Write(OutStrm, 0, True);
      finally
        OutStrm.Free;
      end;
    end;