menu

秋梦无痕

一场秋雨无梦痕,春夜清风冻煞人。冬来冷水寒似铁,夏至京北蟑满城。

Avatar

文件/文件夹LZSS压缩/解压缩

前些天要实现多文件/文件夹的打包/压缩,网上还暂时找不到合适的代码,所以只好自己折腾了。相关压缩算法是在网上找到的,采用Huffman编码。目前的压缩比率在10%-50%之间,差于WinZip及WinRar算法。

功能:
1. 将多个文件/文件夹压缩并打包,生成一个单独的文件。
2. 解压缩一个压缩文件。
3. 解压缩内存中的压缩内容。

公开接口和参数都是自解释的,就没有多写注释了。如果有什么不清楚的地方,可以发mail给我,如果你做了什么改进,也请发mail给我。cyifyr(at)gmail(dot)com

声明:

#ifndef _CZIP_H_
#define _CZIP_H_

#include <vector>

#define N 4096 /* size of ring buffer */
#define F 60 /* upper limit for match_length */
#define THRESHOLD 2 /* encode string into position and length
if match_length is greater than this */
#define NIL N /* index for root of binary search trees */
/********** Arithmetic Compression **********/

/*
If you are not familiar with arithmetic compression, you should read
I. E. Witten, R. M. Neal, and J. G. Cleary,
Communications of the ACM, Vol. 30, pp. 520-540 (1987),
from which much have been borrowed.
*/

#define M 15

/* Q1 (= 2 to the M) must be sufficiently large, but not so
large as the unsigned long 4 * Q1 * (Q1 - 1) overflows. */

#define Q1 (1UL << M)
#define Q2 (2 * Q1)
#define Q3 (3 * Q1)
#define Q4 (4 * Q1)
#define MAX_CUM (Q1 - 1)

#define N_CHAR (256 - THRESHOLD + F)

typedef struct PackItem {
CHAR cFileType;
CHAR szFilePath[MAX_PATH];
DWORD dwUnzipSize;
DWORD dwZippedSize;
LPBYTE pData;
} * LPPACKITEM;

class CZip {
public:
CZip();
~CZip();
public:
void Pack(const char* lpszInPath[], const char* lpszOutFile);
void Unpack(const char *lpszInfile, const char* lpszOutPath);
void Unpack(const BYTE* lpData, const DWORD nDataLength, const char* lpszOutPath);
private:
CHAR m_szWorkDir[MAX_PATH];

DWORD textsize;
DWORD codesize;
DWORD printcount;
BYTE text_buf[N + F - 1]; /* ring buffer of size N,with extra F-1 bytes to facilitate string comparison */
int match_position;
int match_length; /* of longest match. These areset by the InsertNode() procedure. */
int lson[N + 1];
int rson[N + 257];
int dad[N + 1]; /* left & right children &parents -- These constitute binary search trees. */

/* character code = 0, 1, ..., N_CHAR - 1 */

DWORD low;
DWORD high;
DWORD value;
int shifts; /* counts for magnifying low and high around Q2 */
int char_to_sym[N_CHAR];
int sym_to_char[N_CHAR + 1];
DWORD sym_freq[N_CHAR + 1]; /* frequency for symbols */
DWORD sym_cum[N_CHAR + 1]; /* cumulative freq for symbols */
DWORD position_cum[N + 1]; /* cumulative freq for positions */

// Compress in memory;
bool m_bMem;

std::vector<BYTE> m_OutBuffer;
int m_nOutLength;

const BYTE *m_pInBuffer;
int m_nInLength;
int m_nInCur;

DWORD buffer_putbit, mask_putbit;
DWORD buffer_getbit, mask_getbit;

std::vector<LPPACKITEM> m_PackList;
private:
void Initialize();
void Release();

void PutBit(int bit); /* Output one bit (bit = 0,1) */
void FlushBitBuffer(void); /* Send remaining bits */
int GetBit(void); /* Get one bit (0 or 1) */

/********** LZSS with multiple binary trees **********/

void InitTree(void); /* Initialize trees */
void InsertNode(int r);
void DeleteNode(int p); /* Delete node p from tree */
void StartModel(void); /* Initialize model */
void UpdateModel(int sym);
void Output(int bit); /* Output 1 bit, followed by its complements */
void EncodeChar(int ch);
void EncodePosition(int position);
void EncodeEnd(void);
int BinarySearchSym(unsigned int x);
int BinarySearchPos(unsigned int x);
void StartDecode(void);
int DecodeChar(void);
int DecodePosition(void);

void Encode(void);
void Decode(void);

void Compress(const BYTE *pInBuffer, DWORD nInLength, const BYTE *&pOutBuffer, DWORD &nOutLength);
void UnCompress(const BYTE *pInBuffer, DWORD nInLength, const BYTE *&pOutBuffer, DWORD &nOutLength);

void AddEntry(const char* lpszInPath);
void FetchEntry(const char* lpszOutPath);
};

