Platon Technologies
not logged in Login Registration
EnglishSlovak
open source software development celebrating 10 years of open source development! Friday, April 19, 2024

File: [Platon] / libplaton / platon / compress / lz-rle.c (download)

Revision 1.1, Mon Jan 5 10:48:32 2004 UTC (20 years, 3 months ago) by nepto

Added implementation of RLE and LZ/RLE compression algorithms.

#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/
Copyright © 2002-2006 Platon Group
Site powered by Metafox CMS
Go to Top