Changed to use the miniLZO compression library
This commit is contained in:
		@@ -31,341 +31,11 @@
 | 
			
		||||
 | 
			
		||||
#include "amxmodx.h"
 | 
			
		||||
#include "amxxfile.h"
 | 
			
		||||
/*****************
 | 
			
		||||
 ****** RLE ******
 | 
			
		||||
 *****************/
 | 
			
		||||
 | 
			
		||||
/*************************************************************************
 | 
			
		||||
* Name:        rle.c
 | 
			
		||||
* Author:      Marcus Geelnard
 | 
			
		||||
* Description: RLE coder/decoder implementation.
 | 
			
		||||
* Reentrant:   Yes
 | 
			
		||||
* $Id$
 | 
			
		||||
*
 | 
			
		||||
* RLE (Run Length Encoding) is the simplest possible lossless compression
 | 
			
		||||
* method. Nevertheless it serves a purpose, even in state of the art
 | 
			
		||||
* compression (it is used in JPEG compression, for instance). The basic
 | 
			
		||||
* principle is to identify sequences of equal bytes, and replace them with
 | 
			
		||||
* the byte in question and a repetition count (coded in some clever
 | 
			
		||||
* fashion).
 | 
			
		||||
*
 | 
			
		||||
* There are several different ways to do RLE. The particular method
 | 
			
		||||
* implemented here is a very efficient one. Instead of coding runs for
 | 
			
		||||
* both repeating and non-repeating sections, a special marker byte is
 | 
			
		||||
* used to indicate the start of a repeating section. Non-repeating
 | 
			
		||||
* sections can thus have any length without being interrupted by control
 | 
			
		||||
* bytes, except for the rare case when the special marker byte appears in
 | 
			
		||||
* the non-repeating section (which is coded with at most two bytes). For
 | 
			
		||||
* optimal efficiency, the marker byte is chosen as the least frequent
 | 
			
		||||
* (perhaps even non-existent) symbol in the input stream.
 | 
			
		||||
*
 | 
			
		||||
* Repeating runs can be as long as 32768 bytes. Runs shorter than 129
 | 
			
		||||
* bytes require three bytes for coding (marker + count + symbol), whereas
 | 
			
		||||
* runs longer than 128 bytes require four bytes for coding (marker +
 | 
			
		||||
* counthi|0x80 + countlo + symbol). This is normally a win in compression,
 | 
			
		||||
* and it's very seldom a loss of compression ratio compared to using a
 | 
			
		||||
* fixed coding of three bytes (which allows coding a run of 256 bytes in
 | 
			
		||||
* just three bytes).
 | 
			
		||||
*
 | 
			
		||||
* With this scheme, the worst case compression result is
 | 
			
		||||
* (257/256)*insize + 1.
 | 
			
		||||
*
 | 
			
		||||
*-------------------------------------------------------------------------
 | 
			
		||||
* Note: This code is based on the code found in "codrle2.c" and
 | 
			
		||||
* "dcodrle2.c" by David Bourgin, as described in "Introduction to the
 | 
			
		||||
* losslessy compression schemes", 1994. The main differences from Davids
 | 
			
		||||
* implementation are the addition of long (15-bit) run counts, the removal
 | 
			
		||||
* of file I/O (this implementation works solely with preallocated memory
 | 
			
		||||
* buffers), and that the code is now 100% reentrant.
 | 
			
		||||
*-------------------------------------------------------------------------
 | 
			
		||||
* Copyright (c) 2003-2004 Marcus Geelnard
 | 
			
		||||
*
 | 
			
		||||
* This software is provided 'as-is', without any express or implied
 | 
			
		||||
* warranty. In no event will the authors be held liable for any damages
 | 
			
		||||
* arising from the use of this software.
 | 
			
		||||
*
 | 
			
		||||
* Permission is granted to anyone to use this software for any purpose,
 | 
			
		||||
* including commercial applications, and to alter it and redistribute it
 | 
			
		||||
* freely, subject to the following restrictions:
 | 
			
		||||
*
 | 
			
		||||
* 1. The origin of this software must not be misrepresented; you must not
 | 
			
		||||
*    claim that you wrote the original software. If you use this software
 | 
			
		||||
*    in a product, an acknowledgment in the product documentation would
 | 
			
		||||
*    be appreciated but is not required.
 | 
			
		||||
*
 | 
			
		||||
* 2. Altered source versions must be plainly marked as such, and must not
 | 
			
		||||
*    be misrepresented as being the original software.
 | 
			
		||||
*
 | 
			
		||||
* 3. This notice may not be removed or altered from any source
 | 
			
		||||
*    distribution.
 | 
			
		||||
*
 | 
			
		||||
* Marcus Geelnard
 | 
			
		||||
* marcus.geelnard at home.se
 | 
			
		||||
*************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "amxxfile.h"
 | 
			
		||||
 | 
			
		||||
/*************************************************************************
 | 
			
		||||
*                           INTERNAL FUNCTIONS                           *
 | 
			
		||||
*************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************************************
 | 
			
		||||
* _RLE_WriteRep() - Encode a repetition of 'symbol' repeated 'count'
 | 
			
		||||
* times.
 | 
			
		||||
*************************************************************************/
 | 
			
		||||
 | 
			
		||||
