📄 lz77.h
字号:
//////////////////////////////
// LZ77.h
//////////////////////////////
// 使用在自己的堆中分配索引节点,不滑动窗口
// 每次最多压缩 65536 字节数据
// 的优化版本
#ifndef _WIX_LZ77_COMPRESS_HEADER_001_
#define _WIX_LZ77_COMPRESS_HEADER_001_
// 滑动窗口的字节大小
#define _MAX_WINDOW_SIZE 65536
class CCompress
{
public:
CCompress() {};
virtual ~CCompress() {};
public:
virtual int Compress(BYTE* src, int srclen, BYTE* dest) = 0;
virtual BOOL Decompress(BYTE* src, int srclen, BYTE* dest) = 0;
protected:
// tools
/////////////////////////////////////////////////////////
// CopyBitsInAByte : 在一个字节范围内复制位流
// 参数含义同 CopyBits 的参数
// 说明:
// 此函数由 CopyBits 调用,不做错误检查,即
// 假定要复制的位都在一个字节范围内
void CopyBitsInAByte(BYTE* memDest, int nDestPos,
BYTE* memSrc, int nSrcPos, int nBits);
////////////////////////////////////////////////////////
// CopyBits : 复制内存中的位流
// memDest - 目标数据区
// nDestPos - 目标数据区第一个字节中的起始位
// memSrc - 源数据区
// nSrcPos - 源数据区第一个字节的中起始位
// nBits - 要复制的位数
// 说明:
// 起始位的表示约定为从字节的高位至低位(由左至右)
// 依次为 0,1,... , 7
// 要复制的两块数据区不能有重合
void CopyBits(BYTE* memDest, int nDestPos,
BYTE* memSrc, int nSrcPos, int nBits);
//////////////////////////////////////////////////////////////
// 将DWORD值从高位字节到低位字节排列
void InvertDWord(DWORD* pDW);
/////////////////////////////////////////////////////////////
// 设置byte的第iBit位为aBit
// iBit顺序为高位起从0记数(左起)
void SetBit(BYTE* byte, int iBit, BYTE aBit);
////////////////////////////////////////////////////////////
// 得到字节byte第pos位的值
// pos顺序为高位起从0记数(左起)
BYTE GetBit(BYTE byte, int pos);
////////////////////////////////////////////////////////////
// 将位指针*piByte(字节偏移), *piBit(字节内位偏移)后移num位
void MovePos(int* piByte, int* piBit, int num);
/////////////////////////////////////////////////////////
// 取log2(n)的upper_bound
int UpperLog2(int n);
/////////////////////////////////////////////////////////
// 取log2(n)的lower_bound
int LowerLog2(int n);
};
class CCompressLZ77 : public CCompress
{
public:
CCompressLZ77();
virtual ~CCompressLZ77();
public:
/////////////////////////////////////////////
// 压缩一段字节流
// src - 源数据区
// srclen - 源数据区字节长度, srclen <= 65536
// dest - 压缩数据区,调用前分配srclen字节内存
// 返回值 > 0 压缩数据长度
// 返回值 = 0 数据无法压缩
// 返回值 < 0 压缩中异常错误
int Compress(BYTE* src, int srclen, BYTE* dest);
/////////////////////////////////////////////
// 解压缩一段字节流
// src - 接收原始数据的内存区, srclen <= 65536
// srclen - 源数据区字节长度
// dest - 压缩数据区
// 返回值 - 成功与否
BOOL Decompress(BYTE* src, int srclen, BYTE* dest);
protected:
BYTE* pWnd;
// 窗口大小最大为 64k ,并且不做滑动
// 每次最多只压缩 64k 数据,这样可以方便从文件中间开始解压
// 当前窗口的长度
int nWndSize;
// 对滑动窗口中每一个2字节串排序
// 排序是为了进行快速术语匹配
// 排序的方法是用一个64k大小的指针数组
// 数组下标依次对应每一个2字节串:(00 00) (00 01) ... (01 00) (01 01) ...
// 每一个指针指向一个链表,链表中的节点为该2字节串的每一个出现位置
struct STIDXNODE
{
WORD off; // 在src中的偏移
WORD off2; // 用于对应的2字节串为重复字节的节点
// 指从 off 到 off2 都对应了该2字节串
WORD next; // 在SortHeap中的指针
};
WORD SortTable[65536]; // 256 * 256 指向SortHeap中下标的指针
// 因为窗口不滑动,没有删除节点的操作,所以
// 节点可以在SortHeap 中连续分配
struct STIDXNODE* SortHeap;
int HeapPos; // 当前分配位置
// 当前输出位置(字节偏移及位偏移)
int CurByte, CurBit;
protected:
////////////////////////////////////////
// 输出压缩码
// code - 要输出的数
// bits - 要输出的位数(对isGamma=TRUE时无效)
// isGamma - 是否输出为γ编码
void _OutCode(BYTE* dest, DWORD code, int bits, BOOL isGamma);
///////////////////////////////////////////////////////////
// 在滑动窗口中查找术语
// nSeekStart - 从何处开始匹配
// offset, len - 用于接收结果,表示在滑动窗口内的偏移和长度
// 返回值- 是否查到长度为3或3以上的匹配字节串
BOOL _SeekPhase(BYTE* src, int srclen, int nSeekStart, int* offset, int* len);
///////////////////////////////////////////////////////////
// 得到已经匹配了3个字节的窗口位置offset
// 共能匹配多少个字节
inline int _GetSameLen(BYTE* src, int srclen, int nSeekStart, int offset);
//////////////////////////////////////////
// 将窗口向右滑动n个字节
inline void _ScrollWindow(int n);
// 向索引中添加一个2字节串
inline void _InsertIndexItem(int off);
// 初始化索引表,释放上次压缩用的空间
void _InitSortTable();
};
#endif // _WIX_LZW_COMPRESS_HEADER_001_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -