efl

Форк
0
/
edje_decc.c 
636 строк · 17.8 Кб
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
#include <Ecore_File.h>
16
#include <Ecore_Evas.h>
17

18
#include "edje_decc.h"
19

20
int _edje_cc_log_dom = -1;
21
static const char *progname = NULL;
22
char *file_in = NULL;
23
char *file_out = NULL;
24
char *outdir = NULL;
25
int compress_mode = EET_COMPRESSION_DEFAULT;
26

27
Edje_File *edje_file = NULL;
28
SrcFile_List *srcfiles = NULL;
29
Edje_Font_List *fontlist = NULL;
30

31
int line = 0;
32
int build_sh = 1;
33
int new_dir = 1;
34

35
int        decomp(void);
36
void       output(void);
37
static int compiler_cmd_is_sane(void);
38
static int root_filename_is_sane(void);
39

40
static void
41
_edje_cc_log_cb(const Eina_Log_Domain *d,
42
                Eina_Log_Level level,
43
                const char *file,
44
                const char *fnc,
45
                int cur_line,
46
                const char *fmt,
47
                EINA_UNUSED void *data,
48
                va_list args)
49
{
50
   if ((d->name) && (d->namelen == sizeof("edje_decc") - 1) &&
51
       (memcmp(d->name, "edje_decc", sizeof("edje_decc") - 1) == 0))
52
     {
53
        const char *prefix;
54
        Eina_Bool use_color = !eina_log_color_disable_get();
55

56
        if (use_color)
57
          {
58
#ifndef _WIN32
59
             fputs(eina_log_level_color_get(level), stderr);
60
#else
61
             int color;
62
             switch (level)
63
               {
64
                case EINA_LOG_LEVEL_CRITICAL:
65
                  color = FOREGROUND_RED | FOREGROUND_INTENSITY;
66
                  break;
67

68
                case EINA_LOG_LEVEL_ERR:
69
                  color = FOREGROUND_RED;
70
                  break;
71

72
                case EINA_LOG_LEVEL_WARN:
73
                  color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
74
                  break;
75

76
                case EINA_LOG_LEVEL_INFO:
77
                  color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
78
                  break;
79

80
                case EINA_LOG_LEVEL_DBG:
81
                  color = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
82
                  break;
83

84
                default:
85
                  color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
86
               }
87
             SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
88
#endif
89
          }
90

91
        switch (level)
92
          {
93
           case EINA_LOG_LEVEL_CRITICAL:
94
             prefix = "Critical. ";
95
             break;
96

97
           case EINA_LOG_LEVEL_ERR:
98
             prefix = "Error. ";
99
             break;
100

101
           case EINA_LOG_LEVEL_WARN:
102
             prefix = "Warning. ";
103
             break;
104

105
           default:
106
             prefix = "";
107
          }
108
        fprintf(stderr, "%s: %s", progname, prefix);
109

110
        if (use_color)
111
          {
112
#ifndef _WIN32
113
             fputs(EINA_COLOR_RESET, stderr);
114
#else
115
             SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
116
                                     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
117
#endif
118
          }
119

120
        vfprintf(stderr, fmt, args);
121
        putc('\n', stderr);
122
     }
123
   else
124
     eina_log_print_cb_stderr(d, level, file, fnc, cur_line, fmt, NULL, args);
125
}
126

127
static void
128
main_help(void)
129
{
130
   printf
131
     ("Usage:\n"
132
      "\t%s input_file.edj [-main-out file.edc] [-no-build-sh] [-current-dir | -output path_to_dir]\n"
133
      "\n"
134
      " -main-out\tCreate a symbolic link to the main edc (disabled on Windows) \n"
135
      " -no-build-sh\tDon't output build.sh \n"
136
      " -output, -o\tOutput to specified directory \n"
137
      " -current-dir\tOutput to current directory \n"
138
      " -quiet\t\tProduce less output\n"
139
      "\n"
140
     , progname);
141
}
142

143
Eet_File *ef;
144
Eet_Dictionary *ed;
145

