SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Toggle main menu visibility
Loading...
Searching...
No Matches
CmdSeq.cpp
Go to the documentation of this file.
1
// ReSharper disable CppRedundantQualifier
2
3
#include <
toolpp/CmdSeq.h
>
4
5
#include <cstring>
6
#include <format>
7
8
#include <FileStream.h>
9
#include <
kvpp/kvpp.h
>
10
#include <
sourcepp/String.h
>
11
12
using namespace
kvpp
;
13
using namespace
sourcepp
;
14
using namespace
toolpp
;
15
16
namespace
{
17
18
CmdSeq::Command::Special
specialCmdFromString(std::string_view specialCmd) {
19
using
enum
CmdSeq::Command::Special
;
20
if
(
string::iequals
(specialCmd,
"change_dir"
)) {
21
return
CHANGE_DIRECTORY;
22
}
23
if
(
string::iequals
(specialCmd,
"copy_file"
)) {
24
return
COPY_FILE;
25
}
26
if
(
string::iequals
(specialCmd,
"delete_file"
)) {
27
return
DELETE_FILE;
28
}
29
if
(
string::iequals
(specialCmd,
"rename_file"
)) {
30
return
RENAME_FILE;
31
}
32
if
(
string::iequals
(specialCmd,
"copy_file_if_exists"
)) {
33
return
COPY_FILE_IF_EXISTS;
34
}
35
return
NONE
;
36
}
37
38
}
// namespace
39
40
std::string
CmdSeq::Command::getSpecialDisplayNameFor
(
Special
special
) {
41
switch
(
special
) {
42
case
Special::NONE
:
43
break
;
44
case
Special::CHANGE_DIRECTORY
:
45
return
"Change Directory"
;
46
case
Special::COPY_FILE
:
47
return
"Copy File"
;
48
case
Special::DELETE_FILE
:
49
return
"Delete File"
;
50
case
Special::RENAME_FILE
:
51
return
"Rename File"
;
52
case
Special::COPY_FILE_IF_EXISTS
:
53
return
"Copy File If It Exists"
;
54
}
55
return
"None"
;
56
}
57
58
std::string
CmdSeq::Command::getExecutableDisplayName
()
const
{
59
if
(this->
special
!=
Command::Special::NONE
) {
60
return
getSpecialDisplayNameFor
(this->
special
);
61
}
62
return
this->
executable
;
63
}
64
65
CmdSeq::CmdSeq
(
Type
type_)
66
:
type
(type_)
67
,
version
(0.2f) {}
68
69
CmdSeq::CmdSeq
(
const
std::filesystem::path& cmdSeqPath)
70
:
type
(
Type
::INVALID)
71
,
version
(0.2f) {
72
{
73
FileStream reader{cmdSeqPath};
74
if
(!reader) {
75
return
;
76
}
77
if
(
const
auto
binStr = reader.seek_in(0).read_string(10); binStr ==
"Worldcraft"
) {
78
this->
type
=
Type::BINARY
;
79
}
else
{
80
auto
kvStr = reader.seek_in(0).read_string(19);
81
string::toLower
(kvStr);
82
if
(kvStr ==
"\"command sequences\""
) {
83
this->
type
= cmdSeqPath.extension() ==
".cfg"
?
Type::KEYVALUES_HPP
:
Type::KEYVALUES_STRATA
;
84
}
else
{
85
return
;
86
}
87
}
88
}
89
switch
(this->
type
) {
90
using
enum
Type
;
91
case
INVALID
:
92
break
;
93
case
BINARY
:
94
this->
parseBinary
(cmdSeqPath);
95
break
;
96
case
KEYVALUES_HPP
:
97
this->
parseKeyValuesHPP
(cmdSeqPath);
98
break
;
99
case
KEYVALUES_STRATA
:
100
this->
parseKeyValuesStrata
(cmdSeqPath);
101
break
;
102
}
103
}
104
105
CmdSeq::operator bool()
const
{
106
return
this->
type
!=
Type::INVALID
;
107
}
108
109
CmdSeq::Type
CmdSeq::getType
()
const
{
110
return
this->
type
;
111
}
112
113
void
CmdSeq::setType
(
Type
type_) {
114
this->
type
= type_;
115
}
116
117
float
CmdSeq::getBinaryVersion
()
const
{
118
return
this->
version
;
119
}
120
121
void
CmdSeq::setBinaryVersion
(
bool
isV02) {
122
if
(isV02) {
123
this->
version
= 0.2f;
124
}
else
{
125
this->
version
= 0.1f;
126
}
127
}
128
129
void
CmdSeq::parseBinary
(
const
std::filesystem::path& path) {
130
FileStream reader{path};
131
if
(!reader) {
132
return
;
133
}
134
135
reader.seek_in(31).read(this->
version
);
136
137
const
auto
sequenceCount = reader.read<uint32_t>();
138
for
(uint32_t s = 0; s < sequenceCount; s++) {
139
auto
& [seqName, seqCommands] = this->
sequences
.emplace_back();
140
seqName = reader.read_string(128);
141
142
const
auto
commandCount = reader.read<uint32_t>();
143
for
(uint32_t c = 0; c < commandCount; c++) {
144
auto
& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands.emplace_back();
145
enabled = reader.read<int32_t>() & 0xFF;
146
special = reader.read<
Command::Special
>();
147
if
(special ==
static_cast<
Command::Special
>
(
Command::SPECIAL_COPY_FILE_IF_EXISTS_ALIAS
)) {
148
special =
Command::Special::COPY_FILE_IF_EXISTS
;
149
}
150
executable = reader.read_string(260);
151
arguments = reader.read_string(260);
152
reader.skip_in<int32_t>();
153
ensureFileExists = reader.read<int32_t>();
154
pathToTheoreticallyExistingFile = reader.read_string(260);
155
useProcessWindow = reader.read<int32_t>();
156
if
(
version
> 0.15f) {
157
waitForKeypress = reader.read<int32_t>();
158
}
159
}
160
}
161
}
162
163
void
CmdSeq::parseKeyValuesHPP
(
const
std::filesystem::path& path) {
164
this->
version
= 0.2f;
165
166
const
KV1
cmdSeq{
fs::readFileText
(path)};
167
for
(
const
auto
& kvSequence : cmdSeq[
"Command Sequences"
].getChildren()) {
168
auto
& [seqName, seqCommands] = this->
sequences
.emplace_back();
169
seqName = kvSequence.getKey();
170
171
for
(
const
auto
& kvCommand : kvSequence.getChildren()) {
172
auto
& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands.emplace_back();
173
string::toBool
(kvCommand[
"enable"
].getValue(), enabled);
174
const
auto
specialCmd = kvCommand[
"specialcmd"
].getValue();
175
if
(
parser::text::isNumber
(specialCmd)) {
176
string::toInt
(specialCmd,
reinterpret_cast<
std::underlying_type_t<Command::Special>&
>
(special));
177
if
(special ==
Command::SPECIAL_COPY_FILE_IF_EXISTS_ALIAS
) {
178
special =
Command::Special::COPY_FILE_IF_EXISTS
;
179
}
180
}
else
{
181
special = ::specialCmdFromString(specialCmd);
182
}
183
executable = kvCommand[
"run"
].getValue();
184
arguments = kvCommand[
"parms"
].getValue();
185
}
186
}
187
}
188
189
void
CmdSeq::parseKeyValuesStrata
(
const
std::filesystem::path& path) {
190
this->
version
= 0.2f;
191
192
const
KV1
cmdSeq{
fs::readFileText
(path)};
193
for
(
const
auto
& kvSequence : cmdSeq[
"Command Sequences"
].getChildren()) {
194
auto
& [seqName, seqCommands] = this->
sequences
.emplace_back();
195
seqName = kvSequence.getKey();
196
197
for
(
const
auto
& kvCommand : kvSequence.getChildren()) {
198
auto
& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands.emplace_back();
199
string::toBool
(kvCommand[
"enabled"
].getValue(), enabled);
200
const
auto
specialCmd = kvCommand[
"special_cmd"
].getValue();
201
if
(
parser::text::isNumber
(specialCmd)) {
202
string::toInt
(specialCmd,
reinterpret_cast<
std::underlying_type_t<Command::Special>&
>
(special));
203
if
(special ==
Command::SPECIAL_COPY_FILE_IF_EXISTS_ALIAS
) {
204
special =
Command::Special::COPY_FILE_IF_EXISTS
;
205
}
206
}
else
{
207
special = ::specialCmdFromString(specialCmd);
208
}
209
executable = kvCommand[
"run"
].getValue();
210
arguments = kvCommand[
"params"
].getValue();
211
string::toBool
(kvCommand[
"ensure_check"
].getValue(), ensureFileExists);
212
pathToTheoreticallyExistingFile = kvCommand[
"ensure_fn"
].getValue();
213
string::toBool
(kvCommand[
"use_process_wnd"
].getValue(), useProcessWindow);
214
string::toBool
(kvCommand[
"no_wait"
].getValue(), waitForKeypress);
215
}
216
}
217
}
218
219
std::vector<CmdSeq::Sequence>&
CmdSeq::getSequences
() {
220
return
this->
sequences
;
221
}
222
223
const
std::vector<CmdSeq::Sequence>&
CmdSeq::getSequences
()
const
{
224
return
this->
sequences
;
225
}
226
227
std::vector<std::byte>
CmdSeq::bakeBinary
()
const
{
228
std::vector<std::byte> out;
229
BufferStream writer{out};
230
231
writer
232
.write(
"Worldcraft Command Sequences\r\n\x1a"
, 31)
233
.write<
float
>(this->
getBinaryVersion
())
234
.write<uint32_t>(this->
getSequences
().size());
235
236
for
(
const
auto
& [seqName, seqCommands] : this->
getSequences
()) {
237
writer
238
.write(seqName,
true
, 128)
239
.write<uint32_t>(seqCommands.size());
240
241
for
(
const
auto
& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] : seqCommands) {
242
writer
243
.write<uint32_t>(enabled)
244
.write(special)
245
.write(executable,
true
, 260)
246
.write(arguments,
true
, 260)
247
.write<uint32_t>(
true
)
248
.write<uint32_t>(ensureFileExists)
249
.write(pathToTheoreticallyExistingFile,
true
, 260)
250
.write<uint32_t>(useProcessWindow);
251
252
if
(this->
getBinaryVersion
() > 0.15f) {
253
writer.write<uint32_t>(waitForKeypress);
254
}
255
}
256
}
257
258
out.resize(writer.size());
259
return
out;
260
}
261
262
std::vector<std::byte>
CmdSeq::bakeKeyValuesHPP
()
const
{
263
KV1Writer
kv;
264
auto
& kvFile = kv.
addChild
(
"Command Sequences"
);
265
for
(
const
auto
& [seqName, seqCommands] : this->
getSequences
()) {
266
auto
& kvSequence = kvFile.addChild(seqName);
267
for
(
int
i = 1; i <= seqCommands.size(); i++) {
268
const
auto
& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands[i - 1];
269
auto
& kvCommand = kvSequence.addChild(std::format(
"{}"
, i));
270
kvCommand[
"enable"
] = enabled;
271
kvCommand[
"specialcmd"
] =
static_cast<
int
>
(special);
272
kvCommand[
"run"
] = executable;
273
kvCommand[
"parms"
] = arguments;
274
}
275
}
276
277
const
auto
kvStr = kv.
bake
();
278
std::vector<std::byte> out;
279
out.resize(kvStr.length());
280
std::memcpy(out.data(), kvStr.data(), kvStr.length());
281
return
out;
282
}
283
284
std::vector<std::byte>
CmdSeq::bakeKeyValuesStrata
()
const
{
285
KV1Writer
kv;
286
auto
& kvFile = kv.
addChild
(
"Command Sequences"
);
287
for
(
const
auto
& [seqName, seqCommands] : this->
getSequences
()) {
288
auto
& kvSequence = kvFile.addChild(seqName);
289
for
(
int
i = 1; i <= seqCommands.size(); i++) {
290
const
auto
& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands[i - 1];
291
auto
& kvCommand = kvSequence.addChild(std::format(
"{}"
, i));
292
kvCommand[
"enabled"
] = enabled;
293
kvCommand[
"special_cmd"
] =
static_cast<
int
>
(special);
294
kvCommand[
"run"
] = executable;
295
kvCommand[
"params"
] = arguments;
296
kvCommand[
"ensure_check"
] = ensureFileExists;
297
kvCommand[
"ensure_fn"
] = pathToTheoreticallyExistingFile;
298
kvCommand[
"use_process_wnd"
] = useProcessWindow;
299
kvCommand[
"no_wait"
] = waitForKeypress;
300
}
301
}
302
303
const
auto
kvStr = kv.
bake
();
304
std::vector<std::byte> out;
305
out.resize(kvStr.length());
306
std::memcpy(out.data(), kvStr.data(), kvStr.length());
307
return
out;
308
}
309
310
std::vector<std::byte>
CmdSeq::bake
()
const
{
311
switch
(this->
type
) {
312
using
enum
Type
;
313
case
INVALID
:
314
return
{};
315
case
BINARY
:
316
return
this->
bakeBinary
();
317
case
KEYVALUES_HPP
:
318
return
this->
bakeKeyValuesHPP
();
319
case
KEYVALUES_STRATA
:
320
return
this->
bakeKeyValuesStrata
();
321
}
322
return
{};
323
}
324
325
bool
CmdSeq::bake
(
const
std::filesystem::path& path)
const
{
326
FileStream writer{path};
327
if
(!writer) {
328
return
false
;
329
}
330
writer.seek_out(0).write(this->
bake
());
331
return
true
;
332
}
CmdSeq.h
String.h
kvpp::KV1ElementWritable::addChild
KV1ElementWritable & addChild(std::string_view key_, V value_={}, std::string_view conditional_="")
Definition
KV1Writer.h:89
kvpp::KV1Writer
Definition
KV1Writer.h:347
kvpp::KV1Writer::bake
std::string bake() const
Definition
KV1Writer.h:361
kvpp::KV1
Definition
KV1.h:216
toolpp::CmdSeq::parseKeyValuesHPP
void parseKeyValuesHPP(const std::filesystem::path &path)
Definition
CmdSeq.cpp:163
toolpp::CmdSeq::bake
std::vector< std::byte > bake() const
Definition
CmdSeq.cpp:310
toolpp::CmdSeq::getBinaryVersion
float getBinaryVersion() const
Definition
CmdSeq.cpp:117
toolpp::CmdSeq::setBinaryVersion
void setBinaryVersion(bool isV02)
Definition
CmdSeq.cpp:121
toolpp::CmdSeq::getType
Type getType() const
Definition
CmdSeq.cpp:109
toolpp::CmdSeq::parseKeyValuesStrata
void parseKeyValuesStrata(const std::filesystem::path &path)
Definition
CmdSeq.cpp:189
toolpp::CmdSeq::CmdSeq
CmdSeq(Type type_)
Definition
CmdSeq.cpp:65
toolpp::CmdSeq::Type
Type
Definition
CmdSeq.h:48
toolpp::CmdSeq::Type::KEYVALUES_HPP
@ KEYVALUES_HPP
Definition
CmdSeq.h:51
toolpp::CmdSeq::Type::KEYVALUES_STRATA
@ KEYVALUES_STRATA
Definition
CmdSeq.h:52
toolpp::CmdSeq::Type::BINARY
@ BINARY
Definition
CmdSeq.h:50
toolpp::CmdSeq::Type::INVALID
@ INVALID
Definition
CmdSeq.h:49
toolpp::CmdSeq::setType
void setType(Type type_)
Definition
CmdSeq.cpp:113
toolpp::CmdSeq::bakeKeyValuesStrata
std::vector< std::byte > bakeKeyValuesStrata() const
Definition
CmdSeq.cpp:284
toolpp::CmdSeq::getSequences
std::vector< Sequence > & getSequences()
Definition
CmdSeq.cpp:219
toolpp::CmdSeq::parseBinary
void parseBinary(const std::filesystem::path &path)
Definition
CmdSeq.cpp:129
toolpp::CmdSeq::type
Type type
Definition
CmdSeq.h:90
toolpp::CmdSeq::sequences
std::vector< Sequence > sequences
Definition
CmdSeq.h:92
toolpp::CmdSeq::bakeKeyValuesHPP
std::vector< std::byte > bakeKeyValuesHPP() const
Definition
CmdSeq.cpp:262
toolpp::CmdSeq::version
float version
Definition
CmdSeq.h:91
toolpp::CmdSeq::bakeBinary
std::vector< std::byte > bakeBinary() const
Definition
CmdSeq.cpp:227
kvpp.h
kvpp
Definition
DMX.h:13
sourcepp::fs::readFileText
std::string readFileText(const std::filesystem::path &filepath, std::size_t startOffset=0)
Definition
FS.cpp:22
sourcepp::parser::text::isNumber
bool isNumber(char c)
If a char is a numerical character (0-9).
Definition
Text.cpp:48
sourcepp::string::toBool
std::from_chars_result toBool(std::string_view number, bool &out, int base=10)
Definition
String.cpp:247
sourcepp::string::toInt
std::from_chars_result toInt(std::string_view number, std::integral auto &out, int base=10)
Definition
String.h:83
sourcepp::string::iequals
bool iequals(std::string_view s1, std::string_view s2)
Definition
String.cpp:63
sourcepp::string::toLower
void toLower(std::string &input)
Definition
String.cpp:167
sourcepp
Definition
LZMA.h:11
toolpp
Definition
CmdSeq.h:9
vpkpp::Attribute::NONE
@ NONE
Definition
Attribute.h:8
toolpp::CmdSeq::Command::executable
std::string executable
Definition
CmdSeq.h:28
toolpp::CmdSeq::Command::getExecutableDisplayName
std::string getExecutableDisplayName() const
Definition
CmdSeq.cpp:58
toolpp::CmdSeq::Command::special
enum toolpp::CmdSeq::Command::Special special
toolpp::CmdSeq::Command::SPECIAL_COPY_FILE_IF_EXISTS_ALIAS
static constexpr auto SPECIAL_COPY_FILE_IF_EXISTS_ALIAS
Definition
CmdSeq.h:26
toolpp::CmdSeq::Command::Special
Special
Definition
CmdSeq.h:16
toolpp::CmdSeq::Command::Special::DELETE_FILE
@ DELETE_FILE
Definition
CmdSeq.h:20
toolpp::CmdSeq::Command::Special::COPY_FILE
@ COPY_FILE
Definition
CmdSeq.h:19
toolpp::CmdSeq::Command::Special::COPY_FILE_IF_EXISTS
@ COPY_FILE_IF_EXISTS
Definition
CmdSeq.h:24
toolpp::CmdSeq::Command::Special::NONE
@ NONE
Definition
CmdSeq.h:17
toolpp::CmdSeq::Command::Special::CHANGE_DIRECTORY
@ CHANGE_DIRECTORY
Definition
CmdSeq.h:18
toolpp::CmdSeq::Command::Special::RENAME_FILE
@ RENAME_FILE
Definition
CmdSeq.h:21
toolpp::CmdSeq::Command::getSpecialDisplayNameFor
static std::string getSpecialDisplayNameFor(Special special)
Definition
CmdSeq.cpp:40
src
toolpp
CmdSeq.cpp
Generated on
for SourcePP by
1.17.0