diff options
Diffstat (limited to 'src/godot_variant.cpp')
-rw-r--r-- | src/godot_variant.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/godot_variant.cpp b/src/godot_variant.cpp new file mode 100644 index 0000000..1bc906f --- /dev/null +++ b/src/godot_variant.cpp | |||
@@ -0,0 +1,83 @@ | |||
1 | // Godot save decoder algorithm by Chris Souvey. | ||
2 | |||
3 | #include "godot_variant.h" | ||
4 | |||
5 | #include <algorithm> | ||
6 | #include <charconv> | ||
7 | #include <cstddef> | ||
8 | #include <fstream> | ||
9 | #include <string> | ||
10 | #include <tuple> | ||
11 | #include <variant> | ||
12 | #include <vector> | ||
13 | |||
14 | namespace { | ||
15 | |||
16 | uint16_t ReadUint16(std::basic_istream<char>& stream) { | ||
17 | uint16_t result; | ||
18 | stream.read(reinterpret_cast<char*>(&result), 2); | ||
19 | return result; | ||
20 | } | ||
21 | |||
22 | uint32_t ReadUint32(std::basic_istream<char>& stream) { | ||
23 | uint32_t result; | ||
24 | stream.read(reinterpret_cast<char*>(&result), 4); | ||
25 | return result; | ||
26 | } | ||
27 | |||
28 | GodotVariant ParseVariant(std::basic_istream<char>& stream) { | ||
29 | uint16_t type = ReadUint16(stream); | ||
30 | stream.ignore(2); | ||
31 | |||
32 | switch (type) { | ||
33 | case 1: { | ||
34 | // bool | ||
35 | bool boolval = (ReadUint32(stream) == 1); | ||
36 | return {boolval}; | ||
37 | } | ||
38 | case 15: { | ||
39 | // nodepath | ||
40 | uint32_t name_length = ReadUint32(stream) & 0x7fffffff; | ||
41 | uint32_t subname_length = ReadUint32(stream) & 0x7fffffff; | ||
42 | uint32_t flags = ReadUint32(stream); | ||
43 | |||
44 | std::vector<std::string> result; | ||
45 | for (size_t i = 0; i < name_length + subname_length; i++) { | ||
46 | uint32_t char_length = ReadUint32(stream); | ||
47 | uint32_t padded_length = (char_length % 4 == 0) | ||
48 | ? char_length | ||
49 | : (char_length + 4 - (char_length % 4)); | ||
50 | std::vector<char> next_bytes(padded_length); | ||
51 | stream.read(next_bytes.data(), padded_length); | ||
52 | std::string next_piece; | ||
53 | std::copy(next_bytes.begin(), | ||
54 | std::next(next_bytes.begin(), char_length), | ||
55 | std::back_inserter(next_piece)); | ||
56 | result.push_back(next_piece); | ||
57 | } | ||
58 | |||
59 | return {result}; | ||
60 | } | ||
61 | case 19: { | ||
62 | // array | ||
63 | uint32_t length = ReadUint32(stream) & 0x7fffffff; | ||
64 | std::vector<GodotVariant> result; | ||
65 | for (size_t i = 0; i < length; i++) { | ||
66 | result.push_back(ParseVariant(stream)); | ||
67 | } | ||
68 | return {result}; | ||
69 | } | ||
70 | default: { | ||
71 | // eh | ||
72 | return {std::monostate{}}; | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | } // namespace | ||
78 | |||
79 | GodotVariant ParseGodotFile(std::string filename) { | ||
80 | std::ifstream file_stream(filename, std::ios_base::binary); | ||
81 | file_stream.ignore(4); | ||
82 | return ParseVariant(file_stream); | ||
83 | } | ||