146
int
147
main(int argc, char **argv)
148
{
149
   int i;
150

151
   setlocale(LC_NUMERIC, "C");
152

153
   ecore_app_no_system_modules();
154

155
   if (!eina_init())
156
     exit(-1);
157
   _edje_cc_log_dom = eina_log_domain_register
158
       ("edje_decc", EDJE_CC_DEFAULT_LOG_COLOR);
159
   if (_edje_cc_log_dom < 0)
160
     {
161
        EINA_LOG_ERR("Impossible to create a log domain.");
162
        eina_shutdown();
163
        exit(-1);
164
     }
165
   progname = ecore_file_file_get(argv[0]);
166
   eina_log_print_cb_set(_edje_cc_log_cb, NULL);
167
   eina_log_domain_level_set("edje_decc", EINA_LOG_LEVEL_INFO);
168

169
   for (i = 1; i < argc; i++)
170
     {
171
        if (!strcmp(argv[i], "-h"))
172
          {
173
             main_help();
174
             exit(0);
175
          }
176
        if (!file_in)
177
          file_in = argv[i];
178
        else if ((!strcmp(argv[i], "-main-out")) && (i < (argc - 1)))
179
          {
180
             i++;
181
#ifndef _WIN32
182
             file_out = argv[i];
183
#endif
184
          }
185
        else if (!strcmp(argv[i], "-no-build-sh"))
186
          build_sh = 0;
187
        else if (!strcmp(argv[i], "-current-dir"))
188
          new_dir = 0;
189
        else if (!strcmp(argv[i], "-quiet"))
190
          eina_log_domain_level_set("edje_decc", EINA_LOG_LEVEL_WARN);
191
        else if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "-output")) && (i < (argc - 1)))
192
          {
193
             i++;
194
             outdir = strdup(argv[i]);
195
          }
196
     }
197
   if (!file_in)
198
     {
199
        ERR("no input file specified.");
200
        main_help();
201
        exit(-1);
202
     }
203

204
   if (!edje_init())
205
     exit(-1);
206
   source_edd();
207

208
   if (!decomp()) return -1;
209
   output();
210

211
   WRN("If any Image or audio data was encoded in a LOSSY way, then "
212
       "re-encoding will drop quality even more. "
213
       "You need access to the original data to ensure no loss of quality.");
214
   eet_close(ef);
215
   edje_shutdown();
216
   eina_log_domain_unregister(_edje_cc_log_dom);
217
   _edje_cc_log_dom = -1;
218
   eina_shutdown();
219
   return 0;
220
}
221

222
int
223
decomp(void)
224
{
225
   ef = eet_open(file_in, EET_FILE_MODE_READ);
226
   if (!ef)
227
     {
228
        ERR("cannot open %s", file_in);
229
        return 0;
230
     }
231

232
   srcfiles = source_load(ef);
233
   if (!srcfiles || !srcfiles->list)
234
     {
235
        ERR("%s has no decompile information", file_in);
236
        eet_close(ef);
237
        return 0;
238
     }
239
   if (!eina_list_data_get(srcfiles->list) || !root_filename_is_sane())
240
     {
241
        ERR("Invalid root filename: '%s'", (char *)eina_list_data_get(srcfiles->list));
242
        eet_close(ef);
243
        return 0;
244
     }
245
   edje_file = eet_data_read(ef, _edje_edd_edje_file, "edje/file");
246
   if (!edje_file)
247
     {
248
        ERR("%s does not appear to be an edje file", file_in);
249
        eet_close(ef);
250
        return 0;
251
     }
252
   /* force compiler to be edje_cc */
253
   edje_file->compiler = strdup("edje_cc");
254
   if (!edje_file->compiler)
255
     {
256
        edje_file->compiler = strdup("edje_cc");
257
     }
258
   else if (!compiler_cmd_is_sane())
259
     {
260
        ERR("invalid compiler executable: '%s'", edje_file->compiler);
261
        eet_close(ef);
262
        return 0;
263
     }
264
   fontlist = source_fontmap_load(ef);
265
   return 1;
266
}
267

