Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/export/lipo.cpp
9896 views
1
/**************************************************************************/
2
/* lipo.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 "lipo.h"
32
33
#include "macho.h"
34
35
bool LipO::is_lipo(const String &p_path) {
36
Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ);
37
ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path));
38
uint32_t magic = fb->get_32();
39
return (magic == 0xbebafeca || magic == 0xcafebabe || magic == 0xbfbafeca || magic == 0xcafebabf);
40
}
41
42
bool LipO::create_file(const String &p_output_path, const Vector<String> &p_files) {
43
close();
44
45
fa = FileAccess::open(p_output_path, FileAccess::WRITE);
46
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_output_path));
47
48
uint64_t max_size = 0;
49
for (int i = 0; i < p_files.size(); i++) {
50
{
51
MachO mh;
52
if (!mh.open_file(p_files[i])) {
53
ERR_FAIL_V_MSG(false, vformat("LipO: Invalid MachO file: \"%s\".", p_files[i]));
54
}
55
56
FatArch arch;
57
arch.cputype = mh.get_cputype();
58
arch.cpusubtype = mh.get_cpusubtype();
59
arch.offset = 0;
60
arch.size = mh.get_size();
61
arch.align = mh.get_align();
62
max_size += arch.size;
63
64
archs.push_back(arch);
65
}
66
67
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
68
if (fb.is_null()) {
69
close();
70
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
71
}
72
}
73
74
// Write header.
75
bool is_64 = (max_size >= std::numeric_limits<uint32_t>::max());
76
if (is_64) {
77
fa->store_32(0xbfbafeca);
78
} else {
79
fa->store_32(0xbebafeca);
80
}
81
fa->store_32(BSWAP32(archs.size()));
82
uint64_t offset = archs.size() * (is_64 ? 32 : 20) + 8;
83
for (int i = 0; i < archs.size(); i++) {
84
archs.write[i].offset = offset + PAD(offset, uint64_t(1) << archs[i].align);
85
if (is_64) {
86
fa->store_32(BSWAP32(archs[i].cputype));
87
fa->store_32(BSWAP32(archs[i].cpusubtype));
88
fa->store_64(BSWAP64(archs[i].offset));
89
fa->store_64(BSWAP64(archs[i].size));
90
fa->store_32(BSWAP32(archs[i].align));
91
fa->store_32(0);
92
} else {
93
fa->store_32(BSWAP32(archs[i].cputype));
94
fa->store_32(BSWAP32(archs[i].cpusubtype));
95
fa->store_32(BSWAP32(archs[i].offset));
96
fa->store_32(BSWAP32(archs[i].size));
97
fa->store_32(BSWAP32(archs[i].align));
98
}
99
offset = archs[i].offset + archs[i].size;
100
}
101
102
// Write files and padding.
103
for (int i = 0; i < archs.size(); i++) {
104
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
105
if (fb.is_null()) {
106
close();
107
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
108
}
109
uint64_t cur = fa->get_position();
110
for (uint64_t j = cur; j < archs[i].offset; j++) {
111
fa->store_8(0);
112
}
113
int pages = archs[i].size / 4096;
114
int remain = archs[i].size % 4096;
115
unsigned char step[4096];
116
for (int j = 0; j < pages; j++) {
117
uint64_t br = fb->get_buffer(step, 4096);
118
if (br > 0) {
119
fa->store_buffer(step, br);
120
}
121
}
122
uint64_t br = fb->get_buffer(step, remain);
123
if (br > 0) {
124
fa->store_buffer(step, br);
125
}
126
}
127
return true;
128
}
129
130
bool LipO::create_file(const String &p_output_path, const Vector<String> &p_files, const Vector<Vector2i> &p_cputypes) {
131
close();
132
133
fa = FileAccess::open(p_output_path, FileAccess::WRITE);
134
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_output_path));
135
ERR_FAIL_COND_V(p_files.size() != p_cputypes.size(), false);
136
137
uint64_t max_size = 0;
138
for (int i = 0; i < p_files.size(); i++) {
139
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
140
if (fb.is_null()) {
141
close();
142
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
143
}
144
145
{
146
FatArch arch;
147
MachO mh;
148
if (MachO::is_macho(p_files[i]) && mh.open_file(p_files[i])) {
149
arch.cputype = mh.get_cputype();
150
arch.cpusubtype = mh.get_cpusubtype();
151
arch.offset = 0;
152
arch.size = mh.get_size();
153
arch.align = mh.get_align();
154
ERR_FAIL_V_MSG(arch.cputype != (uint32_t)p_cputypes[i].x || arch.cpusubtype != (uint32_t)p_cputypes[i].y, vformat("Mismatching MachO architecture: \"%s\".", p_files[i]));
155
} else {
156
arch.cputype = (uint32_t)p_cputypes[i].x;
157
arch.cpusubtype = (uint32_t)p_cputypes[i].y;
158
arch.offset = 0;
159
arch.size = fb->get_length();
160
arch.align = 0x03;
161
}
162
max_size += arch.size;
163
164
archs.push_back(arch);
165
}
166
}
167
168
// Write header.
169
bool is_64 = (max_size >= std::numeric_limits<uint32_t>::max());
170
if (is_64) {
171
fa->store_32(0xbfbafeca);
172
} else {
173
fa->store_32(0xbebafeca);
174
}
175
fa->store_32(BSWAP32(archs.size()));
176
uint64_t offset = archs.size() * (is_64 ? 32 : 20) + 8;
177
for (int i = 0; i < archs.size(); i++) {
178
archs.write[i].offset = offset + PAD(offset, uint64_t(1) << archs[i].align);
179
if (is_64) {
180
fa->store_32(BSWAP32(archs[i].cputype));
181
fa->store_32(BSWAP32(archs[i].cpusubtype));
182
fa->store_64(BSWAP64(archs[i].offset));
183
fa->store_64(BSWAP64(archs[i].size));
184
fa->store_32(BSWAP32(archs[i].align));
185
fa->store_32(0);
186
} else {
187
fa->store_32(BSWAP32(archs[i].cputype));
188
fa->store_32(BSWAP32(archs[i].cpusubtype));
189
fa->store_32(BSWAP32(archs[i].offset));
190
fa->store_32(BSWAP32(archs[i].size));
191
fa->store_32(BSWAP32(archs[i].align));
192
}
193
offset = archs[i].offset + archs[i].size;
194
}
195
196
// Write files and padding.
197
for (int i = 0; i < archs.size(); i++) {
198
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
199
if (fb.is_null()) {
200
close();
201
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
202
}
203
uint64_t cur = fa->get_position();
204
for (uint64_t j = cur; j < archs[i].offset; j++) {
205
fa->store_8(0);
206
}
207
int pages = archs[i].size / 4096;
208
int remain = archs[i].size % 4096;
209
unsigned char step[4096];
210
for (int j = 0; j < pages; j++) {
211
uint64_t br = fb->get_buffer(step, 4096);
212
if (br > 0) {
213
fa->store_buffer(step, br);
214
}
215
}
216
uint64_t br = fb->get_buffer(step, remain);
217
if (br > 0) {
218
fa->store_buffer(step, br);
219
}
220
}
221
return true;
222
}
223
224
bool LipO::open_file(const String &p_path) {
225
close();
226
227
fa = FileAccess::open(p_path, FileAccess::READ);
228
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path));
229
230
uint32_t magic = fa->get_32();
231
if (magic == 0xbebafeca) {
232
// 32-bit fat binary, bswap.
233
uint32_t nfat_arch = BSWAP32(fa->get_32());
234
for (uint32_t i = 0; i < nfat_arch; i++) {
235
FatArch arch;
236
arch.cputype = BSWAP32(fa->get_32());
237
arch.cpusubtype = BSWAP32(fa->get_32());
238
arch.offset = BSWAP32(fa->get_32());
239
arch.size = BSWAP32(fa->get_32());
240
arch.align = BSWAP32(fa->get_32());
241
242
archs.push_back(arch);
243
}
244
} else if (magic == 0xcafebabe) {
245
// 32-bit fat binary.
246
uint32_t nfat_arch = fa->get_32();
247
for (uint32_t i = 0; i < nfat_arch; i++) {
248
FatArch arch;
249
arch.cputype = fa->get_32();
250
arch.cpusubtype = fa->get_32();
251
arch.offset = fa->get_32();
252
arch.size = fa->get_32();
253
arch.align = fa->get_32();
254
255
archs.push_back(arch);
256
}
257
} else if (magic == 0xbfbafeca) {
258
// 64-bit fat binary, bswap.
259
uint32_t nfat_arch = BSWAP32(fa->get_32());
260
for (uint32_t i = 0; i < nfat_arch; i++) {
261
FatArch arch;
262
arch.cputype = BSWAP32(fa->get_32());
263
arch.cpusubtype = BSWAP32(fa->get_32());
264
arch.offset = BSWAP64(fa->get_64());
265
arch.size = BSWAP64(fa->get_64());
266
arch.align = BSWAP32(fa->get_32());
267
fa->get_32(); // Skip, reserved.
268
269
archs.push_back(arch);
270
}
271
} else if (magic == 0xcafebabf) {
272
// 64-bit fat binary.
273
uint32_t nfat_arch = fa->get_32();
274
for (uint32_t i = 0; i < nfat_arch; i++) {
275
FatArch arch;
276
arch.cputype = fa->get_32();
277
arch.cpusubtype = fa->get_32();
278
arch.offset = fa->get_64();
279
arch.size = fa->get_64();
280
arch.align = fa->get_32();
281
fa->get_32(); // Skip, reserved.
282
283
archs.push_back(arch);
284
}
285
} else {
286
close();
287
ERR_FAIL_V_MSG(false, vformat("LipO: Invalid fat binary: \"%s\".", p_path));
288
}
289
return true;
290
}
291
292
int LipO::get_arch_count() const {
293
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
294
return archs.size();
295
}
296
297
uint32_t LipO::get_arch_cputype(int p_index) const {
298
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
299
ERR_FAIL_INDEX_V(p_index, archs.size(), 0);
300
return archs[p_index].cputype;
301
}
302
303
uint32_t LipO::get_arch_cpusubtype(int p_index) const {
304
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
305
ERR_FAIL_INDEX_V(p_index, archs.size(), 0);
306
return archs[p_index].cpusubtype;
307
}
308
309
bool LipO::extract_arch(int p_index, const String &p_path) {
310
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "LipO: File not opened.");
311
ERR_FAIL_INDEX_V(p_index, archs.size(), false);
312
313
Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::WRITE);
314
ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path));
315
316
fa->seek(archs[p_index].offset);
317
318
int pages = archs[p_index].size / 4096;
319
int remain = archs[p_index].size % 4096;
320
unsigned char step[4096];
321
for (int i = 0; i < pages; i++) {
322
uint64_t br = fa->get_buffer(step, 4096);
323
if (br > 0) {
324
fb->store_buffer(step, br);
325
}
326
}
327
uint64_t br = fa->get_buffer(step, remain);
328
if (br > 0) {
329
fb->store_buffer(step, br);
330
}
331
return true;
332
}
333
334
void LipO::close() {
335
archs.clear();
336
}
337
338
LipO::~LipO() {
339
close();
340
}
341
342