0

I all, I remember you my question about ZLib problems.... Delphi XE and ZLib Problems

David Heffernan put me on the way with his excellent answer (Thanks again @David)...

Summarizing the answer ... "This flow for the compressor looks like this: string -> UTF-8 bytes -> compressed bytes -> base64 string. Obviously you reverse the arrows to decompress."

I don't know I must post it in the same post or i must append a new question like this...

Well, I was working last weekend...

I followed the flow string -> UTF-8 bytes -> compressed bytes -> base64 string

This is the compress function and it works...

function CompressStrToCode64Str(const aText: string; aCompressionLevel: TZCompressionLevel): string;
var
  strStreamIN,
  strStreamOUT: TStringStream;
begin
  result := '';
  /// Putting the string received to a Stream.
  strStreamIN := TStringStream.Create(aText, TEncoding.UTF8);
  try
    /// Creating the output stream for compression.
    strStreamOUT := TStringStream.Create('', TEncoding.UTF8);
    try
      /// Compressing streamIN to streamOUT
      ZCompressStream(strStreamIN, strStreamOUT, aCompressionLevel);
      /// Encoding to base64 for string handling.
      result := string(EncodeBase64(strStreamOUT, strStreamOUT.Size));
    finally
      strStreamOUT.Free;
    end;
  finally
    strStreamIN.Free;
  end;
end;

and this is the Uncompress functions... but it doesn't works... (returns empty string)

function TForm1.Code64StrToUncompressStr(Const aText: string): string;
var
  strStreamIN,
  strStreamOUT: TStringStream;
  data: TBytes;
begin
  result := '';
  /// Creating the input stream.
  strStreamIN := TStringStream.Create('', TEncoding.UTF8);
  try
    /// Decoding base64 of received string to a TBytes
    data := DecodeBase64(ansistring(aText));
    /// Putting the TBytes to a Stream
    strStreamIN.Write(data[0], Length(data));
    /// Creating uncompressed stream
    strStreamOUT := TStringStream.Create('', TEncoding.UTF8);
    try
      /// Decompressing streamIN to StreamOUT
      ZDeCompressStream(strStreamIN, strStreamOUT);
      result := strStreamOUT.DataString;
    finally
      strStreamOUT.Free;
    end;
  finally
    strStreamIN.Free;
  end;
end;

Some idea why doesn't work the uncompress function. It returns an empty string. TIA for your patience.

Community
  • 1
  • 1
JosepMaria
  • 99
  • 1
  • 10

1 Answers1

2

This is what I had in mind:

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, ZLib, EncdDecd;

function CompressAndEncodeString(const Str: string): string;
var
  Utf8Stream: TStringStream;
  Compressed: TMemoryStream;
  Base64Stream: TStringStream;
begin
  Utf8Stream := TStringStream.Create(Str, TEncoding.UTF8);
  try
    Compressed := TMemoryStream.Create;
    try
      ZCompressStream(Utf8Stream, Compressed);
      Compressed.Position := 0;
      Base64Stream := TStringStream.Create('', TEncoding.ASCII);
      try
        EncodeStream(Compressed, Base64Stream);
        Result := Base64Stream.DataString;
      finally
        Base64Stream.Free;
      end;
    finally
      Compressed.Free;
    end;
  finally
    Utf8Stream.Free;
  end;
end;

function DecodeAndDecompressString(const Str: string): string;
var
  Utf8Stream: TStringStream;
  Compressed: TMemoryStream;
  Base64Stream: TStringStream;
begin
  Base64Stream := TStringStream.Create(Str, TEncoding.ASCII);
  try
    Compressed := TMemoryStream.Create;
    try
      DecodeStream(Base64Stream, Compressed);
      Compressed.Position := 0;
      Utf8Stream := TStringStream.Create('', TEncoding.UTF8);
      try
        ZDecompressStream(Compressed, Utf8Stream);
        Result := Utf8Stream.DataString;
      finally
        Utf8Stream.Free;
      end;
    finally
      Compressed.Free;
    end;
  finally
    Base64Stream.Free;
  end;
end;

var
  EncodedAndCompressed: AnsiString;

begin
  EncodedAndCompressed := CompressAndEncodeString('ZLib, Utf-8, compression test');
  Writeln(EncodedAndCompressed);
  Writeln(DecodeAndDecompressString(EncodedAndCompressed));
  Readln;
end.

Output

eJyL8slM0lEILUnTtdBRSM7PLShKLS7OzM9TKEktLgEAjjwKMA==
ZLib, Utf-8, compression test

As you can see, by the time you include base64, it is not really compression. It might be compression with a larger input string. That's why I think you are better to transmit binary, as I explained in your previous question.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Many thanks again @David. I see I must use ASCII encoding for base64...I must convert it to base64 to send the compressed text inside a CDATA in a XML and don't have problems with codepage, and I must try it with large strings to see if the length goes down... – JosepMaria Feb 25 '14 at 09:28
  • @JosepMaria Actually any 8 bit encoding that contains ASCII would work. So you could use any ANSI encoding, or UTF-8. But ASCII is semantically correct. If you need it in CDATA then base 64 is probably the best option. I expect that with larger strings you will get compression. – David Heffernan Feb 25 '14 at 09:41
  • I've ended the tests and runs very very fine!! In large messages of 41KB are reduced to 8KB; And in medium messages of 12KB are reduced to 3KB... between 70% and 80% of compression!!! is amazing!! Thanks a lot again, not only for the code, thanks to teach me (us) about streams and encoding... – JosepMaria Feb 25 '14 at 10:04
  • You are welcome. I have to say it is a delight to answer questions from somebody who wants to learn and understand. It is not uncommon to find askers here on SO that care only about getting code that works and who have no desire to understand it. I know I did not explain anything here, but I think the answer goes hand in hand with my previous answer which does seek to explain. – David Heffernan Feb 25 '14 at 10:08