268
void
269
output(void)
270
{
271
   Eina_List *l;
272
   Eet_File *tef;
273
   SrcFile *sf;
274
   char *p;
275

276
   if (!outdir)
277
     {
278
        if (!new_dir)
279
          outdir = strdup(".");
280
        else
281
          {
282
             p = strrchr(file_in, '/');
283
             if (p)
284
               outdir = strdup(p + 1);
285
             else
286
               outdir = strdup(file_in);
287
             p = strrchr(outdir, '.');
288
             if (p) *p = 0;
289
             ecore_file_mkpath(outdir);
290
          }
291
     }
292

293
   tef = eet_open(file_in, EET_FILE_MODE_READ);
294

295
   if (edje_file->image_dir)
296
     {
297
        Edje_Image_Directory_Entry *ei;
298
        unsigned int i;
299

300
        for (i = 0; i < edje_file->image_dir->entries_count; ++i)
301
          {
302
             ei = &edje_file->image_dir->entries[i];
303

304
             if ((ei->source_type > EDJE_IMAGE_SOURCE_TYPE_NONE) &&
305
                 (ei->source_type < EDJE_IMAGE_SOURCE_TYPE_LAST) &&
306
                 (ei->source_type != EDJE_IMAGE_SOURCE_TYPE_USER) &&
307
                 (ei->source_type != EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) &&
308
                 (ei->entry))
309
               {
310
                  Ecore_Evas *ee;
311
                  Evas *evas;
312
                  Evas_Object *im;
313
                  char buf[4096];
314
                  char out[4096];
315
                  char *pp;
316

317
                  ecore_init();
318
                  ecore_evas_init();
319
                  ee = ecore_evas_buffer_new(1, 1);
320
                  if (!ee)
321
                    {
322
                       ERR("Cannot create buffer engine canvas for image save.");
323
                       exit(-1);
324
                    }
325
                  evas = ecore_evas_get(ee);
326
                  im = evas_object_image_add(evas);
327
                  if (!im)
328
                    {
329
                       ERR("Cannot create image object for save.");
330
                       exit(-1);
331
                    }
332
                  snprintf(buf, sizeof(buf), "edje/images/%i", ei->id);
333
                  evas_object_image_file_set(im, file_in, buf);
334
                  snprintf(out, sizeof(out), "%s/%s", outdir, ei->entry);
335
                  INF("Output Image: %s", out);
336
                  pp = strdup(out);
337
                  p = strrchr(pp, '/');
338
                  if (p) *p = 0;
339
                  if (strstr(pp, "../"))
340
                    {
341
                       ERR("Potential security violation. attempt to write in parent dir.");
342
                       exit(-1);
343
                    }
344
                  ecore_file_mkpath(pp);
345
                  free(pp);
346
                  if (!evas_object_image_save(im, out, NULL, "quality=100 compress=9 encoding=auto"))
347
                    {
348
                       ERR("Cannot write file %s. Perhaps missing JPEG or PNG saver modules for Evas.", out);
349
                       exit(-1);
350
                    }
351
                  evas_object_del(im);
352
                  ecore_evas_free(ee);
353
                  ecore_evas_shutdown();
354
                  ecore_shutdown();
355
               }
356
          }
357
     }
358

359
   EINA_LIST_FOREACH(srcfiles->list, l, sf)
360
     {
361
        char out[4096];
362
        FILE *f;
363
        char *pp;
364

365
        snprintf(out, sizeof(out), "%s/%s", outdir, sf->name);
366
        INF("Output Source File: %s", out);
367
        pp = strdup(out);
368
        p = strrchr(pp, '/');
369
        if (p) *p = 0;
370
        if (strstr(pp, "../"))
371
          {
372
             ERR("Potential security violation. attempt to write in parent dir.");
373
             exit(-1);
374
          }
375
        ecore_file_mkpath(pp);
376
        free(pp);
377
        if (strstr(out, "../"))
378
          {
379
             ERR("Potential security violation. attempt to write in parent dir.");
380
             exit(-1);
381
          }
382
        f = fopen(out, "wb");
383
        if (!f)
384
          {
385
             ERR("Unable to write file (%s).", out);
386
             exit(-1);
387
          }
388

389
        /* if the file is empty, sf->file will be NULL.
390
         * note that that's not an error
391
         */
392
        if (sf->file) fputs(sf->file, f);
393
        fclose(f);
394
     }
395
   if (edje_file->fonts)
396
     {
397
        Edje_Font_Directory_Entry *fn;
398
        Eina_Iterator *it;
399

400
        it = eina_hash_iterator_data_new(edje_file->fonts);
401
        EINA_ITERATOR_FOREACH(it, fn)
402
          {
403
             void *font;
404
             int fontsize;
405
             char out[4096];
406
             /* FIXME!!!! */
407
             /* should be fn->entry -v */
408
             snprintf(out, sizeof(out), "edje/fonts/%s", fn->file);
409
             font = eet_read(tef, out, &fontsize);
410
             if (font)
411
               {
412
                  FILE *f;
413
                  char *pp;
414

415
                  /* should be fn->file -v */
416
                  snprintf(out, sizeof(out), "%s/%s", outdir, fn->entry);
417
                  INF("Output Font: %s", out);
418
                  pp = strdup(out);
419
                  p = strrchr(pp, '/');
420
                  if (p) *p = 0;
421
                  if (strstr(pp, "../"))
422
                    {
423
                       ERR("Potential security violation. attempt to write in parent dir.");
424
                       exit(-1);
425
                    }
426
                  ecore_file_mkpath(pp);
427
                  free(pp);
428
                  if (strstr(out, "../"))
429
                    {
430
                       ERR("Potential security violation. attempt to write in parent dir.");
431
                       exit(-1);
432
                    }
433
                  if (!(f = fopen(out, "wb")))
434
                    {
435
                       ERR("Could not open file: %s", out);
436
                       exit(-1);
437
                    }
438
                  if (fwrite(font, fontsize, 1, f) != 1)
439
                    ERR("Could not write font: %s", strerror(errno));
440
                  if (f) fclose(f);
441
                  free(font);
442
               }
443
          }
444
        eina_iterator_free(it);
445
     }
446
   {
447
      char out[4096];
448
      FILE *f;
449
      sf = eina_list_data_get(srcfiles->list);
450

451
      if (build_sh)
452
        {
453
           snprintf(out, sizeof(out), "%s/build.sh", outdir);
454
           INF("Output Build Script: %s", out);
455
           if (strstr(out, "../"))
456
             {
457
                ERR("potential security violation. attempt to write in parent dir.");
458
                exit(-1);
459
             }
460
           if ((f = fopen(out, "wb")))
461
             {
462
                fprintf(f, "#!/bin/sh\n");
463
                fprintf(f, "%s $@ -id . -fd . %s -o %s.edj\n",
464
                        edje_file->compiler, sf->name, outdir);
465
                fclose(f);
466
                if (chmod(out,
467
                          S_IRUSR | S_IWUSR | S_IXUSR |
468
                          S_IRGRP | S_IWGRP | S_IXGRP) < 0)
469
                  ERR("chmod on %s failed", out);
470
             }
471

472
           WRN("*** CAUTION ***\n"
473
               "Please check the build script for anything malicious "
474
               "before running it!\n\n");
475
        }
476

477
      if (file_out)
478
        {
479
           snprintf(out, sizeof(out), "%s/%s", outdir, file_out);
480
           if (ecore_file_symlink(sf->name, out) != EINA_TRUE)
481
             {
482
                ERR("symlink %s -> %s failed", sf->name, out);
483
             }
484
        }
485
   }
486

487
   if (edje_file->sound_dir)
488
     {
489
        Edje_Sound_Sample *sample;
490
        void *sound_data;
491
        char out[PATH_MAX];
492
        char out1[PATH_MAX];
493
        char *pp;
494
        int sound_data_size;
495
        FILE *f;
496
        int i;
497

498
        for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
499
          {
500
             sample = &edje_file->sound_dir->samples[i];
501
             if ((!sample) || (!sample->name)) continue;
502
             snprintf(out, sizeof(out), "edje/sounds/%i", sample->id);
503
             sound_data = (void *)eet_read_direct(tef, out, &sound_data_size);
504
             if (sound_data)
505
               {
506
                  snprintf(out1, sizeof(out1), "%s/%s", outdir, sample->snd_src);
507
                  pp = strdup(out1);
508
                  p = strrchr(pp, '/');
509
                  if (p) *p = 0;
510
                  if (strstr(pp, "../"))
511
                    {
512
                       ERR("Potential security violation. attempt to write in parent dir.");
513
                       exit(-1);
514
                    }
515
                  ecore_file_mkpath(pp);
516
                  free(pp);
517
                  if (strstr(out, "../"))
518
                    {
519
                       ERR("Potential security violation. attempt to write in parent dir.");
520
                       exit(-1);
521
                    }
522
                  f = fopen(out1, "wb");
523
                  if (f)
524
                    {
525
                       if (fwrite(sound_data, sound_data_size, 1, f) != 1)
526
                         ERR("Could not write sound: %s: %s", out1, strerror(errno));
527
                       fclose(f);
528
                    }
529
                  else ERR("Could not open for writing sound: %s: %s", out1, strerror(errno));
530
               }
531
          }
532
     }
533
   if (edje_file->vibration_dir)
534
     {
535
        Edje_Vibration_Sample *sample;
536
        void *data;
537
        char out[PATH_MAX];
538
        char out1[PATH_MAX];
539
        char *pp;
540
        int data_size;
541
        FILE *f;
542
        int i;
543

544
        for (i = 0; i < (int)edje_file->vibration_dir->samples_count; i++)
545
          {
546
             sample = &edje_file->vibration_dir->samples[i];
547
             if ((!sample) || (!sample->name)) continue;
548
             snprintf(out, sizeof(out), "edje/vibrations/%i", sample->id);
549
             data = (void *)eet_read_direct(tef, out, &data_size);
550
             if (data)
551
               {
552
                  snprintf(out1, sizeof(out1), "%s/%s", outdir, sample->src);
553
                  pp = strdup(out1);
554
                  p = strrchr(pp, '/');
555
                  if (p) *p = 0;
556
                  if (strstr(pp, "../"))
557
                    {
558
                       ERR("Potential security violation. attempt to write in parent dir.");
559
                       exit(-1);
560
                    }
561
                  ecore_file_mkpath(pp);
562
                  free(pp);
563
                  if (strstr(out, "../"))
564
                    {
565
                       ERR("Potential security violation. attempt to write in parent dir.");
566
                       exit(-1);
567
                    }
568
                  f = fopen(out1, "wb");
569
                  if (f)
570
                    {
571
                       if (fwrite(data, data_size, 1, f) != 1)
572
                         ERR("Could not write sound: %s", strerror(errno));
573
                       fclose(f);
574
                    }
575
                  else ERR("Could not open for writing sound: %s: %s", out1, strerror(errno));
576
               }
577
          }
578
     }
579

580
   eet_close(tef);
581
   if (outdir) free(outdir);
582
}
583

