📄 lzo1.c
字号:
/* lzo1.c -- implementation of the LZO1 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 <lzo1.h>#include "lzo_conf.h"/***********************************************************************// The next two defines can be changed to customize LZO1.// The default version is LZO1-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/* check configuration */#if (RBITS < 3 || RBITS > 5)# error "invalid RBITS"#endif#if (CLEVEL < 1 || CLEVEL > 9)# error "invalid CLEVEL"#endif/***********************************************************************// You should not have to change anything below this line.************************************************************************/#include "lzo_util.h"/***********************************************************************//************************************************************************//* Format of the marker byte 76543210 -------- 00000000 a long run (a 'R0' run) - there are short and long R0 runs 000rrrrr a short run with len r mmmooooo a short match (len = 2+m, o = offset low bits) 111ooooo a long match (o = offset low bits)*/#define RSIZE (1 << RBITS)#define RMASK (RSIZE - 1)#define OBITS RBITS /* offset and run-length use same bits */#define OSIZE (1 << OBITS)#define OMASK (OSIZE - 1)#define MBITS (8 - OBITS)#define MSIZE (1 << MBITS)#define MMASK (MSIZE - 1)/* sanity checks */#if (OBITS < 3 || OBITS > 5)# error "invalid OBITS"#endif#if (MBITS < 3 || MBITS > 5)# error "invalid MBITS"#endif/***********************************************************************// some macros to improve readability************************************************************************//* Minimum len of a match */#define MIN_MATCH 3#define THRESHOLD (MIN_MATCH - 1)/* Minimum len of match coded in 2 bytes */#define MIN_MATCH_SHORT MIN_MATCH/* Maximum len of match coded in 2 bytes */#define MAX_MATCH_SHORT (THRESHOLD + (MSIZE - 2))/* MSIZE - 2: 0 is used to indicate runs, * MSIZE-1 is used to indicate a long match *//* Minimum len of match coded in 3 bytes */#define MIN_MATCH_LONG (MAX_MATCH_SHORT + 1)/* Maximum len of match coded in 3 bytes */#define MAX_MATCH_LONG (MIN_MATCH_LONG + 255)/* Maximum offset of a match */#define MAX_OFFSET (1 << (8 + OBITS))/*RBITS | MBITS MIN THR. MSIZE MAXS MINL MAXL MAXO R0MAX R0FAST======+=============================================================== 3 | 5 3 2 32 32 33 288 2048 263 256 4 | 4 3 2 16 16 17 272 4096 271 264 5 | 3 3 2 8 8 9 264 8192 287 280 *//***********************************************************************// 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#define DBITS (8 + RBITS)#include "lzo_dict.h"#define DVAL_LEN DVAL_LOOKAHEAD/***********************************************************************// get algorithm info, return memory required for compression************************************************************************/LZO_EXTERN(lzo_uint) lzo1_info ( int *rbits, int *clevel );LZO_PUBLIC(lzo_uint)lzo1_info ( int *rbits, int *clevel ){ if (rbits) *rbits = RBITS; if (clevel) *clevel = CLEVEL; return D_SIZE * lzo_sizeof(lzo_byte *);}/***********************************************************************// decode a R0 literal run (a long run)************************************************************************/#define R0MIN (RSIZE) /* Minimum len of R0 run of literals */#define R0MAX (R0MIN + 255) /* Maximum len of R0 run of literals */#define R0FAST (R0MAX & ~7u) /* R0MAX aligned to 8 byte boundary */#if (R0MAX - R0FAST != 7) || ((R0FAST & 7) != 0)# error "something went wrong"#endif/* 7 special codes from R0FAST+1 .. R0MAX * these codes mean long R0 runs with lengths * 512, 1024, 2048, 4096, 8192, 16384, 32768 *//***********************************************************************// LZO1 decompress a block of data.//// Could be easily translated into assembly code.************************************************************************/LZO_PUBLIC(int)lzo1_decompress ( const lzo_byte *in , lzo_uint in_len, lzo_byte *out, lzo_uintp out_len, lzo_voidp wrkmem ){ lzo_byte *op; const lzo_byte *ip; const lzo_byte * const ip_end = in + in_len; lzo_uint t; 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 */ if (t < R0MIN) /* a literal run */ { 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; } MEMCPY_DS(op,ip,t); } else /* a match */ { lzo_uint tt; /* get match offset */ const lzo_byte *m_pos = op - 1; m_pos -= (lzo_uint)(t & OMASK) | (((lzo_uint) *ip++) << OBITS); /* get match len */ if (t >= ((MSIZE - 1) << OBITS)) /* all m-bits set */ tt = (MIN_MATCH_LONG - THRESHOLD) + *ip++; /* a long match */ else tt = t >> OBITS; /* a short match */ assert(m_pos >= out); assert(m_pos < op); /* a half unrolled loop */ *op++ = *m_pos++; *op++ = *m_pos++; MEMMOVE_DS(op,m_pos,tt); } } *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));}/***********************************************************************// code a literal run************************************************************************/static lzo_byte *store_run(lzo_byte *op, const lzo_byte *ii, lzo_uint r_len){ assert(r_len > 0); /* code a long R0 run */ if (r_len >= 512) { unsigned r_bits = 7; /* 256 << 7 == 32768 */ do { while (r_len >= (256u << r_bits)) { r_len -= (256u << r_bits); *op++ = 0; *op++ = LZO_BYTE((R0FAST - R0MIN) + r_bits); MEMCPY8_DS(op, ii, (256u << r_bits)); } } while (--r_bits > 0); } while (r_len >= R0FAST) { r_len -= R0FAST; *op++ = 0; *op++ = R0FAST - R0MIN; MEMCPY8_DS(op, ii, R0FAST); } if (r_len >= R0MIN) { /* code a short R0 run */ *op++ = 0; *op++ = LZO_BYTE(r_len - R0MIN); MEMCPY_DS(op, ii, r_len); } else if (r_len > 0) { /* code a 'normal' run */ *op++ = LZO_BYTE(r_len); MEMCPY_DS(op, ii, r_len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -