SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
KV1Binary.cpp
Go to the documentation of this file.
1#include <kvpp/KV1Binary.h>
2
3#include <format>
4#include <functional>
5
6#include <kvpp/KV1.h>
7#include <sourcepp/FS.h>
8
9using namespace kvpp;
10using namespace sourcepp;
11
12std::string_view KV1BinaryElement::getKey() const {
13 return this->key;
14}
15
16void KV1BinaryElement::setKey(std::string_view key_) {
17 this->key = key_;
18}
19
21 return this->value;
22}
23
25 this->value = std::move(value_);
26}
27
29 this->setValue(std::move(value_));
30 return *this;
31}
32
33bool KV1BinaryElement::hasChild(std::string_view childKey) const {
34 return !this->operator[](childKey).isInvalid();
35}
36
38 return this->children.size();
39}
40
41uint64_t KV1BinaryElement::getChildCount(std::string_view childKey) const {
42 uint64_t count = 0;
43 for (const KV1BinaryElement& element : this->children) {
44 if (string::iequals(element.key, childKey)) {
45 ++count;
46 }
47 }
48 return count;
49}
50
51const std::vector<KV1BinaryElement>& KV1BinaryElement::getChildren() const {
52 return this->children;
53}
54
57 elem.setKey(key_);
58 this->children.push_back(elem);
59 return this->children.back();
60}
61
62const KV1BinaryElement& KV1BinaryElement::operator[](unsigned int n) const {
63 return this->children.at(n);
64}
65
67 return this->children.at(n);
68}
69
70const KV1BinaryElement& KV1BinaryElement::operator[](std::string_view childKey) const {
71 return this->operator()(childKey);
72}
73
75 return this->operator()(childKey);
76}
77
78const KV1BinaryElement& KV1BinaryElement::operator()(std::string_view childKey) const {
79 for (const auto& element : this->children) {
80 if (string::iequals(element.getKey(), childKey)) {
81 return element;
82 }
83 }
84 return getInvalid();
85}
86
88 for (auto& element : this->children) {
89 if (string::iequals(element.getKey(), childKey)) {
90 return element;
91 }
92 }
93 return this->addChild(childKey);
94}
95
96const KV1BinaryElement& KV1BinaryElement::operator()(std::string_view childKey, unsigned int n) const {
97 unsigned int count = 0;
98 for (const auto& element : this->children) {
99 if (string::iequals(element.getKey(), childKey)) {
100 if (count == n) {
101 return element;
102 }
103 ++count;
104 }
105 }
106 return getInvalid();
107}
108
109KV1BinaryElement& KV1BinaryElement::operator()(std::string_view childKey, unsigned int n) {
110 unsigned int count = 0;
111 for (auto& element: this->children) {
112 if (string::iequals(element.getKey(), childKey)) {
113 if (count == n) {
114 return element;
115 }
116 ++count;
117 }
118 }
119 return this->addChild(childKey);
120}
121
122void KV1BinaryElement::removeChild(unsigned int n) {
123 if (this->children.size() > n) {
124 this->children.erase(this->children.begin() + n);
125 }
126}
127
128void KV1BinaryElement::removeChild(std::string_view childKey, int n) {
129 unsigned int count = 0;
130 for (auto element = this->children.begin(); element != this->children.end(); ++element) {
131 if (string::iequals(element->getKey(), childKey)) {
132 if (n < 0 || count == n) {
133 element = this->children.erase(element);
134 if (count == n) {
135 return;
136 }
137 }
138 ++count;
139 }
140 }
141}
142
144 return this == &getInvalid();
145}
146
148 static KV1BinaryElement element;
149 return element;
150}
151
152void KV1BinaryElement::read(BufferStreamReadOnly& stream, std::vector<KV1BinaryElement>& elements, const parser::text::EscapeSequenceMap& escapeSequences) {
153 for (;;) {
154 const auto type = stream.read<KV1BinaryValueType>();
155 if (type == KV1BinaryValueType::COUNT) {
156 break;
157 }
158 KV1BinaryElement& element = elements.emplace_back();
159 element.key = stream.read_string();
160 switch (type) {
161 using enum KV1BinaryValueType;
162 case CHILDREN:
163 KV1BinaryElement::read(stream, element.children, escapeSequences);
164 break;
165 case STRING:
166 element.value = stream.read_string();
167 break;
168 case INT32:
169 element.value = stream.read<int32_t>();
170 break;
171 case FLOAT:
172 element.value = stream.read<float>();
173 break;
174 case POINTER:
175 element.value = reinterpret_cast<void*>(stream.read<int32_t>());
176 break;
177 case WSTRING: {
178 const auto len = stream.read<uint16_t>();
179 std::wstring value;
180 for (int i = 0; i < len; i++) {
181 value += stream.read<char16_t>();
182 }
183 element.value = value;
184 break;
185 }
186 case COLOR_RGBA: {
187 math::Vec4ui8 value;
188 value[0] = stream.read<uint8_t>();
189 value[1] = stream.read<uint8_t>();
190 value[2] = stream.read<uint8_t>();
191 value[3] = stream.read<uint8_t>();
192 element.value = value;
193 break;
194 }
195 case UINT64:
196 element.value = stream.read<uint64_t>();
197 break;
198 case COUNT:
199 break;
200 }
201 }
202}
203
204void KV1BinaryElement::write(BufferStream& stream, const std::vector<KV1BinaryElement>& elements, const parser::text::EscapeSequenceMap& escapeSequences) {
205 for (const auto& element : elements) {
206 const auto type = static_cast<KV1BinaryValueType>(element.getValue().index());
207 stream
208 .write(type)
209 .write(element.getKey());
210 switch (type) {
211 using enum KV1BinaryValueType;
212 case CHILDREN:
213 KV1BinaryElement::write(stream, element.children, escapeSequences);
214 break;
215 case STRING:
216 stream.write(*element.getValue<std::string>());
217 break;
218 case INT32:
219 stream.write(*element.getValue<int32_t>());
220 break;
221 case FLOAT:
222 stream.write(*element.getValue<float>());
223 break;
224 case POINTER:
225 stream.write(static_cast<int32_t>(reinterpret_cast<uint64_t>(*element.getValue<void*>())));
226 break;
227 case WSTRING: {
228 const auto val = *element.getValue<std::wstring>();
229 stream
230 .write<uint16_t>(val.size() + 1)
231 .write(reinterpret_cast<const char16_t*>(val.data()), val.size() * sizeof(char16_t) / sizeof(wchar_t))
232 .write<uint16_t>(0);
233 break;
234 }
235 case COLOR_RGBA: {
236 const auto val = *element.getValue<math::Vec4ui8>();
237 stream << val[0] << val[1] << val[2] << val[3];
238 break;
239 }
240 case UINT64:
241 stream.write(*element.getValue<uint64_t>());
242 break;
243 case COUNT:
244 break;
245 }
246 }
247 stream.write(KV1BinaryValueType::COUNT);
248}
249
250KV1Binary::KV1Binary(std::span<const std::byte> kv1Data, bool useEscapeSequences_)
252 , useEscapeSequences(useEscapeSequences_) {
253 if (kv1Data.empty()) {
254 return;
255 }
256 BufferStreamReadOnly stream{kv1Data.data(), kv1Data.size()};
258}
259
260std::vector<std::byte> KV1Binary::bake() const {
261 std::vector<std::byte> buffer;
262 BufferStream stream{buffer};
264 buffer.resize(stream.size());
265 return buffer;
266}
267
268void KV1Binary::bake(const std::string& kv1Path) const {
269 fs::writeFileBuffer(kv1Path, this->bake());
270}
271
272std::string KV1Binary::bakeText() const {
273 KV1Writer writer;
274 std::function<void(const KV1BinaryElement&, KV1ElementWritable<>&)> recurseBinaryKeyValues;
275 recurseBinaryKeyValues = [&recurseBinaryKeyValues](const KV1BinaryElement& element, KV1ElementWritable<>& kv) {
276 auto& child = kv.addChild(element.getKey());
277 switch (static_cast<KV1BinaryValueType>(element.getValue().index())) {
278 using enum KV1BinaryValueType;
279 case CHILDREN:
280 for (const auto& elementChild : element.getChildren()) {
281 recurseBinaryKeyValues(elementChild, child);
282 }
283 break;
284 case STRING:
285 child = *element.getValue<std::string>();
286 break;
287 case INT32:
288 child = *element.getValue<int32_t>();
289 break;
290 case FLOAT:
291 child = *element.getValue<float>();
292 break;
293 case POINTER:
294 child = reinterpret_cast<int64_t>(*element.getValue<void*>());
295 break;
296 case WSTRING:
297 break;
298 case COLOR_RGBA: {
299 const auto val = *element.getValue<math::Vec4ui8>();
300 child = std::format("{} {} {} {}", val[0], val[1], val[2], val[3]);
301 break;
302 }
303 case UINT64:
304 child = std::format("{}", *element.getValue<uint64_t>());
305 break;
306 case COUNT:
307 break;
308 }
309 };
310 recurseBinaryKeyValues(*this, writer);
311 return writer.bake();
312}
313
314void KV1Binary::bakeText(const std::string& kv1Path) const {
315 fs::writeFileText(kv1Path, this->bakeText());
316}
const std::vector< KV1BinaryElement > & getChildren() const
Get the child elements of the element.
Definition: KV1Binary.cpp:51
KV1BinaryElement & addChild(std::string_view key_)
Add a child element to the element.
Definition: KV1Binary.cpp:55
static void read(BufferStreamReadOnly &stream, std::vector< KV1BinaryElement > &elements, const sourcepp::parser::text::EscapeSequenceMap &escapeSequences)
Definition: KV1Binary.cpp:152
std::vector< KV1BinaryElement > children
Definition: KV1Binary.h:185
const KV1BinaryElement & operator()(std::string_view childKey) const
Get the first child element of the element with the given key.
Definition: KV1Binary.cpp:78
static const KV1BinaryElement & getInvalid()
Definition: KV1Binary.cpp:147
void removeChild(unsigned int n)
Remove a child element from the element.
Definition: KV1Binary.cpp:122
bool hasChild(std::string_view childKey) const
Check if the element has one or more children with the given name.
Definition: KV1Binary.cpp:33
KV1BinaryValue value
Definition: KV1Binary.h:184
void setKey(std::string_view key_)
Set the key associated with the element.
Definition: KV1Binary.cpp:16
const KV1BinaryValue & getValue() const
Get the value associated with the element.
Definition: KV1Binary.cpp:20
uint64_t getChildCount() const
Get the number of child elements.
Definition: KV1Binary.cpp:37
KV1BinaryElement & operator=(KV1BinaryValue value_)
Set the value associated with the element.
Definition: KV1Binary.cpp:28
void setValue(KV1BinaryValue value_)
Set the value associated with the element.
Definition: KV1Binary.cpp:24
const KV1BinaryElement & operator[](unsigned int n) const
Get the child element of the element at the given index.
Definition: KV1Binary.cpp:62
bool isInvalid() const
Check if the given element is invalid.
Definition: KV1Binary.cpp:143
static void write(BufferStream &stream, const std::vector< KV1BinaryElement > &elements, const sourcepp::parser::text::EscapeSequenceMap &escapeSequences)
Definition: KV1Binary.cpp:204
std::string_view getKey() const
Get the key associated with the element.
Definition: KV1Binary.cpp:12
std::vector< std::byte > bake() const
Definition: KV1Binary.cpp:260
KV1Binary(std::span< const std::byte > kv1Data={}, bool useEscapeSequences_=false)
Definition: KV1Binary.cpp:250
bool useEscapeSequences
Definition: KV1Binary.h:201
std::string bakeText() const
Definition: KV1Binary.cpp:272
KV1ElementWritable & addChild(std::string_view key_, V value_={}, std::string_view conditional_="")
Definition: KV1.h:282
std::string bake() const
Definition: KV1.h:410
Definition: KV1.h:13
KV1BinaryValueType
Definition: KV1Binary.h:16
std::variant< std::monostate, std::string, int32_t, float, void *, std::wstring, sourcepp::math::Vec4ui8, uint64_t > KV1BinaryValue
Definition: KV1Binary.h:37
bool writeFileText(const std::string &filepath, const std::string &text)
Definition: FS.cpp:36
bool writeFileBuffer(const std::string &filepath, std::span< const std::byte > buffer)
Definition: FS.cpp:27
std::unordered_map< char, char > EscapeSequenceMap
Definition: Text.h:17
const EscapeSequenceMap & getDefaultEscapeSequencesOrNone(bool useEscapes)
Definition: Text.cpp:27
bool iequals(std::string_view s1, std::string_view s2)
Definition: String.cpp:61
Definition: LZMA.h:11