void CAmxxReader::_RLE_WriteRep( unsigned char *out, unsigned int *outpos,
 | 
			
		||||
    unsigned char marker, unsigned char symbol, unsigned int count )
 | 
			
		||||
{
 | 
			
		||||
    unsigned int i, idx;
 | 
			
		||||
 | 
			
		||||
    idx = *outpos;
 | 
			
		||||
    if( count < 4 )
 | 
			
		||||
    {
 | 
			
		||||
        if( symbol == marker )
 | 
			
		||||
        {
 | 
			
		||||
            out[ idx ++ ] = marker;
 | 
			
		||||
            out[ idx ++ ] = count-1;
 | 
			
		||||
            if( count == 3 )
 | 
			
		||||
            {
 | 
			
		||||
                out[ idx ++ ] = marker;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            for( i = 0; i < count; ++ i )
 | 
			
		||||
            {
 | 
			
		||||
                out[ idx ++ ] = symbol;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        out[ idx ++ ] = marker;
 | 
			
		||||
        -- count;
 | 
			
		||||
        if( count >= 128 )
 | 
			
		||||
        {
 | 
			
		||||
            out[ idx ++ ] = (count >> 8) | 0x80;
 | 
			
		||||
        }
 | 
			
		||||
        out[ idx ++ ] = count & 0xff;
 | 
			
		||||
        out[ idx ++ ] = symbol;
 | 
			
		||||
    }
 | 
			
		||||
    *outpos = idx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************************************
 | 
			
		||||
* _RLE_WriteNonRep() - Encode a non-repeating symbol, 'symbol'. 'marker'
 | 
			
		||||
* is the marker symbol, and special care has to be taken for the case
 | 
			
		||||
* when 'symbol' == 'marker'.
 | 
			
		||||
*************************************************************************/
 | 
			
		||||
 | 
			
		||||
void CAmxxReader::_RLE_WriteNonRep( unsigned char *out, unsigned int *outpos,
 | 
			
		||||
    unsigned char marker, unsigned char symbol )
 | 
			
		||||
{
 | 
			
		||||
    unsigned int idx;
 | 
			
		||||
 | 
			
		||||
    idx = *outpos;
 | 
			
		||||
    if( symbol == marker )
 | 
			
		||||
    {
 | 
			
		||||
        out[ idx ++ ] = marker;
 | 
			
		||||
        out[ idx ++ ] = 0;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        out[ idx ++ ] = symbol;
 | 
			
		||||
    }
 | 
			
		||||
    *outpos = idx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************************************
 | 
			
		||||
*                            PUBLIC FUNCTIONS                            *
 | 
			
		||||
*************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************************************
 | 
			
		||||
* RLE_Compress() - Compress a block of data using an RLE coder.
 | 
			
		||||
*  in     - Input (uncompressed) buffer.
 | 
			
		||||
*  out    - Output (compressed) buffer. This buffer must be 0.4% larger
 | 
			
		||||
*           than the input buffer, plus one byte.
 | 
			
		||||
*  insize - Number of input bytes.
 | 
			
		||||
* The function returns the size of the compressed data.
 | 
			
		||||
*************************************************************************/
 | 
			
		||||
 | 
			
		||||
int CAmxxReader::RLE_Compress( unsigned char *in, unsigned char *out,
 | 
			
		||||
    unsigned int insize )
 | 
			
		||||
{
 | 
			
		||||
    unsigned char byte1, byte2, marker;
 | 
			
		||||
    unsigned int  inpos, outpos, count, i, histogram[ 256 ];
 | 
			
		||||
 | 
			
		||||
    /* Do we have anything to compress? */
 | 
			
		||||
    if( insize < 1 )
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Create histogram */
 | 
			
		||||
    for( i = 0; i < 256; ++ i )
 | 
			
		||||
    {
 | 
			
		||||
        histogram[ i ] = 0;
 | 
			
		||||
    }
 | 
			
		||||
    for( i = 0; i < insize; ++ i )
 | 
			
		||||
    {
 | 
			
		||||
        ++ histogram[ in[ i ] ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Find the least common byte, and use it as the repetition marker */
 | 
			
		||||
    marker = 0;
 | 
			
		||||
    for( i = 1; i < 256; ++ i )
 | 
			
		||||
    {
 | 
			
		||||
        if( histogram[ i ] < histogram[ marker ] )
 | 
			
		||||
        {
 | 
			
		||||
            marker = i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Remember the repetition marker for the decoder */
 | 
			
		||||
    out[ 0 ] = marker;
 | 
			
		||||
    outpos = 1;
 | 
			
		||||
 | 
			
		||||
    /* Start of compression */
 | 
			
		||||
    byte1 = in[ 0 ];
 | 
			
		||||
    inpos = 1;
 | 
			
		||||
    count = 1;
 | 
			
		||||
 | 
			
		||||
    /* Are there at least two bytes? */
 | 
			
		||||
    if( insize >= 2 )
 | 
			
		||||
    {
 | 
			
		||||
        byte2 = in[ inpos ++ ];
 | 
			
		||||
        count = 2;
 | 
			
		||||
 | 
			
		||||
        /* Main compression loop */
 | 
			
		||||
        do
 | 
			
		||||
        {
 | 
			
		||||
            if( byte1 == byte2 )
 | 
			
		||||
            {
 | 
			
		||||
                /* Do we meet only a sequence of identical bytes? */
 | 
			
		||||
                while( (inpos < insize) && (byte1 == byte2) &&
 | 
			
		||||
                       (count < 32768) )
 | 
			
		||||
                {
 | 
			
		||||
                    byte2 = in[ inpos ++ ];
 | 
			
		||||
                    ++ count;
 | 
			
		||||
                }
 | 
			
		||||
                if( byte1 == byte2 )
 | 
			
		||||
                {
 | 
			
		||||
                    _RLE_WriteRep( out, &outpos, marker, byte1, count );
 | 
			
		||||
                    if( inpos < insize )
 | 
			
		||||
                    {
 | 
			
		||||
                        byte1 = in[ inpos ++ ];
 | 
			
		||||
                        count = 1;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        count = 0;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    _RLE_WriteRep( out, &outpos, marker, byte1, count-1 );
 | 
			
		||||
                    byte1 = byte2;
 | 
			
		||||
                    count = 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                /* No, then don't handle the last byte */
 | 
			
		||||
                _RLE_WriteNonRep( out, &outpos, marker, byte1 );
 | 
			
		||||
                byte1 = byte2;
 | 
			
		||||
                count = 1;
 | 
			
		||||
            }
 | 
			
		||||
            if( inpos < insize )
 | 
			
		||||
            {
 | 
			
		||||
                byte2 = in[ inpos ++ ];
 | 
			
		||||
                count = 2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        while( (inpos < insize) || (count >= 2) );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* One byte left? */
 | 
			
		||||
    if( count == 1 )
 | 
			
		||||
    {
 | 
			
		||||
        _RLE_WriteNonRep( out, &outpos, marker, byte1 );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return outpos;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************************************
 | 
			
		||||
* RLE_Uncompress() - Uncompress a block of data using an RLE decoder.
 | 
			
		||||
*  in      - Input (compressed) buffer.
 | 
			
		||||
*  out     - Output (uncompressed) buffer. This buffer must be large
 | 
			
		||||
*            enough to hold the uncompressed data.
 | 
			
		||||
*  insize  - Number of input bytes.
 | 
			
		||||
*************************************************************************/
 | 
			
		||||
 | 
			
		||||
void CAmxxReader::RLE_Uncompress( unsigned char *in, unsigned char *out,
 | 
			
		||||
    unsigned int insize )
 | 
			
		||||
{
 | 
			
		||||
    unsigned char marker, symbol;
 | 
			
		||||
    unsigned int  i, inpos, outpos, count;
 | 
			
		||||
 | 
			
		||||
    /* Do we have anything to compress? */
 | 
			
		||||
    if( insize < 1 )
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Get marker symbol from input stream */
 | 
			
		||||
    inpos = 0;
 | 
			
		||||
    marker = in[ inpos ++ ];
 | 
			
		||||
 | 
			
		||||
    /* Main decompression loop */
 | 
			
		||||
    outpos = 0;
 | 
			
		||||
    do
 | 
			
		||||
    {
 | 
			
		||||
        symbol = in[ inpos ++ ];
 | 
			
		||||
        if( symbol == marker )
 | 
			
		||||
        {
 | 
			
		||||
            /* We had a marker byte */
 | 
			
		||||
            count = in[ inpos ++ ];
 | 
			
		||||
            if( count < 3 )
 | 
			
		||||
            {
 | 
			
		||||
                for( i = 0; i <= count; ++ i )
 | 
			
		||||
                {
 | 
			
		||||
                    out[ outpos ++ ] = marker;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if( count & 0x80 )
 | 
			
		||||
                {
 | 
			
		||||
                    count = ((count & 0x7f) << 8) + in[ inpos ++ ];
 | 
			
		||||
                }
 | 
			
		||||
                symbol = in[ inpos ++ ];
 | 
			
		||||
                for( i = 0; i <= count; ++ i )
 | 
			
		||||
                {
 | 
			
		||||
                    out[ outpos ++ ] = symbol;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            /* No marker, plain copy */
 | 
			
		||||
            out[ outpos ++ ] = symbol;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while( inpos < insize );
 | 
			
		||||
} 
 | 
			
		||||
#include "minilzo/minilzo.h"
 | 
			
		||||
 | 
			
		||||
/**********************
 | 
			
		||||
 ****** AMXXFILE ******
 | 
			
		||||
 **********************/
 | 
			
		||||
 | 
			
		||||
#if defined __GNUC__
 | 
			
		||||
  #define PACKED        __attribute__((packed))
 | 
			
		||||
#else
 | 
			
		||||
@@ -381,6 +51,13 @@ void CAmxxReader::RLE_Uncompress( unsigned char *in, unsigned char *out,
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct TableEntry
 | 
			
		||||
{
 | 
			
		||||
	CAmxxReader::mint8_t cellSize PACKED;
 | 
			
		||||
	CAmxxReader::mint32_t origSize PACKED;			// contains AMX_HEADER->stp
 | 
			
		||||
	CAmxxReader::mint32_t offset PACKED;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define DATAREAD(addr, itemsize, itemcount) \
 | 
			
		||||
	if (fread((addr), (itemsize), (itemcount), (m_pFile)) != (itemcount)) \
 | 
			
		||||
	{ \
 | 
			
		||||
@@ -403,6 +80,14 @@ CAmxxReader::CAmxxReader(const char *filename, int cellsize)
 | 
			
		||||
 | 
			
		||||
	m_Status = Err_None;
 | 
			
		||||
	m_CellSize = cellsize;
 | 
			
		||||
 | 
			
		||||
	// Make sure the decompressor runs
 | 
			
		||||
	if (lzo_init() != LZO_E_OK)
 | 
			
		||||
	{
 | 
			
		||||
		m_Status = Err_DecompressorInit;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_pFile = fopen(filename, "rb");
 | 
			
		||||
	if (!m_pFile)
 | 
			
		||||
	{
 | 
			
		||||
@@ -567,9 +252,17 @@ CAmxxReader::Error CAmxxReader::GetSection(void *buffer)
 | 
			
		||||
	fseek(m_pFile, entry.offset, SEEK_SET);
 | 
			
		||||
 | 
			
		||||
	// read the data to a temporary buffer
 | 
			
		||||
	char *tempBuffer = new char[m_SectionLength + 1];
 | 
			
		||||
	DATAREAD(static_cast<void*>(tempBuffer), 1, m_SectionLength);
 | 
			
		||||
	lzo_byte *tempBuffer = new lzo_byte[m_SectionLength + 1];
 | 
			
		||||
	DATAREAD((void*)tempBuffer, 1, m_SectionLength);
 | 
			
		||||
	// decompress
 | 
			
		||||
	RLE_Uncompress((unsigned char*)tempBuffer, (unsigned char*)(buffer), m_SectionLength);
 | 
			
		||||
	lzo_uint destLen = GetBufferSize();
 | 
			
		||||
	int result = lzo1x_decompress_safe(tempBuffer, m_SectionLength,
 | 
			
		||||
			(lzo_byte*)buffer, &destLen,
 | 
			
		||||
			NULL /*unused*/ );
 | 
			
		||||
	if (result != LZO_E_OK)
 | 
			
		||||
	{
 | 
			
		||||
		m_Status = Err_Decompress;
 | 
			
		||||
		return Err_Decompress;
 | 
			
		||||
	}
 | 
			
		||||
	return Err_None;
 | 
			
		||||
}
 | 
			
		||||
@@ -42,30 +42,16 @@ public:
 | 
			
		||||
		Err_FileOpen,
 | 
			
		||||
		Err_FileRead,
 | 
			
		||||
		Err_FileInvalid,
 | 
			
		||||
		Err_SectionNotFound
 | 
			
		||||
		Err_SectionNotFound,
 | 
			
		||||
		Err_DecompressorInit,
 | 
			
		||||
		Err_Decompress
 | 
			
		||||
	};
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	typedef char		mint8_t;
 | 
			
		||||
	typedef short		mint16_t;
 | 
			
		||||
	typedef long		mint32_t;
 | 
			
		||||
 | 
			
		||||
	struct TableEntry
 | 
			
		||||
	{
 | 
			
		||||
		mint8_t cellSize;
 | 
			
		||||
		mint32_t origSize;			// contains AMX_HEADER->stp
 | 
			
		||||
		mint32_t offset;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// These functions don't access members
 | 
			
		||||
	static void _RLE_WriteRep(unsigned char *out, unsigned int *outpos,
 | 
			
		||||
		unsigned char marker, unsigned char symbol, unsigned int count);
 | 
			
		||||
	static void _RLE_WriteNonRep(unsigned char *out, unsigned int *outpos,
 | 
			
		||||
		unsigned char marker, unsigned char symbol);
 | 
			
		||||
	static int RLE_Compress(unsigned char *in, unsigned char *out,
 | 
			
		||||
		unsigned int insize);
 | 
			
		||||
	static void RLE_Uncompress(unsigned char *in, unsigned char *out,
 | 
			
		||||
		unsigned int insize);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Error m_Status;
 | 
			
		||||
	FILE *m_pFile;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user