SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
FPX.cpp
Go to the documentation of this file.
1#include <vpkpp/format/FPX.h>
2
3#include <filesystem>
4#include <FileStream.h>
5#include <sourcepp/String.h>
6
7using namespace sourcepp;
8using namespace vpkpp;
9
10std::unique_ptr<PackFile> FPX::create(const std::string& path) {
11 {
12 FileStream stream{path, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
13
16 header1.version = 10;
17 header1.treeSize = 1;
18 stream.write(header1);
19
20 stream.write('\0');
21 }
22 return FPX::open(path);
23}
24
25std::unique_ptr<PackFile> FPX::open(const std::string& path, const EntryCallback& callback) {
26 std::unique_ptr<PackFile> fpx;
27
28 // Try loading the directory FPX first if this is a numbered archive and the dir exists
29 if (path.length() >= 8) {
30 auto dirPath = path.substr(0, path.length() - 8) + "_fdr.fpx";
31 auto pathEnd = path.substr(path.length() - 8, path.length());
32 if (string::matches(pathEnd, "_%d%d%d.fpx") && std::filesystem::exists(dirPath)) {
33 fpx = FPX::openInternal(dirPath, callback);
34 if (fpx) {
35 return fpx;
36 }
37 }
38 }
39
40 return FPX::openInternal(path, callback);
41}
42
43std::unique_ptr<PackFile> FPX::openInternal(const std::string& path, const EntryCallback& callback) {
44 if (!std::filesystem::exists(path)) {
45 // File does not exist
46 return nullptr;
47 }
48
49 auto* fpx = new FPX{path};
50 auto packFile = std::unique_ptr<PackFile>(fpx);
51
52 FileStream reader{fpx->fullFilePath};
53 reader.seek_in(0);
54 reader.read(fpx->header1);
55 if (fpx->header1.signature != FPX_SIGNATURE) {
56 // File is not an FPX
57 return nullptr;
58 }
59 if (fpx->header1.version != 10) {
60 // Only support v10 FPX files
61 return nullptr;
62 }
63
64 // Extensions
65 while (true) {
66 std::string extension;
67 reader.read(extension);
68 if (extension.empty())
69 break;
70
71 // Directories
72 while (true) {
73 std::string directory;
74 reader.read(directory);
75 if (directory.empty())
76 break;
77
78 std::string fullDir;
79 if (directory == " ") {
80 fullDir = "";
81 } else {
82 fullDir = directory;
83 }
84
85 // Files
86 while (true) {
87 std::string entryName;
88 reader.read(entryName);
89 if (entryName.empty())
90 break;
91
92 Entry entry = createNewEntry();
93
94 std::string entryPath;
95 if (extension == " ") {
96 entryPath = fullDir.empty() ? "" : fullDir + '/';
97 entryPath += entryName;
98 } else {
99 entryPath = fullDir.empty() ? "" : fullDir + '/';
100 entryPath += entryName + '.';
101 entryPath += extension;
102 }
103 entryPath = fpx->cleanEntryPath(entryPath);
104
105 reader.read(entry.crc32);
106 auto preloadedDataSize = reader.read<uint16_t>();
107 entry.archiveIndex = reader.read<uint16_t>();
108 entry.offset = reader.read<uint32_t>();
109 entry.length = reader.read<uint32_t>();
110
111 if (reader.read<uint16_t>() != VPK_ENTRY_TERM) {
112 // Invalid terminator!
113 return nullptr;
114 }
115
116 if (preloadedDataSize > 0) {
117 entry.extraData = reader.read_bytes(preloadedDataSize);
118 entry.length += preloadedDataSize;
119 }
120
121 if (entry.archiveIndex != VPK_DIR_INDEX && entry.archiveIndex > fpx->numArchives) {
122 fpx->numArchives = entry.archiveIndex;
123 }
124
125 fpx->entries.emplace(entryPath, entry);
126
127 if (callback) {
128 callback(entryPath, entry);
129 }
130 }
131 }
132 }
133
134 // If there are no archives, -1 will be incremented to 0
135 fpx->numArchives++;
136
137 return packFile;
138}
This class represents the metadata that a file has inside a PackFile.
Definition: Entry.h:14
uint64_t offset
Offset, format-specific meaning - 0 if unused, or if the offset genuinely is 0.
Definition: Entry.h:33
uint32_t archiveIndex
Which external archive this entry is in.
Definition: Entry.h:23
uint32_t crc32
CRC32 checksum - 0 if unused.
Definition: Entry.h:40
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length)
Definition: Entry.h:26
std::vector< std::byte > extraData
Format-specific (PCK: MD5 hash, VPK: Preloaded data)
Definition: Entry.h:36
Definition: FPX.h:11
static std::unique_ptr< PackFile > openInternal(const std::string &path, const EntryCallback &callback=nullptr)
Definition: FPX.cpp:43
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open an FPX file.
Definition: FPX.cpp:25
static std::unique_ptr< PackFile > create(const std::string &path)
Create a new directory FPX file - should end in "_dir.fpx"! This is not enforced but STRONGLY recomme...
Definition: FPX.cpp:10
EntryCallbackBase< void > EntryCallback
Definition: PackFile.h:30
static Entry createNewEntry()
Definition: PackFile.cpp:686
Header1 header1
Definition: VPK.h:149
bool matches(std::string_view in, std::string_view search)
A very basic regex-like pattern checker for ASCII strings.
Definition: String.cpp:24
Definition: LZMA.h:11
Definition: Attribute.h:5
constexpr uint16_t VPK_ENTRY_TERM
Definition: VPK.h:11
constexpr uint32_t FPX_SIGNATURE
Definition: FPX.h:7
constexpr uint16_t VPK_DIR_INDEX
Definition: VPK.h:10
uint32_t treeSize
Definition: VPK.h:30
uint32_t signature
Definition: VPK.h:28
uint32_t version
Definition: VPK.h:29