#endif // _CZIP_H_


实现:

// Zip.cpp : Defines the entry point for the application.
//

#include <windows.h>
#include <mstask.h>
#include "zip.h"

CZip::CZip() {
Initialize();
}

CZip::~CZip() {
Release();
}

void CZip::Initialize() {
textsize = 0;
codesize = 0;
printcount = 0;

low = 0;
high = Q4;
value = 0;
shifts = 0;/* counts for magnifying low and high around Q2 */

m_pInBuffer = NULL;
m_nInLength = 0;
m_nInCur = 0;

m_nOutLength = 0;

buffer_putbit = 0;
mask_putbit = 128;

buffer_getbit = 0;
mask_getbit = 0;

memset(text_buf, 0, N + F - 1);
memset(lson, 0, N + 1);
memset(rson, 0, N + 257);
memset(dad, 0, N + 1);
memset(char_to_sym, 0, N_CHAR * sizeof(int));
memset(sym_to_char, 0 , (N_CHAR + 1) * sizeof(int));
memset(sym_freq, 0, (N_CHAR + 1) * sizeof(DWORD));
memset(sym_cum, 0, (N_CHAR + 1) * sizeof(DWORD));
memset(position_cum, 0, (N_CHAR + 1) * sizeof(DWORD));

GetModuleFileName(NULL,m_szWorkDir,MAX_PATH);
(strrchr(m_szWorkDir,'\\'))[1] = 0;
//GetCurrentDirectory(MAX_PATH, m_szWorkDir);
}

void CZip::Release() {
if(!m_OutBuffer.empty()) {
textsize = 0;
codesize = 0;
printcount = 0;

low = 0;
high = Q4;
value = 0;
shifts = 0;

m_pInBuffer = NULL;
m_nInLength = 0;
m_nInCur = 0;

m_OutBuffer.clear();
m_nOutLength = 0;

buffer_putbit = 0;
mask_putbit = 128;

buffer_getbit = 0;
mask_getbit = 0;
}
}

/*
* Output one bit (bit = 0,1)
*/
void CZip::PutBit(int bit) {
if(bit) {
buffer_putbit |= mask_putbit;
}
if((mask_putbit >>= 1) == 0) {
m_OutBuffer.push_back(buffer_putbit);
buffer_putbit = 0;
mask_putbit = 128;
codesize++;
}
}

/*
* Send remaining bits
*/
void CZip::FlushBitBuffer(void) {
for(int i = 0; i < 7; i++) {
PutBit(0);
}
}

/*
* Get one bit (0 or 1)
*/
int CZip::GetBit(void) {
if((mask_getbit >>= 1) == 0) {
buffer_getbit = m_pInBuffer[m_nInCur++];
mask_getbit = 128;
}
return ((buffer_getbit & mask_getbit) != 0);
}

/******** LZSS with multiple binary trees ********/

/*
* Initialize trees
*/
void CZip::InitTree(void) {
int i;

/* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
left children of node i. These nodes need not be initialized.
Also, dad[i] is the parent of node i. These are initialized to
NIL (= N), which stands for 'not used.'
For i = 0 to 255, rson[N + i + 1] is the root of the tree
for strings that begin with character i. These are initialized
to NIL. Note there are 256 trees. */

for(i = N + 1; i <= N + 256; i++) { /* root */
rson[i] = NIL;
}
for(i = 0; i < N; i++) { /* node */
dad[i] = NIL;
}
}

