-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathembedresource.cpp
181 lines (155 loc) · 6.32 KB
/
embedresource.cpp
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include "EmbeddedResource.h"
#if defined _MSC_VER
#pragma warning(push, 3)
#pragma warning(disable : 5262) /*xlocale(2010,13): implicit fall-through occurs here*/
#endif
#include <algorithm>
#include <cctype>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
#if defined _MSC_VER
#pragma warning(pop)
#endif
static std::string FilePathToSym(std::filesystem::path filepath)
{
auto sym = filepath.filename().string();
replace(sym.begin(), sym.end(), '.', '_');
replace(sym.begin(), sym.end(), '-', '_');
if (std::isdigit(sym[0])) { return "_" + sym; }
return sym;
}
struct Content
{
std::filesystem::path fpath;
std::string resname;
std::string symname;
Content(std::string_view const& spec)
{
// If name is resname!filepath use resname or else convert filename into a symbol
size_t idx = static_cast<size_t>(spec.find('!'));
if (idx == std::string::npos)
{
fpath = spec;
resname = fpath.filename().string();
symname = FilePathToSym(fpath);
}
else
{
if (idx == 0) { throw std::invalid_argument("Invalid name for resource: " + std::string(spec)); }
fpath = std::filesystem::path(std::string(spec.substr(idx + 1)));
resname = std::string_view(spec.data(), idx);
symname = FilePathToSym(fpath);
}
}
};
#define NL "\n"
static void HandleArg(std::vector<Content>& contents, std::string_view const& arg)
{
if (arg.size() == 0) return;
if (arg[0] == '@')
{
auto src = std::filesystem::path(arg.substr(1));
std::ifstream ifs(src);
if (!ifs.is_open()) { throw std::invalid_argument("Cannot find file: " + src.string()); }
if (ifs.fail()) { throw std::logic_error("file corrupt: " + src.string()); }
std::string line;
while (std::getline(ifs, line)) { contents.push_back(Content(line)); }
}
else { contents.push_back(Content(arg)); }
}
#if defined __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif
int main(int argc, char** argv)
try
{
if (argc < 3)
{
for (int i = 0; i < argc; i++) { std::cerr << " " << argv[i]; }
std::cerr << NL << NL << "USAGE: %s {sym} {rsrc}..." << NL << NL << " Creates {sym}.c from the contents of each {rsrc}\n"
<< " Each resource {rsrc} can be specified in the format [name!]filepath" << argv[0];
return EXIT_FAILURE;
}
std::filesystem::path dst{argv[1]};
#if defined __clang__
#pragma clang diagnostic pop
#endif
create_directories(dst.parent_path());
std::ofstream ofs{dst.string()};
ofs << R"(
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-macros"
#define EMBEDDED_RESOURCE_EXPORTED_API_IMPL 1
#pragma clang diagnostic pop
#endif
#include <EmbeddedResource.h>
)";
auto colsym = FilePathToSym(dst.stem());
std::vector<std::string> symbols;
std::vector<Content> args;
for (int i = 2; i < argc; i++) HandleArg(args, std::string_view(argv[i]));
for (auto const& arg : args)
{
auto [src, resname, sym] = arg;
std::ifstream ifs{src, std::ios::binary | std::ios::in};
if (!ifs.is_open()) { throw std::invalid_argument("Cannot find file" + src.string()); }
if (ifs.fail()) { throw std::logic_error("file corrupt: " + src.string()); }
uint8_t c;
ifs.read(reinterpret_cast<char*>(&c), sizeof(c));
if (ifs.fail()) { continue; }
symbols.push_back(FilePathToSym(src));
ofs << "namespace EmbeddedResource::Data::" << colsym << "::Resources::" << sym << " {" << NL;
ofs << "static constexpr uint8_t _ResourceData[] = {" << NL;
for (size_t j = 0; !ifs.eof() && !ifs.fail(); j++, ifs.read(reinterpret_cast<char*>(&c), sizeof(c)))
{
if (j > 0) { ofs << ","; }
ofs << "0x" << std::hex << static_cast<uint32_t>(c) << "u";
if ((j + 1) % 10 == 0) { ofs << NL; }
}
ofs << "};" << NL;
ofs << "static constexpr std::wstring_view _ResourceName = L\"" << resname << "\";" << NL;
ofs << "}" << NL << NL;
}
for (const auto& ressym : symbols) { ofs << "DECLARE_RESOURCE(" << colsym << "," << ressym << ");" << NL; }
for (const auto& ressym : symbols)
{
ofs << "DECLARE_RESOURCE(" << colsym << "," << ressym << ")" << NL;
ofs << "{" << NL;
ofs << " auto nameptr = EmbeddedResource::Data::" << colsym << "::Resources::" << ressym << "::_ResourceName.data();" << NL;
ofs << " auto namelen = EmbeddedResource::Data::" << colsym << "::Resources::" << ressym << "::_ResourceName.size();" << NL;
ofs << " auto dataptr = EmbeddedResource::Data::" << colsym << "::Resources::" << ressym << "::_ResourceData;" << NL;
ofs << " auto datalen = std::size(EmbeddedResource::Data::" << colsym << "::Resources::" << ressym << "::_ResourceData);" << NL;
ofs << " return EmbeddedResource::ABI::ResourceInfo { { nameptr, namelen }, { dataptr, datalen } };" << NL;
ofs << "}" << NL;
}
ofs << "namespace EmbeddedResource::Data::" << colsym << " {" << NL;
ofs << "static constexpr EmbeddedResource::ABI::GetCollectionResourceInfo * const _ResourceTable[] = {" << NL;
bool first = true;
for (const auto& ressym : symbols)
{
if (!first) { ofs << ","; }
else { first = false; }
ofs << "EMBEDDEDRESOURCE_ABI_RESOURCE_FUNCNAME(" << colsym << "," << ressym << ", GetCollectionResourceInfo)" << NL;
}
ofs << "};" << NL;
ofs << "}" << NL;
ofs << "DECLARE_RESOURCE_COLLECTION(" << colsym << ");" << NL;
ofs << "DECLARE_RESOURCE_COLLECTION(" << colsym << ")" << NL;
ofs << "{" << NL;
ofs << " auto tableptr = EmbeddedResource::Data::" << colsym << "::_ResourceTable;" << NL;
ofs << " auto tablelen = std::size(EmbeddedResource::Data::" << colsym << "::_ResourceTable);" << NL;
ofs << " return EmbeddedResource::ABI::Data<EmbeddedResource::ABI::GetCollectionResourceInfo*> {tableptr, tablelen };" << NL;
ofs << "}" << NL;
ofs.close();
return EXIT_SUCCESS;
} catch (std::exception const& ex)
{
std::cerr << ex.what() << NL;
return -1;
}