From 8473d547edb2b33f2318444f5b155eaab8fa1a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Ho=C5=A1ek?= Date: Tue, 11 Dec 2012 03:02:11 +0100 Subject: [PATCH] update HLLib to 2.4.3 --- HLExtract.Net/HLLib.cs | 22 +- HLExtract.Net/Properties/AssemblyInfo.cs | 6 +- HLExtract/HLExtract.rc | 16 +- HLLib/DirectoryFolder.cpp | 8 +- HLLib/HLLib.rc | 16 +- HLLib/Packages.h | 3 +- HLLib/SGAFile.cpp | 627 +++++++++++++++++++++++ HLLib/SGAFile.h | 207 ++++++++ HLLib/Utility.cpp | 60 ++- HLLib/Utility.h | 18 +- HLLib/VPKFile.cpp | 12 + HLLib/Wrapper.cpp | 6 +- HLLib/ZIPFile.cpp | 165 +++++- HLLib/ZIPFile.h | 3 +- HLLib/stdafx.h | 27 +- Readme.txt | 11 +- lib/HLLib.h | 217 +++++++- sln/vs10/HLLib/HLLib.vcxproj | 22 +- sln/vs8/HLLib/HLLib.vcproj | 172 ++++--- sln/vs9/HLLib/HLLib.vcproj | 28 +- 20 files changed, 1498 insertions(+), 148 deletions(-) create mode 100644 HLLib/SGAFile.cpp create mode 100644 HLLib/SGAFile.h diff --git a/HLExtract.Net/HLLib.cs b/HLExtract.Net/HLLib.cs index f40710c..4c99214 100644 --- a/HLExtract.Net/HLLib.cs +++ b/HLExtract.Net/HLLib.cs @@ -1,6 +1,6 @@ /* * HLExtract.Net - * Copyright (C) 2008-2010 Ryan Gregg + * Copyright (C) 2008-2012 Ryan Gregg * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,8 +19,8 @@ using System.Runtime.InteropServices; public sealed class HLLib { #region Constants - public const int HL_VERSION_NUMBER = ((2 << 24) | (4 << 16) | (2 << 8) | 0); - public const string HL_VERSION_STRING = "2.4.2"; + public const int HL_VERSION_NUMBER = ((2 << 24) | (4 << 16) | (3 << 8) | 0); + public const string HL_VERSION_STRING = "2.4.3"; public const uint HL_ID_INVALID = 0xffffffff; @@ -143,7 +143,8 @@ public sealed class HLLib HL_PACKAGE_XZP, HL_PACKAGE_ZIP, HL_PACKAGE_NCF, - HL_PACKAGE_VPK + HL_PACKAGE_VPK, + HL_PACKAGE_SGA } public enum HLAttributeType : uint @@ -194,6 +195,19 @@ public sealed class HLLib HL_PAK_PACKAGE_COUNT = 0, HL_PAK_ITEM_COUNT = 0, + HL_SGA_PACKAGE_VERSION_MAJOR = 0, + HL_SGA_PACKAGE_VERSION_MINOR, + HL_SGA_PACKAGE_MD5_FILE, + HL_SGA_PACKAGE_NAME, + HL_SGA_PACKAGE_MD5_HEADER, + HL_SGA_PACKAGE_COUNT, + HL_SGA_ITEM_SECTION_ALIAS = 0, + HL_SGA_ITEM_SECTION_NAME, + HL_SGA_ITEM_MODIFIED, + HL_SGA_ITEM_TYPE, + HL_SGA_ITEM_CRC, + HL_SGA_ITEM_COUNT, + HL_VBSP_PACKAGE_VERSION = 0, HL_VBSP_PACKAGE_MAP_REVISION, HL_VBSP_PACKAGE_COUNT, diff --git a/HLExtract.Net/Properties/AssemblyInfo.cs b/HLExtract.Net/Properties/AssemblyInfo.cs index 54dcab7..0e46866 100644 --- a/HLExtract.Net/Properties/AssemblyInfo.cs +++ b/HLExtract.Net/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("HLExtract.Net")] -[assembly: AssemblyCopyright("Copyright (C) 2008-2011 Ryan Gregg")] +[assembly: AssemblyCopyright("Copyright (C) 2008-2012 Ryan Gregg")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.4.2.0")] -[assembly: AssemblyFileVersion("2.4.2.0")] +[assembly: AssemblyVersion("2.4.3.0")] +[assembly: AssemblyFileVersion("2.4.3.0")] diff --git a/HLExtract/HLExtract.rc b/HLExtract/HLExtract.rc index 83381b6..1110cf0 100644 --- a/HLExtract/HLExtract.rc +++ b/HLExtract/HLExtract.rc @@ -13,13 +13,11 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources +// English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) -#endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -53,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,4,2,0 - PRODUCTVERSION 2,4,2,0 + FILEVERSION 2,4,3,0 + PRODUCTVERSION 2,4,3,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -71,12 +69,12 @@ BEGIN BEGIN VALUE "Comments", "Half-Life Package Extraction Utility" VALUE "FileDescription", "HLExtract Application" - VALUE "FileVersion", "2.4.2" + VALUE "FileVersion", "2.4.3" VALUE "InternalName", "HLExtract" - VALUE "LegalCopyright", "Copyright (C) 2006-2011 Ryan Gregg" + VALUE "LegalCopyright", "Copyright (C) 2006-2012 Ryan Gregg" VALUE "OriginalFilename", "HLExtract.exe" VALUE "ProductName", " HLExtract Application" - VALUE "ProductVersion", "2.4.2" + VALUE "ProductVersion", "2.4.3" END END BLOCK "VarFileInfo" @@ -85,7 +83,7 @@ BEGIN END END -#endif // English (U.S.) resources +#endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/HLLib/DirectoryFolder.cpp b/HLLib/DirectoryFolder.cpp index 8385784..1cfc4bb 100644 --- a/HLLib/DirectoryFolder.cpp +++ b/HLLib/DirectoryFolder.cpp @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -678,7 +678,11 @@ hlBool CDirectoryFolder::Extract(const hlChar *lpPath) const for(hlUInt i = 0; i < this->pDirectoryItemVector->size(); i++) { - bResult &= (*this->pDirectoryItemVector)[i]->Extract(lpFolderName); + const CDirectoryItem *pItem = (*this->pDirectoryItemVector)[i]; + if(pItem->GetType() != HL_ITEM_FILE || static_cast(pItem)->GetExtractable()) + { + bResult &= pItem->Extract(lpFolderName); + } } } diff --git a/HLLib/HLLib.rc b/HLLib/HLLib.rc index 601e93b..12d4d0c 100644 --- a/HLLib/HLLib.rc +++ b/HLLib/HLLib.rc @@ -13,13 +13,11 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources +// English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) -#endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -53,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,4,2,0 - PRODUCTVERSION 2,4,2,0 + FILEVERSION 2,4,3,0 + PRODUCTVERSION 2,4,3,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -71,12 +69,12 @@ BEGIN BEGIN VALUE "Comments", "Half-Life Package Library" VALUE "FileDescription", "HLLib Dynamic Link Library" - VALUE "FileVersion", "2.4.2" + VALUE "FileVersion", "2.4.3" VALUE "InternalName", "HLLib" - VALUE "LegalCopyright", "Copyright (C) 2006-2011 Ryan Gregg" + VALUE "LegalCopyright", "Copyright (C) 2006-2012 Ryan Gregg" VALUE "OriginalFilename", "HLLib.dll" VALUE "ProductName", " HLLib Dynamic Link Library" - VALUE "ProductVersion", "2.4.2" + VALUE "ProductVersion", "2.4.3" END END BLOCK "VarFileInfo" @@ -85,7 +83,7 @@ BEGIN END END -#endif // English (U.S.) resources +#endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/HLLib/Packages.h b/HLLib/Packages.h index 9319815..6ebc32e 100644 --- a/HLLib/Packages.h +++ b/HLLib/Packages.h @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,6 +14,7 @@ #include "GCFFile.h" #include "NCFFile.h" #include "PAKFile.h" +#include "SGAFile.h" #include "VBSPFile.h" #include "VPKFile.h" #include "WADFile.h" diff --git a/HLLib/SGAFile.cpp b/HLLib/SGAFile.cpp new file mode 100644 index 0000000..3ae2513 --- /dev/null +++ b/HLLib/SGAFile.cpp @@ -0,0 +1,627 @@ +/* + * HLLib + * Copyright (C) 2006-2012 Ryan Gregg + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later + * version. + */ + +#include "HLLib.h" +#include "SGAFile.h" +#include "Streams.h" +#include "Checksum.h" +#include "Utility.h" + +#if USE_ZLIB +# ifdef _WIN32 +# define ZLIB_WINAPI +# endif +# include +#endif + +using namespace HLLib; + +#define HL_SGA_CHECKSUM_LENGTH 0x00008000 + +const char *CSGAFile::lpAttributeNames[] = { "Major Version", "Minor Version", "File MD5", "Name", "Header MD5" }; +const char *CSGAFile::lpItemAttributeNames[] = { "Section Alias", "Section Name", "Modified", "Type", "CRC" }; + +CSGAFile::CSGAFile() : CPackage(), pHeaderView(0), pHeader(0), pDirectory(0) +{ + +} + +CSGAFile::~CSGAFile() +{ + this->Close(); +} + +HLPackageType CSGAFile::GetType() const +{ + return HL_PACKAGE_SGA; +} + +const hlChar *CSGAFile::GetExtension() const +{ + return "sga"; +} + +const hlChar *CSGAFile::GetDescription() const +{ + return "Archive File"; +} + +hlBool CSGAFile::MapDataStructures() +{ + if(sizeof(SGAHeader) > 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(SGAHeader))) + { + return hlFalse; + } + this->pHeader = static_cast(this->pHeaderView->GetView()); + + if(memcmp(this->pHeader->lpSignature, "_ARCHIVE", 8) != 0) + { + LastError.SetErrorMessage("Invalid file: the file's signature does not match."); + return hlFalse; + } + + if((this->pHeader->uiMajorVersion != 4 || this->pHeader->uiMinorVersion != 0) && (this->pHeader->uiMajorVersion != 5 || this->pHeader->uiMinorVersion != 0)) + { + LastError.SetErrorMessageFormated("Invalid SGA version (v%hu.%hu): you have a version of a SGA file that HLLib does not know how to read. Check for product updates.", this->pHeader->uiMajorVersion, this->pHeader->uiMinorVersion); + return hlFalse; + } + + if(this->pHeader->uiHeaderLength > this->pMapping->GetMappingSize()) + { + LastError.SetErrorMessage("Invalid file: the file map is too small for it's extended header."); + return hlFalse; + } + + switch(this->pHeader->uiMajorVersion) + { + case 4: + this->pDirectory = new CSGADirectory4(*this); + break; + case 5: + this->pDirectory = new CSGADirectory5(*this); + break; + default: + assert(false); + return hlFalse; + } + + if(!this->pDirectory->MapDataStructures()) + { + return hlFalse; + } + + return hlTrue; +} + +hlVoid CSGAFile::UnmapDataStructures() +{ + delete this->pDirectory; + this->pDirectory = 0; + + this->pHeader = 0; + + this->pMapping->Unmap(this->pHeaderView); +} + +CDirectoryFolder *CSGAFile::CreateRoot() +{ + return this->pDirectory->CreateRoot(); +} + +hlBool CSGAFile::GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const +{ + return this->pDirectory->GetItemAttributeInternal(pItem, eAttribute, Attribute); +} + +hlBool CSGAFile::GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const +{ + return this->pDirectory->GetFileExtractableInternal(pFile, bExtractable); +} + +hlBool CSGAFile::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const +{ + return this->pDirectory->GetFileValidationInternal(pFile, eValidation); +} + +hlBool CSGAFile::GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const +{ + return this->pDirectory->GetFileSizeInternal(pFile, uiSize); +} + +hlBool CSGAFile::GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const +{ + return this->pDirectory->GetFileSizeOnDiskInternal(pFile, uiSize); +} + +hlBool CSGAFile::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const +{ + return this->pDirectory->CreateStreamInternal(pFile, pStream); +} + +hlVoid CSGAFile::ReleaseStreamInternal(Streams::IStream &Stream) const +{ + return this->pDirectory->ReleaseStreamInternal(Stream); +} + + +hlUInt CSGAFile::GetAttributeCountInternal() const +{ + return HL_SGA_PACKAGE_COUNT; +} + +const hlChar *CSGAFile::GetAttributeNameInternal(HLPackageAttribute eAttribute) const +{ + if(eAttribute < HL_SGA_PACKAGE_COUNT) + { + return this->lpAttributeNames[eAttribute]; + } + + return 0; +} + +hlBool CSGAFile::GetAttributeInternal(HLPackageAttribute eAttribute, HLAttribute &Attribute) const +{ + hlChar lpBuffer[64]; + switch(eAttribute) + { + case HL_SGA_PACKAGE_VERSION_MAJOR: + hlAttributeSetUnsignedInteger(&Attribute, this->lpAttributeNames[eAttribute], this->pHeader->uiMajorVersion, hlFalse); + return hlTrue; + case HL_SGA_PACKAGE_VERSION_MINOR: + hlAttributeSetUnsignedInteger(&Attribute, this->lpAttributeNames[eAttribute], this->pHeader->uiMinorVersion, hlFalse); + return hlTrue; + case HL_SGA_PACKAGE_MD5_FILE: + BufferToHexString(this->pHeader->lpFileMD5, 16, lpBuffer, sizeof(lpBuffer)); + hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer); + return hlTrue; + case HL_SGA_PACKAGE_NAME: + WStringToString(this->pHeader->lpName, lpBuffer, sizeof(lpBuffer)); + hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer); + return hlTrue; + case HL_SGA_PACKAGE_MD5_HEADER: + BufferToHexString(this->pHeader->lpHeaderMD5, 16, lpBuffer, sizeof(lpBuffer)); + hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer); + return hlTrue; + default: + return hlFalse; + } +} + +hlUInt CSGAFile::GetItemAttributeCountInternal() const +{ + return HL_SGA_ITEM_COUNT; +} + +const hlChar *CSGAFile::GetItemAttributeNameInternal(HLPackageAttribute eAttribute) const +{ + if(eAttribute < HL_SGA_ITEM_COUNT) + { + return this->lpItemAttributeNames[eAttribute]; + } + + return 0; +} + +CSGAFile::ISGADirectory::~ISGADirectory() +{ + +} + +template +CSGAFile::CSGADirectory::CSGADirectory(CSGAFile& File) : File(File), pHeaderDirectoryView(0), pDirectoryHeader(0), lpSections(0), lpFolders(0), lpFiles(0), lpStringTable(0) +{ + +} + +template +CSGAFile::CSGADirectory::~CSGADirectory() +{ + this->UnmapDataStructures(); +} + +template +hlBool CSGAFile::CSGADirectory::MapDataStructures() +{ + if(!this->File.pMapping->Map(this->pHeaderDirectoryView, sizeof(SGAHeader), this->File.pHeader->uiHeaderLength)) + { + return hlFalse; + } + + this->pDirectoryHeader = static_cast(this->pHeaderDirectoryView->GetView()); + + if(this->pDirectoryHeader->uiSectionCount > 0 && this->pDirectoryHeader->uiSectionOffset + sizeof(TSGASection) * this->pDirectoryHeader->uiSectionCount > this->File.pHeader->uiHeaderLength) + { + LastError.SetErrorMessage("Invalid file: the file map is too small for section data."); + return hlFalse; + } + if(this->pDirectoryHeader->uiFolderCount > 0 && this->pDirectoryHeader->uiFolderOffset + sizeof(TSGAFolder) * this->pDirectoryHeader->uiFolderCount > this->File.pHeader->uiHeaderLength) + { + LastError.SetErrorMessage("Invalid file: the file map is too small for folder data."); + return hlFalse; + } + if(this->pDirectoryHeader->uiFileCount > 0 && this->pDirectoryHeader->uiFileOffset + sizeof(TSGAFile) * this->pDirectoryHeader->uiFileCount > this->File.pHeader->uiHeaderLength) + { + LastError.SetErrorMessage("Invalid file: the file map is too small for file data."); + return hlFalse; + } + if(this->pDirectoryHeader->uiStringTableOffset > this->File.pHeader->uiHeaderLength) + { + LastError.SetErrorMessage("Invalid file: the file map is too small for string table data."); + return hlFalse; + } + + this->lpSections = reinterpret_cast(reinterpret_cast(this->pDirectoryHeader) + this->pDirectoryHeader->uiSectionOffset); + this->lpFolders = reinterpret_cast(reinterpret_cast(this->pDirectoryHeader) + this->pDirectoryHeader->uiFolderOffset); + this->lpFiles = reinterpret_cast(reinterpret_cast(this->pDirectoryHeader) + this->pDirectoryHeader->uiFileOffset); + this->lpStringTable = reinterpret_cast(reinterpret_cast(this->pDirectoryHeader) + this->pDirectoryHeader->uiStringTableOffset); + + return hlTrue; +} + +template +hlVoid CSGAFile::CSGADirectory::UnmapDataStructures() +{ + this->pDirectoryHeader = 0; + this->lpSections = 0; + this->lpFolders = 0; + this->lpFiles = 0; + this->lpStringTable = 0; + + this->File.pMapping->Unmap(this->pHeaderDirectoryView); +} + +template +CDirectoryFolder *CSGAFile::CSGADirectory::CreateRoot() +{ + CDirectoryFolder *pRoot = new CDirectoryFolder(&File); + + for(hlUInt i = 0; i < this->pDirectoryHeader->uiSectionCount; i++) + { + CDirectoryFolder* pSection; + // Check if folder exists. + CDirectoryItem *pItem = pRoot->GetItem(this->lpSections[i].lpAlias); + if(pItem == 0 || pItem->GetType() == HL_ITEM_FILE) + { + // It doesn't, create it. + pSection = pRoot->AddFolder(this->lpSections[i].lpAlias); + } + else + { + // It does, use it. + pSection = static_cast(pItem); + } + this->CreateFolder(pSection, this->lpSections[i].uiFolderRootIndex); + } + + return pRoot; +} + +template +hlVoid CSGAFile::CSGADirectory::CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex) +{ + const hlChar* lpName = this->lpStringTable + this->lpFolders[uiFolderIndex].uiNameOffset; + if(*lpName != '\0') + { + // Strip parent folder names. + const hlChar* lpTemp = strrchr(lpName, '/'); + if(lpTemp != 0) + { + lpName = lpTemp + 1; + } + lpTemp = strrchr(lpName, '\\'); + if(lpTemp != 0) + { + lpName = lpTemp + 1; + } + // Check if folder exists. + CDirectoryItem *pItem = pParent->GetItem(lpName); + if(pItem == 0 || pItem->GetType() == HL_ITEM_FILE) + { + // It doesn't, create it. + pParent = pParent->AddFolder(lpName); + } + else + { + // It does, use it. + pParent = static_cast(pItem); + } + } + for(hlUInt i = this->lpFolders[uiFolderIndex].uiFolderStartIndex; i < this->lpFolders[uiFolderIndex].uiFolderEndIndex; i++) + { + CreateFolder(pParent, i); + } + for(hlUInt i = this->lpFolders[uiFolderIndex].uiFileStartIndex; i < this->lpFolders[uiFolderIndex].uiFileEndIndex; i++) + { + const hlChar* lpName = this->lpStringTable + this->lpFiles[i].uiNameOffset; + pParent->AddFile(lpName, i); + } +} + +template +hlBool CSGAFile::CSGADirectory::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(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(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(pFileHeaderView->GetView()); + hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], pFileHeader->uiCRC32, hlTrue); + this->File.pMapping->Unmap(pFileHeaderView); + return hlTrue; + } + return hlFalse; + } + } + break; + } + } + } + return hlFalse; +} + +template +hlBool CSGAFile::CSGADirectory::GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const +{ +#if !USE_ZLIB + const TSGAFile &File = this->lpFiles[pFile->GetID()]; + + bExtractable = File.uiType == 0; +#else + bExtractable = true; +#endif + + return hlTrue; +} + +template +hlBool CSGAFile::CSGADirectory::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(pFileHeaderDataView->GetView()); + const hlByte* lpBuffer = reinterpret_cast(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(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(pFile), uiTotalBytes, uiFileBytes, &bCancel); + + while(uiTotalBytes < uiFileBytes) + { + if(bCancel) + { + eValidation = HL_VALIDATES_CANCELED; + break; + } + + hlUInt uiBufferSize = static_cast(uiTotalBytes + HL_SGA_CHECKSUM_LENGTH <= uiFileBytes ? HL_SGA_CHECKSUM_LENGTH : uiFileBytes - uiTotalBytes); + uiChecksum = CRC32(lpBuffer, uiBufferSize, uiChecksum); + + lpBuffer += uiBufferSize; + uiTotalBytes += static_cast(uiBufferSize); + + hlValidateFileProgress(const_cast(pFile), uiTotalBytes, uiFileBytes, &bCancel); + } + } +#if USE_ZLIB + delete []lpInflateBuffer; +#endif + eValidation = static_cast(pFileHeader->uiCRC32) == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT; + + this->File.pMapping->Unmap(pFileHeaderDataView); + } + else + { + eValidation = HL_VALIDATES_ERROR; + } + + return hlTrue; +} + +template +hlBool CSGAFile::CSGADirectory::GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const +{ + const TSGAFile &File = this->lpFiles[pFile->GetID()]; + + uiSize = File.uiSize; + + return hlTrue; +} + +template +hlBool CSGAFile::CSGADirectory::GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const +{ + const TSGAFile &File = this->lpFiles[pFile->GetID()]; + + uiSize = File.uiSizeOnDisk; + + return hlTrue; +} + +template +hlBool CSGAFile::CSGADirectory::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(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; + } +} + +template +hlVoid CSGAFile::CSGADirectory::ReleaseStreamInternal(Streams::IStream &Stream) const +{ + if(Stream.GetType() == HL_STREAM_MEMORY) + { + delete []static_cast(static_cast(Stream).GetBuffer()); + } +} \ No newline at end of file diff --git a/HLLib/SGAFile.h b/HLLib/SGAFile.h new file mode 100644 index 0000000..65a9142 --- /dev/null +++ b/HLLib/SGAFile.h @@ -0,0 +1,207 @@ +/* + * HLLib + * Copyright (C) 2006-2012 Ryan Gregg + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later + * version. + */ + +#ifndef SGAFILE_H +#define SGAFILE_H + +#include "stdafx.h" +#include "Package.h" + +namespace HLLib +{ + class HLLIB_API CSGAFile : public CPackage + { + private: + #pragma pack(1) + + struct SGAHeader + { + hlChar lpSignature[8]; + hlUShort uiMajorVersion; + hlUShort uiMinorVersion; + hlByte lpFileMD5[16]; + hlWChar lpName[64]; + hlByte lpHeaderMD5[16]; + hlUInt uiHeaderLength; + hlUInt uiFileDataOffset; + hlUInt uiDummy0; + }; + + template + struct SGADirectoryHeader + { + hlUInt uiSectionOffset; + T uiSectionCount; + hlUInt uiFolderOffset; + T uiFolderCount; + hlUInt uiFileOffset; + T uiFileCount; + hlUInt uiStringTableOffset; + T uiStringTableCount; + }; + + typedef SGADirectoryHeader SGADirectoryHeader4; + typedef SGADirectoryHeader SGADirectoryHeader5; + + template + struct SGASection + { + hlChar lpAlias[64]; + hlChar lpName[64]; + T uiFolderStartIndex; + T uiFolderEndIndex; + T uiFileStartIndex; + T uiFileEndIndex; + T uiFolderRootIndex; + }; + + typedef SGASection SGASection4; + typedef SGASection SGASection5; + + template + struct SGAFolder + { + hlUInt uiNameOffset; + T uiFolderStartIndex; + T uiFolderEndIndex; + T uiFileStartIndex; + T uiFileEndIndex; + }; + + typedef SGAFolder SGAFolder4; + typedef SGAFolder SGAFolder5; + + struct SGAFile + { + hlUInt uiNameOffset; + hlUInt uiOffset; + hlUInt uiSizeOnDisk; + hlUInt uiSize; + hlUInt uiTimeModified; + hlByte uiDummy0; + hlByte uiType; + }; + + struct SGAFileHeader + { + hlChar lpName[256]; + hlUInt uiCRC32; + }; + + #pragma pack() + + class ISGADirectory + { + public: + virtual ~ISGADirectory() = 0; + + public: + virtual hlBool MapDataStructures() = 0; + virtual hlVoid UnmapDataStructures() = 0; + + virtual CDirectoryFolder *CreateRoot() = 0; + + virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const = 0; + + virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const = 0; + virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const = 0; + virtual hlBool GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const = 0; + virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const = 0; + + virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const = 0; + virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const = 0; + }; + + template + class CSGADirectory : public ISGADirectory + { + public: + CSGADirectory(CSGAFile& File); + virtual ~CSGADirectory(); + + private: + CSGAFile& File; + + Mapping::CView *pHeaderDirectoryView; + const TSGADirectoryHeader *pDirectoryHeader; + const TSGASection *lpSections; + const TSGAFolder *lpFolders; + const TSGAFile *lpFiles; + const hlChar *lpStringTable; + + public: + virtual hlBool MapDataStructures(); + virtual hlVoid UnmapDataStructures(); + + virtual CDirectoryFolder *CreateRoot(); + + virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const; + + virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const; + virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const; + virtual hlBool GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + + virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const; + virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const; + + private: + hlVoid CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex); + }; + + typedef CSGADirectory CSGADirectory4; + typedef CSGADirectory CSGADirectory5; + + friend CSGADirectory4; + friend CSGADirectory5; + + private: + static const char *lpAttributeNames[]; + static const char *lpItemAttributeNames[]; + + Mapping::CView *pHeaderView; + const SGAHeader *pHeader; + + ISGADirectory* pDirectory; + + public: + CSGAFile(); + virtual ~CSGAFile(); + + virtual HLPackageType GetType() const; + virtual const hlChar *GetExtension() const; + virtual const hlChar *GetDescription() const; + + protected: + virtual hlBool MapDataStructures(); + virtual hlVoid UnmapDataStructures(); + + virtual CDirectoryFolder *CreateRoot(); + + virtual hlUInt GetAttributeCountInternal() const; + virtual const hlChar *GetAttributeNameInternal(HLPackageAttribute eAttribute) const; + virtual hlBool GetAttributeInternal(HLPackageAttribute eAttribute, HLAttribute &Attribute) const; + + virtual hlUInt GetItemAttributeCountInternal() const; + virtual const hlChar *GetItemAttributeNameInternal(HLPackageAttribute eAttribute) const; + virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const; + + virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const; + virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const; + virtual hlBool GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + + virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const; + virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const; + }; +} + +#endif diff --git a/HLLib/Utility.cpp b/HLLib/Utility.cpp index 10534a9..ad1d85e 100644 --- a/HLLib/Utility.cpp +++ b/HLLib/Utility.cpp @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -157,3 +157,61 @@ hlVoid HLLib::RemoveIllegalCharacters(hlChar *lpName) } } } + +hlChar HLLib::NibbleToChar(hlByte uiNibble) +{ + uiNibble &= 0x0F; + return uiNibble <= 9 ? '0' + static_cast(uiNibble) : 'A' + static_cast(uiNibble) - ('9' - '0' + 1); +} + +hlUInt HLLib::BufferToHexString(const hlByte *lpBuffer, hlUInt uiBufferSize, hlChar* lpString, hlUInt uiStringSize) +{ + hlUInt uiCharsWritten = (uiStringSize + 1) / 2; + for(hlUInt i = 0; i < uiBufferSize && uiStringSize > 2; i++) + { + *lpString++ = NibbleToChar(lpBuffer[i] >> 4); + uiStringSize--; + + *lpString++ = NibbleToChar(lpBuffer[i]); + uiStringSize--; + } + if(uiStringSize > 0) + { + *lpString = '\0'; + } + return uiCharsWritten; +} + +hlUInt HLLib::WStringToString(const hlWChar *lpSource, hlChar* lpDest, hlUInt uiDestSize) +{ +#ifdef _WIN32 + int iResult = WideCharToMultiByte(CP_ACP, 0, lpSource, -1, lpDest, static_cast(uiDestSize), NULL, NULL); + if(iResult > 0) + { + return static_cast(iResult); + } + else if(uiDestSize > 0) + { + *lpDest = '\0'; + return 1; + } + return 0; +#else + hlUInt uiCharsWritten = 0; + while(*lpSource != L'\0' && uiDestSize > 1) + { + if(*lpSource >= L' ' && *lpSource <= L'~') + { + *lpDest++ = static_cast(*lpSource++); + uiDestSize--; + uiCharsWritten++; + } + } + if(uiDestSize > 0) + { + *lpDest = '\0'; + uiCharsWritten++; + } + return uiCharsWritten; +#endif +} \ No newline at end of file diff --git a/HLLib/Utility.h b/HLLib/Utility.h index e743280..1391e17 100644 --- a/HLLib/Utility.h +++ b/HLLib/Utility.h @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,15 +17,19 @@ namespace HLLib { - hlBool GetFileExists(const hlChar *lpPath); - hlBool GetFolderExists(const hlChar *lpPath); + extern hlBool GetFileExists(const hlChar *lpPath); + extern hlBool GetFolderExists(const hlChar *lpPath); - hlBool GetFileSize(const hlChar *lpPath, hlUInt &uiFileSize); + extern hlBool GetFileSize(const hlChar *lpPath, hlUInt &uiFileSize); - hlBool CreateFolder(const hlChar *lpPath); + extern hlBool CreateFolder(const hlChar *lpPath); - hlVoid FixupIllegalCharacters(hlChar *lpName); - hlVoid RemoveIllegalCharacters(hlChar *lpName); + extern hlVoid FixupIllegalCharacters(hlChar *lpName); + extern hlVoid RemoveIllegalCharacters(hlChar *lpName); + + extern hlChar NibbleToChar(hlByte uiNibble); + extern hlUInt BufferToHexString(const hlByte *lpBuffer, hlUInt uiBufferSize, hlChar* lpString, hlUInt uiStringSize); + extern hlUInt WStringToString(const hlWChar *lpSource, hlChar* lpDest, hlUInt uiDestSize); } #endif diff --git a/HLLib/VPKFile.cpp b/HLLib/VPKFile.cpp index 93a6457..80c534c 100644 --- a/HLLib/VPKFile.cpp +++ b/HLLib/VPKFile.cpp @@ -97,7 +97,19 @@ hlBool CVPKFile::MapDataStructures() } else { + if(this->pHeader->uiVersion > 2) + { + LastError.SetErrorMessageFormated("Invalid VPK version (v%u): you have a version of a VPK file that HLLib does not know how to read. Check for product updates.", this->pHeader->uiVersion); + return hlFalse; + } lpViewData += sizeof(VPKHeader); + switch(this->pHeader->uiVersion) + { + case 2: + // Version two includes 4 more double words. + lpViewData += 4 * sizeof(hlUInt); + break; + } lpViewDirectoryDataEnd = lpViewData + this->pHeader->uiDirectoryLength; } diff --git a/HLLib/Wrapper.cpp b/HLLib/Wrapper.cpp index 90e11b9..f1f12c6 100644 --- a/HLLib/Wrapper.cpp +++ b/HLLib/Wrapper.cpp @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -513,6 +513,7 @@ HLPackageTest lpPackageTests[] = { HL_PACKAGE_GCF, 8, { 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 } }, { HL_PACKAGE_NCF, 8, { 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 } }, { HL_PACKAGE_PAK, 4, { 'P', 'A', 'C', 'K' } }, + { HL_PACKAGE_SGA, 8, { '_', 'A', 'R', 'C', 'H', 'I', 'V', 'E' } }, { HL_PACKAGE_VBSP, 4, { 'V', 'B', 'S', 'P' } }, { HL_PACKAGE_VPK, 4, { 0x34, 0x12, 0xaa, 0x55 } }, { HL_PACKAGE_WAD, 4, { 'W', 'A', 'D', '3' } }, @@ -596,6 +597,9 @@ HLLIB_API hlBool hlCreatePackage(HLPackageType ePackageType, hlUInt *uiPackage) case HL_PACKAGE_PAK: pNewPackage = new CPAKFile(); break; + case HL_PACKAGE_SGA: + pNewPackage = new CSGAFile(); + break; case HL_PACKAGE_VBSP: pNewPackage = new CVBSPFile(); break; diff --git a/HLLib/ZIPFile.cpp b/HLLib/ZIPFile.cpp index 2f068f2..af7e01b 100644 --- a/HLLib/ZIPFile.cpp +++ b/HLLib/ZIPFile.cpp @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,6 +14,69 @@ #include "Streams.h" #include "Checksum.h" +#if USE_ZLIB +# ifdef _WIN32 +# define ZLIB_WINAPI +# endif +# include + +struct OutDesc +{ + Bytef *dest; + uLongf destLen; +}; + +static unsigned in(void FAR *in_desc, unsigned char FAR * FAR *input) +{ + return 0; +} + +static int out(void FAR *out_desc, unsigned char FAR *ouput, unsigned len) +{ + if(len <= ((OutDesc*)(out_desc))->destLen) + { + memcpy(((OutDesc*)(out_desc))->dest, ouput, len); + ((OutDesc*)(out_desc))->dest += len; + ((OutDesc*)(out_desc))->destLen -= len; + return 0; + } + return 1; +} + +static int uncompressBack(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + unsigned char window[32768]; + err = inflateBackInit(&stream, 15, window); + if (err != Z_OK) return err; + + OutDesc out_desc = { dest, *destLen }; + err = inflateBack(&stream, in, 0, out, &out_desc); + if (err != Z_STREAM_END) { + inflateBackEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = *destLen - out_desc.destLen; + + err = inflateBackEnd(&stream); + return err; +} + +#endif + using namespace HLLib; #define HL_ZIP_LOCAL_FILE_HEADER_SIGNATURE 0x04034b50 @@ -342,7 +405,18 @@ hlBool CZIPFile::GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool { const ZIPFileHeader *pDirectoryItem = static_cast(pFile->GetData()); - bExtractable = pDirectoryItem->uiCompressionMethod == 0 && pDirectoryItem->uiDiskNumberStart == this->pEndOfCentralDirectoryRecord->uiNumberOfThisDisk; + switch(pDirectoryItem->uiCompressionMethod) + { + case 0: // None. +#if USE_ZLIB + case 8: // Deflate. +#endif + bExtractable = (pDirectoryItem->uiFlags & 0x01u) == 0 && pDirectoryItem->uiDiskNumberStart == this->pEndOfCentralDirectoryRecord->uiNumberOfThisDisk; + break; + default: + bExtractable = hlFalse; + break; + } return hlTrue; } @@ -351,7 +425,8 @@ hlBool CZIPFile::GetFileValidationInternal(const CDirectoryFile *pFile, HLValida { const ZIPFileHeader *pDirectoryItem = static_cast(pFile->GetData()); - if(pDirectoryItem->uiCompressionMethod != 0 || pDirectoryItem->uiDiskNumberStart != this->pEndOfCentralDirectoryRecord->uiNumberOfThisDisk) + hlBool bExtractable = false; + if(!GetFileExtractableInternal(pFile, bExtractable) || !bExtractable) { eValidation = HL_VALIDATES_ASSUMED_OK; return hlTrue; @@ -419,12 +494,24 @@ hlBool CZIPFile::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStr { const ZIPFileHeader *pDirectoryItem = static_cast(pFile->GetData()); - if(pDirectoryItem->uiCompressionMethod != 0) + switch(pDirectoryItem->uiCompressionMethod) { + case 0: // None. +#if USE_ZLIB + case 8: // Deflate. +#endif + break; + default: LastError.SetErrorMessageFormated("Compression format %#.2x not supported.", pDirectoryItem->uiCompressionMethod); return hlFalse; } + if((pDirectoryItem->uiFlags & 0x01u) != 0) + { + LastError.SetErrorMessageFormated("File is encrypted."); + return hlFalse; + } + if(pDirectoryItem->uiDiskNumberStart != this->pEndOfCentralDirectoryRecord->uiNumberOfThisDisk) { LastError.SetErrorMessageFormated("File resides on disk %u.", pDirectoryItem->uiDiskNumberStart); @@ -438,17 +525,77 @@ hlBool CZIPFile::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStr return hlFalse; } - const ZIPLocalFileHeader DirectoryEntry = *static_cast(pDirectoryEnrtyView->GetView()); + ZIPLocalFileHeader DirectoryEntry = *static_cast(pDirectoryEnrtyView->GetView()); this->pMapping->Unmap(pDirectoryEnrtyView); + if((DirectoryEntry.uiFlags & 0x08u) != 0) + { + DirectoryEntry.uiCRC32 = pDirectoryItem->uiCRC32; + DirectoryEntry.uiUncompressedSize = pDirectoryItem->uiUncompressedSize; + DirectoryEntry.uiCompressedSize = pDirectoryItem->uiCompressedSize; + } + if(DirectoryEntry.uiSignature != HL_ZIP_LOCAL_FILE_HEADER_SIGNATURE) { - LastError.SetErrorMessageFormated("Invalid file data offset.", pDirectoryItem->uiDiskNumberStart); + LastError.SetErrorMessageFormated("Invalid file data offset."); return hlFalse; } - pStream = new Streams::CMappingStream(*this->pMapping, pDirectoryItem->uiRelativeOffsetOfLocalHeader + sizeof(ZIPLocalFileHeader) + DirectoryEntry.uiFileNameLength + DirectoryEntry.uiExtraFieldLength, DirectoryEntry.uiUncompressedSize); - - return hlTrue; + switch(pDirectoryItem->uiCompressionMethod) + { + case 0: // None. + { + pStream = new Streams::CMappingStream(*this->pMapping, pDirectoryItem->uiRelativeOffsetOfLocalHeader + sizeof(ZIPLocalFileHeader) + DirectoryEntry.uiFileNameLength + DirectoryEntry.uiExtraFieldLength, DirectoryEntry.uiUncompressedSize); + return hlTrue; + } +#if USE_ZLIB + case 8: // Deflate. + { + Mapping::CView *pFileDataView = 0; + if(this->pMapping->Map(pFileDataView, pDirectoryItem->uiRelativeOffsetOfLocalHeader + sizeof(ZIPLocalFileHeader) + DirectoryEntry.uiFileNameLength + DirectoryEntry.uiExtraFieldLength, DirectoryEntry.uiCompressedSize)) + { + hlBool bResult = hlFalse; + hlByte *lpInflateBuffer = new hlByte[DirectoryEntry.uiUncompressedSize]; + uLongf iInflateSize = DirectoryEntry.uiUncompressedSize; + switch(uncompressBack(lpInflateBuffer, &iInflateSize, static_cast(pFileDataView->GetView()), (uLong)DirectoryEntry.uiCompressedSize)) + { + 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->pMapping->Unmap(pFileDataView); + return bResult; + } + return hlFalse; + } +#endif + default: + return hlFalse; + } } + +hlVoid CZIPFile::ReleaseStreamInternal(Streams::IStream &Stream) const +{ + if(Stream.GetType() == HL_STREAM_MEMORY) + { + delete []static_cast(static_cast(Stream).GetBuffer()); + } +} \ No newline at end of file diff --git a/HLLib/ZIPFile.h b/HLLib/ZIPFile.h index 4a0a74a..10269b5 100644 --- a/HLLib/ZIPFile.h +++ b/HLLib/ZIPFile.h @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -116,6 +116,7 @@ namespace HLLib virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const; + virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const; }; } diff --git a/HLLib/stdafx.h b/HLLib/stdafx.h index 2061635..4eb4023 100644 --- a/HLLib/stdafx.h +++ b/HLLib/stdafx.h @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,11 @@ typedef unsigned char hlBool; typedef char hlChar; +#ifdef __cplusplus +typedef wchar_t hlWChar; +#else +typedef unsigned short hlWChar; +#endif typedef unsigned char hlByte; typedef signed short hlShort; typedef unsigned short hlUShort; @@ -60,8 +65,8 @@ typedef hlSingle hlFloat; #define hlFalse 0 #define hlTrue 1 -#define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (2 << 8) | 0) -#define HL_VERSION_STRING "2.4.2" +#define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (3 << 8) | 0) +#define HL_VERSION_STRING "2.4.3" #define HL_ID_INVALID 0xffffffff @@ -186,7 +191,8 @@ typedef enum HL_PACKAGE_XZP, HL_PACKAGE_ZIP, HL_PACKAGE_NCF, - HL_PACKAGE_VPK + HL_PACKAGE_VPK, + HL_PACKAGE_SGA } HLPackageType; typedef enum @@ -237,6 +243,19 @@ typedef enum HL_PAK_PACKAGE_COUNT = 0, HL_PAK_ITEM_COUNT = 0, + HL_SGA_PACKAGE_VERSION_MAJOR = 0, + HL_SGA_PACKAGE_VERSION_MINOR, + HL_SGA_PACKAGE_MD5_FILE, + HL_SGA_PACKAGE_NAME, + HL_SGA_PACKAGE_MD5_HEADER, + HL_SGA_PACKAGE_COUNT, + HL_SGA_ITEM_SECTION_ALIAS = 0, + HL_SGA_ITEM_SECTION_NAME, + HL_SGA_ITEM_MODIFIED, + HL_SGA_ITEM_TYPE, + HL_SGA_ITEM_CRC, + HL_SGA_ITEM_COUNT, + HL_VBSP_PACKAGE_VERSION = 0, HL_VBSP_PACKAGE_MAP_REVISION, HL_VBSP_PACKAGE_COUNT, diff --git a/Readme.txt b/Readme.txt index 91850f1..e3bef2a 100644 --- a/Readme.txt +++ b/Readme.txt @@ -9,11 +9,11 @@ Library/Author Information: =========================== ---- General Library Information ---- -Date : May 22nd, 2011 +Date : September 18th, 2012 Author : Ryan Gregg Michael Mohr (Linux Port) Title : HLLib -Build : 2.4.2 +Build : 2.4.3 Email address : ryansgregg@hotmail.com (Ryan Gregg) m.mohr@laposte.net (Michael Mohr) Home page / Website : http://nemesis.thewavelength.net/ @@ -93,6 +93,11 @@ Console Commands (Interactive console mode): Library Changelog: ================== + v2.4.3 + - Added support for new VPK file format (v2). + - Added SGA file support. + - Added ZIP deflate support. + v2.4.2 - Fixed crash when opening VBSP files with no pak file lump. @@ -117,7 +122,7 @@ Library Changelog: - Added support for new VBSP file format. v2.1.1 - - Added support for new VPK file format. + - Added support for new VPK file format (v1). - Added VPK file validation. - Fixed crash when closing VPK files. diff --git a/lib/HLLib.h b/lib/HLLib.h index 8e4a4f6..8536669 100644 --- a/lib/HLLib.h +++ b/lib/HLLib.h @@ -1,6 +1,6 @@ /* * HLLib - * Copyright (C) 2006-2010 Ryan Gregg + * Copyright (C) 2006-2012 Ryan Gregg * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,11 @@ typedef unsigned char hlBool; typedef char hlChar; +#ifdef __cplusplus +typedef wchar_t hlWChar; +#else +typedef unsigned short hlWChar; +#endif typedef unsigned char hlByte; typedef signed short hlShort; typedef unsigned short hlUShort; @@ -60,8 +65,8 @@ typedef hlSingle hlFloat; #define hlFalse 0 #define hlTrue 1 -#define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (2 << 8) | 0) -#define HL_VERSION_STRING "2.4.2" +#define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (3 << 8) | 0) +#define HL_VERSION_STRING "2.4.3" #define HL_ID_INVALID 0xffffffff @@ -190,7 +195,8 @@ typedef enum HL_PACKAGE_XZP, HL_PACKAGE_ZIP, HL_PACKAGE_NCF, - HL_PACKAGE_VPK + HL_PACKAGE_VPK, + HL_PACKAGE_SGA } HLPackageType; typedef enum @@ -241,6 +247,19 @@ typedef enum HL_PAK_PACKAGE_COUNT = 0, HL_PAK_ITEM_COUNT = 0, + HL_SGA_PACKAGE_VERSION_MAJOR = 0, + HL_SGA_PACKAGE_VERSION_MINOR, + HL_SGA_PACKAGE_MD5_FILE, + HL_SGA_PACKAGE_NAME, + HL_SGA_PACKAGE_MD5_HEADER, + HL_SGA_PACKAGE_COUNT, + HL_SGA_ITEM_SECTION_ALIAS = 0, + HL_SGA_ITEM_SECTION_NAME, + HL_SGA_ITEM_MODIFIED, + HL_SGA_ITEM_TYPE, + HL_SGA_ITEM_CRC, + HL_SGA_ITEM_COUNT, + HL_VBSP_PACKAGE_VERSION = 0, HL_VBSP_PACKAGE_MAP_REVISION, HL_VBSP_PACKAGE_COUNT, @@ -1858,6 +1877,196 @@ namespace HLLib virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const; }; + // + // CSGAFile + // + + class HLLIB_API CSGAFile : public CPackage + { + private: + #pragma pack(1) + + struct SGAHeader + { + hlChar lpSignature[8]; + hlUShort uiMajorVersion; + hlUShort uiMinorVersion; + hlByte lpFileMD5[16]; + hlWChar lpName[64]; + hlByte lpHeaderMD5[16]; + hlUInt uiHeaderLength; + hlUInt uiFileDataOffset; + hlUInt uiDummy0; + }; + + template + struct SGADirectoryHeader + { + hlUInt uiSectionOffset; + T uiSectionCount; + hlUInt uiFolderOffset; + T uiFolderCount; + hlUInt uiFileOffset; + T uiFileCount; + hlUInt uiStringTableOffset; + T uiStringTableCount; + }; + + typedef SGADirectoryHeader SGADirectoryHeader4; + typedef SGADirectoryHeader SGADirectoryHeader5; + + template + struct SGASection + { + hlChar lpAlias[64]; + hlChar lpName[64]; + T uiFolderStartIndex; + T uiFolderEndIndex; + T uiFileStartIndex; + T uiFileEndIndex; + T uiFolderRootIndex; + }; + + typedef SGASection SGASection4; + typedef SGASection SGASection5; + + template + struct SGAFolder + { + hlUInt uiNameOffset; + T uiFolderStartIndex; + T uiFolderEndIndex; + T uiFileStartIndex; + T uiFileEndIndex; + }; + + typedef SGAFolder SGAFolder4; + typedef SGAFolder SGAFolder5; + + struct SGAFile + { + hlUInt uiNameOffset; + hlUInt uiOffset; + hlUInt uiSizeOnDisk; + hlUInt uiSize; + hlUInt uiTimeModified; + hlByte uiDummy0; + hlByte uiType; + }; + + struct SGAFileHeader + { + hlChar lpName[256]; + hlUInt uiCRC32; + }; + + #pragma pack() + + class ISGADirectory + { + public: + virtual ~ISGADirectory() = 0; + + public: + virtual hlBool MapDataStructures() = 0; + virtual hlVoid UnmapDataStructures() = 0; + + virtual CDirectoryFolder *CreateRoot() = 0; + + virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const = 0; + + virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const = 0; + virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const = 0; + virtual hlBool GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const = 0; + virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const = 0; + + virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const = 0; + virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const = 0; + }; + + template + class CSGADirectory : public ISGADirectory + { + public: + CSGADirectory(CSGAFile& File); + virtual ~CSGADirectory(); + + private: + CSGAFile& File; + + Mapping::CView *pHeaderDirectoryView; + const TSGADirectoryHeader *pDirectoryHeader; + const TSGASection *lpSections; + const TSGAFolder *lpFolders; + const TSGAFile *lpFiles; + const hlChar *lpStringTable; + + public: + virtual hlBool MapDataStructures(); + virtual hlVoid UnmapDataStructures(); + + virtual CDirectoryFolder *CreateRoot(); + + virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const; + + virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const; + virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const; + virtual hlBool GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + + virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const; + virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const; + + private: + hlVoid CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex); + }; + + typedef CSGADirectory CSGADirectory4; + typedef CSGADirectory CSGADirectory5; + + friend CSGADirectory4; + friend CSGADirectory5; + + private: + static const char *lpAttributeNames[]; + static const char *lpItemAttributeNames[]; + + Mapping::CView *pHeaderView; + const SGAHeader *pHeader; + + ISGADirectory* pDirectory; + + public: + CSGAFile(); + virtual ~CSGAFile(); + + virtual HLPackageType GetType() const; + virtual const hlChar *GetExtension() const; + virtual const hlChar *GetDescription() const; + + protected: + virtual hlBool MapDataStructures(); + virtual hlVoid UnmapDataStructures(); + + virtual CDirectoryFolder *CreateRoot(); + + virtual hlUInt GetAttributeCountInternal() const; + virtual const hlChar *GetAttributeNameInternal(HLPackageAttribute eAttribute) const; + virtual hlBool GetAttributeInternal(HLPackageAttribute eAttribute, HLAttribute &Attribute) const; + + virtual hlUInt GetItemAttributeCountInternal() const; + virtual const hlChar *GetItemAttributeNameInternal(HLPackageAttribute eAttribute) const; + virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const; + + virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const; + virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const; + virtual hlBool GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; + + virtual hlBool CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const; + virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const; + }; + // // CVBSPFile // diff --git a/sln/vs10/HLLib/HLLib.vcxproj b/sln/vs10/HLLib/HLLib.vcxproj index b4effdc..b5a9d42 100644 --- a/sln/vs10/HLLib/HLLib.vcxproj +++ b/sln/vs10/HLLib/HLLib.vcxproj @@ -80,7 +80,7 @@ Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_USE_RTM_VERSION;HLLIB_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_USE_RTM_VERSION;HLLIB_EXPORTS;USE_ZLIB=1;%(PreprocessorDefinitions) true Sync EnableFastChecks @@ -90,6 +90,7 @@ Level3 EditAndContinue + E:\Projects\Utilities\ZLib $(OutDir)HLLib.dll @@ -101,6 +102,8 @@ $(OutDir)HLLib.lib MachineX86 + E:\Projects\Utilities\ZLib\contrib\vstudio\vc10\x86\ZlibStatDebug + zlibstat.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -109,7 +112,7 @@ Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_USE_RTM_VERSION;HLLIB_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_USE_RTM_VERSION;HLLIB_EXPORTS;USE_ZLIB=1;%(PreprocessorDefinitions) true Sync EnableFastChecks @@ -119,6 +122,7 @@ Level3 ProgramDatabase + E:\Projects\Utilities\ZLib $(OutDir)HLLib.dll @@ -130,6 +134,8 @@ $(OutDir)HLLib.lib MachineX64 + zlibstat.lib;%(AdditionalDependencies) + E:\Projects\Utilities\ZLib\contrib\vstudio\vc10\x64\ZlibStatDebug;%(AdditionalLibraryDirectories) @@ -139,7 +145,7 @@ true Speed true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HLLIB_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;HLLIB_EXPORTS;USE_ZLIB=1;%(PreprocessorDefinitions) Sync MultiThreaded false @@ -147,6 +153,7 @@ Level3 ProgramDatabase + E:\Projects\Utilities\ZLib $(OutDir)HLLib.dll @@ -159,6 +166,8 @@ $(OutDir)HLLib.lib MachineX86 + E:\Projects\Utilities\ZLib\contrib\vstudio\vc10\x86\ZlibStatRelease + zlibstat.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -171,7 +180,7 @@ true Speed true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HLLIB_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;HLLIB_EXPORTS;USE_ZLIB=1;%(PreprocessorDefinitions) Sync MultiThreaded false @@ -179,6 +188,7 @@ Level3 ProgramDatabase + E:\Projects\Utilities\ZLib $(OutDir)HLLib.dll @@ -191,6 +201,8 @@ $(OutDir)HLLib.lib MachineX64 + E:\Projects\Utilities\ZLib\contrib\vstudio\vc10\x64\ZlibStatRelease;%(AdditionalLibraryDirectories) + zlibstat.lib;%(AdditionalDependencies) @@ -198,6 +210,7 @@ + @@ -231,6 +244,7 @@ + diff --git a/sln/vs8/HLLib/HLLib.vcproj b/sln/vs8/HLLib/HLLib.vcproj index 2df8705..13e587c 100644 --- a/sln/vs8/HLLib/HLLib.vcproj +++ b/sln/vs8/HLLib/HLLib.vcproj @@ -99,6 +99,88 @@ Name="VCPostBuildEventTool" /> + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + @@ -582,6 +586,10 @@ RelativePath="..\..\..\HLLib\PAKFile.h" > + + diff --git a/sln/vs9/HLLib/HLLib.vcproj b/sln/vs9/HLLib/HLLib.vcproj index e4823cb..e03cc9f 100644 --- a/sln/vs9/HLLib/HLLib.vcproj +++ b/sln/vs9/HLLib/HLLib.vcproj @@ -45,7 +45,8 @@ + + @@ -575,6 +591,10 @@ RelativePath="..\..\..\HLLib\PAKFile.h" > + +