summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAECX <aecx@aecx.cc>2019-09-06 08:58:36 +0200
committerAECX <aecx@aecx.cc>2019-09-06 08:58:36 +0200
commit292c916ac328292959586a1b441b5a2d938a333f (patch)
tree415d984f8f9647df94cc0e91a40516b4bf1dde95
parent6df776d7b8f078a72b18f03333766f3c13c18f17 (diff)
Added GET mode
-rw-r--r--CMakeLists.txt11
-rw-r--r--include/Twilight Editor.h22
-rw-r--r--include/checksum.h15
-rw-r--r--include/converter.h21
-rw-r--r--include/settings.h8
-rw-r--r--source/Twilight Editor.cpp215
-rw-r--r--source/checksum.cpp28
-rw-r--r--source/converter.cpp197
-rw-r--r--source/settings.cpp6
9 files changed, 471 insertions, 52 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 91c1933..bb99f6b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ set (CMAKE_CXX_STANDARD 17)
project (TwilightEditor)
set (TE_VERSION_MAIN 3)
-set (TE_VERSION_SUB 0)
+set (TE_VERSION_SUB 1)
configure_file (
"${projectDir}include/config.h.in"
@@ -14,8 +14,8 @@ configure_file (
include_directories("${PROJECT_BINARY_DIR}/include")
-file(GLOB_RECURSE TE_SOURCES "${projectDir}source/*.cpp")
-file(GLOB_RECURSE TE_HEADERS "${projectDir}include/*.h")
+file(GLOB TE_SOURCES "${projectDir}source/*.cpp")
+file(GLOB TE_HEADERS "${projectDir}include/*.h")
set (TE_INCLUDE_DIRS "")
@@ -30,5 +30,10 @@ add_executable (TwilightEditor ${TE_SOURCES})
target_include_directories(TwilightEditor PRIVATE ${TE_INCLUDE_DIRS})
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
+ add_definitions (-DOS_STRING="LINUX")
+ add_definitions (-DLINUX)
target_link_libraries(TwilightEditor stdc++fs)
+else ()
+ add_definitions (-DOS_STRING="WIN32")
+ add_definitions (-DWIN32)
endif() \ No newline at end of file
diff --git a/include/Twilight Editor.h b/include/Twilight Editor.h
index 44619fc..d11ecab 100644
--- a/include/Twilight Editor.h
+++ b/include/Twilight Editor.h
@@ -1,3 +1,25 @@
#pragma once
+#include "settings.h"
+#include "cxxopts.h"
+#include "config.h"
+#include "converter.h"
+
#include <iostream>
+#include <fstream>
+#include <filesystem>
+
+namespace fs = std::filesystem;
+
+int main(int argc, char* argv[]);
+void fastPrint(const std::string& message, bool newline = true);
+cxxopts::ParseResult parse(int argc, char* argv[]);
+
+namespace TwilightEditor
+{
+ extern FILE* currentFilePtr;
+ extern std::size_t fileSize;
+
+ void initFile();
+ std::string get();
+} \ No newline at end of file
diff --git a/include/checksum.h b/include/checksum.h
new file mode 100644
index 0000000..cc872db
--- /dev/null
+++ b/include/checksum.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "Twilight Editor.h"
+
+#include <cstdint>
+#include <iostream>
+
+namespace TwilightEditor
+{
+ /**
+ * Generates a tp-valid checksum for data
+ * and stores the results in csum and nsum
+ */
+ void checkSum(uint8_t* data, std::size_t length, uint32_t* csum, uint32_t* nsum);
+} \ No newline at end of file
diff --git a/include/converter.h b/include/converter.h
new file mode 100644
index 0000000..c8fac1b
--- /dev/null
+++ b/include/converter.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "settings.h"
+
+#include <string>
+#include <iostream>
+#include <cstdint>
+#include <sstream>
+
+namespace TwilightEditor
+{
+ namespace Converter
+ {
+ uint32_t u32(std::string& value);
+ uint16_t u16(std::string& value);
+ uint8_t u8(std::string& value);
+
+ void flag(uint8_t* value, std::string& flag, bool set = true);
+
+ std::string toStr(uint8_t* data, offsetType type, std::size_t length, uint8_t flag = 0);
+ }
+} \ No newline at end of file
diff --git a/include/settings.h b/include/settings.h
index 43d2e5b..5ce0e2e 100644
--- a/include/settings.h
+++ b/include/settings.h
@@ -15,6 +15,7 @@ namespace TwilightEditor
{
TPINT,
TPFLAG,
+ TPUFLAG,
TPSTRING
};
@@ -26,15 +27,18 @@ namespace TwilightEditor
mode MODE;
uint16_t QUESTLOG;
bool FIX;
-
+ bool HEX;
+
// Offset
uint16_t OFFSET;
uint16_t LENGTH;
offsetType TYPE;
- std::string VALUE;
+ std::string STR_VALUE;
// Additional
bool VERBOSE;
bool FORCE;
};
+
+ extern settings Settings;
} \ No newline at end of file
diff --git a/source/Twilight Editor.cpp b/source/Twilight Editor.cpp
index ac072e9..df46ffe 100644
--- a/source/Twilight Editor.cpp
+++ b/source/Twilight Editor.cpp
@@ -1,23 +1,67 @@
#include "Twilight Editor.h"
-#include "settings.h"
-#include "cxxopts.h"
-#include "config.h"
-#include <filesystem>
-namespace fs = std::filesystem;
-namespace TE = TwilightEditor;
+int main(int argc, char* argv[])
+{
+ auto result = parse(argc, argv);
+ auto arguments = result.arguments();
-namespace TwilightEditor
+ if (TwilightEditor::Settings.VERBOSE)
+ {
+ std::cout << "Settings:" << std::endl;
+ std::cout << "Input File: " << TwilightEditor::Settings.INPUT_FILE << std::endl;
+ std::cout << "Output File: " << TwilightEditor::Settings.OUTPUT_FILE << std::endl;
+ std::cout << "Mode: " << TwilightEditor::Settings.MODE << std::endl;
+ std::cout << "QuestLog: " << TwilightEditor::Settings.QUESTLOG << std::endl;
+ std::cout << "Fix checksum: " << TwilightEditor::Settings.FIX << std::endl;
+
+
+ std::cout << "Offset: " << TwilightEditor::Settings.OFFSET << std::endl;
+ std::cout << "Length: " << TwilightEditor::Settings.LENGTH << std::endl;
+ std::cout << "Type: " << TwilightEditor::Settings.TYPE << std::endl;
+ std::cout << "Value: " << TwilightEditor::Settings.STR_VALUE << std::endl;
+
+ std::cout << "Verbose: " << TwilightEditor::Settings.VERBOSE << std::endl;
+ std::cout << "Force: " << TwilightEditor::Settings.FORCE << std::endl;
+ }
+
+ fastPrint("initializing file...");
+
+ TwilightEditor::initFile();
+
+ switch (TwilightEditor::Settings.MODE)
+ {
+ case TwilightEditor::mode::GET:
+ fastPrint("> GET");
+
+ std::cout << TwilightEditor::get() << std::endl;
+ break;
+
+ case TwilightEditor::mode::SET:
+ fastPrint("> SET");
+
+ break;
+ }
+
+ fastPrint("Closing file...");
+ fclose(TwilightEditor::currentFilePtr);
+ return 0;
+}
+
+void fastPrint(const std::string& message, bool newline)
{
- settings Settings;
+ if (TwilightEditor::Settings.VERBOSE)
+ {
+ std::cout << message;
+ if (newline) std::cout << std::endl;
+ }
}
cxxopts::ParseResult parse(int argc, char* argv[])
{
try
{
- cxxopts::Options options(argv[0], "Twilight Editor | (C) @theAECX | *required");
+ cxxopts::Options options(argv[0], "Twilight Editor | (C) AECX 2019 | *required");
options.add_options("General")
("h,help", " Prints this help")
@@ -25,16 +69,18 @@ cxxopts::ParseResult parse(int argc, char* argv[])
("m,mode", " (string) <GET> or <SET>", cxxopts::value<std::string>()->default_value("GET"), "<GET|SET>")
("o,output", " (string) If empty: Override input file", cxxopts::value<std::string>(), "<path/to/file>")
("q,questlog", " (int) QuestLog Index (0 based)", cxxopts::value<std::uint16_t>()->default_value("0"), "<n>")
- ("fix", " (bool) Correct checksum?", cxxopts::value<bool>()->default_value("false"));
+ ("fix", " (bool) Correct checksum?", cxxopts::value<bool>()->default_value("false"))
+ ("hex", " (bool) Output in Hexadecimal format?", cxxopts::value<bool>()->default_value("false"));
options.add_options("Offset")
("offset", "*(hex/dec) Hexadecimal QuestLog offset", cxxopts::value<uint16_t>(), "<0x000>")
("length", "*(hex/dec) Hexadecimal Length", cxxopts::value<uint16_t>(), "<0x00>")
- ("type", "*(string) Value type/interpretation", cxxopts::value<std::string>(), "<int|flg|str>")
- ("value", "*(string) The value you want to apply", cxxopts::value<std::string>(), "<\"Link\">");
+ ("type", "*(string) Value type/interpretation", cxxopts::value<std::string>(), "<int|flg|uflg|str>")
+ ("value", "(string) The value you want to apply", cxxopts::value<std::string>()->default_value("0"), "<\"Link\">");
options.add_options("Additional")
- ("v,verbose", " Print additional output information", cxxopts::value<bool>()->default_value("false"))
+ ("v,version", " Display current version information")
+ ("verbose", " Print additional output information", cxxopts::value<bool>()->default_value("false"))
("f,force", " Don't ask for file overrides", cxxopts::value<bool>()->default_value("false"));
auto result = options.parse(argc, argv);
@@ -45,39 +91,51 @@ cxxopts::ParseResult parse(int argc, char* argv[])
exit(0);
}
+ if (result.count("version"))
+ {
+ std::cout << "Twilight Editor (" << OS_STRING << ") v" << TE_VERSION_MAIN << "." << TE_VERSION_SUB << " (C) AECX 2019" << std::endl;
+ std::cout << "https://editor.tpspeed.run | https://aecx.cc | https://twitter.com/theAECX" << std::endl;
+ exit(0);
+ }
+
// Set values to global settings struct
if (result.count("input"))
{
- TE::Settings.INPUT_FILE = result["input"].as<std::string>();
+ TwilightEditor::Settings.INPUT_FILE = result["input"].as<std::string>();
}
else
{
throw cxxopts::OptionException("Missing parameter --input");
}
- TE::Settings.MODE = (result["mode"].as<std::string>() == "GET" ? TE::mode::GET : TE::mode::SET);
+ TwilightEditor::Settings.MODE = (result["mode"].as<std::string>() == "GET" ? TwilightEditor::mode::GET : TwilightEditor::mode::SET);
if (result.count("output"))
{
- TE::Settings.OUTPUT_FILE = result["output"].as<std::string>();
+ TwilightEditor::Settings.OUTPUT_FILE = result["output"].as<std::string>();
}
else
{
// Overwrite original
- TE::Settings.OUTPUT_FILE = TE::Settings.INPUT_FILE;
+ TwilightEditor::Settings.OUTPUT_FILE = TwilightEditor::Settings.INPUT_FILE;
}
- TE::Settings.QUESTLOG = result["questlog"].as<std::uint16_t>();
- if (TE::Settings.QUESTLOG > 2)
+ TwilightEditor::Settings.QUESTLOG = result["questlog"].as<std::uint16_t>();
+ if (TwilightEditor::Settings.QUESTLOG > 2)
{
throw cxxopts::OptionException("Invalid QuestLog Index");
}
- TE::Settings.FIX = result["fix"].as<bool>();
+ if (result.count("hex"))
+ {
+ TwilightEditor::Settings.HEX = result["hex"].as<bool>();
+ }
+
+ TwilightEditor::Settings.FIX = result["fix"].as<bool>();
if (result.count("offset"))
{
- TE::Settings.OFFSET = result["offset"].as<uint16_t>();
+ TwilightEditor::Settings.OFFSET = result["offset"].as<uint16_t>();
}
else
{
@@ -86,32 +144,30 @@ cxxopts::ParseResult parse(int argc, char* argv[])
if (result.count("length"))
{
- TE::Settings.LENGTH = result["length"].as<uint16_t>();
+ TwilightEditor::Settings.LENGTH = result["length"].as<uint16_t>();
}
else
{
throw cxxopts::OptionException("Missing parameter --length");
}
+ // --type
if (result.count("type"))
{
- TE::Settings.TYPE = (result["type"].as<std::string>() == "int" ? TE::offsetType::TPINT : result["type"].as<std::string>() == "flg" ? TE::offsetType::TPFLAG : TE::offsetType::TPSTRING);
+ TwilightEditor::Settings.TYPE = (result["type"].as<std::string>() == "int" ? TwilightEditor::offsetType::TPINT : result["type"].as<std::string>() == "flg" ? TwilightEditor::offsetType::TPFLAG : result["type"].as<std::string>() == "uflg" ? TwilightEditor::offsetType::TPUFLAG : TwilightEditor::offsetType::TPSTRING);
}
+ // --value
if (result.count("value"))
{
- TE::Settings.VALUE = result["value"].as<std::string>();
- }
- else
- {
- throw cxxopts::OptionException("Missing parameter --value");
+ TwilightEditor::Settings.STR_VALUE = result["value"].as<std::string>();
}
// -v, --verbose
- TE::Settings.VERBOSE = result["verbose"].as<bool>();
+ TwilightEditor::Settings.VERBOSE = result["verbose"].as<bool>();
// -f, --force
- TE::Settings.FORCE = result["force"].as<bool>();
+ TwilightEditor::Settings.FORCE = result["force"].as<bool>();
return result;
}
@@ -122,28 +178,93 @@ cxxopts::ParseResult parse(int argc, char* argv[])
}
}
-int main(int argc, char* argv[])
+namespace TwilightEditor
{
- auto result = parse(argc, argv);
- auto arguments = result.arguments();
+ FILE* currentFilePtr = NULL;
+ std::size_t fileSize = 0;
- std::cout << "Results:" << std::endl;
- std::cout << "Input File: " << TE::Settings.INPUT_FILE << std::endl;
- std::cout << "Output File: " << TE::Settings.OUTPUT_FILE << std::endl;
- std::cout << "Mode: " << TE::Settings.MODE << std::endl;
- std::cout << "QuestLog: " << TE::Settings.QUESTLOG << std::endl;
- std::cout << "Fix checksum: " << TE::Settings.FIX << std::endl;
+ std::string get()
+ {
+ try
+ {
+ if (Settings.OFFSET + Settings.LENGTH > fileSize)
+ {
+ throw std::runtime_error("offset + length exceeds the filesize");
+ }
+ uint8_t* buffer = new uint8_t[Settings.LENGTH];
+ fseek(currentFilePtr, Settings.OFFSET, SEEK_SET);
+ fread(buffer, sizeof(uint8_t), Settings.LENGTH, currentFilePtr);
- std::cout << "Offset: " << TE::Settings.OFFSET << std::endl;
- std::cout << "Length: " << TE::Settings.LENGTH << std::endl;
- std::cout << "Type: " << TE::Settings.TYPE << std::endl;
- std::cout << "Value: " << TE::Settings.VALUE << std::endl;
+ return TwilightEditor::Converter::toStr(buffer, Settings.TYPE, Settings.LENGTH, Converter::u8(Settings.STR_VALUE));
+ }
+ catch (const std::runtime_error& ex)
+ {
+ std::cerr << "error getting from file: " << ex.what() << std::endl;
+ exit(1);
+ }
+ catch (...)
+ {
+ std::cerr << "unknown error while getting from file" << std::endl;
+ exit(1);
+ }
+ }
- std::cout << "Verbose: " << TE::Settings.VERBOSE << std::endl;
- std::cout << "Force: " << TE::Settings.FORCE << std::endl;
+ void initFile()
+ {
+ try
+ {
+ if (!fs::exists(Settings.INPUT_FILE))
+ {
+ throw std::runtime_error("file does not exist");
+ }
- getchar();
+ fastPrint("Opening file for reading...");
+ currentFilePtr = fopen(Settings.INPUT_FILE.c_str(), "r");
+ fs::path filePath{ Settings.INPUT_FILE };
- return 0;
+ if (currentFilePtr == NULL)
+ {
+ throw std::runtime_error("file does not exist or is invalid");
+ }
+
+ fileSize = static_cast<std::size_t>(fs::file_size(filePath));
+
+ switch (fileSize)
+ {
+ case 0x8040:
+ // GCI/Container
+ fastPrint("Operating in GCI mode");
+ break;
+
+ case 0xE00:
+ // WiiU/QuestLog
+ fastPrint("Operating in Wii U mode");
+ break;
+
+ default:
+ if (!Settings.FORCE)
+ {
+ std::cout << "File could not be identified, do you want to treat it as a single QuestLog? (y/n)" << std::endl << "Is this a Questlog? ";
+ int result = getchar();
+ if (result != 'Y' && result != 'y')
+ {
+ std::cout << "Exiting application..." << std::endl;
+ exit(1);
+ }
+ }
+ break;
+ }
+ }
+ catch (const std::runtime_error& ex)
+ {
+ std::cerr << "error opening file " << Settings.INPUT_FILE << ": " << ex.what() << std::endl;
+ exit(1);
+ }
+ catch (...)
+ {
+ std::cerr << "unknown error opening file " << Settings.INPUT_FILE << std::endl;
+ exit(1);
+ }
+ }
} \ No newline at end of file
diff --git a/source/checksum.cpp b/source/checksum.cpp
new file mode 100644
index 0000000..27a7fde
--- /dev/null
+++ b/source/checksum.cpp
@@ -0,0 +1,28 @@
+#include "checksum.h"
+#include "settings.h"
+
+namespace TwilightEditor
+{
+ void checkSum(uint8_t* data, std::size_t length, uint32_t* csum, uint32_t* nsum)
+ {
+ try
+ {
+ uint32_t sum = 0;
+ uint32_t _sum = 0;
+
+ for (uint32_t i = 0; i < length; i++)
+ {
+ sum += data[i];
+ }
+ _sum = -(sum + 0x0a8c);
+
+ *csum = sum;
+ *nsum = _sum;
+ }
+ catch (...)
+ {
+ std::cout << "Fatal error during checksum calculation..." << std::endl;
+ exit(1);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/converter.cpp b/source/converter.cpp
new file mode 100644
index 0000000..a6f001b
--- /dev/null
+++ b/source/converter.cpp
@@ -0,0 +1,197 @@
+#include "converter.h"
+
+namespace TwilightEditor
+{
+ namespace Converter
+ {
+ uint32_t u32(std::string& value)
+ {
+ try
+ {
+ return static_cast<uint32_t>(std::stoul(value, nullptr, 0));
+ }
+ catch (const std::invalid_argument& ia)
+ {
+ std::cerr << "error: " << ia.what() << std::endl;
+ exit(1);
+ }
+ catch (const std::out_of_range& oor)
+ {
+ std::cerr << "error: " << oor.what() << std::endl;
+ exit(1);
+ }
+ catch (...)
+ {
+ std::cerr << "unknown error while parsing u32" << value << std::endl;
+ exit(1);
+ }
+ }
+
+ uint16_t u16(std::string& value)
+ {
+ try
+ {
+ return static_cast<uint16_t>(std::stoul(value, nullptr, 0));
+ }
+ catch (const std::invalid_argument& ia)
+ {
+ std::cerr << "error: " << ia.what() << std::endl;
+ exit(1);
+ }
+ catch (const std::out_of_range& oor)
+ {
+ std::cerr << "error: " << oor.what() << std::endl;
+ exit(1);
+ }
+ catch (...)
+ {
+ std::cerr << "unknown error while parsing u16" << value << std::endl;
+ exit(1);
+ }
+ }
+
+ uint8_t u8(std::string& value)
+ {
+ try
+ {
+ return static_cast<uint8_t>(std::stoul(value, nullptr, 0));
+ }
+ catch (const std::invalid_argument& ia)
+ {
+ std::cerr << "error: " << ia.what() << std::endl;
+ exit(1);
+ }
+ catch (const std::out_of_range& oor)
+ {
+ std::cerr << "error: " << oor.what() << std::endl;
+ exit(1);
+ }
+ catch (...)
+ {
+ std::cerr << "unknown error while parsing u8" << value << std::endl;
+ exit(1);
+ }
+ }
+
+ void flag(uint8_t* value, std::string& flag, bool set)
+ {
+ try
+ {
+ uint8_t _flag = u8(flag);
+
+ if (set)
+ {
+ // Add the flags to the value
+ *value |= _flag;
+ }
+ else
+ {
+ // Remove the flags from the value
+ *value = (*value & ~_flag);
+ }
+ }
+ catch (...)
+ {
+ std::cerr << "unknown error while " << (set ? "flagging " : "unflagging ") << value << " with " << flag << std::endl;
+ exit(1);
+ }
+ }
+
+ std::string toStr(uint8_t* data, offsetType type, std::size_t length, uint8_t flag)
+ {
+ try
+ {
+ std::string value("");
+
+ // Templates
+ bool flagstate;
+
+ std::stringstream ss;
+
+ uint16_t t16 = 0;
+ uint32_t t32 = 0;
+
+
+ if (type == offsetType::TPINT)
+ {
+ switch (length)
+ {
+ case 1:
+ value = std::to_string(data[0]);
+ if (Settings.HEX)
+ {
+ ss << std::hex << static_cast<unsigned>(data[0]);
+ value = ss.str();
+ }
+ break;
+
+ case 2:
+ t16 = (data[1]| data[0] << 8);
+ value = std::to_string(t16);
+ if (Settings.HEX)
+ {
+ ss << std::hex << t16;
+ value = ss.str();
+ }
+ break;
+
+ case 4:
+ t32 = (data[3] | data[2] << 8 | data[1] << 16 | data[0] << 24);
+ value = std::to_string(t32);
+ if (Settings.HEX)
+ {
+ ss << std::hex << t32;
+ value = ss.str();
+ }
+ break;
+
+ default:
+ throw std::runtime_error("invalid length supplied for type int");
+ break;
+ }
+ }
+
+ else if (type == offsetType::TPFLAG || type == offsetType::TPUFLAG)
+ {
+ flagstate = (flag == (data[0] & flag));
+
+ value = flagstate ? "true" : "false";
+ }
+
+ else
+ {
+ for (int i = 0; i < length; i++)
+ {
+ if (Settings.HEX)
+ {
+ // Not really optimized but functional
+ ss << std::hex << static_cast<unsigned>(data[i]) << " ";
+ value = ss.str();
+ }
+ else
+ {
+ // We're reading it as a proper string, if data[i] is null the string is terminated
+ if (data[i] == 0x0)
+ {
+ break;
+ }
+ value += data[i];
+ }
+ }
+ }
+
+ return value;
+ }
+ catch (const std::runtime_error& ex)
+ {
+ std::cerr << "error converting data to string: " << ex.what() << std::endl;
+ exit(1);
+ }
+ catch (...)
+ {
+ std::cerr << "unknown error while converting data to string" << std::endl;
+ exit(1);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/settings.cpp b/source/settings.cpp
new file mode 100644
index 0000000..a54fc1c
--- /dev/null
+++ b/source/settings.cpp
@@ -0,0 +1,6 @@
+#include "settings.h"
+
+namespace TwilightEditor
+{
+ settings Settings = { "", "", GET, 0, false, false, 0, 0, TPINT, "0", false, false };
+} \ No newline at end of file