Beispiel #1
0
hlBool CVPKFile::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const
{
	const VPKDirectoryItem *pDirectoryItem = static_cast<const VPKDirectoryItem *>(pFile->GetData());

	if(pDirectoryItem->pDirectoryEntry->uiEntryLength != 0)
	{
		if(pDirectoryItem->pDirectoryEntry->uiArchiveIndex == HL_VPK_NO_ARCHIVE)
		{
			if(pDirectoryItem->lpPreloadData != 0)
			{
				pStream = new Streams::CMemoryStream(const_cast<hlVoid *>(pDirectoryItem->lpPreloadData), pDirectoryItem->pDirectoryEntry->uiEntryLength);
			}
			else
			{
				return hlFalse;
			}
		}
		else if(this->lpArchives[pDirectoryItem->pDirectoryEntry->uiArchiveIndex].pMapping != 0)
		{
			if(pDirectoryItem->pDirectoryEntry->uiPreloadBytes != 0)
			{
				Mapping::CView *pView = 0;
				if(!this->lpArchives[pDirectoryItem->pDirectoryEntry->uiArchiveIndex].pMapping->Map(pView, pDirectoryItem->pDirectoryEntry->uiEntryOffset, pDirectoryItem->pDirectoryEntry->uiEntryLength))
				{
					return hlFalse;
				}

				hlUInt uiBufferSize = pDirectoryItem->pDirectoryEntry->uiEntryLength + pDirectoryItem->pDirectoryEntry->uiPreloadBytes;
				hlByte *lpBuffer = new hlByte[uiBufferSize];

				memcpy(lpBuffer, pDirectoryItem->lpPreloadData, pDirectoryItem->pDirectoryEntry->uiPreloadBytes);
				memcpy(lpBuffer + pDirectoryItem->pDirectoryEntry->uiPreloadBytes, pView->GetView(), pDirectoryItem->pDirectoryEntry->uiEntryLength);

				this->lpArchives[pDirectoryItem->pDirectoryEntry->uiArchiveIndex].pMapping->Unmap(pView);

				pStream = new Streams::CMemoryStream(lpBuffer, uiBufferSize);
			}
			else
			{
				pStream = new Streams::CMappingStream(*this->lpArchives[pDirectoryItem->pDirectoryEntry->uiArchiveIndex].pMapping, pDirectoryItem->pDirectoryEntry->uiEntryOffset, pDirectoryItem->pDirectoryEntry->uiEntryLength);
			}
		}
		else
		{
			return hlFalse;
		}
	}
	else if(pDirectoryItem->pDirectoryEntry->uiPreloadBytes != 0)
	{
		pStream = new Streams::CMemoryStream(const_cast<hlVoid *>(pDirectoryItem->lpPreloadData), pDirectoryItem->pDirectoryEntry->uiPreloadBytes);
	}
	else
	{
		pStream = new Streams::CNullStream();
	}

	return hlTrue;
}
Beispiel #2
0
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const
{
	const TSGAFile &File = this->lpFiles[pFile->GetID()];

	if(File.uiType == 0)
	{
		pStream = new Streams::CMappingStream(*this->File.pMapping, this->File.pHeader->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk);
		return hlTrue;
	}
	else
	{
#if USE_ZLIB
		Mapping::CView *pFileDataView = 0;
		if(this->File.pMapping->Map(pFileDataView, this->File.pHeader->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk))
		{
			hlBool bResult = hlFalse;
			hlByte *lpInflateBuffer = new hlByte[File.uiSize];
			uLongf iInflateSize = File.uiSize;
			switch(uncompress(lpInflateBuffer, &iInflateSize, static_cast<const hlByte *>(pFileDataView->GetView()), (uLong)File.uiSizeOnDisk))
			{
			case Z_OK:
				pStream = new Streams::CMemoryStream(lpInflateBuffer, iInflateSize);
				bResult = hlTrue;
				break;
			case Z_MEM_ERROR:
				delete []lpInflateBuffer;
				LastError.SetErrorMessage("Deflate Error: Z_MEM_ERROR.");
				break;
			case Z_BUF_ERROR:
				delete []lpInflateBuffer;
				LastError.SetErrorMessage("Deflate Error: Z_BUF_ERROR.");
				break;
			case Z_DATA_ERROR:
				delete []lpInflateBuffer;
				LastError.SetErrorMessage("Deflate Error: Z_DATA_ERROR.");
				break;
			default:
				delete []lpInflateBuffer;
				LastError.SetErrorMessage("Deflate Error: Unknown.");
				break;
			}
			this->File.pMapping->Unmap(pFileDataView);
			return bResult;
		}
#endif
		return hlFalse;
	}
}
Beispiel #3
0
CPackage *CPackage::AutoOpen(Mapping::CMapping &Mapping, hlUInt uiMode) {
	Mapping::CView *lpView = 0;
	if (!Mapping.Map(lpView, 0, 512 > Mapping.GetMappingSize() ? Mapping.GetMappingSize() : 512)) {
		return 0;
	}
	CPackage *lpPackage = PackageFromMemory(lpView->GetView(), lpView->GetLength());
	Mapping.Unmap(lpView);

	if (lpPackage != 0) {
		if (!lpPackage->Open(Mapping, uiMode)) {
			delete lpPackage;
			lpPackage = 0;
		}
	}

	return lpPackage;
}
Beispiel #4
0
hlBool CZIPFile::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const
{
	const ZIPFileHeader *pDirectoryItem = static_cast<const ZIPFileHeader *>(pFile->GetData());

	if(pDirectoryItem->uiCompressionMethod != 0)
	{
		LastError.SetErrorMessageFormated("Compression format %#.2x not supported.", pDirectoryItem->uiCompressionMethod);
		return hlFalse;
	}

	if(pDirectoryItem->uiDiskNumberStart != this->pEndOfCentralDirectoryRecord->uiNumberOfThisDisk)
	{
		LastError.SetErrorMessageFormated("File resides on disk %u.", pDirectoryItem->uiDiskNumberStart);
		return hlFalse;
	}

	Mapping::CView *pDirectoryEnrtyView = 0;

	if(!this->pMapping->Map(pDirectoryEnrtyView, pDirectoryItem->uiRelativeOffsetOfLocalHeader, sizeof(ZIPLocalFileHeader)))
	{
		return hlFalse;
	}

	const ZIPLocalFileHeader DirectoryEntry = *static_cast<const ZIPLocalFileHeader *>(pDirectoryEnrtyView->GetView());

	this->pMapping->Unmap(pDirectoryEnrtyView);

	if(DirectoryEntry.uiSignature != HL_ZIP_LOCAL_FILE_HEADER_SIGNATURE)
	{
		LastError.SetErrorMessageFormated("Invalid file data offset.", pDirectoryItem->uiDiskNumberStart);
		return hlFalse;
	}

	pStream = new Streams::CMappingStream(*this->pMapping, pDirectoryItem->uiRelativeOffsetOfLocalHeader + sizeof(ZIPLocalFileHeader) + DirectoryEntry.uiFileNameLength + DirectoryEntry.uiExtraFieldLength, DirectoryEntry.uiUncompressedSize);

	return hlTrue;
}
hlBool CWADFile::GetLumpInfo(const CDirectoryFile &File, hlUInt &uiWidth, hlUInt &uiHeight, hlUInt &uiPaletteSize, hlUInt uiMipmap) const
{
	const WADLump &Lump = this->lpLumps[File.GetID()];

	if(Lump.iCompression)
	{
		LastError.SetErrorMessageFormated("Error reading lump: compression format %#.2x not supported.", Lump.iCompression);
		return hlFalse;
	}

	if(Lump.iType == 0x42)
	{
		if(uiMipmap > 0)
		{
			LastError.SetErrorMessageFormated("Error reading lump: invalid mipmap level %u.", uiMipmap);
			return hlFalse;
		}
	}
	else if(Lump.iType == 0x43)
	{
		if(uiMipmap > 3)
		{
			LastError.SetErrorMessageFormated("Error reading lump: invalid mipmap level %u.", uiMipmap);
			return hlFalse;
		}
	}
	else
	{
		LastError.SetErrorMessageFormated("Error reading lump: lump type %#.2x not supported.", Lump.iType);
		return hlFalse;
	}

	WADLumpInfo &Info = this->lpLumpInfo[File.GetID()];

	if(Info.uiWidth && Info.uiHeight && Info.uiPaletteSize)
	{
		uiWidth = Info.uiWidth;
		uiHeight = Info.uiHeight;
		uiPaletteSize = Info.uiPaletteSize;
	}
	else
	{
		Mapping::CView *pView = 0;

		if(!this->pMapping->Map(pView, Lump.uiOffset, Lump.uiDiskLength))
		{
			return hlFalse;
		}

		hlByte *lpData = (hlByte *)pView->GetView();

		// Type 0x42 has no name, type 0x43 does.  Are these flags?
		if(Lump.iType == 0x42)
		{
			// Get Width.
			uiWidth = *(hlUInt *)lpData;
			lpData += 4;

			// Get Height.
			uiHeight = *(hlUInt *)lpData;
			lpData += 4;

			// Scan past pixel data.
			lpData += (uiWidth * uiHeight);

			// Get palette size.
			uiPaletteSize = (hlUInt)(*(hlUInt16 *)lpData);
		}
		else if(Lump.iType == 0x43)
		{
			// Scan past name.
			lpData += 16;

			// Get Width.
			uiWidth = *(hlUInt *)lpData;
			lpData += 4;

			// Get Height.
			uiHeight = *(hlUInt *)lpData;
			lpData += 4;

			// Scan past pixel offset.
			lpData += 16;

			hlUInt uiPixelSize = uiWidth * uiHeight;

			switch(uiMipmap)
			{
			case 1:
				lpData += (uiPixelSize);
				break;
			case 2:
				lpData += (uiPixelSize) + (uiPixelSize / 4);
				break;
			case 3:
				lpData += (uiPixelSize) + (uiPixelSize / 4) + (uiPixelSize / 16);
				break;
			}

			// Scan past data.
			lpData += (uiPixelSize) + (uiPixelSize / 4) + (uiPixelSize / 16) + (uiPixelSize / 64);

			// Get palette size.
			uiPaletteSize = (hlUInt)(*(hlUInt16 *)lpData);
		}

		this->pMapping->Unmap(pView);

		Info.uiWidth = uiWidth;
		Info.uiHeight = uiHeight;
		Info.uiPaletteSize = uiPaletteSize;
	}

	switch(uiMipmap)
	{
	case 1:
		uiWidth /= 2;
		uiHeight /= 2;
		break;
	case 2:
		uiWidth /= 4;
		uiHeight /= 4;
		break;
	case 3:
		uiWidth /= 8;
		uiHeight /= 8;
		break;
	}

	return hlTrue;
}
Beispiel #6
0
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const
{
	const TSGAFile &File = this->lpFiles[pFile->GetID()];

#if !USE_ZLIB
	if(File.uiType != 0)
	{
		eValidation = HL_VALIDATES_ASSUMED_OK;
		return hlTrue;
	}
#endif

	Mapping::CView *pFileHeaderDataView = 0;
	if(this->File.pMapping->Map(pFileHeaderDataView, this->File.pHeader->uiFileDataOffset + File.uiOffset - sizeof(TSGAFileHeader), File.uiSizeOnDisk + sizeof(TSGAFileHeader)))
	{
		hlULong uiChecksum = 0;
		const TSGAFileHeader* pFileHeader = static_cast<const TSGAFileHeader*>(pFileHeaderDataView->GetView());
		const hlByte* lpBuffer = reinterpret_cast<const hlByte *>(pFileHeader) + sizeof(TSGAFileHeader);
#if USE_ZLIB
		hlByte *lpInflateBuffer = 0;
		if(File.uiType != 0)
		{
			lpInflateBuffer = new hlByte[File.uiSize];
			uLongf iInflateSize = File.uiSize;
			switch(uncompress(lpInflateBuffer, &iInflateSize, lpBuffer, static_cast<uLong>(File.uiSizeOnDisk)))
			{
			case Z_OK:
				lpBuffer = lpInflateBuffer;
				break;
			default:
				delete []lpInflateBuffer;
				lpInflateBuffer = 0;
				eValidation = HL_VALIDATES_ERROR;
				break;
			}
		}
		if(File.uiType == 0 || lpInflateBuffer != 0)
#endif
		{
			hlULongLong uiTotalBytes = 0, uiFileBytes = File.uiSize;

			hlBool bCancel = hlFalse;
			hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel);

			while(uiTotalBytes < uiFileBytes)
			{
				if(bCancel)
				{
					eValidation = HL_VALIDATES_CANCELED;
					break;
				}

				hlUInt uiBufferSize = static_cast<hlUInt>(uiTotalBytes + HL_SGA_CHECKSUM_LENGTH <= uiFileBytes ? HL_SGA_CHECKSUM_LENGTH : uiFileBytes - uiTotalBytes);
				uiChecksum = CRC32(lpBuffer, uiBufferSize, uiChecksum);

				lpBuffer += uiBufferSize;
				uiTotalBytes += static_cast<hlULongLong>(uiBufferSize);

				hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel);
			}
		}
