Skip to content

Commit 9207b98

Browse files
committed
Update README.md
1 parent 26bc599 commit 9207b98

File tree

1 file changed

+124
-7
lines changed

1 file changed

+124
-7
lines changed

README.md

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
<h1><img src="./Misc/logo.png" width="64" align="center"> Valve Pak (vpk) for .NET</h1>
1+
<h1 align="center"><img src="./Misc/logo.png" width="64" height="64" align="center"> Valve Pak for .NET</h1>
22

3-
[![Build Status (GitHub)](https://img.shields.io/github/actions/workflow/status/ValveResourceFormat/ValvePak/ci.yml?label=Build&style=flat-square&branch=master)](https://github.com/ValveResourceFormat/ValvePak/actions)
4-
[![NuGet](https://img.shields.io/nuget/v/ValvePak.svg?label=NuGet&style=flat-square)](https://www.nuget.org/packages/ValvePak/)
5-
[![Coverage Status](https://img.shields.io/codecov/c/github/ValveResourceFormat/ValvePak/master?label=Coverage&style=flat-square)](https://app.codecov.io/gh/ValveResourceFormat/ValvePak)
3+
<p align="center">
4+
<a href="https://github.com/ValveResourceFormat/ValvePak/actions" title="Build Status"><img alt="Build Status" src="https://img.shields.io/github/actions/workflow/status/ValveResourceFormat/ValvePak/ci.yml?logo=github&label=Build&logoColor=ffffff&style=for-the-badge&branch=master"></a>
5+
<a href="https://www.nuget.org/packages/ValvePak/" title="NuGet"><img alt="NuGet" src="https://img.shields.io/nuget/v/ValvePak.svg?logo=nuget&label=NuGet&logoColor=ffffff&color=004880&style=for-the-badge"></a>
6+
<a href="https://app.codecov.io/gh/ValveResourceFormat/ValvePak" title="Code Coverage"><img alt="Code Coverage" src="https://img.shields.io/codecov/c/github/ValveResourceFormat/ValvePak/master?logo=codecov&label=Coverage&logoColor=ffffff&color=F01F7A&style=for-the-badge"></a>
7+
</p>
68

7-
VPK (Valve Pak) files are uncompressed archives used to package game content.
8-
This library allows you to read and extract files out of these paks.
9+
A .NET library for reading and extracting VPK (Valve Pak) files, the uncompressed archive format used to package game content in Source and Source 2 engine games.
910

10-
Usage:
11+
## Usage
1112

1213
```csharp
1314
using var package = new Package();
@@ -27,7 +28,123 @@ var file = package.FindEntry("path/to/file.txt");
2728
if (file != null) {
2829
// Read a file to a byte array
2930
package.ReadEntry(file, out byte[] fileContents);
31+
32+
// Inspect entry metadata
33+
Console.WriteLine(file.GetFullPath()); // "path/to/file.txt"
34+
Console.WriteLine(file.GetFileName()); // "file.txt"
35+
Console.WriteLine(file.TotalLength); // file size in bytes
36+
Console.WriteLine(file.CRC32); // CRC32 checksum
3037
}
3138
```
3239

3340
Do note that files such as `pak01_001.vpk` are just data files, you have to open `pak01_dir.vpk`.
41+
42+
## Extract all files
43+
44+
```csharp
45+
using var package = new Package();
46+
package.Read("pak01_dir.vpk");
47+
48+
foreach (var group in package.Entries)
49+
{
50+
foreach (var entry in group.Value)
51+
{
52+
var filePath = entry.GetFullPath();
53+
54+
package.ReadEntry(entry, out byte[] data);
55+
56+
// Create the directory if needed, then write the file
57+
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
58+
File.WriteAllBytes(filePath, data);
59+
}
60+
}
61+
```
62+
63+
## Create a VPK
64+
65+
```csharp
66+
using var package = new Package();
67+
68+
// Add files to the package
69+
package.AddFile("path/to/file.txt", File.ReadAllBytes("file.txt"));
70+
package.AddFile("models/example.vmdl", File.ReadAllBytes("example.vmdl"));
71+
72+
// Remove a file from the package
73+
package.RemoveFile(package.FindEntry("path/to/file.txt"));
74+
75+
// Write the package to disk
76+
package.Write("pak01_dir.vpk");
77+
```
78+
79+
## Optimize for many lookups
80+
81+
By default, `FindEntry` performs a linear scan. If you need to look up many files, call `OptimizeEntriesForBinarySearch()` before `Read()` to sort entries and use binary search instead. You can also pass `StringComparison.OrdinalIgnoreCase` for case-insensitive lookups.
82+
83+
```csharp
84+
using var package = new Package();
85+
86+
// Call before Read() to enable binary search for FindEntry
87+
package.OptimizeEntriesForBinarySearch();
88+
package.Read("pak01_dir.vpk");
89+
90+
// FindEntry calls are now significantly faster
91+
var file = package.FindEntry("path/to/file.txt");
92+
```
93+
94+
## Read into a user-provided buffer
95+
96+
```csharp
97+
var entry = package.FindEntry("path/to/file.txt");
98+
99+
// Allocate your own buffer (must be at least entry.TotalLength bytes)
100+
var buffer = new byte[entry.TotalLength];
101+
package.ReadEntry(entry, buffer, validateCrc: true);
102+
```
103+
104+
Using `ArrayPool` to avoid allocations when reading many files:
105+
106+
```csharp
107+
var entry = package.FindEntry("path/to/file.txt");
108+
109+
var buffer = ArrayPool<byte>.Shared.Rent((int)entry.TotalLength);
110+
111+
try
112+
{
113+
package.ReadEntry(entry, buffer, validateCrc: true);
114+
115+
// Use buffer[..entry.TotalLength] here
116+
}
117+
finally
118+
{
119+
ArrayPool<byte>.Shared.Return(buffer);
120+
}
121+
```
122+
123+
## Stream-based access
124+
125+
`GetMemoryMappedStreamIfPossible` returns a memory-mapped stream for large files (over 4 KiB) and a `MemoryStream` for smaller ones. This avoids reading the entire file into a byte array.
126+
127+
```csharp
128+
var entry = package.FindEntry("path/to/file.txt");
129+
130+
using var stream = package.GetMemoryMappedStreamIfPossible(entry);
131+
```
132+
133+
## Verification
134+
135+
```csharp
136+
using var package = new Package();
137+
package.Read("pak01_dir.vpk");
138+
139+
// Verify MD5 hashes of the directory tree and whole file
140+
package.VerifyHashes();
141+
142+
// Verify MD5/Blake3 hashes of individual chunk files (pak01_000.vpk, pak01_001.vpk, ...)
143+
package.VerifyChunkHashes();
144+
145+
// Verify CRC32 checksums of every file in the package
146+
package.VerifyFileChecksums();
147+
148+
// Verify the RSA signature if the package is signed
149+
bool valid = package.IsSignatureValid();
150+
```

0 commit comments

Comments
 (0)