예제 #1
0
파일: CentralDir.cpp 프로젝트: F5000/spree
void CCentralDir::Write()
{
	if (m_bOnDisk)
		return;
	if (!m_pStorage->IsSpanMode())
	{
		m_pStorage->Flush();
		m_pStorage->m_file.SeekToEnd();
	}
	if (m_szComment.GetLength() > USHRT_MAX)
		m_szComment = m_szComment.Left(USHRT_MAX);
	m_uCommentSize = (WORD)m_szComment.GetLength();
	m_uEntriesNumber = (WORD)m_headers.GetSize();
	m_uSize = 0;
	bool bDontAllowDiskChange = false;
	// if there is a disk spanning archive in creation and it is only one-volume,
	//	(current disk is 0 so far, no bytes has been written so we know they are 
	//  all in the buffer)	make sure that it will be after writting central dir 
	// and make it a non disk spanning archive
	if (m_pStorage->IsSpanMode() && !m_pStorage->GetCurrentDisk())
	{
		DWORD uVolumeFree = m_pStorage->VolumeLeft();
		// calculate the size of data descriptors already in the buffer or on the disk
		// (they will be removed in the non disk spanning archive):
		// multi span signature at the beginnig (4 bytes) + the size of the data 
		// descr. for each file (multi span signature + 12 bytes data)
		// the count of bytes to add: central dir size - total to remove;
		DWORD uToGrow = GetSize(true) - (4 + m_uEntriesNumber * (4 + 12)); 
		if (uVolumeFree >= uToGrow) // lets make sure it will be one-disk archive
		{
			// can the operation be done only in the buffer?
			if (!m_pStorage->m_iBytesWritten && // no bytes on the disk yet
				(m_pStorage->GetFreeInBuffer() >= uToGrow)) // is the buffer big enough?
			{
					RemoveDataDescr(true);
					bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
			}
			else
			{
				m_pStorage->Flush();
				m_pStorage->m_file.Flush();
				if (RemoveDataDescr(false))
					bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
			}
		}
	}

	WriteHeaders();
	m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
	DWORD uSize = WriteCentralEnd();
	if (bDontAllowDiskChange && (m_pStorage->GetCurrentDisk() != 0))
		ThrowError(ZIP_BADZIPFILE);
	// if after adding a central directory there is a disk change, 
	// update the information and write it again
	if (m_uThisDisk != m_pStorage->GetCurrentDisk())
	{
		m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
		if (m_uEntriesNumber)
		{
			m_uDiskEntriesNo = 0;	
		}
		else
		{
			m_uDiskWithCD = m_uThisDisk;
			m_uOffset = 0;
		}

		if (m_pStorage->m_uBytesInWriteBuffer >= uSize)
			// if the data is still in the buffer, simply remove it
			m_pStorage->m_uBytesInWriteBuffer -= uSize;
		else
		{
			m_pStorage->Flush();
			m_pStorage->m_iBytesWritten -= uSize;
			m_pStorage->m_file.SeekToBegin();	
		}
		
		WriteCentralEnd();
	}

}
예제 #2
0
void CZipCentralDir::Write(CZipActionCallback* pCallback)
{
	if (m_info.m_bOnDisk)
		return;
	if (!m_pStorage->IsSpanMode())
	{
		m_pStorage->Flush();
		m_pStorage->m_pFile->SeekToEnd();
	}

// 	else
// 		// we are at the end already

	m_info.m_uEntriesNumber = (WORD)m_headers.GetSize();
	m_info.m_uSize = 0;
	bool bDontAllowDiskChange = false;
	// if there is a disk spanning archive in creation and it is only one-volume,
	//	(current disk is 0 so far, no bytes has been written so we know they are 
	//  all in the buffer)	make sure that it will be after writing central dir 
	// and make it a non disk spanning archive
	if (m_pStorage->IsSpanMode() && m_pStorage->GetCurrentDisk() == 0)
	{
		DWORD uVolumeFree = m_pStorage->VolumeLeft();
		// calculate the size of data descriptors already in the buffer or on the disk
		// (they will be removed in the non disk spanning archive):
		// multi span signature at the beginnig (4 bytes) + the size of the data 
		// descr. for each file (multi span signature + 12 bytes data)
		// the number of bytes to add: central dir size - total to remove;
		DWORD uToGrow = GetSize(true) - (4 + m_info.m_uEntriesNumber * (4 + 12)); 
		if (uVolumeFree >= uToGrow) 
		// lets make sure it will be one-disk archive
		{
			// can the operation be done only in the buffer?
			if (!m_pStorage->m_iBytesWritten && // no bytes on the disk yet
				(m_pStorage->GetFreeInBuffer() >= uToGrow)) // is the buffer big enough?
			{
					RemoveDataDescr(true);
					bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
			}
			else
			{
				m_pStorage->Flush();
				if (RemoveDataDescr(false))
					bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
			}
		}
	}

	try
	{
		WriteHeaders(pCallback, bDontAllowDiskChange || !m_pStorage->IsSpanMode());

		m_info.m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
		DWORD uSize = WriteCentralEnd();
		if (bDontAllowDiskChange)
		{
			if (m_pStorage->GetCurrentDisk() != 0)
				ThrowError(CZipException::badZipFile);
		}
		// if after adding a central directory there is a disk change, 
		// update the information and write it again
		if (m_info.m_uThisDisk != m_pStorage->GetCurrentDisk())
		{
			m_info.DiskChange(m_pStorage->GetCurrentDisk());

			if (m_pStorage->m_uBytesInWriteBuffer >= uSize)
				// if the data is still in the buffer, simply remove it
				m_pStorage->m_uBytesInWriteBuffer -= uSize;
			else
			{
				m_pStorage->Flush();
				m_pStorage->m_iBytesWritten -= uSize;
				m_pStorage->m_pFile->SeekToBegin();	
			}
			
			WriteCentralEnd();
		}
	}
	catch (...)
	{
		if (bDontAllowDiskChange)
		{
			m_pStorage->FinalizeSpan();
			m_info.m_uThisDisk = 0;
		}
		throw;
	}
	m_info.m_bOnDisk = true;
}