Last active
March 8, 2022 21:57
-
-
Save BenLubar/1f517a66f328731b291ac6acb21821b8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"bytes" | |
"encoding/binary" | |
"io" | |
"os" | |
) | |
const ( | |
ExpectedSignature = 0x55aa1234 | |
ExpectedVersion = 1 | |
) | |
type VPKHeader struct { | |
Signature uint32 | |
Version uint32 | |
TreeSize uint32 | |
} | |
type VPKDirectoryEntry struct { | |
CRC uint32 | |
PreloadBytes uint16 | |
ArchiveIndex uint16 | |
EntryOffset uint32 | |
EntryLength uint32 | |
Terminator int16 | |
} | |
type VPKDirectoryEntryInfo struct { | |
Ext string | |
Path string | |
Base string | |
Ent VPKDirectoryEntry | |
Preload []byte | |
} | |
func main() { | |
f, err := os.Open("pak01_dir.vpk") | |
if err != nil { | |
panic(err) | |
} | |
defer f.Close() | |
var header VPKHeader | |
err = binary.Read(f, binary.LittleEndian, &header) | |
if err != nil { | |
panic(err) | |
} | |
if header.Signature != ExpectedSignature { | |
panic("Invalid signature") | |
} | |
if header.Version != ExpectedVersion { | |
panic("Invalid version") | |
} | |
br := bufio.NewReader(io.LimitReader(f, int64(header.TreeSize))) | |
var entries []VPKDirectoryEntryInfo | |
nextString := func() string { | |
s, err := br.ReadString(0) | |
if err != nil { | |
panic(err) | |
} | |
return s[:len(s)-1] | |
} | |
var maxArchive uint16 | |
for { | |
ext := nextString() | |
if ext == "" { | |
break | |
} | |
for { | |
path := nextString() | |
if path == "" { | |
break | |
} | |
for { | |
base := nextString() | |
if base == "" { | |
break | |
} | |
var ent VPKDirectoryEntry | |
err = binary.Read(br, binary.LittleEndian, &ent) | |
if err != nil { | |
panic(err) | |
} | |
preload := make([]byte, ent.PreloadBytes) | |
_, err = io.ReadFull(br, preload) | |
if err != nil { | |
panic(err) | |
} | |
if ent.ArchiveIndex > maxArchive { | |
maxArchive = ent.ArchiveIndex | |
} | |
entries = append(entries, VPKDirectoryEntryInfo{ | |
Ext: ext, | |
Path: path, | |
Base: base, | |
Ent: ent, | |
Preload: preload, | |
}) | |
} | |
} | |
} | |
var directory bytes.Buffer | |
var lastExt, lastPath string | |
for _, e := range entries { | |
if e.Ent.ArchiveIndex == maxArchive { | |
continue | |
} | |
if e.Ext != lastExt { | |
if lastExt != "" { | |
directory.WriteByte(0) // end path | |
directory.WriteByte(0) // end ext | |
} | |
directory.WriteString(e.Ext) | |
directory.WriteByte(0) | |
directory.WriteString(e.Path) | |
directory.WriteByte(0) | |
lastExt = e.Ext | |
lastPath = e.Path | |
} else if e.Path != lastPath { | |
directory.WriteByte(0) | |
directory.WriteString(e.Path) | |
directory.WriteByte(0) | |
lastPath = e.Path | |
} | |
directory.WriteString(e.Base) | |
directory.WriteByte(0) | |
err = binary.Write(&directory, binary.LittleEndian, &e.Ent) | |
if err != nil { | |
panic(err) | |
} | |
directory.Write(e.Preload) | |
} | |
if lastExt != "" { | |
directory.WriteByte(0) | |
directory.WriteByte(0) | |
directory.WriteByte(0) | |
} | |
header.TreeSize = uint32(directory.Len()) | |
f1, err := os.Create("pak01_dir2.vpk") | |
if err != nil { | |
panic(err) | |
} | |
defer f1.Close() | |
err = binary.Write(f1, binary.LittleEndian, &header) | |
if err != nil { | |
panic(err) | |
} | |
_, err = f1.Write(directory.Bytes()) | |
if err != nil { | |
panic(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment