diff options
Diffstat (limited to 'libraries/edje/src/bin/edje_decc.c')
-rw-r--r-- | libraries/edje/src/bin/edje_decc.c | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/libraries/edje/src/bin/edje_decc.c b/libraries/edje/src/bin/edje_decc.c new file mode 100644 index 0000000..1b79e13 --- /dev/null +++ b/libraries/edje/src/bin/edje_decc.c | |||
@@ -0,0 +1,472 @@ | |||
1 | /* ugly ugly. avert your eyes. */ | ||
2 | |||
3 | #ifdef HAVE_CONFIG_H | ||
4 | # include <config.h> | ||
5 | #endif | ||
6 | |||
7 | #include <string.h> | ||
8 | #include <ctype.h> | ||
9 | #include <unistd.h> | ||
10 | #include <locale.h> | ||
11 | #include <sys/types.h> | ||
12 | #include <sys/stat.h> | ||
13 | #include <errno.h> | ||
14 | |||
15 | |||
16 | #include <Ecore_File.h> | ||
17 | #include <Ecore_Evas.h> | ||
18 | |||
19 | #include "edje_decc.h" | ||
20 | |||
21 | int _edje_cc_log_dom = -1; | ||
22 | char *progname = NULL; | ||
23 | char *file_in = NULL; | ||
24 | char *file_out = NULL; | ||
25 | |||
26 | Edje_File *edje_file = NULL; | ||
27 | SrcFile_List *srcfiles = NULL; | ||
28 | Font_List *fontlist = NULL; | ||
29 | |||
30 | int line = 0; | ||
31 | int build_sh = 1; | ||
32 | int new_dir = 1; | ||
33 | |||
34 | int decomp(void); | ||
35 | void output(void); | ||
36 | static int compiler_cmd_is_sane(); | ||
37 | static int root_filename_is_sane(); | ||
38 | |||
39 | static void | ||
40 | main_help(void) | ||
41 | { | ||
42 | printf | ||
43 | ("Usage:\n" | ||
44 | "\t%s input_file.edj [-main-out file.edc] [-no-build-sh] [-current-dir]\n" | ||
45 | "\n" | ||
46 | " -main-out\tCreate a symbolic link to the main edc \n" | ||
47 | " -no-build-sh\tDon't output build.sh \n" | ||
48 | " -current-dir\tOutput to current directory \n" | ||
49 | "\n" | ||
50 | ,progname); | ||
51 | } | ||
52 | |||
53 | Eet_File *ef; | ||
54 | Eet_Dictionary *ed; | ||
55 | |||
56 | int | ||
57 | main(int argc, char **argv) | ||
58 | { | ||
59 | int i; | ||
60 | |||
61 | setlocale(LC_NUMERIC, "C"); | ||
62 | if (!eina_init()) | ||
63 | exit(-1); | ||
64 | _edje_cc_log_dom = eina_log_domain_register | ||
65 | ("edje_decc", EDJE_CC_DEFAULT_LOG_COLOR); | ||
66 | if (_edje_cc_log_dom < 0) | ||
67 | { | ||
68 | EINA_LOG_ERR("Impossible to create a log domain."); | ||
69 | eina_shutdown(); | ||
70 | exit(-1); | ||
71 | } | ||
72 | eina_log_level_set(EINA_LOG_LEVEL_INFO); | ||
73 | progname = argv[0]; | ||
74 | for (i = 1; i < argc; i++) | ||
75 | { | ||
76 | if (!strcmp(argv[i], "-h")) | ||
77 | { | ||
78 | main_help(); | ||
79 | exit(0); | ||
80 | } | ||
81 | if (!file_in) | ||
82 | file_in = argv[i]; | ||
83 | else if ((!strcmp(argv[i], "-main-out")) && (i < (argc - 1))) | ||
84 | { | ||
85 | i++; | ||
86 | file_out = argv[i]; | ||
87 | } | ||
88 | else if (!strcmp(argv[i], "-no-build-sh")) | ||
89 | build_sh = 0; | ||
90 | else if (!strcmp(argv[i], "-current-dir")) | ||
91 | new_dir = 0; | ||
92 | } | ||
93 | if (!file_in) | ||
94 | { | ||
95 | ERR("%s: Error: no input file specified.", progname); | ||
96 | main_help(); | ||
97 | exit(-1); | ||
98 | } | ||
99 | |||
100 | if (!edje_init()) | ||
101 | exit(-1); | ||
102 | source_edd(); | ||
103 | |||
104 | if (!decomp()) return -1; | ||
105 | output(); | ||
106 | |||
107 | printf("WARNING! If any Image or audio data was encoded in a LOSSY way, then\n" | ||
108 | "re-encoding will drop quality even more. You need access to the original\n" | ||
109 | "data to ensure no loss of quality.\n"); | ||
110 | eet_close(ef); | ||
111 | edje_shutdown(); | ||
112 | eina_log_domain_unregister(_edje_cc_log_dom); | ||
113 | _edje_cc_log_dom = -1; | ||
114 | eina_shutdown(); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int | ||
119 | decomp(void) | ||
120 | { | ||
121 | ef = eet_open(file_in, EET_FILE_MODE_READ); | ||
122 | if (!ef) | ||
123 | { | ||
124 | ERR("ERROR: cannot open %s", file_in); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | srcfiles = source_load(ef); | ||
129 | if (!srcfiles || !srcfiles->list) | ||
130 | { | ||
131 | ERR("ERROR: %s has no decompile information", file_in); | ||
132 | eet_close(ef); | ||
133 | return 0; | ||
134 | } | ||
135 | if (!eina_list_data_get(srcfiles->list) || !root_filename_is_sane()) | ||
136 | { | ||
137 | ERR("ERROR: Invalid root filename: '%s'", (char *) eina_list_data_get(srcfiles->list)); | ||
138 | eet_close(ef); | ||
139 | return 0; | ||
140 | } | ||
141 | edje_file = eet_data_read(ef, _edje_edd_edje_file, "edje/file"); | ||
142 | if (!edje_file) | ||
143 | { | ||
144 | ERR("ERROR: %s does not appear to be an edje file", file_in); | ||
145 | eet_close(ef); | ||
146 | return 0; | ||
147 | } | ||
148 | /* force compiler to be edje_cc */ | ||
149 | edje_file->compiler = strdup("edje_cc"); | ||
150 | if (!edje_file->compiler) | ||
151 | { | ||
152 | edje_file->compiler = strdup("edje_cc"); | ||
153 | } | ||
154 | else if (!compiler_cmd_is_sane()) | ||
155 | { | ||
156 | ERR("ERROR: invalid compiler executable: '%s'", edje_file->compiler); | ||
157 | eet_close(ef); | ||
158 | return 0; | ||
159 | } | ||
160 | fontlist = source_fontmap_load(ef); | ||
161 | return 1; | ||
162 | } | ||
163 | |||
164 | void | ||
165 | output(void) | ||
166 | { | ||
167 | Eina_List *l; | ||
168 | Eet_File *tef; | ||
169 | SrcFile *sf; | ||
170 | char *outdir, *p; | ||
171 | |||
172 | if (!new_dir) | ||
173 | outdir = strdup("."); | ||
174 | else | ||
175 | { | ||
176 | p = strrchr(file_in, '/'); | ||
177 | if (p) | ||
178 | outdir = strdup(p + 1); | ||
179 | else | ||
180 | outdir = strdup(file_in); | ||
181 | p = strrchr(outdir, '.'); | ||
182 | if (p) *p = 0; | ||
183 | ecore_file_mkpath(outdir); | ||
184 | } | ||
185 | |||
186 | |||
187 | tef = eet_open(file_in, EET_FILE_MODE_READ); | ||
188 | |||
189 | if (edje_file->image_dir) | ||
190 | { | ||
191 | Edje_Image_Directory_Entry *ei; | ||
192 | unsigned int i; | ||
193 | |||
194 | for (i = 0; i < edje_file->image_dir->entries_count; ++i) | ||
195 | { | ||
196 | ei = &edje_file->image_dir->entries[i]; | ||
197 | |||
198 | if ((ei->source_type > EDJE_IMAGE_SOURCE_TYPE_NONE) && | ||
199 | (ei->source_type < EDJE_IMAGE_SOURCE_TYPE_LAST) && | ||
200 | (ei->source_type != EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) && | ||
201 | (ei->entry)) | ||
202 | { | ||
203 | Ecore_Evas *ee; | ||
204 | Evas *evas; | ||
205 | Evas_Object *im; | ||
206 | char buf[4096]; | ||
207 | char out[4096]; | ||
208 | char *pp; | ||
209 | |||
210 | ecore_init(); | ||
211 | ecore_evas_init(); | ||
212 | ee = ecore_evas_buffer_new(1, 1); | ||
213 | if (!ee) | ||
214 | { | ||
215 | ERR("Cannot create buffer engine canvas for image save."); | ||
216 | exit(-1); | ||
217 | } | ||
218 | evas = ecore_evas_get(ee); | ||
219 | im = evas_object_image_add(evas); | ||
220 | if (!im) | ||
221 | { | ||
222 | ERR("Cannot create image object for save."); | ||
223 | exit(-1); | ||
224 | } | ||
225 | snprintf(buf, sizeof(buf), "edje/images/%i", ei->id); | ||
226 | evas_object_image_file_set(im, file_in, buf); | ||
227 | snprintf(out, sizeof(out), "%s/%s", outdir, ei->entry); | ||
228 | printf("Output Image: %s\n", out); | ||
229 | pp = strdup(out); | ||
230 | p = strrchr(pp, '/'); | ||
231 | *p = 0; | ||
232 | if (strstr(pp, "../")) | ||
233 | { | ||
234 | ERR("Potential security violation. attempt to write in parent dir."); | ||
235 | exit(-1); | ||
236 | } | ||
237 | ecore_file_mkpath(pp); | ||
238 | free(pp); | ||
239 | if (!evas_object_image_save(im, out, NULL, "quality=100 compress=9")) | ||
240 | { | ||
241 | ERR("Cannot write file %s. Perhaps missing JPEG or PNG saver modules for Evas.", out); | ||
242 | exit(-1); | ||
243 | } | ||
244 | evas_object_del(im); | ||
245 | ecore_evas_free(ee); | ||
246 | ecore_evas_shutdown(); | ||
247 | ecore_shutdown(); | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | |||
252 | EINA_LIST_FOREACH(srcfiles->list, l, sf) | ||
253 | { | ||
254 | char out[4096]; | ||
255 | FILE *f; | ||
256 | char *pp; | ||
257 | |||
258 | snprintf(out, sizeof(out), "%s/%s", outdir, sf->name); | ||
259 | INF("Output Source File: %s\n", out); | ||
260 | pp = strdup(out); | ||
261 | p = strrchr(pp, '/'); | ||
262 | *p = 0; | ||
263 | if (strstr(pp, "../")) | ||
264 | { | ||
265 | ERR("Potential security violation. attempt to write in parent dir."); | ||
266 | exit (-1); | ||
267 | } | ||
268 | ecore_file_mkpath(pp); | ||
269 | free(pp); | ||
270 | if (strstr(out, "../")) | ||
271 | { | ||
272 | ERR("Potential security violation. attempt to write in parent dir."); | ||
273 | exit (-1); | ||
274 | } | ||
275 | f = fopen(out, "wb"); | ||
276 | if (!f) | ||
277 | { | ||
278 | ERR("Unable to write file (%s).", out); | ||
279 | exit (-1); | ||
280 | } | ||
281 | |||
282 | /* if the file is empty, sf->file will be NULL. | ||
283 | * note that that's not an error | ||
284 | */ | ||
285 | if (sf->file) fputs(sf->file, f); | ||
286 | fclose(f); | ||
287 | } | ||
288 | if (edje_file->fonts) | ||
289 | { | ||
290 | Edje_Font_Directory_Entry *fn; | ||
291 | Eina_Iterator *it; | ||
292 | |||
293 | it = eina_hash_iterator_data_new(edje_file->fonts); | ||
294 | EINA_ITERATOR_FOREACH(it, fn) | ||
295 | { | ||
296 | void *font; | ||
297 | int fontsize; | ||
298 | char out[4096]; | ||
299 | /* FIXME!!!! */ | ||
300 | /* should be fn->entry -v */ | ||
301 | snprintf(out, sizeof(out), "edje/fonts/%s", fn->file); | ||
302 | font = eet_read(tef, out, &fontsize); | ||
303 | if (font) | ||
304 | { | ||
305 | FILE *f; | ||
306 | char *pp; | ||
307 | |||
308 | /* should be fn->file -v */ | ||
309 | snprintf(out, sizeof(out), "%s/%s", outdir, fn->entry); | ||
310 | INF("Output Font: %s", out); | ||
311 | pp = strdup(out); | ||
312 | p = strrchr(pp, '/'); | ||
313 | *p = 0; | ||
314 | if (strstr(pp, "../")) | ||
315 | { | ||
316 | ERR("Potential security violation. attempt to write in parent dir."); | ||
317 | exit (-1); | ||
318 | } | ||
319 | ecore_file_mkpath(pp); | ||
320 | free(pp); | ||
321 | if (strstr(out, "../")) | ||
322 | { | ||
323 | ERR("Potential security violation. attempt to write in parent dir."); | ||
324 | exit (-1); | ||
325 | } | ||
326 | if (!(f = fopen(out, "wb"))) | ||
327 | { | ||
328 | ERR("Could not open file: %s", out); | ||
329 | exit (-1); | ||
330 | } | ||
331 | if (fwrite(font, fontsize, 1, f) != 1) | ||
332 | ERR("Could not write font: %s", strerror(errno)); | ||
333 | if (f) fclose(f); | ||
334 | free(font); | ||
335 | } | ||
336 | } | ||
337 | eina_iterator_free(it); | ||
338 | } | ||
339 | { | ||
340 | char out[4096]; | ||
341 | FILE *f; | ||
342 | sf = eina_list_data_get(srcfiles->list); | ||
343 | |||
344 | |||
345 | if (build_sh) | ||
346 | { | ||
347 | snprintf(out, sizeof(out), "%s/build.sh", outdir); | ||
348 | printf("Output Build Script: %s\n", out); | ||
349 | if (strstr(out, "../")) | ||
350 | { | ||
351 | ERR("potential security violation. attempt to write in parent dir.\n"); | ||
352 | exit (-1); | ||
353 | } | ||
354 | f = fopen(out, "wb"); | ||
355 | fprintf(f, "#!/bin/sh\n"); | ||
356 | fprintf(f, "%s $@ -id . -fd . %s -o %s.edj\n", edje_file->compiler, sf->name, outdir); | ||
357 | fclose(f); | ||
358 | |||
359 | WRN("\n*** CAUTION ***\n" | ||
360 | "Please check the build script for anything malicious " | ||
361 | "before running it!\n\n"); | ||
362 | } | ||
363 | |||
364 | if (file_out) | ||
365 | { | ||
366 | snprintf(out, sizeof(out), "%s/%s", outdir, file_out); | ||
367 | if (ecore_file_symlink(sf->name, out) != EINA_TRUE) | ||
368 | { | ||
369 | ERR("symlink %s -> %s failed\n", sf->name, out); | ||
370 | } | ||
371 | } | ||
372 | |||
373 | chmod(out, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP); | ||
374 | |||
375 | } | ||
376 | |||
377 | if (edje_file->sound_dir) | ||
378 | { | ||
379 | Edje_Sound_Sample *sample; | ||
380 | void *sound_data; | ||
381 | char out[PATH_MAX]; | ||
382 | char out1[PATH_MAX]; | ||
383 | char *pp; | ||
384 | int sound_data_size; | ||
385 | FILE *f; | ||
386 | int i; | ||
387 | |||
388 | for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++) | ||
389 | { | ||
390 | sample = &edje_file->sound_dir->samples[i]; | ||
391 | if ((!sample) || (!sample->name)) continue; | ||
392 | snprintf(out, sizeof(out), "edje/sounds/%i", sample->id); | ||
393 | sound_data = (void *)eet_read_direct(tef, out, &sound_data_size); | ||
394 | if (sound_data) | ||
395 | { | ||
396 | snprintf(out1, sizeof(out1), "%s/%s", outdir, sample->name); | ||
397 | pp = strdup(out1); | ||
398 | p = strrchr(pp, '/'); | ||
399 | *p = 0; | ||
400 | if (strstr(pp, "../")) | ||
401 | { | ||
402 | ERR("Potential security violation. attempt to write in parent dir."); | ||
403 | exit(-1); | ||
404 | } | ||
405 | ecore_file_mkpath(pp); | ||
406 | free(pp); | ||
407 | if (strstr(out, "../")) | ||
408 | { | ||
409 | ERR("Potential security violation. attempt to write in parent dir."); | ||
410 | exit(-1); | ||
411 | } | ||
412 | f = fopen(out1, "wb"); | ||
413 | if (fwrite(sound_data, sound_data_size, 1, f) != 1) | ||
414 | ERR("Could not write sound: %s", strerror(errno)); | ||
415 | fclose(f); | ||
416 | free(sound_data); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | } | ||
421 | eet_close(tef); | ||
422 | } | ||
423 | |||
424 | static int | ||
425 | compiler_cmd_is_sane() | ||
426 | { | ||
427 | const char *c = edje_file->compiler, *ptr; | ||
428 | |||
429 | if ((!c) || (!*c)) | ||
430 | { | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | for (ptr = c; ptr && *ptr; ptr++) | ||
435 | { | ||
436 | /* only allow [a-z][A-Z][0-9]_- */ | ||
437 | if ((!isalnum(*ptr)) && (*ptr != '_') && (*ptr != '-')) | ||
438 | { | ||
439 | return 0; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | return 1; | ||
444 | } | ||
445 | |||
446 | static int | ||
447 | root_filename_is_sane() | ||
448 | { | ||
449 | SrcFile *sf = eina_list_data_get(srcfiles->list); | ||
450 | char *f = sf->name, *ptr; | ||
451 | |||
452 | if (!f || !*f) | ||
453 | { | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | for (ptr = f; ptr && *ptr; ptr++) | ||
458 | { | ||
459 | /* only allow [a-z][A-Z][0-9]_-./ */ | ||
460 | switch (*ptr) | ||
461 | { | ||
462 | case '_': case '-': case '.': case '/': | ||
463 | break; | ||
464 | default: | ||
465 | if (!isalnum(*ptr)) | ||
466 | { | ||
467 | return 0; | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | return 1; | ||
472 | } | ||