Ejemplo n.º 1
0
bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer)
{
	// this will not work if there are bytes before zip
	CZipFileMapping fm;
	char* pFile;
	ZIP_SIZE_TYPE uSize;
	if (bFromBuffer)
	{
		uSize = m_pStorage->m_uBytesInWriteBuffer;
		pFile = m_pStorage->m_pWriteBuffer;
	}
	else
	{
		uSize = (ZIP_SIZE_TYPE)m_pStorage->m_pFile->GetLength();
		// we cannot use CZipMemFile in multi-volume archive
		// so it must be CZipFile
		if (!fm.CreateMapping(static_cast<CZipFile*>(m_pStorage->m_pFile)))
			return false;
		pFile = fm.GetMappedMemory();
	}

	ZIP_SIZE_TYPE uOffsetToChange = 4;
	ZIP_SIZE_TYPE uPosInBuffer = 0;
	WORD uExtraHeaderLen;
	ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize();
	for (ZIP_INDEX_TYPE i = 0; i < uCount; i++)
	{
		CZipFileHeader* pHeader = (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i];
		char* pSource = pFile + pHeader->m_uOffset;

		if (pHeader->NeedsDataDescriptor())
			uExtraHeaderLen = (WORD)(pHeader->IsEncrypted() ? 0 : 4);
		else
		{
			uExtraHeaderLen = pHeader->GetDataDescriptorSize(true);
			// removing data descriptor
			pHeader->m_uFlag &= ~8;
			// update local header:
			// write modified flag in the local header
			CBytesWriter::WriteBytes(pSource + 6, pHeader->m_uFlag);			
			pHeader->WriteSmallDataDescriptor(pSource + 14, false);
		}

		ZIP_SIZE_TYPE uToCopy = (i == (uCount - 1) ? uSize : (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)(i + 1)]->m_uOffset)
			- pHeader->m_uOffset - uExtraHeaderLen;
		if (uToCopy > 0)
			// TODO: [postponed] the size_t limit on uToCopy, but creating such a big segment is unlikely (at least at the moment of writing)
			memmove(pFile + uPosInBuffer, pSource, (size_t)uToCopy);

		uPosInBuffer += uToCopy;
		pHeader->m_uOffset -= uOffsetToChange;
		uOffsetToChange += uExtraHeaderLen;
	}

	if (bFromBuffer)
		m_pStorage->m_uBytesInWriteBuffer = (DWORD)uPosInBuffer;
	else
	{
		m_pStorage->m_uBytesWritten = uPosInBuffer;
		fm.RemoveMapping();
		m_pStorage->m_pFile->SetLength((ZIP_FILE_USIZE)uPosInBuffer);
	}
	return true;
}
Ejemplo n.º 2
0
bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer)
{
	ziparchv::CZipFileMapping fm;
	char* pFile;
	DWORD uSize;
	if (bFromBuffer)
	{
		uSize = m_pStorage->m_uBytesInWriteBuffer;
		pFile = m_pStorage->m_pWriteBuffer;
	}
	else
	{
		uSize = m_pStorage->m_pFile->GetLength();
		// we cannot use CZipMemFile in multidisk archive
		// so it MUST be CZipFile
		if (!fm.CreateMapping(static_cast<CZipFile*>(m_pStorage->m_pFile)))
			return false;
		pFile = fm.GetMappedMemory();
	}

	DWORD uOffsetToChange = 4;
	DWORD uPosInBuffer = 0;
	DWORD uExtraHeaderLen;
	int iCount = m_headers.GetSize();
	for (int i = 0; i < iCount; i++)
	{
		// update the flag value in the local and central header
// 		int uDataDescr = (m_headers[i]->m_uFlag & 8) ? (4 + 12) : 0;

		CZipFileHeader* pHeader = m_headers[i];


		char* pSour = pFile + pHeader->m_uOffset;
		
		if (!pHeader->IsEncrypted())
		{
			// removing data descriptor
			pHeader->m_uFlag &= ~8;
			// update local header:
			// write modified flag in the local header
			memcpy(pSour + 6, &pHeader->m_uFlag, 2);
			uExtraHeaderLen = 4/*ext. header signature*/ + 12/*data descriptor*/;
		}
		else
			// do not remove data descriptors from encrypted files
			uExtraHeaderLen = 0;

		// update crc32 and sizes' values
		pHeader->GetCrcAndSizes(pSour+ 14);

		DWORD uToCopy = (i == (iCount - 1) ? uSize : m_headers[i + 1]->m_uOffset)
			- pHeader->m_uOffset - uExtraHeaderLen;

		memmove(pFile + uPosInBuffer, pSour, uToCopy);

		uPosInBuffer += uToCopy;
		pHeader->m_uOffset -= uOffsetToChange;
		uOffsetToChange += uExtraHeaderLen;
	}

	if (bFromBuffer)
		m_pStorage->m_uBytesInWriteBuffer = uPosInBuffer;
	else
	{
		m_pStorage->m_iBytesWritten = uPosInBuffer;
		fm.RemoveMapping();
		m_pStorage->m_pFile->SetLength(uPosInBuffer);
	}
	return true;
}
Ejemplo n.º 3
0
void CZipCentralDir::Write()
{
	if (m_pInfo->m_bInArchive)
		return;

	m_pInfo->m_uEntriesNumber = (ZIP_INDEX_TYPE)m_pHeaders->GetSize();	

	if (!m_pStorage->IsSegmented())
	{
		m_pStorage->Flush();
		m_pStorage->m_pFile->SeekToEnd();
	}
// 	else
// 		we are at the end already

	m_pInfo->m_uSize = 0;
	bool bDontAllowVolumeChange = false;
	
	if (m_pStorage->IsSegmented())
	{
		// segmentation signature at the beginning (4 bytes) + the size of the data descr. for each file
		ZIP_SIZE_TYPE uSize = GetSize(true);
		// if there is a segmented archive in creation and it is only one-volume,
		//	(current volume number 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 not segmented archive
		if (m_pStorage->GetCurrentVolume() == 0)
		{
			// calculate the size of data descriptors already in the buffer or on the disk
			// (they will be removed in the not segmented archive).
			ZIP_SIZE_TYPE uToGrow = uSize - 4;
			for (ZIP_INDEX_TYPE i = 0; i < m_pInfo->m_uEntriesNumber; i++)
			{
				CZipFileHeader* pHeader = (*this)[i];
				if (pHeader->NeedsDataDescriptor())
				{
					if (!pHeader->IsEncrypted())
						uToGrow -= 4; // remove the signature only
				}
				else
					uToGrow -= pHeader->GetDataDescriptorSize(true);
			}

			ZIP_SIZE_TYPE uVolumeFree = m_pStorage->VolumeLeft();
			
			if (uVolumeFree >= uToGrow) 
			// lets make sure it will be one-volume archive
			{
				// can the operation be done only in the buffer?
				if (!m_pStorage->m_uBytesWritten && // no bytes on the disk yet
					(m_pStorage->GetFreeInBuffer() >= uToGrow)) // is the buffer big enough?
				{
						RemoveDataDescr(true);
						bDontAllowVolumeChange = true; // if a volume change occurs somehow, we'll throw an error later
				}
				else
				{
					m_pStorage->Flush();
					if (RemoveDataDescr(false))
						bDontAllowVolumeChange = true; // if a volume change occurs somehow, we'll throw an error later
				}
			}
		}

		// make sure that in a segmented archive, the whole central directory will fit on the single volume
		if (!bDontAllowVolumeChange && !m_pStorage->IsBinarySplit())
			m_pStorage->AssureFree(uSize);
	}

	try
	{
		WriteHeaders(bDontAllowVolumeChange || !m_pStorage->IsSegmented());
				
		WriteCentralEnd();

		if (bDontAllowVolumeChange)
		{
			if (m_pStorage->GetCurrentVolume() != 0)
				ThrowError(CZipException::badZipFile);
		}		
	}
	catch (...)
	{
		if (bDontAllowVolumeChange)
		{
			m_pStorage->FinalizeSegm();
			m_pInfo->m_uLastVolume = 0;
		}
		throw;
	}
	m_pInfo->m_bInArchive = true;
}