void CZip::InsertNode(int r) {
/* Inserts string of length F, text_buf[r..r+F-1], into one of the
trees (text_buf[r]'th tree) and returns the longest-match position
and length via the global variables match_position and match_length.
If match_length = F, then removes the old node in favor of the new
one, because the old one will be deleted sooner.
Note r plays double role, as tree node and position in buffer. */
int i, p, cmp, temp;
unsigned char *key;

cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
rson[r] = lson[r] = NIL; match_length = 0;
while(TRUE) {
if(cmp >= 0) {
if(rson[p] != NIL) {
p = rson[p];
} else {
rson[p] = r;
dad[r] = p;
return;
}
} else {
if(lson[p] != NIL) {
p = lson[p];
} else {
lson[p] = r;
dad[r] = p;
return;
}
}
for(i = 1; i < F; i++) {
if((cmp = key[i] - text_buf[p + i]) != 0) {
break;
}
}
if(i > THRESHOLD) {
if(i > match_length) {
match_position = (r - p) & (N - 1);
if((match_length = i) >= F) {
break;
}
} else if(i == match_length) {
if((temp = (r - p) & (N - 1)) < match_position) {
match_position = temp;
}
}
}
}
dad[r] = dad[p];
lson[r] = lson[p];
rson[r] = rson[p];

dad[lson[p]] = r;
dad[rson[p]] = r;
if(rson[dad[p]] == p) {
rson[dad[p]] = r;
} else {
lson[dad[p]] = r;
}
dad[p] = NIL; /* remove p */
}

/*
* Delete node p from tree
*/
void CZip::DeleteNode(int p) {
int q;

if(dad[p] == NIL) { /* not in tree */
return;
}
if(rson[p] == NIL) {
q = lson[p];
} else if(lson[p] == NIL) {
q = rson[p];
} else {
q = lson[p];
if(rson[q] != NIL) {
do {
q = rson[q];
} while(rson[q] != NIL);
rson[dad[q]] = lson[q];
dad[lson[q]] = dad[q];
lson[q] = lson[p];
dad[lson[p]] = q;
}
rson[q] = rson[p];
dad[rson[p]] = q;
}
dad[q] = dad[p];
if(rson[dad[p]] == p) {
rson[dad[p]] = q;
} else {
lson[dad[p]] = q;
}
dad[p] = NIL;
}

/******** Arithmetic Compression ********/

/*
If you are not familiar with arithmetic compression, you should read
I. E. Witten, R. M. Neal, and J. G. Cleary,
Communications of the ACM, Vol. 30, pp. 520-540 (1987),
from which much have been borrowed.
*/

/* character code = 0, 1, ..., N_CHAR - 1 */

/*
* Initialize model
*/
void CZip::StartModel(void) {
int ch, sym, i;

sym_cum[N_CHAR] = 0;
for(sym = N_CHAR; sym >= 1; sym--) {
ch = sym - 1;
char_to_sym[ch] = sym;
sym_to_char[sym] = ch;
sym_freq[sym] = 1;
sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym];
}
sym_freq[0] = 0; /* sentinel (!= sym_freq[1]) */
position_cum[N] = 0;
for(i = N; i >= 1; i--) {
position_cum[i - 1] = position_cum[i] + 10000 / (i + 200);
}
/* empirical distribution function (quite tentative) */
/* Please devise a better mechanism! */
}

