443 lines
9.8 KiB
C++
443 lines
9.8 KiB
C++
// Zipper.cpp: implementation of the CZipper class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "Zipper.h"
|
|
|
|
#include "zip.h"
|
|
#include "iowin32.h"
|
|
#include "filemisc.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const UINT BUFFERSIZE = 2048;
|
|
|
|
CZipper::CZipper(LPCTSTR szFilePath, LPCTSTR szRootFolder, bool bAppend) : m_uzFile(0)
|
|
{
|
|
CloseZip();
|
|
|
|
if (szFilePath)
|
|
OpenZip(szFilePath, szRootFolder, bAppend);
|
|
}
|
|
|
|
CZipper::~CZipper()
|
|
{
|
|
CloseZip();
|
|
}
|
|
|
|
bool CZipper::CloseZip()
|
|
{
|
|
int nRet = m_uzFile ? zipClose(m_uzFile, NULL) : ZIP_OK;
|
|
|
|
m_uzFile = NULL;
|
|
m_szRootFolder[0] = 0;
|
|
ZeroMemory(&m_info, sizeof(m_info));
|
|
|
|
return (nRet == ZIP_OK);
|
|
}
|
|
|
|
void CZipper::GetFileInfo(Z_FileInfo& info)
|
|
{
|
|
info = m_info;
|
|
}
|
|
|
|
// simple interface
|
|
bool CZipper::ZipFile(LPCTSTR szFilePath)
|
|
{
|
|
// make zip path
|
|
char szDrive[_MAX_DRIVE], szFolder[MAX_PATH], szName[_MAX_FNAME];
|
|
_splitpath(szFilePath, szDrive, szFolder, szName, NULL);
|
|
|
|
char szZipPath[MAX_PATH];
|
|
_makepath(szZipPath, szDrive, szFolder, szName, "zip");
|
|
|
|
CZipper zip;
|
|
|
|
if (zip.OpenZip(szZipPath, false))
|
|
return zip.AddFileToZip(szFilePath, false);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
bool CZipper::ZipFolder(LPCTSTR szFilePath, bool bIgnoreFilePath)
|
|
{
|
|
// make zip path
|
|
char szDrive[_MAX_DRIVE], szFolder[MAX_PATH], szName[_MAX_FNAME];
|
|
_splitpath(szFilePath, szDrive, szFolder, szName, NULL);
|
|
|
|
char szZipPath[MAX_PATH];
|
|
_makepath(szZipPath, szDrive, szFolder, szName, "zip");
|
|
|
|
CZipper zip;
|
|
|
|
if (zip.OpenZip(szZipPath, FALSE))
|
|
return zip.AddFolderToZip(szFilePath, bIgnoreFilePath);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// works with prior opened zip
|
|
bool CZipper::AddFileToZip(LPCTSTR szFilePath, bool bIgnoreFilePath)
|
|
{
|
|
if (!m_uzFile)
|
|
return FALSE;
|
|
|
|
// we don't allow paths beginning with '..\' because this would be outside
|
|
// the root folder
|
|
if (!bIgnoreFilePath && strstr(szFilePath, "..\\") == szFilePath)
|
|
return false;
|
|
|
|
bool bFullPath = (strchr(szFilePath, ':') != NULL);
|
|
|
|
// if the file is relative then we need to append the root before opening
|
|
char szFullFilePath[MAX_PATH];
|
|
|
|
lstrcpy(szFullFilePath, szFilePath);
|
|
PrepareSourcePath(szFullFilePath);
|
|
|
|
// if the file is a fullpath then remove the root path bit
|
|
char szFileName[MAX_PATH] = "";
|
|
|
|
if (bIgnoreFilePath)
|
|
{
|
|
char szName[_MAX_FNAME], szExt[_MAX_EXT];
|
|
_splitpath(szFilePath, NULL, NULL, szName, szExt);
|
|
|
|
_makepath(szFileName, NULL, NULL, szName, szExt);
|
|
}
|
|
else if (bFullPath)
|
|
{
|
|
// check the root can be found
|
|
if (0 != _strnicmp(szFilePath, m_szRootFolder, lstrlen(m_szRootFolder)))
|
|
return false;
|
|
|
|
// else
|
|
lstrcpy(szFileName, szFilePath + lstrlen(m_szRootFolder));
|
|
}
|
|
else // relative path
|
|
{
|
|
// if the path begins with '.\' then remove it
|
|
if (strstr(szFilePath, ".\\") == szFilePath)
|
|
lstrcpy(szFileName, szFilePath + 2);
|
|
else
|
|
lstrcpy(szFileName, szFilePath);
|
|
}
|
|
|
|
// save file attributes
|
|
zip_fileinfo zfi;
|
|
|
|
zfi.internal_fa = 0;
|
|
zfi.external_fa = ::GetFileAttributes(szFilePath);
|
|
|
|
// save file time
|
|
SYSTEMTIME st;
|
|
|
|
GetLastModified(szFullFilePath, st, TRUE);
|
|
|
|
zfi.dosDate = 0;
|
|
zfi.tmz_date.tm_year = st.wYear;
|
|
zfi.tmz_date.tm_mon = st.wMonth - 1;
|
|
zfi.tmz_date.tm_mday = st.wDay;
|
|
zfi.tmz_date.tm_hour = st.wHour;
|
|
zfi.tmz_date.tm_min = st.wMinute;
|
|
zfi.tmz_date.tm_sec = st.wSecond;
|
|
|
|
// load input file
|
|
HANDLE hInputFile = ::CreateFile(szFullFilePath,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
NULL);
|
|
|
|
if (hInputFile == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
int nRet = zipOpenNewFileInZip(m_uzFile,
|
|
szFileName,
|
|
&zfi,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
Z_DEFLATED,
|
|
Z_DEFAULT_COMPRESSION);
|
|
|
|
if (nRet == ZIP_OK)
|
|
{
|
|
m_info.nFileCount++;
|
|
|
|
// read the file and output to zip
|
|
char pBuffer[BUFFERSIZE];
|
|
DWORD dwBytesRead = 0, dwFileSize = 0;
|
|
|
|
while (nRet == ZIP_OK && ::ReadFile(hInputFile, pBuffer, BUFFERSIZE, &dwBytesRead, NULL))
|
|
{
|
|
dwFileSize += dwBytesRead;
|
|
|
|
if (dwBytesRead)
|
|
nRet = zipWriteInFileInZip(m_uzFile, pBuffer, dwBytesRead);
|
|
else
|
|
break;
|
|
}
|
|
|
|
m_info.dwUncompressedSize += dwFileSize;
|
|
}
|
|
|
|
zipCloseFileInZip(m_uzFile);
|
|
::CloseHandle(hInputFile);
|
|
|
|
return (nRet == ZIP_OK);
|
|
}
|
|
|
|
bool CZipper::AddFileToZip(LPCTSTR szFilePath, LPCTSTR szRelFolderPath)
|
|
{
|
|
if (!m_uzFile)
|
|
return FALSE;
|
|
|
|
// szRelFolderPath cannot contain drive info
|
|
if (szRelFolderPath && strchr(szRelFolderPath, ':'))
|
|
return FALSE;
|
|
|
|
// if the file is relative then we need to append the root before opening
|
|
char szFullFilePath[MAX_PATH];
|
|
|
|
lstrcpy(szFullFilePath, szFilePath);
|
|
PrepareSourcePath(szFullFilePath);
|
|
|
|
// save file attributes and time
|
|
zip_fileinfo zfi;
|
|
|
|
zfi.internal_fa = 0;
|
|
zfi.external_fa = ::GetFileAttributes(szFilePath);
|
|
|
|
// save file time
|
|
SYSTEMTIME st;
|
|
|
|
GetLastModified(szFullFilePath, st, TRUE);
|
|
|
|
zfi.dosDate = 0;
|
|
zfi.tmz_date.tm_year = st.wYear;
|
|
zfi.tmz_date.tm_mon = st.wMonth - 1;
|
|
zfi.tmz_date.tm_mday = st.wDay;
|
|
zfi.tmz_date.tm_hour = st.wHour;
|
|
zfi.tmz_date.tm_min = st.wMinute;
|
|
zfi.tmz_date.tm_sec = st.wSecond;
|
|
|
|
// load input file
|
|
HANDLE hInputFile = ::CreateFile(szFullFilePath,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
NULL);
|
|
|
|
if (hInputFile == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
// strip drive info off filepath
|
|
char szName[_MAX_FNAME], szExt[_MAX_EXT];
|
|
_splitpath(szFilePath, NULL, NULL, szName, szExt);
|
|
|
|
// prepend new folder path
|
|
char szFileName[MAX_PATH];
|
|
_makepath(szFileName, NULL, szRelFolderPath, szName, szExt);
|
|
|
|
// open the file in the zip making sure we remove any leading '\'
|
|
int nRet = zipOpenNewFileInZip(m_uzFile,
|
|
szFileName + (szFileName[0] == '\\' ? 1 : 0),
|
|
&zfi,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
Z_DEFLATED,
|
|
Z_DEFAULT_COMPRESSION);
|
|
|
|
if (nRet == ZIP_OK)
|
|
{
|
|
m_info.nFileCount++;
|
|
|
|
// read the file and output to zip
|
|
char pBuffer[BUFFERSIZE];
|
|
DWORD dwBytesRead = 0, dwFileSize = 0;
|
|
|
|
while (nRet == ZIP_OK && ::ReadFile(hInputFile, pBuffer, BUFFERSIZE, &dwBytesRead, NULL))
|
|
{
|
|
dwFileSize += dwBytesRead;
|
|
|
|
if (dwBytesRead)
|
|
nRet = zipWriteInFileInZip(m_uzFile, pBuffer, dwBytesRead);
|
|
else
|
|
break;
|
|
}
|
|
|
|
m_info.dwUncompressedSize += dwFileSize;
|
|
}
|
|
|
|
zipCloseFileInZip(m_uzFile);
|
|
::CloseHandle(hInputFile);
|
|
|
|
return (nRet == ZIP_OK);
|
|
}
|
|
|
|
bool CZipper::AddFolderToZip(LPCTSTR szFolderPath, bool bIgnoreFilePath)
|
|
{
|
|
if (!m_uzFile)
|
|
return FALSE;
|
|
|
|
m_info.nFolderCount++;
|
|
|
|
// if the path is relative then we need to append the root before opening
|
|
char szFullPath[MAX_PATH];
|
|
|
|
lstrcpy(szFullPath, szFolderPath);
|
|
PrepareSourcePath(szFullPath);
|
|
|
|
// always add folder first
|
|
// save file attributes
|
|
zip_fileinfo zfi;
|
|
|
|
zfi.internal_fa = 0;
|
|
zfi.external_fa = ::GetFileAttributes(szFullPath);
|
|
|
|
SYSTEMTIME st;
|
|
|
|
GetLastModified(szFullPath, st, TRUE);
|
|
|
|
zfi.dosDate = 0;
|
|
zfi.tmz_date.tm_year = st.wYear;
|
|
zfi.tmz_date.tm_mon = st.wMonth - 1;
|
|
zfi.tmz_date.tm_mday = st.wDay;
|
|
zfi.tmz_date.tm_hour = st.wHour;
|
|
zfi.tmz_date.tm_min = st.wMinute;
|
|
zfi.tmz_date.tm_sec = st.wSecond;
|
|
|
|
// if the folder is a fullpath then remove the root path bit
|
|
char szFolderName[MAX_PATH] = "";
|
|
|
|
if (bIgnoreFilePath)
|
|
{
|
|
_splitpath(szFullPath, NULL, NULL, szFolderName, NULL);
|
|
}
|
|
else
|
|
{
|
|
// check the root can be found
|
|
if (0 != _strnicmp(szFullPath, m_szRootFolder, lstrlen(m_szRootFolder)))
|
|
return false;
|
|
|
|
// else
|
|
lstrcpy(szFolderName, szFullPath + lstrlen(m_szRootFolder));
|
|
}
|
|
|
|
// folders are denoted by a trailing '\\'
|
|
lstrcat(szFolderName, "\\");
|
|
|
|
// open the file in the zip making sure we remove any leading '\'
|
|
int nRet = zipOpenNewFileInZip(m_uzFile,
|
|
szFolderName,
|
|
&zfi,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
Z_DEFLATED,
|
|
Z_DEFAULT_COMPRESSION);
|
|
|
|
zipCloseFileInZip(m_uzFile);
|
|
|
|
// build searchspec
|
|
char szDrive[_MAX_DRIVE], szFolder[MAX_PATH], szName[_MAX_FNAME];
|
|
_splitpath(szFullPath, szDrive, szFolder, szName, NULL);
|
|
lstrcat(szFolder, szName);
|
|
|
|
char szSearchSpec[MAX_PATH];
|
|
_makepath(szSearchSpec, szDrive, szFolder, "*", "*");
|
|
|
|
WIN32_FIND_DATA finfo;
|
|
HANDLE hSearch = FindFirstFile(szSearchSpec, &finfo);
|
|
|
|
if (hSearch != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
if (finfo.cFileName[0] != '.')
|
|
{
|
|
char szItem[MAX_PATH];
|
|
_makepath(szItem, szDrive, szFolder, finfo.cFileName, NULL);
|
|
|
|
if (finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
AddFolderToZip(szItem, bIgnoreFilePath);
|
|
}
|
|
else
|
|
AddFileToZip(szItem, bIgnoreFilePath);
|
|
}
|
|
}
|
|
while (FindNextFile(hSearch, &finfo));
|
|
|
|
FindClose(hSearch);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// extended interface
|
|
bool CZipper::OpenZip(LPCTSTR szFilePath, LPCTSTR szRootFolder, bool bAppend)
|
|
{
|
|
CloseZip();
|
|
|
|
if (!szFilePath || !lstrlen(szFilePath))
|
|
return false;
|
|
|
|
// convert szFilePath to fully qualified path
|
|
char szFullPath[MAX_PATH];
|
|
|
|
if (!GetFullPathName(szFilePath, MAX_PATH, szFullPath, NULL))
|
|
return false;
|
|
|
|
// zipOpen will fail if bAppend is TRUE and zip does not exist
|
|
if (bAppend && ::GetFileAttributes(szFullPath) == 0xffffffff)
|
|
bAppend = false;
|
|
|
|
m_uzFile = zipOpen(szFullPath, bAppend ? 1 : 0);
|
|
|
|
if (m_uzFile)
|
|
{
|
|
if (!szRootFolder)
|
|
{
|
|
char szDrive[_MAX_DRIVE], szFolder[MAX_PATH];
|
|
_splitpath(szFullPath, szDrive, szFolder, NULL, NULL);
|
|
|
|
_makepath(m_szRootFolder, szDrive, szFolder, NULL, NULL);
|
|
}
|
|
else if (lstrlen(szRootFolder))
|
|
{
|
|
_makepath(m_szRootFolder, NULL, szRootFolder, "", NULL);
|
|
}
|
|
}
|
|
|
|
return (m_uzFile != NULL);
|
|
}
|
|
|
|
void CZipper::PrepareSourcePath(LPTSTR szPath)
|
|
{
|
|
bool bFullPath = (strchr(szPath, ':') != NULL);
|
|
|
|
// if the file is relative then we need to append the root before opening
|
|
if (!bFullPath)
|
|
{
|
|
char szTemp[MAX_PATH];
|
|
lstrcpy(szTemp, szPath);
|
|
|
|
_makepath(szPath, NULL, m_szRootFolder, szTemp, NULL);
|
|
}
|
|
}
|