⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ziparchive.cpp

📁 ZIP压缩代码:基于开源ZipArchive和zlib
💻 CPP
📖 第 1 页 / 共 5 页
字号:
			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 + -