📄 ziparchive.cpp
字号:
WideToSingle(lpszComment, m_centralDir.m_pszComment);
m_centralDir.RemoveFromDisk();
if (m_bAutoFlush)
Flush();
return true;
}
int CZipArchive::GetCurrentDisk() const
{
return m_storage.GetCurrentDisk() + 1;
}
bool CZipArchive::SetFileComment(WORD uIndex, LPCTSTR lpszComment)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return false;
}
if (m_storage.IsSpanMode() == -1)
{
TRACE(_T("%s(%i) : You cannot modify the file comment in the existing disk spanning archive.\n"),__FILE__,__LINE__);
return false;
}
if (!m_centralDir.IsValidIndex(uIndex))
{
ASSERT(FALSE);
return false;
}
m_centralDir[uIndex]->SetComment(lpszComment);
m_centralDir.RemoveFromDisk();
if (m_bAutoFlush)
Flush();
return true;
}
void CZipArchive::CryptInitKeys()
{
ASSERT(m_pszPassword.GetSize());
m_keys[0] = 305419896L;
m_keys[1] = 591751049L;
m_keys[2] = 878082192L;
for (DWORD i = 0; i < m_pszPassword.GetSize(); i++)
CryptUpdateKeys(m_pszPassword[i]);
}
void CZipArchive::CryptUpdateKeys(char c)
{
m_keys[0] = CryptCRC32(m_keys[0], c);
m_keys[1] += m_keys[0] & 0xff;
m_keys[1] = m_keys[1] * 134775813L + 1;
c = char(m_keys[1] >> 24);
m_keys[2] = CryptCRC32(m_keys[2], c);
}
bool CZipArchive::CryptCheck()
{
CZipAutoBuffer buf(ZIPARCHIVE_ENCR_HEADER_LEN);
m_storage.Read(buf, ZIPARCHIVE_ENCR_HEADER_LEN, false);
BYTE b = 0;
for (int i = 0; i < ZIPARCHIVE_ENCR_HEADER_LEN; i++)
{
b = buf[i]; // only temporary
CryptDecode((char&)b);
}
// check the last byte
return CurrentFile()->IsDataDescr() ?
(BYTE(CurrentFile()->m_uModTime >> 8) == b) : (BYTE(CurrentFile()->m_uCrc32 >> 24) == b);
}
char CZipArchive::CryptDecryptByte()
{
int temp = (m_keys[2] & 0xffff) | 2;
return (char)(((temp * (temp ^ 1)) >> 8) & 0xff);
}
void CZipArchive::CryptDecode(char &c)
{
c ^= CryptDecryptByte();
CryptUpdateKeys(c);
}
bool CZipArchive::SetPassword(LPCTSTR lpszPassword)
{
if (m_iFileOpened != nothing)
{
TRACE(_T("%s(%i) : You cannot change the password when the file is opened.\n"),__FILE__,__LINE__);
return false; // it's important not to change the password when the file inside archive is opened
}
if (IsClosed())
{
TRACE(_T("%s(%i) : Setting the password for a closed archive has no effect.\n"),__FILE__,__LINE__);
}
if (lpszPassword)
{
int iLen = WideToSingle(lpszPassword, m_pszPassword);
if (iLen == -1)
return false;
for (size_t i = 0; (int)i < iLen; i++)
if (m_pszPassword[i] <= 0)
{
m_pszPassword.Release();
TRACE(_T("%s(%i) : The password contains forbidden characters. Password cleared.\n"),__FILE__,__LINE__);
return false;
}
}
else
m_pszPassword.Release();
return true;
}
CZipString CZipArchive::GetPassword()const
{
CZipString temp;
CZipArchive::SingleToWide(m_pszPassword, temp);
return temp;
}
DWORD CZipArchive::CryptCRC32(DWORD l, char c)
{
const DWORD *CRC_TABLE = get_crc_table();
return CRC_TABLE[(l ^ c) & 0xff] ^ (l >> 8);
}
void CZipArchive::CryptCryptHeader(long iCrc, CZipAutoBuffer &buf)
{
CryptInitKeys();
srand(UINT(time(NULL)));
// genereate pseudo-random sequence
char c;
for (int i = 0; i < ZIPARCHIVE_ENCR_HEADER_LEN - 2; i++)
{
int t1 = rand();
c = (char)(t1 >> 6);
if (!c)
c = (char)t1;
CryptEncode(c);
buf[i] = c;
}
c = (char)((iCrc >> 16) & 0xff);
CryptEncode(c);
buf[ZIPARCHIVE_ENCR_HEADER_LEN - 2] = c;
c = (char)((iCrc >> 24) & 0xff);
CryptEncode(c);
buf[ZIPARCHIVE_ENCR_HEADER_LEN - 1] = c;
}
void CZipArchive::CryptEncode(char &c)
{
char t = CryptDecryptByte();
CryptUpdateKeys(c);
c ^= t;
}
void CZipArchive::CryptEncodeBuffer()
{
if (CurrentFile()->IsEncrypted())
for (DWORD i = 0; i < m_info.m_uComprLeft; i++)
CryptEncode(m_info.m_pBuffer[i]);
}
void CZipArchive::CloseFileAfterTestFailed()
{
if (m_iFileOpened != extract)
{
TRACE(_T("%s(%i) : No file opened.\n"),__FILE__,__LINE__);
return;
}
m_info.ReleaseBuf();
m_centralDir.Clear(false);
m_iFileOpened = nothing;
}
bool CZipArchive::TestFile(WORD uIndex, DWORD uBufSize)
{
if (m_storage.IsSpanMode() == 1)
{
TRACE(_T("%s(%i) : You cannot test the spanning archive in creation.\n"),__FILE__,__LINE__);
return false;
}
if (!uBufSize)
return false;
CZipFileHeader* pHeader = m_centralDir[uIndex];
CZipActionCallback* pCallback = GetCallback(cbTest);
if (pCallback)
{
pCallback->Init(m_centralDir.GetProperHeaderFileName(pHeader));
}
if (pHeader->IsDirectory())
{
if (pCallback)
pCallback->SetTotal(0);
// we do not test whether the password for the encrypted directory
// is correct, since it seems to be senseless (anyway password
// encrypted directories should be avoided - it adds 12 bytes)
DWORD iSize = pHeader->m_uComprSize;
if ((iSize != 0 || iSize != pHeader->m_uUncomprSize)
// different treating compressed directories
&& !(pHeader->IsEncrypted() && iSize == 12 && !pHeader->m_uUncomprSize))
CZipException::Throw(CZipException::dirWithSize);
if (pCallback)
pCallback->CallbackEnd();
return true;
}
else
{
try
{
if (pCallback)
pCallback->SetTotal(pHeader->m_uUncomprSize);
if (!OpenFile(uIndex))
return false;
CZipAutoBuffer buf(uBufSize);
DWORD iRead;
int iAborted = 0;
do
{
iRead = ReadFile(buf, buf.GetSize());
if (pCallback && iRead)
if (!(*pCallback)(iRead))
{
if (iRead == buf.GetSize() && ReadFile(buf, 1) != 0) // test one byte if there is something left
iAborted = CZipException::abortedAction;
else
iAborted = CZipException::abortedSafely; // we did it!
break;
}
}
while (iRead == buf.GetSize());
bool bRet = CloseFile() != -1;
if (!bRet && iAborted == CZipException::abortedSafely)
iAborted = CZipException::abortedAction; // sorry, finished, but not successfull
if (pCallback)
pCallback->CallbackEnd();
if (iAborted)
CZipException::Throw(iAborted); // throw to distuingiush from other return codes
return bRet;
}
catch(...)
{
CloseFileAfterTestFailed();
throw;
}
}
}
int CZipArchive::WideToSingle(LPCTSTR lpWide, CZipAutoBuffer &szSingle)
{
#ifdef _UNICODE
return ZipPlatform::WideToSingle(lpWide, szSingle);
#else
size_t iLen = strlen(lpWide);
// if not UNICODE just copy
// iLen does not include the NULL character
szSingle.Allocate(iLen);
memcpy(szSingle, lpWide, iLen);
return iLen;
#endif
}
int CZipArchive::SingleToWide(const CZipAutoBuffer &szSingle, CZipString& szWide)
{
#ifdef _UNICODE
return ZipPlatform::SingleToWide(szSingle, szWide);
#else // if not UNICODE just copy
int singleLen = szSingle.GetSize();
// iLen does not include the NULL character
memcpy(szWide.GetBuffer(singleLen),szSingle.GetBuffer(), singleLen);
szWide.ReleaseBuffer(singleLen);
return singleLen;
#endif
}
void CZipArchive::CryptDecodeBuffer(DWORD uCount)
{
if (CurrentFile()->IsEncrypted())
for (DWORD i = 0; i < uCount; i++)
CryptDecode(m_info.m_pBuffer[i]);
}
void CZipArchive::EmptyPtrList()
{
if (m_list.GetCount())
{
// if some memory hasn't been freed due to an error in zlib, so free it now
CZipPtrListIter iter = m_list.GetHeadPosition();
while (m_list.IteratorValid(iter))
delete[] (char*) m_list.GetNext(iter);
}
m_list.RemoveAll();
}
void CZipArchive::SetFileHeaderAttr(CZipFileHeader& header, DWORD uAttr)
{
header.SetSystemCompatibility(m_iArchiveSystCompatib);
header.SetSystemAttr(uAttr);
}
void CZipArchive::EnableFindFast(bool bEnable)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : Set it after opening the archive.\n"),__FILE__,__LINE__);
return;
}
m_centralDir.EnableFindFast(bEnable, m_bCaseSensitive);
}
bool CZipArchive::SetSystemCompatibility(int iSystemComp)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : Set it after opening the archive.\n"),__FILE__,__LINE__);
return false;
}
if (m_iFileOpened == compress)
{
TRACE(_T("%s(%i) : Set it before opening a file inside archive.\n"),__FILE__,__LINE__);
return false;
}
if (!ZipCompatibility::IsPlatformSupported(iSystemComp))
return false;
m_iArchiveSystCompatib = iSystemComp;
return true;
}
void CZipArchive::SetRootPath(LPCTSTR szPath)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : Set it after opening the archive.\n"),__FILE__,__LINE__);
return;
}
if (m_iFileOpened != nothing)
{
TRACE(_T("%s(%i) : Set it before opening a file inside archive.\n"),__FILE__,__LINE__);
return;
}
if (szPath)
{
m_szRootPath = szPath;
CZipPathComponent::RemoveSeparators(m_szRootPath);
}
else
m_szRootPath.Empty();
}
CZipString CZipArchive::TrimRootPath(CZipPathComponent &zpc)const
{
if (m_szRootPath.IsEmpty())
return zpc.GetFileName();
CZipString szPath = zpc.GetFullPath();
return RemovePathBeginning(m_szRootPath, szPath, m_pZipCompare) ? szPath : zpc.GetFileName();
}
bool CZipArchive::RemovePathBeginning(LPCTSTR lpszBeginning, CZipString& szPath, ZIPSTRINGCOMPARE pCompareFunction)
{
CZipString szBeginning(lpszBeginning);
CZipPathComponent::RemoveSeparators(szBeginning);
int iRootPathLength = szBeginning.GetLength();
if (iRootPathLength && szPath.GetLength() >= iRootPathLength &&
(szPath.Left(iRootPathLength).*pCompareFunction)(szBeginning) == 0)
{
// the beginning is the same
if (szPath.GetLength() == iRootPathLength)
{
szPath.Empty();
return true;
}
// is the end of m_szPathRoot only a beginning of a directory name?
// check for a separator
// we know the length is larger, so we can write:
if (CZipPathComponent::IsSeparator(szPath[iRootPathLength]))
{
szPath = szPath.Mid(iRootPathLength);
CZipPathComponent::RemoveSeparatorsLeft(szPath);
return true;
}
}
return false;
}
void CZipArchive::SetTempPath(LPCTSTR lpszPath, bool bForce)
{
m_szTempPath = lpszPath;
if (lpszPath && bForce)
ZipPlatform::ForceDirectory(lpszPath);
CZipPathComponent::RemoveSeparators(m_szTempPath);
}
CZipString CZipArchive::PredictFileNameInZip(LPCTSTR lpszFilePath,
bool bFullPath, int iWhat, bool bExactly)const
{
CZipString sz = lpszFilePath;
if (sz.IsEmpty())
return _T("");
bool bAppend;
switch (iWhat)
{
case prFile:
bAppend = false;
break;
case prDir:
bAppend = true;
break;
default:
bAppend = CZipPathComponent::IsSeparator(sz[sz.GetLength() - 1]);
}
// remove for CZipPathComponent treating last name as a file even if dir
CZipPathComponent::RemoveSeparators(sz);
CZipPathComponent zpc(sz);
if (bFullPath)
{
if (m_bRemoveDriveLetter)
sz = zpc.GetNoDrive();
}
else
sz = TrimRootPath(zpc);
if (bAppend && !sz.IsEmpty())
CZipPathComponent::AppendSeparator(sz);
CZipFileHeader fh; // create a temporary object to convert
fh.SetFileName(sz);
if (bExactly)
{
fh.SetSystemCompatibility(m_iArchiveSystCompatib);
ZipCompatibility::FileNameUpdate(fh, false);
}
else
{
fh.SetSystemCompatibility(-1); // non existing system to prevent ansi oem conversion
ZipCompatibility::FileNameUpdate(fh, true);// update only path separators
}
return fh.GetFileName();
}
CZipString CZipArchive::PredictExtractedFileName(LPCTSTR lpszFileNameInZip, LPCTSTR lpszPath, bool bFullPath, LPCTSTR lpszNewName)const
{
CZipString szFile = lpszPath;
CZipString sz = lpszNewName ? lpszNewName : lpszFileNameInZip;
if (sz.IsEmpty())
return szFile;
if (!szFile.IsEmpty())
CZipPathComponent::AppendSeparator(szFile);
// remove for CZipPathComponent treating last name as a file even if dir
CZipPathComponent::RemoveSeparators(sz);
CZipPathComponent zpc(sz);
szFile += bFullPath ? (m_bRemoveDriveLetter ? zpc.GetNoDrive() : sz)
: TrimRootPath(zpc);
return szFile;
}
void CZipArchive::SetAutoFlush(bool bAutoFlush)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive not yet opened.\n"),__FILE__,__LINE__);
return;
}
if (m_storage.IsSpanMode() != 0)
{
TRACE(_T("%s(%i) : Cannot set auto-flush for the disk spanning archive.\n"),__FILE__,__LINE__);
return;
}
m_bAutoFlush = bAutoFlush;
}
void CZipArchive::Flush()
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive not yet opened.\n"),__FILE__,__LINE__);
return;
}
if (m_storage.IsSpanMode() < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -