SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
PakLump.cpp
Go to the documentation of this file.
1#include <bsppp/PakLump.h>
2
3#include <filesystem>
4#include <format>
5
6#include <bsppp/BSP.h>
7#include <FileStream.h>
8#include <mz.h>
9#include <mz_zip.h>
10#include <sourcepp/FS.h>
11#include <sourcepp/String.h>
12
13using namespace bsppp;
14using namespace sourcepp;
15using namespace vpkpp;
16
17PakLump::PakLump(const std::string& fullFilePath_)
18 : ZIP(fullFilePath_)
19 , tempPakLumpPath((std::filesystem::temp_directory_path() / (string::generateUUIDv4() + ".zip")).string()) {}
20
22 // Pull this in from the ZIP dtor, have to do it before deleting the file
23 this->closeZIP();
24 std::filesystem::remove(this->tempPakLumpPath);
25}
26
27std::unique_ptr<PackFile> PakLump::open(const std::string& path, const EntryCallback& callback) {
28 if (!std::filesystem::exists(path)) {
29 // File does not exist
30 return nullptr;
31 }
32
33 auto* bsp = new PakLump{path};
34 auto packFile = std::unique_ptr<PackFile>(bsp);
35
36 {
37 bsppp::BSP reader{path};
38 if (!reader) {
39 // File failed to load, or has an invalid signature
40 return nullptr;
41 }
42
43 bsp->version = reader.getVersion();
44 bsp->mapRevision = reader.getMapRevision();
45
46 if (auto pakFileLump = reader.getLumpData(BSPLump::PAKFILE)) {
47 // Extract the paklump to a temp file
48 FileStream writer{bsp->tempPakLumpPath, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
49 writer.write(*pakFileLump);
50 } else {
51 // No paklump, create an empty zip
52 if (!ZIP::create(bsp->tempPakLumpPath)) {
53 return nullptr;
54 }
55 }
56 }
57
58 if (!bsp->openZIP(bsp->tempPakLumpPath)) {
59 return nullptr;
60 }
61
62 for (auto code = mz_zip_goto_first_entry(bsp->zipHandle); code == MZ_OK; code = mz_zip_goto_next_entry(bsp->zipHandle)) {
63 mz_zip_file* fileInfo = nullptr;
64 if (mz_zip_entry_get_info(bsp->zipHandle, &fileInfo)) {
65 return nullptr;
66 }
67 if (mz_zip_entry_is_dir(bsp->zipHandle) == MZ_OK) {
68 continue;
69 }
70
71 auto entryPath = bsp->cleanEntryPath(fileInfo->filename);
72
73 Entry entry = createNewEntry();
74 entry.flags = fileInfo->compression_method << 16;
75 entry.length = fileInfo->uncompressed_size;
76 entry.compressedLength = fileInfo->compressed_size;
77 entry.crc32 = fileInfo->crc;
78
79 bsp->entries.emplace(entryPath, entry);
80
81 if (callback) {
82 callback(entryPath, entry);
83 }
84 }
85
86 return packFile;
87}
88
89bool PakLump::bake(const std::string& outputDir_, BakeOptions options, const EntryCallback& callback) {
90 // Get the proper file output folder
91 const std::string outputDir = this->getBakeOutputDir(outputDir_);
92 const std::string outputPath = outputDir + '/' + this->getFilename();
93
94 // If the output path is different, copy the entire BSP there
95 if (outputPath != this->fullFilePath) {
96 std::filesystem::copy_file(this->fullFilePath, outputPath, std::filesystem::copy_options::overwrite_existing);
98 }
99
100 // Use temp folder so we can read from the current ZIP
101 if (!this->bakeTempZip(this->tempZIPPath, options, callback)) {
102 return false;
103 }
104 this->mergeUnbakedEntries();
105
106 // Close the ZIP
107 this->closeZIP();
108
109 // Write the new lump
110 {
111 bsppp::BSP writer{this->fullFilePath};
112 if (!writer) {
113 return false;
114 }
116 writer.bake();
117 }
118
119 // Rename and reopen the ZIP
120 std::filesystem::rename(this->tempZIPPath, this->tempPakLumpPath);
121 return this->openZIP(this->tempPakLumpPath);
122}
123
124PakLump::operator std::string() const {
125 return PackFile::operator std::string() + std::format(" | Version v{} | Map Revision {}", this->version, this->mapRevision);
126}
uint32_t getVersion() const
Definition BSP.cpp:94
bool bake(std::string_view outputPath="")
Definition BSP.cpp:365
uint32_t getMapRevision() const
Definition BSP.cpp:102
std::optional< std::vector< std::byte > > getLumpData(BSPLump lumpIndex, bool noDecompression=false) const
Definition BSP.cpp:154
bool setLump(BSPLump lumpIndex, uint32_t version, std::span< const std::byte > data, uint8_t compressLevel=0)
BSP::setGameLump should be used for writing game lumps as they need special handling.
Definition BSP.cpp:177
uint32_t version
Definition PakLump.h:32
uint32_t mapRevision
Definition PakLump.h:33
PakLump(const std::string &fullFilePath_)
Definition PakLump.cpp:17
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open a BSP file.
Definition PakLump.cpp:27
const std::string tempPakLumpPath
Definition PakLump.h:31
~PakLump() override
Definition PakLump.cpp:21
operator std::string() const override
Definition PakLump.cpp:124
This class represents the metadata that a file has inside a PackFile.
Definition Entry.h:14
uint32_t flags
Format-specific flags (PCK: File flags, VPK: Internal parser state, ZIP: Compression method / strengt...
Definition Entry.h:19
uint64_t compressedLength
If the format supports compression, this is the compressed length.
Definition Entry.h:30
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
EntryCallbackBase< void > EntryCallback
Definition PackFile.h:38
void mergeUnbakedEntries()
Definition PackFile.cpp:685
std::string fullFilePath
Definition PackFile.h:231
bool bake()
If output folder is an empty string, it will overwrite the original.
Definition PackFile.cpp:369
std::string getFilename() const
/home/user/pak01_dir.vpk -> pak01_dir.vpk
Definition PackFile.cpp:621
std::string getBakeOutputDir(const std::string &outputDir) const
Definition PackFile.cpp:670
void setFullFilePath(const std::string &outputDir)
Definition PackFile.cpp:701
static Entry createNewEntry()
Definition PackFile.cpp:715
ZIP(const std::string &fullFilePath_)
Definition ZIP.cpp:21
const std::string tempZIPPath
Definition ZIP.h:64
void closeZIP()
Definition ZIP.cpp:272
bool openZIP(std::string_view path)
Definition ZIP.cpp:254
bool bakeTempZip(const std::string &writeZipPath, BakeOptions options, const EntryCallback &callback) const
Definition ZIP.cpp:187
static std::unique_ptr< PackFile > create(const std::string &path)
Create a ZIP file.
Definition ZIP.cpp:29
Definition BSP.h:18
std::vector< std::byte > readFileBuffer(const std::filesystem::path &filepath, std::size_t startOffset=0)
Definition FS.cpp:7