Lempel-Ziv-Welch (LZW) Compression
Site Map Feedback

Download:

Up LZW

Store LZW Compressed Data

This is a small suite of simple compression classes that use the LZW algorithm optionally using the GIF coding format.
Unisys patented the LZW algorithm, but the patent has now expired and you are free to use this algorithm without license.
They were designed to store short text messages efficiently.
You can specify a File or a CString or an area of memory for each class to act upon.
The Encoder can be told to create GIF codes in the Stream.
The Decoder automatically decodes GIF or normal LZW.
The code has the following behaviour:

The simplest way to use a CString to hold the data.
Here's example code for some of the constructors:
  CString S("anna and nanna banned bananas and bandannas");
  S+=S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S+S;
  int Length=S.GetLength();
  CLZWEncoder E(S);
  // S is now the compressed data (or the original data if no compression was possible).
  DWORD CompressedLength=S.GetLength(); // At this point: note the leading 0xFF Byte. S may contain NULLs before its end. GetLength returns the correct length for the compressed data.
  if((BYTE)*S==0xFF) {
    DWORD UnCompressedLength=*((DWORD*)(&*S+1)); //You can access the UnCompressed data Length from the compressed code
  }
  CLZWDecoder D(S);
  //S is now back to the original data or empty if it ran out of memory or the data was corrupt.
  if(S.IsEmpty() && CompressedLength) AfxMessageBox("LZW Decompression Failed");
  if(Length!=S.GetLength()) AfxMessageBox("LZW Decompression lost Byte(s)");
A file is specified simply by its Path, a section of memory by its Base and Length.
  CLZWEncoder Encoder1;
  const char* src="anna and nanna banned bananas and bandannas";
  DWORD UnCompressedLength=strlen(src)+1; // +1 to include the NULL terminator.
  char* LZW=new char[UnCompressedLength];
  S=Encoder1.Encode(src, UnCompressedLength, LZW, UnCompressedLength);
  if(!S.IsEmpty()) AfxMessageBox(S);
  else{
    CompressedLength=Encoder1.GetOutSize();
    double Ratio=UnCompressedLength+1./CompressedLength;
    CLZWDecoder Decoder1;
    char* dst=LZW; //start assuming no compression happened, so destination is the same as the source.
    if((BYTE)*LZW==0xFF) { // Decoding is necessary
      ASSERT(UnCompressedLength==*((DWORD*)(LZW+1))); //You can access the UnCompressed data Length from the compressed code
      dst=new char[UnCompressedLength];
      Decoder1.Decode(LZW, CompressedLength, dst, UnCompressedLength);
      ASSERT(strcmp(src,dst)==0);
      delete dst;
  } }
  delete LZW;

  DeleteFile("ReadMeNow.txt");
  CLZWEncoder Encoder2;
  Encoder2.Encode("ReadMe.txt", "ReadMe.lzw"); // You could use a memory buffer instead of the .lzw file
  CLZWDecoder Decoder2;
  Decoder2.Decode("ReadMe.lzw", "ReadMeNow.txt");
The bulk of the code handles the input/output, the compression and decompression are short sections of code.
If you remove the GIF decoding block, the Decoder involves very little code: it should be very clear and easy to alter.