📄 ziparchive.cpp
字号:
bool CZipArchive::OpenNewFile(CZipFileHeader & header,
int iLevel,
LPCTSTR lpszFilePath, DWORD uInternal)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return false;
}
if (m_iFileOpened)
{
TRACE(_T("%s(%i) : A file already opened.\n"),__FILE__,__LINE__);
return false;
}
if (m_storage.IsSpanMode() == -1)
{
TRACE(_T("%s(%i) : You cannot add files to the existing disk spannig archive.\n"),__FILE__,__LINE__);
return false;
}
if (GetCount() ==(WORD)USHRT_MAX)
{
TRACE(_T("%s(%i) : Maximum file count inside archive reached.\n"),__FILE__,__LINE__);
return false;
}
DWORD uAttr = 0; // ..compiler
time_t ttime;
if (lpszFilePath)
{
if (!ZipPlatform::GetFileAttr(lpszFilePath, uAttr))
// do not continue - if the file was a directory then not recognizing it will cause
// serious errors (need uAttr to recognize it)
return false;
if (!ZipPlatform::GetFileModTime(lpszFilePath, ttime))
ttime = time(NULL);
}
m_info.Init();
if (lpszFilePath)
{
header.SetTime(ttime);
SetFileHeaderAttr(header, uAttr); // set system compatibility as well
}
else
header.SetSystemCompatibility(m_iArchiveSystCompatib);
CZipString szFileName = header.GetFileName();
bool bIsDirectory = header.IsDirectory();
if (bIsDirectory)
{
int iNameLen = szFileName.GetLength();
if (!iNameLen || !CZipPathComponent::IsSeparator(szFileName[iNameLen-1]))
{
szFileName += CZipPathComponent::m_cSeparator;
header.SetFileName(szFileName);
}
}
if (szFileName.IsEmpty())
{
szFileName.Format(_T("file%i"), GetCount());
header.SetFileName(szFileName);
}
// make sure that all slashes are correct (as the current system default)
// because AddNewFile calls InsertFindFastElement if necessary and
// the find array keeps all the files already converted to the current system standards
// we do not perform Oem->Ansi here, because who would pass oem values here?
//
ZipCompatibility::SlashBackslashChg(header.m_pszFileName, true);
bool bEncrypted = m_pszPassword.GetSize() != 0;
#ifdef _DEBUG
if (bIsDirectory && bEncrypted)
TRACE(_T("%s(%i) : Encrypting a directory. It's pointless.\n\
Clear the password before adding a directory.\n"),__FILE__,__LINE__);
#endif
int iReplaceIndex = -1;
bool bReplace = (iLevel & 0xffff) == ZIP_COMPR_REPL_SIGN;
if (bReplace)
{
int iMask = ZIP_COMPR_REPL_MASK;
iReplaceIndex = (iLevel & iMask) >> 16;
iLevel = (char)(iLevel & ~iMask);
ASSERT(iLevel == 0);
}
else
uInternal = 0;
if (iLevel < -1 || iLevel > 9)
iLevel = -1;
if (!header.PrepareData(iLevel, m_storage.IsSpanMode() == 1, bEncrypted))
ThrowError(CZipException::tooLongFileName);
if (bReplace)
{
uInternal += header.GetSize(true);
if (header.IsEncrypted())
uInternal += ZIPARCHIVE_ENCR_HEADER_LEN;
if (header.IsDataDescr())
uInternal += ZIPARCHIVE_DATADESCRIPTOR_LEN + 4; // CZipCentralDir::CloseNewFile
}
m_centralDir.AddNewFile(header, iReplaceIndex);
if (bReplace)
MakeSpaceForReplace(iReplaceIndex, uInternal, szFileName);
// this ensures the conversion will take place anyway (must take because we are going
// to write the local header in a moment
m_centralDir.ConvertFileName(false, m_centralDir.m_bConvertAfterOpen);
CurrentFile()->WriteLocal(m_storage);
// we have written the local header, but if we keep filenames not converted
// in memory , we have to restore the non-converted value
if (m_centralDir.m_bConvertAfterOpen)
CurrentFile()->SetFileName(szFileName);
if (bEncrypted)
{
CZipAutoBuffer buf(ZIPARCHIVE_ENCR_HEADER_LEN);
// use pseudo-crc since we don't know it yet
CryptCryptHeader((long)header.m_uModTime << 16, buf);
m_storage.Write(buf, ZIPARCHIVE_ENCR_HEADER_LEN, false);
}
m_info.m_uComprLeft = 0;
m_info.m_stream.avail_in = (uInt)0;
m_info.m_stream.avail_out = (uInt)m_info.m_pBuffer.GetSize();
m_info.m_stream.next_out = (Bytef*)(char*)m_info.m_pBuffer;
m_info.m_stream.total_in = 0;
m_info.m_stream.total_out = 0;
if (bIsDirectory && (CurrentFile()->m_uMethod != 0))
CurrentFile()->m_uMethod = 0;
if (CurrentFile()->m_uMethod == Z_DEFLATED)
{
m_info.m_stream.opaque = m_bDetectZlibMemoryLeaks ? &m_list : 0;
int err = deflateInit2(&m_info.m_stream, iLevel,
Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
CheckForError(err);
}
m_iFileOpened = compress;
return true;
}
bool CZipArchive::ExtractFile(WORD uIndex,
LPCTSTR lpszPath,
bool bFullPath,
LPCTSTR lpszNewName,
DWORD nBufSize)
{
if (!nBufSize && !lpszPath)
return false;
CZipFileHeader header;
GetFileInfo(header, uIndex); // to ensure that slash and oem conversions take place
CZipString szFileNameInZip = (LPCTSTR)header.GetFileName();
CZipString szFile = PredictExtractedFileName(szFileNameInZip, lpszPath, bFullPath, lpszNewName);
CZipActionCallback* pCallback = GetCallback(cbExtract);
if (pCallback)
pCallback->Init(szFileNameInZip, szFile);
if (header.IsDirectory())
{
if (pCallback)
pCallback->SetTotal(0); // in case of calling LeftToDo afterwards
ZipPlatform::ForceDirectory(szFile);
ZipPlatform::SetFileAttr(szFile, header.GetSystemAttr());
if (pCallback)
pCallback->CallbackEnd();
return true;
}
else
{
if (pCallback)
pCallback->SetTotal(header.m_uUncomprSize);
if (!OpenFile(uIndex))
return false;
CZipPathComponent zpc(szFile);
ZipPlatform::ForceDirectory(zpc.GetFilePath());
CZipFile f(szFile, CZipFile::modeWrite |
CZipFile::modeCreate | CZipFile::shareDenyWrite);
DWORD iRead;
CZipAutoBuffer buf(nBufSize);
int iAborted = 0;
do
{
iRead = ReadFile(buf, buf.GetSize());
if (iRead)
{
f.Write(buf, iRead);
if (pCallback)
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(f) == 1;
if (!bRet && iAborted == CZipException::abortedSafely)
iAborted = CZipException::abortedAction; // sorry, finished, but not successfull
if (pCallback)
pCallback->CallbackEnd();
if (iAborted)
CZipException::Throw(iAborted, szFile); // throw to distuingiush from other return codes
return bRet;
}
}
bool CZipArchive::ExtractFile(WORD uIndex,
CZipMemFile& mf,
DWORD nBufSize)
{
if (!nBufSize)
return false;
CZipFileHeader header;
GetFileInfo(header, uIndex); // to ensure that slash and oem conversions take place
CZipActionCallback* pCallback = GetCallback(cbExtract);
if (pCallback)
{
pCallback->Init(header.GetFileName());
pCallback->SetTotal(header.m_uUncomprSize);
}
if (header.IsDirectory() || !OpenFile(uIndex))
return false;
CZipAutoBuffer buf(nBufSize);
mf.SeekToEnd();
DWORD iRead;
int iAborted = 0;
do
{
iRead = ReadFile(buf, buf.GetSize());
if (iRead)
{
mf.Write(buf, iRead);
if (pCallback)
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;
}
void CZipArchive::SetExtraField(const char *pBuf, WORD iSize)
{
if (m_iFileOpened != compress)
{
TRACE(_T("%s(%i) : A new file must be opened.\n"),__FILE__,__LINE__);
return;
}
if (!pBuf || !iSize)
return;
CurrentFile()->m_pExtraField.Allocate(iSize);
memcpy(CurrentFile()->m_pExtraField, pBuf, iSize);
}
bool CZipArchive::WriteNewFile(const void *pBuf, DWORD iSize)
{
if (m_iFileOpened != compress)
{
TRACE(_T("%s(%i) : A new file must be opened.\n"),__FILE__,__LINE__);
return false;
}
m_info.m_stream.next_in = (Bytef*)pBuf;
m_info.m_stream.avail_in = iSize;
CurrentFile()->m_uCrc32 = crc32(CurrentFile()->m_uCrc32, (Bytef*)pBuf, iSize);
while (m_info.m_stream.avail_in > 0)
{
if (m_info.m_stream.avail_out == 0)
{
CryptEncodeBuffer();
m_storage.Write(m_info.m_pBuffer, m_info.m_uComprLeft, false);
m_info.m_uComprLeft = 0;
m_info.m_stream.avail_out = m_info.m_pBuffer.GetSize();
m_info.m_stream.next_out = (Bytef*)(char*)m_info.m_pBuffer;
}
if (CurrentFile()->m_uMethod == Z_DEFLATED)
{
DWORD uTotal = m_info.m_stream.total_out;
int err = deflate(&m_info.m_stream, Z_NO_FLUSH);
CheckForError(err);
m_info.m_uComprLeft += m_info.m_stream.total_out - uTotal;
}
else
{
DWORD uToCopy = (m_info.m_stream.avail_in < m_info.m_stream.avail_out)
? m_info.m_stream.avail_in : m_info.m_stream.avail_out;
memcpy(m_info.m_stream.next_out, m_info.m_stream.next_in, uToCopy);
m_info.m_stream.avail_in -= uToCopy;
m_info.m_stream.avail_out -= uToCopy;
m_info.m_stream.next_in += uToCopy;
m_info.m_stream.next_out += uToCopy;
m_info.m_stream.total_in += uToCopy;
m_info.m_stream.total_out += uToCopy;
m_info.m_uComprLeft += uToCopy;
}
}
return true;
}
bool CZipArchive::CloseNewFile(bool bAfterException)
{
if (m_iFileOpened != compress)
{
TRACE(_T("%s(%i) : A new file must be opened.\n"),__FILE__,__LINE__);
return false;
}
m_info.m_stream.avail_in = 0;
if (!bAfterException)
{
int err = Z_OK;
if (CurrentFile()->m_uMethod == Z_DEFLATED)
while (err == Z_OK)
{
if (m_info.m_stream.avail_out == 0)
{
CryptEncodeBuffer();
m_storage.Write(m_info.m_pBuffer, m_info.m_uComprLeft, false);
m_info.m_uComprLeft = 0;
m_info.m_stream.avail_out = m_info.m_pBuffer.GetSize();
m_info.m_stream.next_out = (Bytef*)(char*)m_info.m_pBuffer;
}
DWORD uTotal = m_info.m_stream.total_out;
err = deflate(&m_info.m_stream, Z_FINISH);
m_info.m_uComprLeft += m_info.m_stream.total_out - uTotal;
}
if (err == Z_STREAM_END)
err = Z_OK;
CheckForError(err);
if (m_info.m_uComprLeft > 0)
{
CryptEncodeBuffer();
m_storage.Write(m_info.m_pBuffer, m_info.m_uComprLeft, false);
}
if (CurrentFile()->m_uMethod == Z_DEFLATED)
{
err = deflateEnd(&m_info.m_stream);
CheckForError(err);
}
// it may be increased by the encrypted header size
CurrentFile()->m_uComprSize += m_info.m_stream.total_out;
CurrentFile()->m_uUncomprSize = m_info.m_stream.total_in;
m_centralDir.CloseNewFile();
}
else
m_centralDir.m_pOpenedFile = NULL;
m_iFileOpened = nothing;
m_info.ReleaseBuf();
EmptyPtrList();
if (m_bAutoFlush && !bAfterException)
Flush();
return true;
}
void CZipArchive::DeleteFile(WORD uIndex)
{
CZipWordArray indexes;
indexes.Add(uIndex);
DeleteFiles(indexes);
}
void CZipArchive::GetIndexes(const CZipStringArray &aNames, CZipWordArray& aIndexes)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return;
}
int iSize = aNames.GetSize();
for (WORD i = 0; i < iSize; i++)
{
int idx = FindFile(aNames[i], ffDefault, false);
if (idx != -1)
aIndexes.Add((WORD)idx);
}
}
void CZipArchive::DeleteFiles(const CZipStringArray &aNames)
{
CZipWordArray indexes;
GetIndexes(aNames, indexes);
DeleteFiles(indexes);
}
void CZipArchive::DeleteFiles(CZipWordArray &aIndexes)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return;
}
if (m_storage.IsSpanMode())
{
TRACE(_T("%s(%i) : You cannot delete files from the disk spannig archive.\n"),__FILE__,__LINE__);
return;
}
if (m_iFileOpened)
{
TRACE(_T("%s(%i) : You cannot delete files if there is a file opened.\n"),__FILE__,__LINE__);
return;
}
CZipActionCallback* pCallback = GetCallback(cbDeleteCnt);
if (pCallback)
pCallback->Init();
int uSize = aIndexes.GetSize();
if (!uSize)
{
TRACE(_T("%s(%i) : The indekses array is empty.\n"),__FILE__,__LINE__);
return;
}
// remove all - that's easy so don't waste the time
if (uSize == GetCount())
{
pCallback = GetCallback(cbDelete);
if (pCallback)
{
// do it right and sent the notification
pCallback->Init();
pCallback->SetTotal(uSize);
}
m_centralDir.RemoveFromDisk();
m_storage.m_pFile->SetLength(m_centralDir.GetBytesBefore());
m_centralDir.RemoveAll();
if (m_bAutoFlush)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -