#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <platon/compress/lz-rle.h>
/*
* Finds a match for the bytes at the specified offset.
*/
static int get_match (const unsigned char *source, int ptr, int source_size,
int *hash, int *size, int *pos)
{
int hash_value;
hash_value = (int) (40543L * (int) ((((source [ptr] << 4) ^
source [ptr + 1]) << 4) ^
source [ptr + 2]) >> 4) & 0xfff;
*pos = hash [hash_value];
hash [hash_value] = ptr;
if ((int) ((*pos != -1) && ((ptr - *pos)) < 4096U))
{
for (*size = 0;; (*size)++)
if ((*size >= 18)
|| ((int) (ptr + *size) >= source_size)
|| (source [ptr + *size] != source [*pos + *size]))
break;
return (int) (*size >= 3);
}
return 0;
}
int PLATON_FUNC(compress_lz_rle)(src, dst, src_size)
const unsigned char *src;
unsigned char *dst;
int src_size;
{
static int
Hash [4096];
int SymbolAddress;
int Key;
int Size;
int Bit = 0;
int Command = 0;
int src_index = 0;
int dst_size = 3;
int HeaderIndex = 1;
dst [0] = COMPRESS_LZ_RLE_COMPRESS;
for (Key = 0; Key < 4096; Key++)
Hash [Key] = -1;
while ((src_index < src_size) && (dst_size <= src_size))
{
if (Bit > 15)
{
dst [HeaderIndex] = (int) ((Command >> 8) & 0x00ff);
dst [HeaderIndex + 1] = (int) ( Command & 0x00ff);
HeaderIndex = dst_size;
dst_size += 2;
Bit = 0;
}
for (Size = 1;; Size++)
if ((int) (src_index + Size) >= src_size
|| (src [src_index] != src [src_index + Size])
|| (Size >= 0x0fff))
break;
if (Size >= 16)
{
dst [dst_size++] = 0;
dst [dst_size++] = (int) (((int) (Size - 16) >> 8) & 0x00ff);
dst [dst_size++] = (int) ((Size - 16) & 0x00ff);
dst [dst_size++] = src [src_index];
src_index += Size;
Command = (Command << 1) + 1;
}
else
if (get_match (src, src_index, src_size,
Hash, &Size, &SymbolAddress) != 0)
{
Key = ((src_index - SymbolAddress) << 4) + (Size - 3);
dst [dst_size++] = (int) ((Key >> 8) & 0x00ff);
dst [dst_size++] = (int) (Key & 0x00ff);
src_index += Size;
Command = (Command << 1) + 1;
}
else
{
dst [dst_size++] = src [src_index++];
Command = (Command << 1);
}
Bit++;
}
Command <<= (16 - Bit);
dst [HeaderIndex] = (int) ((Command >> 8) & 0x00ff);
dst [HeaderIndex + 1] = (int) ( Command & 0x00ff);
if (dst_size > src_size)
{
for (dst_size = 0; dst_size < src_size; dst_size++)
dst [dst_size + 1] = src [dst_size];
dst [0] = COMPRESS_LZ_RLE_COPY;
return (src_size + 1);
}
return (dst_size);
}
int
PLATON_FUNC(uncompress_lz_rle)(src, dst, src_size)
const unsigned char *src;
unsigned char *dst;
int src_size;
{
int SymbolAddress;
int ChunkSize;
int Counter;
int Command = 0;
int src_index = 1;
int dst_size = 0;
int Bit = 0;
if (src [0] == COMPRESS_LZ_RLE_COPY)
{
for (dst_size = 1; dst_size < src_size; dst_size++)
dst [dst_size - 1] = src [dst_size];
return (src_size - 1);
}
while (src_index < src_size)
{
if (Bit == 0)
{
Command = src [src_index++] << 8;
Command += src [src_index++];
Bit = 16;
}
if (Command & 0x8000)
{
SymbolAddress = (int) (src [src_index++] << 4);
SymbolAddress += (int) (src [src_index] >> 4);
if (SymbolAddress)
{
ChunkSize = (int) (src [src_index++] & 0x0f) + 3;
SymbolAddress = dst_size - SymbolAddress;
for (Counter = 0; Counter < ChunkSize; Counter++)
dst [dst_size++] = dst [SymbolAddress++];
}
else
{
ChunkSize = (int) (src [src_index++] << 8);
ChunkSize += (int) (src [src_index++] + 16);
for (Counter = 0; Counter < ChunkSize; Counter++)
dst [dst_size++] = src [src_index];
src_index++;
}
}
else
dst [dst_size++] = src [src_index++];
Command <<= 1;
Bit--;
}
return (dst_size);
}
Platon Group <platon@platon.org> http://platon.org/
|