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 | bool LipO::is_lipo(const String &p_path) { |
34 | Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); |
35 | ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\"." , p_path)); |
36 | uint32_t magic = fb->get_32(); |
37 | return (magic == 0xbebafeca || magic == 0xcafebabe || magic == 0xbfbafeca || magic == 0xcafebabf); |
38 | } |
39 | |
40 | bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_files) { |
41 | close(); |
42 | |
43 | fa = FileAccess::open(p_output_path, FileAccess::WRITE); |
44 | ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\"." , p_output_path)); |
45 | |
46 | uint64_t max_size = 0; |
47 | for (int i = 0; i < p_files.size(); i++) { |
48 | { |
49 | MachO mh; |
50 | if (!mh.open_file(p_files[i])) { |
51 | ERR_FAIL_V_MSG(false, vformat("LipO: Invalid MachO file: \"%s\"." , p_files[i])); |
52 | } |
53 | |
54 | FatArch arch; |
55 | arch.cputype = mh.get_cputype(); |
56 | arch.cpusubtype = mh.get_cpusubtype(); |
57 | arch.offset = 0; |
58 | arch.size = mh.get_size(); |
59 | arch.align = mh.get_align(); |
60 | max_size += arch.size; |
61 | |
62 | archs.push_back(arch); |
63 | } |
64 | |
65 | Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ); |
66 | if (fb.is_null()) { |
67 | close(); |
68 | ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\"." , p_files[i])); |
69 | } |
70 | } |
71 | |
72 | // Write header. |
73 | bool is_64 = (max_size >= std::numeric_limits<uint32_t>::max()); |
74 | if (is_64) { |
75 | fa->store_32(0xbfbafeca); |
76 | } else { |
77 | fa->store_32(0xbebafeca); |
78 | } |
79 | fa->store_32(BSWAP32(archs.size())); |
80 | uint64_t offset = archs.size() * (is_64 ? 32 : 20) + 8; |
81 | for (int i = 0; i < archs.size(); i++) { |
82 | archs.write[i].offset = offset + PAD(offset, uint64_t(1) << archs[i].align); |
83 | if (is_64) { |
84 | fa->store_32(BSWAP32(archs[i].cputype)); |
85 | fa->store_32(BSWAP32(archs[i].cpusubtype)); |
86 | fa->store_64(BSWAP64(archs[i].offset)); |
87 | fa->store_64(BSWAP64(archs[i].size)); |
88 | fa->store_32(BSWAP32(archs[i].align)); |
89 | fa->store_32(0); |
90 | } else { |
91 | fa->store_32(BSWAP32(archs[i].cputype)); |
92 | fa->store_32(BSWAP32(archs[i].cpusubtype)); |
93 | fa->store_32(BSWAP32(archs[i].offset)); |
94 | fa->store_32(BSWAP32(archs[i].size)); |
95 | fa->store_32(BSWAP32(archs[i].align)); |
96 | } |
97 | offset = archs[i].offset + archs[i].size; |
98 | } |
99 | |
100 | // Write files and padding. |
101 | for (int i = 0; i < archs.size(); i++) { |
102 | Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ); |
103 | if (fb.is_null()) { |
104 | close(); |
105 | ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\"." , p_files[i])); |
106 | } |
107 | uint64_t cur = fa->get_position(); |
108 | for (uint64_t j = cur; j < archs[i].offset; j++) { |
109 | fa->store_8(0); |
110 | } |
111 | int pages = archs[i].size / 4096; |
112 | int remain = archs[i].size % 4096; |
113 | unsigned char step[4096]; |
114 | for (int j = 0; j < pages; j++) { |
115 | uint64_t br = fb->get_buffer(step, 4096); |
116 | if (br > 0) { |
117 | fa->store_buffer(step, br); |
118 | } |
119 | } |
120 | uint64_t br = fb->get_buffer(step, remain); |
121 | if (br > 0) { |
122 | fa->store_buffer(step, br); |
123 | } |
124 | } |
125 | return true; |
126 | } |
127 | |
128 | bool LipO::open_file(const String &p_path) { |
129 | close(); |
130 | |
131 | fa = FileAccess::open(p_path, FileAccess::READ); |
132 | ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\"." , p_path)); |
133 | |
134 | uint32_t magic = fa->get_32(); |
135 | if (magic == 0xbebafeca) { |
136 | // 32-bit fat binary, bswap. |
137 | uint32_t nfat_arch = BSWAP32(fa->get_32()); |
138 | for (uint32_t i = 0; i < nfat_arch; i++) { |
139 | FatArch arch; |
140 | arch.cputype = BSWAP32(fa->get_32()); |
141 | arch.cpusubtype = BSWAP32(fa->get_32()); |
142 | arch.offset = BSWAP32(fa->get_32()); |
143 | arch.size = BSWAP32(fa->get_32()); |
144 | arch.align = BSWAP32(fa->get_32()); |
145 | |
146 | archs.push_back(arch); |
147 | } |
148 | } else if (magic == 0xcafebabe) { |
149 | // 32-bit fat binary. |
150 | uint32_t nfat_arch = fa->get_32(); |
151 | for (uint32_t i = 0; i < nfat_arch; i++) { |
152 | FatArch arch; |
153 | arch.cputype = fa->get_32(); |
154 | arch.cpusubtype = fa->get_32(); |
155 | arch.offset = fa->get_32(); |
156 | arch.size = fa->get_32(); |
157 | arch.align = fa->get_32(); |
158 | |
159 | archs.push_back(arch); |
160 | } |
161 | } else if (magic == 0xbfbafeca) { |
162 | // 64-bit fat binary, bswap. |
163 | uint32_t nfat_arch = BSWAP32(fa->get_32()); |
164 | for (uint32_t i = 0; i < nfat_arch; i++) { |
165 | FatArch arch; |
166 | arch.cputype = BSWAP32(fa->get_32()); |
167 | arch.cpusubtype = BSWAP32(fa->get_32()); |
168 | arch.offset = BSWAP64(fa->get_64()); |
169 | arch.size = BSWAP64(fa->get_64()); |
170 | arch.align = BSWAP32(fa->get_32()); |
171 | fa->get_32(); // Skip, reserved. |
172 | |
173 | archs.push_back(arch); |
174 | } |
175 | } else if (magic == 0xcafebabf) { |
176 | // 64-bit fat binary. |
177 | uint32_t nfat_arch = fa->get_32(); |
178 | for (uint32_t i = 0; i < nfat_arch; i++) { |
179 | FatArch arch; |
180 | arch.cputype = fa->get_32(); |
181 | arch.cpusubtype = fa->get_32(); |
182 | arch.offset = fa->get_64(); |
183 | arch.size = fa->get_64(); |
184 | arch.align = fa->get_32(); |
185 | fa->get_32(); // Skip, reserved. |
186 | |
187 | archs.push_back(arch); |
188 | } |
189 | } else { |
190 | close(); |
191 | ERR_FAIL_V_MSG(false, vformat("LipO: Invalid fat binary: \"%s\"." , p_path)); |
192 | } |
193 | return true; |
194 | } |
195 | |
196 | int LipO::get_arch_count() const { |
197 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened." ); |
198 | return archs.size(); |
199 | } |
200 | |
201 | bool LipO::(int p_index, const String &p_path) { |
202 | ERR_FAIL_COND_V_MSG(fa.is_null(), false, "LipO: File not opened." ); |
203 | ERR_FAIL_INDEX_V(p_index, archs.size(), false); |
204 | |
205 | Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::WRITE); |
206 | ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\"." , p_path)); |
207 | |
208 | fa->seek(archs[p_index].offset); |
209 | |
210 | int pages = archs[p_index].size / 4096; |
211 | int remain = archs[p_index].size % 4096; |
212 | unsigned char step[4096]; |
213 | for (int i = 0; i < pages; i++) { |
214 | uint64_t br = fa->get_buffer(step, 4096); |
215 | if (br > 0) { |
216 | fb->store_buffer(step, br); |
217 | } |
218 | } |
219 | uint64_t br = fa->get_buffer(step, remain); |
220 | if (br > 0) { |
221 | fb->store_buffer(step, br); |
222 | } |
223 | return true; |
224 | } |
225 | |
226 | void LipO::close() { |
227 | archs.clear(); |
228 | } |
229 | |
230 | LipO::~LipO() { |
231 | close(); |
232 | } |
233 | |