diff --git a/include/toolpp/CmdSeq.h b/include/toolpp/CmdSeq.h index 8e69d9f19..8b4f56a11 100644 --- a/include/toolpp/CmdSeq.h +++ b/include/toolpp/CmdSeq.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -20,9 +19,12 @@ class CmdSeq { COPY_FILE = 257, DELETE_FILE = 258, RENAME_FILE = 259, - COPY_FILE_IF_EXISTS_ALT = 260, + // This used to be a different thing - Strata changes it to be an alias for 261 + //COPY_FILE_IF_EXISTS_ALT = 260, COPY_FILE_IF_EXISTS = 261, } special; + static constexpr auto SPECIAL_COPY_FILE_IF_EXISTS_ALIAS = static_cast(260); + std::string executable; std::string arguments; @@ -39,6 +41,12 @@ class CmdSeq { std::vector commands; }; + enum class Type { + INVALID, + BINARY, + KEYVALUES_STRATA, + }; + explicit CmdSeq(std::string path_); [[nodiscard]] float getVersion() const; @@ -51,18 +59,22 @@ class CmdSeq { [[nodiscard]] std::vector bake() const; - [[nodiscard]] std::vector bake(bool overrideUsingKeyValues) const; + [[nodiscard]] std::vector bake(Type typeOverride) const; bool bake(const std::string& path_); - bool bake(const std::string& path_, bool overrideUsingKeyValues); + bool bake(const std::string& path_, Type typeOverride); protected: void parseBinary(const std::string& path); - void parseKeyValues(const std::string& path); + void parseKeyValuesStrata(const std::string& path); + + [[nodiscard]] std::vector bakeBinary() const; + + [[nodiscard]] std::vector bakeKeyValuesStrata() const; - bool usingKeyValues = false; + Type type; float version; std::string path; std::vector sequences; diff --git a/src/toolpp/CmdSeq.cpp b/src/toolpp/CmdSeq.cpp index a2e06a3ea..8592ca33e 100644 --- a/src/toolpp/CmdSeq.cpp +++ b/src/toolpp/CmdSeq.cpp @@ -12,71 +12,31 @@ using namespace toolpp; namespace { -std::vector bakeBinary(const CmdSeq& cmdSeq) { - std::vector out; - BufferStream writer{out}; - - writer - .write("Worldcraft Command Sequences\r\n\x1a", 31) - .write(cmdSeq.getVersion()) - .write(cmdSeq.getSequences().size()); - - for (const auto& [seqName, seqCommands] : cmdSeq.getSequences()) { - writer - .write(seqName, true, 128) - .write(seqCommands.size()); - - for (const auto& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] : seqCommands) { - writer - .write(enabled) - .write(special) - .write(executable, true, 260) - .write(arguments, true, 260) - .write(true) - .write(ensureFileExists) - .write(pathToTheoreticallyExistingFile, true, 260) - .write(useProcessWindow); - - if (cmdSeq.getVersion() > 0.15f) { - writer.write(waitForKeypress); - } - } +CmdSeq::Command::Special specialCmdFromString(std::string_view specialCmd) { + using enum CmdSeq::Command::Special; + if (string::iequals(specialCmd, "change_dir")) { + return CHANGE_DIRECTORY; } - - out.resize(writer.size()); - return out; -} - -std::vector bakeKeyValues(const CmdSeq& cmdSeq) { - KV1Writer kv; - auto& kvFile = kv.addChild("Command Sequences"); - for (const auto& [seqName, seqCommands] : cmdSeq.getSequences()) { - auto& kvSequence = kvFile.addChild(seqName); - for (int i = 1; i <= seqCommands.size(); i++) { - const auto& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands[i - 1]; - auto& kvCommand = kvSequence.addChild(std::to_string(i)); - kvCommand["enabled"] = enabled; - kvCommand["special_cmd"] = static_cast(special); - kvCommand["run"] = executable; - kvCommand["params"] = arguments; - kvCommand["ensure_check"] = ensureFileExists; - kvCommand["ensure_fn"] = pathToTheoreticallyExistingFile; - kvCommand["use_process_wnd"] = useProcessWindow; - kvCommand["no_wait"] = waitForKeypress; - } + if (string::iequals(specialCmd, "copy_file")) { + return COPY_FILE; } - - const auto kvStr = kv.bake(); - std::vector out; - out.resize(kvStr.length()); - std::memcpy(out.data(), kvStr.data(), kvStr.length()); - return out; + if (string::iequals(specialCmd, "delete_file")) { + return DELETE_FILE; + } + if (string::iequals(specialCmd, "rename_file")) { + return RENAME_FILE; + } + if (string::iequals(specialCmd, "copy_file_if_exists")) { + return COPY_FILE_IF_EXISTS; + } + return NONE; } } // namespace CmdSeq::CmdSeq(std::string path_) - : version(0.f) + : type(Type::INVALID) + , version(0.f) , path(std::move(path_)) { { FileStream reader{path}; @@ -84,21 +44,27 @@ CmdSeq::CmdSeq(std::string path_) return; } if (auto binStr = reader.seek_in(0).read_string(10); binStr == "Worldcraft") { - this->usingKeyValues = false; + this->type = Type::BINARY; } else { auto kvStr = reader.seek_in(0).read_string(19); string::toLower(kvStr); if (kvStr == "\"command sequences\"") { - this->usingKeyValues = true; + this->type = Type::KEYVALUES_STRATA; } else { return; } } } - if (this->usingKeyValues) { - this->parseKeyValues(path); - } else { - this->parseBinary(path); + switch (this->type) { + using enum Type; + case INVALID: + break; + case BINARY: + this->parseBinary(path); + break; + case KEYVALUES_STRATA: + this->parseKeyValuesStrata(path); + break; } } @@ -132,6 +98,9 @@ void CmdSeq::parseBinary(const std::string& path) { auto& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands.emplace_back(); enabled = reader.read() & 0xFF; special = reader.read(); + if (special == static_cast(Command::SPECIAL_COPY_FILE_IF_EXISTS_ALIAS)) { + special = Command::Special::COPY_FILE_IF_EXISTS; + } executable = reader.read_string(260); arguments = reader.read_string(260); reader.skip_in(); @@ -145,7 +114,7 @@ void CmdSeq::parseBinary(const std::string& path) { } } -void CmdSeq::parseKeyValues(const std::string& path) { +void CmdSeq::parseKeyValuesStrata(const std::string& path) { this->version = 0.2f; const KV1 cmdSeq{fs::readFileText(path)}; @@ -156,7 +125,15 @@ void CmdSeq::parseKeyValues(const std::string& path) { for (const auto& kvCommand : kvSequence.getChildren()) { auto& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands.emplace_back(); string::toBool(kvCommand["enabled"].getValue(), enabled); - string::toInt(kvCommand["special_cmd"].getValue(), reinterpret_cast&>(special)); + const auto specialCmd = kvCommand["special_cmd"].getValue(); + if (parser::text::isNumber(specialCmd)) { + string::toInt(specialCmd, reinterpret_cast&>(special)); + if (special == Command::SPECIAL_COPY_FILE_IF_EXISTS_ALIAS) { + special = Command::Special::COPY_FILE_IF_EXISTS; + } + } else { + special = ::specialCmdFromString(specialCmd); + } executable = kvCommand["run"].getValue(); arguments = kvCommand["params"].getValue(); string::toBool(kvCommand["ensure_check"].getValue(), ensureFileExists); @@ -175,33 +152,94 @@ const std::vector& CmdSeq::getSequences() const { return this->sequences; } +std::vector CmdSeq::bakeBinary() const { + std::vector out; + BufferStream writer{out}; + + writer + .write("Worldcraft Command Sequences\r\n\x1a", 31) + .write(this->getVersion()) + .write(this->getSequences().size()); + + for (const auto& [seqName, seqCommands] : this->getSequences()) { + writer + .write(seqName, true, 128) + .write(seqCommands.size()); + + for (const auto& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] : seqCommands) { + writer + .write(enabled) + .write(special) + .write(executable, true, 260) + .write(arguments, true, 260) + .write(true) + .write(ensureFileExists) + .write(pathToTheoreticallyExistingFile, true, 260) + .write(useProcessWindow); + + if (this->getVersion() > 0.15f) { + writer.write(waitForKeypress); + } + } + } + + out.resize(writer.size()); + return out; +} + +std::vector CmdSeq::bakeKeyValuesStrata() const { + KV1Writer kv; + auto& kvFile = kv.addChild("Command Sequences"); + for (const auto& [seqName, seqCommands] : this->getSequences()) { + auto& kvSequence = kvFile.addChild(seqName); + for (int i = 1; i <= seqCommands.size(); i++) { + const auto& [enabled, special, executable, arguments, ensureFileExists, pathToTheoreticallyExistingFile, useProcessWindow, waitForKeypress] = seqCommands[i - 1]; + auto& kvCommand = kvSequence.addChild(std::to_string(i)); + kvCommand["enabled"] = enabled; + kvCommand["special_cmd"] = static_cast(special); + kvCommand["run"] = executable; + kvCommand["params"] = arguments; + kvCommand["ensure_check"] = ensureFileExists; + kvCommand["ensure_fn"] = pathToTheoreticallyExistingFile; + kvCommand["use_process_wnd"] = useProcessWindow; + kvCommand["no_wait"] = waitForKeypress; + } + } + + const auto kvStr = kv.bake(); + std::vector out; + out.resize(kvStr.length()); + std::memcpy(out.data(), kvStr.data(), kvStr.length()); + return out; +} + std::vector CmdSeq::bake() const { - return this->bake(this->usingKeyValues); + return this->bake(this->type); } -std::vector CmdSeq::bake(bool overrideUsingKeyValues) const { - if (overrideUsingKeyValues) { - return ::bakeKeyValues(*this); +std::vector CmdSeq::bake(Type typeOverride) const { + switch (typeOverride) { + using enum Type; + case INVALID: + return {}; + case BINARY: + return this->bakeBinary(); + case KEYVALUES_STRATA: + return this->bakeKeyValuesStrata(); } - return ::bakeBinary(*this); + return {}; } bool CmdSeq::bake(const std::string& path_) { - return this->bake(path_, this->usingKeyValues); + return this->bake(path_, this->type); } -bool CmdSeq::bake(const std::string& path_, bool overrideUsingKeyValues) { +bool CmdSeq::bake(const std::string& path_, Type typeOverride) { FileStream writer{path_}; if (!writer) { return false; } this->path = path_; - - writer.seek_out(0); - if (overrideUsingKeyValues) { - writer.write(::bakeKeyValues(*this)); - } else { - writer.write(::bakeBinary(*this)); - } + writer.seek_out(0).write(this->bake(typeOverride)); return true; } diff --git a/test/toolpp.cpp b/test/toolpp.cpp index 19ff0830c..cbd45e20d 100644 --- a/test/toolpp.cpp +++ b/test/toolpp.cpp @@ -11,7 +11,7 @@ TEST(toolpp, cmdSeqOpenBinary) { ASSERT_EQ(cmdSeq.getSequences().size(), 8); } -TEST(toolpp, cmdSeqOpenKeyValues) { +TEST(toolpp, cmdSeqOpenKeyValuesStrata) { CmdSeq cmdSeq{ASSET_ROOT "toolpp/cmdseq/keyvalues.wc"}; ASSERT_EQ(cmdSeq.getSequences().size(), 4); } @@ -23,7 +23,7 @@ TEST(toolpp, cmdSeqBakeBinary) { ASSERT_EQ(existingData, bakedData); } -TEST(toolpp, cmdSeqBakeKeyValues) { +TEST(toolpp, cmdSeqBakeKeyValuesStrata) { CmdSeq cmdSeq{ASSET_ROOT "toolpp/cmdseq/keyvalues.wc"}; auto existingData = fs::readFileBuffer(ASSET_ROOT "toolpp/cmdseq/keyvalues.wc"); auto bakedData = cmdSeq.bake();