-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathparser_pak.go
More file actions
112 lines (87 loc) · 2.6 KB
/
parser_pak.go
File metadata and controls
112 lines (87 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package parser
import (
"encoding/binary"
)
func (parser *PakParser) Parse() (*PakFile, error) {
// Find magic number
magicOffset := int64(-44)
for {
_, err := parser.Seek(magicOffset, 2)
if err != nil {
return nil, err
}
magicArray := parser.Read(4)
if magicArray[0] == 0xE1 && magicArray[1] == 0x12 && magicArray[2] == 0x6F && magicArray[3] == 0x5A {
break
}
magicOffset -= 1
if magicOffset < -1024 {
panic("Could not find magic bytes in pak!")
}
}
// Seek and read the footer of the file
_, err := parser.Seek(magicOffset, 2)
if err != nil {
return nil, err
}
footer := parser.Read(int32(magicOffset * -1))
pakFooter := &FPakInfo{
Magic: binary.LittleEndian.Uint32(footer[0:4]),
Version: binary.LittleEndian.Uint32(footer[4:8]),
IndexOffset: binary.LittleEndian.Uint64(footer[8:16]),
IndexSize: binary.LittleEndian.Uint64(footer[16:24]),
IndexSHA1Hash: footer[24:44],
}
// Seek and read the index of the file
_, err = parser.Seek(int64(pakFooter.IndexOffset), 0)
if err != nil {
return nil, err
}
mountPoint := parser.ReadString()
recordCount := parser.ReadUint32()
pakIndex := &FPakIndex{
MountPoint: mountPoint,
Records: make([]*FPakEntry, recordCount),
}
for i := 0; i < len(pakIndex.Records); i++ {
pakIndex.Records[i] = &FPakEntry{}
pakIndex.Records[i].FileName = parser.ReadString()
pakIndex.Records[i].FileOffset = parser.ReadUint64()
pakIndex.Records[i].FileSize = parser.ReadUint64()
pakIndex.Records[i].UncompressedSize = parser.ReadUint64()
if pakFooter.Version >= 8 {
pakIndex.Records[i].CompressionMethod = uint32(parser.Read(1)[0])
} else {
pakIndex.Records[i].CompressionMethod = parser.ReadUint32()
}
if pakFooter.Version <= 1 {
pakIndex.Records[i].Timestamp = parser.ReadUint64()
}
pakIndex.Records[i].DataSHA1Hash = parser.Read(20)
if pakFooter.Version >= 3 {
if pakIndex.Records[i].CompressionMethod != 0 {
blockCount := parser.ReadUint32()
pakIndex.Records[i].CompressionBlocks = make([]*FPakCompressedBlock, blockCount)
for j := 0; j < len(pakIndex.Records[i].CompressionBlocks); j++ {
pakIndex.Records[i].CompressionBlocks[j] = &FPakCompressedBlock{
StartOffset: parser.ReadUint64(),
EndOffset: parser.ReadUint64(),
}
}
}
pakIndex.Records[i].IsEncrypted = parser.Read(1)[0] > 0
pakIndex.Records[i].CompressionBlockSize = parser.ReadUint32()
}
if pakFooter.Version == 4 {
// TODO ???
}
if pakFooter.Version >= 9 {
// TODO Unknown bytes
parser.Read(3)
}
}
return &PakFile{
Footer: pakFooter,
Index: pakIndex,
}, nil
}