// testZlib.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
//#define BOOST_IOSTREAMS_SOURCE
#include <boost/static_assert.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/counter.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/array.hpp>
#include <boost/crc.hpp>
//#include <boost/../libs/iostreams/src/zlib.cpp>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
typedef std::vector<char> DataStream;
using namespace std;
const DWORD dwVersion = MAKELONG(MAKEWORD('z', 'y'), MAKEWORD('z', 'f'));
struct PacketFileHeader
{
DWORD version;
DWORD dwFileHeaderPos; //FileHeader 开始的偏移位置
DWORD dwTotalFile; //保存了多少个文件.在文件头之后,都是每一个文件的内容,文件结尾保存文件的名字和原来大小及位置
};
const int packetFileHeaderLenght = sizeof(PacketFileHeader);
struct FileHeader
{
char fileName[32];
DWORD dwOriginFileSize; //原来文件的大小
DWORD dwFileOffset; //在压缩包中文件的偏移
DWORD dwFileSize; //压缩后的大小。
DWORD crc;
};
const int fileHeaderSize = sizeof(FileHeader);
const std::string strDir("E:\\QQ资源\\Data\\Head\\");
bool changeName(const char* src, const char* dst)
{
char buf[1024];
_snprintf(buf, 1024, "rename %s%s %s", strDir.c_str(), src, dst);
system(buf);
return true;
}
class CUnPacketFile
{
std::string m_strFilename;
HANDLE m_hReader;
std::vector<FileHeader> m_FileHeaders;
char* m_buffer;
bool m_bValid;
public:
CUnPacketFile() : m_hReader(INVALID_HANDLE_VALUE) , m_buffer(NULL), m_bValid(false)
{
}
~CUnPacketFile()
{
if (m_hReader != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hReader);
m_hReader = INVALID_HANDLE_VALUE;
}
}
DWORD GetUnFileSize(const char* pszFileName) //如果存在这个文件,返回大于0的值(需要解压缩的最小空间),否则返回0
{
if (!m_bValid)
{
return 0;
}
for (size_t i = 0; i < m_FileHeaders.size(); ++i)
{
if (strcmp(pszFileName, m_FileHeaders[i].fileName) == 0)
{
return m_FileHeaders[i].dwOriginFileSize;
}
}
return 0;
}
bool UnpackFile(const char* pszFileName, void* pBuffer, DWORD bufSize)
{
DWORD fileSize = GetUnFileSize(pszFileName); //得到文件原始大小。
if (fileSize == 0)
{
return false;
}
if (bufSize < fileSize)
{
return false;
}
FileHeader* pHeader = NULL;
for (size_t i = 0; i < m_FileHeaders.size(); ++i)
{
if (strcmp(pszFileName, m_FileHeaders[i].fileName) == 0)
{
pHeader = &m_FileHeaders[i];
break;
}
}
if (pHeader == NULL)
{
assert(0);
return false;
}
char* pStart = m_buffer + pHeader->dwFileOffset;
DWORD dwSize = pHeader->dwFileSize;
std::vector<char> out;
boost::iostreams::copy(boost::make_iterator_range(pStart, pStart + dwSize),
boost::iostreams::filtering_ostream(boost::iostreams::zlib_decompressor() | boost::iostreams::back_inserter(out)));
if (out.size() > bufSize)
{
return false;
}
memcpy(pBuffer, &out[0], out.size());
return true;
}
bool OpenPacket(const char* strPacketFileName)
{
m_bValid = false;
m_strFilename = strPacketFileName;
m_hReader = CreateFileA(m_strFilename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (m_hReader == INVALID_HANDLE_VALUE)
{
return false;
}
DWORD dwRead = 0;
DWORD dwHighSize, dwLowSize;
dwLowSize = GetFileSize(m_hReader, &dwHighSize);
if (dwHighSize != 0)
{
//文件太大,暂时不支持
CloseHandle(m_hReader);
m_hReader = INVALID_HANDLE_VALUE;
return false;
}
try
{
m_buffer = new char[dwLowSize];
}
catch(...)
{
m_buffer = NULL;
}
if (m_buffer == NULL)
{
CloseHandle(m_hReader);
m_hReader = INVALID_HANDLE_VALUE;
return false;
}
if(!ReadFile(m_hReader, m_buffer, dwLowSize, &dwRead, NULL) || (dwRead != dwLowSize)) //读入整个文件
{
CloseHandle(m_hReader);
m_hReader = INVALID_HANDLE_VALUE;
return false;
}
PacketFileHeader* pFileHeader = (PacketFileHeader*)m_buffer;
if (pFileHeader->version != dwVersion)
{
CloseHandle(m_hReader);
m_hReader = INVALID_HANDLE_VALUE;
return false;
}
if (dwLowSize != (pFileHeader->dwFileHeaderPos + sizeof(FileHeader) * pFileHeader->dwTotalFile)) //校验文件的长度。
{
CloseHandle(m_hReader);
m_hReader = INVALID_HANDLE_VALUE;
return false;
}
FileHeader* pFh = (FileHeader*)(m_buffer + pFileHeader->dwFileHeaderPos);
m_FileHeaders.clear();
boost::crc_32_type crc;
for (DWORD i = 0; i < pFileHeader->dwTotalFile; ++i)
{
//crc检验
crc.reset();
crc.process_bytes(m_buffer + pFh->dwFileOffset, pFh->dwFileSize);
if (crc.checksum() != pFh->crc)
{
CloseHandle(m_hReader);
m_hReader = INVALID_HANDLE_VALUE;
return false;
}
m_FileHeaders.push_back(*pFh++);
}
DWORD dwCheck = (const char*)pFh - m_buffer;
if(dwCheck != dwLowSize)
{
return false;
}
m_bValid = true;
return true;
}
};
bool PacketAFile(const char* fileName, DataStream& ds, FileHeader& fh)
{
memset(&fh, 0, sizeof(FileHeader));
strcpy(fh.fileName, fileName);
std::string strFullPathName = strDir;
strFullPathName += fileName;
HANDLE hFile = CreateFileA(strFullPathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
DWORD dwHigh = 0;
DWORD dwFileSize = GetFileSize(hFile, &dwHigh);
if (dwHigh != 0)
{
CloseHandle(hFile);
return false;
}
char *pBuffer = new char[dwFileSize];
DWORD dwFileRead = 0;
if(!ReadFile(hFile, pBuffer, dwFileSize, &dwFileRead, NULL))
{
delete[] pBuffer;
CloseHandle(hFile);
return false;
}
if (dwFileRead != dwFileSize)
{
delete[] pBuffer;
CloseHandle(hFile);
return false;
}
CloseHandle(hFile);
ds.resize(0);
boost::iostreams::copy(boost::make_iterator_range(pBuffer, pBuffer + dwFileRead),
boost::iostreams::filtering_ostream(boost::iostreams::zlib_compressor() | boost::iostreams::back_inserter(ds)));
fh.dwOriginFileSize = dwFileSize;
fh.dwFileSize = ds.size();
boost::crc_32_type crc;
crc.process_bytes(&ds[0], ds.size());
fh.crc = crc.checksum();
//偏址由调用者填写。
delete[] pBuffer;
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
char tmpBuf[32];
HANDLE hWriteFile = CreateFileA("d:\\res.dat", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hWriteFile == INVALID_HANDLE_VALUE)
{
std::cout << "Write file failed.\n";
return -1;
}
PacketFileHeader pfh;
DWORD dwFileWritten = 0;
if(!WriteFile(hWriteFile, &pfh, packetFileHeaderLenght, &dwFileWritten, NULL) || (dwFileWritten != packetFileHeaderLenght))
{
std::cout << "write file header failed.\n";
return -1;
}
int offset = packetFileHeaderLenght; //已经计入文件包的头部。
DataStream ds;
std::vector<FileHeader> fileHeaderArray;
FileHeader fh;
for (int i = 1; i <= 254; ++i)
{
_snprintf(tmpBuf, 32, "%d.png", i);
if (PacketAFile(tmpBuf, ds, fh)) //打包png
{
fh.dwFileOffset = offset;
offset += fh.dwFileSize;
if(!WriteFile(hWriteFile, &ds[0], ds.size(), &dwFileWritten, NULL) || (dwFileWritten != ds.size()))
{
std::cout << "write file " << tmpBuf << "failed.\n";
return -1;
}
fileHeaderArray.push_back(fh);
}
else
{
std::cout << "error:" << tmpBuf << std::endl;
return -1;
}
_snprintf(tmpBuf, 32, "%d_16.bmp", i);
if (PacketAFile(tmpBuf, ds, fh)) //打包bmp
{
fh.dwFileOffset = offset;
offset += fh.dwFileSize;
//out.write(&ds[0], ds.size());
if(!WriteFile(hWriteFile, &ds[0], ds.size(), &dwFileWritten, NULL) || (dwFileWritten != ds.size()))
{
std::cout << "write file " << tmpBuf << "failed.\n";
return -1;
}
fileHeaderArray.push_back(fh);
}
else
{
std::cout << "error:" << tmpBuf << std::endl;
return -1;
}
}
//if (PacketAFile("test.txt", ds, fh)) //写一个测试文件
//{
// fh.dwFileOffset = offset;
// offset += fh.dwFileSize;
// if(!WriteFile(hWriteFile, &ds[0], ds.size(), &dwFileWritten, NULL) || (dwFileWritten != ds.size()))
// {
// std::cout << "write file " << tmpBuf << "failed.\n";
// return -1;
// }
// fileHeaderArray.push_back(fh);
//}
//else
//{
// std::cout << "error:" << tmpBuf << std::endl;
// return -1;
//}
//写每个文件的文件头
for (int i = 0; i < fileHeaderArray.size(); ++i)
{
if(!WriteFile(hWriteFile, &fileHeaderArray[i], fileHeaderSize, &dwFileWritten, NULL) || (dwFileWritten != fileHeaderSize))
{
std::cout << "write file header info failed.\n";
return -1;
}
}
pfh.version = dwVersion;
pfh.dwTotalFile = fileHeaderArray.size();
pfh.dwFileHeaderPos = offset;
SetFilePointer(hWriteFile, 0, 0, FILE_BEGIN);
WriteFile(hWriteFile, &pfh, packetFileHeaderLenght, &dwFileWritten, NULL);
if (dwFileWritten != packetFileHeaderLenght)
{
std::cout << "修改文件头失败" << std::endl;
return -1;
}
CloseHandle(hWriteFile);
CUnPacketFile upf;
bool bSuccess = upf.OpenPacket("d:\\res.dat");
if (bSuccess)
{
DWORD dwSize = upf.GetUnFileSize("211.png");
if (dwSize)
{
unsigned char* pBuf = new unsigned char[dwSize];
hWriteFile = CreateFileA("d:\\211.png", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
DWORD dwWrite = 0;
if(upf.UnpackFile("211.png", pBuf, dwSize))
{
WriteFile(hWriteFile, pBuf, dwSize, &dwFileWritten, NULL);
}
else
{
std::cout << "写png文件失败!" << std::endl;
}
delete[] pBuf;
CloseHandle(hWriteFile);
}
}
return 0;
}