Files
harbour-core/harbour/source/rdd/hbsix/sxcompr.c
Przemyslaw Czerpak 271095b949 2007-05-03 16:10 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/common.mak
  * harbour/include/hbapirdd.h
  - harbour/include/hbrddwrk.h
  * harbour/source/rdd/Makefile
  + harbour/source/rdd/wacore.c
  + harbour/source/rdd/wafunc.c
  * harbour/source/rdd/workarea.c
    * cleaned RDD code:
      * the default work area implementation from which each RDD inherits
        and RDD management is now in workarea.c file - this part will be
        common for all threads in future MT version
      * the code to mange workareas and aliases moved to wacore.c - this
        code uses some static variables which will be moved to HVM stack
        in MT version
      * helper RDD functions thread independent moved to wafunc.c

  * harbour/source/rdd/dbcmd.c
    * removed RDD/WorkArea management code - only independent HB_FUNCs
      left. IMHO it will be good to divide this file into few ones.
    * changed dbCreate() and dbUseArea() to return logical value

  * harbour/config/global.cf
    - removed nulsys from linked library list - it should not be here
      because it can confuse some linkers and wrong library will be
      created

  * harbour/contrib/rdd_ads/ads1.c
  * harbour/source/rdd/dbf1.c
  * harbour/source/rdd/delim1.c
  * harbour/source/rdd/sdf1.c
  * harbour/source/rdd/dbfcdx/dbfcdx1.c
  * harbour/source/rdd/dbfdbt/dbfdbt1.c
  * harbour/source/rdd/dbffpt/dbffpt1.c
  * harbour/source/rdd/dbfntx/dbfntx1.c
  * harbour/source/rdd/nulsys/nulsys.c
    * updated for recent modifications in RDD API

  * harbour/include/hbextern.ch
    - removed __RDDSETDEFAULT() - this function was necessary with old
      rdd register code and we not not need it for few years. It's not
      Clipper function so I do not see any reason to keep it but if you
      want we can add wrapper to standard RDDSETDEFAULT()

  * harbour/source/rdd/hbsix/sxcompr.c
    + added workaround for SIX3 bug which I intentionally replicated in
      [x]Harbour but it may cause data corruption so IMHO it will be better
      to fix it.

  * harbour/source/rtl/errorsys.prg
    * added default action for EG_LOCK - it's Clipper compatible behavior
      but done in differ way. Due to some differences in linker we are
      using we cannot exactly replicate Clipper behavior because it will
      not work on some platforms as expected so I decided to add it here.
      I think it's even more Clear then the trick with source/sys/ntxerr.prg
      done by Clipper. Many people do not even knows about it.

  * harbour/source/rtl/gtcrs/chrmap.c
    * changed environment variable name from HB_CHRMAP to HB_CHARMAP to
      be compatible with description in default map file
2007-05-03 14:11:30 +00:00

748 lines
24 KiB
C

