/// <summary> /// Reads the entry from the VPK package. /// </summary> /// <param name="entry">Package entry.</param> /// <param name="output">Output buffer.</param> /// <param name="validateCrc">If true, CRC32 will be calculated and verified for read data.</param> public void ReadEntry(PackageEntry entry, out byte[] output, bool validateCrc = true) { output = new byte[entry.SmallData.Length + entry.Length]; if (entry.SmallData.Length > 0) { entry.SmallData.CopyTo(output, 0); } if (entry.Length > 0) { Stream fs = null; try { var offset = entry.Offset; if (entry.ArchiveIndex != 0x7FFF) { if (!IsDirVPK) { throw new InvalidOperationException("Given VPK is not a _dir, but entry is referencing an external archive."); } var fileName = $"{FileName}_{entry.ArchiveIndex:D3}.vpk"; fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); } else { fs = Reader.BaseStream; offset += HeaderSize + TreeSize; } fs.Seek(offset, SeekOrigin.Begin); fs.Read(output, entry.SmallData.Length, (int)entry.Length); } finally { if (entry.ArchiveIndex != 0x7FFF) { fs?.Close(); } } } if (validateCrc && entry.CRC32 != Crc32.Compute(output)) { throw new InvalidDataException("CRC32 mismatch for read data."); } }
private void ReadEntries() { var typeEntries = new Dictionary <string, List <PackageEntry> >(); // Types while (true) { var typeName = Reader.ReadNullTermString(Encoding.UTF8); if (typeName == string.Empty) { break; } // Valve uses a space for missing extensions, // we replace it with an empty string to match how System.IO.Path deals with it. if (typeName == " ") { typeName = string.Empty; } var entries = new List <PackageEntry>(); // Directories while (true) { var directoryName = Reader.ReadNullTermString(Encoding.UTF8); if (directoryName == string.Empty) { break; } // Valve uses a space for blank directory names, // we replace it with a null to match how System.IO.Path deals with root paths. if (directoryName == " ") { directoryName = null; } // Files while (true) { var fileName = Reader.ReadNullTermString(Encoding.UTF8); if (fileName == string.Empty) { break; } var entry = new PackageEntry { FileName = fileName, DirectoryName = directoryName, TypeName = typeName, CRC32 = Reader.ReadUInt32(), SmallData = new byte[Reader.ReadUInt16()], ArchiveIndex = Reader.ReadUInt16(), Offset = Reader.ReadUInt32(), Length = Reader.ReadUInt32() }; if (Reader.ReadUInt16() != 0xFFFF) { throw new FormatException("Invalid terminator."); } if (entry.SmallData.Length > 0) { Reader.Read(entry.SmallData, 0, entry.SmallData.Length); } entries.Add(entry); } } typeEntries.Add(typeName, entries); } Entries = typeEntries; }
private void ReadEntries() { var typeEntries = new Dictionary <string, List <PackageEntry> >(); // Types while (true) { var typeName = Reader.ReadNullTermString(Encoding.UTF8); if (typeName?.Length == 0) { break; } var entries = new List <PackageEntry>(); // Directories while (true) { var directoryName = Reader.ReadNullTermString(Encoding.UTF8); if (directoryName?.Length == 0) { break; } // Files while (true) { var fileName = Reader.ReadNullTermString(Encoding.UTF8); if (fileName?.Length == 0) { break; } var entry = new PackageEntry { FileName = fileName, DirectoryName = directoryName, TypeName = typeName, CRC32 = Reader.ReadUInt32(), SmallData = new byte[Reader.ReadUInt16()], ArchiveIndex = Reader.ReadUInt16(), Offset = Reader.ReadUInt32(), Length = Reader.ReadUInt32() }; if (Reader.ReadUInt16() != 0xFFFF) { throw new FormatException("Invalid terminator."); } if (entry.SmallData.Length > 0) { Reader.Read(entry.SmallData, 0, entry.SmallData.Length); } entries.Add(entry); } } typeEntries.Add(typeName, entries); } Entries = typeEntries; }