584
static int
585
compiler_cmd_is_sane()
586
{
587
   const char *c = edje_file->compiler, *ptr;
588

589
   if ((!c) || (!*c))
590
     {
591
        return 0;
592
     }
593

594
   for (ptr = c; ptr && *ptr; ptr++)
595
     {
596
        /* only allow [a-z][A-Z][0-9]_- */
597
        if ((!isalnum(*ptr)) && (*ptr != '_') && (*ptr != '-'))
598
          {
599
             return 0;
600
          }
601
     }
602

603
   return 1;
604
}
605

606
static int
607
root_filename_is_sane()
608
{
609
   SrcFile *sf = eina_list_data_get(srcfiles->list);
610
   char *f = sf->name, *ptr;
611

612
   if (!f || !*f)
613
     {
614
        return 0;
615
     }
616

617
   for (ptr = f; ptr && *ptr; ptr++)
618
     {
619
        /* only allow [a-z][A-Z][0-9]_-./ */
620
        switch (*ptr)
621
          {
622
           case '_':
623
           case '-':
624
           case '.':
625
           case '/':
626
             break;
627

628
           default:
629
             if (!isalnum(*ptr))
630
               {
631
                  return 0;
632
               }
633
          }
634
     }
635
   return 1;
636
}
637

638

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.