/*
* $Id$
*/
/*
* xHarbour Project source code:
* SIX compatible functions:
* hb_LZSSxCompressMem()
* hb_LZSSxDecompressMem()
* hb_LZSSxCompressFile()
* hb_LZSSxDecompressFile()
*
* SX_FCOMPRESS
* SX_FDECOMPRESS
* _SX_STRDECOMPRESS
* _SX_STRCOMPRESS
*
* Copyright 2005 Przemyslaw Czerpak <druzus@acn.waw.pl>
* www - http://www.xharbour.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
/*
SIX uses modified version of LZSS algorithm.
It uses 12 bits for position offset in ring buffer and 4 bits for the
match length. LZSS is modified version of LZ77 algorithm which can store
original bytes from input string instead of position and match length in
the ring buffer when the match length does not reach some limit. In SIX
the minimum match length is 3 and it is used to increase to match length
in 4 bit offset by adding 3 also so the efective maximum match length is
18. Of course we have to store the information about the type of item in
compressed data to know it is (offset+length) pair or simple byte.
SIX put 1 byte in compressed data which inform about the type of next
8 items: bit set to 1 means normal byte, 0 means item pair.
The funny thing is that SIX seems to effectively use only 11 bits ring
buffer (2048 bytes size). I still do not know why. Maybe it was a hack
for some problems with implementation of encoding or work around for
a bug in some signed/unsigned value conversions? Or maybe someone
wanted to reduce memory overhead in used algorithm for finding the
longest match? The SIX was written for 16-bit DOS and the memory
consumption was important though it should not be too much. They
documented ~9KB increasing the ring buffer size should be linear to
other used (helper) structures.
The next interesting thing is that it dynamically overwrites the ring
buffer with stream data and does not use any separate look ahead buffers.
This fact suggests that SIX uses some simple implementation with
greedy early parsing and does not look for optimal matches.
Our algorithm has to make the same with the ring buffer to be compatible.
UPDATE: Using smaller ring buffer without increasing the match pointer
suggested me that it is possible that someone didn't understand it fully
and modified already existing algorithm. I spend a while with a google
looking for old LZSS implementations and I've found it. IMHO in 99%
this code is used in SIX. This is lzss.c file written by Haruhiko Okumura
with the following note in header:
,---------------------------------------------------------
| Use, distribute, and modify this program freely.
| Please send me your improved versions.
`---------------------------------------------------------
This LZSS implementation gives exactly the same results as SIX when we
change the ring buffer size (#define N 4096 //in the head of this file)
to 2048. So I used exactly the same algorithm with binary tree for
finding the longest match. The code may looks a little bit differ then
in lzss.c because I've already implement most of it before I found
this file and I didn't want to remove it but the original author is
Haruhiko Okumura. The text above allow us use it in [x]Harbour.
This version isn't for sure improved due to SIX modifications so I do
not think I should send it to him. IMHO it is also less usable for
other things then strict SIX compatibility - we already have much
stronger compressions in ZLIB.
After the LZSS compression the result could be longer then original
strings. It looks that SIX return original string when the compressed
one is longer then original + 253. I do not like it because there is
no marker which informs if string was compressed or not and calling
decompression procedure for uncompressed data gives broken results.
I do not want to make the same.
When file is compressed then SIX put the uncompressed file size in
first four bytes. Similar situation is with string returned by
sx_compress() - first four bytes is uncompressed size in little
endian order. This has to be done in upper level functions,
hb_LZSSxCompressMem() and hb_LZSSxCompressFile() intentionally
do not do that.
*/
#include "hbsxfunc.h"
#define HB_SX_UNCOMPRESED 0xFFFFFFFFUL
/* number of bits for encoded item (position,length) */
#define ITEMBITS 16
/* unused DUMMY bits - who does know why SIX has it? */
#define DUMMYBITS 1
/* number of bits for position offset */
#define OFFSETBITS (12 - DUMMYBITS)
/* the minimum match length to encode as new position */
#define MINLENGTH 3
/* number of bits for match length, 1 bit reserved for ITEM type */
#define LENGTHBITS ( ITEMBITS - OFFSETBITS - DUMMYBITS )
/* the maximum match length we can encode in LENGTHBITS */
#define MAXLENGTH ( ( 1 << LENGTHBITS ) + MINLENGTH - 1 )
/* size of ring buffer */
#define RBUFLENGTH ( 1 << OFFSETBITS )
/* the bit mask for ring buffer */
#define RBUFMASK ( ( 1 << OFFSETBITS ) - 1 )
/* the bit mask for match length */
#define MATCHMASK ( ( 1 << LENGTHBITS ) - 1 )
/* get ringbuffer index */
#define RBUFINDEX(i) ( ( i ) & RBUFMASK )
/* get ring buffer offset position from low and high bytes */
#define LZSS_OFFSET(l, h) ( (l) | ( (h & ~MATCHMASK) << ( 8 - LENGTHBITS ) ) )
/* get match length from low and high byte */
#define LZSS_LENGTH(l, h) ( ( (h) & MATCHMASK ) + MINLENGTH )
/* create compressed item from match position and length */
#define LZSS_ITEM(o, l) ( ( (o) << LENGTHBITS ) | ( (l) - MINLENGTH ) )
/* create low byte of compressed item */
#define LZSS_ITMLO(o, l) ( ( BYTE ) (o) )
/* create high byte of compressed item */
#define LZSS_ITMHI(o, l) ( ( BYTE ) ( ( ( (o) >> ( 8 - LENGTHBITS ) ) & ~MATCHMASK ) | \
( (l) - MINLENGTH ) ) )
/* maximum size of item set: byte with item type bits plus 8 items */
#define ITEMSETSIZE ( ( ITEMBITS << 3 ) + 1 )
/* the size of IO buffer for file (de)compression */
#define LZSS_IOBUFLEN 8192
/* uninitialized (dummy) node in compression trees */
#define DUMMYNODE RBUFLENGTH
typedef struct _HB_LZSSX_COMPR
{
FHANDLE hInput;
BYTE * inBuffer;
ULONG inBuffSize;
ULONG inBuffPos;
ULONG inBuffRead;
BOOL fInFree;
FHANDLE hOutput;
BYTE * outBuffer;
ULONG outBuffSize;
ULONG outBuffPos;
BOOL fOutFree;
ULONG ulMaxSize;
ULONG ulOutSize;
BOOL fResult;
BOOL fContinue;
BYTE ring_buffer[ RBUFLENGTH + MAXLENGTH - 1 ];
SHORT match_offset;
SHORT match_length;
SHORT parent[ RBUFLENGTH + 1 ];
SHORT left [ RBUFLENGTH + 1 ];
SHORT right [ RBUFLENGTH + 257 ];
}
HB_LZSSX_COMPR;
typedef HB_LZSSX_COMPR * PHB_LZSSX_COMPR;
static void hb_LZSSxExit( PHB_LZSSX_COMPR pCompr )
{
if( pCompr->fInFree )
hb_xfree( pCompr->inBuffer );
if( pCompr->fOutFree )
hb_xfree( pCompr->outBuffer );
hb_xfree( pCompr );
}
static PHB_LZSSX_COMPR hb_LZSSxInit(
FHANDLE hInput, BYTE * pSrcBuf, ULONG ulSrcBuf,
FHANDLE hOutput, BYTE * pDstBuf, ULONG ulDstBuf )
{
PHB_LZSSX_COMPR pCompr = ( PHB_LZSSX_COMPR ) hb_xgrab( sizeof( HB_LZSSX_COMPR ) );
if( hInput != FS_ERROR && ulSrcBuf == 0 )
ulSrcBuf = LZSS_IOBUFLEN;
if( hOutput != FS_ERROR && ulDstBuf == 0 )
ulDstBuf = LZSS_IOBUFLEN;
pCompr->hInput = hInput;
pCompr->inBuffer = pSrcBuf;
pCompr->inBuffSize = ulSrcBuf;
pCompr->inBuffPos = 0;
pCompr->inBuffRead = ( hInput == FS_ERROR ) ? ulSrcBuf : 0;
pCompr->fInFree = ( hInput != FS_ERROR && pSrcBuf == NULL );
pCompr->hOutput = hOutput;
pCompr->outBuffer = pDstBuf;
pCompr->outBuffSize = ulDstBuf;
pCompr->outBuffPos = 0;
pCompr->fOutFree = ( hOutput != FS_ERROR && pDstBuf == NULL );
pCompr->ulMaxSize = 0;
pCompr->ulOutSize = 0;
pCompr->fResult = TRUE;
pCompr->fContinue = FALSE;
if( pCompr->fInFree )
pCompr->inBuffer = ( BYTE * ) hb_xgrab( ulDstBuf );
if( pCompr->fOutFree )
pCompr->outBuffer = ( BYTE * ) hb_xgrab( ulDstBuf );
/* initialize the ring buffer with spaces, because SIX uses
dynamic ring buffer then we do not have to fill last MAXLENGTH
characters */
memset( pCompr->ring_buffer, ' ', RBUFLENGTH - MAXLENGTH );
return pCompr;
}
static BOOL hb_LZSSxFlush( PHB_LZSSX_COMPR pCompr )
{
if( pCompr->fResult && pCompr->hOutput != FS_ERROR )
{
if( hb_fsWriteLarge( pCompr->hOutput, pCompr->outBuffer,
pCompr->outBuffPos ) != pCompr->outBuffPos )
{
pCompr->fResult = FALSE;
}
else
{
pCompr->ulOutSize += pCompr->outBuffPos;
pCompr->outBuffPos = 0;
}
}
return pCompr->fResult;
}
static BOOL hb_LZSSxWrite( PHB_LZSSX_COMPR pCompr, BYTE bVal )
{
if( pCompr->fResult )
{
if( pCompr->outBuffPos == pCompr->outBuffSize )
hb_LZSSxFlush( pCompr );
if( pCompr->outBuffPos < pCompr->outBuffSize )
pCompr->outBuffer[pCompr->outBuffPos] = bVal;
else
pCompr->fResult = FALSE;
}
pCompr->outBuffPos++;
return pCompr->fResult || pCompr->fContinue;
}
static int hb_LZSSxRead( PHB_LZSSX_COMPR pCompr )
{
if( pCompr->inBuffPos < pCompr->inBuffRead )
return pCompr->inBuffer[ pCompr->inBuffPos++ ];
if( pCompr->hInput != FS_ERROR )
{
pCompr->inBuffRead = hb_fsReadLarge( pCompr->hInput, pCompr->inBuffer,
pCompr->inBuffSize );
pCompr->inBuffPos = 0;
if( pCompr->inBuffPos < pCompr->inBuffRead )
return pCompr->inBuffer[ pCompr->inBuffPos++ ];
}
return -1;
}
static BOOL hb_LZSSxDecode( PHB_LZSSX_COMPR pCompr )
{
BOOL fResult = TRUE;
USHORT itemMask;
int offset, length, index, c, h;
index = RBUFLENGTH - MAXLENGTH;
itemMask = 0;
do
{
itemMask >>= 1;
/* Is the next character bitfield with type of next 8 items ? */
if( ( itemMask & 0x0100 ) == 0 )
{
if( ( c = hb_LZSSxRead( pCompr ) ) == -1 )
break;
/* simple trick to reduce number of shift operations */
itemMask = c | 0xff00;
}
if( ( c = hb_LZSSxRead( pCompr ) ) == -1 )
break;
if( itemMask & 1 ) /* Is the next character normal byte ? */
{
if( ! hb_LZSSxWrite( pCompr, ( BYTE ) c ) )
{
fResult = FALSE;
break;
}
pCompr->ring_buffer[ index ] = ( BYTE ) c;
index = RBUFINDEX( index + 1 );
}
else /* we have an item pair (ring buffer offset : match length) */
{
if( ( h = hb_LZSSxRead( pCompr ) ) == -1 )
{
/* fResult = FALSE; */
break;
}
offset = LZSS_OFFSET( c, h ); /* get offset to ring buffer */
length = LZSS_LENGTH( c, h ); /* get match length */
for( h = 0; h < length; h++ )
{
c = pCompr->ring_buffer[ RBUFINDEX( offset + h ) ];
if( ! hb_LZSSxWrite( pCompr, ( BYTE ) c ) )
{
fResult = FALSE;
break;
}
/* SIX does not use additional buffers and dynamically
overwrite the ring buffer - we have to make exactly
the same or our results will be differ when
abs( offset - index ) < length */
pCompr->ring_buffer[ index ] = ( BYTE ) c;
index = RBUFINDEX( index + 1 );
}
}
}
while( fResult );
if( fResult )
fResult = hb_LZSSxFlush( pCompr );
return fResult;
}
static void hb_LZSSxNodeInsert( PHB_LZSSX_COMPR pCompr, int r )
{
int i, p, cmp;
unsigned char *key;
cmp = 1;
key = &pCompr->ring_buffer[ r ];
p = RBUFLENGTH + 1 + key[ 0 ];
pCompr->right[ r ] = pCompr->left[ r ] = DUMMYNODE;
pCompr->match_length = 0;
for( ; ; )
{
if( cmp >= 0 )
{
if( pCompr->right[ p ] != DUMMYNODE )
p = pCompr->right[ p ];
else
{
pCompr->right[ p ] = r;
pCompr->parent[ r ] = p;
return;
}
}
else
{
if( pCompr->left[ p ] != DUMMYNODE )
p = pCompr->left[ p ];
else
{
pCompr->left[ p ] = r;
pCompr->parent[ r ] = p;
return;
}
}
for( i = 1; i < MAXLENGTH; i++ )
{
if( ( cmp = key[ i ] - pCompr->ring_buffer[ p + i ] ) != 0 )
break;
}
if( i > pCompr->match_length )
{
pCompr->match_offset = p;
pCompr->match_length = i;
if( i >= MAXLENGTH )
break;
}
}
pCompr->parent[ r ] = pCompr->parent[ p ];
pCompr->left[ r ] = pCompr->left[ p ];
pCompr->right[ r ] = pCompr->right[ p ];
pCompr->parent[ pCompr->left[ p ] ] = r;
pCompr->parent[ pCompr->right[ p ] ] = r;
if( pCompr->right[ pCompr->parent[ p ] ] == p )
pCompr->right[ pCompr->parent[ p ] ] = r;
else
pCompr->left[ pCompr->parent[ p ] ] = r;
pCompr->parent[ p ] = DUMMYNODE;
}
static void hb_LZSSxNodeDelete( PHB_LZSSX_COMPR pCompr, int p )
{
if( pCompr->parent[ p ] != DUMMYNODE )
{
int q;
if( pCompr->right[ p ] == DUMMYNODE )
q = pCompr->left[ p ];
else if( pCompr->left[ p ] == DUMMYNODE )
q = pCompr->right[ p ];
else
{
q = pCompr->left[ p ];
if( pCompr->right[ q ] != DUMMYNODE )
{
do
{
q = pCompr->right[ q ];
}
while( pCompr->right[ q ] != DUMMYNODE );
pCompr->right[ pCompr->parent[ q ] ] = pCompr->left[ q ];
pCompr->parent[ pCompr->left[ q ] ] = pCompr->parent[ q ];
pCompr->left[ q ] = pCompr->left[ p ];
pCompr->parent[ pCompr->left[ p ] ] = q;
}
pCompr->right[ q ] = pCompr->right[ p ];
pCompr->parent[ pCompr->right[ p ] ] = q;
}
pCompr->parent[ q ] = pCompr->parent[ p ];
if( pCompr->right[ pCompr->parent[ p ] ] == p )
pCompr->right[ pCompr->parent[ p ] ] = q;
else
pCompr->left[ pCompr->parent[ p ] ] = q;
pCompr->parent[ p ] = DUMMYNODE;
}
}
static ULONG hb_LZSSxEncode( PHB_LZSSX_COMPR pCompr )
{
BYTE itemSet[ITEMSETSIZE];
BYTE itemMask;
ULONG ulSize = 0;
int iItem;
short int i, c, len, r, s, last_match_length;
for( i = RBUFLENGTH + 1; i < RBUFLENGTH + 257; i++ )
pCompr->right[i] = DUMMYNODE;
for( i = 0; i < RBUFLENGTH; i++ )
pCompr->parent[ i ] = DUMMYNODE;
itemSet[ 0 ] = 0;
iItem = itemMask = 1;
s = 0;
r = RBUFLENGTH - MAXLENGTH;
for( len = 0; len < MAXLENGTH; len++ )
{
if( ( c = hb_LZSSxRead( pCompr ) ) == -1 )
break;
pCompr->ring_buffer[ r + len ] = ( BYTE ) c;
}
if( len == 0 )
return ulSize;
for( i = 1; i <= MAXLENGTH; i++ )
hb_LZSSxNodeInsert( pCompr, r - i );
hb_LZSSxNodeInsert( pCompr, r );
do
{
if( pCompr->match_length > len )
pCompr->match_length = len;
if( pCompr->match_length < MINLENGTH )
{
pCompr->match_length = 1;
itemSet[ 0 ] |= itemMask;
itemSet[ iItem++ ] = pCompr->ring_buffer[ r ];
}
else
{
itemSet[iItem++] = LZSS_ITMLO( pCompr->match_offset,
pCompr->match_length );
itemSet[iItem++] = LZSS_ITMHI( pCompr->match_offset,
pCompr->match_length );
}
if( ( itemMask <<= 1 ) == 0 )
{
for( i = 0; i < iItem; i++ )
{
if( !hb_LZSSxWrite( pCompr, itemSet[ i ] ) )
return ( ULONG ) -1;
}
ulSize += iItem;
itemSet[ 0 ] = 0;
iItem = itemMask = 1;
}
last_match_length = pCompr->match_length;
for( i = 0; i < last_match_length &&
( c = hb_LZSSxRead( pCompr ) ) != -1; i++ )
{
hb_LZSSxNodeDelete( pCompr, s );
pCompr->ring_buffer[ s ] = ( BYTE ) c;
if( s < MAXLENGTH - 1 )
pCompr->ring_buffer[ s + RBUFLENGTH ] = ( BYTE ) c;
s = RBUFINDEX( s + 1 );
r = RBUFINDEX( r + 1 );
hb_LZSSxNodeInsert( pCompr, r );
}
while( i++ < last_match_length )
{
hb_LZSSxNodeDelete( pCompr, s );
s = RBUFINDEX( s + 1 );
r = RBUFINDEX( r + 1 );
if( --len )
hb_LZSSxNodeInsert( pCompr, r );
}
} while( len > 0 );
if( iItem > 1 )
{
for( i = 0; i < iItem; i++ )
{
if( !hb_LZSSxWrite( pCompr, itemSet[ i ] ) )
return ( ULONG ) -1;
}
ulSize += iItem;
}
if( !hb_LZSSxFlush( pCompr ) )
return ( ULONG ) -1;
return ulSize;
}
BOOL hb_LZSSxCompressMem( BYTE * pSrcBuf, ULONG ulSrcLen,
BYTE * pDstBuf, ULONG ulDstLen,
ULONG * pulSize )
{
PHB_LZSSX_COMPR pCompr;
ULONG ulSize;
pCompr = hb_LZSSxInit( FS_ERROR, pSrcBuf, ulSrcLen,
FS_ERROR, pDstBuf, ulDstLen );
ulSize = hb_LZSSxEncode( pCompr );
hb_LZSSxExit( pCompr );
if( pulSize )
*pulSize = ulSize;
return ( ulSize <= ulDstLen );
}
BOOL hb_LZSSxDecompressMem( BYTE * pSrcBuf, ULONG ulSrcLen,
BYTE * pDstBuf, ULONG ulDstLen )
{
PHB_LZSSX_COMPR pCompr;
BOOL fResult;
pCompr = hb_LZSSxInit( FS_ERROR, pSrcBuf, ulSrcLen,
FS_ERROR, pDstBuf, ulDstLen );
fResult = hb_LZSSxDecode( pCompr );
hb_LZSSxExit( pCompr );
return fResult;
}
BOOL hb_LZSSxCompressFile( FHANDLE hInput, FHANDLE hOutput, ULONG * pulSize )
{
PHB_LZSSX_COMPR pCompr;
ULONG ulSize;
pCompr = hb_LZSSxInit( hInput, NULL, 0, hOutput, NULL, 0 );
ulSize = hb_LZSSxEncode( pCompr );
hb_LZSSxExit( pCompr );
if( pulSize )
*pulSize = ulSize;
return ulSize != ( ULONG ) -1;
}
BOOL hb_LZSSxDecompressFile( FHANDLE hInput, FHANDLE hOutput )
{
PHB_LZSSX_COMPR pCompr;
BOOL fResult;
pCompr = hb_LZSSxInit( hInput, NULL, 0, hOutput, NULL, 0 );
fResult = hb_LZSSxDecode( pCompr );
hb_LZSSxExit( pCompr );
return fResult;
}
HB_FUNC( SX_FCOMPRESS )
{
BOOL fRet = FALSE;
FHANDLE hInput, hOutput;
char * szSource = hb_parc( 1 ), * szDestin = hb_parc( 2 );
BYTE buf[ 4 ];
ULONG ulSize;
if( szSource && *szSource && szDestin && *szDestin )
{
hInput = hb_fsExtOpen( ( BYTE * ) szSource, NULL, FO_READ | FO_DENYNONE |
FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL );
if( hInput != FS_ERROR )
{
hOutput = hb_fsExtOpen( ( BYTE * ) szDestin, NULL, FO_READWRITE |
FO_EXCLUSIVE | FXO_TRUNCATE |
FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL );
if( hOutput != FS_ERROR )
{
/* store uncompressed file size in first 4 bytes of destination
* file in little endian order - for SIX3 compatibility
*/
ulSize = hb_fsSeek( hInput, 0, FS_END );
if( hb_fsSeek( hInput, 0, FS_SET ) == 0 )
{
HB_PUT_LE_UINT32( buf, ulSize );
if( hb_fsWrite( hOutput, buf, 4 ) == 4 )
fRet = hb_LZSSxCompressFile( hInput, hOutput, NULL );
}
hb_fsClose( hOutput );
}
hb_fsClose( hInput );
}
}
hb_retl( fRet );
}
HB_FUNC( SX_FDECOMPRESS )
{
BOOL fRet = FALSE;
FHANDLE hInput, hOutput;
char * szSource = hb_parc( 1 ), * szDestin = hb_parc( 2 );
if( szSource && *szSource && szDestin && *szDestin )
{
hInput = hb_fsExtOpen( ( BYTE * ) szSource, NULL, FO_READ | FO_DENYNONE |
FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL );
if( hInput != FS_ERROR )
{
hOutput = hb_fsExtOpen( ( BYTE * ) szDestin, NULL, FO_READWRITE |
FO_EXCLUSIVE | FXO_TRUNCATE |
FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL );
if( hOutput != FS_ERROR )
{
/* skip the four bytes with original file length */
if( hb_fsSeek( hInput, 4, FS_SET ) == 4 )
fRet = hb_LZSSxDecompressFile( hInput, hOutput );
hb_fsClose( hOutput );
}
hb_fsClose( hInput );
}
}
hb_retl( fRet );
}
HB_FUNC( _SX_STRCOMPRESS )
{
BYTE * pStr = ( BYTE * ) hb_parc( 1 ), * pBuf;
if( pStr )
{
ULONG ulLen = hb_parclen( 1 ), ulBuf, ulDst;
/* this is for strict SIX compatibility - in general very bad idea */
ulBuf = ulLen + 257;
pBuf = ( BYTE * ) hb_xgrab( ulBuf );
HB_PUT_LE_UINT32( pBuf, ulLen );
if( ! hb_LZSSxCompressMem( pStr, ulLen, pBuf + 4, ulBuf - 4, &ulDst ) )
{
/* It's not six compatible - it's a workaround for wrongly defined SIX behavior */
HB_PUT_LE_UINT32( pBuf, HB_SX_UNCOMPRESED );
memcpy( pBuf + 4, pStr, ulLen );
}
hb_retclen( ( char * ) pBuf, ulDst + 4 );
hb_xfree( pBuf );
}
else
hb_itemReturn( hb_param( 1, HB_IT_ANY ) );
}
HB_FUNC( _SX_STRDECOMPRESS )
{
BOOL fOK = FALSE;
BYTE * pStr = ( BYTE * ) hb_parc( 1 ), * pBuf;
if( pStr )
{
ULONG ulLen = hb_parclen( 1 ), ulBuf;
if( ulLen >= 4 )
{
ulBuf = HB_GET_LE_UINT32( pStr );
if( ulBuf == HB_SX_UNCOMPRESED )
{
hb_retclen( ( char * ) pStr + 4, ulLen - 4 );
fOK = TRUE;
}
else
{
pBuf = ( BYTE * ) hb_xalloc( ulBuf + 1 );
if( pBuf )
{
fOK = hb_LZSSxDecompressMem( pStr + 4, ulLen - 4, pBuf, ulBuf );
if( fOK )
hb_retclen_buffer( ( char * ) pBuf, ulBuf );
else
hb_xfree( pBuf );
}
else
{
PHB_ITEM pItem = hb_errRT_SubstParams( "SIXCOMPRESS", EG_MEM, 0, "possible compressed string corruption", "_SX_STRDECOMPRESS" );
if( pItem )
hb_itemRelease( hb_itemReturn( pItem ) );
return;
}
}
}
}
if( !fOK )
hb_itemReturn( hb_param( 1, HB_IT_ANY ) );
}