00001 #ifndef __J2K__LZH__LZHLCompressor_CPP__
00002 #define __J2K__LZH__LZHLCompressor_CPP__
00003
00004 LZHLCompressor::LZHLCompressor() {
00005 table = new LZTableItem[ LZTABLESIZE ];
00006 for ( int i=0; i < LZTABLESIZE ; ++i ) {
00007 table[ i ] = (LZTABLEINT)(-1);
00008 }
00009 }
00010
00011 LZHLCompressor::~LZHLCompressor() {
00012 delete [] table;
00013 }
00014
00015 inline LZHASH LZHLCompressor::_updateTable( LZHASH hash, const BYTE* src, LZPOS pos, int len )
00016 {
00017 if ( len <= 0 )
00018 return 0;
00019
00020 if ( len > LZSKIPHASH ) {
00021 ++src;
00022 hash = 0;
00023 const BYTE* pEnd = src + len + LZMATCH;
00024
00025 for ( const BYTE* p=src+len; p < pEnd ; ) {
00026 UPDATE_HASH( hash, *p++ );
00027 }
00028
00029 return hash;
00030 }
00031
00032 UPDATE_HASH_EX( hash, src );
00033 ++src;
00034
00035 for ( int i=0; i < len ; ++i ) {
00036 table[ HASH_POS( hash ) ] = (LZTableItem)_wrap( pos + i );
00037 UPDATE_HASH_EX( hash, src + i );
00038 }
00039
00040 return hash;
00041 }
00042
00043 size_t LZHLCompressor::compress( BYTE* dst, const BYTE* src, size_t sz ) {
00044 LZHLEncoder coder( &stat, dst );
00045 const BYTE* srcBegin = src;
00046 const BYTE* srcEnd = src + sz;
00047
00048 LZHASH hash = 0;
00049
00050 if ( sz >= LZMATCH ) {
00051 const BYTE* pEnd = src + LZMATCH;
00052
00053 for ( const BYTE* p=src; p < pEnd ; ) {
00054 UPDATE_HASH( hash, *p++ );
00055 }
00056 }
00057
00058 for (;;) {
00059 int srcLeft = srcEnd - src;
00060 if ( srcLeft < LZMATCH ) {
00061 if ( srcLeft ) {
00062 _toBuf( src, srcLeft );
00063 coder.putRaw( src, srcLeft );
00064 src += srcLeft;
00065 }
00066
00067 break;
00068 }
00069
00070 int nRaw = 0;
00071 int maxRaw = min( srcLeft - LZMATCH, LZHLEncoder::maxRaw );
00072
00073 #ifdef LZLAZYMATCH
00074 int lazyMatchLen = 0;
00075 int lazyMatchHashPos;
00076 LZPOS lazyMatchBufPos;
00077 int lazyMatchNRaw;
00078 LZHASH lazyMatchHash;
00079 BOOL lazyForceMatch = FALSE;
00080 #endif
00081 for (;;) {
00082 LZHASH hash2 = HASH_POS( hash );
00083
00084 int hashPos = table[ hash2 ];
00085 int wrapBufPos = _wrap( bufPos );
00086 table[ hash2 ] = (LZTableItem)wrapBufPos;
00087
00088 int matchLen = 0;
00089 if ( hashPos != (LZTABLEINT)(-1) && hashPos != wrapBufPos )
00090 {
00091 int matchLimit = min( min( _distance( wrapBufPos - hashPos ), srcLeft - nRaw ), LZMIN + LZHLEncoder::maxMatchOver );
00092 matchLen = _nMatch( hashPos, src + nRaw, matchLimit );
00093
00094 #ifdef LZOVERLAP
00095 if ( _wrap( hashPos + matchLen ) == wrapBufPos )
00096 {
00097 assert( matchLen != 0 );
00098 int xtraMatchLimit = min( LZMIN + LZHLEncoder::maxMatchOver - matchLen, srcLeft - nRaw - matchLen );
00099 for ( int xtraMatch = 0; xtraMatch < xtraMatchLimit ; ++xtraMatch )
00100 {
00101 if ( src[ nRaw + xtraMatch ] != src[ nRaw + xtraMatch + matchLen ] )
00102 break;
00103 }
00104
00105 matchLen += xtraMatch;
00106 }
00107 #endif
00108
00109 #ifdef LZBACKWARDMATCH
00110 if ( matchLen >= LZMIN - 1 )
00111 {
00112 int xtraMatchLimit = min( LZMIN + LZHLEncoder::maxMatchOver - matchLen, nRaw );
00113 int d = (int)_distance( bufPos - hashPos );
00114 xtraMatchLimit = min( min( xtraMatchLimit, d - matchLen ), LZBUFSIZE - d );
00115 for ( int xtraMatch = 0; xtraMatch < xtraMatchLimit ; ++xtraMatch )
00116 {
00117 if ( buf[ _wrap( hashPos - xtraMatch - 1 ) ] != src[ nRaw - xtraMatch - 1 ] )
00118 break;
00119 }
00120
00121 if ( xtraMatch > 0 ) {
00122 assert( matchLen + xtraMatch >= LZMIN );
00123 assert( matchLen + xtraMatch <= _distance( bufPos - hashPos ) );
00124
00125 nRaw -= xtraMatch;
00126 bufPos -= xtraMatch;
00127 hashPos -= xtraMatch;
00128 matchLen += xtraMatch;
00129 wrapBufPos = _wrap( bufPos );
00130 hash = _calcHash( src + nRaw );
00131
00132 #ifdef LZLAZYMATCH
00133 lazyForceMatch = TRUE;
00134 #endif
00135 }
00136 }
00137 #endif
00138 }
00139
00140 #ifdef LZLAZYMATCH
00141 if ( lazyMatchLen >= LZMIN ) {
00142 if ( matchLen > lazyMatchLen ) {
00143 coder.putMatch( src, nRaw, matchLen - LZMIN, _distance( wrapBufPos - hashPos ) );
00144 hash = _updateTable( hash, src + nRaw, bufPos + 1, min( matchLen - 1, srcEnd - (src + nRaw + 1) ) );
00145 _toBuf( src + nRaw, matchLen );
00146 src += nRaw + matchLen;
00147 break;
00148
00149 } else {
00150 nRaw = lazyMatchNRaw;
00151 bufPos = lazyMatchBufPos;
00152
00153 hash = lazyMatchHash;
00154 UPDATE_HASH_EX( hash, src + nRaw );
00155 coder.putMatch( src, nRaw, lazyMatchLen - LZMIN, _distance( bufPos - lazyMatchHashPos ) );
00156 hash = _updateTable( hash, src + nRaw + 1, bufPos + 2, min( lazyMatchLen - 2, srcEnd - (src + nRaw + 2) ) );
00157 _toBuf( src + nRaw, lazyMatchLen );
00158 src += nRaw + lazyMatchLen;
00159
00160 break;
00161 }
00162 }
00163 #endif
00164
00165 if ( matchLen >= LZMIN ) {
00166
00167 #ifdef LZLAZYMATCH
00168 if ( !lazyForceMatch ) {
00169 lazyMatchLen = matchLen;
00170 lazyMatchHashPos = hashPos;
00171 lazyMatchNRaw = nRaw;
00172 lazyMatchBufPos = bufPos;
00173 lazyMatchHash = hash;
00174 } else
00175 #endif
00176 {
00177 coder.putMatch( src, nRaw, matchLen - LZMIN, _distance( wrapBufPos - hashPos ) );
00178 hash = _updateTable( hash, src + nRaw, bufPos + 1, min( matchLen - 1, srcEnd - (src + nRaw + 1) ) );
00179 _toBuf( src + nRaw, matchLen );
00180 src += nRaw + matchLen;
00181
00182 break;
00183 }
00184 }
00185
00186 #ifdef LZLAZYMATCH
00187 assert( !lazyForceMatch );
00188 #endif
00189
00190 if ( nRaw + 1 > maxRaw )
00191 {
00192 #ifdef LZLAZYMATCH
00193 if ( lazyMatchLen >= LZMIN )
00194 {
00195 coder.putMatch( src, nRaw, lazyMatchLen - LZMIN, _distance( bufPos - lazyMatchHashPos ) );
00196 hash = _updateTable( hash, src + nRaw, bufPos + 1, min( lazyMatchLen - 1, srcEnd - (src + nRaw + 1) ) );
00197 _toBuf( src + nRaw, lazyMatchLen );
00198 src += nRaw + lazyMatchLen;
00199 break;
00200 }
00201 #endif
00202
00203 if ( nRaw + LZMATCH >= srcLeft && srcLeft <= LZHLEncoder::maxRaw )
00204 {
00205 _toBuf( src + nRaw, srcLeft - nRaw );
00206 nRaw = srcLeft;
00207 }
00208
00209 coder.putRaw( src, nRaw );
00210 src += nRaw;
00211 break;
00212 }
00213
00214 UPDATE_HASH_EX( hash, src + nRaw );
00215 _toBuf( src[ nRaw++ ] );
00216 }
00217 }
00218
00219 return coder.flush();
00220 }
00221
00222 #endif