/// <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 = string.Format("{0}_{1:D3}.vpk", FileName, entry.ArchiveIndex); fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); } else { fs = Reader.BaseStream; offset += OffsetAfterHeader; } fs.Seek(offset, SeekOrigin.Begin); fs.Read(output, entry.SmallData.Length, (int)entry.Length); } finally { if (entry.ArchiveIndex != 0x7FFF && fs != null) { fs.Close(); } } } if (validateCrc && entry.CRC32 != Crc32.Compute(output)) { throw new InvalidDataException("CRC32 mismatch for read data."); } }
/// <summary> /// Reads the given <see cref="Stream"/>. /// </summary> /// <param name="input">The input <see cref="Stream"/> to read from.</param> /// <returns>Returns true if this archive contains inline entries, false otherwise.</returns> public bool Read(Stream input) { if (FileName == null) { throw new InvalidOperationException("If you call Read() directly with a stream, you must call SetFileName() first."); } Reader = new BinaryReader(input); if (Reader.ReadUInt32() != Package.MAGIC) { throw new InvalidDataException("Given file is not a VPK."); } Version = Reader.ReadUInt32(); TreeSize = Reader.ReadUInt32(); if (Version == 1) { // Nothing else } else if (Version == 2) { FileDataSectionSize = Reader.ReadUInt32(); ArchiveMD5SectionSize = Reader.ReadUInt32(); OtherMD5SectionSize = Reader.ReadUInt32(); SignatureSectionSize = Reader.ReadUInt32(); } else { throw new InvalidDataException(string.Format("Bad VPK version. ({0})", Version)); } var typeEntries = new Dictionary <string, List <PackageEntry> >(); bool hasInlineEntries = false; // Types while (true) { string typeName = Reader.ReadNullTermString(Encoding.UTF8); if (typeName == "") { break; } var entries = new List <PackageEntry>(); // Directories while (true) { string directoryName = Reader.ReadNullTermString(Encoding.UTF8); if (directoryName == "") { break; } // Files while (true) { string fileName = Reader.ReadNullTermString(Encoding.UTF8); if (fileName == "") { break; } var entry = new PackageEntry(); entry.FileName = fileName; entry.DirectoryName = directoryName.Replace("/", "\\"); entry.TypeName = typeName; entry.CRC32 = Reader.ReadUInt32(); entry.SmallData = new byte[Reader.ReadUInt16()]; entry.ArchiveIndex = Reader.ReadUInt16(); entry.Offset = Reader.ReadUInt32(); entry.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); } if (entry.ArchiveIndex == 0x7FFF) { hasInlineEntries = true; } entries.Add(entry); } } typeEntries.Add(typeName, entries); } Entries = typeEntries; OffsetAfterHeader = (uint)Reader.BaseStream.Position; return(hasInlineEntries); }
/// <summary> /// Reads the given <see cref="Stream"/>. /// </summary> /// <param name="input">The input <see cref="Stream"/> to read from.</param> /// <returns>Returns true if this archive contains inline entries, false otherwise.</returns> public bool Read(Stream input) { if (FileName == null) { throw new InvalidOperationException("If you call Read() directly with a stream, you must call SetFileName() first."); } Reader = new BinaryReader(input); if (Reader.ReadUInt32() != Package.MAGIC) { throw new InvalidDataException("Given file is not a VPK."); } Version = Reader.ReadUInt32(); TreeSize = Reader.ReadUInt32(); if (Version == 1) { // Nothing else } else if (Version == 2) { FileDataSectionSize = Reader.ReadUInt32(); ArchiveMD5SectionSize = Reader.ReadUInt32(); OtherMD5SectionSize = Reader.ReadUInt32(); SignatureSectionSize = Reader.ReadUInt32(); } else { throw new InvalidDataException(string.Format("Bad VPK version. ({0})", Version)); } var typeEntries = new Dictionary<string, List<PackageEntry>>(); bool hasInlineEntries = false; // Types while (true) { string typeName = Reader.ReadNullTermString(Encoding.UTF8); if (typeName == "") { break; } var entries = new List<PackageEntry>(); // Directories while (true) { string directoryName = Reader.ReadNullTermString(Encoding.UTF8); if (directoryName == "") { break; } // Files while (true) { string fileName = Reader.ReadNullTermString(Encoding.UTF8); if (fileName == "") { break; } var entry = new PackageEntry(); entry.FileName = fileName; entry.DirectoryName = directoryName.Replace("/", "\\"); entry.TypeName = typeName; entry.CRC32 = Reader.ReadUInt32(); entry.SmallData = new byte[Reader.ReadUInt16()]; entry.ArchiveIndex = Reader.ReadUInt16(); entry.Offset = Reader.ReadUInt32(); entry.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); } if (entry.ArchiveIndex == 0x7FFF) { hasInlineEntries = true; } entries.Add(entry); } } typeEntries.Add(typeName, entries); } Entries = typeEntries; OffsetAfterHeader = (uint)Reader.BaseStream.Position; return hasInlineEntries; }
private void ReadEntries() { var typeEntries = new Dictionary <string, List <PackageEntry> >(); // Types while (true) { var typeName = Reader.ReadNullTermString(Encoding.UTF8); if (typeName == string.Empty) { break; } var entries = new List <PackageEntry>(); // Directories while (true) { var directoryName = Reader.ReadNullTermString(Encoding.UTF8); if (directoryName == string.Empty) { break; } // Files while (true) { var fileName = Reader.ReadNullTermString(Encoding.UTF8); if (fileName == string.Empty) { break; } var entry = new PackageEntry(); entry.FileName = fileName; entry.DirectoryName = directoryName.Replace("/", "\\"); entry.TypeName = typeName; entry.CRC32 = Reader.ReadUInt32(); entry.SmallData = new byte[Reader.ReadUInt16()]; entry.ArchiveIndex = Reader.ReadUInt16(); entry.Offset = Reader.ReadUInt32(); entry.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 == 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; }
/// <summary> /// Adds a node to the tree based on the passed file information. This is useful when building a directory-based tree. /// </summary> /// <param name="file"></param> /// <param name="fileType"></param> public void AddFileNode(PackageEntry file, KeyValuePair<string, List<PackageEntry>> fileType) { TreeNode currentNode = null; string fileName = String.Format("{0}.{1}", file.FileName, fileType.Key); string path = Path.Combine(file.DirectoryName, fileName); string[] subPaths = path.Split(Path.DirectorySeparatorChar); foreach (string subPath in subPaths) { if (currentNode == null) //Root directory { if (subPath == " ") { continue; //root files } if (null == this.Nodes[subPath]) { currentNode = this.Nodes.Add(subPath, subPath); } else { currentNode = this.Nodes[subPath]; } } else //Not root directory { if (null == currentNode.Nodes[subPath]) { currentNode = currentNode.Nodes.Add(subPath, subPath); } else { currentNode = currentNode.Nodes[subPath]; } } var ext = Path.GetExtension(currentNode.Name); if (ext.Length == 0) { ext = "_folder"; currentNode.Tag = new Controls.TreeViewFolder(file.DirectoryName, currentNode.Nodes.Count + 1); //is this enough? } else { currentNode.Tag = file; //so we can use it later ext = ext.Substring(1); if (ext.EndsWith("_c", StringComparison.Ordinal)) { ext = ext.Substring(0, ext.Length - 2); } if (!ImageList.Images.ContainsKey(ext)) { if (ext[0] == 'v') { ext = ext.Substring(1); if (!ImageList.Images.ContainsKey(ext)) { ext = "_default"; } } else { ext = "_default"; } } } currentNode.ImageKey = ext; currentNode.SelectedImageKey = ext; } }