Merge branch 'upstream'

merging in 2.4.5
This commit is contained in:
Ondřej Hošek 2013-11-22 01:03:39 +01:00
commit f93bccd42c
13 changed files with 945 additions and 144 deletions

View File

@ -19,8 +19,8 @@ using System.Runtime.InteropServices;
public sealed class HLLib public sealed class HLLib
{ {
#region Constants #region Constants
public const int HL_VERSION_NUMBER = ((2 << 24) | (4 << 16) | (4 << 8) | 0); public const int HL_VERSION_NUMBER = ((2 << 24) | (4 << 16) | (5 << 8) | 0);
public const string HL_VERSION_STRING = "2.4.4"; public const string HL_VERSION_STRING = "2.4.5";
public const uint HL_ID_INVALID = 0xffffffff; public const uint HL_ID_INVALID = 0xffffffff;
@ -206,6 +206,7 @@ public sealed class HLLib
HL_SGA_ITEM_MODIFIED, HL_SGA_ITEM_MODIFIED,
HL_SGA_ITEM_TYPE, HL_SGA_ITEM_TYPE,
HL_SGA_ITEM_CRC, HL_SGA_ITEM_CRC,
HL_SGA_ITEM_VERIFICATION,
HL_SGA_ITEM_COUNT, HL_SGA_ITEM_COUNT,
HL_VBSP_PACKAGE_VERSION = 0, HL_VBSP_PACKAGE_VERSION = 0,

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("2.4.4.0")] [assembly: AssemblyVersion("2.4.5.0")]
[assembly: AssemblyFileVersion("2.4.4.0")] [assembly: AssemblyFileVersion("2.4.5.0")]

View File

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,4,4,0 FILEVERSION 2,4,5,0
PRODUCTVERSION 2,4,4,0 PRODUCTVERSION 2,4,5,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -69,12 +69,12 @@ BEGIN
BEGIN BEGIN
VALUE "Comments", "Half-Life Package Extraction Utility" VALUE "Comments", "Half-Life Package Extraction Utility"
VALUE "FileDescription", "HLExtract Application" VALUE "FileDescription", "HLExtract Application"
VALUE "FileVersion", "2.4.4" VALUE "FileVersion", "2.4.5"
VALUE "InternalName", "HLExtract" VALUE "InternalName", "HLExtract"
VALUE "LegalCopyright", "Copyright (C) 2006-2013 Ryan Gregg" VALUE "LegalCopyright", "Copyright (C) 2006-2013 Ryan Gregg"
VALUE "OriginalFilename", "HLExtract.exe" VALUE "OriginalFilename", "HLExtract.exe"
VALUE "ProductName", " HLExtract Application" VALUE "ProductName", " HLExtract Application"
VALUE "ProductVersion", "2.4.4" VALUE "ProductVersion", "2.4.5"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -207,6 +207,17 @@ hlULong HLLib::CRC32(const hlByte *lpBuffer, hlUInt uiBufferSize, hlULong uiCRC)
return uiCRC ^ 0xffffffffUL; return uiCRC ^ 0xffffffffUL;
} }
inline hlULong LeftRoate(hlULong value, hlUInt bits)
{
return (value << bits) | (value >> (32 - bits));
}
inline hlULong SwapEndian(hlULong value)
{
value = ((value << 8) & 0xFF00FF00UL) | ((value >> 8) & 0x00FF00FFUL);
return (value << 16) | (value >> 16);
}
const hlULong lpMD5Table[4][16] = const hlULong lpMD5Table[4][16] =
{ {
{ {
@ -251,11 +262,6 @@ const hlByte lpMD5Padding[64] =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; };
hlULong LeftRoate(hlULong value, hlUInt bits)
{
return (value << bits) | (value >> (32 - bits));
}
hlVoid HLLib::MD5_Initialize(MD5Context& context) hlVoid HLLib::MD5_Initialize(MD5Context& context)
{ {
context.lpState[0] = 0x67452301UL; context.lpState[0] = 0x67452301UL;
@ -286,7 +292,7 @@ hlVoid HLLib::MD5_Update(MD5Context& context, const hlByte *lpBuffer, hlUInt uiB
// Round 1. // Round 1.
for(hlULong i = 0; i < 16; ++i) for(hlULong i = 0; i < 16; ++i)
{ {
hlULong x = (b & c) | ((~b) & d); hlULong x = d ^ (b & (c ^ d));
hlULong t = d; hlULong t = d;
d = c; d = c;
@ -360,5 +366,144 @@ hlVoid HLLib::MD5_Finalize(MD5Context& context, hlByte (&lpDigest)[16])
MD5_Update(context, reinterpret_cast<hlByte*>(&uiLengthInBits), sizeof(uiLengthInBits)); MD5_Update(context, reinterpret_cast<hlByte*>(&uiLengthInBits), sizeof(uiLengthInBits));
memcpy(lpDigest, context.lpState, sizeof(lpDigest)); for(hlULong i = 0; i < sizeof(context.lpState) / sizeof(context.lpState[0]); ++i)
{
reinterpret_cast<hlULong*>(lpDigest)[i] = context.lpState[i];
}
} }
hlVoid HLLib::SHA1_Initialize(SHA1Context& context)
{
context.lpState[0] = 0x67452301UL;
context.lpState[1] = 0xEFCDAB89UL;
context.lpState[2] = 0x98BADCFEUL;
context.lpState[3] = 0x10325476UL;
context.lpState[4] = 0xC3D2E1F0UL;
context.uiLength = 0;
}
hlVoid HLLib::SHA1_Update(SHA1Context& context, const hlByte *lpBuffer, hlUInt uiBufferSize)
{
hlULong uiBlockLength = context.uiLength % sizeof(context.lpBlock);
while(uiBlockLength + uiBufferSize >= sizeof(context.lpBlock))
{
hlULong uiCopyLength = std::min(static_cast<hlULong>(uiBufferSize), static_cast<hlULong>(sizeof(context.lpBlock) - uiBlockLength));
memcpy(reinterpret_cast<hlByte*>(context.lpBlock) + uiBlockLength, lpBuffer, uiCopyLength);
context.uiLength += uiCopyLength;
lpBuffer += uiCopyLength;
uiBufferSize -= uiCopyLength;
{
hlULong a = context.lpState[0];
hlULong b = context.lpState[1];
hlULong c = context.lpState[2];
hlULong d = context.lpState[3];
hlULong e = context.lpState[4];
hlULong i;
hlULong lpExtendedBlock[80];
// Input needs to be big-endian.
for(i = 0; i < 16; ++i)
{
lpExtendedBlock[i] = SwapEndian(context.lpBlock[i]);
}
// Extend the 16 dwords to 80.
for(; i < 80; ++i)
{
lpExtendedBlock[i] = LeftRoate(lpExtendedBlock[i - 3] ^ lpExtendedBlock[i - 8] ^ lpExtendedBlock[i - 14] ^ lpExtendedBlock[i - 16], 1);
}
// Round 1.
for(i = 0; i < 20; ++i)
{
hlULong x = d ^ (b & (c ^ d));
hlULong t = LeftRoate(a, 5) + x + e + 0x5A827999UL + lpExtendedBlock[i];
e = d;
d = c;
c = LeftRoate(b, 30);
b = a;
a = t;
}
// Round 2.
for(; i < 40; ++i)
{
hlULong x = b ^ c ^ d;
hlULong t = LeftRoate(a, 5) + x + e + 0x6ED9EBA1UL + lpExtendedBlock[i];
e = d;
d = c;
c = LeftRoate(b, 30);
b = a;
a = t;
}
// Round 3.
for(; i < 60; ++i)
{
hlULong x = (b & c) | ((b | c) & d);
hlULong t = LeftRoate(a, 5) + x + e + 0x8F1BBCDCUL + lpExtendedBlock[i];
e = d;
d = c;
c = LeftRoate(b, 30);
b = a;
a = t;
}
// Round 4.
for(; i < 80; ++i)
{
hlULong x = b ^ c ^ d;
hlULong t = LeftRoate(a, 5) + x + e + 0xCA62C1D6UL + lpExtendedBlock[i];
e = d;
d = c;
c = LeftRoate(b, 30);
b = a;
a = t;
}
context.lpState[0] += a;
context.lpState[1] += b;
context.lpState[2] += c;
context.lpState[3] += d;
context.lpState[4] += e;
}
uiBlockLength = 0;
}
memcpy(reinterpret_cast<hlByte*>(context.lpBlock) + uiBlockLength, lpBuffer, uiBufferSize);
context.uiLength += uiBufferSize;
}
hlVoid HLLib::SHA1_Finalize(SHA1Context& context, hlByte (&lpDigest)[20])
{
hlULongLong uiLengthInBits = 8ULL * static_cast<hlULongLong>(context.uiLength);
hlULong uiBlockLength = context.uiLength % sizeof(context.lpBlock);
if(uiBlockLength < sizeof(context.lpBlock) - sizeof(hlULongLong))
{
SHA1_Update(context, lpMD5Padding, sizeof(context.lpBlock) - sizeof(uiLengthInBits) - uiBlockLength);
}
else
{
SHA1_Update(context, lpMD5Padding, 2 * sizeof(context.lpBlock) - sizeof(uiLengthInBits) - uiBlockLength);
}
// Length needs to be big-endian.
uiLengthInBits = (uiLengthInBits << 32) | (uiLengthInBits >> 32);
uiLengthInBits = static_cast<hlULongLong>(SwapEndian(static_cast<hlULong>(uiLengthInBits & 0xFFFFFFFFULL))) | static_cast<hlULongLong>(SwapEndian(static_cast<hlULong>(uiLengthInBits >> 32))) << 32;
SHA1_Update(context, reinterpret_cast<hlByte*>(&uiLengthInBits), sizeof(uiLengthInBits));
for(hlULong i = 0; i < sizeof(context.lpState) / sizeof(context.lpState[0]); ++i)
{
// Output needs to be big-endian.
reinterpret_cast<hlULong*>(lpDigest)[i] = SwapEndian(context.lpState[i]);
}
}

View File

@ -30,6 +30,130 @@ namespace HLLib
hlVoid MD5_Initialize(MD5Context& context); hlVoid MD5_Initialize(MD5Context& context);
hlVoid MD5_Update(MD5Context& context, const hlByte *lpBuffer, hlUInt uiBufferSize); hlVoid MD5_Update(MD5Context& context, const hlByte *lpBuffer, hlUInt uiBufferSize);
hlVoid MD5_Finalize(MD5Context& context, hlByte (&lpDigest)[16]); hlVoid MD5_Finalize(MD5Context& context, hlByte (&lpDigest)[16]);
struct SHA1Context
{
hlULong lpState[5];
hlULong lpBlock[16];
hlULong uiLength;
};
hlVoid SHA1_Initialize(SHA1Context& context);
hlVoid SHA1_Update(SHA1Context& context, const hlByte *lpBuffer, hlUInt uiBufferSize);
hlVoid SHA1_Finalize(SHA1Context& context, hlByte (&lpDigest)[20]);
class Checksum
{
public:
virtual ~Checksum()
{
}
virtual hlULong GetDigestSize() const = 0;
virtual void Initialize() = 0;
virtual void Update(const hlByte *lpBuffer, hlUInt uiBufferSize) = 0;
virtual bool Finalize(const hlByte *lpHash) = 0;
};
class CRC32Checksum : public Checksum
{
public:
CRC32Checksum()
{
Initialize();
}
virtual hlULong GetDigestSize() const
{
return sizeof(this->uiChecksum);
}
virtual void Initialize()
{
this->uiChecksum = 0;
}
virtual void Update(const hlByte *lpBuffer, hlUInt uiBufferSize)
{
this->uiChecksum = CRC32(lpBuffer, uiBufferSize, this->uiChecksum);
}
virtual bool Finalize(const hlByte *lpHash)
{
return *reinterpret_cast<const hlULong*>(lpHash) == this->uiChecksum;
}
private:
hlULong uiChecksum;
};
class MD5Checksum : public Checksum
{
public:
MD5Checksum()
{
Initialize();
}
virtual hlULong GetDigestSize() const
{
return sizeof(this->context.lpState);
}
virtual void Initialize()
{
MD5_Initialize(this->context);
}
virtual void Update(const hlByte *lpBuffer, hlUInt uiBufferSize)
{
MD5_Update(this->context, lpBuffer, uiBufferSize);
}
virtual bool Finalize(const hlByte *lpHash)
{
hlByte lpDigest[16];
MD5_Finalize(this->context, lpDigest);
return memcmp(lpHash, lpDigest, sizeof(lpDigest)) == 0;
}
private:
MD5Context context;
};
class SHA1Checksum : public Checksum
{
public:
SHA1Checksum()
{
Initialize();
}
virtual hlULong GetDigestSize() const
{
return sizeof(this->context.lpState);
}
virtual void Initialize()
{
SHA1_Initialize(this->context);
}
virtual void Update(const hlByte *lpBuffer, hlUInt uiBufferSize)
{
SHA1_Update(this->context, lpBuffer, uiBufferSize);
}
virtual bool Finalize(const hlByte *lpHash)
{
hlByte lpDigest[20];
SHA1_Finalize(this->context, lpDigest);
return memcmp(lpHash, lpDigest, sizeof(lpDigest)) == 0;
}
private:
SHA1Context context;
};
} }
#endif #endif

View File

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,4,4,0 FILEVERSION 2,4,5,0
PRODUCTVERSION 2,4,4,0 PRODUCTVERSION 2,4,5,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -69,12 +69,12 @@ BEGIN
BEGIN BEGIN
VALUE "Comments", "Half-Life Package Library" VALUE "Comments", "Half-Life Package Library"
VALUE "FileDescription", "HLLib Dynamic Link Library" VALUE "FileDescription", "HLLib Dynamic Link Library"
VALUE "FileVersion", "2.4.4" VALUE "FileVersion", "2.4.5"
VALUE "InternalName", "HLLib" VALUE "InternalName", "HLLib"
VALUE "LegalCopyright", "Copyright (C) 2006-2013 Ryan Gregg" VALUE "LegalCopyright", "Copyright (C) 2006-2013 Ryan Gregg"
VALUE "OriginalFilename", "HLLib.dll" VALUE "OriginalFilename", "HLLib.dll"
VALUE "ProductName", " HLLib Dynamic Link Library" VALUE "ProductName", " HLLib Dynamic Link Library"
VALUE "ProductVersion", "2.4.4" VALUE "ProductVersion", "2.4.5"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -27,7 +27,8 @@ using namespace HLLib;
#define HL_SGA_CHECKSUM_LENGTH 0x00008000 #define HL_SGA_CHECKSUM_LENGTH 0x00008000
const char *CSGAFile::lpAttributeNames[] = { "Major Version", "Minor Version", "File MD5", "Name", "Header MD5" }; const char *CSGAFile::lpAttributeNames[] = { "Major Version", "Minor Version", "File MD5", "Name", "Header MD5" };
const char *CSGAFile::lpItemAttributeNames[] = { "Section Alias", "Section Name", "Modified", "Type", "CRC" }; const char *CSGAFile::lpItemAttributeNames[] = { "Section Alias", "Section Name", "Modified", "Type", "CRC", "Verification" };
const char *CSGAFile::lpVerificationNames[] = { "None", "CRC", "CRC Blocks", "MD5 Blocks", "SHA1 Blocks" };
CSGAFile::CSGAFile() : CPackage(), pHeaderView(0), pHeader(0), pDirectory(0) CSGAFile::CSGAFile() : CPackage(), pHeaderView(0), pHeader(0), pDirectory(0)
{ {
@ -56,17 +57,18 @@ const hlChar *CSGAFile::GetDescription() const
hlBool CSGAFile::MapDataStructures() hlBool CSGAFile::MapDataStructures()
{ {
if(sizeof(SGAHeader) > this->pMapping->GetMappingSize()) hlULongLong uiMaxHeaderSize = std::max(sizeof(SGAHeader4), sizeof(SGAHeader6));
if(uiMaxHeaderSize > this->pMapping->GetMappingSize())
{ {
LastError.SetErrorMessage("Invalid file: the file map is too small for it's header."); LastError.SetErrorMessage("Invalid file: the file map is too small for it's header.");
return hlFalse; return hlFalse;
} }
if(!this->pMapping->Map(this->pHeaderView, 0, sizeof(SGAHeader))) if(!this->pMapping->Map(this->pHeaderView, 0, uiMaxHeaderSize))
{ {
return hlFalse; return hlFalse;
} }
this->pHeader = static_cast<const SGAHeader *>(this->pHeaderView->GetView()); this->pHeader = static_cast<const SGAHeaderBase *>(this->pHeaderView->GetView());
if(memcmp(this->pHeader->lpSignature, "_ARCHIVE", 8) != 0) if(memcmp(this->pHeader->lpSignature, "_ARCHIVE", 8) != 0)
{ {
@ -74,26 +76,53 @@ hlBool CSGAFile::MapDataStructures()
return hlFalse; return hlFalse;
} }
if((this->pHeader->uiMajorVersion != 4 || this->pHeader->uiMinorVersion != 0) && (this->pHeader->uiMajorVersion != 5 || this->pHeader->uiMinorVersion != 0)) if((this->pHeader->uiMajorVersion != 4 || this->pHeader->uiMinorVersion != 0) &&
(this->pHeader->uiMajorVersion != 5 || this->pHeader->uiMinorVersion != 0) &&
(this->pHeader->uiMajorVersion != 6 || this->pHeader->uiMinorVersion != 0) &&
(this->pHeader->uiMajorVersion != 7 || 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); 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; 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) switch(this->pHeader->uiMajorVersion)
{ {
case 4: case 4:
if(static_cast<const CSGADirectory4::SGAHeader*>(this->pHeader)->uiHeaderLength > this->pMapping->GetMappingSize())
{
LastError.SetErrorMessage("Invalid file: the file map is too small for it's extended header.");
return hlFalse;
}
this->pDirectory = new CSGADirectory4(*this); this->pDirectory = new CSGADirectory4(*this);
break; break;
case 5: case 5:
if(static_cast<const CSGADirectory5::SGAHeader*>(this->pHeader)->uiHeaderLength > this->pMapping->GetMappingSize())
{
LastError.SetErrorMessage("Invalid file: the file map is too small for it's extended header.");
return hlFalse;
}
this->pDirectory = new CSGADirectory5(*this); this->pDirectory = new CSGADirectory5(*this);
break; break;
case 6:
if(static_cast<const CSGADirectory6::SGAHeader*>(this->pHeader)->uiHeaderLength > this->pMapping->GetMappingSize())
{
LastError.SetErrorMessage("Invalid file: the file map is too small for it's extended header.");
return hlFalse;
}
this->pDirectory = new CSGADirectory6(*this);
break;
case 7:
if(static_cast<const CSGADirectory7::SGAHeader*>(this->pHeader)->uiHeaderLength > this->pMapping->GetMappingSize())
{
LastError.SetErrorMessage("Invalid file: the file map is too small for it's extended header.");
return hlFalse;
}
this->pDirectory = new CSGADirectory7(*this);
break;
default: default:
assert(false); assert(false);
return hlFalse; return hlFalse;
@ -185,17 +214,35 @@ hlBool CSGAFile::GetAttributeInternal(HLPackageAttribute eAttribute, HLAttribute
hlAttributeSetUnsignedInteger(&Attribute, this->lpAttributeNames[eAttribute], this->pHeader->uiMinorVersion, hlFalse); hlAttributeSetUnsignedInteger(&Attribute, this->lpAttributeNames[eAttribute], this->pHeader->uiMinorVersion, hlFalse);
return hlTrue; return hlTrue;
case HL_SGA_PACKAGE_MD5_FILE: case HL_SGA_PACKAGE_MD5_FILE:
BufferToHexString(this->pHeader->lpFileMD5, 16, lpBuffer, sizeof(lpBuffer)); if(this->pHeader->uiMajorVersion >= 4 && this->pHeader->uiMajorVersion <= 5)
hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer); {
return hlTrue; BufferToHexString(static_cast<const SGAHeader4 *>(this->pHeader)->lpFileMD5, 16, lpBuffer, sizeof(lpBuffer));
hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer);
return hlTrue;
}
return hlFalse;
case HL_SGA_PACKAGE_NAME: case HL_SGA_PACKAGE_NAME:
WStringToString(this->pHeader->lpName, lpBuffer, sizeof(lpBuffer)); if(this->pHeader->uiMajorVersion >= 4 && this->pHeader->uiMajorVersion <= 5)
hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer); {
return hlTrue; WStringToString(static_cast<const SGAHeader4 *>(this->pHeader)->lpName, lpBuffer, sizeof(lpBuffer));
hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer);
return hlTrue;
}
if(this->pHeader->uiMajorVersion >= 6 && this->pHeader->uiMajorVersion <= 6)
{
WStringToString(static_cast<const SGAHeader6 *>(this->pHeader)->lpName, lpBuffer, sizeof(lpBuffer));
hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer);
return hlTrue;
}
return hlFalse;
case HL_SGA_PACKAGE_MD5_HEADER: case HL_SGA_PACKAGE_MD5_HEADER:
BufferToHexString(this->pHeader->lpHeaderMD5, 16, lpBuffer, sizeof(lpBuffer)); if(this->pHeader->uiMajorVersion >= 4 && this->pHeader->uiMajorVersion <= 5)
hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer); {
return hlTrue; BufferToHexString(static_cast<const SGAHeader4 *>(this->pHeader)->lpHeaderMD5, 16, lpBuffer, sizeof(lpBuffer));
hlAttributeSetString(&Attribute, this->lpAttributeNames[eAttribute], lpBuffer);
return hlTrue;
}
return hlFalse;
default: default:
return hlFalse; return hlFalse;
} }
@ -221,59 +268,77 @@ CSGAFile::ISGADirectory::~ISGADirectory()
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::CSGADirectory(CSGAFile& File) : File(File), pHeaderDirectoryView(0), pDirectoryHeader(0), lpSections(0), lpFolders(0), lpFiles(0), lpStringTable(0) CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::CSGASpecializedDirectory(CSGAFile& File) : File(File), pHeaderDirectoryView(0), pDirectoryHeader(0), lpSections(0), lpFolders(0), lpFiles(0), lpStringTable(0)
{ {
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::~CSGADirectory() CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, CSGAFile::SGAFile4>::CSGASpecializedDirectory(CSGAFile& File) : File(File), pHeaderDirectoryView(0), pDirectoryHeader(0), lpSections(0), lpFolders(0), lpFiles(0), lpStringTable(0)
{
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, CSGAFile::SGAFile6>::CSGASpecializedDirectory(CSGAFile& File) : File(File), pHeaderDirectoryView(0), pDirectoryHeader(0), lpSections(0), lpFolders(0), lpFiles(0), lpStringTable(0)
{
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::CSGADirectory(CSGAFile& File) : CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>(File)
{
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::~CSGADirectory()
{ {
this->UnmapDataStructures(); this->UnmapDataStructures();
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::MapDataStructures() hlBool CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::MapDataStructures()
{ {
if(!this->File.pMapping->Map(this->pHeaderDirectoryView, sizeof(SGAHeader), this->File.pHeader->uiHeaderLength)) if(!this->File.pMapping->Map(this->pHeaderDirectoryView, sizeof(SGAHeader), static_cast<const SGAHeader *>(this->File.pHeader)->uiHeaderLength))
{ {
return hlFalse; return hlFalse;
} }
this->pDirectoryHeader = static_cast<const TSGADirectoryHeader *>(this->pHeaderDirectoryView->GetView()); this->pDirectoryHeader = static_cast<const SGADirectoryHeader *>(this->pHeaderDirectoryView->GetView());
if(this->pDirectoryHeader->uiSectionCount > 0 && this->pDirectoryHeader->uiSectionOffset + sizeof(TSGASection) * this->pDirectoryHeader->uiSectionCount > this->File.pHeader->uiHeaderLength) if(this->pDirectoryHeader->uiSectionCount > 0 && this->pDirectoryHeader->uiSectionOffset + sizeof(SGASection) * this->pDirectoryHeader->uiSectionCount > static_cast<const SGAHeader *>(this->File.pHeader)->uiHeaderLength)
{ {
LastError.SetErrorMessage("Invalid file: the file map is too small for section data."); LastError.SetErrorMessage("Invalid file: the file map is too small for section data.");
return hlFalse; return hlFalse;
} }
if(this->pDirectoryHeader->uiFolderCount > 0 && this->pDirectoryHeader->uiFolderOffset + sizeof(TSGAFolder) * this->pDirectoryHeader->uiFolderCount > this->File.pHeader->uiHeaderLength) if(this->pDirectoryHeader->uiFolderCount > 0 && this->pDirectoryHeader->uiFolderOffset + sizeof(SGAFolder) * this->pDirectoryHeader->uiFolderCount > static_cast<const SGAHeader *>(this->File.pHeader)->uiHeaderLength)
{ {
LastError.SetErrorMessage("Invalid file: the file map is too small for folder data."); LastError.SetErrorMessage("Invalid file: the file map is too small for folder data.");
return hlFalse; return hlFalse;
} }
if(this->pDirectoryHeader->uiFileCount > 0 && this->pDirectoryHeader->uiFileOffset + sizeof(TSGAFile) * this->pDirectoryHeader->uiFileCount > this->File.pHeader->uiHeaderLength) if(this->pDirectoryHeader->uiFileCount > 0 && this->pDirectoryHeader->uiFileOffset + sizeof(SGAFile) * this->pDirectoryHeader->uiFileCount > static_cast<const SGAHeader *>(this->File.pHeader)->uiHeaderLength)
{ {
LastError.SetErrorMessage("Invalid file: the file map is too small for file data."); LastError.SetErrorMessage("Invalid file: the file map is too small for file data.");
return hlFalse; return hlFalse;
} }
if(this->pDirectoryHeader->uiStringTableOffset > this->File.pHeader->uiHeaderLength) if(this->pDirectoryHeader->uiStringTableOffset > static_cast<const SGAHeader *>(this->File.pHeader)->uiHeaderLength)
{ {
LastError.SetErrorMessage("Invalid file: the file map is too small for string table data."); LastError.SetErrorMessage("Invalid file: the file map is too small for string table data.");
return hlFalse; return hlFalse;
} }
this->lpSections = reinterpret_cast<const TSGASection *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiSectionOffset); this->lpSections = reinterpret_cast<const SGASection *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiSectionOffset);
this->lpFolders = reinterpret_cast<const TSGAFolder *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiFolderOffset); this->lpFolders = reinterpret_cast<const SGAFolder *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiFolderOffset);
this->lpFiles = reinterpret_cast<const TSGAFile *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiFileOffset); this->lpFiles = reinterpret_cast<const SGAFile *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiFileOffset);
this->lpStringTable = reinterpret_cast<const hlChar *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiStringTableOffset); this->lpStringTable = reinterpret_cast<const hlChar *>(reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiStringTableOffset);
return hlTrue; return hlTrue;
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlVoid CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::UnmapDataStructures() hlVoid CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::UnmapDataStructures()
{ {
this->pDirectoryHeader = 0; this->pDirectoryHeader = 0;
this->lpSections = 0; this->lpSections = 0;
@ -284,8 +349,8 @@ hlVoid CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
this->File.pMapping->Unmap(this->pHeaderDirectoryView); this->File.pMapping->Unmap(this->pHeaderDirectoryView);
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
CDirectoryFolder *CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::CreateRoot() CDirectoryFolder *CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::CreateRoot()
{ {
CDirectoryFolder *pRoot = new CDirectoryFolder(&File); CDirectoryFolder *pRoot = new CDirectoryFolder(&File);
@ -310,8 +375,8 @@ CDirectoryFolder *CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGA
return pRoot; return pRoot;
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlVoid CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex) hlVoid CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex)
{ {
const hlChar* lpName = this->lpStringTable + this->lpFolders[uiFolderIndex].uiNameOffset; const hlChar* lpName = this->lpStringTable + this->lpFolders[uiFolderIndex].uiNameOffset;
if(*lpName != '\0') if(*lpName != '\0')
@ -351,8 +416,108 @@ hlVoid CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
} }
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const hlBool CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, CSGAFile::SGAFile4>::GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const
{
if(pItem->GetID() != HL_ID_INVALID)
{
switch(pItem->GetType())
{
case HL_ITEM_FILE:
{
const CDirectoryFile *pFile = static_cast<const CDirectoryFile *>(pItem);
const SGAFile &File = this->lpFiles[pFile->GetID()];
switch(eAttribute)
{
case HL_SGA_ITEM_CRC:
{
Mapping::CView *pFileHeaderView = 0;
if(this->File.pMapping->Map(pFileHeaderView, static_cast<const SGAHeader *>(this->File.pHeader)->uiFileDataOffset + File.uiOffset - sizeof(SGAFileHeader), sizeof(SGAFileHeader)))
{
const SGAFileHeader* pFileHeader = static_cast<const SGAFileHeader *>(pFileHeaderView->GetView());
hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], pFileHeader->uiCRC32, hlTrue);
this->File.pMapping->Unmap(pFileHeaderView);
return hlTrue;
}
return hlFalse;
}
case HL_SGA_ITEM_VERIFICATION:
{
hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], CSGAFile::lpVerificationNames[CSGAFile::VERIFICATION_CRC]);
return hlTrue;
}
}
break;
}
}
}
return hlFalse;
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
hlBool CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, CSGAFile::SGAFile6>::GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const
{
if(pItem->GetID() != HL_ID_INVALID)
{
switch(pItem->GetType())
{
case HL_ITEM_FILE:
{
const CDirectoryFile *pFile = static_cast<const CDirectoryFile *>(pItem);
const SGAFile &File = this->lpFiles[pFile->GetID()];
switch(eAttribute)
{
case HL_SGA_ITEM_CRC:
{
hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], File.uiCRC32, hlTrue);
return hlTrue;
}
case HL_SGA_ITEM_VERIFICATION:
{
hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], CSGAFile::lpVerificationNames[CSGAFile::VERIFICATION_CRC]);
return hlTrue;
}
}
break;
}
}
}
return hlFalse;
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const
{
if(pItem->GetID() != HL_ID_INVALID)
{
switch(pItem->GetType())
{
case HL_ITEM_FILE:
{
const CDirectoryFile *pFile = static_cast<const CDirectoryFile *>(pItem);
const SGAFile &File = this->lpFiles[pFile->GetID()];
switch(eAttribute)
{
case HL_SGA_ITEM_CRC:
{
hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], File.uiCRC32, hlTrue);
return hlTrue;
}
case HL_SGA_ITEM_VERIFICATION:
{
hlAttributeSetString(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], CSGAFile::lpVerificationNames[File.uiDummy0 < CSGAFile::VERIFICATION_COUNT ? File.uiDummy0 : CSGAFile::VERIFICATION_NONE]);
return hlTrue;
}
}
break;
}
}
}
return hlFalse;
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const
{ {
if(pItem->GetID() != HL_ID_INVALID) if(pItem->GetID() != HL_ID_INVALID)
{ {
@ -393,7 +558,7 @@ hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
case HL_ITEM_FILE: case HL_ITEM_FILE:
{ {
const CDirectoryFile *pFile = static_cast<const CDirectoryFile *>(pItem); const CDirectoryFile *pFile = static_cast<const CDirectoryFile *>(pItem);
const TSGAFile &File = this->lpFiles[pFile->GetID()]; const SGAFile &File = this->lpFiles[pFile->GetID()];
switch(eAttribute) switch(eAttribute)
{ {
case HL_SGA_ITEM_SECTION_ALIAS: case HL_SGA_ITEM_SECTION_ALIAS:
@ -436,31 +601,19 @@ hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], File.uiType, hlFalse); hlAttributeSetUnsignedInteger(&Attribute, CSGAFile::lpItemAttributeNames[eAttribute], File.uiType, hlFalse);
return hlTrue; 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; break;
} }
} }
} }
return hlFalse; return CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::GetItemAttributeInternal(pItem, eAttribute, Attribute);
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const hlBool CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) const
{ {
#if !USE_ZLIB #if !USE_ZLIB
const TSGAFile &File = this->lpFiles[pFile->GetID()]; const SGAFile &File = this->lpFiles[pFile->GetID()];
bExtractable = File.uiType == 0; bExtractable = File.uiType == 0;
#else #else
@ -470,10 +623,10 @@ hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
return hlTrue; return hlTrue;
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const hlBool CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, CSGAFile::SGAFile4>::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const
{ {
const TSGAFile &File = this->lpFiles[pFile->GetID()]; const SGAFile &File = this->lpFiles[pFile->GetID()];
#if !USE_ZLIB #if !USE_ZLIB
if(File.uiType != 0) if(File.uiType != 0)
@ -484,11 +637,11 @@ hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
#endif #endif
Mapping::CView *pFileHeaderDataView = 0; Mapping::CView *pFileHeaderDataView = 0;
if(this->File.pMapping->Map(pFileHeaderDataView, this->File.pHeader->uiFileDataOffset + File.uiOffset - sizeof(TSGAFileHeader), File.uiSizeOnDisk + sizeof(TSGAFileHeader))) if(this->File.pMapping->Map(pFileHeaderDataView, static_cast<const SGAHeader *>(this->File.pHeader)->uiFileDataOffset + File.uiOffset - sizeof(SGAFileHeader), File.uiSizeOnDisk + sizeof(SGAFileHeader)))
{ {
hlULong uiChecksum = 0; hlULong uiChecksum = 0;
const TSGAFileHeader* pFileHeader = static_cast<const TSGAFileHeader*>(pFileHeaderDataView->GetView()); const SGAFileHeader* pFileHeader = static_cast<const SGAFileHeader*>(pFileHeaderDataView->GetView());
const hlByte* lpBuffer = reinterpret_cast<const hlByte *>(pFileHeader) + sizeof(TSGAFileHeader); const hlByte* lpBuffer = reinterpret_cast<const hlByte *>(pFileHeader) + sizeof(SGAFileHeader);
#if USE_ZLIB #if USE_ZLIB
hlByte *lpInflateBuffer = 0; hlByte *lpInflateBuffer = 0;
if(File.uiType != 0) if(File.uiType != 0)
@ -535,7 +688,10 @@ hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
#if USE_ZLIB #if USE_ZLIB
delete []lpInflateBuffer; delete []lpInflateBuffer;
#endif #endif
eValidation = static_cast<hlULong>(pFileHeader->uiCRC32) == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT; if(eValidation == HL_VALIDATES_ASSUMED_OK)
{
eValidation = static_cast<hlULong>(pFileHeader->uiCRC32) == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT;
}
this->File.pMapping->Unmap(pFileHeaderDataView); this->File.pMapping->Unmap(pFileHeaderDataView);
} }
@ -547,41 +703,166 @@ hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
return hlTrue; return hlTrue;
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const hlBool CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, CSGAFile::SGAFile6>::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const
{ {
const TSGAFile &File = this->lpFiles[pFile->GetID()]; const SGAFile &File = this->lpFiles[pFile->GetID()];
Mapping::CView *pFileHeaderDataView = 0;
if(this->File.pMapping->Map(pFileHeaderDataView, static_cast<const SGAHeader *>(this->File.pHeader)->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk))
{
hlULong uiChecksum = 0;
const hlByte* lpBuffer = reinterpret_cast<const hlByte *>(pFileHeaderDataView->GetView());
hlULongLong uiTotalBytes = 0, uiFileBytes = File.uiSizeOnDisk;
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(eValidation == HL_VALIDATES_ASSUMED_OK)
{
eValidation = static_cast<hlULong>(File.uiCRC32) == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT;
}
this->File.pMapping->Unmap(pFileHeaderDataView);
}
else
{
eValidation = HL_VALIDATES_ERROR;
}
return hlTrue;
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const
{
const SGAFile &File = this->lpFiles[pFile->GetID()];
Mapping::CView *pFileHeaderDataView = 0;
if(this->File.pMapping->Map(pFileHeaderDataView, static_cast<const SGAHeader *>(this->File.pHeader)->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk))
{
hlULong uiChecksum = 0;
const hlByte* lpBuffer = reinterpret_cast<const hlByte *>(pFileHeaderDataView->GetView());
hlULongLong uiTotalBytes = 0, uiFileBytes = File.uiSizeOnDisk;
hlULongLong uiBlockSize = this->pDirectoryHeader->uiBlockSize;
if(uiBlockSize == 0)
{
uiBlockSize = HL_SGA_CHECKSUM_LENGTH;
}
Checksum* checksum = 0;
switch(File.uiDummy0)
{
case CSGAFile::VERIFICATION_CRC_BLOCKS:
checksum = new CRC32Checksum();
break;
case CSGAFile::VERIFICATION_MD5_BLOCKS:
checksum = new MD5Checksum();
break;
case CSGAFile::VERIFICATION_SHA1_BLOCKS:
checksum = new SHA1Checksum();
break;
}
const hlByte *lpHashTable = reinterpret_cast<const hlByte *>(this->pDirectoryHeader) + this->pDirectoryHeader->uiHashTableOffset + File.uiHashOffset;
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 + uiBlockSize <= uiFileBytes ? uiBlockSize : uiFileBytes - uiTotalBytes);
uiChecksum = CRC32(lpBuffer, uiBufferSize, uiChecksum);
if(checksum != 0)
{
checksum->Initialize();
checksum->Update(lpBuffer, uiBufferSize);
if(!checksum->Finalize(lpHashTable))
{
eValidation = HL_VALIDATES_CORRUPT;
break;
}
lpHashTable += checksum->GetDigestSize();
}
lpBuffer += uiBufferSize;
uiTotalBytes += static_cast<hlULongLong>(uiBufferSize);
hlValidateFileProgress(const_cast<CDirectoryFile *>(pFile), uiTotalBytes, uiFileBytes, &bCancel);
}
if(eValidation == HL_VALIDATES_ASSUMED_OK)
{
eValidation = static_cast<hlULong>(File.uiCRC32) == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT;
}
delete checksum;
this->File.pMapping->Unmap(pFileHeaderDataView);
}
else
{
eValidation = HL_VALIDATES_ERROR;
}
return hlTrue;
}
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const
{
const SGAFile &File = this->lpFiles[pFile->GetID()];
uiSize = File.uiSize; uiSize = File.uiSize;
return hlTrue; return hlTrue;
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const hlBool CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const
{ {
const TSGAFile &File = this->lpFiles[pFile->GetID()]; const SGAFile &File = this->lpFiles[pFile->GetID()];
uiSize = File.uiSizeOnDisk; uiSize = File.uiSizeOnDisk;
return hlTrue; return hlTrue;
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const hlBool CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::CreateStreamInternal(const CDirectoryFile *pFile, Streams::IStream *&pStream) const
{ {
const TSGAFile &File = this->lpFiles[pFile->GetID()]; const SGAFile &File = this->lpFiles[pFile->GetID()];
if(File.uiType == 0) if(File.uiType == 0)
{ {
pStream = new Streams::CMappingStream(*this->File.pMapping, this->File.pHeader->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk); pStream = new Streams::CMappingStream(*this->File.pMapping, static_cast<const SGAHeader *>(this->File.pHeader)->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk);
return hlTrue; return hlTrue;
} }
else else
{ {
#if USE_ZLIB #if USE_ZLIB
Mapping::CView *pFileDataView = 0; Mapping::CView *pFileDataView = 0;
if(this->File.pMapping->Map(pFileDataView, this->File.pHeader->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk)) if(this->File.pMapping->Map(pFileDataView, static_cast<const SGAHeader *>(this->File.pHeader)->uiFileDataOffset + File.uiOffset, File.uiSizeOnDisk))
{ {
hlBool bResult = hlFalse; hlBool bResult = hlFalse;
hlByte *lpInflateBuffer = new hlByte[File.uiSize]; hlByte *lpInflateBuffer = new hlByte[File.uiSize];
@ -617,8 +898,8 @@ hlBool CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSG
} }
} }
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
hlVoid CSGAFile::CSGADirectory<TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile, TSGAFileHeader>::ReleaseStreamInternal(Streams::IStream &Stream) const hlVoid CSGAFile::CSGADirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>::ReleaseStreamInternal(Streams::IStream &Stream) const
{ {
if(Stream.GetType() == HL_STREAM_MEMORY) if(Stream.GetType() == HL_STREAM_MEMORY)
{ {

View File

@ -22,11 +22,15 @@ namespace HLLib
private: private:
#pragma pack(1) #pragma pack(1)
struct SGAHeader struct SGAHeaderBase
{ {
hlChar lpSignature[8]; hlChar lpSignature[8];
hlUShort uiMajorVersion; hlUShort uiMajorVersion;
hlUShort uiMinorVersion; hlUShort uiMinorVersion;
};
struct SGAHeader4 : public SGAHeaderBase
{
hlByte lpFileMD5[16]; hlByte lpFileMD5[16];
hlWChar lpName[64]; hlWChar lpName[64];
hlByte lpHeaderMD5[16]; hlByte lpHeaderMD5[16];
@ -35,6 +39,14 @@ namespace HLLib
hlUInt uiDummy0; hlUInt uiDummy0;
}; };
struct SGAHeader6 : public SGAHeaderBase
{
hlWChar lpName[64];
hlUInt uiHeaderLength;
hlUInt uiFileDataOffset;
hlUInt uiDummy0;
};
template<typename T> template<typename T>
struct SGADirectoryHeader struct SGADirectoryHeader
{ {
@ -51,6 +63,12 @@ namespace HLLib
typedef SGADirectoryHeader<hlUShort> SGADirectoryHeader4; typedef SGADirectoryHeader<hlUShort> SGADirectoryHeader4;
typedef SGADirectoryHeader<hlUInt> SGADirectoryHeader5; typedef SGADirectoryHeader<hlUInt> SGADirectoryHeader5;
struct SGADirectoryHeader7 : public SGADirectoryHeader5
{
hlUInt uiHashTableOffset;
hlUInt uiBlockSize;
};
template<typename T> template<typename T>
struct SGASection struct SGASection
{ {
@ -79,7 +97,7 @@ namespace HLLib
typedef SGAFolder<hlUShort> SGAFolder4; typedef SGAFolder<hlUShort> SGAFolder4;
typedef SGAFolder<hlUInt> SGAFolder5; typedef SGAFolder<hlUInt> SGAFolder5;
struct SGAFile struct SGAFile4
{ {
hlUInt uiNameOffset; hlUInt uiNameOffset;
hlUInt uiOffset; hlUInt uiOffset;
@ -90,12 +108,32 @@ namespace HLLib
hlByte uiType; hlByte uiType;
}; };
struct SGAFile6 : public SGAFile4
{
hlUInt uiCRC32;
};
struct SGAFile7 : public SGAFile6
{
hlUInt uiHashOffset;
};
struct SGAFileHeader struct SGAFileHeader
{ {
hlChar lpName[256]; hlChar lpName[256];
hlUInt uiCRC32; hlUInt uiCRC32;
}; };
enum SGAFileVerification
{
VERIFICATION_NONE,
VERIFICATION_CRC,
VERIFICATION_CRC_BLOCKS,
VERIFICATION_MD5_BLOCKS,
VERIFICATION_SHA1_BLOCKS,
VERIFICATION_COUNT,
};
#pragma pack() #pragma pack()
class ISGADirectory class ISGADirectory
@ -120,23 +158,100 @@ namespace HLLib
virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const = 0; virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const = 0;
}; };
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> // Specialization SGAFile7 and up where the CRC moved to the header and the CRC is of the compressed data and there are stronger hashes.
class CSGADirectory : public ISGADirectory template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
class CSGASpecializedDirectory : public ISGADirectory
{
public:
typedef TSGAHeader SGAHeader;
typedef TSGADirectoryHeader SGADirectoryHeader;
typedef TSGASection SGASection;
typedef TSGAFolder SGAFolder;
typedef TSGAFile SGAFile;
CSGASpecializedDirectory(CSGAFile& File);
protected:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const SGADirectoryHeader *pDirectoryHeader;
const SGASection *lpSections;
const SGAFolder *lpFolders;
const SGAFile *lpFiles;
const hlChar *lpStringTable;
public:
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const;
};
// Specialization SGAFile4 where the CRC was stored in a SGAFileHeader located before the file data.
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
class CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, SGAFile4> : public ISGADirectory
{
public:
typedef TSGAHeader SGAHeader;
typedef TSGADirectoryHeader SGADirectoryHeader;
typedef TSGASection SGASection;
typedef TSGAFolder SGAFolder;
typedef CSGAFile::SGAFile4 SGAFile;
CSGASpecializedDirectory(CSGAFile& File);
protected:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const SGADirectoryHeader *pDirectoryHeader;
const SGASection *lpSections;
const SGAFolder *lpFolders;
const SGAFile *lpFiles;
const hlChar *lpStringTable;
public:
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const;
};
// Specialization SGAFile6 where the CRC moved to the header and the CRC is of the compressed data.
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
class CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, SGAFile6> : public ISGADirectory
{
public:
typedef TSGAHeader SGAHeader;
typedef TSGADirectoryHeader SGADirectoryHeader;
typedef TSGASection SGASection;
typedef TSGAFolder SGAFolder;
typedef CSGAFile::SGAFile6 SGAFile;
CSGASpecializedDirectory(CSGAFile& File);
protected:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const SGADirectoryHeader *pDirectoryHeader;
const SGASection *lpSections;
const SGAFolder *lpFolders;
const SGAFile *lpFiles;
const hlChar *lpStringTable;
public:
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const;
};
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
class CSGADirectory : public CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>
{ {
public: public:
CSGADirectory(CSGAFile& File); CSGADirectory(CSGAFile& File);
virtual ~CSGADirectory(); virtual ~CSGADirectory();
private:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const TSGADirectoryHeader *pDirectoryHeader;
const TSGASection *lpSections;
const TSGAFolder *lpFolders;
const TSGAFile *lpFiles;
const hlChar *lpStringTable;
public: public:
virtual hlBool MapDataStructures(); virtual hlBool MapDataStructures();
virtual hlVoid UnmapDataStructures(); virtual hlVoid UnmapDataStructures();
@ -146,7 +261,6 @@ namespace HLLib
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const; virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) 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 GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const;
virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const;
@ -157,18 +271,23 @@ namespace HLLib
hlVoid CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex); hlVoid CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex);
}; };
typedef CSGADirectory<SGADirectoryHeader4, SGASection4, SGAFolder4, SGAFile, SGAFileHeader> CSGADirectory4; typedef CSGADirectory<SGAHeader4, SGADirectoryHeader4, SGASection4, SGAFolder4, SGAFile4> CSGADirectory4;
typedef CSGADirectory<SGADirectoryHeader5, SGASection5, SGAFolder5, SGAFile, SGAFileHeader> CSGADirectory5; typedef CSGADirectory<SGAHeader4, SGADirectoryHeader5, SGASection5, SGAFolder5, SGAFile4> CSGADirectory5;
typedef CSGADirectory<SGAHeader6, SGADirectoryHeader5, SGASection5, SGAFolder5, SGAFile6> CSGADirectory6;
typedef CSGADirectory<SGAHeader6, SGADirectoryHeader7, SGASection5, SGAFolder5, SGAFile7> CSGADirectory7;
friend CSGADirectory4; friend CSGADirectory4;
friend CSGADirectory5; friend CSGADirectory5;
friend CSGADirectory6;
friend CSGADirectory7;
private: private:
static const char *lpAttributeNames[]; static const char *lpAttributeNames[];
static const char *lpItemAttributeNames[]; static const char *lpItemAttributeNames[];
static const char *lpVerificationNames[];
Mapping::CView *pHeaderView; Mapping::CView *pHeaderView;
const SGAHeader *pHeader; const SGAHeaderBase *pHeader;
ISGADirectory* pDirectory; ISGADirectory* pDirectory;

View File

@ -547,7 +547,10 @@ hlBool CVBSPFile::GetFileValidationInternal(const CDirectoryFile *pFile, HLValid
delete pStream; delete pStream;
} }
eValidation = (hlULong)pDirectoryItem->uiCRC32 == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT; if(eValidation == HL_VALIDATES_ASSUMED_OK)
{
eValidation = (hlULong)pDirectoryItem->uiCRC32 == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT;
}
} }
else else
{ {

View File

@ -471,7 +471,10 @@ hlBool CZIPFile::GetFileValidationInternal(const CDirectoryFile *pFile, HLValida
delete pStream; delete pStream;
} }
eValidation = (hlULong)pDirectoryItem->uiCRC32 == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT; if(eValidation == HL_VALIDATES_ASSUMED_OK)
{
eValidation = (hlULong)pDirectoryItem->uiCRC32 == uiChecksum ? HL_VALIDATES_OK : HL_VALIDATES_CORRUPT;
}
return hlTrue; return hlTrue;
} }

View File

@ -65,8 +65,8 @@ typedef hlSingle hlFloat;
#define hlFalse 0 #define hlFalse 0
#define hlTrue 1 #define hlTrue 1
#define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (4 << 8) | 0) #define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (5 << 8) | 0)
#define HL_VERSION_STRING "2.4.4" #define HL_VERSION_STRING "2.4.5"
#define HL_ID_INVALID 0xffffffff #define HL_ID_INVALID 0xffffffff
@ -254,6 +254,7 @@ typedef enum
HL_SGA_ITEM_MODIFIED, HL_SGA_ITEM_MODIFIED,
HL_SGA_ITEM_TYPE, HL_SGA_ITEM_TYPE,
HL_SGA_ITEM_CRC, HL_SGA_ITEM_CRC,
HL_SGA_ITEM_VERIFICATION,
HL_SGA_ITEM_COUNT, HL_SGA_ITEM_COUNT,
HL_VBSP_PACKAGE_VERSION = 0, HL_VBSP_PACKAGE_VERSION = 0,

View File

@ -9,11 +9,11 @@ Library/Author Information:
=========================== ===========================
---- General Library Information ---- ---- General Library Information ----
Date : January 27th, 2013 Date : October 17th, 2013
Author : Ryan Gregg Author : Ryan Gregg
Michael Mohr (Linux Port) Michael Mohr (Linux Port)
Title : HLLib Title : HLLib
Build : 2.4.4 Build : 2.4.5
Email address : ryansgregg@hotmail.com (Ryan Gregg) Email address : ryansgregg@hotmail.com (Ryan Gregg)
m.mohr@laposte.net (Michael Mohr) m.mohr@laposte.net (Michael Mohr)
Home page / Website : http://nemesis.thewavelength.net/ Home page / Website : http://nemesis.thewavelength.net/
@ -93,6 +93,10 @@ Console Commands (Interactive console mode):
Library Changelog: Library Changelog:
================== ==================
v2.4.5
- Added support for new SGA file format (v6).
- Added support for new SGA file format (v7).
v2.4.4 v2.4.4
- Fixed support for VPK file format (v1). - Fixed support for VPK file format (v1).

View File

@ -65,8 +65,8 @@ typedef hlSingle hlFloat;
#define hlFalse 0 #define hlFalse 0
#define hlTrue 1 #define hlTrue 1
#define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (4 << 8) | 0) #define HL_VERSION_NUMBER ((2 << 24) | (4 << 16) | (5 << 8) | 0)
#define HL_VERSION_STRING "2.4.4" #define HL_VERSION_STRING "2.4.5"
#define HL_ID_INVALID 0xffffffff #define HL_ID_INVALID 0xffffffff
@ -258,6 +258,7 @@ typedef enum
HL_SGA_ITEM_MODIFIED, HL_SGA_ITEM_MODIFIED,
HL_SGA_ITEM_TYPE, HL_SGA_ITEM_TYPE,
HL_SGA_ITEM_CRC, HL_SGA_ITEM_CRC,
HL_SGA_ITEM_VERIFICATION,
HL_SGA_ITEM_COUNT, HL_SGA_ITEM_COUNT,
HL_VBSP_PACKAGE_VERSION = 0, HL_VBSP_PACKAGE_VERSION = 0,
@ -1884,16 +1885,20 @@ namespace HLLib
// CSGAFile // CSGAFile
// //
class HLLIB_API CSGAFile : public CPackage class HLLIB_API CSGAFile : public CPackage
{ {
private: private:
#pragma pack(1) #pragma pack(1)
struct SGAHeader struct SGAHeaderBase
{ {
hlChar lpSignature[8]; hlChar lpSignature[8];
hlUShort uiMajorVersion; hlUShort uiMajorVersion;
hlUShort uiMinorVersion; hlUShort uiMinorVersion;
};
struct SGAHeader4 : public SGAHeaderBase
{
hlByte lpFileMD5[16]; hlByte lpFileMD5[16];
hlWChar lpName[64]; hlWChar lpName[64];
hlByte lpHeaderMD5[16]; hlByte lpHeaderMD5[16];
@ -1902,6 +1907,14 @@ namespace HLLib
hlUInt uiDummy0; hlUInt uiDummy0;
}; };
struct SGAHeader6 : public SGAHeaderBase
{
hlWChar lpName[64];
hlUInt uiHeaderLength;
hlUInt uiFileDataOffset;
hlUInt uiDummy0;
};
template<typename T> template<typename T>
struct SGADirectoryHeader struct SGADirectoryHeader
{ {
@ -1918,6 +1931,12 @@ namespace HLLib
typedef SGADirectoryHeader<hlUShort> SGADirectoryHeader4; typedef SGADirectoryHeader<hlUShort> SGADirectoryHeader4;
typedef SGADirectoryHeader<hlUInt> SGADirectoryHeader5; typedef SGADirectoryHeader<hlUInt> SGADirectoryHeader5;
struct SGADirectoryHeader7 : public SGADirectoryHeader5
{
hlUInt uiHashTableOffset;
hlUInt uiBlockSize;
};
template<typename T> template<typename T>
struct SGASection struct SGASection
{ {
@ -1946,7 +1965,7 @@ namespace HLLib
typedef SGAFolder<hlUShort> SGAFolder4; typedef SGAFolder<hlUShort> SGAFolder4;
typedef SGAFolder<hlUInt> SGAFolder5; typedef SGAFolder<hlUInt> SGAFolder5;
struct SGAFile struct SGAFile4
{ {
hlUInt uiNameOffset; hlUInt uiNameOffset;
hlUInt uiOffset; hlUInt uiOffset;
@ -1957,12 +1976,32 @@ namespace HLLib
hlByte uiType; hlByte uiType;
}; };
struct SGAFile6 : public SGAFile4
{
hlUInt uiCRC32;
};
struct SGAFile7 : public SGAFile6
{
hlUInt uiHashOffset;
};
struct SGAFileHeader struct SGAFileHeader
{ {
hlChar lpName[256]; hlChar lpName[256];
hlUInt uiCRC32; hlUInt uiCRC32;
}; };
enum SGAFileVerification
{
VERIFICATION_NONE,
VERIFICATION_CRC,
VERIFICATION_CRC_BLOCKS,
VERIFICATION_MD5_BLOCKS,
VERIFICATION_SHA1_BLOCKS,
VERIFICATION_COUNT,
};
#pragma pack() #pragma pack()
class ISGADirectory class ISGADirectory
@ -1987,23 +2026,100 @@ namespace HLLib
virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const = 0; virtual hlVoid ReleaseStreamInternal(Streams::IStream &Stream) const = 0;
}; };
template<typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile, typename TSGAFileHeader> // Specialization SGAFile7 and up where the CRC moved to the header and the CRC is of the compressed data and there are stronger hashes.
class CSGADirectory : public ISGADirectory template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
class CSGASpecializedDirectory : public ISGADirectory
{
public:
typedef TSGAHeader SGAHeader;
typedef TSGADirectoryHeader SGADirectoryHeader;
typedef TSGASection SGASection;
typedef TSGAFolder SGAFolder;
typedef TSGAFile SGAFile;
CSGASpecializedDirectory(CSGAFile& File);
protected:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const SGADirectoryHeader *pDirectoryHeader;
const SGASection *lpSections;
const SGAFolder *lpFolders;
const SGAFile *lpFiles;
const hlChar *lpStringTable;
public:
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const;
};
// Specialization SGAFile4 where the CRC was stored in a SGAFileHeader located before the file data.
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
class CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, SGAFile4> : public ISGADirectory
{
public:
typedef TSGAHeader SGAHeader;
typedef TSGADirectoryHeader SGADirectoryHeader;
typedef TSGASection SGASection;
typedef TSGAFolder SGAFolder;
typedef CSGAFile::SGAFile4 SGAFile;
CSGASpecializedDirectory(CSGAFile& File);
protected:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const SGADirectoryHeader *pDirectoryHeader;
const SGASection *lpSections;
const SGAFolder *lpFolders;
const SGAFile *lpFiles;
const hlChar *lpStringTable;
public:
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const;
};
// Specialization SGAFile6 where the CRC moved to the header and the CRC is of the compressed data.
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder>
class CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, SGAFile6> : public ISGADirectory
{
public:
typedef TSGAHeader SGAHeader;
typedef TSGADirectoryHeader SGADirectoryHeader;
typedef TSGASection SGASection;
typedef TSGAFolder SGAFolder;
typedef CSGAFile::SGAFile6 SGAFile;
CSGASpecializedDirectory(CSGAFile& File);
protected:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const SGADirectoryHeader *pDirectoryHeader;
const SGASection *lpSections;
const SGAFolder *lpFolders;
const SGAFile *lpFiles;
const hlChar *lpStringTable;
public:
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileValidationInternal(const CDirectoryFile *pFile, HLValidation &eValidation) const;
};
template<typename TSGAHeader, typename TSGADirectoryHeader, typename TSGASection, typename TSGAFolder, typename TSGAFile>
class CSGADirectory : public CSGASpecializedDirectory<TSGAHeader, TSGADirectoryHeader, TSGASection, TSGAFolder, TSGAFile>
{ {
public: public:
CSGADirectory(CSGAFile& File); CSGADirectory(CSGAFile& File);
virtual ~CSGADirectory(); virtual ~CSGADirectory();
private:
CSGAFile& File;
Mapping::CView *pHeaderDirectoryView;
const TSGADirectoryHeader *pDirectoryHeader;
const TSGASection *lpSections;
const TSGAFolder *lpFolders;
const TSGAFile *lpFiles;
const hlChar *lpStringTable;
public: public:
virtual hlBool MapDataStructures(); virtual hlBool MapDataStructures();
virtual hlVoid UnmapDataStructures(); virtual hlVoid UnmapDataStructures();
@ -2013,7 +2129,6 @@ namespace HLLib
virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const; virtual hlBool GetItemAttributeInternal(const CDirectoryItem *pItem, HLPackageAttribute eAttribute, HLAttribute &Attribute) const;
virtual hlBool GetFileExtractableInternal(const CDirectoryFile *pFile, hlBool &bExtractable) 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 GetFileSizeInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const;
virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const; virtual hlBool GetFileSizeOnDiskInternal(const CDirectoryFile *pFile, hlUInt &uiSize) const;
@ -2024,18 +2139,23 @@ namespace HLLib
hlVoid CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex); hlVoid CreateFolder(CDirectoryFolder *pParent, hlUInt uiFolderIndex);
}; };
typedef CSGADirectory<SGADirectoryHeader4, SGASection4, SGAFolder4, SGAFile, SGAFileHeader> CSGADirectory4; typedef CSGADirectory<SGAHeader4, SGADirectoryHeader4, SGASection4, SGAFolder4, SGAFile4> CSGADirectory4;
typedef CSGADirectory<SGADirectoryHeader5, SGASection5, SGAFolder5, SGAFile, SGAFileHeader> CSGADirectory5; typedef CSGADirectory<SGAHeader4, SGADirectoryHeader5, SGASection5, SGAFolder5, SGAFile4> CSGADirectory5;
typedef CSGADirectory<SGAHeader6, SGADirectoryHeader5, SGASection5, SGAFolder5, SGAFile6> CSGADirectory6;
typedef CSGADirectory<SGAHeader6, SGADirectoryHeader7, SGASection5, SGAFolder5, SGAFile7> CSGADirectory7;
friend CSGADirectory4; friend CSGADirectory4;
friend CSGADirectory5; friend CSGADirectory5;
friend CSGADirectory6;
friend CSGADirectory7;
private: private:
static const char *lpAttributeNames[]; static const char *lpAttributeNames[];
static const char *lpItemAttributeNames[]; static const char *lpItemAttributeNames[];
static const char *lpVerificationNames[];
Mapping::CView *pHeaderView; Mapping::CView *pHeaderView;
const SGAHeader *pHeader; const SGAHeaderBase *pHeader;
ISGADirectory* pDirectory; ISGADirectory* pDirectory;