private void parsePak(PakFormat pakFormat, bool debugFile)
{
_debugFile = debugFile;
_pakFormat = pakFormat;
_pakFilename = (!_debugFile ? _pakFormat.FullPakFilename : _pakFormat.FullDebugFilename);
Dictionary <uint, PakDbgQbKey> qbKeyFilenames = new Dictionary <uint, PakDbgQbKey>();
//if PC or xbox then we need to look up the filename from the debug file
//create a PakEditor and load the debug pak, then load all internal debug files, add the first line to our filenames dictionary
if (!debugFile) // && (_pakFormat.PakFormatType == PakFormatType.PC || _pakFormat.PakFormatType == PakFormatType.XBox))
{
try
{
_pakFormat.Decompress();
_pakFilename = _pakFormat.FullPakFilename;
}
catch (Exception ex)
{
throw new Exception("Decompression Error", ex);
}
if (_pakFormat.DebugFileExists && _debugFile) // cancer
{
string debugFileContents;
string filename;
uint crc;
PakEditor pakDebug = new PakEditor(new PakFormat(_pakFormat.FullDebugFilename, "", _pakFormat.FullDebugFilename, _pakFormat.PakFormatType), true);
foreach (PakHeaderItem dphi in pakDebug.Headers.Values)
{
debugFileContents = string.Empty;
filename = string.Empty;
crc = 0;
if (dphi.FullFilenameQbKey != 0)
{
crc = dphi.FullFilenameQbKey;
}
else if (dphi.PakFullFileNameQbKey != 0)
{
crc = dphi.PakFullFileNameQbKey;
}
else if (dphi.NameOnlyCrc != 0)
{
crc = dphi.NameOnlyCrc;
}
if (crc != 0)
{
filename = crc.ToString("X").PadLeft(8, '0');
if (pakDebug.Headers.ContainsKey(filename.ToLower()))
{
debugFileContents = pakDebug.ExtractFileToString(filename);
if (debugFileContents.Length != 0)
{
addDebugFilename(debugFileContents, qbKeyFilenames, crc);
}
}
}
}
}
}
long minOffset = uint.MaxValue;
long maxOffset = 0;
_pakHeaders = new Dictionary <string, PakHeaderItem>();
using (Stream st = File.Open(_pakFilename, FileMode.Open, FileAccess.Read))
{
_pakFileLength = st.Length;
using (BinaryEndianReader br = new BinaryEndianReader(st))
{
PakHeaderItem phi = null;
QbKey lastQbKey = QbKey.Create("last");
QbKey dotLastQbKey = QbKey.Create(".last");
do
{
phi = new PakHeaderItem();
phi.HeaderStart = (uint)st.Position;
phi.IsStoredInPak = true;
phi.FileType = QbKey.Create(br.ReadUInt32(_pakFormat.EndianType));
//if the entry has the file type of last then we're done
if (phi.FileType == lastQbKey || phi.FileType == dotLastQbKey)
{
break;
}
phi.FileOffset = br.ReadUInt32(_pakFormat.EndianType);
phi.FileLength = br.ReadUInt32(_pakFormat.EndianType);
phi.PakFullFileNameQbKey = br.ReadUInt32(_pakFormat.EndianType);
phi.FullFilenameQbKey = br.ReadUInt32(_pakFormat.EndianType);
phi.NameOnlyCrc = br.ReadUInt32(_pakFormat.EndianType);
phi.Unknown = br.ReadUInt32(_pakFormat.EndianType);
phi.Flags = (PakHeaderFlags)br.ReadUInt32(_pakFormat.EndianType);
if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename)
{
uint crc = 0;
//get any Crc
if (phi.FullFilenameQbKey != 0)
{
crc = phi.FullFilenameQbKey;
}
else if (phi.PakFullFileNameQbKey != 0)
{
crc = phi.PakFullFileNameQbKey;
}
else if (phi.NameOnlyCrc != 0)
{
crc = phi.NameOnlyCrc;
}
if (!debugFile)
{
uint crc2 = 0;
//get a crc that exists in the debug names
if (qbKeyFilenames.ContainsKey(phi.FullFilenameQbKey))
{
crc2 = phi.FullFilenameQbKey;
}
else if (qbKeyFilenames.ContainsKey(phi.PakFullFileNameQbKey))
{
crc2 = phi.PakFullFileNameQbKey;
}
else if (qbKeyFilenames.ContainsKey(phi.NameOnlyCrc))
{
crc2 = phi.NameOnlyCrc;
}
//if 0 then get any crc
if (crc2 != 0)
{
phi.Filename = qbKeyFilenames[crc2].Filename;
phi.DebugQbKey = qbKeyFilenames[crc2].DebugQbKey;
crc = crc2;
}
}
if (phi.Filename == null)
{
if (crc != 0)
{
phi.Filename = crc.ToString("X").PadLeft(8, '0');
}
else
{
phi.Filename = string.Format("Unknown={0}", phi.HeaderStart.ToString("X").PadLeft(8, '0'));
}
}
}
else
{
phi.Filename = UTF8Encoding.UTF8.GetString(br.ReadBytes(PakHeaderItem.FileNameMaxLength)).TrimEnd(new char[] { '\0' });
}
try
{
_pakHeaders.Add(phi.Filename.ToLower(), phi);
}
catch (Exception ex)
{
throw new ApplicationException(string.Format("Error adding '{0}' to headers: {1}", phi.Filename, ex.Message));
}
if (phi.HeaderStart + phi.FileOffset < minOffset)
{
minOffset = phi.HeaderStart + phi.FileOffset;
}
if (phi.HeaderStart + phi.FileOffset > maxOffset)
{
maxOffset = phi.HeaderStart + phi.FileOffset;
}
}while (1 == 1); //minOffset > fs.Position + 0x100); //drop out if we reach the data
//this is a simple hack/fix to cater for padding on PAK files,
//it relies on the data starting at the top of the PAB file (which it always does, currently)
_requiresPab = maxOffset >= st.Length;
if (!debugFile) //only when loading pak
{
_pakFormat.PakPabMinDataOffset = minOffset; //remember this value
}
//detect GH5 PAB files
if (_requiresPab)
{
foreach (PakHeaderItem ph in _pakHeaders.Values)
{
ph.FileOffset += (uint)(_pakFileLength - _pakFormat.PakPabMinDataOffset) - (_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0); //gh5 doesn't hold the offset in relation to the data.
}
minOffset = _pakFileLength;
}
}
}
_qbFilenames = new string[_pakHeaders.Count];
int i = 0;
foreach (PakHeaderItem hi in _pakHeaders.Values)
{
_qbFilenames[i++] = hi.Filename;
}
StructItemChildrenType s;
if (!debugFile)
{
s = this.StructItemChildrenType; //auto detect the structitemchildren type
}
}