TPWM compression

From ModdingWiki
Jump to navigation Jump to search

TPWM stands for Turbo Packer by Wolfgang Meyerle. This relatively unknown compression tool was released for the Amiga and Atari ST in the late 1980s and was used by BlueByte (Ubisoft) to compress the data files of many of their games from the early 1990s. Files compressed with this packer can be easily recognized by an ID string "TPWM" directly at the beginning of the file. This ID string is followed by four bytes, which is the size of the unpacked data and then the packed data itself. The size of the packed data thus results from the file size - 8; The packing algorithm shortens repeating byte sequences with a length between 3 and 18 bytes to 2 bytes. In these 2 bytes, the length of the sequence and the relative offset (max. 0xFFF bytes) is recorded. Longer sequences are accordingly composed of several such bytes with unpacking information. All other byte sequences remain unchanged. In order to determine during unpacking where in the packed file an unpacking information is located instead of normal data bytes, the packer inserts an extra byte whose bits for the next 8 bytes indicate whether they are data bytes or unpacking information.

Here is an example of an unpack routine as C code:

int Unpack_TPWM()
{
  unsigned char  b1,b2;
  unsigned short packbyte;
  int            bit, i;
  unsigned long  input_offset;
  unsigned long  output_offset;
  unsigned int   distance;
  unsigned int   length;


  output_offset = 0;
  input_offset = 0;


  while ((input_offset < pack_size) && (output_offset < unpacked_size))
  {
   packbyte = Input_Buffer[input_offset];
   input_offset++;

   for (bit = 0; bit <= 7; bit++)
   {
     if ((output_offset >= unpacked_size) || (input_offset >= packed_size)) break;
     packbyte *= 2;

     if (packbyte > 0xFF)
     {
       packbyte &= 0x00FF;
       b1 = Input_Buffer[input_offset];
       
       input_offset++;       
       if (input_offset > packed_size) break;
       
       length = (b1 & 0x000F)+2;

       b2 = Input_Buffer[input_offset];
       input_offset++;
       
       distance = b2 | ((b1 << 4) & 0x0F00);

       for (i = 0; i <= length; i++)
       {	  
         Output_Buffer[output_offset] = Output_Buffer[output_offset-distance];
         output_offset++;
         if (output_offset >= unpacked_size) break;
       }
     }
     else
     {      
       Output_Buffer[output_offset] = Input_Buffer[input_offset];
       input_offset++;
       output_offset++;
     }
   }
  }

  if (output_offset < unpacked_size)
    return -1;
  else
    return 0;
}

Source:

Article by the author of Turbo Packer in the German Atari ST Magazin TOS, issue 10/1990. [1]