1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
#include <evfl/ResEventFlowFile.h>
#include <evfl/ResFlowchart.h>
#include <evfl/ResTimeline.h>
#include <ore/Array.h>
#include <ore/RelocationTable.h>
#include <ore/ResDic.h>
#include <ore/ResEndian.h>
#include <ore/StringPool.h>
#include <string_view>
namespace evfl {
using ore::SwapEndian;
template <typename T>
constexpr T MakeMagic(std::string_view magic) {
T result = 0;
for (size_t i = 0; i < magic.length(); ++i)
result |= T(magic[i]) << (8 * i);
return result;
}
bool ResEventFlowFile::IsValid(void* data) {
return static_cast<ore::BinaryFileHeader*>(data)->IsValid(MakeMagic<u64>("BFEVFL"), 0, 3, 0, 0);
}
ResEventFlowFile* ResEventFlowFile::ResCast(void* data) {
auto* file = static_cast<ResEventFlowFile*>(data);
file->Relocate();
return file;
}
void ResEventFlowFile::Relocate() {
if (header.IsRelocated())
return;
auto* table = header.GetRelocationTable();
table->Relocate();
header.SetRelocated(true);
}
void ResEventFlowFile::Unrelocate() {
if (!header.IsRelocated())
return;
auto* table = header.GetRelocationTable();
table->Unrelocate();
header.SetRelocated(false);
}
static void SwapEndian(ore::ResEndian* endian, ore::StringPool* pool) {
ore::BinString* str = pool->GetFirstString();
const int num_strings = pool->GetLength();
if (endian->is_serializing) {
for (int i = 0; i < num_strings; ++i) {
auto* next = str->NextString();
SwapEndian(&str->length);
str = next;
}
} else {
for (int i = 0; i < num_strings; ++i) {
SwapEndian(&str->length);
str = str->NextString();
}
}
}
template <typename T>
static void SwapEndian(ore::ResEndian* endian, ore::BinTPtr<T>* ptr) {
if (auto* value = ptr->ToPtr(endian->base))
SwapEndian(endian, value);
}
static void SwapEndianForFileData(ore::ResEndian* endian, ResEventFlowFile* file) {
ore::Array<ore::BinTPtr<ResFlowchart>> flowcharts{file->flowcharts.ToPtr(endian->base),
file->num_flowcharts};
for (auto& flowchart : flowcharts)
SwapEndian(endian, &flowchart);
if (auto* flowchart_names = file->flowchart_names.ToPtr(endian->base))
SwapEndian(endian, flowchart_names);
ore::Array<ore::BinTPtr<ResTimeline>> timelines{file->timelines.ToPtr(endian->base),
file->num_timelines};
for (auto& timeline : timelines)
SwapEndian(endian, &timeline);
if (auto* timeline_names = file->timeline_names.ToPtr(endian->base))
SwapEndian(endian, timeline_names);
auto* string_pool =
static_cast<ore::StringPool*>(file->header.FindFirstBlock(MakeMagic<u32>("STR ")));
SwapEndian(endian, string_pool);
}
void SwapEndian(ore::ResEndian* endian, ResEventFlowFile* file) {
const auto swap_fields = [&] {
SwapEndian(&file->header.bom);
SwapEndian(&file->num_flowcharts);
SwapEndian(&file->num_timelines);
};
if (endian->is_serializing) {
SwapEndianForFileData(endian, file);
swap_fields();
} else {
swap_fields();
SwapEndianForFileData(endian, file);
}
}
} // namespace evfl
|