SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
TTX.cpp
Go to the documentation of this file.
1#include <vtfpp/TTX.h>
2
3#include <BufferStream.h>
4#include <miniz.h>
5#include <sourcepp/FS.h>
6
7using namespace sourcepp;
8using namespace vtfpp;
9
11 : vtf(std::move(vtf_))
12 , aspectRatioType(3) {
13 this->mipFlags.resize(this->vtf.getMipCount());
14
15 this->opened = true;
16}
17
18TTX::TTX(std::span<const std::byte> tthData, std::span<const std::byte> ttzData) {
19 BufferStreamReadOnly header{tthData.data(), tthData.size()};
20
21 if (header.read<uint32_t>() != TTH_SIGNATURE) {
22 return;
23 }
24
25 header >> this->majorVersion >> this->minorVersion;
26 if (this->majorVersion != 1 || this->minorVersion != 0) {
27 return;
28 }
29
30 const auto mipCount = header.read<uint8_t>();
31 header >> this->aspectRatioType;
32 const auto vtfChunkSize = header.read<uint32_t>();
33 if (mipCount > 0) {
34 header.read(this->mipFlags, mipCount);
35 }
36 mz_ulong ttzUncompressedSize = header.read<uint32_t>() - vtfChunkSize;
37 const mz_ulong ttzCompressedSize = header.read<uint32_t>();
38
39 std::vector<std::byte> vtfData;
40 BufferStream vtfStream{vtfData};
41 vtfStream << header.read_bytes(vtfChunkSize);
42 if (ttzCompressedSize > 0) {
43 if (ttzCompressedSize > ttzData.size()) {
44 return;
45 }
46 std::vector<std::byte> additionalDataUncompressed(ttzUncompressedSize);
47 if (mz_uncompress(reinterpret_cast<unsigned char*>(additionalDataUncompressed.data()), &ttzUncompressedSize, reinterpret_cast<const unsigned char*>(ttzData.data()), ttzCompressedSize) != MZ_OK) {
48 return;
49 }
50 vtfStream << additionalDataUncompressed;
51 }
52 vtfData.resize(vtfStream.size());
53 this->vtf = VTF{vtfData};
54 if (!this->vtf) {
55 return;
56 }
57
58 this->opened = true;
59}
60
61TTX::TTX(const std::string& tthPath, const std::string& ttzPath)
62 : TTX(fs::readFileBuffer(tthPath), fs::readFileBuffer(ttzPath)) {}
63
64TTX::operator bool() const {
65 return this->opened;
66}
67
68uint8_t TTX::getMajorVersion() const {
69 return this->majorVersion;
70}
71
72uint8_t TTX::getMinorVersion() const {
73 return this->minorVersion;
74}
75
76void TTX::setVersion(uint8_t newMajorVersion, uint8_t newMinorVersion) {
77 this->majorVersion = newMajorVersion;
78 this->minorVersion = newMinorVersion;
79}
80
81void TTX::setMajorVersion(uint8_t newMajorVersion) {
82 this->majorVersion = newMajorVersion;
83}
84
85void TTX::setMinorVersion(uint8_t newMinorVersion) {
86 this->minorVersion = newMinorVersion;
87}
88
89uint8_t TTX::getAspectRatioType() const {
90 return this->aspectRatioType;
91}
92
93void TTX::setAspectRatioType(uint8_t newAspectRatioType) {
94 this->aspectRatioType = newAspectRatioType;
95}
96
97const std::vector<uint64_t>& TTX::getMipFlags() const {
98 return this->mipFlags;
99}
100
101std::vector<uint64_t>& TTX::getMipFlags() {
102 return this->mipFlags;
103}
104
105const VTF& TTX::getVTF() const {
106 return this->vtf;
107}
108
110 return this->vtf;
111}
112
114 return this->compressionLevel;
115}
116
117void TTX::setCompressionLevel(int16_t newCompressionLevel) {
118 this->compressionLevel = newCompressionLevel;
119}
120
121std::pair<std::vector<std::byte>, std::vector<std::byte>> TTX::bake() const {
122 std::pair<std::vector<std::byte>, std::vector<std::byte>> data;
123 BufferStream streamTTH{data.first};
124
125 // TTH
126 streamTTH
128 << this->majorVersion
129 << this->minorVersion
130 << static_cast<uint8_t>(this->mipFlags.size())
131 << this->aspectRatioType;
132
133 // VTF data
134 const auto vtfData = this->vtf.bake();
135 if (vtfData.empty()) {
136 return {};
137 }
138 uint32_t vtfChunkLength;
139 {
140 BufferStreamReadOnly streamVTF{vtfData.data(), vtfData.size()};
141 vtfChunkLength = streamVTF.skip<uint32_t>(3).read<uint32_t>();
142 if (this->vtf.hasThumbnailData()) {
143 vtfChunkLength += this->vtf.getThumbnailDataRaw().size();
144 }
145 }
146 const auto vtfTheRestLength = static_cast<uint32_t>(vtfData.size() - vtfChunkLength);
147 streamTTH << vtfChunkLength << this->mipFlags << static_cast<uint32_t>(vtfData.size());
148 const auto vtfTTZLengthPos = streamTTH.tell();
149 streamTTH.write<uint32_t>(0).write(vtfData.data(), vtfChunkLength);
150
151 // TTZ (copied from VTF ::compressData)
152 mz_ulong compressedSize = mz_compressBound(vtfTheRestLength);
153 data.second.resize(compressedSize);
154 int status = MZ_OK;
155 while ((status = mz_compress2(reinterpret_cast<unsigned char*>(data.second.data()), &compressedSize, reinterpret_cast<const unsigned char*>(vtfData.data() + vtfChunkLength), vtfTheRestLength, this->compressionLevel)) == MZ_BUF_ERROR) {
156 compressedSize *= 2;
157 data.second.resize(compressedSize);
158 }
159 if (status != MZ_OK) {
160 return {};
161 }
162 data.second.resize(compressedSize);
163
164 // Fix header
165 streamTTH.seek_u(vtfTTZLengthPos).write<uint32_t>(data.second.size());
166 data.first.resize(streamTTH.size());
167
168 return data;
169}
170
171bool TTX::bake(const std::string& tthPath, const std::string& ttzPath) const {
172 const auto data = this->bake();
173 const bool tth = fs::writeFileBuffer(tthPath, data.first);
174 if (!data.second.empty()) {
175 return fs::writeFileBuffer(ttzPath, data.second) && tth;
176 }
177 return tth;
178}
Definition: TTX.h:11
const VTF & getVTF() const
Definition: TTX.cpp:105
const std::vector< uint64_t > & getMipFlags() const
Definition: TTX.cpp:97
uint8_t getMinorVersion() const
Definition: TTX.cpp:72
std::vector< uint64_t > mipFlags
Definition: TTX.h:60
uint8_t aspectRatioType
Definition: TTX.h:59
VTF vtf
Definition: TTX.h:55
bool opened
Definition: TTX.h:52
uint8_t minorVersion
Definition: TTX.h:58
uint8_t getMajorVersion() const
Definition: TTX.cpp:68
uint8_t getAspectRatioType() const
Definition: TTX.cpp:89
void setVersion(uint8_t newMajorVersion, uint8_t newMinorVersion)
Definition: TTX.cpp:76
void setMinorVersion(uint8_t newMinorVersion)
Definition: TTX.cpp:85
int16_t getCompressionLevel() const
Definition: TTX.cpp:113
void setAspectRatioType(uint8_t newAspectRatioType)
Definition: TTX.cpp:93
std::pair< std::vector< std::byte >, std::vector< std::byte > > bake() const
Definition: TTX.cpp:121
void setCompressionLevel(int16_t newCompressionLevel)
Definition: TTX.cpp:117
TTX(VTF &&vtf_)
Definition: TTX.cpp:10
int16_t compressionLevel
Definition: TTX.h:53
void setMajorVersion(uint8_t newMajorVersion)
Definition: TTX.cpp:81
uint8_t majorVersion
Definition: TTX.h:57
bool hasThumbnailData() const
Definition: VTF.cpp:1434
std::vector< std::byte > bake() const
Definition: VTF.cpp:1495
uint8_t getMipCount() const
Definition: VTF.cpp:805
std::span< const std::byte > getThumbnailDataRaw() const
Definition: VTF.cpp:1438
bool writeFileBuffer(const std::string &filepath, std::span< const std::byte > buffer)
Definition: FS.cpp:27
Definition: LZMA.h:11
constexpr uint32_t TTH_SIGNATURE
Definition: TTX.h:9