Changed to use the miniLZO compression library

This commit is contained in:
Pavol Marko 2004-07-22 13:05:03 +00:00
parent 1a9d55a0f4
commit b7e9f34471
2 changed files with 32 additions and 353 deletions

View File

@ -31,341 +31,11 @@
#include "amxmodx.h" #include "amxmodx.h"
#include "amxxfile.h" #include "amxxfile.h"
/***************** #include "minilzo/minilzo.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 );
}
/********************** /**********************
****** AMXXFILE ****** ****** AMXXFILE ******
**********************/ **********************/
#if defined __GNUC__ #if defined __GNUC__
#define PACKED __attribute__((packed)) #define PACKED __attribute__((packed))
#else #else
@ -381,6 +51,13 @@ void CAmxxReader::RLE_Uncompress( unsigned char *in, unsigned char *out,
#endif #endif
#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) \ #define DATAREAD(addr, itemsize, itemcount) \
if (fread((addr), (itemsize), (itemcount), (m_pFile)) != (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_Status = Err_None;
m_CellSize = cellsize; m_CellSize = cellsize;
// Make sure the decompressor runs
if (lzo_init() != LZO_E_OK)
{
m_Status = Err_DecompressorInit;
return;
}
m_pFile = fopen(filename, "rb"); m_pFile = fopen(filename, "rb");
if (!m_pFile) if (!m_pFile)
{ {
@ -567,9 +252,17 @@ CAmxxReader::Error CAmxxReader::GetSection(void *buffer)
fseek(m_pFile, entry.offset, SEEK_SET); fseek(m_pFile, entry.offset, SEEK_SET);
// read the data to a temporary buffer // read the data to a temporary buffer
char *tempBuffer = new char[m_SectionLength + 1]; lzo_byte *tempBuffer = new lzo_byte[m_SectionLength + 1];
DATAREAD(static_cast<void*>(tempBuffer), 1, m_SectionLength); DATAREAD((void*)tempBuffer, 1, m_SectionLength);
// decompress // 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; return Err_None;
} }

View File

@ -42,30 +42,16 @@ public:
Err_FileOpen, Err_FileOpen,
Err_FileRead, Err_FileRead,
Err_FileInvalid, Err_FileInvalid,
Err_SectionNotFound Err_SectionNotFound,
Err_DecompressorInit,
Err_Decompress
}; };
private:
typedef char mint8_t; typedef char mint8_t;
typedef short mint16_t; typedef short mint16_t;
typedef long mint32_t; typedef long mint32_t;
struct TableEntry private:
{
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);
Error m_Status; Error m_Status;
FILE *m_pFile; FILE *m_pFile;