📄 lzo1a.c
字号:
/* lzo1a.c -- implementation of the LZO1A algorithm This file is part of the LZO real-time data compression library. Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library 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 of the License, or (at your option) any later version. The LZO library 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 the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Markus F.X.J. Oberhumer <markus@oberhumer.com> */#include <lzo1a.h>#include "lzo_conf.h"/***********************************************************************// The next two defines can be changed to customize LZO1A.// The default version is LZO1A-5/1.************************************************************************//* run bits (3 - 5) - the compressor and the decompressor * must use the same value. */#if !defined(RBITS)# define RBITS 5#endif/* compression level (1 - 9) - this only affects the compressor. * 1 is fastest, 9 is best compression ratio */#if !defined(CLEVEL)# define CLEVEL 1 /* fastest by default */#endif/* Collect statistics */#if 0 && !defined(LZO_COLLECT_STATS)# define LZO_COLLECT_STATS#endif/***********************************************************************// You should not have to change anything below this line.************************************************************************//* check configuration */#if (RBITS < 3 || RBITS > 5)# error "invalid RBITS"#endif#if (CLEVEL < 1 || CLEVEL > 9)# error "invalid CLEVEL"#endif/***********************************************************************// internal configuration// all of these affect compression only************************************************************************//* return -1 instead of copying if the data cannot be compressed */#undef LZO_RETURN_IF_NOT_COMPRESSIBLE/* choose the hashing strategy */#ifndef LZO_HASH#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_A#endif#define D_INDEX1(d,p) d = DM((0x21*DX2(p,5,5)) >> 5)#define D_INDEX2(d,p) d = d ^ D_MASK#include "lzo1a_de.h"#include "stats1a.h"#include "lzo_util.h"/* check other constants */#if (LBITS < 5 || LBITS > 8)# error "invalid LBITS"#endif#if defined(LZO_COLLECT_STATS) static lzo1a_stats_t lzo_statistics; lzo1a_stats_t *lzo1a_stats = &lzo_statistics;# define lzo_stats lzo1a_stats#endif/***********************************************************************// get algorithm info, return memory required for compression************************************************************************/LZO_EXTERN(lzo_uint) lzo1a_info ( int *rbits, int *clevel );LZO_PUBLIC(lzo_uint)lzo1a_info ( int *rbits, int *clevel ){ if (rbits) *rbits = RBITS; if (clevel) *clevel = CLEVEL; return D_SIZE * lzo_sizeof(lzo_byte *);}/***********************************************************************// LZO1A decompress a block of data.//// Could be easily translated into assembly code.************************************************************************/LZO_PUBLIC(int)lzo1a_decompress ( const lzo_byte *in , lzo_uint in_len, lzo_byte *out, lzo_uintp out_len, lzo_voidp wrkmem ){#if defined(LZO_OPTIMIZE_GNUC_i386) register lzo_byte *op __asm__("%edi"); register const lzo_byte *ip __asm__("%esi"); register lzo_uint t __asm__("%ecx"); register const lzo_byte *m_pos __asm__("%ebx");#else register lzo_byte *op; register const lzo_byte *ip; register lzo_uint t; register const lzo_byte *m_pos;#endif const lzo_byte * const ip_end = in + in_len; LZO_UNUSED(wrkmem);#if defined(__LZO_QUERY_DECOMPRESS) if (__LZO_IS_DECOMPRESS_QUERY(in,in_len,out,out_len,wrkmem)) return __LZO_QUERY_DECOMPRESS(in,in_len,out,out_len,wrkmem,0,0);#endif op = out; ip = in; while (ip < ip_end) { t = *ip++; /* get marker */ LZO_STATS(lzo_stats->marker[t]++); if (t == 0) /* a R0 literal run */ { t = *ip++; if (t >= R0FAST - R0MIN) /* a long R0 run */ { t -= R0FAST - R0MIN; if (t == 0) t = R0FAST; else {#if 0 t = 256u << ((unsigned) t);#else /* help the optimizer */ lzo_uint tt = 256; do tt <<= 1; while (--t > 0); t = tt;#endif } MEMCPY8_DS(op,ip,t); continue; } t += R0MIN; goto literal; } else if (t < R0MIN) /* a short literal run */ {literal: MEMCPY_DS(op,ip,t); /* after a literal a match must follow */ while (ip < ip_end) { t = *ip++; /* get R1 marker */ if (t >= R0MIN) goto match; /* R1 match - a context sensitive 3 byte match + 1 byte literal */ assert((t & OMASK) == t); m_pos = op - MIN_OFFSET; m_pos -= t | (((lzo_uint) *ip++) << OBITS); assert(m_pos >= out); assert(m_pos < op); *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *ip++; } } else /* a match */ {match: /* get match offset */ m_pos = op - MIN_OFFSET; m_pos -= (t & OMASK) | (((lzo_uint) *ip++) << OBITS); assert(m_pos >= out); assert(m_pos < op); /* get match len */ if (t < ((MSIZE - 1) << OBITS)) /* a short match */ { t >>= OBITS; *op++ = *m_pos++; *op++ = *m_pos++; MEMMOVE_DS(op,m_pos,t); } else /* a long match */ {#if (LBITS < 8) t = (MIN_MATCH_LONG - THRESHOLD) + ((lzo_uint)(*ip++) & LMASK);#else t = (MIN_MATCH_LONG - THRESHOLD) + (lzo_uint)(*ip++);#endif *op++ = *m_pos++; *op++ = *m_pos++; MEMMOVE_DS(op,m_pos,t);#if (LBITS < 8) /* a very short literal following a long match */ t = ip[-1] >> LBITS; if (t) do *op++ = *ip++; while (--t);#endif } } } *out_len = op - out; /* the next line is the only check in the decompressor */ return (ip == ip_end ? LZO_E_OK : (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));}/***********************************************************************// LZO1A compress a block of data.//// I apologize for the spaghetti code, but it really helps the optimizer.************************************************************************/#include "lzo1a_cr.ch"static intdo_compress ( const lzo_byte *in , lzo_uint in_len, lzo_byte *out, lzo_uintp out_len, lzo_voidp wrkmem ){#if defined(LZO_OPTIMIZE_GNUC_i386) register const lzo_byte *ip __asm__("%esi");#else register const lzo_byte *ip;#endif#if defined(__LZO_HASH_INCREMENTAL) lzo_uint32 dv;#endif const lzo_byte *m_pos; lzo_byte *op; const lzo_byte * const ip_end = in+in_len - DVAL_LEN - MIN_MATCH_LONG; const lzo_byte * const in_end = in+in_len - DVAL_LEN; const lzo_byte *ii; lzo_dict_p const dict = (lzo_dict_p) wrkmem; const lzo_byte *r1 = ip_end; /* pointer for R1 match (none yet) */#if (LBITS < 8) const lzo_byte *im = ip_end; /* pointer to last match start */#endif#if !defined(NDEBUG) const lzo_byte *m_pos_sav;#endif op = out; ip = in; ii = ip; /* point to start of current literal run */ /* init dictionary */#if defined(LZO_DETERMINISTIC) BZERO8_PTR(wrkmem,sizeof(lzo_dict_t),D_SIZE);#endif DVAL_FIRST(dv,ip); UPDATE_D(dict,0,dv,ip,in); ip++; DVAL_NEXT(dv,ip); do { lzo_moff_t m_off; lzo_uint dindex; DINDEX1(dindex,ip); GINDEX(m_pos,m_off,dict,dindex,in); if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,MAX_OFFSET)) goto literal; if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2]) goto match; DINDEX2(dindex,ip); GINDEX(m_pos,m_off,dict,dindex,in); if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,MAX_OFFSET)) goto literal; if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2]) goto match; goto literal;literal: UPDATE_I(dict,0,dindex,ip,in); if (++ip >= ip_end) break; continue;match: UPDATE_I(dict,0,dindex,ip,in);#if !defined(NDEBUG) && defined(LZO_DICT_USE_PTR) assert(m_pos == NULL || m_pos >= in); m_pos_sav = m_pos;#endif m_pos += 3; { /* we have found a match (of at least length 3) */#if !defined(NDEBUG) && !defined(LZO_DICT_USE_PTR) assert((m_pos_sav = ip - m_off) == (m_pos - 3));#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -