📄 ziparchive.cpp
字号:
Flush();
if (pCallback)
pCallback->CallbackEnd();
return;
}
aIndexes.Sort(true);
CZipArray<CZipDeleteInfo> aInfo;
int iDelIndex = 0;
int iStep = 0; // for the compiler
if (pCallback)
{
pCallback->SetTotal(GetCount());
iStep = CZipActionCallback::m_iStep; // we don't want to wait forever
}
int i;
int uMaxDelIndex = aIndexes[uSize - 1];
for (i = aIndexes[0]; i < GetCount(); i++)
{
CZipFileHeader* pHeader = m_centralDir[i];
bool bDelete;
if (i <= uMaxDelIndex && i == aIndexes[iDelIndex])
{
iDelIndex++;
bDelete = true;
}
else
bDelete = false;
aInfo.Add(CZipDeleteInfo(pHeader, bDelete));
if (pCallback && (!(i % iStep)))
if (!(*pCallback)(iStep))
ThrowError(CZipException::abortedSafely);
}
ASSERT(iDelIndex == uSize);
uSize = aInfo.GetSize();
if (!uSize) // it is possible
return;
// now we start deleting (not safe to break)
pCallback = GetCallback(cbDelete);
if (pCallback)
pCallback->Init();
m_centralDir.RemoveFromDisk();
DWORD uTotalToMoveBytes = 0, uLastOffset = m_storage.m_pFile->GetLength() - m_centralDir.GetBytesBefore();
// count the number of bytes to move
for (i = uSize - 1; i >=0 ; i--)
{
const CZipDeleteInfo& di = aInfo[i];
if (!di.m_bDelete)
uTotalToMoveBytes += uLastOffset - di.m_pHeader->m_uOffset;
uLastOffset = di.m_pHeader->m_uOffset;
}
if (pCallback)
pCallback->CallbackEnd();
if (pCallback)
pCallback->SetTotal(uTotalToMoveBytes);
m_info.Init();
DWORD uMoveBy = 0, uOffsetStart = 0;
for (i = 0; i < uSize; i++)
{
const CZipDeleteInfo& di = aInfo[i];
if (di.m_bDelete)
{
// next hole
DWORD uTemp = di.m_pHeader->m_uOffset;
m_centralDir.RemoveFile(di.m_pHeader); // first remove
if (uOffsetStart)
{
// copy the files over a previous holes
MovePackedFiles(uOffsetStart, uTemp, uMoveBy, pCallback);
uOffsetStart = 0; // never be at the beginning, because the first file is always to be deleted
}
if (i == uSize - 1)
uTemp = (m_storage.m_pFile->GetLength() - m_centralDir.GetBytesBefore()) - uTemp;
else
uTemp = aInfo[i+1].m_pHeader->m_uOffset - uTemp;
uMoveBy += uTemp;
}
else
{
if (uOffsetStart == 0) // find contiuos area to move
uOffsetStart = di.m_pHeader->m_uOffset;
di.m_pHeader->m_uOffset -= uMoveBy;
}
}
if (uOffsetStart)
MovePackedFiles(uOffsetStart,
m_storage.m_pFile->GetLength() - m_centralDir.GetBytesBefore(),
uMoveBy, pCallback);
m_info.ReleaseBuf();
if (uMoveBy) // just in case
m_storage.m_pFile->SetLength(m_storage.m_pFile->GetLength() - uMoveBy);
if (pCallback)
pCallback->CallbackEnd();
if (m_bAutoFlush)
Flush();
}
bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath,
int iComprLevel,
bool bFullPath,
int iSmartLevel,
unsigned long nBufSize)
{
CZipAddNewFileInfo zanfi (lpszFilePath, bFullPath);
zanfi.m_iComprLevel = iComprLevel;
zanfi.m_iSmartLevel = zipsmSafeSmart;
zanfi.m_nBufSize = nBufSize;
return AddNewFile(zanfi);
}
bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath,
LPCTSTR lpszFileNameInZip,
int iComprLevel,
int iSmartLevel,
unsigned long nBufSize)
{
CZipAddNewFileInfo zanfi(lpszFilePath, lpszFileNameInZip);
zanfi.m_iComprLevel = iComprLevel;
zanfi.m_iSmartLevel = zipsmSafeSmart;
zanfi.m_nBufSize = nBufSize;
return AddNewFile(zanfi);
}
bool CZipArchive::AddNewFile(CZipMemFile& mf,
LPCTSTR lpszFileNameInZip,
int iComprLevel,
int iSmartLevel,
unsigned long nBufSize)
{
CZipAddNewFileInfo zanfi(&mf, lpszFileNameInZip);
zanfi.m_iComprLevel = iComprLevel;
zanfi.m_iSmartLevel = zipsmSafeSmart;
zanfi.m_nBufSize = nBufSize;
return AddNewFile(zanfi);
}
bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info)
{
// no need for ASSERT and TRACE here - it will be done by OpenNewFile
if (!m_info.m_iBufferSize)
return false;
CZipPathComponent::RemoveSeparators(info.m_szFilePath);
if (!info.m_szFilePath.IsEmpty()) // it may be empty after removing sep.
{
if (info.m_szFileNameInZip.IsEmpty())
{
CZipPathComponent zpc(info.m_szFilePath);
if (info.m_bFullPath)
{
if (m_bRemoveDriveLetter)
info.m_szFileNameInZip = zpc.GetNoDrive();
}
else
info.m_szFileNameInZip = TrimRootPath(zpc);
}
}
else if (!info.m_pFile)
return false;
bool bSpan = GetSpanMode() != 0;
// checking the iReplace index
if (!UpdateReplaceIndex(info.m_iReplaceIndex, info.m_szFileNameInZip))
return false;
bool bReplace = info.m_iReplaceIndex >= 0;
DWORD uAttr;
time_t ttime;
if (info.m_pFile)
{
uAttr = ZipPlatform::GetDefaultAttributes();
ttime = time(NULL);
}
else
{
if (!ZipPlatform::GetFileAttr(info.m_szFilePath, uAttr))
return false; // we don't know whether it is a file or a directory
if (!ZipPlatform::GetFileModTime(info.m_szFilePath, ttime))
ttime = time(NULL);
}
CZipFileHeader header;
header.SetFileName(info.m_szFileNameInZip);
if (ZipPlatform::GetSystemID() != ZipCompatibility::zcUnix)
uAttr |= ZipCompatibility::ConvertToSystem(uAttr, ZipPlatform::GetSystemID(), ZipCompatibility::zcUnix); // make it readable under Unix as well, since it stores its attributes in HIWORD(uAttr)
SetFileHeaderAttr(header, uAttr);
header.SetTime(ttime);
bool bInternal = (info.m_iSmartLevel & zipsmInternal01) != 0;
CZipActionCallback* pCallback = NULL;
if (!bInternal)
{
pCallback = GetCallback(cbAdd);
if (pCallback)
pCallback->Init(info.m_szFileNameInZip, info.m_szFilePath);
}
if (header.IsDirectory()) // will never be when m_pFile is not NULL, so we don't check it
{
ASSERT(!info.m_pFile); // should never happened
ASSERT(!bInternal);
if (pCallback)
pCallback->SetTotal(0); // in case of calling LeftToDo afterwards
// clear password for a directory
bool bRet = false;
CZipSmClrPass smcp;
if (info.m_iSmartLevel & zipsmCPassDir)
smcp.ClearPasswordSmartly(this);
bRet = OpenNewFile(header, bReplace ? (info.m_iReplaceIndex << 16) | ZIP_COMPR_REPL_SIGN : 0);
CloseNewFile();
if (pCallback)
pCallback->CallbackEnd();
return bRet;
}
CZipSmClrPass smcp;
bool bIsCompression = info.m_iComprLevel != 0;
bool bEff = (info.m_iSmartLevel & zipsmCheckForEff)&& bIsCompression;
bool bCheckForZeroSized = (info.m_iSmartLevel & zipsmCPFile0) && !GetPassword().IsEmpty();
bool bCheckForSmallFiles = (info.m_iSmartLevel & zipsmNotCompSmall) && bIsCompression;
DWORD iFileSize = DWORD(-1);
bool bNeedTempArchive = (bEff && bSpan) || (bReplace && bIsCompression);
if (bCheckForSmallFiles || bCheckForZeroSized || bNeedTempArchive)
{
if (info.m_pFile)
iFileSize = info.m_pFile->GetLength();
else
{
if (!ZipPlatform::GetFileSize(info.m_szFilePath, iFileSize) && bEff)
bEff = false; // the file size is needed only when eff. in span mode
}
if (iFileSize != DWORD(-1))
{
if (bCheckForZeroSized && iFileSize == 0)
smcp.ClearPasswordSmartly(this);
if (bCheckForSmallFiles && iFileSize < 5)
info.m_iComprLevel = 0;
}
}
bool bEffInMem = bEff && (info.m_iSmartLevel & zipsmMemoryFlag);
CZipString szTempFileName;
if (bNeedTempArchive && (bEffInMem ||
!(szTempFileName = ZipPlatform::GetTmpFileName(
m_szTempPath.IsEmpty() ? NULL : (LPCTSTR)m_szTempPath, iFileSize)
).IsEmpty()))
{
CZipMemFile* pmf = NULL;
CZipArchive zip;
try
{
// compress first to a temporary file, if ok - copy the data, if not - add storing
if (bEffInMem)
{
pmf = new CZipMemFile;
zip.Open(*pmf, zipCreate);
}
else
zip.Open(szTempFileName, zipCreate);
zip.SetRootPath(m_szRootPath);
zip.SetPassword(GetPassword());
zip.SetSystemCompatibility(m_iArchiveSystCompatib);
zip.SetCallback(pCallback, cbAdd);
// create a temporary file
int iTempReplaceIndex = info.m_iReplaceIndex;
info.m_iSmartLevel = zipsmLazy;
info.m_iReplaceIndex = -1;
if (!zip.AddNewFile(info))
throw false;
info.m_iReplaceIndex = iTempReplaceIndex;
// this may also happen when bReplace, but not in span mode
if (bEff)
{
CZipFileHeader fh;
zip.GetFileInfo(fh, 0);
if (!fh.CompressionEfficient())
{
info.m_iComprLevel = 0;
info.m_iSmartLevel = zipsmInternal01;
// compression is pointless, store instead
throw AddNewFile(info);
}
}
m_info.Init();
throw GetFromArchive(zip, 0, info.m_iReplaceIndex, true, GetCallback(cbAddTmp));
}
catch (bool bRet)
{
zip.Close(!bRet); // that doesn't really matter how it will be closed
if (pmf)
delete pmf;
if (!bEffInMem)
ZipPlatform::RemoveFile(szTempFileName, false);
m_info.ReleaseBuf();
return bRet;
}
catch (...)
{
zip.Close(true);
if (pmf)
delete pmf;
if (!bEffInMem)
ZipPlatform::RemoveFile(szTempFileName, false);
m_info.ReleaseBuf();
throw;
}
}
// try to open before adding
CZipFile f;
CZipAbstractFile *pf;
if (info.m_pFile)
pf = info.m_pFile;
else
{
if (!f.Open(info.m_szFilePath, CZipFile::modeRead | CZipFile::shareDenyWrite, false))
{
if (pCallback)
pCallback->CallbackEnd();
return false;
}
pf = &f;
}
ASSERT(pf);
// call init before opening (in case of exception we have the names)
iFileSize = pf->GetLength();
bool bRet;
if (bReplace)
{
ASSERT(!bIsCompression);
bRet = OpenNewFile(header, (info.m_iReplaceIndex << 16) | ZIP_COMPR_REPL_SIGN , NULL, iFileSize);
}
else
bRet = OpenNewFile(header, info.m_iComprLevel);
if (!bRet)
{
if (pCallback)
pCallback->CallbackEnd();
return false;
}
if (bInternal)
{
// we do it here, because if in OpenNewFile is replacing
// then we get called cbReplace callback before and it would
// overwrite callback information written in pCallback->Init
pCallback = GetCallback(cbAddStore);
if (pCallback)
pCallback->Init(info.m_szFileNameInZip, info.m_szFilePath);
}
if (pCallback)
pCallback->SetTotal(iFileSize);
CZipAutoBuffer buf(info.m_nBufSize);
DWORD iRead;
int iAborted = 0;
do
{
iRead = pf->Read(buf, info.m_nBufSize);
if (iRead)
{
WriteNewFile(buf, iRead);
if (pCallback)
if (!(*pCallback)(iRead))
{
// todo: we could remove here the bytes of the file partially added if not disk-spanning
if (iRead == buf.GetSize() && pf->Read(buf, 1) != 0) // test one byte if there is something left
{
if (!m_storage.IsSpanMode() && !bReplace)
{
RemoveLast(true);
CloseNewFile(true);
iAborted = CZipException::abortedSafely;
}
else
iAborted = CZipException::abortedAction;
}
else
{
iAborted = CZipException::abortedSafely; // we did it!
CloseNewFile();
}
break;
}
}
}
while (iRead == buf.GetSize());
if (!iAborted)
CloseNewFile();
if (pCallback)
pCallback->CallbackEnd();
if (iAborted)
CZipException::Throw(iAborted); // throw to distuinguish from other return codes
if (bEff)
{
// remove the last file and add it without the compression if needed
if (!info.m_pFile)
f.Close();
buf.Release();
if (RemoveLast())
{
info.m_iComprLevel = 0;
info.m_iSmartLevel = zipsmInternal01;
return AddNewFile(info);
}
}
return true;
}
bool CZipArchive::RemoveLast(bool bRemoveAnyway)
{
int iIndex = GetCount() - 1;
if (iIndex < 0)
return false;
CZipFileHeader* pHeader = m_centralDir[iIndex];
if (!bRemoveAnyway && pHeader->CompressionEfficient())
return false;
m_centralDir.RemoveLastFile(pHeader, iIndex);
return true;
}
CZipString CZipArchive::GetArchivePath() const
{
if (IsClosed(false))
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return _T("");
}
return m_storage.m_pFile->GetFilePath();
}
CZipString CZipArchive::GetGlobalComment() const
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return _T("");
}
CZipString temp;
return SingleToWide(m_centralDir.m_pszComment, temp) != -1 ? (LPCTSTR)temp : _T("");
}
bool CZipArchive::SetGlobalComment(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 global comment of the existing disk spanning archive.\n"),__FILE__,__LINE__);
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -