Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/windows/export/template_modifier.cpp
20871 views
1
/**************************************************************************/
2
/* template_modifier.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "template_modifier.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/io/dir_access.h"
35
#include "core/io/image.h"
36
37
void TemplateModifier::ByteStream::save(uint8_t p_value, Vector<uint8_t> &r_bytes) const {
38
save(p_value, r_bytes, 1);
39
}
40
41
void TemplateModifier::ByteStream::save(uint16_t p_value, Vector<uint8_t> &r_bytes) const {
42
save(p_value, r_bytes, 2);
43
}
44
45
void TemplateModifier::ByteStream::save(uint32_t p_value, Vector<uint8_t> &r_bytes) const {
46
save(p_value, r_bytes, 4);
47
}
48
49
void TemplateModifier::ByteStream::save(const String &p_value, Vector<uint8_t> &r_bytes) const {
50
r_bytes.append_array(p_value.to_utf16_buffer());
51
save((uint16_t)0, r_bytes);
52
}
53
54
void TemplateModifier::ByteStream::save(uint32_t p_value, Vector<uint8_t> &r_bytes, uint32_t p_count) const {
55
for (uint32_t i = 0; i < p_count; i++) {
56
r_bytes.append((uint8_t)(p_value & 0xff));
57
p_value >>= 8;
58
}
59
}
60
61
Vector<uint8_t> TemplateModifier::ByteStream::save() const {
62
return Vector<uint8_t>();
63
}
64
65
Vector<uint8_t> TemplateModifier::Structure::save() const {
66
Vector<uint8_t> bytes;
67
ByteStream::save(length, bytes);
68
ByteStream::save(value_length, bytes);
69
ByteStream::save(type, bytes);
70
ByteStream::save(key, bytes);
71
while (bytes.size() % 4) {
72
bytes.append(0);
73
}
74
return bytes;
75
}
76
77
Vector<uint8_t> &TemplateModifier::Structure::add_length(Vector<uint8_t> &r_bytes) const {
78
r_bytes.write[0] = r_bytes.size() & 0xff;
79
r_bytes.write[1] = r_bytes.size() >> 8 & 0xff;
80
return r_bytes;
81
}
82
83
Vector<uint8_t> TemplateModifier::ResourceDirectoryTable::save() const {
84
Vector<uint8_t> bytes;
85
bytes.resize_initialized(12);
86
ByteStream::save(name_entry_count, bytes);
87
ByteStream::save(id_entry_count, bytes);
88
return bytes;
89
}
90
91
Vector<uint8_t> TemplateModifier::ResourceDirectoryEntry::save() const {
92
Vector<uint8_t> bytes;
93
ByteStream::save(id | (name ? HIGH_BIT : 0), bytes);
94
ByteStream::save(data_offset | (subdirectory ? HIGH_BIT : 0), bytes);
95
return bytes;
96
}
97
98
Vector<uint8_t> TemplateModifier::FixedFileInfo::save() const {
99
Vector<uint8_t> bytes;
100
ByteStream::save(signature, bytes);
101
ByteStream::save(struct_version, bytes);
102
ByteStream::save(file_version_ms, bytes);
103
ByteStream::save(file_version_ls, bytes);
104
ByteStream::save(product_version_ms, bytes);
105
ByteStream::save(product_version_ls, bytes);
106
ByteStream::save(file_flags_mask, bytes);
107
ByteStream::save(file_flags, bytes);
108
ByteStream::save(file_os, bytes);
109
ByteStream::save(file_type, bytes);
110
ByteStream::save(file_subtype, bytes);
111
ByteStream::save(file_date_ms, bytes);
112
ByteStream::save(file_date_ls, bytes);
113
return bytes;
114
}
115
116
void TemplateModifier::FixedFileInfo::set_file_version(const String &p_file_version) {
117
Vector<String> parts = p_file_version.split(".");
118
while (parts.size() < 4) {
119
parts.append("0");
120
}
121
file_version_ms = parts[0].to_int() << 16 | (parts[1].to_int() & 0xffff);
122
file_version_ls = parts[2].to_int() << 16 | (parts[3].to_int() & 0xffff);
123
}
124
125
void TemplateModifier::FixedFileInfo::set_product_version(const String &p_product_version) {
126
Vector<String> parts = p_product_version.split(".");
127
while (parts.size() < 4) {
128
parts.append("0");
129
}
130
product_version_ms = parts[0].to_int() << 16 | (parts[1].to_int() & 0xffff);
131
product_version_ls = parts[2].to_int() << 16 | (parts[3].to_int() & 0xffff);
132
}
133
134
Vector<uint8_t> TemplateModifier::StringStructure::save() const {
135
Vector<uint8_t> bytes = Structure::save();
136
ByteStream::save(value, bytes);
137
return add_length(bytes);
138
}
139
140
TemplateModifier::StringStructure::StringStructure() {
141
type = 1;
142
}
143
144
TemplateModifier::StringStructure::StringStructure(const String &p_key, const String &p_value) {
145
type = 1;
146
value_length = p_value.length() + 1;
147
key = p_key;
148
value = p_value;
149
}
150
151
Vector<uint8_t> TemplateModifier::StringTable::save() const {
152
Vector<uint8_t> bytes = Structure::save();
153
for (const StringStructure &string : strings) {
154
bytes.append_array(string.save());
155
while (bytes.size() % 4) {
156
bytes.append(0);
157
}
158
}
159
return add_length(bytes);
160
}
161
162
void TemplateModifier::StringTable::put(const String &p_key, const String &p_value) {
163
strings.append(StringStructure(p_key, p_value));
164
}
165
166
TemplateModifier::StringTable::StringTable() {
167
key = "040904b0";
168
type = 1;
169
}
170
171
TemplateModifier::StringFileInfo::StringFileInfo() {
172
key = "StringFileInfo";
173
value_length = 0;
174
type = 1;
175
}
176
177
Vector<uint8_t> TemplateModifier::StringFileInfo::save() const {
178
Vector<uint8_t> bytes = Structure::save();
179
bytes.append_array(string_table.save());
180
return add_length(bytes);
181
}
182
183
Vector<uint8_t> TemplateModifier::Var::save() const {
184
Vector<uint8_t> bytes = Structure::save();
185
ByteStream::save(value, bytes);
186
return add_length(bytes);
187
}
188
189
TemplateModifier::Var::Var() {
190
value_length = 4;
191
key = "Translation";
192
}
193
194
Vector<uint8_t> TemplateModifier::VarFileInfo::save() const {
195
Vector<uint8_t> bytes = Structure::save();
196
bytes.append_array(var.save());
197
return add_length(bytes);
198
}
199
200
TemplateModifier::VarFileInfo::VarFileInfo() {
201
type = 1;
202
key = "VarFileInfo";
203
}
204
205
Vector<uint8_t> TemplateModifier::VersionInfo::save() const {
206
Vector<uint8_t> fixed_file_info = value.save();
207
Vector<uint8_t> bytes = Structure::save();
208
bytes.append_array(fixed_file_info);
209
bytes.append_array(string_file_info.save());
210
while (bytes.size() % 4) {
211
bytes.append(0);
212
}
213
bytes.append_array(var_file_info.save());
214
return add_length(bytes);
215
}
216
217
TemplateModifier::VersionInfo::VersionInfo() {
218
key = "VS_VERSION_INFO";
219
value_length = 52;
220
}
221
222
Vector<uint8_t> TemplateModifier::ManifestInfo::save() const {
223
Vector<uint8_t> bytes = manifest.to_utf8_buffer();
224
return bytes;
225
}
226
227
Vector<uint8_t> TemplateModifier::IconEntry::save() const {
228
Vector<uint8_t> bytes;
229
ByteStream::save(width, bytes);
230
ByteStream::save(height, bytes);
231
ByteStream::save(colors, bytes);
232
ByteStream::save((uint8_t)0, bytes);
233
ByteStream::save(planes, bytes);
234
ByteStream::save(bits_per_pixel, bytes);
235
ByteStream::save(image_size, bytes);
236
ByteStream::save((uint16_t)image_offset, bytes);
237
return bytes;
238
}
239
240
void TemplateModifier::IconEntry::load(Ref<FileAccess> p_file) {
241
width = p_file->get_8(); // Width in pixels.
242
height = p_file->get_8(); // Height in pixels.
243
colors = p_file->get_8(); // Number of colors in the palette (0 - no palette).
244
p_file->get_8(); // Reserved.
245
planes = p_file->get_16(); // Number of color planes.
246
bits_per_pixel = p_file->get_16(); // Bits per pixel.
247
image_size = p_file->get_32(); // Image data size in bytes.
248
image_offset = p_file->get_32(); // Image data offset.
249
}
250
251
Vector<uint8_t> TemplateModifier::GroupIcon::save() const {
252
Vector<uint8_t> bytes;
253
ByteStream::save(reserved, bytes);
254
ByteStream::save(type, bytes);
255
ByteStream::save(image_count, bytes);
256
for (const IconEntry &icon_entry : icon_entries) {
257
bytes.append_array(icon_entry.save());
258
}
259
return bytes;
260
}
261
262
void TemplateModifier::GroupIcon::load(Ref<FileAccess> p_icon_file) {
263
if (p_icon_file->get_32() != 0x10000) { // Wrong reserved bytes
264
ERR_FAIL_MSG("Wrong icon file type.");
265
}
266
267
image_count = p_icon_file->get_16();
268
for (uint16_t i = 0; i < image_count; i++) {
269
IconEntry icon_entry;
270
icon_entry.load(p_icon_file);
271
icon_entries.append(icon_entry);
272
}
273
274
int id = 1;
275
for (IconEntry &icon_entry : icon_entries) {
276
Vector<uint8_t> image;
277
image.resize(icon_entry.image_size);
278
p_icon_file->seek(icon_entry.image_offset);
279
p_icon_file->get_buffer(image.ptrw(), image.size());
280
icon_entry.image_offset = id++;
281
images.append(image);
282
}
283
}
284
285
void TemplateModifier::GroupIcon::fill_with_godot_blue() {
286
uint32_t id = 1;
287
for (uint8_t size : SIZES) {
288
Ref<Image> image = Image::create_empty(size ? size : 256, size ? size : 256, false, Image::FORMAT_RGB8);
289
image->fill(Color::hex(0x478cbfff));
290
Vector<uint8_t> data = image->save_png_to_buffer();
291
IconEntry icon_entry;
292
icon_entry.width = size;
293
icon_entry.height = size;
294
icon_entry.bits_per_pixel = 24;
295
icon_entry.image_size = data.size();
296
icon_entry.image_offset = id++;
297
icon_entries.append(icon_entry);
298
images.append(data);
299
}
300
}
301
302
Vector<uint8_t> TemplateModifier::SectionEntry::save() const {
303
Vector<uint8_t> bytes;
304
bytes.append_array(name.to_utf8_buffer());
305
while (bytes.size() < 8) {
306
bytes.append(0);
307
}
308
ByteStream::save(virtual_size, bytes);
309
ByteStream::save(virtual_address, bytes);
310
ByteStream::save(size_of_raw_data, bytes);
311
ByteStream::save(pointer_to_raw_data, bytes);
312
ByteStream::save(pointer_to_relocations, bytes);
313
ByteStream::save(pointer_to_line_numbers, bytes);
314
ByteStream::save(number_of_relocations, bytes);
315
ByteStream::save(number_of_line_numbers, bytes);
316
ByteStream::save(characteristics, bytes);
317
return bytes;
318
}
319
320
void TemplateModifier::SectionEntry::load(Ref<FileAccess> p_file) {
321
uint8_t section_name[8];
322
p_file->get_buffer(section_name, 8);
323
name = String::utf8((char *)section_name, 8);
324
virtual_size = p_file->get_32();
325
virtual_address = p_file->get_32();
326
size_of_raw_data = p_file->get_32();
327
pointer_to_raw_data = p_file->get_32();
328
pointer_to_relocations = p_file->get_32();
329
pointer_to_line_numbers = p_file->get_32();
330
number_of_relocations = p_file->get_16();
331
number_of_line_numbers = p_file->get_16();
332
characteristics = p_file->get_32();
333
}
334
335
Vector<uint8_t> TemplateModifier::ResourceDataEntry::save() const {
336
Vector<uint8_t> bytes;
337
ByteStream::save(rva, bytes);
338
ByteStream::save(size, bytes);
339
ByteStream::save(0, bytes, 8);
340
return bytes;
341
}
342
343
uint32_t TemplateModifier::_get_pe_header_offset(Ref<FileAccess> p_executable) const {
344
p_executable->seek(POINTER_TO_PE_HEADER_OFFSET);
345
uint32_t pe_header_offset = p_executable->get_32();
346
347
p_executable->seek(pe_header_offset);
348
uint32_t magic = p_executable->get_32();
349
350
return magic == 0x00004550 ? pe_header_offset : 0;
351
}
352
353
uint32_t TemplateModifier::_snap(uint32_t p_value, uint32_t p_size) const {
354
return p_value + (p_value % p_size ? p_size - (p_value % p_size) : 0);
355
}
356
357
Vector<uint8_t> TemplateModifier::_create_resources(uint32_t p_virtual_address, const GroupIcon &p_group_icon, const VersionInfo &p_version_info, const ManifestInfo &p_manifest_info) const {
358
// 0x04, 0x00 as string length ICON in UTF16 and padding to 32 bits
359
const uint8_t ICON_DIRECTORY_STRING[] = { 0x04, 0x00, 0x49, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x4e, 0x00, 0x00, 0x00 };
360
const uint16_t RT_ENTRY_COUNT = 4;
361
const uint32_t icon_count = p_group_icon.images.size();
362
363
ResourceDirectoryTable root_directory_table;
364
root_directory_table.id_entry_count = RT_ENTRY_COUNT;
365
366
Vector<uint8_t> resources = root_directory_table.save();
367
368
ResourceDirectoryEntry rt_icon_entry;
369
rt_icon_entry.id = ResourceDirectoryEntry::ICON;
370
rt_icon_entry.data_offset = ResourceDirectoryTable::SIZE + RT_ENTRY_COUNT * ResourceDirectoryEntry::SIZE;
371
rt_icon_entry.subdirectory = true;
372
resources.append_array(rt_icon_entry.save());
373
374
ResourceDirectoryEntry rt_group_icon_entry;
375
rt_group_icon_entry.id = ResourceDirectoryEntry::GROUP_ICON;
376
rt_group_icon_entry.data_offset = (2 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count) * ResourceDirectoryEntry::SIZE;
377
rt_group_icon_entry.subdirectory = true;
378
resources.append_array(rt_group_icon_entry.save());
379
380
ResourceDirectoryEntry rt_version_entry;
381
rt_version_entry.id = ResourceDirectoryEntry::VERSION;
382
rt_version_entry.data_offset = (4 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 2) * ResourceDirectoryEntry::SIZE;
383
rt_version_entry.subdirectory = true;
384
resources.append_array(rt_version_entry.save());
385
386
ResourceDirectoryEntry rt_manifest_entry;
387
rt_manifest_entry.id = ResourceDirectoryEntry::MANIFEST;
388
rt_manifest_entry.data_offset = (6 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 4) * ResourceDirectoryEntry::SIZE;
389
rt_manifest_entry.subdirectory = true;
390
resources.append_array(rt_manifest_entry.save());
391
392
ResourceDirectoryTable icon_table;
393
icon_table.id_entry_count = icon_count;
394
resources.append_array(icon_table.save());
395
396
for (uint32_t i = 0; i < icon_count; i++) {
397
ResourceDirectoryEntry icon_entry;
398
icon_entry.id = i + 1;
399
icon_entry.data_offset = (2 + i) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + icon_count + i) * ResourceDirectoryEntry::SIZE;
400
icon_entry.subdirectory = true;
401
resources.append_array(icon_entry.save());
402
}
403
404
for (uint32_t i = 0; i < icon_count; i++) {
405
ResourceDirectoryTable language_icon_table;
406
language_icon_table.id_entry_count = 1;
407
resources.append_array(language_icon_table.save());
408
409
ResourceDirectoryEntry language_icon_entry;
410
language_icon_entry.id = ResourceDirectoryEntry::ENGLISH;
411
language_icon_entry.data_offset = (8 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + icon_count * 2 + 6) * ResourceDirectoryEntry::SIZE + sizeof(ICON_DIRECTORY_STRING) + i * ResourceDataEntry::SIZE;
412
resources.append_array(language_icon_entry.save());
413
}
414
415
ResourceDirectoryTable group_icon_name_table;
416
group_icon_name_table.name_entry_count = 1;
417
resources.append_array(group_icon_name_table.save());
418
419
ResourceDirectoryEntry group_icon_name_entry;
420
group_icon_name_entry.id = (6 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + icon_count * 2 + 4) * ResourceDirectoryEntry::SIZE;
421
group_icon_name_entry.data_offset = (3 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 1) * ResourceDirectoryEntry::SIZE;
422
group_icon_name_entry.name = true;
423
group_icon_name_entry.subdirectory = true;
424
resources.append_array(group_icon_name_entry.save());
425
426
ResourceDirectoryTable group_icon_language_table;
427
group_icon_language_table.id_entry_count = 1;
428
resources.append_array(group_icon_language_table.save());
429
430
ResourceDirectoryEntry group_icon_language_entry;
431
group_icon_language_entry.id = ResourceDirectoryEntry::ENGLISH;
432
group_icon_language_entry.data_offset = (8 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 6) * ResourceDirectoryEntry::SIZE + sizeof(ICON_DIRECTORY_STRING) + icon_count * ResourceDataEntry::SIZE;
433
resources.append_array(group_icon_language_entry.save());
434
435
ResourceDirectoryTable version_table;
436
version_table.id_entry_count = 1;
437
resources.append_array(version_table.save());
438
439
ResourceDirectoryEntry version_entry;
440
version_entry.id = 1;
441
version_entry.data_offset = (5 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 3) * ResourceDirectoryEntry::SIZE;
442
version_entry.subdirectory = true;
443
resources.append_array(version_entry.save());
444
445
ResourceDirectoryTable version_language_table;
446
version_language_table.id_entry_count = 1;
447
resources.append_array(version_language_table.save());
448
449
ResourceDirectoryEntry version_language_entry;
450
version_language_entry.id = ResourceDirectoryEntry::ENGLISH;
451
version_language_entry.data_offset = (8 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 6) * ResourceDirectoryEntry::SIZE + sizeof(ICON_DIRECTORY_STRING) + (icon_count + 1) * ResourceDataEntry::SIZE;
452
resources.append_array(version_language_entry.save());
453
454
ResourceDirectoryTable manifest_table;
455
manifest_table.id_entry_count = 1;
456
resources.append_array(manifest_table.save());
457
458
ResourceDirectoryEntry manifest_entry;
459
manifest_entry.id = 1;
460
manifest_entry.data_offset = (7 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 5) * ResourceDirectoryEntry::SIZE;
461
manifest_entry.subdirectory = true;
462
resources.append_array(manifest_entry.save());
463
464
ResourceDirectoryTable manifest_language_table;
465
manifest_language_table.id_entry_count = 1;
466
resources.append_array(manifest_language_table.save());
467
468
ResourceDirectoryEntry manifest_language_entry;
469
manifest_language_entry.id = ResourceDirectoryEntry::ENGLISH;
470
manifest_language_entry.data_offset = (8 + icon_count) * ResourceDirectoryTable::SIZE + (RT_ENTRY_COUNT + 2 * icon_count + 6) * ResourceDirectoryEntry::SIZE + sizeof(ICON_DIRECTORY_STRING) + (icon_count + 2) * ResourceDataEntry::SIZE;
471
resources.append_array(manifest_language_entry.save());
472
473
Vector<uint8_t> icon_directory_string;
474
icon_directory_string.resize(sizeof(ICON_DIRECTORY_STRING));
475
memcpy(icon_directory_string.ptrw(), ICON_DIRECTORY_STRING, sizeof(ICON_DIRECTORY_STRING));
476
resources.append_array(icon_directory_string);
477
478
Vector<Vector<uint8_t>> data_entries;
479
for (const Vector<uint8_t> &image : p_group_icon.images) {
480
data_entries.append(image);
481
}
482
data_entries.append(p_group_icon.save());
483
data_entries.append(p_version_info.save());
484
data_entries.append(p_manifest_info.save());
485
486
uint32_t offset = resources.size() + data_entries.size() * ResourceDataEntry::SIZE;
487
488
for (const Vector<uint8_t> &data_entry : data_entries) {
489
ResourceDataEntry resource_data_entry;
490
resource_data_entry.rva = p_virtual_address + offset;
491
resource_data_entry.size = data_entry.size();
492
resources.append_array(resource_data_entry.save());
493
offset += resource_data_entry.size;
494
while (offset % 4) {
495
offset += 1;
496
}
497
}
498
499
for (const Vector<uint8_t> &data_entry : data_entries) {
500
resources.append_array(data_entry);
501
while (resources.size() % 4) {
502
resources.append(0);
503
}
504
}
505
506
return resources;
507
}
508
509
TemplateModifier::VersionInfo TemplateModifier::_create_version_info(const HashMap<String, String> &p_strings) const {
510
StringTable string_table;
511
for (const KeyValue<String, String> &E : p_strings) {
512
string_table.put(E.key, E.value);
513
}
514
515
StringFileInfo string_file_info;
516
string_file_info.string_table = string_table;
517
518
FixedFileInfo fixed_file_info;
519
if (p_strings.has("FileVersion")) {
520
fixed_file_info.set_file_version(p_strings["FileVersion"]);
521
}
522
if (p_strings.has("ProductVersion")) {
523
fixed_file_info.set_product_version(p_strings["ProductVersion"]);
524
}
525
526
VersionInfo version_info;
527
version_info.value = fixed_file_info;
528
version_info.string_file_info = string_file_info;
529
530
return version_info;
531
}
532
533
TemplateModifier::ManifestInfo TemplateModifier::_create_manifest_info() const {
534
ManifestInfo manifest_info;
535
manifest_info.manifest = R"MANIFEST(<?xml version="1.0" encoding="utf-8"?>
536
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
537
<application xmlns="urn:schemas-microsoft-com:asm.v3">
538
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
539
<ws2:longPathAware>true</ws2:longPathAware>
540
</windowsSettings>
541
</application>
542
<dependency>
543
<dependentAssembly>
544
<assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'/>
545
</dependentAssembly>
546
</dependency>
547
</assembly>)MANIFEST";
548
return manifest_info;
549
}
550
551
TemplateModifier::GroupIcon TemplateModifier::_create_group_icon(const String &p_icon_path) const {
552
GroupIcon group_icon;
553
554
Ref<FileAccess> icon_file = FileAccess::open(p_icon_path, FileAccess::READ);
555
if (icon_file.is_null()) {
556
group_icon.fill_with_godot_blue();
557
return group_icon;
558
}
559
560
group_icon.load(icon_file);
561
562
return group_icon;
563
}
564
565
Error TemplateModifier::_truncate(const String &p_path, uint32_t p_size) const {
566
Error error;
567
568
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &error);
569
ERR_FAIL_COND_V(error != OK, ERR_CANT_OPEN);
570
571
String truncated_path = p_path + ".truncated";
572
Ref<FileAccess> truncated = FileAccess::open(truncated_path, FileAccess::WRITE, &error);
573
ERR_FAIL_COND_V(error != OK, ERR_CANT_CREATE);
574
575
truncated->store_buffer(file->get_buffer(p_size));
576
577
file->close();
578
truncated->close();
579
580
DirAccess::remove_absolute(p_path);
581
DirAccess::rename_absolute(truncated_path, p_path);
582
583
return error;
584
}
585
586
HashMap<String, String> TemplateModifier::_get_strings(const Ref<EditorExportPreset> &p_preset) const {
587
String file_version = p_preset->get_version("application/file_version", true);
588
String product_version = p_preset->get_version("application/product_version", true);
589
String company_name = p_preset->get("application/company_name");
590
String product_name = p_preset->get("application/product_name");
591
String file_description = p_preset->get("application/file_description");
592
String copyright = p_preset->get("application/copyright");
593
String trademarks = p_preset->get("application/trademarks");
594
595
HashMap<String, String> strings;
596
if (!file_version.is_empty()) {
597
strings["FileVersion"] = file_version;
598
}
599
if (!product_version.is_empty()) {
600
strings["ProductVersion"] = product_version;
601
}
602
if (!company_name.is_empty()) {
603
strings["CompanyName"] = company_name;
604
}
605
if (!product_name.is_empty()) {
606
strings["ProductName"] = product_name;
607
}
608
if (!file_description.is_empty()) {
609
strings["FileDescription"] = file_description;
610
}
611
if (!copyright.is_empty()) {
612
strings["LegalCopyright"] = copyright;
613
}
614
if (!trademarks.is_empty()) {
615
strings["LegalTrademarks"] = trademarks;
616
}
617
618
return strings;
619
}
620
621
Error TemplateModifier::_modify_template(const Ref<EditorExportPreset> &p_preset, const String &p_template_path, const String &p_icon_path) const {
622
Error error;
623
Ref<FileAccess> template_file = FileAccess::open(p_template_path, FileAccess::READ_WRITE, &error);
624
ERR_FAIL_COND_V(error != OK, ERR_CANT_OPEN);
625
626
Vector<SectionEntry> section_entries = _get_section_entries(template_file);
627
ERR_FAIL_COND_V(section_entries.size() < 2, ERR_CANT_OPEN);
628
629
// Find resource (".rsrc") and relocation (".reloc") sections, usually last two, but ".debug_*" sections (referenced as "/[n]"), symbol table, and string table can follow.
630
int resource_index = section_entries.size() - 2;
631
int relocations_index = section_entries.size() - 1;
632
for (int i = 0; i < section_entries.size(); i++) {
633
if (section_entries[i].name == ".rsrc") {
634
resource_index = i;
635
} else if (section_entries[i].name == ".reloc") {
636
relocations_index = i;
637
}
638
}
639
640
ERR_FAIL_COND_V(section_entries[resource_index].name != ".rsrc", ERR_CANT_OPEN);
641
ERR_FAIL_COND_V(section_entries[relocations_index].name != ".reloc", ERR_CANT_OPEN);
642
643
uint64_t original_template_size = template_file->get_length();
644
645
GroupIcon group_icon = _create_group_icon(p_icon_path);
646
647
VersionInfo version_info = _create_version_info(_get_strings(p_preset));
648
ManifestInfo manifest_info = _create_manifest_info();
649
650
SectionEntry &resources_section_entry = section_entries.write[resource_index];
651
uint32_t old_resources_size_of_raw_data = resources_section_entry.size_of_raw_data;
652
Vector<uint8_t> resources = _create_resources(resources_section_entry.virtual_address, group_icon, version_info, manifest_info);
653
resources_section_entry.virtual_size = resources.size();
654
resources.resize_initialized(_snap(resources.size(), BLOCK_SIZE));
655
resources_section_entry.size_of_raw_data = resources.size();
656
657
int32_t raw_size_delta = resources_section_entry.size_of_raw_data - old_resources_size_of_raw_data;
658
uint32_t old_last_section_virtual_address = section_entries.get(section_entries.size() - 1).virtual_address;
659
660
// Some data (e.g. DWARF debug symbols) can be placed after the last section.
661
uint32_t old_footer_offset = section_entries.get(section_entries.size() - 1).pointer_to_raw_data + section_entries.get(section_entries.size() - 1).size_of_raw_data;
662
663
// Copy and update sections after ".rsrc".
664
Vector<Vector<uint8_t>> moved_section_data;
665
uint32_t prev_virtual_address = resources_section_entry.virtual_address;
666
uint32_t prev_virtual_size = resources_section_entry.virtual_size;
667
for (int i = resource_index + 1; i < section_entries.size(); i++) {
668
SectionEntry &section_entry = section_entries.write[i];
669
template_file->seek(section_entry.pointer_to_raw_data);
670
Vector<uint8_t> data = template_file->get_buffer(section_entry.size_of_raw_data);
671
moved_section_data.push_back(data);
672
section_entry.pointer_to_raw_data += raw_size_delta;
673
section_entry.virtual_address = prev_virtual_address + _snap(prev_virtual_size, PE_PAGE_SIZE);
674
prev_virtual_address = section_entry.virtual_address;
675
prev_virtual_size = section_entry.virtual_size;
676
}
677
678
// Copy COFF symbol table and string table after the last section.
679
uint32_t footer_size = template_file->get_length() - old_footer_offset;
680
template_file->seek(old_footer_offset);
681
Vector<uint8_t> footer;
682
if (footer_size > 0) {
683
footer = template_file->get_buffer(footer_size);
684
}
685
686
uint32_t pe_header_offset = _get_pe_header_offset(template_file);
687
688
// Update symbol table pointer.
689
template_file->seek(pe_header_offset + 12);
690
uint32_t symbols_offset = template_file->get_32();
691
if (symbols_offset > resources_section_entry.pointer_to_raw_data) {
692
template_file->seek(pe_header_offset + 12);
693
template_file->store_32(symbols_offset + raw_size_delta);
694
}
695
696
template_file->seek(pe_header_offset + MAGIC_NUMBER_OFFSET);
697
uint16_t magic_number = template_file->get_16();
698
ERR_FAIL_COND_V_MSG(magic_number != 0x10b && magic_number != 0x20b, ERR_CANT_OPEN, vformat("Magic number has wrong value: %04x", magic_number));
699
bool pe32plus = magic_number == 0x20b;
700
701
// Update image size.
702
template_file->seek(pe_header_offset + SIZE_OF_INITIALIZED_DATA_OFFSET);
703
uint32_t size_of_initialized_data = template_file->get_32();
704
size_of_initialized_data += resources_section_entry.size_of_raw_data - old_resources_size_of_raw_data;
705
template_file->seek(pe_header_offset + SIZE_OF_INITIALIZED_DATA_OFFSET);
706
template_file->store_32(size_of_initialized_data);
707
708
template_file->seek(pe_header_offset + SIZE_OF_IMAGE_OFFSET);
709
uint32_t size_of_image = template_file->get_32();
710
size_of_image += section_entries.get(section_entries.size() - 1).virtual_address - old_last_section_virtual_address;
711
template_file->seek(pe_header_offset + SIZE_OF_IMAGE_OFFSET);
712
template_file->store_32(size_of_image);
713
714
uint32_t optional_header_offset = pe_header_offset + COFF_HEADER_SIZE;
715
716
// Update resource section size.
717
template_file->seek(optional_header_offset + (pe32plus ? 132 : 116));
718
template_file->store_32(resources_section_entry.virtual_size);
719
720
// Update relocation section size and pointer.
721
template_file->seek(optional_header_offset + (pe32plus ? 152 : 136));
722
template_file->store_32(section_entries[relocations_index].virtual_address);
723
template_file->store_32(section_entries[relocations_index].virtual_size);
724
725
template_file->seek(optional_header_offset + (pe32plus ? 240 : 224) + SectionEntry::SIZE * resource_index);
726
template_file->store_buffer(resources_section_entry.save());
727
for (int i = resource_index + 1; i < section_entries.size(); i++) {
728
template_file->seek(optional_header_offset + (pe32plus ? 240 : 224) + SectionEntry::SIZE * i);
729
template_file->store_buffer(section_entries[i].save());
730
}
731
732
// Write new resource section.
733
template_file->seek(resources_section_entry.pointer_to_raw_data);
734
template_file->store_buffer(resources);
735
// Write the rest of sections.
736
for (const Vector<uint8_t> &data : moved_section_data) {
737
template_file->store_buffer(data);
738
}
739
// Write footer data.
740
if (footer_size > 0) {
741
template_file->store_buffer(footer);
742
}
743
744
if (template_file->get_position() < original_template_size) {
745
template_file->close();
746
_truncate(p_template_path, section_entries.get(section_entries.size() - 1).pointer_to_raw_data + section_entries.get(section_entries.size() - 1).size_of_raw_data + footer_size);
747
}
748
749
return OK;
750
}
751
752
Vector<TemplateModifier::SectionEntry> TemplateModifier::_get_section_entries(Ref<FileAccess> p_executable) const {
753
Vector<SectionEntry> section_entries;
754
755
uint32_t pe_header_offset = _get_pe_header_offset(p_executable);
756
if (pe_header_offset == 0) {
757
return section_entries;
758
}
759
760
p_executable->seek(pe_header_offset + 6);
761
int num_sections = p_executable->get_16();
762
p_executable->seek(pe_header_offset + 20);
763
uint16_t size_of_optional_header = p_executable->get_16();
764
p_executable->seek(pe_header_offset + COFF_HEADER_SIZE + size_of_optional_header);
765
766
for (int i = 0; i < num_sections; ++i) {
767
SectionEntry section_entry;
768
section_entry.load(p_executable);
769
section_entries.append(section_entry);
770
}
771
772
return section_entries;
773
}
774
775
Error TemplateModifier::modify(const Ref<EditorExportPreset> &p_preset, const String &p_template_path, const String &p_icon_path) {
776
TemplateModifier template_modifier;
777
return template_modifier._modify_template(p_preset, p_template_path, p_icon_path);
778
}
779
780