void CZip::UpdateModel(int sym) {
int i, c, ch_i, ch_sym;

if(sym_cum[0] >= MAX_CUM) {
c = 0;
for(i = N_CHAR; i > 0; i--) {
sym_cum[i] = c;
c += (sym_freq[i] = (sym_freq[i] + 1) >> 1);
}
sym_cum[0] = c;
}
for(i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ;
if(i < sym) {
ch_i = sym_to_char[i]; ch_sym = sym_to_char[sym];
sym_to_char[i] = ch_sym; sym_to_char[sym] = ch_i;
char_to_sym[ch_i] = sym; char_to_sym[ch_sym] = i;
}
sym_freq[i]++;
while(--i >= 0) {
sym_cum[i]++;
}
}

/*
* Output 1 bit, followed by its complements
*/
void CZip::Output(int bit) {
PutBit(bit);
for( ; shifts > 0; shifts--) {
PutBit(! bit);
}
}

void CZip::EncodeChar(int ch) {
int sym;
unsigned long int range;

sym = char_to_sym[ch];
range = high - low;
high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
low += (range * sym_cum[sym ]) / sym_cum[0];
while(TRUE) {
if(high <= Q2) {
Output(0);
} else if(low >= Q2) {
Output(1);
low -= Q2;
high -= Q2;
} else if(low >= Q1 && high <= Q3) {
shifts++;
low -= Q1;
high -= Q1;
} else {
break;
}
low += low;
high += high;
}
UpdateModel(sym);
}

void CZip::EncodePosition(int position) {
unsigned long int range;

range = high - low;
high = low + (range * position_cum[position ]) / position_cum[0];
low += (range * position_cum[position + 1]) / position_cum[0];
while(TRUE) {
if(high <= Q2) {
Output(0);
} else if(low >= Q2) {
Output(1); low -= Q2; high -= Q2;
} else if(low >= Q1 && high <= Q3) {
shifts++; low -= Q1; high -= Q1;
} else {
break;
}
low += low;
high += high;
}
}

void CZip::EncodeEnd(void) {
shifts++;
if(low < Q1) {
Output(0);
} else {
Output(1);
}
FlushBitBuffer(); /* flush bits remaining in buffer */
}

int CZip::BinarySearchSym(unsigned int x) {
/* 1 if x >= sym_cum[1],
N_CHAR if sym_cum[N_CHAR] > x,
i such that sym_cum[i - 1] > x >= sym_cum[i] otherwise */
int i, j, k;

i = 1; j = N_CHAR;
while(i < j) {
k = (i + j) / 2;
if(sym_cum[k] > x) {
i = k + 1;
} else {
j = k;
}
}
return i;
}

int CZip::BinarySearchPos(unsigned int x) {
/* 0 if x >= position_cum[1],
N - 1 if position_cum[N] > x,
i such that position_cum[i] > x >= position_cum[i + 1] otherwise */
int i, j, k;

i = 1; j = N;
while(i < j) {
k = (i + j) / 2;
if(position_cum[k] > x) {
i = k + 1;
} else {
j = k;
}
}
return i - 1;
}

void CZip::StartDecode(void) {
int i;

for(i = 0; i < M + 2; i++) {
value = 2 * value + GetBit();
}
}

int CZip::DecodeChar(void) {
int sym, ch;
unsigned long int range;

range = high - low;
sym = BinarySearchSym((unsigned int)(((value - low + 1) * sym_cum[0] - 1) / range));
high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
low += (range * sym_cum[sym ]) / sym_cum[0];
while(TRUE) {
if(low >= Q2) {
value -= Q2;
low -= Q2;
high -= Q2;
} else if(low >= Q1 && high <= Q3) {
value -= Q1;
low -= Q1;
high -= Q1;
} else if(high > Q2) {
break;
}
low += low;
high += high;
value = 2 * value + GetBit();
}
ch = sym_to_char[sym];
UpdateModel(sym);
return ch;
}

int CZip::DecodePosition(void) {
int position;
unsigned long int range;

range = high - low;
position = BinarySearchPos((unsigned int)(((value - low + 1) * position_cum[0] - 1) / range));
high = low + (range * position_cum[position ]) / position_cum[0];
low += (range * position_cum[position + 1]) / position_cum[0];
while(TRUE) {
if(low >= Q2) {
value -= Q2;
low -= Q2;
high -= Q2;
} else if(low >= Q1 && high <= Q3) {
value -= Q1;
low -= Q1;
high -= Q1;
} else if(high > Q2) {
break;
}
low += low;
high += high;
value = 2 * value + GetBit();
}
return position;
}

/******** Encode and Decode ********/

void CZip::Encode(void) {
int i, c, len, r, s, last_match_length;

textsize = m_nInLength;
m_OutBuffer.resize(sizeof textsize);
memcpy(&m_OutBuffer[0],&textsize,sizeof textsize);
codesize += sizeof textsize;
if(textsize == 0) return;
m_nInCur = 0;
textsize = 0;

StartModel();
InitTree();
s = 0; r = N - F;
for(i = s; i < r; i++) {
text_buf[i] = ' ';
}
for(len = 0; len < F && m_nInCur < m_nInLength ; len++) {
c = m_pInBuffer[m_nInCur++];
text_buf[r + len] = c;
}

textsize = len;
for(i = 1; i <= F; i++) {
InsertNode(r - i);
}

InsertNode(r);

do {
if(match_length > len) {
match_length = len;
}
if(match_length <= THRESHOLD) {
match_length = 1; EncodeChar(text_buf[r]);
} else {
EncodeChar(255 - THRESHOLD + match_length);
EncodePosition(match_position - 1);
}
last_match_length = match_length;
for(i = 0; i < last_match_length && m_nInCur < m_nInLength ; i++)
{
c = m_pInBuffer[m_nInCur++];
DeleteNode(s);
text_buf[s] = c;
if(s < F - 1) {
text_buf[s + N] = c;
}
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
InsertNode(r);
}
if((textsize += i) > printcount) {
printcount += 1024;
}
while(i++ < last_match_length) {
DeleteNode(s);
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
if(--len) {
InsertNode(r);
}
}
} while(len > 0);

EncodeEnd();
}

void CZip::Decode(void) {
int i, j, k, r, c;
unsigned long int count;

if(m_nInLength < sizeof textsize) {
return;
}
memcpy(&textsize,m_pInBuffer + m_nInCur,sizeof textsize);

m_nOutLength = textsize;

m_nInCur += sizeof textsize;

if(textsize == 0) {
return;
}

StartDecode();
StartModel();

for(i = 0; i < N - F; i++) {
text_buf[i] = ' ';
}
r = N - F;
for(count = 0; count < textsize; ) {
c = DecodeChar();
if(c < 256) {
m_OutBuffer.push_back(c);
text_buf[r++] = c;
r &= (N - 1);
count++;
} else {
i = (r - DecodePosition() - 1) & (N - 1);
j = c - 255 + THRESHOLD;
for(k = 0; k < j; k++) {
c = text_buf[(i + k) & (N - 1)];
m_OutBuffer.push_back(c);
text_buf[r++] = c;
r &= (N - 1);
count++;
}
}
if(count > printcount) {
printcount += 1024;
}
}
}

void CZip::Compress(const BYTE *pInBuffer,DWORD nInLength,const BYTE *&pOutBuffer, DWORD &nOutLength) {
Initialize();
m_pInBuffer = pInBuffer;
m_nInLength = nInLength;
m_nInCur = 0;

Encode();
nOutLength = m_OutBuffer.size();
pOutBuffer = new BYTE[nOutLength];
memcpy((void *)pOutBuffer, &m_OutBuffer[0], nOutLength);
Release();
}

void CZip::UnCompress(const BYTE *pInBuffer,DWORD nInLength,const BYTE *&pOutBuffer, DWORD &nOutLength) {
Initialize();
m_pInBuffer = pInBuffer;
m_nInLength = nInLength;
m_nInCur = 0;

Decode();
nOutLength = m_OutBuffer.size();
pOutBuffer = new BYTE[nOutLength];
memcpy((void *)pOutBuffer, &m_OutBuffer[0], nOutLength);
Release();
}

void CZip::AddEntry(const char* lpszInPath) {
OFSTRUCT os;
DWORD dwFileAttributes = GetFileAttributes(lpszInPath);

LPPACKITEM item = new PackItem;
memset(item, 0, sizeof(PackItem));

if(dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
char szAbsPath[MAX_PATH], szFind[MAX_PATH], szRefPath[MAX_PATH];
strcpy(szAbsPath, lpszInPath);
if(lpszInPath[strlen(lpszInPath) - 1] != '\\') {
strcat(szAbsPath, "\\");
}

strcpy(szFind, szAbsPath);
strcat(szFind, "*");

strcpy(szRefPath, szAbsPath);
if(strncmp(szRefPath, m_szWorkDir, strlen(m_szWorkDir)) == 0) {
strcpy(szRefPath, szRefPath + strlen(m_szWorkDir));
}
item->cFileType = 1;
strcpy(item->szFilePath, szRefPath);
m_PackList.push_back(item);

HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA FindFileData;
hFind = FindFirstFile(szFind, &FindFileData);
if(hFind != INVALID_HANDLE_VALUE) {
if(strcmp(FindFileData.cFileName, ".") != 0
&& strcmp(FindFileData.cFileName, "..") != 0) {
char szFile[MAX_PATH];
strcpy(szFile, szAbsPath);
strcat(szFile, FindFileData.cFileName);
AddEntry(szFile);
}
while(FindNextFile(hFind, &FindFileData) != 0) {
if(strcmp(FindFileData.cFileName, ".") != 0
&& strcmp(FindFileData.cFileName, "..") != 0) {
char szFile[MAX_PATH];
strcpy(szFile, szAbsPath);
strcat(szFile, FindFileData.cFileName);
AddEntry(szFile);
}
}
FindClose(hFind);
}
} else {
char szAbsPath[MAX_PATH], szRefPath[MAX_PATH];
strcpy(szAbsPath, lpszInPath);
strcpy(szRefPath, lpszInPath);

if(strncmp(szRefPath, m_szWorkDir, strlen(m_szWorkDir)) == 0) {
strcpy(szRefPath, szRefPath + strlen(m_szWorkDir));
}
strcpy(item->szFilePath, szRefPath);
item->cFileType = 0;

HANDLE hFile = (HANDLE)OpenFile(szAbsPath, &os, OF_READ | OF_SHARE_DENY_WRITE);
if((HFILE)hFile != HFILE_ERROR) {
BY_HANDLE_FILE_INFORMATION info;
if(GetFileInformationByHandle(hFile, &info)) {
// no more than 4G
item->dwUnzipSize = info.nFileSizeLow;
LPBYTE inBuffer = new BYTE[item->dwUnzipSize];
DWORD dwReaded;
LPBYTE outBuffer;
DWORD dwZipped;
if(ReadFile(hFile, inBuffer, item->dwUnzipSize, &dwReaded, NULL) && dwReaded == item->dwUnzipSize) {
Compress(inBuffer, dwReaded, outBuffer, dwZipped);
item->dwZippedSize = dwZipped;
item->pData = outBuffer;
m_PackList.push_back(item);
} else {
delete item;
}
delete[] inBuffer;
}
}
CloseHandle(hFile);
}
}

void CZip::FetchEntry(const char* lpszOutPath) {
int i = 0;
CHAR szPath[MAX_PATH];
if(lpszOutPath == NULL) {
strcpy(szPath, m_szWorkDir);
} else {
OFSTRUCT os;
HFILE hFile = OpenFile(lpszOutPath, &os, OF_EXIST);
if(hFile != HFILE_ERROR) {
DWORD dwFileAttributes = GetFileAttributes(lpszOutPath);
if(dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) {
return;
}
} else {
CreateDirectory(lpszOutPath, NULL);
}
strcpy(szPath, lpszOutPath);
}
if(szPath[strlen(szPath) - 1] != '\\') {
strcat(szPath, "\\");
}
for(i = 0; i < m_PackList.size(); i ++) {
LPPACKITEM pItem = (LPPACKITEM)m_PackList[i];
CHAR szFile[MAX_PATH];
strcpy(szFile, szPath);
strcat(szFile, pItem->szFilePath);
if(pItem->cFileType == 1) {
CreateDirectory(szFile, NULL);
} else {
LPBYTE pData = NULL;
DWORD dwOutLength;
UnCompress(pItem->pData, pItem->dwZippedSize, pData, dwOutLength);
if(dwOutLength == pItem->dwUnzipSize) {
OFSTRUCT os;
HANDLE hFile = (HANDLE)OpenFile(szFile, &os, OF_CREATE | OF_WRITE);
if((HFILE)hFile != HFILE_ERROR) {
DWORD dwWritten;
WriteFile(hFile, pData, dwOutLength, &dwWritten, NULL);
}
CloseHandle(hFile);
}
delete[] pData;
}
}
}

/******** Public Interfaces ********/

/*
* Pack Files/Directorys into a single file.
* This can be modified into a much more smart interface.
*/
void CZip::Pack(const char* lpszInPath[], const char* lpszOutFile) {
int iItem = 0;
while(lpszInPath[iItem] != NULL) {
AddEntry(lpszInPath[iItem]);
iItem ++;
}
if(!m_PackList.empty()) {
OFSTRUCT os;
HANDLE hFile = (HANDLE)OpenFile(lpszOutFile, &os, OF_CREATE | OF_WRITE);
if((HFILE)hFile == HFILE_ERROR) {
return;
}
LPSTR pData = "IF"; // filename list separator
DWORD dwWritten;
for(iItem = 0; iItem < m_PackList.size(); iItem ++) {
WriteFile(hFile, pData, 2, &dwWritten, NULL);
LPPACKITEM pItem = (LPPACKITEM)m_PackList[iItem];
WriteFile(hFile, &pItem->cFileType, sizeof(CHAR), &dwWritten, NULL);
WriteFile(hFile, &pItem->szFilePath, strlen(pItem->szFilePath) + 1, &dwWritten, NULL);
WriteFile(hFile, &pItem->dwUnzipSize, sizeof(DWORD), &dwWritten, NULL);
WriteFile(hFile, &pItem->dwZippedSize, sizeof(DWORD), &dwWritten, NULL);
}
pData = "YR"; // data list separator
for(iItem = 0; iItem < m_PackList.size(); iItem ++) {
LPPACKITEM pItem = (LPPACKITEM)m_PackList[iItem];
while(pItem->cFileType == 1 && iItem < m_PackList.size()) { // Directory
iItem ++;
pItem = (LPPACKITEM)m_PackList[iItem];
}
if(iItem >= m_PackList.size()) {
break;
}
WriteFile(hFile, pData, 2, &dwWritten, NULL);
LPBYTE pBody = pItem->pData;
WriteFile(hFile, pBody, pItem->dwZippedSize, &dwWritten, NULL);
}
CloseHandle(hFile);

for(iItem = 0; iItem < m_PackList.size(); iItem ++) {
LPPACKITEM pItem = (LPPACKITEM)m_PackList[iItem];
if(pItem->cFileType != 1) { // Directory
LPBYTE pData = pItem->pData;
delete[] pData;
}
delete pItem;
}
}
}

/*
* Unpack a memory segment into Files/Directories.
*/
void CZip::Unpack(const BYTE* lpData, const DWORD nDataLength, const char* lpszOutPath) {
DWORD dwFileSize = nDataLength; // less than 4G
LPBYTE pData = (LPBYTE)lpData;
DWORD dwPos = 0;

while(dwPos < dwFileSize && strncmp((LPSTR)(pData + dwPos), "IF", 2) == 0) {
dwPos += 2;
LPPACKITEM pItem = new PackItem;
pItem->cFileType = *(LPSTR)(pData + dwPos);
dwPos += sizeof(CHAR);
strcpy(pItem->szFilePath, (LPSTR)(pData + dwPos));
dwPos += strlen(pItem->szFilePath) + 1;
pItem->dwUnzipSize = *(LPDWORD)(pData + dwPos);
dwPos += sizeof(DWORD);
pItem->dwZippedSize = *(LPDWORD)(pData + dwPos);
dwPos += sizeof(DWORD);
m_PackList.push_back(pItem);
}

int iItem = 0;
while(dwPos < dwFileSize && strncmp((LPSTR)(pData + dwPos), "YR", 2) == 0 && iItem < m_PackList.size()) {
dwPos += 2;
LPPACKITEM pItem = m_PackList[iItem];
while(pItem->cFileType == 1 && iItem < m_PackList.size()) { // Directory
iItem ++;
pItem = m_PackList[iItem];
}
if(iItem >= m_PackList.size()) {
break;
}
pItem->pData = (pData + dwPos);
dwPos += pItem->dwZippedSize;
iItem ++;
}
FetchEntry(lpszOutPath);
for(iItem = 0; iItem < m_PackList.size(); iItem ++) {
LPPACKITEM pItem = (LPPACKITEM)m_PackList[iItem];
delete pItem;
}
}

/*
* Unpack a packed file into Files/Directories.
*/
void CZip::Unpack(const char *lpszInfile, const char* lpszOutPath) {
OFSTRUCT os;
HANDLE hFile = (HANDLE)OpenFile(lpszInfile, &os, OF_READ | OF_SHARE_DENY_WRITE);
if((HFILE)hFile != HFILE_ERROR) {
BY_HANDLE_FILE_INFORMATION info;
if(GetFileInformationByHandle(hFile, &info)) {
DWORD dwFileSize = info.nFileSizeLow; // less than 4G
LPBYTE pData = new BYTE[dwFileSize];
DWORD dwReaded;
if(ReadFile(hFile, pData, dwFileSize, &dwReaded, NULL)) {
Unpack(pData, dwReaded, lpszOutPath);
}
delete[] pData;
}
CloseHandle(hFile);
}
}


用法:

#include <windows.h>
#include "zip.h"

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow) {
CZip zip;
if(lpCmdLine != NULL && strlen(lpCmdLine) != 0) {
LPSTR paramDecompress = strstr(lpCmdLine, "-d ");
LPSTR paramTarget = strstr(lpCmdLine, "-t ");
if(paramDecompress != NULL) {
LPSTR szFileZipped = strdup(paramDecompress + 3);
LPSTR szUnzipTarget = strdup(paramTarget + 3);
if(paramTarget != NULL && paramTarget > paramDecompress) {
szFileZipped[paramTarget - paramDecompress - 4] = 0;
} else if(paramTarget != NULL && paramDecompress > paramTarget) {
szUnzipTarget[paramDecompress - paramTarget - 4] = 0;
}
std::vector<LPSTR> fileList;
LPCSTR szSep = " ,\t\n";
LPSTR szToken = strtok(szFileZipped, szSep);
while(szToken) {
zip.Unpack(szFileZipped, szUnzipTarget);
szToken = strtok(NULL, szSep);
}
free(szUnzipTarget);
free(szFileZipped);
} else {
std::vector<LPSTR> fileList;
LPSTR fileUnzipped = lpCmdLine;
LPCSTR szSep = " ,\t\n";
LPSTR szToken = strtok(fileUnzipped, szSep);
while(szToken) {
fileList.push_back(szToken);
szToken = strtok(NULL, szSep);
}
if(fileList.empty()) {
return 0;
}
int nItemCount = fileList.size();
LPCSTR* szFileList = (LPCTSTR *)malloc(sizeof(LPTSTR) * (nItemCount + 1));
memcpy(szFileList, &fileList[0], sizeof(LPTSTR) * nItemCount);
szFileList[nItemCount] = NULL;
if(nItemCount == 1) {
LPSTR fileZipped = (CHAR *)malloc(strlen(szFileList[0]) + 5);
strcpy(fileZipped, fileUnzipped);
(strrchr(fileZipped, '.'))[0] = 0;
strcat(fileZipped, ".zpd");
zip.Pack(szFileList, fileZipped);
free(fileZipped);
} else {
zip.Pack(szFileList, "zip.zpd");
}
free(szFileList);
}
} else {
MessageBox(NULL,
"Compress Files:\n\tZip FileList\nDecompress Files:\n\tZip [-t TargetPath] -d ZippedFileList",
"Usage",
MB_OK);
}
return 0;
}

====================
Updated 2005-07-07:
应网友要求,提供编译通过的完整代码下载:请点这里

tututu -_-!!!

不知道这个有没有用http://sourceforge.net/projects/sevenzip/

那个太复杂了,不够简单实用。

大虾,你好,你能不能把编译通过的完整代码给我发一份呀,小弟将不胜感激.再此先谢过了!

不敢称大虾。

提供压缩包下载了,请见文末最新更新部分。

评论已关闭