#if USE_ZLIB
		delete []lpInflateBuffer;
#endif
		eValidation = static_cast<hlULong>(pFileHeader->uiCRC32) == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT;

		this->File.pMapping->Unmap(pFileHeaderDataView);
	}
	else
	{
		eValidation = HL_VALIDATES_ERROR;
	}

	return hlTrue;
}
Beispiel #7
0
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const
{
	if(pItem->GetID() != HL_ID_INVALID)
	{
		switch(pItem->GetType())
		{
			case HL_ITEM_FOLDER:
			{
				const CDirectoryFolder *pFolder = static_cast<const CDirectoryFolder *>(pItem);
				switch(eAttribute)
				{
					case HL_SGA_ITEM_SECTION_ALIAS:
					{
						for(hlUInt i = 0; i < this->pDirectoryHeader->uiSectionCount; i++)
						{
							if(pFolder->GetID() >= this->lpSections[i].uiFolderStartIndex && pFolder->GetID() < this->lpSections[i].uiFolderEndIndex)
							{
								hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], this->lpSections[i].lpAlias);
								return hlTrue;
							}
						}
						return hlFalse;
					}
					case HL_SGA_ITEM_SECTION_NAME:
					{
						for(hlUInt i = 0; i < this->pDirectoryHeader->uiSectionCount; i++)
						{
							if(pFolder->GetID() >= this->lpSections[i].uiFolderStartIndex && pFolder->GetID() < this->lpSections[i].uiFolderEndIndex)
							{
								hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], this->lpSections[i].lpName);
								return hlTrue;
							}
						}
						return hlFalse;
					}
				}
				break;
			}
			case HL_ITEM_FILE:
			{
				const CDirectoryFile *pFile = static_cast<const CDirectoryFile *>(pItem);
				const TSGAFile &File = this->lpFiles[pFile->GetID()];
				switch(eAttribute)
				{
					case HL_SGA_ITEM_SECTION_ALIAS:
					{
						for(hlUInt i = 0; i < this->pDirectoryHeader->uiSectionCount; i++)
						{
							if(pFile->GetID() >= this->lpSections[i].uiFileStartIndex && pFile->GetID() < this->lpSections[i].uiFileEndIndex)
							{
								hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], this->lpSections[i].lpAlias);
								return hlTrue;
							}
						}
						return hlFalse;
					}
					case HL_SGA_ITEM_SECTION_NAME:
					{
						for(hlUInt i = 0; i < this->pDirectoryHeader->uiSectionCount; i++)
						{
							if(pFile->GetID() >= this->lpSections[i].uiFileStartIndex && pFile->GetID() < this->lpSections[i].uiFileEndIndex)
							{
								hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], this->lpSections[i].lpName);
								return hlTrue;
							}
						}
						return hlFalse;
					}
					case HL_SGA_ITEM_MODIFIED:
					{
						time_t Time = (time_t)File.uiTimeModified;
						tm *pTime = localtime(&Time);

						hlChar lpTime[128];
						strftime(lpTime, sizeof(lpTime), "%c", pTime);

						hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], lpTime);
						return hlTrue;
					}
					case HL_SGA_ITEM_TYPE:
					{
						hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], File.uiType, hlFalse);
						return hlTrue;
					}
					case HL_SGA_ITEM_CRC:
					{
						Mapping::CView *pFileHeaderView = 0;
						if(this->File.pMapping->Map(pFileHeaderView, this->File.pHeader->uiFileDataOffset + File.uiOffset - sizeof(TSGAFileHeader), sizeof(TSGAFileHeader)))
						{
							const TSGAFileHeader* pFileHeader = static_cast<const TSGAFileHeader *>(pFileHeaderView->GetView());
							hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], pFileHeader->uiCRC32, hlTrue);
							this->File.pMapping->Unmap(pFileHeaderView);
							return hlTrue;
						}
						return hlFalse;
					}
				}
				break;
			}
		}
	}
	return hlFalse;
}
Beispiel #8
0
hlBool CVBSPFile::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const
{
	if(pFile->GetData())
	{
		const ZIPFileHeader *pDirectoryItem = static_cast<const ZIPFileHeader *>(pFile->GetData());

		if(pDirectoryItem->uiCompressionMethod != 0)
		{
			LastError.SetErrorMessageFormated("Compression format %#.2x not supported.", pDirectoryItem->uiCompressionMethod);
			return hlFalse;
		}

		if(pDirectoryItem->uiDiskNumberStart != this->pEndOfCentralDirectoryRecord->uiNumberOfThisDisk)
		{
			LastError.SetErrorMessageFormated("File resides on disk %u.", pDirectoryItem->uiDiskNumberStart);
			return hlFalse;
		}

		Mapping::CView *pDirectoryEnrtyView = 0;

		if(!this->pMapping->Map(pDirectoryEnrtyView, this->pHeader->lpLumps[HL_VBSP_LUMP_PAKFILE].uiOffset + pDirectoryItem->uiRelativeOffsetOfLocalHeader, sizeof(ZIPLocalFileHeader)))
		{
			return hlFalse;
		}

		const ZIPLocalFileHeader DirectoryEntry = *static_cast<const ZIPLocalFileHeader *>(pDirectoryEnrtyView->GetView());

		this->pMapping->Unmap(pDirectoryEnrtyView);

		if(DirectoryEntry.uiSignature != HL_VBSP_ZIP_LOCAL_FILE_HEADER_SIGNATURE)
		{
			LastError.SetErrorMessageFormated("Invalid file data offset %u.", pDirectoryItem->uiDiskNumberStart);
			return hlFalse;
		}

		pStream = new Streams::CMappingStream(*this->pMapping, this->pHeader->lpLumps[HL_VBSP_LUMP_PAKFILE].uiOffset + pDirectoryItem->uiRelativeOffsetOfLocalHeader + sizeof(ZIPLocalFileHeader) + DirectoryEntry.uiFileNameLength + DirectoryEntry.uiExtraFieldLength, DirectoryEntry.uiUncompressedSize);
	}
	else if(pFile->GetID() < HL_VBSP_LUMP_COUNT)
	{
		pStream = new Streams::CMappingStream(*this->pMapping, this->pHeader->lpLumps[pFile->GetID()].uiOffset, this->pHeader->lpLumps[pFile->GetID()].uiLength);
	}
	else
	{
		hlUInt uiID = pFile->GetID() - HL_VBSP_LUMP_COUNT;

		Mapping::CView *pLumpView = 0;
		if(!this->pMapping->Map(pLumpView, this->pHeader->lpLumps[uiID].uiOffset, this->pHeader->lpLumps[uiID].uiLength))
		{
			return hlFalse;
		}

		hlUInt uiBufferSize = sizeof(LMPHeader) + this->pHeader->lpLumps[uiID].uiLength;
		hlByte *lpBuffer = new hlByte[uiBufferSize];

		LMPHeader *pLMPHeader = (LMPHeader *)lpBuffer;
		pLMPHeader->iLumpOffset = sizeof(LMPHeader);
		pLMPHeader->iLumpID = uiID;
		pLMPHeader->iLumpVersion = this->pHeader->lpLumps[uiID].uiVersion;
		pLMPHeader->iLumpLength = this->pHeader->lpLumps[uiID].uiLength;
		pLMPHeader->iMapRevision = this->pHeader->iMapRevision;

		memcpy(lpBuffer + sizeof(LMPHeader), pLumpView->GetView(), this->pHeader->lpLumps[uiID].uiLength);

		pStream = new Streams::CMemoryStream(lpBuffer, uiBufferSize);

		this->pMapping->Unmap(pLumpView);
	}

	return hlTrue;
}
Beispiel #9
0
hlBool CVBSPFile::MapDataStructures()
{
	if(sizeof(VBSPHeader) > this->pMapping->GetMappingSize())
	{
		LastError.SetErrorMessage("Invalid file: the file map is too small for it's header.");
		return hlFalse;
	}

	if(!this->pMapping->Map(this->pHeaderView, 0, sizeof(VBSPHeader)))
	{
		return hlFalse;
	}
	this->pHeader = static_cast<const VBSPHeader *>(this->pHeaderView->GetView());

	if(memcmp(this->pHeader->lpSignature, "VBSP", 4) != 0)
	{
		LastError.SetErrorMessage("Invalid file: the file's signature does not match.");
		return hlFalse;
	}

	// Versions:
	//  19-20:			Source
	//  21:				Source - The lump version property was moved to the start of the struct.
	//  0x00040014:		Dark Messiah - Looks like the 32 bit version has been split into two 16 bit fields.
	if((this->pHeader->iVersion < 19 || this->pHeader->iVersion > 21) && this->pHeader->iVersion != 0x00040014)
	{
		LastError.SetErrorMessageFormated("Invalid VBSP version (v%i): you have a version of a VBSP file that HLLib does not know how to read. Check for product updates.", this->pHeader->iVersion);
		return hlFalse;
	}

	if(this->pHeader->iVersion >= 21 && this->pHeader->iVersion != 0x00040014)
	{
		VBSPHeader *pHeader = new VBSPHeader;
		memcpy(pHeader, this->pHeader, sizeof(VBSPHeader));
		for(hlUInt i = 0; i < HL_VBSP_LUMP_COUNT; i++)
		{
			pHeader->lpLumps[i].uiVersion = this->pHeader->lpLumps[i].uiOffset;
			pHeader->lpLumps[i].uiOffset = this->pHeader->lpLumps[i].uiLength;
			pHeader->lpLumps[i].uiLength = this->pHeader->lpLumps[i].uiVersion;
		}
		this->pHeader = pHeader;
	}

	if(sizeof(ZIPEndOfCentralDirectoryRecord) <= this->pHeader->lpLumps[HL_VBSP_LUMP_PAKFILE].uiLength)
	{
		hlUInt uiTest, uiOffset = this->pHeader->lpLumps[HL_VBSP_LUMP_PAKFILE].uiOffset;
		while(uiOffset < this->pHeader->lpLumps[HL_VBSP_LUMP_PAKFILE].uiOffset + this->pHeader->lpLumps[HL_VBSP_LUMP_PAKFILE].uiLength - sizeof(uiTest))
		{
			Mapping::CView *pTestView = 0;

			if(!this->pMapping->Map(pTestView, uiOffset, sizeof(hlUInt)))
			{
				return hlFalse;
			}

			uiTest = *(hlUInt *)pTestView->GetView();

			this->pMapping->Unmap(pTestView);

			switch(uiTest)
			{
				case HL_VBSP_ZIP_END_OF_CENTRAL_DIRECTORY_RECORD_SIGNATURE:
				{
					if(!this->pMapping->Map(pTestView, uiOffset, sizeof(ZIPEndOfCentralDirectoryRecord)))
					{
						return hlFalse;
					}

					const ZIPEndOfCentralDirectoryRecord EndOfCentralDirRecord = *static_cast<const ZIPEndOfCentralDirectoryRecord *>(pTestView->GetView());

					this->pMapping->Unmap(pTestView);

					if(!this->pMapping->Map(this->pEndOfCentralDirectoryRecordView, uiOffset, sizeof(ZIPEndOfCentralDirectoryRecord) + EndOfCentralDirRecord.uiCommentLength))
					{
						return hlFalse;
					}

					this->pEndOfCentralDirectoryRecord = static_cast<const ZIPEndOfCentralDirectoryRecord *>(this->pEndOfCentralDirectoryRecordView->GetView());

					if(!this->pMapping->Map(this->pFileHeaderView, this->pHeader->lpLumps[HL_VBSP_LUMP_PAKFILE].uiOffset + this->pEndOfCentralDirectoryRecord->uiStartOfCentralDirOffset, this->pEndOfCentralDirectoryRecord->uiCentralDirectorySize))
					{
						return hlFalse;
					}

					return hlTrue;
				}
				case HL_VBSP_ZIP_FILE_HEADER_SIGNATURE:
				{
					if(!this->pMapping->Map(pTestView, uiOffset, sizeof(ZIPFileHeader)))
					{
						return hlFalse;
					}

					const ZIPFileHeader FileHeader = *static_cast<const ZIPFileHeader *>(pTestView->GetView());

					this->pMapping->Unmap(pTestView);

					uiOffset += sizeof(ZIPFileHeader) + FileHeader.uiFileNameLength + FileHeader.uiExtraFieldLength + FileHeader.uiFileCommentLength;
					break;
				}
				case HL_VBSP_ZIP_LOCAL_FILE_HEADER_SIGNATURE:
				{
					if(!this->pMapping->Map(pTestView, uiOffset, sizeof(ZIPLocalFileHeader)))
					{
						return hlFalse;
					}

					const ZIPLocalFileHeader LocalFileHeader = *static_cast<const ZIPLocalFileHeader *>(pTestView->GetView());

					this->pMapping->Unmap(pTestView);

					uiOffset += sizeof(ZIPLocalFileHeader) + LocalFileHeader.uiFileNameLength + LocalFileHeader.uiExtraFieldLength + LocalFileHeader.uiCompressedSize;
					break;
				}
				default:
				{
					LastError.SetErrorMessageFormated("Invalid file: unknown ZIP section signature %#.8x.", uiTest);
					return hlFalse;
				}
			}
		}

		LastError.SetErrorMessage("Invalid file: unexpected end of file while scanning for end of ZIP central directory record.");
		return hlFalse;
	}

	return hlTrue;
}
Beispiel #10
0
hlBool CZIPFile::MapDataStructures()
{
	if(sizeof(ZIPEndOfCentralDirectoryRecord) > this->pMapping->GetMappingSize())
	{
		LastError.SetErrorMessage("Invalid file: the file map is too small for it's header.");
		return hlFalse;
	}

	hlUInt uiTest;
	hlULongLong uiOffset = 0, uiLength = this->pMapping->GetMappingSize();
	while(uiOffset < uiLength - sizeof(uiTest))
	{
		Mapping::CView *pTestView = 0;

		if(!this->pMapping->Map(pTestView, uiOffset, sizeof(hlUInt)))
		{
			return hlFalse;
		}

		uiTest = *(hlUInt *)pTestView->GetView();

		this->pMapping->Unmap(pTestView);

		switch(uiTest)
		{
			case HL_ZIP_END_OF_CENTRAL_DIRECTORY_RECORD_SIGNATURE:
			{
				if(!this->pMapping->Map(pTestView, uiOffset, sizeof(ZIPEndOfCentralDirectoryRecord)))
				{
					return hlFalse;
				}

				const ZIPEndOfCentralDirectoryRecord EndOfCentralDirRecord = *static_cast<const ZIPEndOfCentralDirectoryRecord *>(pTestView->GetView());

				this->pMapping->Unmap(pTestView);

				if(!this->pMapping->Map(this->pEndOfCentralDirectoryRecordView, uiOffset, sizeof(ZIPEndOfCentralDirectoryRecord) + EndOfCentralDirRecord.uiCommentLength))
				{
					return hlFalse;
				}

				this->pEndOfCentralDirectoryRecord = static_cast<const ZIPEndOfCentralDirectoryRecord *>(this->pEndOfCentralDirectoryRecordView->GetView());

				if(!this->pMapping->Map(this->pFileHeaderView, this->pEndOfCentralDirectoryRecord->uiStartOfCentralDirOffset, this->pEndOfCentralDirectoryRecord->uiCentralDirectorySize))
				{
					return hlFalse;
				}

				return hlTrue;
			}
			case HL_ZIP_FILE_HEADER_SIGNATURE:
			{
				if(!this->pMapping->Map(pTestView, uiOffset, sizeof(ZIPFileHeader)))
				{
					return hlFalse;
				}

				const ZIPFileHeader FileHeader = *static_cast<const ZIPFileHeader *>(pTestView->GetView());

				this->pMapping->Unmap(pTestView);

				uiOffset += static_cast<hlULongLong>(sizeof(ZIPFileHeader) + FileHeader.uiFileNameLength + FileHeader.uiExtraFieldLength + FileHeader.uiFileCommentLength);
				break;
			}
			case HL_ZIP_LOCAL_FILE_HEADER_SIGNATURE:
			{
				if(!this->pMapping->Map(pTestView, uiOffset, sizeof(ZIPLocalFileHeader)))
				{
					return hlFalse;
				}

				const ZIPLocalFileHeader LocalFileHeader = *static_cast<const ZIPLocalFileHeader *>(pTestView->GetView());

				this->pMapping->Unmap(pTestView);

				uiOffset += static_cast<hlULongLong>(sizeof(ZIPLocalFileHeader) + LocalFileHeader.uiFileNameLength + LocalFileHeader.uiExtraFieldLength + LocalFileHeader.uiCompressedSize);
				break;
			}
			default:
			{
				LastError.SetErrorMessageFormated("Invalid file: unknown section signature %#.8x.", uiTest);
				return hlFalse;
			}
		}
	}

	LastError.SetErrorMessage("Invalid file: unexpected end of file while scanning for end of central directory record.");
	return hlFalse;
}
Beispiel #11
0
hlBool CGCFFile::DefragmentInternal()
{
    hlBool bError = hlFalse, bCancel = hlFalse;
    hlUInt uiFilesDefragmented = 0, uiFilesTotal = 0;
    hlULongLong uiBytesDefragmented = 0, uiBytesTotal = 0;

    // Check the current fragmentation state.
    {
        hlUInt uiBlocksFragmented = 0;
        hlUInt uiBlocksUsed = 0;

        for(hlUInt i = 0; i < this->pDirectoryHeader->uiItemCount; i++)
        {
            if(this->lpDirectoryEntries[i].uiDirectoryFlags & HL_GCF_FLAG_FILE)
            {
                hlUInt uiFileBlocksFragmented = 0;
                hlUInt uiFileBlocksUsed = 0;

                this->GetItemFragmentation(i, uiFileBlocksFragmented, uiFileBlocksUsed);

                uiBlocksFragmented += uiFileBlocksFragmented;
                uiBlocksUsed += uiFileBlocksUsed;

                uiFilesTotal++;
                uiBytesTotal += static_cast<hlULongLong>(uiFileBlocksUsed * this->pDataBlockHeader->uiBlockSize);
            }
        }

        // If there are no data blocks to defragment, and we don't want to sort the data blocks
        // lexicographically, then we're done.
        if((uiBlocksFragmented == 0 && !bForceDefragment) || uiBlocksUsed == 0)
        {
            hlDefragmentProgress(0, uiFilesTotal, uiFilesTotal, uiBytesTotal, uiBytesTotal, &bCancel);

            return hlTrue;
        }
    }

    Mapping::CView *pCurrentView = 0, *pIncrementedView = 0;
    hlUInt uiIncrement = 0;

    //hlUInt uiDataBlockTerminator = this->pDataBlockHeader->uiBlockCount >= 0x0000ffff ? 0xffffffff : 0x0000ffff;
    hlUInt uiDataBlockTerminator = this->pFragmentationMapHeader->uiTerminator == 0 ? 0x0000ffff : 0xffffffff;

    hlByte *lpDataBlock = new hlByte[this->pDataBlockHeader->uiBlockSize];

    // Step through each data block in each file as it appears in the directory and defragment (order each data
    // block sequentially).  This is a slow brute force approach, but since related half-life 2 files
    // often start with the same name we *may* expect a performance boost from odering files lexicographically
    // (as they appear in the directory).  That's my justification at least...
    for(hlUInt i = 0; i < this->pDirectoryHeader->uiItemCount && !bError && !bCancel; i++)
    {
        if(this->lpDirectoryEntries[i].uiDirectoryFlags & HL_GCF_FLAG_FILE)
        {
            hlUInt uiCurrentBlockEntryIndex = this->lpDirectoryMapEntries[i].uiFirstBlockIndex;

            while(uiCurrentBlockEntryIndex != this->pDataBlockHeader->uiBlockCount)
            {
                hlUInt uiCurrentBlockEntrySize = 0;
                hlUInt uiCurrentDataBlockIndex = this->lpBlockEntries[uiCurrentBlockEntryIndex].uiFirstDataBlockIndex;
                hlUInt uiLastDataBlockIndex = this->pDataBlockHeader->uiBlockCount;

                while(uiCurrentDataBlockIndex < uiDataBlockTerminator && uiCurrentBlockEntrySize < this->lpBlockEntries[uiCurrentBlockEntryIndex].uiFileDataSize)
                {
                    hlUInt uiNextDataBlockIndex = this->lpFragmentationMap[uiCurrentDataBlockIndex].uiNextDataBlockIndex;

                    // If this data block is not ordered sequentially, swap it with the sequential data block.
                    if(uiCurrentDataBlockIndex != uiIncrement)
                    {
                        // Make sure we can map the two data blocks before we alter any tables.
                        if(this->pMapping->Map(pCurrentView, static_cast<hlULongLong>(this->pDataBlockHeader->uiFirstBlockOffset) + static_cast<hlULongLong>(uiCurrentDataBlockIndex) * static_cast<hlULongLong>(this->pDataBlockHeader->uiBlockSize), static_cast<hlULongLong>(this->pDataBlockHeader->uiBlockSize)) &&
                                this->pMapping->Map(pIncrementedView, static_cast<hlULongLong>(this->pDataBlockHeader->uiFirstBlockOffset) + static_cast<hlULongLong>(uiIncrement) * static_cast<hlULongLong>(this->pDataBlockHeader->uiBlockSize), static_cast<hlULongLong>(this->pDataBlockHeader->uiBlockSize)))
                        {
                            // Search to see if the sequential data block is in use, we only need to check
                            // files after ours in the directory because everything before is sequential.
                            hlBool bFound = hlFalse;
                            for(hlUInt j = i; j < this->pDirectoryHeader->uiItemCount && !bFound; j++)
                            {
                                if(this->lpDirectoryEntries[j].uiDirectoryFlags & HL_GCF_FLAG_FILE)
                                {
                                    hlUInt uiIncrementedBlockEntryIndex = this->lpDirectoryMapEntries[j].uiFirstBlockIndex;

                                    while(uiIncrementedBlockEntryIndex != this->pDataBlockHeader->uiBlockCount && !bFound)
                                    {
                                        hlUInt uiIncrementedDataBlockIndex = this->lpBlockEntries[uiIncrementedBlockEntryIndex].uiFirstDataBlockIndex;

                                        if(uiIncrementedDataBlockIndex == uiIncrement)
                                        {
                                            // The sequential data block is the first data block in a block entry,
                                            // update the tables preserving the sequence for the file we are fragmenting.

                                            this->lpBlockEntries[uiIncrementedBlockEntryIndex].uiFirstDataBlockIndex = uiCurrentDataBlockIndex;

                                            this->lpFragmentationMap[uiCurrentDataBlockIndex].uiNextDataBlockIndex = this->lpFragmentationMap[uiIncrementedDataBlockIndex].uiNextDataBlockIndex;

                                            // We found it.
                                            bFound = hlTrue;
                                            break;
                                        }
                                        else
                                        {
                                            // The sequential data block is in the middle of a block entry,
                                            // update the tables preserving the sequence for the file we are fragmenting.

                                            hlUInt uiIncrementedBlockEntrySize = 0;
                                            hlUInt uiIncrementedLastDataBlockIndex = this->pDataBlockHeader->uiBlockCount;

                                            while(uiIncrementedDataBlockIndex < uiDataBlockTerminator && uiIncrementedBlockEntrySize < this->lpBlockEntries[uiIncrementedBlockEntryIndex].uiFileDataSize)
                                            {
                                                if(uiIncrementedDataBlockIndex == uiIncrement)
                                                {
                                                    // If the data blocks are side by side, prevent circular maps.
                                                    if(uiIncrement != uiNextDataBlockIndex)
                                                    {
                                                        this->lpFragmentationMap[uiIncrementedLastDataBlockIndex].uiNextDataBlockIndex = uiCurrentDataBlockIndex;
                                                    }

                                                    this->lpFragmentationMap[uiCurrentDataBlockIndex].uiNextDataBlockIndex = this->lpFragmentationMap[uiIncrementedDataBlockIndex].uiNextDataBlockIndex;

                                                    // We found it.
                                                    bFound = hlTrue;
                                                    break;
                                                }

                                                uiIncrementedLastDataBlockIndex = uiIncrementedDataBlockIndex;

                                                uiIncrementedDataBlockIndex = this->lpFragmentationMap[uiIncrementedDataBlockIndex].uiNextDataBlockIndex;
                                                uiIncrementedBlockEntrySize += this->pDataBlockHeader->uiBlockSize;
                                            }
                                        }

                                        uiIncrementedBlockEntryIndex = this->lpBlockEntries[uiIncrementedBlockEntryIndex].uiNextBlockEntryIndex;
                                    }
                                }
                            }

                            // Swap the data blocks if necessary.
                            if(bFound)
                            {
                                memcpy(lpDataBlock, pIncrementedView->GetView(), this->pDataBlockHeader->uiBlockSize);
                            }
                            memcpy(const_cast<hlVoid *>(pIncrementedView->GetView()), pCurrentView->GetView(), this->pDataBlockHeader->uiBlockSize);
                            if(!this->pMapping->Commit(*pIncrementedView))
                            {
                                // At this point the GCF will be corrupt and require validating by Steam for repair.
                                bError = hlTrue;
                            }
                            if(bFound)
                            {
                                memcpy(const_cast<hlVoid *>(pCurrentView->GetView()), lpDataBlock, this->pDataBlockHeader->uiBlockSize);
                                if(!this->pMapping->Commit(*pCurrentView))
                                {
                                    // At this point the GCF will be corrupt and require validating by Steam for repair.
                                    bError = hlTrue;
                                }
                            }

                            // Update the tables preserving the sequence of the file we are defragmenting.
                            if(uiLastDataBlockIndex == this->pDataBlockHeader->uiBlockCount)
                            {
                                this->lpBlockEntries[uiCurrentBlockEntryIndex].uiFirstDataBlockIndex = uiIncrement;
                            }
                            else
                            {
                                this->lpFragmentationMap[uiLastDataBlockIndex].uiNextDataBlockIndex = uiIncrement;
                            }

                            if(uiIncrement != this->pDataBlockHeader->uiBlockCount)
                            {
                                // If the data blocks are side by side, prevent circular maps.
                                if(uiIncrement != uiNextDataBlockIndex)
                                {
                                    this->lpFragmentationMap[uiIncrement].uiNextDataBlockIndex = uiNextDataBlockIndex;
                                }
                                else
                                {
                                    this->lpFragmentationMap[uiIncrement].uiNextDataBlockIndex = uiCurrentDataBlockIndex;
                                }
                            }
                        }
                        else
                        {
                            bError = hlTrue;
                            break;
                        }
                    }

                    // Move to the next data block.
                    uiLastDataBlockIndex = uiIncrement;
                    uiIncrement++;

                    uiCurrentDataBlockIndex = this->lpFragmentationMap[uiLastDataBlockIndex].uiNextDataBlockIndex;
                    uiCurrentBlockEntrySize += this->pDataBlockHeader->uiBlockSize;

                    // Update the progress.
                    uiBytesDefragmented += static_cast<hlULongLong>(this->pDataBlockHeader->uiBlockSize);
                    hlDefragmentProgress(this->lpDirectoryItems != 0 ? static_cast<CDirectoryFile *>(this->lpDirectoryItems[i]) : 0, uiFilesDefragmented, uiFilesTotal, uiBytesDefragmented, uiBytesTotal, &bCancel);
                    if(bCancel)
                    {
                        break;
                    }
                }

                if(bError || bCancel)
                {
                    break;
                }

                // Update the tables to make sure the last data block points to nothing.
                // It would seem that this is only necessary if there is an eror in the GCF
                // in which case we should just let it be (Steam knows better)...
                /*if(uiLastDataBlockIndex != this->pDataBlockHeader->uiBlockCount)
                {
                	this->lpFragmentationMap[uiLastDataBlockIndex].uiNextDataBlockIndex = uiDataBlockTerminator;
                }*/

                uiCurrentBlockEntryIndex = this->lpBlockEntries[uiCurrentBlockEntryIndex].uiNextBlockEntryIndex;
            }

            uiFilesDefragmented++;
        }
    }

    if(!bError && !bCancel)
    {
        // Store the first unused fragmentation map entry.
        if(uiIncrement < this->pFragmentationMapHeader->uiBlockCount)
        {
            // Note: usually if there are no unused data blocks, uiFirstUnusedEntry is 0, but
            // sometimes it isn't (and I don't know why) so I'm unsure if I should set it to
            // 0 in the else case.
            this->pFragmentationMapHeader->uiFirstUnusedEntry = uiIncrement;
            this->pFragmentationMapHeader->uiChecksum = this->pFragmentationMapHeader->uiBlockCount +
                    this->pFragmentationMapHeader->uiFirstUnusedEntry +
                    this->pFragmentationMapHeader->uiTerminator;
        }

        // Fill in the unused fragmentation map entries with uiBlockCount.
        for(hlUInt i = uiIncrement; i < this->pFragmentationMapHeader->uiBlockCount; i++)
        {
            this->lpFragmentationMap[i].uiNextDataBlockIndex = this->pFragmentationMapHeader->uiBlockCount;
        }
    }
    else
    {
        hlByte *lpTouched = new hlByte[this->pFragmentationMapHeader->uiBlockCount];
        memset(lpTouched, 0, sizeof(hlByte) * this->pFragmentationMapHeader->uiBlockCount);

        // Figure out which fragmentation map entries are used.
        for(hlUInt i = 0; i < this->pDirectoryHeader->uiItemCount; i++)
        {
            if(this->lpDirectoryEntries[i].uiDirectoryFlags & HL_GCF_FLAG_FILE)
            {
                hlUInt uiBlockEntryIndex = this->lpDirectoryMapEntries[i].uiFirstBlockIndex;

                while(uiBlockEntryIndex != this->pDataBlockHeader->uiBlockCount)
                {
                    hlUInt uiBlockEntrySize = 0;
                    hlUInt uiDataBlockIndex = this->lpBlockEntries[uiBlockEntryIndex].uiFirstDataBlockIndex;

                    while(uiDataBlockIndex < uiDataBlockTerminator && uiBlockEntrySize < this->lpBlockEntries[uiBlockEntryIndex].uiFileDataSize)
                    {
                        lpTouched[uiDataBlockIndex] = hlTrue;

                        uiDataBlockIndex = this->lpFragmentationMap[uiDataBlockIndex].uiNextDataBlockIndex;

                        uiBlockEntrySize += this->pDataBlockHeader->uiBlockSize;
                    }

                    uiBlockEntryIndex = this->lpBlockEntries[uiBlockEntryIndex].uiNextBlockEntryIndex;
                }
            }
        }

        // Fill in the unused fragmentation map entries with uiBlockCount.
        hlBool bFirst = hlFalse;
        for(hlUInt i = 0; i < this->pFragmentationMapHeader->uiBlockCount; i++)
        {
            if(!lpTouched[i])
            {
                if(!bFirst)
                {
                    // Store the first unused fragmentation map entry.
                    this->pFragmentationMapHeader->uiFirstUnusedEntry = i;
                    this->pFragmentationMapHeader->uiChecksum = this->pFragmentationMapHeader->uiBlockCount +
                            this->pFragmentationMapHeader->uiFirstUnusedEntry +
                            this->pFragmentationMapHeader->uiTerminator;

                    bFirst = hlTrue;
                }
                this->lpFragmentationMap[i].uiNextDataBlockIndex = this->pFragmentationMapHeader->uiBlockCount;
            }
        }

        delete []lpTouched;
    }

    delete []lpDataBlock;

    this->pMapping->Unmap(pCurrentView);
    this->pMapping->Unmap(pIncrementedView);

    // Commit header changes to mapping.
    this->pMapping->Commit(*this->pHeaderView, (hlUInt)((const hlByte *)this->lpBlockEntries - (const hlByte *)this->pHeaderView->GetView()), sizeof(GCFBlockEntry) * this->pBlockEntryHeader->uiBlockCount);
    this->pMapping->Commit(*this->pHeaderView, (hlUInt)((const hlByte *)this->pFragmentationMapHeader - (const hlByte *)this->pHeaderView->GetView()), sizeof(GCFFragmentationMapHeader));
    this->pMapping->Commit(*this->pHeaderView, (hlUInt)((const hlByte *)this->lpFragmentationMap - (const hlByte *)this->pHeaderView->GetView()), sizeof(GCFFragmentationMap) * this->pFragmentationMapHeader->uiBlockCount);

    return !bError;
}