efl

Форк
0
/
edje_cc_out.c 
4654 строки · 135.3 Кб
1
#ifdef HAVE_CONFIG_H
2
# include "config.h"
3
#endif
4

5
#ifdef STDC_HEADERS
6
# include <stdlib.h>
7
# include <stddef.h>
8
#else
9
# ifdef HAVE_STDLIB_H
10
#  include <stdlib.h>
11
# endif
12
#endif
13

14
#include <string.h>
15
#include <limits.h>
16
#include <unistd.h>
17
#include <sys/stat.h>
18
#include <libgen.h>
19

20
#include <Ecore_Evas.h>
21

22
#include "edje_cc.h"
23
#include "edje_convert.h"
24
#include "edje_multisense_convert.h"
25

26
#include <lua.h>
27
#include <lauxlib.h>
28

29
typedef struct _External_Lookup External_Lookup;
30
typedef struct _Part_Lookup     Part_Lookup;
31
typedef struct _Part_Lookup_Key Part_Lookup_Key;
32
typedef struct _Program_Lookup  Program_Lookup;
33
typedef struct _Group_Lookup    Group_Lookup;
34
typedef struct _Image_Lookup    Image_Lookup;
35
typedef struct _Code_Lookup     Code_Lookup;
36

37
struct _External_Lookup
38
{
39
   char *name;
40
};
41

42
struct _Part_Lookup_Key
43
{
44
   Edje_Part_Collection *pc;
45

46
   union
47
   {
48
      int *dest;
49
      struct
50
      {
51
         unsigned char **base;
52
         int             offset;
53
      } reallocated;
54
   } mem;
55
   char    **dest2;
56

57
   Eina_Bool stable : 1;
58
};
59

60
struct _Part_Lookup
61
{
62
   Part_Lookup_Key key;
63
   char           *name;
64
};
65

66
struct _Program_Lookup
67
{
68
   Edje_Part_Collection *pc;
69

70
   union
71
   {
72
      char         *name;
73
      Edje_Program *ep;
74
   } u;
75

76
   int                  *dest;
77

78
   Eina_Bool             anonymous : 1;
79
};
80

81
struct _Group_Lookup
82
{
83
   char      *name;
84
   Edje_Part *part;
85
};
86

87
struct _String_Lookup
88
{
89
   char *name;
90
   int  *dest;
91
};
92

93
struct _Image_Lookup
94
{
95
   char      *name;
96
   int       *dest;
97
   Eina_Bool *set;
98
};
99

100
struct _Code_Lookup
101
{
102
   char     *ptr;
103
   int       len;
104
   int       val;
105
   Eina_Bool set;
106
};
107

108
typedef struct _Script_Lua_Writer Script_Lua_Writer;
109

110
struct _Script_Lua_Writer
111
{
112
   char *buf;
113
   int   size;
114
};
115

116
typedef struct _Script_Write    Script_Write;
117
typedef struct _Head_Write      Head_Write;
118
typedef struct _Fonts_Write     Fonts_Write;
119
typedef struct _Image_Write     Image_Write;
120
typedef struct _Sound_Write     Sound_Write;
121
typedef struct _Mo_Write        Mo_Write;
122
typedef struct _Vibration_Write Vibration_Write;
123
typedef struct _Group_Write     Group_Write;
124
typedef struct _License_Write   License_Write;
125

126
struct _Script_Write
127
{
128
   Eet_File    *ef;
129
   Code        *cd;
130
   int          i;
131
   Ecore_Exe   *exe;
132
   int          tmpn_fd;
133
   Eina_Tmpstr *tmpn;
134
   Eina_Tmpstr *tmpo;
135
   char        *errstr;
136
};
137

138
struct _Head_Write
139
{
140
   Eet_File *ef;
141
   char     *errstr;
142
};
143

144
struct _Fonts_Write
145
{
146
   Eet_File  *ef;
147
   Edje_Font *fn;
148
   char      *errstr;
149
};
150

151
struct _Image_Write
152
{
153
   Eet_File                   *ef;
154
   Edje_Image_Directory_Entry *img;
155
   Evas_Object                *im;
156
   Emile_Image_Property        prop;
157
   Eina_File                  *f;
158
   Emile_Image                *emi;
159
   int                         w, h;
160
   int                         alpha;
161
   unsigned int               *data;
162
   char                       *path;
163
   char                       *errstr;
164
};
165

166
struct _Sound_Write
167
{
168
   Eet_File          *ef;
169
   Edje_Sound_Sample *sample;
170
   int                i;
171
};
172

173
struct _Mo_Write
174
{
175
   Eet_File  *ef;
176
   Edje_Mo   *mo_entry;
177
   char      *mo_path;
178
   Ecore_Exe *exe;
179
   char      *errstr;
180
};
181

182
struct _Vibration_Write
183
{
184
   Eet_File              *ef;
185
   Edje_Vibration_Sample *sample;
186
   int                    i;
187
};
188

189
struct _Group_Write
190
{
191
   Eet_File             *ef;
192
   Edje_Part_Collection *pc;
193
   char                 *errstr;
194
};
195

196
struct _License_Write
197
{
198
   Eet_File   *ef;
199
   const char *file;
200
   Eina_Bool   master;
201
};
202

203
struct _Image_Unused_Ids
204
{
205
   int old_id;
206
   int new_id;
207
};
208

209
typedef struct _Image_Unused_Ids Image_Unused_Ids;
210

211
static int pending_threads = 0;
212
static int pending_image_threads = 0;
213

214
static void data_process_string(Edje_Part_Collection *pc, const char *prefix, char *s, void (*func)(Edje_Part_Collection *pc, char *name, char *ptr, int len));
215

216
extern Eina_List *po_files;
217

218
Edje_File *edje_file = NULL;
219
Eina_List *edje_collections = NULL;
220
Eina_Hash *edje_collections_lookup = NULL;
221
Eina_List *externals = NULL;
222
Eina_List *fonts = NULL;
223
Eina_List *codes = NULL;
224
Eina_List *code_lookups = NULL;
225
Eina_List *aliases = NULL;
226
Eina_List *color_tree_root = NULL;
227
Eina_Hash *color_class_reg = NULL;
228

229
static Eet_Data_Descriptor *edd_edje_file = NULL;
230
static Eet_Data_Descriptor *edd_edje_part_collection = NULL;
231

232
static Eina_List *program_lookups = NULL;
233
static Eina_List *group_lookups = NULL;
234
static Eina_List *face_group_lookups = NULL;
235
static Eina_List *image_lookups = NULL;
236

237
static Eina_Hash *part_dest_lookup = NULL;
238
static Eina_Hash *part_pc_dest_lookup = NULL;
239
static Eina_Hash *groups_sourced = NULL;
240

241
static Eet_File *cur_ef;
242
static int image_num;
243
static Ecore_Evas *buffer_ee;
244
static int cur_image_entry;
245

246
static void data_write_images(void);
247

248
void
249
error_and_abort(Eet_File *ef EINA_UNUSED, const char *fmt, ...)
250
{
251
   va_list ap;
252

253
   va_start(ap, fmt);
254
   eina_log_vprint(_edje_cc_log_dom, EINA_LOG_LEVEL_CRITICAL,
255
                   "unknown", "unknown", 0, fmt, ap);
256
   va_end(ap);
257
   unlink(file_out);
258
   if (watchfile) unlink(watchfile);
259
   exit(-1);
260
}
261

262
static void
263
thread_end(Eina_Bool img)
264
{
265
   if (img)
266
     pending_image_threads--;
267
   else
268
     pending_threads--;
269
   if (threads)
270
     {
271
        if ((pending_image_threads + pending_threads) < (int)max_open_files - 2)
272
          data_write_images();
273
     }
274
   if (pending_threads + pending_image_threads <= 0) ecore_main_loop_quit();
275
}
276

277
static unsigned int
278
_part_lookup_key_length(const void *key EINA_UNUSED)
279
{
280
   return sizeof (Part_Lookup_Key);
281
}
282

283
static int
284
_part_lookup_key_pc_cmp(const void *key1, int key1_length EINA_UNUSED,
285
                        const void *key2, int key2_length EINA_UNUSED)
286
{
287
   const Part_Lookup_Key *a = key1;
288
   const Part_Lookup_Key *b = key2;
289
   uintptr_t delta;
290

291
   delta = a->pc - b->pc;
292
   if (delta) return delta;
293

294
   if (a->stable) return a->mem.dest - b->mem.dest;
295

296
   delta = a->mem.reallocated.base - b->mem.reallocated.base;
297
   if (delta) return delta;
298
   return a->mem.reallocated.offset - b->mem.reallocated.offset;
299
}
300

301
static int
302
_part_lookup_key_pc_hash(const void *key, int key_length EINA_UNUSED)
303
{
304
   const Part_Lookup_Key *a = key;
305

306
   if (a->stable)
307
     {
308
#ifdef EFL64
309
        return eina_hash_int64((unsigned long long int *)&a->pc, sizeof (void *)) ^
310
               eina_hash_int64((unsigned long long int *)&a->mem.dest, sizeof (void *));
311
#else
312
        return eina_hash_int32((uintptr_t *)&a->pc, sizeof (void *)) ^
313
               eina_hash_int32((uintptr_t *)&a->mem.dest, sizeof (void *));
314
#endif
315
     }
316
   else
317
     {
318
#ifdef EFL64
319
        return eina_hash_int64((unsigned long long int *)&a->pc, sizeof (void *)) ^
320
               eina_hash_int64((unsigned long long int *)&a->mem.reallocated.base, sizeof (void *)) ^
321
               eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
322
#else
323
        return eina_hash_int32((uintptr_t *)&a->pc, sizeof (void *)) ^
324
               eina_hash_int32((uintptr_t *)&a->mem.reallocated.base, sizeof (void *)) ^
325
               eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
326
#endif
327
     }
328
}
329

330
static int
331
_part_lookup_key_cmp(const void *key1, int key1_length EINA_UNUSED,
332
                     const void *key2, int key2_length EINA_UNUSED)
333
{
334
   const Part_Lookup_Key *a = key1;
335
   const Part_Lookup_Key *b = key2;
336
   uintptr_t delta;
337

338
   if (a->stable) return a->mem.dest - b->mem.dest;
339

340
   delta = a->mem.reallocated.base - b->mem.reallocated.base;
341
   if (delta) return delta;
342
   return a->mem.reallocated.offset - b->mem.reallocated.offset;
343
}
344

345
static int
346
_part_lookup_key_hash(const void *key, int key_length EINA_UNUSED)
347
{
348
   const Part_Lookup_Key *a = key;
349

350
   if (a->stable)
351
     {
352
#ifdef EFL64
353
        return eina_hash_int64((unsigned long long int *)&a->mem.dest, sizeof (void *));
354
#else
355
        return eina_hash_int32((uintptr_t *)&a->mem.dest, sizeof (void *));
356
#endif
357
     }
358
   else
359
     {
360
#ifdef EFL64
361
        return eina_hash_int64((unsigned long long int *)&a->mem.reallocated.base, sizeof (void *)) ^
362
               eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
363
#else
364
        return eina_hash_int32((uintptr_t *)&a->mem.reallocated.base, sizeof (void *)) ^
365
               eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
366
#endif
367
     }
368
}
369

370
static void
371
data_part_lookup_free(Part_Lookup *pl)
372
{
373
   free(pl->name);
374
   free(pl);
375
}
376

377
static void
378
list_free(void *list)
379
{
380
   eina_list_free(list);
381
}
382

383
void
384
data_setup(void)
385
{
386
   edd_edje_file = _edje_edd_edje_file;
387
   edd_edje_part_collection = _edje_edd_edje_part_collection;
388

389
   part_dest_lookup = eina_hash_new(EINA_KEY_LENGTH(_part_lookup_key_length),
390
                                    EINA_KEY_CMP(_part_lookup_key_cmp),
391
                                    EINA_KEY_HASH(_part_lookup_key_hash),
392
                                    EINA_FREE_CB(list_free),
393
                                    8);
394
   part_pc_dest_lookup = eina_hash_new(EINA_KEY_LENGTH(_part_lookup_key_length),
395
                                       EINA_KEY_CMP(_part_lookup_key_pc_cmp),
396
                                       EINA_KEY_HASH(_part_lookup_key_pc_hash),
397
                                       EINA_FREE_CB(data_part_lookup_free),
398
                                       8);
399
}
400

401
static void
402
check_image_part_desc(Edje_Part_Collection *pc, Edje_Part *ep,
403
                      Edje_Part_Description_Image *epd, Eet_File *ef)
404
{
405
   unsigned int i;
406
   Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser *)pc;
407

408
   if (pcp->inherit_only) return;
409

410
   if (epd->image.id == -1 && epd->common.visible)
411
     WRN("Collection %s(%i): image attributes missing for "
412
         "part \"%s\", description \"%s\" %f",
413
         pc->part, pc->id, ep->name, epd->common.state.name, epd->common.state.value);
414

415
   for (i = 0; i < epd->image.tweens_count; ++i)
416
     {
417
        if (epd->image.tweens[i]->id == -1)
418
          error_and_abort(ef, "Collection %i: tween image id missing for "
419
                              "part \"%s\", description \"%s\" %f",
420
                          pc->id, ep->name, epd->common.state.name, epd->common.state.value);
421
     }
422
}
423

424
static Edje_Part_Collection *
425
_source_group_find(const char *source)
426
{
427
   Edje_Part_Collection *pc2;
428
   Eina_List *l;
429
   if (!source) return NULL;
430
   EINA_LIST_FOREACH(edje_collections, l, pc2)
431
     {
432
        if (!strcmp(pc2->part, source))
433
          return pc2;
434
     }
435
   return NULL;
436
}
437

438
static Edje_Part *
439
_aliased_text_part_find(Edje_Part_Collection *pc,
440
                        int id_source, const char *id_source_part)
441
{
442
   Edje_Part_Collection *group;
443
   unsigned int i;
444

445
   if (!pc->parts[id_source]->source)
446
     return NULL;
447

448
   group = _source_group_find(pc->parts[id_source]->source);
449
   if (!group) return NULL;
450

451
   for (i = 0; i < group->parts_count; i++)
452
     {
453
        if (!strcmp(group->parts[i]->name, id_source_part))
454
          return group->parts[i];
455
     }
456
   return NULL;
457
}
458

459
static void
460
check_text_part_desc(Edje_Part_Collection *pc, Edje_Part *ep,
461
                     Edje_Part_Description_Text *epd, Eet_File *ef)
462
{
463
   Edje_Part *ep2;
464

465
   if (epd->text.id_source != -1)
466
     {
467
        if ((pc->parts[epd->text.id_source]->type == EDJE_PART_TYPE_TEXT) ||
468
            (pc->parts[epd->text.id_source]->type == EDJE_PART_TYPE_TEXTBLOCK))
469
          return;
470

471
        if (epd->text.id_source_part)
472
          {
473
             ep2 = _aliased_text_part_find(pc, epd->text.id_source, epd->text.id_source_part);
474
             if (ep2 && ((ep2->type == EDJE_PART_TYPE_TEXT) ||
475
                         (ep2->type == EDJE_PART_TYPE_TEXTBLOCK)))
476
               return;
477
          }
478

479
        error_and_abort(ef, "Collection \"%s\" Part \"%s\" Description \"%s\" [%.3f]: "
480
                            "text.source point to a non TEXT part \"%s\"!",
481
                        pc->part, ep->name, epd->common.state.name,
482
                        epd->common.state.value, pc->parts[epd->text.id_source]->name);
483
     }
484

485
   if (epd->text.id_text_source != -1)
486
     {
487
        if ((pc->parts[epd->text.id_text_source]->type == EDJE_PART_TYPE_TEXT) ||
488
            (pc->parts[epd->text.id_text_source]->type == EDJE_PART_TYPE_TEXTBLOCK))
489
          return;
490

491
        if (epd->text.id_text_source_part)
492
          {
493
             ep2 = _aliased_text_part_find(pc, epd->text.id_text_source, epd->text.id_text_source_part);
494
             if (ep2 && ((ep2->type == EDJE_PART_TYPE_TEXT) ||
495
                         (ep2->type == EDJE_PART_TYPE_TEXTBLOCK)))
496
               return;
497
          }
498

499
        error_and_abort(ef, "Collection \"%s\" Part \"%s\" Description \"%s\" [%.3f]: "
500
                            "text.text_source point to a non TEXT part \"%s\"!",
501
                        pc->part, ep->name, epd->common.state.name,
502
                        epd->common.state.value, pc->parts[epd->text.id_text_source]->name);
503
     }
504
}
505

506
/* This function check loops between groups.
507
   For example:
508
   > part in group A. It's source is B.
509
   > part in group B. It's source is C.
510
   > part in group C. It's source is A <- here is error.
511
   It's loop that we need to avoid! */
512
static void
513
check_source_links(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef, Eina_List *group_path)
514
{
515
   unsigned int i;
516
   char *data;
517
   Edje_Part_Collection *pc_source;
518
   Eina_List *l;
519

520
   EINA_LIST_FOREACH(edje_collections, l, pc_source)
521
     {
522
        /* Find sourced group */
523
        if (ep->source && pc_source->part && strcmp(ep->source, pc_source->part) == 0)
524
          {
525
             /* Go through every part to find parts with type GROUP */
526
             for (i = 0; i < pc_source->parts_count; ++i)
527
               {
528
                  if ((pc_source->parts[i]->type == EDJE_PART_TYPE_GROUP) &&
529
                      (pc_source->parts[i]->source))
530
                    {
531
                       /* Make sure that this group isn't already in the tree of parents */
532
                       EINA_LIST_FOREACH(group_path, l, data)
533
                         {
534
                            if (data == pc_source->parts[i]->source)
535
                              {
536
                                 error_and_abort(ef, "Recursive loop group '%s' "
537
                                                     "already included inside "
538
                                                     "part '%s' of group '%s'",
539
                                                 data, pc_source->parts[i]->name,
540
                                                 pc->part);
541
                              }
542
                         }
543
                       group_path = eina_list_append(group_path, ep->source);
544
                       check_source_links(pc, pc_source->parts[i], ef, group_path);
545
                    }
546
               }
547
          }
548
     }
549
}
550

551
static void
552
check_packed_items(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
553
{
554
   unsigned int i;
555

556
   for (i = 0; i < ep->items_count; ++i)
557
     {
558
        if (ep->items[i]->type == EDJE_PART_TYPE_GROUP && !ep->items[i]->source)
559
          error_and_abort(ef, "Collection %i: missing source on packed item "
560
                              "of type GROUP in part \"%s\"",
561
                          pc->id, ep->name);
562
        if (ep->type == EDJE_PART_TYPE_TABLE && (ep->items[i]->col < 0 || ep->items[i]->row < 0))
563
          error_and_abort(ef, "Collection %i: missing col/row on packed item "
564
                              "for part \"%s\" of type TABLE",
565
                          pc->id, ep->name);
566
     }
567
}
568

569
static void
570
check_nameless_state(Edje_Part_Collection *pc, Edje_Part *ep, Edje_Part_Description_Common *ed, Eet_File *ef)
571
{
572
   Edje_Part_Collection_Directory_Entry *de;
573

574
   if (ed->state.name) return;
575

576
   de = eina_hash_find(edje_collections_lookup, &pc->id);
577
   error_and_abort(ef, "Group '%s': part \"%s\" has description with missing state",
578
                   de->entry, ep->name);
579
}
580

581
static void
582
check_state(Edje_Part_Collection *pc, Edje_Part *ep, Edje_Part_Description_Common *ed, Eet_File *ef)
583
{
584
   check_nameless_state(pc, ep, ed, ef);
585
}
586

587
static void
588
_part_namespace_verify(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef, Eina_Bool ns_required)
589
{
590
   char buf[1024], *p;
591
   size_t len;
592
   Edje_Part_Collection_Directory_Entry *de;
593

594
   if (!namespace_verify) return;
595
   /* this is from a group used as a source, either GROUP or TEXTBLOCK
596
    * namespacing not required
597
    */
598
   if (eina_hash_find(groups_sourced, pc->part)) return;
599

600
   de = eina_hash_find(edje_collections_lookup, &pc->id);
601

602
   p = strchr(de->entry, '/');
603
   if (!p) return;
604

605
   len = p - de->entry;
606
   if (eina_strlcpy(buf, de->entry, len + 1) >= sizeof(buf)) return;
607

608
   p = strchr(ep->name, '.');
609
   /* ignore part types without required namespacing or without '.' in name */
610
   if ((!ns_required) && (!p)) return;
611

612
   if (strncmp(ep->name, buf, len))
613
     error_and_abort(ef, "Part '%s' from group %s is not properly namespaced (should begin with '%s.')!", ep->name, de->entry, buf);
614
}
615

616
static void
617
check_part(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
618
{
619
   Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser*)pc;
620
   unsigned int i;
621
   Eina_List *group_path = NULL;
622
   /* FIXME: check image set and sort them. */
623
   if (!ep->default_desc)
624
     error_and_abort(ef, "Collection %i: default description missing "
625
                         "for part \"%s\"", pc->id, ep->name);
626

627
   check_state(pc, ep, ep->default_desc, ef);
628
   for (i = 0; i < ep->other.desc_count; ++i)
629
     check_state(pc, ep, ep->other.desc[i], ef);
630

631
   if (ep->type == EDJE_PART_TYPE_IMAGE)
632
     {
633
        check_image_part_desc(pc, ep, (Edje_Part_Description_Image *)ep->default_desc, ef);
634

635
        for (i = 0; i < ep->other.desc_count; ++i)
636
          check_image_part_desc(pc, ep, (Edje_Part_Description_Image *)ep->other.desc[i], ef);
637
     }
638
   else if ((ep->type == EDJE_PART_TYPE_BOX) ||
639
            (ep->type == EDJE_PART_TYPE_TABLE))
640
     check_packed_items(pc, ep, ef);
641
   else if (ep->type == EDJE_PART_TYPE_GROUP)
642
     check_source_links(pc, ep, ef, group_path);
643
   else if (ep->type == EDJE_PART_TYPE_TEXT)
644
     {
645
        check_text_part_desc(pc, ep, (Edje_Part_Description_Text *)ep->default_desc, ef);
646

647
        for (i = 0; i < ep->other.desc_count; ++i)
648
          check_text_part_desc(pc, ep, (Edje_Part_Description_Text *)ep->other.desc[i], ef);
649
     }
650

651
   if (!pcp->skip_namespace_validation)
652
     {
653
        switch (ep->type)
654
          {
655
           case EDJE_PART_TYPE_BOX:
656
           case EDJE_PART_TYPE_TABLE:
657
           case EDJE_PART_TYPE_SWALLOW:
658
             _part_namespace_verify(pc, ep, ef, 1);
659
             break;
660
           case EDJE_PART_TYPE_TEXT:
661
           case EDJE_PART_TYPE_TEXTBLOCK:
662
           case EDJE_PART_TYPE_SPACER:
663
             _part_namespace_verify(pc, ep, ef, 0);
664
             break;
665
           default: break;
666
          }
667
     }
668
}
669

670
static void
671
_program_signal_namespace_verify(Edje_Part_Collection *pc, Eet_File *ef, const char *sig, const char *src)
672
{
673
   char buf[1024], *p;
674
   size_t len;
675
   Edje_Part_Collection_Directory_Entry *de;
676

677
   if (!namespace_verify) return;
678
   /* this is from a group used as a source, either GROUP or TEXTBLOCK
679
    * namespacing not required
680
    */
681
   if (eina_hash_find(groups_sourced, pc->part)) return;
682

683
   /* ignore propagation to GROUP parts */
684
   if (strchr(sig, ':')) return;
685

686
   de = eina_hash_find(edje_collections_lookup, &pc->id);
687

688
   p = strchr(de->entry, '/');
689
   if (!p) return;
690
   len = p - de->entry;
691
   if (eina_strlcpy(buf, de->entry, len + 1) >= sizeof(buf)) return;
692

693
   if (strncmp(sig, buf, len))
694
     error_and_abort(ef, "SIGNAL_EMIT (%s:%s) does not match group namespace (%s)!", sig, src, de->entry);
695
}
696

697
static void
698
check_program(Edje_Part_Collection *pc, Edje_Program *ep, Eet_File *ef)
699
{
700
   Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser*)pc;
701
   switch (ep->action)
702
     {
703
      case EDJE_ACTION_TYPE_STATE_SET:
704
      case EDJE_ACTION_TYPE_ACTION_STOP:
705
      case EDJE_ACTION_TYPE_DRAG_VAL_SET:
706
      case EDJE_ACTION_TYPE_DRAG_VAL_STEP:
707
      case EDJE_ACTION_TYPE_DRAG_VAL_PAGE:
708
        if (!ep->targets)
709
          error_and_abort(ef, "Collection %i: target missing in program "
710
                              "\"%s\"", pc->id, ep->name);
711
        break;
712

713
      default:
714
        break;
715
     }
716
   Edje_Program_Target *et;
717
   Eina_List *l;
718
   unsigned int i = 0;
719

720
    if ((!ep->targets) && (ep->action == EDJE_ACTION_TYPE_SIGNAL_EMIT))
721
      {
722
         if (!pcp->skip_namespace_validation)
723
           _program_signal_namespace_verify(pc, ef, ep->state, ep->state2);
724
      }
725

726
   EINA_LIST_FOREACH(ep->targets, l, et)
727
     {
728
        Edje_Part *part;
729

730
        /*
731
         * we are accessing part with an id,
732
         * if actions is ACTION_STOP or ACTION_TYPE_SCRIPT, then id is NOT from the parts array.
733
         * In order to not crash here, we should continue here.
734
         */
735
        if (ep->action == EDJE_ACTION_TYPE_ACTION_STOP || ep->action == EDJE_ACTION_TYPE_SCRIPT)
736
          continue;
737

738
        if (et->id >= (int) pc->parts_count)
739
          {
740
             ERR("In group '%s' program '%s', target id '%d' greater than possible index '%d'.", 
741
                 pc->part ? pc->part : "", ep->name ? ep->name : "", et->id, (int) pc->parts_count - 1);
742
             exit(-1);
743
          }
744

745
        part = pc->parts[et->id];
746
        /* verify existence of description in part */
747
        if (ep->action == EDJE_ACTION_TYPE_STATE_SET)
748
          {
749
             if ((!eina_streq(ep->state, "custom")) &&
750
               ((!eina_streq(ep->state, "default")) || (!EINA_DBL_EQ(ep->value, 0.0))))
751
               {
752
                  Edje_Part_Collection_Directory_Entry *de;
753
                  Eina_Bool found = EINA_FALSE;
754
                  for (i = 0; i < part->other.desc_count; i++)
755
                    {
756
                       Edje_Part_Description_Common *ed = part->other.desc[i];
757
                       if (eina_streq(ed->state.name, ep->state) && EINA_DBL_EQ(ep->value, ed->state.value))
758
                         {
759
                            found = EINA_TRUE;
760
                            break;
761
                         }
762
                    }
763
                  if (!found)
764
                    {
765
                       de = eina_hash_find(edje_collections_lookup, &pc->id);
766
                       error_and_abort(NULL, "GROUP %s - state '%s:%g' does not exist for part '%s'; set in program '%s'",
767
                         de->entry, ep->state, ep->value, part->name, ep->name);
768
                    }
769
               }
770
          }
771
     }
772
}
773

774
/* reset part counters for alias */
775
static void
776
_alias_clean(Edje_Part_Collection_Directory_Entry *ce)
777
{
778
   if (ce)
779
     {
780
        ce->count.RECTANGLE = 0;
781
        ce->count.TEXT = 0;
782
        ce->count.IMAGE = 0;
783
        ce->count.SWALLOW = 0;
784
        ce->count.TEXTBLOCK = 0;
785
        ce->count.GROUP = 0;
786
        ce->count.BOX = 0;
787
        ce->count.TABLE = 0;
788
        ce->count.EXTERNAL = 0;
789
        ce->count.PROXY = 0;
790
        ce->count.SPACER = 0;
791
        ce->count.VECTOR = 0;
792
        ce->count.part = 0;
793
     }
794
}
795

796
static void
797
data_thread_head(void *data, Ecore_Thread *thread EINA_UNUSED)
798
{
799
   Head_Write *hw = data;
800
   int bytes = 0;
801
   char buf[EINA_PATH_MAX];
802

803
   if (edje_file)
804
     {
805
        if (edje_file->collection)
806
          {
807
             Edje_Part_Collection_Directory_Entry *ce;
808

809
             EINA_LIST_FREE(aliases, ce)
810
               {
811
                  Edje_Part_Collection_Directory_Entry *sce;
812

813
                  if (!ce->entry)
814
                    {
815
                       snprintf(buf, sizeof(buf),
816
                                "Collection %i: name missing.", ce->id);
817
                       hw->errstr = strdup(buf);
818
                       return;
819
                    }
820

821
                  sce = eina_hash_find(edje_collections_lookup, &ce->id);
822
                  if (sce)
823
                    {
824
                       memcpy(&ce->count, &sce->count, sizeof (ce->count));
825
                    }
826
                  else
827
                    {
828
                       snprintf(buf, sizeof(buf),
829
                                "Collection %s (%i) can't find an correct alias.",
830
                                ce->entry, ce->id);
831
                       hw->errstr = strdup(buf);
832
                       return;
833
                    }
834

835
                  _alias_clean(ce);
836
                  eina_hash_direct_add(edje_file->collection, ce->entry, ce);
837
               }
838
          }
839
        bytes = eet_data_write(hw->ef, edd_edje_file, "edje/file", edje_file,
840
                               compress_mode);
841
        if (bytes <= 0)
842
          {
843
             snprintf(buf, sizeof(buf),
844
                      "Unable to write \"edje_file\" entry to \"%s\"",
845
                      file_out);
846
             hw->errstr = strdup(buf);
847
             return;
848
          }
849
     }
850

851
   INF("Wrote %9i bytes (%4iKb) for \"edje_file\" header",
852
       bytes, (bytes + 512) / 1024);
853
}
854

855
static void
856
data_thread_head_end(void *data, Ecore_Thread *thread EINA_UNUSED)
857
{
858
   Head_Write *hw = data;
859

860
   if (hw->errstr)
861
     {
862
        error_and_abort(hw->ef, hw->errstr);
863
        free(hw->errstr);
864
     }
865
   free(hw);
866
   thread_end(0);
867
}
868

869
static void
870
data_write_header(Eet_File *ef)
871
{
872
   Head_Write *hw;
873

874
   hw = calloc(1, sizeof(Head_Write));
875
   hw->ef = ef;
876
   pending_threads++;
877
   if (threads)
878
     ecore_thread_run(data_thread_head, data_thread_head_end, NULL, hw);
879
   else
880
     {
881
        data_thread_head(hw, NULL);
882
        data_thread_head_end(hw, NULL);
883
     }
884
}
885

886
static void
887
data_thread_fonts(void *data, Ecore_Thread *thread EINA_UNUSED)
888
{
889
   Fonts_Write *fc = data;
890
   Eina_List *ll;
891
   Eina_File *f = NULL;
892
   void *m = NULL;
893
   int bytes = 0;
894
   char buf[EINA_PATH_MAX];
895
   char buf2[EINA_PATH_MAX + EINA_PATH_MAX + 128];
896
   size_t size;
897

898
   f = eina_file_open(fc->fn->file, 0);
899
   if (f)
900
     {
901
        using_file(fc->fn->file, 'F');
902
        m = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
903
     }
904
   else
905
     {
906
        char *dat;
907

908
        EINA_LIST_FOREACH(fnt_dirs, ll, dat)
909
          {
910
             snprintf(buf, sizeof(buf), "%s/%s", dat, fc->fn->file);
911
             f = eina_file_open(buf, 0);
912
             if (f)
913
               {
914
                  using_file(buf, 'F');
915
                  m = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
916
                  if (m) break;
917
                  eina_file_close(f);
918
                  f = NULL;
919
               }
920
          }
921
     }
922
   if (!m)
923
     {
924
        if (f) eina_file_close(f);
925
        snprintf(buf, sizeof(buf),
926
                 "Unable to load font part \"%s\" entry to %s",
927
                 fc->fn->file, file_out);
928
        fc->errstr = strdup(buf);
929
        return;
930
     }
931

932
   snprintf(buf, sizeof(buf), "edje/fonts/%s", fc->fn->name);
933
   bytes = eet_write(fc->ef, buf, m, eina_file_size_get(f), compress_mode);
934

935
   if ((bytes <= 0) || eina_file_map_faulted(f, m))
936
     {
937
        eina_file_map_free(f, m);
938
        eina_file_close(f);
939
        snprintf(buf2, sizeof(buf2),
940
                 "Unable to write font part \"%s\" as \"%s\" "
941
                 "part entry to %s", fc->fn->file, buf, file_out);
942
        fc->errstr = strdup(buf2);
943
        return;
944
     }
945

946
   size = eina_file_size_get(f);
947
   INF("Wrote %9i bytes (%4iKb) for \"%s\" font entry \"%s\" compress: [real: %2.1f%%]",
948
       bytes, (bytes + 512) / 1024, buf, fc->fn->file,
949
       100 - (100 * (double)bytes) / ((double)((size > 0) ? size : 1))
950
       );
951
   eina_file_map_free(f, m);
952
   eina_file_close(f);
953
}
954

955
static void
956
data_thread_fonts_end(void *data, Ecore_Thread *thread EINA_UNUSED)
957
{
958
   Fonts_Write *fc = data;
959
   if (fc->errstr)
960
     {
961
        error_and_abort(fc->ef, fc->errstr);
962
        free(fc->errstr);
963
     }
964
   free(fc);
965
   thread_end(0);
966
}
967

968
static void
969
data_write_fonts(Eet_File *ef, int *font_num)
970
{
971
   Eina_Iterator *it;
972
   Edje_Font *fn;
973

974
   if (!edje_file->fonts) return;
975

976
   it = eina_hash_iterator_data_new(edje_file->fonts);
977
   EINA_ITERATOR_FOREACH(it, fn)
978
     {
979
        Fonts_Write *fc;
980

981
        fc = calloc(1, sizeof(Fonts_Write));
982
        if (!fc) continue;
983
        fc->ef = ef;
984
        fc->fn = fn;
985
        pending_threads++;
986
        if (threads)
987
          ecore_thread_run(data_thread_fonts, data_thread_fonts_end, NULL, fc);
988
        else
989
          {
990
             data_thread_fonts(fc, NULL);
991
             data_thread_fonts_end(fc, NULL);
992
          }
993
        *font_num += 1;
994
     }
995
   eina_iterator_free(it);
996
}
997

998
static void
999
error_and_abort_image_load_error(Eet_File *ef, const char *file, int error)
1000
{
1001
   const char *errmsg = evas_load_error_str(error);
1002
   char hint[1024] = "";
1003

1004
   if (error == EVAS_LOAD_ERROR_DOES_NOT_EXIST)
1005
     {
1006
        snprintf
1007
          (hint, sizeof(hint),
1008
          " Check if path to file \"%s\" is correct "
1009
          "(both directory and file name).",
1010
          file);
1011
     }
1012
   else if (error == EVAS_LOAD_ERROR_CORRUPT_FILE)
1013
     {
1014
        snprintf
1015
          (hint, sizeof(hint),
1016
          " Check if file \"%s\" is consistent.",
1017
          file);
1018
     }
1019
   else if (error == EVAS_LOAD_ERROR_UNKNOWN_FORMAT)
1020
     {
1021
        const char *ext = strrchr(file, '.');
1022
        const char **itr, *known_loaders[] = {
1023
           /* list from evas_image_load.c */
1024
           "png",
1025
           "jpg",
1026
           "jpeg",
1027
           "jfif",
1028
           "eet",
1029
           "edj",
1030
           "eap",
1031
           "edb",
1032
           "xpm",
1033
           "tiff",
1034
           "tif",
1035
           "svg",
1036
           "svgz",
1037
           "gif",
1038
           "pbm",
1039
           "pgm",
1040
           "ppm",
1041
           "pnm",
1042
           "bmp",
1043
           "ico",
1044
           "tga",
1045
           "tgv",
1046
           NULL
1047
        };
1048

1049
        if (!ext)
1050
          {
1051
             snprintf
1052
               (hint, sizeof(hint),
1053
               " File \"%s\" does not have an extension, "
1054
               "maybe it should?",
1055
               file);
1056
             goto show_err;
1057
          }
1058

1059
        ext++;
1060
        for (itr = known_loaders; *itr; itr++)
1061
          {
1062
             if (strcasecmp(ext, *itr) == 0)
1063
               {
1064
                  snprintf
1065
                    (hint, sizeof(hint),
1066
                    " Check if Evas was compiled with %s module enabled and "
1067
                    "all required dependencies exist.",
1068
                    ext);
1069
                  goto show_err;
1070
               }
1071
          }
1072

1073
        snprintf(hint, sizeof(hint),
1074
                 " Check if Evas supports loading files of type \"%s\" (%s) "
1075
                 "and this module was compiled and all its dependencies exist.",
1076
                 ext, file);
1077
     }
1078
show_err:
1079
   error_and_abort
1080
     (ef, "Unable to load image \"%s\" used by file \"%s\": %s.%s",
1081
     file, file_out, errmsg, hint);
1082
}
1083

1084
static void
1085
data_thread_image(void *data, Ecore_Thread *thread EINA_UNUSED)
1086
{
1087
   Image_Write *iw = data;
1088
   char buf[PATH_MAX], buf2[EINA_PATH_MAX];
1089
   unsigned int *start, *end;
1090
   Eina_Bool opaque = EINA_TRUE;
1091
   int bytes = 0;
1092

1093
   if ((iw->data) && (iw->w > 0) && (iw->h > 0))
1094
     {
1095
        Eet_Image_Encoding lossy = EET_IMAGE_LOSSLESS;
1096
        int mode, qual, comp = 0;
1097

1098
        snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
1099
        qual = 80;
1100
        if ((iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
1101
            (iw->img->source_param == 0))
1102
          mode = 0;  /* RAW */
1103
        else if ((iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
1104
                 (iw->img->source_param == 1))
1105
          mode = 1;  /* COMPRESS */
1106
        else if (iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1)
1107
          mode = 3;  /* LOSSY_ETC1 */
1108
        else if (iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
1109
          mode = 4;  /* LOSSY_ETC2 */
1110
        else
1111
          mode = 2;  /* LOSSY */
1112
        if ((mode == 0) && (no_raw))
1113
          {
1114
             mode = 1; /* promote compression */
1115
             iw->img->source_param = 95;
1116
          }
1117
        if ((mode == 4) && (no_etc2)) mode = 2;  /* demote etc2 to jpeg */
1118
        if ((mode == 3) && (no_etc1)) mode = 2;  /* demote etc1 to jpeg */
1119
        if ((mode == 2) && (no_lossy)) mode = 1;  /* demote compression */
1120
        if ((mode == 1) && (no_comp))
1121
          {
1122
             if (no_lossy) mode = 0;  /* demote compression */
1123
             else if (no_raw)
1124
               {
1125
                  iw->img->source_param = 90;
1126
                  mode = 2; /* no choice. lossy */
1127
               }
1128
          }
1129
        if (mode == 2)
1130
          {
1131
             qual = iw->img->source_param;
1132
             if (qual < min_quality) qual = min_quality;
1133
             if (qual > max_quality) qual = max_quality;
1134
             lossy = EET_IMAGE_JPEG;
1135
          }
1136
        if (iw->alpha)
1137
          {
1138
             start = (unsigned int *)iw->data;
1139
             end = start + (iw->w * iw->h);
1140
             while (start < end)
1141
               {
1142
                  if ((*start & 0xff000000) != 0xff000000)
1143
                    {
1144
                       opaque = EINA_FALSE;
1145
                       break;
1146
                    }
1147
                  start++;
1148
               }
1149
             if (opaque) iw->alpha = 0;
1150
          }
1151
        if (mode == 3)
1152
          {
1153
             qual = iw->img->source_param;
1154
             if (qual < min_quality) qual = min_quality;
1155
             if (qual > max_quality) qual = max_quality;
1156
             // Enable TGV with LZ4. A bit redundant with EET compression.
1157
             comp = !no_comp;
1158
             lossy = opaque ? EET_IMAGE_ETC1 : EET_IMAGE_ETC1_ALPHA;
1159
          }
1160
        if (mode == 4)
1161
          {
1162
             qual = iw->img->source_param;
1163
             if (qual < min_quality) qual = min_quality;
1164
             if (qual > max_quality) qual = max_quality;
1165
             lossy = opaque ? EET_IMAGE_ETC2_RGB : EET_IMAGE_ETC2_RGBA;
1166
          }
1167
        if (mode == 0)
1168
          bytes = eet_data_image_write(iw->ef, buf,
1169
                                       iw->data, iw->w, iw->h,
1170
                                       iw->alpha,
1171
                                       0, 0, 0);
1172
        else if (mode == 1)
1173
          bytes = eet_data_image_write(iw->ef, buf,
1174
                                       iw->data, iw->w, iw->h,
1175
                                       iw->alpha,
1176
                                       compress_mode,
1177
                                       0, 0);
1178
        else if (mode >= 2)
1179
          bytes = eet_data_image_write(iw->ef, buf,
1180
                                       iw->data, iw->w, iw->h,
1181
                                       iw->alpha,
1182
                                       comp, qual, lossy);
1183
        if (bytes <= 0)
1184
          {
1185
             snprintf(buf2, sizeof(buf2),
1186
                      "Unable to write image part "
1187
                      "\"%s\" as \"%s\" part entry to "
1188
                      "%s", iw->img->entry, buf, file_out);
1189
             iw->errstr = strdup(buf2);
1190
             return;
1191
          }
1192
     }
1193
   else
1194
     {
1195
        snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
1196
        snprintf(buf2, sizeof(buf2),
1197
                 "Unable to load image part "
1198
                 "\"%s\" as \"%s\" part entry to "
1199
                 "%s", iw->img->entry, buf, file_out);
1200
        iw->errstr = strdup(buf2);
1201
        return;
1202
     }
1203

1204
   if (eina_log_domain_level_check(_edje_cc_log_dom, EINA_LOG_LEVEL_INFO))
1205
     {
1206
        struct stat st;
1207

1208
        if (!iw->path || (stat(iw->path, &st))) st.st_size = 0;
1209
        if (st.st_size > 0)
1210
          {
1211
             INF("Wrote %9i bytes (%4iKb) for \"%s\" image entry \"%s\" compress: [raw: %2.1f%%] [real: %2.1f%%]",
1212
                 bytes, (bytes + 512) / 1024, buf, iw->img->entry,
1213
                 100 - (100 * (double)bytes) / ((double)(iw->w * iw->h * 4)),
1214
                 100 - (100 * (double)bytes) / ((double)(st.st_size))
1215
                 );
1216
          }
1217
     }
1218
}
1219

1220
static void
1221
data_thread_image_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1222
{
1223
   Image_Write *iw = data;
1224

1225
   if (iw->errstr)
1226
     {
1227
        error_and_abort(iw->ef, iw->errstr);
1228
        free(iw->errstr);
1229
     }
1230
   free(iw->path);
1231
   evas_object_del(iw->im);
1232
   free(iw);
1233
   thread_end(1);
1234
}
1235

1236
static void
1237
data_image_preload_done(void *data, Evas *e EINA_UNUSED, Evas_Object *o, void *event_info EINA_UNUSED)
1238
{
1239
   Image_Write *iw = data;
1240

1241
   evas_object_image_size_get(o, &iw->w, &iw->h);
1242
   iw->alpha = evas_object_image_alpha_get(o);
1243
   iw->data = evas_object_image_data_get(o, 0);
1244
   if (threads)
1245
     ecore_thread_run(data_thread_image, data_thread_image_end, NULL, iw);
1246
   else
1247
     {
1248
        data_thread_image(iw, NULL);
1249
        data_thread_image_end(iw, NULL);
1250
     }
1251
}
1252

1253
static void
1254
tgv_file_thread(void *data, Ecore_Thread *thread EINA_UNUSED)
1255
{
1256
   Image_Write *iw = data;
1257
   char buf[256];
1258
   size_t len;
1259

1260
   snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
1261

1262
   len = eina_file_size_get(iw->f);
1263
   eet_write_cipher(iw->ef, buf, iw->data, len, EINA_FALSE /*!no_comp*/, NULL);
1264
}
1265

1266
static void
1267
tgv_file_thread_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1268
{
1269
   Image_Write *iw = data;
1270

1271
   if (iw->errstr)
1272
     {
1273
        error_and_abort(iw->ef, iw->errstr);
1274
        free(iw->errstr);
1275
     }
1276
   free(iw->path);
1277
   emile_image_close(iw->emi);
1278
   eina_file_map_free(iw->f, iw->data);
1279
   eina_file_close(iw->f);
1280
   free(iw);
1281
   thread_end(1);
1282
}
1283

1284
static Eina_Bool
1285
tgv_file_check_and_add(Eet_File *ef, Edje_Image_Directory_Entry *img)
1286
{
1287
   Emile_Image_Load_Error err;
1288
   Emile_Image *emi = NULL;
1289
   Image_Write *iw = NULL;
1290
   Eina_List *li;
1291
   const char *s;
1292
   Eina_File *f = NULL;
1293
   void *data;
1294

1295
   EINA_LIST_FOREACH(img_dirs, li, s)
1296
     {
1297
        char buf[PATH_MAX];
1298
        snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
1299
        f = eina_file_open(buf, EINA_FALSE);
1300
        if (f) break;
1301
     }
1302
   if (!f) return EINA_FALSE;
1303

1304
   data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
1305
   if (!data) goto on_error;
1306

1307
   using_file(img->entry, 'I');
1308

1309
   emi = emile_image_tgv_file_open(f, NULL, NULL, &err);
1310
   if (!emi || (err != EMILE_IMAGE_LOAD_ERROR_NONE)) goto on_error;
1311

1312
   iw = calloc(1, sizeof(*iw));
1313

1314
   if (!emile_image_head(emi, &iw->prop, sizeof(iw->prop), &err) ||
1315
       (err != EMILE_IMAGE_LOAD_ERROR_NONE))
1316
     goto on_error;
1317

1318
   if (!iw->prop.cspaces || !iw->prop.w || !iw->prop.h)
1319
     goto on_error;
1320

1321
   iw->f = f;
1322
   iw->ef = ef;
1323
   iw->img = img;
1324
   iw->emi = emi;
1325
   iw->data = (unsigned int *)data;
1326
   iw->w = iw->prop.w;
1327
   iw->h = iw->prop.h;
1328

1329
   iw->prop.cspace = iw->prop.cspaces[0];
1330
   if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1)
1331
     {
1332
        if (no_etc1) goto on_error;
1333
        if (iw->prop.cspace == EMILE_COLORSPACE_ETC1)
1334
          iw->alpha = 0;
1335
        else if (iw->prop.cspace == EMILE_COLORSPACE_ETC1_ALPHA)
1336
          iw->alpha = 1;
1337
        else
1338
          goto on_error;
1339
     }
1340
   else if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
1341
     {
1342
        if (no_etc2) goto on_error;
1343
        if (iw->prop.cspace == EMILE_COLORSPACE_RGB8_ETC2)
1344
          iw->alpha = 0;
1345
        else if (iw->prop.cspace == EMILE_COLORSPACE_RGBA8_ETC2_EAC)
1346
          iw->alpha = 1;
1347
        else
1348
          goto on_error;
1349
     }
1350

1351
   image_num += 1;
1352
   iw->path = strdup(img->entry);
1353

1354
   pending_image_threads++;
1355
   if (threads)
1356
     ecore_thread_run(tgv_file_thread, tgv_file_thread_end, NULL, iw);
1357
   else
1358
     {
1359
        tgv_file_thread(iw, NULL);
1360
        tgv_file_thread_end(iw, NULL);
1361
     }
1362

1363
   return EINA_TRUE;
1364

1365
on_error:
1366
   free(iw);
1367
   emile_image_close(emi);
1368
   if (data) eina_file_map_free(f, data);
1369
   eina_file_close(f);
1370
   return EINA_FALSE;
1371
}
1372

1373
static void
1374
data_write_vectors(Eet_File *ef, int *vector_num)
1375
{
1376
   unsigned int i;
1377
   Eina_List *ll;
1378
   char *s;
1379
   Eina_File *f = NULL;
1380
   Edje_Vector_Directory_Entry *vector;
1381
   Eina_Strbuf *buf;
1382
   Eina_Bool found = EINA_FALSE;
1383
   Evas *evas;
1384
   Evas_Object *vg;
1385

1386
   if (!((edje_file) && (edje_file->image_dir))) return;
1387

1388
   if (!buffer_ee)
1389
     buffer_ee = ecore_evas_buffer_new(1, 1);
1390
   if (!buffer_ee)
1391
     error_and_abort(ef, "Cannot create buffer engine canvas for image load.");
1392
   evas = ecore_evas_get(buffer_ee);
1393
   vg = evas_object_vg_add(evas);
1394
   buf = eina_strbuf_new();
1395
   for (i = 0; i < edje_file->image_dir->vectors_count; i++)
1396
     {
1397
        vector = &edje_file->image_dir->vectors[i];
1398
        EINA_LIST_FOREACH(img_dirs, ll, s)
1399
          {
1400
             eina_strbuf_reset(buf);
1401
             eina_strbuf_append_printf(buf, "%s" EINA_PATH_SEP_S "%s", s, vector->entry);
1402
             f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
1403
             if (!f) continue;
1404
             eina_file_close(f);
1405

1406
             if (vector->type == EDJE_VECTOR_FILE_TYPE_LOTTIE)
1407
               {
1408
                  char *lottie_data = NULL;
1409
                  int lottie_data_len = 0;
1410

1411
                  f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
1412
                  if (!f) continue;
1413

1414
                  lottie_data_len = (int) eina_file_size_get(f);
1415
                  lottie_data = eina_file_map_all(f, EINA_FILE_POPULATE);
1416

1417
                  eina_strbuf_reset(buf);
1418
                  eina_strbuf_append_printf(buf, "edje/vectors/%i", vector->id);
1419
                  eet_write(ef, eina_strbuf_string_get(buf), lottie_data, lottie_data_len, EET_COMPRESSION_NONE);
1420

1421
                  eina_file_map_free(f, lottie_data);
1422
                  eina_file_close(f);
1423

1424
                  *vector_num += 1;
1425
                  found = EINA_TRUE;
1426
                  break;
1427
               }
1428
             else
1429
               {
1430
                  f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
1431
                  if (!f) continue;
1432
                  eina_file_close(f);
1433

1434
                  if (efl_file_set(vg, eina_strbuf_string_get(buf)))
1435
                    error_and_abort(ef, "Failed to parse svg : %s", vector->entry);
1436
                  if (efl_file_load(vg))
1437
                    error_and_abort(ef, "Failed to parse svg : %s", vector->entry);
1438

1439
                  eina_strbuf_reset(buf);
1440
                  eina_strbuf_append_printf(buf, "edje/vectors/%i", vector->id);
1441
                  if (!efl_file_save(vg, eet_file_get(ef), eina_strbuf_string_get(buf), NULL))
1442
                    error_and_abort(ef, "Failed to write data in Eet for svg :%s", vector->entry);
1443

1444
                  *vector_num += 1;
1445
                  found = EINA_TRUE;
1446
                  break;
1447
               }
1448
          }
1449
        if (!found)
1450
          error_and_abort(ef, "Unable to find the svg :%s", vector->entry);
1451
        found = EINA_FALSE;
1452
     }
1453
   eina_strbuf_free(buf);
1454
}
1455

1456
static void
1457
data_image_sets_init(void)
1458
{
1459
   int i;
1460

1461
   if (!((edje_file) && (edje_file->image_dir))) return;
1462
   for (i = 0; i < (int)edje_file->image_dir->sets_count; i++)
1463
     {
1464
        Edje_Image_Directory_Set *set;
1465
        Edje_Image_Directory_Set_Entry *set_entry;
1466
        Edje_Image_Directory_Entry *img;
1467
        Eina_List *ll = NULL;
1468

1469
        set = edje_file->image_dir->sets + i;
1470
        if (!set->entries) continue;
1471
        EINA_LIST_FOREACH(set->entries, ll, set_entry)
1472
          {
1473
             if (set_entry->id < (int)edje_file->image_dir->entries_count)
1474
               {
1475
                  img = &edje_file->image_dir->entries[set_entry->id];
1476
                  set_entry->name = img->entry;
1477
               }
1478
             else
1479
               {
1480
                  ERR("set %i / %i, entry %i / %i\n",
1481
                      i, edje_file->image_dir->sets_count,
1482
                      set_entry->id, edje_file->image_dir->entries_count);
1483
                  abort();
1484
               }
1485
          }
1486
     }
1487
}
1488

1489
static void
1490
data_write_images(void)
1491
{
1492
   Evas *evas;
1493
   const char *ext = NULL;
1494

1495
   if (!((edje_file) && (edje_file->image_dir))) return;
1496

1497
   if (!buffer_ee)
1498
     buffer_ee = ecore_evas_buffer_new(1, 1);
1499
   if (!buffer_ee)
1500
     error_and_abort(cur_ef, "Cannot create buffer engine canvas for image load.");
1501
   evas = ecore_evas_get(buffer_ee);
1502

1503
   for (; cur_image_entry < (int)edje_file->image_dir->entries_count; cur_image_entry++)
1504
     {
1505
        Edje_Image_Directory_Entry *img;
1506
        Evas_Object *im;
1507
        Eina_List *ll;
1508
        char *s;
1509
        int load_err = EVAS_LOAD_ERROR_NONE;
1510
        Image_Write *iw;
1511

1512
        img = &edje_file->image_dir->entries[cur_image_entry];
1513
        if ((img->source_type >= EDJE_IMAGE_SOURCE_TYPE_USER) || !img->entry)
1514
          continue;
1515

1516
        if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1 ||
1517
            img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
1518
          {
1519
             ext = strrchr(img->entry, '.');
1520
             if (ext && !strcasecmp(ext, ".tgv"))
1521
               {
1522
                  if (tgv_file_check_and_add(cur_ef, img))
1523
                    {
1524
                       DBG("Directly copying data from TGV file into EDJ");
1525
                       continue;
1526
                    }
1527
                  else
1528
                    ERR("Source '%s' has incompatible ETC format.", img->entry);
1529
               }
1530
          }
1531

1532
        iw = calloc(1, sizeof(Image_Write));
1533
        iw->ef = cur_ef;
1534
        iw->img = img;
1535
        iw->im = im = evas_object_image_add(evas);
1536
        if (threads)
1537
          evas_object_event_callback_add(im,
1538
                                         EVAS_CALLBACK_IMAGE_PRELOADED,
1539
                                         data_image_preload_done,
1540
                                         iw);
1541
        EINA_LIST_FOREACH(img_dirs, ll, s)
1542
          {
1543
             char buf[PATH_MAX];
1544

1545
             snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
1546
             evas_object_image_file_set(im, buf, NULL);
1547
             load_err = evas_object_image_load_error_get(im);
1548
             if (load_err == EVAS_LOAD_ERROR_NONE)
1549
               {
1550
                  image_num += 1;
1551
                  iw->path = strdup(buf);
1552
                  pending_image_threads++;
1553
                  if (threads)
1554
                    evas_object_image_preload(im, 0);
1555
                  using_file(buf, 'I');
1556
                  if (!threads)
1557
                    data_image_preload_done(iw, evas, im, NULL);
1558
                  break;
1559
               }
1560
          }
1561
        if (!img_dirs || (load_err != EVAS_LOAD_ERROR_NONE))
1562
          {
1563
             evas_object_image_file_set(im, img->entry, NULL);
1564
             load_err = evas_object_image_load_error_get(im);
1565
             if (load_err == EVAS_LOAD_ERROR_NONE)
1566
               {
1567
                  image_num += 1;
1568
                  iw->path = strdup(img->entry);
1569
                  pending_image_threads++;
1570
                  if (threads)
1571
                    evas_object_image_preload(im, 0);
1572
                  using_file(img->entry, 'I');
1573
                  if (!threads)
1574
                    data_image_preload_done(iw, evas, im, NULL);
1575
               }
1576
             else
1577
               {
1578
                  free(iw);
1579
                  error_and_abort_image_load_error(cur_ef, img->entry, load_err);
1580
                  exit(1); // ensure static analysis tools know we exit
1581
               }
1582
          }
1583

1584
        if (img->source_type < EDJE_IMAGE_SOURCE_TYPE_USER)
1585
          {
1586
             ext = strrchr(img->entry, '.');
1587
             if (ext && (!strcasecmp(ext, ".svg") || !strcasecmp(ext, ".svgz")))
1588
               {
1589
                  int size = strlen(img->entry) + strlen(".png") + 1;
1590
                  char *tmp = malloc(size);
1591
                  snprintf(tmp, size, "%s.png", img->entry);
1592
                  INF("Vector '%s' used as image, convert to bitmap '%s'", img->entry, tmp);
1593
                  free((void *)img->entry);
1594
                  img->entry = tmp;
1595
               }
1596
          }
1597
        if (threads)
1598
          {
1599
             if (pending_threads + pending_image_threads > (int)max_open_files - 2) break;
1600
          }
1601
     }
1602
}
1603

1604
static void
1605
data_thread_sounds(void *data, Ecore_Thread *thread EINA_UNUSED)
1606
{
1607
   Sound_Write *sw = data;
1608
   Eina_List *ll;
1609
#ifdef HAVE_LIBSNDFILE
1610
   Edje_Sound_Encode *enc_info;
1611
#endif
1612
   char *dir_path = NULL;
1613
   char snd_path[PATH_MAX];
1614
   char sndid_str[15];
1615
   Eina_File *f = NULL;
1616
   void *m = NULL;
1617
   int bytes = 0;
1618

1619
   // Search the Sound file in all the -sd ( sound directory )
1620
   EINA_LIST_FOREACH(snd_dirs, ll, dir_path)
1621
     {
1622
        snprintf((char *)snd_path, sizeof(snd_path), "%s/%s", dir_path,
1623
                 sw->sample->snd_src);
1624
        f = eina_file_open(snd_path, 0);
1625
        if (f) break;
1626
     }
1627
   if (!f)
1628
     {
1629
        snprintf((char *)snd_path, sizeof(snd_path), "%s",
1630
                 sw->sample->snd_src);
1631
        f = eina_file_open(snd_path, 0);
1632
     }
1633
#ifdef HAVE_LIBSNDFILE
1634
   if (f) eina_file_close(f);
1635
   enc_info = _edje_multisense_encode(snd_path, sw->sample,
1636
                                      sw->sample->quality);
1637
   f = eina_file_open(enc_info->file, 0);
1638
   if (f) using_file(enc_info->file, 'S');
1639
#else
1640
   if (f) using_file(snd_path, 'S');
1641
#endif
1642
   if (!f)
1643
     {
1644
        ERR("Unable to load sound data of: %s", sw->sample->name);
1645
        exit(-1);
1646
     }
1647

1648
   snprintf(sndid_str, sizeof(sndid_str), "edje/sounds/%i", sw->sample->id);
1649
   m = eina_file_map_all(f, EINA_FILE_WILLNEED);
1650
   if (m)
1651
     {
1652
        bytes = eet_write(sw->ef, sndid_str, m, eina_file_size_get(f),
1653
                          EET_COMPRESSION_NONE);
1654
        if (eina_file_map_faulted(f, m))
1655
          {
1656
             ERR("File access error when reading '%s'",
1657
                 eina_file_filename_get(f));
1658
             exit(-1);
1659
          }
1660
        eina_file_map_free(f, m);
1661
     }
1662
   eina_file_close(f);
1663

1664
#ifdef HAVE_LIBSNDFILE
1665
   //If encoded temporary file, delete it.
1666
   if (enc_info->encoded) unlink(enc_info->file);
1667
#endif
1668
#ifdef HAVE_LIBSNDFILE
1669
   INF("Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry \"%s\"",
1670
       bytes, (bytes + 512) / 1024,
1671
       sndid_str, enc_info->comp_type, sw->sample->name);
1672
#else
1673
   INF("Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry \"%s\"",
1674
       bytes, (bytes + 512) / 1024,
1675
       sndid_str, "RAW PCM", sw->sample->name);
1676
#endif
1677

1678
#ifdef HAVE_LIBSNDFILE
1679
   if ((enc_info->file) && (!enc_info->encoded))
1680
     eina_stringshare_del(enc_info->file);
1681
   free(enc_info);
1682
   enc_info = NULL;
1683
#endif
1684
}
1685

1686
static void
1687
data_thread_sounds_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1688
{
1689
   Sound_Write *sw = data;
1690
   free(sw);
1691
   thread_end(0);
1692
}
1693

1694
static void
1695
data_write_sounds(Eet_File *ef, int *sound_num)
1696
{
1697
   if ((edje_file) && (edje_file->sound_dir))
1698
     {
1699
        int i;
1700

1701
        for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
1702
          {
1703
             Sound_Write *sw;
1704

1705
             sw = calloc(1, sizeof(Sound_Write));
1706
             if (!sw) continue;
1707
             sw->ef = ef;
1708
             sw->sample = &edje_file->sound_dir->samples[i];
1709
             sw->i = i;
1710
             *sound_num += 1;
1711
             pending_threads++;
1712
             if (threads)
1713
               ecore_thread_run(data_thread_sounds, data_thread_sounds_end, NULL, sw);
1714
             else
1715
               {
1716
                  data_thread_sounds(sw, NULL);
1717
                  data_thread_sounds_end(sw, NULL);
1718
               }
1719
          }
1720
     }
1721
}
1722

1723
static void
1724
data_thread_mo(void *data, Ecore_Thread *thread EINA_UNUSED)
1725
{
1726
   Mo_Write *mw = data;
1727
   char buf[EINA_PATH_MAX];
1728
   Eina_List *ll;
1729

1730
   char *dir_path = NULL;
1731
   char mo_path[PATH_MAX] = {0};
1732
   char moid_str[50];
1733
   Eina_File *f = NULL;
1734
   void *m = NULL;
1735
   int bytes = 0;
1736

1737
   if (mw->mo_path)
1738
     f = eina_file_open(mw->mo_path, 0);
1739
   if (!f)
1740
     {
1741
        // Search the mo file in all the -md ( mo directory )
1742
        EINA_LIST_FOREACH(mo_dirs, ll, dir_path)
1743
          {
1744
             snprintf((char *)mo_path, sizeof(mo_path), "%s/%s/%s", dir_path, mw->mo_entry->locale, mw->mo_entry->mo_src);
1745
             f = eina_file_open(mo_path, 0);
1746
             if (f) break;
1747
          }
1748
     }
1749
   if (!f)
1750
     {
1751
        snprintf((char *)mo_path, sizeof(mo_path), "%s", mw->mo_entry->mo_src);
1752
        f = eina_file_open(mo_path, 0);
1753
     }
1754

1755
   if (f) using_file(mo_path, 'S');
1756

1757
   if (!f)
1758
     {
1759
        snprintf(buf, sizeof(buf), "Unable to load mo data of: %s", mo_path);
1760
        ERR("%s", buf);
1761
        mw->errstr = strdup(buf);
1762
        exit(-1);
1763
     }
1764

1765
   snprintf(moid_str, sizeof(moid_str), "edje/mo/%i/%s/LC_MESSAGES", mw->mo_entry->id, mw->mo_entry->locale);
1766
   m = eina_file_map_all(f, EINA_FILE_WILLNEED);
1767
   if (m)
1768
     {
1769
        bytes = eet_write(mw->ef, moid_str, m, eina_file_size_get(f), EET_COMPRESSION_NONE);
1770
        if (eina_file_map_faulted(f, m))
1771
          {
1772
             snprintf(buf, sizeof(buf), "File access error when reading '%s'",
1773
                      eina_file_filename_get(f));
1774
             ERR("%s", buf);
1775
             mw->errstr = strdup(buf);
1776
             eina_file_close(f);
1777
             exit(-1);
1778
          }
1779
        eina_file_map_free(f, m);
1780
     }
1781
   eina_file_close(f);
1782
   if (mw->mo_path)
1783
     ecore_file_remove(mo_path);
1784

1785
   INF("Wrote %9i bytes (%4iKb) for \"%s\" %s mo entry \"%s\"",
1786
       bytes, (bytes + 512) / 1024, moid_str, "RAW PCM", mw->mo_entry->locale);
1787
}
1788

1789
static void
1790
data_thread_mo_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1791
{
1792
   Mo_Write *mw = data;
1793
   if (mw->errstr)
1794
     {
1795
        error_and_abort(mw->ef, mw->errstr);
1796
        free(mw->errstr);
1797
     }
1798
   if (mw->mo_path)
1799
     free(mw->mo_path);
1800
   free(mw);
1801
   thread_end(0);
1802
}
1803

1804
Eina_Bool
1805
_exe_del_cb(void *data EINA_UNUSED, int evtype EINA_UNUSED, void *evinfo)
1806
{
1807
   Mo_Write *mw = data;
1808
   Ecore_Exe_Event_Del *ev = evinfo;
1809
   if (!ev->exe) return ECORE_CALLBACK_RENEW;
1810
   if (ecore_exe_data_get(ev->exe) != mw) return ECORE_CALLBACK_RENEW;
1811
   if (ev->exit_code != 0)
1812
     {
1813
        error_and_abort(mw->ef, "Creation of .mo from .po failed.");
1814
        return ECORE_CALLBACK_CANCEL;
1815
     }
1816
   if (ecore_file_exists(mw->mo_path))
1817
     {
1818
        if (threads)
1819
          ecore_thread_run(data_thread_mo, data_thread_mo_end, NULL, mw);
1820
        else
1821
          {
1822
             data_thread_mo(mw, NULL);
1823
             data_thread_mo_end(mw, NULL);
1824
          }
1825
     }
1826
   else
1827
     return ECORE_CALLBACK_RENEW;
1828
   if (pending_threads + pending_image_threads <= 0) ecore_main_loop_quit();
1829
   return ECORE_CALLBACK_CANCEL;
1830
}
1831

1832
static void
1833
data_write_mo(Eet_File *ef, int *mo_num)
1834
{
1835
   if ((edje_file) && (edje_file->mo_dir))
1836
     {
1837
        int i;
1838
        char *po_entry;
1839
        char *sub_str;
1840
        char buf[EINA_PATH_MAX + PATH_MAX + PATH_MAX + 128];
1841
        Eina_List *ll;
1842
        char *dir_path = NULL;
1843
        char mo_path[PATH_MAX];
1844
        char po_path[PATH_MAX];
1845

1846
        for (i = 0; i < (int)edje_file->mo_dir->mo_entries_count; i++)
1847
          {
1848
             Mo_Write *mw, *mw2;
1849
             mw = calloc(1, sizeof(Mo_Write));
1850
             if (!mw) continue;
1851
             mw->ef = ef;
1852
             mw->mo_entry = &edje_file->mo_dir->mo_entries[i];
1853
             *mo_num += 1;
1854
             pending_threads++;
1855

1856
             po_entry = strdup(mw->mo_entry->mo_src);
1857
             sub_str = strstr(mw->mo_entry->mo_src, ".po");
1858

1859
             if (sub_str)
1860
               {
1861
                  sub_str[1] = 'm';
1862
                  EINA_LIST_FOREACH(mo_dirs, ll, dir_path)
1863
                    {
1864
                       snprintf((char *)po_path, sizeof(po_path), "%s/%s/%s", dir_path, mw->mo_entry->locale, po_entry);
1865
                       if (ecore_file_exists(po_path))
1866
                         {
1867
                            char *mo_dir = ecore_file_dir_get(eet_file_get(ef));
1868
                            snprintf((char *)mo_path, sizeof(mo_path), "%s/%s", mo_dir, mw->mo_entry->locale);
1869
                            ecore_file_mkpath(mo_path);
1870
                            snprintf((char *)mo_path, sizeof(mo_path), "%s/%s/%s", mo_dir, mw->mo_entry->locale, mw->mo_entry->mo_src);
1871
                            snprintf(buf, sizeof(buf), "msgfmt -o %s %s", mo_path, po_path);
1872
                            mw2 = malloc(sizeof(Mo_Write));
1873
                            if (mw2)
1874
                              {
1875
                                 memcpy(mw2, mw, sizeof(Mo_Write));
1876
                                 mw2->mo_path = strdup(mo_path);
1877
                                 mw2->exe = ecore_exe_run(buf, mw2);
1878
                                 ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
1879
                                                         _exe_del_cb, mw2);
1880
                              }
1881
                            free(mo_dir);
1882
                         }
1883
                       else
1884
                         error_and_abort(mw->ef, "Non-existent .po file specified: \"%s\".", po_path);
1885
                    }
1886
                  free(mw);
1887
               }
1888
             else
1889
               {
1890
                  if (threads)
1891
                    ecore_thread_run(data_thread_mo, data_thread_mo_end, NULL, mw);
1892
                  else
1893
                    {
1894
                       data_thread_mo(mw, NULL);
1895
                       data_thread_mo_end(mw, NULL);
1896
                    }
1897
               }
1898
             free(po_entry);
1899
          }
1900
     }
1901
}
1902

1903
static void
1904
data_thread_vibrations(void *data, Ecore_Thread *thread EINA_UNUSED)
1905
{
1906
   Vibration_Write *vw = data;
1907
   Eina_List *ll;
1908
   char *dir_path = NULL;
1909
   char path[PATH_MAX];
1910
   char id_str[30];
1911
   Eina_File *f = NULL;
1912
   void *m = NULL;
1913
   int bytes = 0;
1914

1915
   EINA_LIST_FOREACH(vibration_dirs, ll, dir_path)
1916
     {
1917
        snprintf((char *)path, sizeof(path), "%s/%s", dir_path,
1918
                 vw->sample->src);
1919
        f = eina_file_open(path, 0);
1920
        if (f) break;
1921
     }
1922
   if (!f)
1923
     {
1924
        snprintf((char *)path, sizeof(path), "%s",
1925
                 vw->sample->src);
1926
        f = eina_file_open(path, 0);
1927
     }
1928
   if (f) using_file(path, 'S');
1929
   if (!f)
1930
     {
1931
        ERR("Unable to load vibration data of: %s", vw->sample->src);
1932
        exit(-1);
1933
     }
1934

1935
   snprintf(id_str, sizeof(id_str), "edje/vibrations/%i", vw->sample->id);
1936
   m = eina_file_map_all(f, EINA_FILE_WILLNEED);
1937
   if (m)
1938
     {
1939
        bytes = eet_write(vw->ef, id_str, m, eina_file_size_get(f),
1940
                          EET_COMPRESSION_NONE);
1941
        if (eina_file_map_faulted(f, m))
1942
          {
1943
             ERR("File access error when reading '%s'",
1944
                 eina_file_filename_get(f));
1945
             exit(-1);
1946
          }
1947
        eina_file_map_free(f, m);
1948
     }
1949
   eina_file_close(f);
1950

1951
   INF("Wrote %9i bytes (%4iKb) for \"%s\" %s vibration entry \"%s\"",
1952
       bytes, (bytes + 512) / 1024,
1953
       id_str, "RAW", vw->sample->name);
1954
}
1955

1956
static void
1957
data_thread_vibrations_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1958
{
1959
   Vibration_Write *sw = data;
1960
   free(sw);
1961
   thread_end(0);
1962
}
1963

1964
static void
1965
data_write_vibrations(Eet_File *ef, int *num)
1966
{
1967
   if ((edje_file) && (edje_file->vibration_dir))
1968
     {
1969
        int i;
1970

1971
        for (i = 0; i < (int)edje_file->vibration_dir->samples_count; i++)
1972
          {
1973
             Vibration_Write *vw;
1974

1975
             vw = calloc(1, sizeof(Vibration_Write));
1976
             if (!vw) continue;
1977
             vw->ef = ef;
1978
             vw->sample = &edje_file->vibration_dir->samples[i];
1979
             vw->i = i;
1980
             *num += 1;
1981
             pending_threads++;
1982
             if (threads)
1983
               ecore_thread_run(data_thread_vibrations, data_thread_vibrations_end, NULL, vw);
1984
             else
1985
               {
1986
                  data_thread_vibrations(vw, NULL);
1987
                  data_thread_vibrations_end(vw, NULL);
1988
               }
1989
          }
1990
     }
1991
}
1992

1993
static void
1994
check_groups(Eet_File *ef)
1995
{
1996
   Edje_Part_Collection *pc;
1997
   Eina_List *l;
1998

1999
   /* sanity checks for parts and programs */
2000
   EINA_LIST_FOREACH(edje_collections, l, pc)
2001
     {
2002
        unsigned int i;
2003

2004
        for (i = 0; i < pc->parts_count; ++i)
2005
          check_part(pc, pc->parts[i], ef);
2006

2007
#define CHECK_PROGRAM(Type, Pc, It)                    \
2008
  for (It = 0; It < Pc->programs.Type ## _count; ++It) \
2009
    check_program(Pc, Pc->programs.Type[i], ef);       \
2010

2011
        CHECK_PROGRAM(fnmatch, pc, i);
2012
        CHECK_PROGRAM(strcmp, pc, i);
2013
        CHECK_PROGRAM(strncmp, pc, i);
2014
        CHECK_PROGRAM(strrncmp, pc, i);
2015
        CHECK_PROGRAM(nocmp, pc, i);
2016
     }
2017
}
2018

2019
static void
2020
data_thread_group(void *data, Ecore_Thread *thread EINA_UNUSED)
2021
{
2022
   Group_Write *gw = data;
2023
   char buf[PATH_MAX];
2024

2025
   snprintf(buf, sizeof(buf), "edje/collections/%i", gw->pc->id);
2026
   eet_data_write(gw->ef, edd_edje_part_collection, buf, gw->pc,
2027
                  compress_mode);
2028
   return;
2029
}
2030

2031
static void
2032
data_thread_group_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2033
{
2034
   Group_Write *gw = data;
2035
   if (gw->errstr)
2036
     {
2037
        error_and_abort(gw->ef, gw->errstr);
2038
        free(gw->errstr);
2039
     }
2040
   free(gw);
2041
   thread_end(0);
2042
}
2043

2044
static void
2045
data_write_groups(Eet_File *ef, int *collection_num)
2046
{
2047
   Eina_List *l;
2048
   Edje_Part_Collection *pc;
2049

2050
   EINA_LIST_FOREACH(edje_collections, l, pc)
2051
     {
2052
        Group_Write *gw;
2053

2054
        gw = calloc(1, sizeof(Group_Write));
2055
        if (!gw)
2056
          {
2057
             error_and_abort(ef, "Cannot allocate memory for group writer");
2058
             return;
2059
          }
2060
        gw->ef = ef;
2061
        gw->pc = pc;
2062
        pending_threads++;
2063
        if (threads)
2064
          ecore_thread_run(data_thread_group, data_thread_group_end, NULL, gw);
2065
        else
2066
          {
2067
             data_thread_group(gw, NULL);
2068
             data_thread_group_end(gw, NULL);
2069
          }
2070
        *collection_num += 1;
2071
     }
2072
}
2073

2074
static void
2075
create_script_file(Eet_File *ef, const char *filename, const Code *cd, int fd)
2076
{
2077
   FILE *f = fdopen(fd, "wb");
2078
   if (!f)
2079
     error_and_abort(ef, "Unable to open temp file \"%s\" for script "
2080
                         "compilation.", filename);
2081

2082
   Eina_List *ll;
2083
   Code_Program *cp;
2084

2085
   fprintf(f, "#include <edje>\n");
2086
   int ln = 2;
2087

2088
   if (cd->shared)
2089
     {
2090
        while (ln < (cd->l1 - 1))
2091
          {
2092
             fprintf(f, " \n");
2093
             ln++;
2094
          }
2095
        {
2096
           char *sp;
2097
           int hash = 0;
2098
           int newlined = 0;
2099

2100
           for (sp = cd->shared; *sp; sp++)
2101
             {
2102
                if ((sp[0] == '#') && (newlined))
2103
                  {
2104
                     hash = 1;
2105
                  }
2106
                newlined = 0;
2107
                if (sp[0] == '\n') newlined = 1;
2108
                if (!hash) fputc(sp[0], f);
2109
                else if (sp[0] == '\n')
2110
                  hash = 0;
2111
             }
2112
           fputc('\n', f);
2113
        }
2114
        ln += cd->l2 - cd->l1 + 1;
2115
     }
2116
   EINA_LIST_FOREACH(cd->programs, ll, cp)
2117
     {
2118
        if (cp->script)
2119
          {
2120
             while (ln < (cp->l1 - 1))
2121
               {
2122
                  fprintf(f, " \n");
2123
                  ln++;
2124
               }
2125
             /* FIXME: this prototype needs to be */
2126
             /* formalised and set in stone */
2127
             fprintf(f, "public _p%i(sig[], src[]) {", cp->id);
2128
             {
2129
                char *sp;
2130
                int hash = 0;
2131
                int newlined = 0;
2132

2133
                for (sp = cp->script; *sp; sp++)
2134
                  {
2135
                     if ((sp[0] == '#') && (newlined))
2136
                       {
2137
                          hash = 1;
2138
                       }
2139
                     newlined = 0;
2140
                     if (sp[0] == '\n') newlined = 1;
2141
                     if (!hash) fputc(sp[0], f);
2142
                     else if (sp[0] == '\n')
2143
                       hash = 0;
2144
                  }
2145
             }
2146
             fprintf(f, "}\n");
2147
             ln += cp->l2 - cp->l1 + 1;
2148
          }
2149
     }
2150

2151
   fclose(f);
2152
}
2153

2154
static void
2155
data_thread_script(void *data, Ecore_Thread *thread EINA_UNUSED)
2156
{
2157
   Script_Write *sc = data;
2158
   FILE *f;
2159
   int size;
2160
   char buf[PATH_MAX];
2161

2162
   f = fopen(sc->tmpo, "rb");
2163
   if (!f)
2164
     {
2165
        snprintf(buf, sizeof(buf),
2166
                 "Unable to open script object \"%s\" for reading.",
2167
                 sc->tmpo);
2168
        sc->errstr = strdup(buf);
2169
        return;
2170
     }
2171

2172
   if (fseek(f, 0, SEEK_END) < 0)
2173
     ERR("Error seeking");
2174
   size = ftell(f);
2175
   rewind(f);
2176

2177
   if (size > 0)
2178
     {
2179
        void *dat = malloc(size);
2180

2181
        if (dat)
2182
          {
2183
             if (fread(dat, size, 1, f) != 1)
2184
               {
2185
                  snprintf(buf, sizeof(buf),
2186
                           "Unable to read all of script object \"%s\"",
2187
                           sc->tmpo);
2188
                  sc->errstr = strdup(buf);
2189
                  free(dat);
2190
                  fclose(f);
2191
                  return;
2192
               }
2193
             snprintf(buf, sizeof(buf), "edje/scripts/embryo/compiled/%i",
2194
                      sc->i);
2195
             eet_write(sc->ef, buf, dat, size, compress_mode);
2196
             free(dat);
2197
          }
2198
        else
2199
          {
2200
             snprintf(buf, sizeof(buf),
2201
                      "Alloc failed for %lu bytes", (unsigned long)size);
2202
             sc->errstr = strdup(buf);
2203
             fclose(f);
2204
             return;
2205
          }
2206
     }
2207

2208
   if (no_save)
2209
     WRN("You are removing the source from this Edje file. This may break some use cases.\nBe aware of your choice and the poor kitten you are harming with it!");
2210
   else
2211
     {
2212
        Eina_List *ll;
2213
        Code_Program *cp;
2214

2215
        if (sc->cd->original)
2216
          {
2217
             snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i", sc->i);
2218
             eet_write(sc->ef, buf, sc->cd->original,
2219
                       strlen(sc->cd->original) + 1, compress_mode);
2220
          }
2221
        EINA_LIST_FOREACH(sc->cd->programs, ll, cp)
2222
          {
2223
             if (!cp->original) continue;
2224
             snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i/%i",
2225
                      sc->i, cp->id);
2226
             eet_write(sc->ef, buf, cp->original,
2227
                       strlen(cp->original) + 1, compress_mode);
2228
          }
2229
     }
2230
   fclose(f);
2231

2232
   unlink(sc->tmpn);
2233
   unlink(sc->tmpo);
2234
   eina_tmpstr_del(sc->tmpn);
2235
   eina_tmpstr_del(sc->tmpo);
2236
// closed by fclose(f) in create_script_file()
2237
//   close(sc->tmpn_fd);
2238
}
2239

2240
typedef struct
2241
{
2242
   char         *exe;
2243
   Script_Write *sc;
2244
} Pending_Script_Write;
2245

2246
#define PENDING_COMMANDS_MAX 8
2247

2248
static int pending_write_commands = 0;
2249
static Eina_List *pending_script_writes = NULL;
2250

2251
static void data_write_script_queue(Script_Write *sc, const char *exeline);
2252

2253
static void
2254
data_thread_script_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2255
{
2256
   Script_Write *sc = data;
2257
   if (sc->errstr)
2258
     {
2259
        error_and_abort(sc->ef, sc->errstr);
2260
        free(sc->errstr);
2261
     }
2262
   free(sc);
2263
   thread_end(0);
2264
}
2265

2266
static Eina_Bool
2267
data_scripts_exe_del_cb(void *data EINA_UNUSED, int evtype EINA_UNUSED, void *evinfo)
2268
{
2269
   Script_Write *sc = data;
2270
   Ecore_Exe_Event_Del *ev = evinfo;
2271

2272
   if (!ev->exe) return ECORE_CALLBACK_RENEW;
2273
   if (ecore_exe_data_get(ev->exe) != sc) return ECORE_CALLBACK_RENEW;
2274
   pending_write_commands--;
2275
   if (pending_write_commands < PENDING_COMMANDS_MAX)
2276
     {
2277
        if (pending_script_writes)
2278
          {
2279
             Pending_Script_Write *pend = pending_script_writes->data;
2280

2281
             pending_script_writes = eina_list_remove_list
2282
                 (pending_script_writes, pending_script_writes);
2283
             data_write_script_queue(pend->sc, pend->exe);
2284
             free(pend->exe);
2285
             free(pend);
2286
          }
2287
     }
2288
   if (ev->exit_code != 0)
2289
     {
2290
        error_and_abort(sc->ef, "Compiling script code not clean.");
2291
        return ECORE_CALLBACK_CANCEL;
2292
     }
2293
   if (threads)
2294
     {
2295
        ecore_thread_run(data_thread_script, data_thread_script_end, NULL, sc);
2296
     }
2297
   else
2298
     {
2299
        data_thread_script(sc, NULL);
2300
        data_thread_script_end(sc, NULL);
2301
     }
2302
   if (pending_threads + pending_image_threads <= 0) ecore_main_loop_quit();
2303
   return ECORE_CALLBACK_CANCEL;
2304
}
2305

2306
static void
2307
data_write_script_queue(Script_Write *sc, const char *exeline)
2308
{
2309
   if (pending_write_commands >= PENDING_COMMANDS_MAX)
2310
     {
2311
        Pending_Script_Write *pend = malloc(sizeof(Pending_Script_Write));
2312
        if (pend)
2313
          {
2314
             pend->sc = sc;
2315
             pend->exe = strdup(exeline);
2316
             if (!pend->exe)
2317
               {
2318
                  error_and_abort(sc->ef,
2319
                                  "Unable to allocate mem pending string.");
2320
                  free(pend);
2321
                  return;
2322
               }
2323
             pending_script_writes = eina_list_append(pending_script_writes,
2324
                                                      pend);
2325
          }
2326
        else
2327
          error_and_abort(sc->ef,
2328
                          "Unable to allocate mem for pending script.");
2329
     }
2330
   else
2331
     {
2332
        pending_threads++;
2333
        sc->exe = ecore_exe_run(exeline, sc);
2334
        if (!sc->exe) error_and_abort(sc->ef, "Unable to fork off embryo_cc.");
2335
        ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
2336
                                data_scripts_exe_del_cb, sc);
2337
        pending_write_commands++;
2338
     }
2339
}
2340

2341
static void
2342
data_write_scripts(Eet_File *ef)
2343
{
2344
   Eina_List *l;
2345
   char embryo_cc_path[PATH_MAX] = "";
2346
   char inc_path[PATH_MAX] = "";
2347
   int i;
2348

2349
#ifdef _WIN32
2350
# define BIN_EXT ".exe"
2351
#else
2352
# define BIN_EXT
2353
#endif
2354
#ifdef NEED_RUN_IN_TREE
2355
   if (getenv("EFL_RUN_IN_TREE"))
2356
     {
2357
        snprintf(embryo_cc_path, sizeof(embryo_cc_path),
2358
                 "%s/src/bin/embryo/embryo_cc" BIN_EXT,
2359
                 PACKAGE_BUILD_DIR);
2360
        snprintf(inc_path, sizeof(inc_path),
2361
                 "%s/data/edje/include", PACKAGE_SRC_DIR);
2362
        if (!ecore_file_exists(embryo_cc_path))
2363
          embryo_cc_path[0] = '\0';
2364
     }
2365
#endif
2366

2367
   if (embryo_cc_path[0] == '\0')
2368
     {
2369
        snprintf(embryo_cc_path, sizeof(embryo_cc_path),
2370
                 "%s/embryo_cc" BIN_EXT,
2371
                 eina_prefix_bin_get(pfx));
2372
        snprintf(inc_path, sizeof(inc_path),
2373
                 "%s/include",
2374
                 eina_prefix_data_get(pfx));
2375
     }
2376
#undef BIN_EXT
2377

2378
   for (i = 0, l = codes; l; l = eina_list_next(l), i++)
2379
     {
2380
        Code *cd = eina_list_data_get(l);
2381
        Script_Write *sc;
2382
        int fd;
2383
        char buf[EINA_PATH_MAX + PATH_MAX + PATH_MAX + 128];
2384

2385
        if (cd->is_lua)
2386
          continue;
2387
        if ((!cd->shared) && (!cd->programs))
2388
          continue;
2389
        sc = calloc(1, sizeof(Script_Write));
2390
        sc->ef = ef;
2391
        sc->cd = cd;
2392
        sc->i = i;
2393
        sc->tmpn_fd = eina_file_mkstemp("edje_cc.sma-tmp-XXXXXX", &sc->tmpn);
2394
        if (sc->tmpn_fd < 0)
2395
          error_and_abort(ef, "Unable to open temp file \"%s\" for script "
2396
                              "compilation.", sc->tmpn);
2397
        fd = eina_file_mkstemp("edje_cc.amx-tmp-XXXXXX", &sc->tmpo);
2398
        if (fd < 0)
2399
          {
2400
             unlink(sc->tmpn);
2401
             eina_tmpstr_del(sc->tmpn);
2402
             error_and_abort(ef, "Unable to open temp file \"%s\" for script "
2403
                                 "compilation.", sc->tmpo);
2404
          }
2405
        //do not carry the fd over the time
2406
        //we should not unnesseserrily carry filedescriptors over time as this could excede system limits
2407
        //which have been fetched earlier
2408
        close(fd);
2409
        create_script_file(ef, sc->tmpn, cd, sc->tmpn_fd);
2410
        snprintf(buf, sizeof(buf),
2411
                 "%s -i %s -o %s %s", embryo_cc_path, inc_path,
2412
                 sc->tmpo, sc->tmpn);
2413
        data_write_script_queue(sc, buf);
2414
     }
2415
}
2416

2417
#ifdef LUA_BINARY
2418
static int
2419
_edje_lua_script_writer(lua_State *L EINA_UNUSED, const void *chunk_buf, size_t chunk_size, void *_data)
2420
{
2421
   Script_Lua_Writer *data;
2422
   void *old;
2423

2424
   data = (Script_Lua_Writer *)_data;
2425
   old = data->buf;
2426
   data->buf = realloc(data->buf, data->size + chunk_size);
2427
   if (data->buf)
2428
     {
2429
        memcpy(&((data->buf)[data->size]), chunk_buf, chunk_size);
2430
        data->size += chunk_size;
2431
     }
2432
   else
2433
     {
2434
        ERR("Failed to copy chunk buffer.\n");
2435
        data->buf = old;
2436
     }
2437

2438
   return 0;
2439
}
2440

2441
#endif
2442

2443
void
2444
_edje_lua_error_and_abort(lua_State *L, int err_code, Script_Write *sc)
2445
{
2446
   char buf[PATH_MAX];
2447
   char *err_type;
2448

2449
   switch (err_code)
2450
     {
2451
      case LUA_ERRRUN:
2452
        err_type = "runtime";
2453
        break;
2454

2455
      case LUA_ERRSYNTAX:
2456
        err_type = "syntax";
2457
        break;
2458

2459
      case LUA_ERRMEM:
2460
        err_type = "memory allocation";
2461
        break;
2462

2463
      case LUA_ERRERR:
2464
        err_type = "error handler";
2465
        break;
2466

2467
      default:
2468
        err_type = "unknown";
2469
        break;
2470
     }
2471
   snprintf(buf, sizeof(buf),
2472
            "Lua %s error: %s", err_type, lua_tostring(L, -1));
2473
   sc->errstr = strdup(buf);
2474
}
2475

2476
static void
2477
data_thread_lua_script(void *data, Ecore_Thread *thread EINA_UNUSED)
2478
{
2479
   Script_Write *sc = data;
2480
   char buf[PATH_MAX];
2481
   lua_State *L;
2482
   int ln = 1;
2483
   luaL_Buffer b;
2484
   Script_Lua_Writer dat;
2485
   Eina_List *ll;
2486
   Code_Program *cp;
2487
#ifdef LUA_BINARY
2488
   int err_code;
2489
#endif
2490

2491
   L = luaL_newstate();
2492
   if (!L)
2493
     {
2494
        snprintf(buf, sizeof(buf),
2495
                 "Lua error: Lua state could not be initialized");
2496
        sc->errstr = strdup(buf);
2497
        return;
2498
     }
2499

2500
   luaL_buffinit(L, &b);
2501

2502
   dat.buf = NULL;
2503
   dat.size = 0;
2504
   if (sc->cd->shared)
2505
     {
2506
        while (ln < (sc->cd->l1 - 1))
2507
          {
2508
             luaL_addchar(&b, '\n');
2509
             ln++;
2510
          }
2511
        luaL_addstring(&b, sc->cd->shared);
2512
        ln += sc->cd->l2 - sc->cd->l1;
2513
     }
2514

2515
   EINA_LIST_FOREACH(sc->cd->programs, ll, cp)
2516
     {
2517
        if (cp->script)
2518
          {
2519
             while (ln < (cp->l1 - 1))
2520
               {
2521
                  luaL_addchar(&b, '\n');
2522
                  ln++;
2523
               }
2524
             luaL_addstring(&b, "_G[");
2525
             lua_pushnumber(L, cp->id);
2526
             luaL_addvalue(&b);
2527
             luaL_addstring(&b, "] = function (ed, signal, source)");
2528
             luaL_addstring(&b, cp->script);
2529
             luaL_addstring(&b, "end\n");
2530
             ln += cp->l2 - cp->l1 + 1;
2531
          }
2532
     }
2533
   luaL_pushresult(&b);
2534
#ifdef LUA_BINARY
2535
   if (err_code = luaL_loadstring(L, lua_tostring(L, -1)))
2536
     {
2537
        _edje_lua_error_and_abort(L, err_code, sc);
2538
        return;
2539
     }
2540
   lua_dump(L, _edje_lua_script_writer, &dat);
2541
#else // LUA_PLAIN_TEXT
2542
   dat.buf = (char *)lua_tostring(L, -1);
2543
   dat.size = strlen(dat.buf);
2544
#endif
2545
   //printf("lua chunk size: %d\n", dat.size);
2546

2547
   /*
2548
    * TODO load and test Lua chunk
2549
    */
2550

2551
   /*
2552
      if (luaL_loadbuffer(L, globbuf, globbufsize, "edje_lua_script"))
2553
      printf("lua load error: %s\n", lua_tostring (L, -1));
2554
      if (lua_pcall(L, 0, 0, 0))
2555
      printf("lua call error: %s\n", lua_tostring (L, -1));
2556
    */
2557

2558
   snprintf(buf, sizeof(buf), "edje/scripts/lua/%i", sc->i);
2559
   if (eet_write(sc->ef, buf, dat.buf, dat.size, compress_mode) <= 0)
2560
     {
2561
        snprintf(buf, sizeof(buf),
2562
                 "Unable to write script %i", sc->i);
2563
        sc->errstr = strdup(buf);
2564
        return;
2565
     }
2566
#ifdef LUA_BINARY
2567
   free(dat.buf);
2568
#endif
2569
   lua_close(L);
2570
}
2571

2572
static void
2573
data_thread_lua_script_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2574
{
2575
   Script_Write *sc = data;
2576
   if (sc->errstr)
2577
     {
2578
        error_and_abort(sc->ef, sc->errstr);
2579
        free(sc->errstr);
2580
     }
2581
   free(sc);
2582
   thread_end(0);
2583
}
2584

2585
static void
2586
data_write_lua_scripts(Eet_File *ef)
2587
{
2588
   Eina_List *l;
2589
   int i;
2590

2591
   for (i = 0, l = codes; l; l = eina_list_next(l), i++)
2592
     {
2593
        Code *cd;
2594
        Script_Write *sc;
2595

2596
        cd = (Code *)eina_list_data_get(l);
2597
        if (!cd->is_lua)
2598
          continue;
2599
        if ((!cd->shared) && (!cd->programs))
2600
          continue;
2601

2602
        sc = calloc(1, sizeof(Script_Write));
2603
        sc->ef = ef;
2604
        sc->cd = cd;
2605
        sc->i = i;
2606
        pending_threads++;
2607
        if (threads)
2608
          ecore_thread_run(data_thread_lua_script, data_thread_lua_script_end, NULL, sc);
2609
        else
2610
          {
2611
             data_thread_lua_script(sc, NULL);
2612
             data_thread_lua_script_end(sc, NULL);
2613
          }
2614
     }
2615
}
2616

2617
static void
2618
data_thread_source(void *data, Ecore_Thread *thread EINA_UNUSED)
2619
{
2620
   Eet_File *ef = data;
2621
   source_append(ef);
2622
}
2623

2624
static void
2625
data_thread_source_end(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
2626
{
2627
   thread_end(0);
2628
}
2629

2630
static void
2631
data_thread_license(void *data, Ecore_Thread *thread EINA_UNUSED)
2632
{
2633
   License_Write *lw = data;
2634
   Eet_File *ef = lw->ef;
2635
   Eina_File *f;
2636
   void *m;
2637
   int bytes;
2638

2639
   f = eina_file_open(lw->file, 0);
2640
   if (!f) return;
2641

2642
   m = eina_file_map_all(f, EINA_FILE_WILLNEED);
2643
   if (!m) goto on_error;
2644

2645
   if (lw->master)
2646
     {
2647
        bytes = eet_write(ef, "edje/license", m, eina_file_size_get(f), compress_mode);
2648
     }
2649
   else
2650
     {
2651
        char *s = alloca(strlen(lw->file) + 1 + 13);
2652

2653
        strcpy(s, lw->file);
2654
        sprintf(s, "edje/license/%s", basename(s));
2655

2656
        bytes = eet_write(ef, s, m, eina_file_size_get(f), compress_mode);
2657
     }
2658

2659
   if ((bytes <= 0) || eina_file_map_faulted(f, m))
2660
     {
2661
        ERR("Unable to write license part \"%s\".", lw->file);
2662
     }
2663
   else
2664
     {
2665
        double fsize = eina_file_size_get(f);
2666

2667
        if (fsize <= 0.0) fsize = 1.0;
2668
        INF("Wrote %9i bytes (%4iKb) for \"%s\" license entry compress: [real: %2.1f%%]",
2669
            bytes, (bytes + 512) / 1024, license,
2670
            100.0 - ((100.0 * (double)bytes) / fsize));
2671
     }
2672

2673
   eina_file_map_free(f, m);
2674

2675
on_error:
2676
   eina_file_close(f);
2677
}
2678

2679
static void
2680
data_thread_license_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2681
{
2682
   free(data);
2683
   thread_end(0);
2684
}
2685

2686
static void
2687
data_write_license(Eet_File *ef)
2688
{
2689
   License_Write *lw;
2690
   Eina_List *l;
2691
   const char *file;
2692

2693
   if (!license) return;
2694

2695
   lw = calloc(1, sizeof (License_Write));
2696
   if (!lw) return;
2697

2698
   lw->ef = ef;
2699
   lw->file = license;
2700
   lw->master = EINA_TRUE;
2701

2702
   pending_threads++;
2703
   if (threads)
2704
     ecore_thread_run(data_thread_license, data_thread_license_end, NULL, lw);
2705
   else
2706
     {
2707
        data_thread_license(lw, NULL);
2708
        data_thread_license_end(lw, NULL);
2709
     }
2710

2711
   EINA_LIST_FOREACH(licenses, l, file)
2712
     {
2713
        lw = calloc(1, sizeof (License_Write));
2714
        if (!lw) return;
2715

2716
        lw->ef = ef;
2717
        lw->file = file;
2718
        lw->master = EINA_FALSE;
2719

2720
        pending_threads++;
2721
        if (threads)
2722
          ecore_thread_run(data_thread_license, data_thread_license_end, NULL, lw);
2723
        else
2724
          {
2725
             data_thread_license(lw, NULL);
2726
             data_thread_license_end(lw, NULL);
2727
          }
2728
     }
2729
}
2730

2731
static void
2732
data_thread_authors(void *data, Ecore_Thread *thread EINA_UNUSED)
2733
{
2734
   Eet_File *ef = data;
2735
   Eina_File *f;
2736
   void *m;
2737
   int bytes;
2738

2739
   f = eina_file_open(authors, 0);
2740
   if (!f) return;
2741

2742
   m = eina_file_map_all(f, EINA_FILE_WILLNEED);
2743
   if (!m) goto on_error;
2744

2745
   bytes = eet_write(ef, "edje/authors", m, eina_file_size_get(f), compress_mode);
2746
   if ((bytes <= 0) || eina_file_map_faulted(f, m))
2747
     {
2748
        ERR("Unable to write authors part \"%s\".", authors);
2749
     }
2750
   else
2751
     {
2752
        double fsize = eina_file_size_get(f);
2753

2754
        if (fsize <= 0.0) fsize = 1.0;
2755
        INF("Wrote %9i bytes (%4iKb) for \"%s\" authors entry compress: [real: %2.1f%%]",
2756
            bytes, (bytes + 512) / 1024, license,
2757
            100.0 - ((100.0 * (double)bytes) / fsize));
2758
     }
2759

2760
   eina_file_map_free(f, m);
2761

2762
on_error:
2763
   eina_file_close(f);
2764
}
2765

2766
static void
2767
data_thread_authors_end(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
2768
{
2769
   thread_end(0);
2770
}
2771

2772
static void
2773
data_thread_fontmap(void *data, Ecore_Thread *thread EINA_UNUSED)
2774
{
2775
   Eet_File *ef = data;
2776
   source_fontmap_save(ef, fonts);
2777
}
2778

2779
static void
2780
data_thread_fontmap_end(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
2781
{
2782
   thread_end(0);
2783
}
2784

2785
static Eina_Bool
2786
data_write_color_class_register_each_cb(const Eina_Hash *hash EINA_UNUSED,
2787
                                        const void *key,
2788
                                        void *data EINA_UNUSED,
2789
                                        void *fdata)
2790
{
2791
   Edje_Color_Class_Info *cc_info = fdata;
2792
   cc_info->colors = eina_list_append(cc_info->colors,
2793
                                      eina_stringshare_add(key));
2794
   return EINA_TRUE;
2795
}
2796

2797
static void
2798
data_write_color_class_register(Eet_File *ef)
2799
{
2800
   Edje_Color_Class_Info *cc_info;
2801
   const char *s;
2802

2803
   if (!color_class_reg) return;
2804
   cc_info = calloc(1, sizeof(Edje_Color_Class_Info));
2805
   if (!cc_info)
2806
     {
2807
        ERR("Out of Memory");
2808
        exit(-1);
2809
     }
2810
   eina_hash_foreach(color_class_reg,
2811
                     data_write_color_class_register_each_cb,
2812
                     cc_info);
2813

2814
   eet_data_write(ef, _edje_edd_edje_color_class_info,
2815
                  "edje/color_class_info", cc_info, compress_mode);
2816

2817
   eina_hash_free(color_class_reg);
2818
   color_class_reg = NULL;
2819
   EINA_LIST_FREE(cc_info->colors, s) eina_stringshare_del(s);
2820
   free(cc_info);
2821
}
2822

2823
void
2824
data_write(void)
2825
{
2826
   Eet_File *ef;
2827
   Eet_Error err;
2828
   int sound_num = 0;
2829
   int mo_num = 0;
2830
   int vibration_num = 0;
2831
   int font_num = 0;
2832
   int collection_num = 0;
2833
   int vector_num = 0;
2834
   double t;
2835

2836
   if (!edje_file)
2837
     {
2838
        ERR("No data to put in \"%s\"", file_out);
2839
        exit(-1);
2840
     }
2841

2842
   cur_ef = ef = eet_open(file_out, EET_FILE_MODE_WRITE);
2843
   if (!ef)
2844
     {
2845
        ERR("Unable to open \"%s\" for writing output", file_out);
2846
        exit(-1);
2847
     }
2848

2849
   if ((edje_file->efl_version.major <= 1) && (edje_file->efl_version.minor <= 18)
2850
       && edje_file->has_textblock_min_max)
2851
     {
2852
        WRN("This EDC file was designed for EFL 1.18. Until 1.19, EFL used an "
2853
            "invalid calculation mechanism for textblock parts, where the value "
2854
            "of text min/max was not properly taken into account. You might "
2855
            "want to consider adding \"efl_version: %d %d;\" in your EDC "
2856
            "file (before the \"collections\" block), and then check the sizing "
2857
            "for all textblock parts that specify text min/max values (the bool "
2858
            "defined as description.text.{min,max}).",
2859
            EFL_VERSION_MAJOR, EFL_VERSION_MINOR);
2860
     }
2861

2862
   if (eina_array_count(requires))
2863
     {
2864
        int i = 0;
2865

2866
        edje_file->requires_count = eina_array_count(requires);
2867
        edje_file->requires = mem_alloc(edje_file->requires_count * sizeof(void*));
2868
        do
2869
          {
2870
             edje_file->requires[i] = eina_array_pop(requires);
2871
             i++;
2872
          } while (eina_array_count(requires));
2873
        eina_array_free(requires);
2874
     }
2875

2876
   check_groups(ef);
2877

2878
   ecore_thread_max_set(ecore_thread_max_get() * 2);
2879

2880
   pending_threads++;
2881
   t = ecore_time_get();
2882

2883
   INF("header: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2884
   data_write_groups(ef, &collection_num);
2885
   INF("groups: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2886
   data_write_scripts(ef);
2887
   INF("scripts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2888
   data_write_lua_scripts(ef);
2889
   INF("lua scripts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2890

2891
   if (!no_save)
2892
     {
2893
        pending_threads++;
2894
        if (threads)
2895
          ecore_thread_run(data_thread_source, data_thread_source_end, NULL, ef);
2896
        else
2897
          {
2898
             data_thread_source(ef, NULL);
2899
             data_thread_source_end(ef, NULL);
2900
          }
2901
     }
2902
   INF("source: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2903
   pending_threads++;
2904
   if (threads)
2905
     ecore_thread_run(data_thread_fontmap, data_thread_fontmap_end, NULL, ef);
2906
   else
2907
     {
2908
        data_thread_fontmap(ef, NULL);
2909
        data_thread_fontmap_end(ef, NULL);
2910
     }
2911
   INF("fontmap: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2912
   data_write_vectors(ef, &vector_num);
2913
   INF("vectors: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2914
   data_write_fonts(ef, &font_num);
2915
   INF("fonts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2916
   data_write_sounds(ef, &sound_num);
2917
   INF("sounds: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2918
   data_write_mo(ef, &mo_num);
2919
   INF("mo: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2920
   data_write_vibrations(ef, &vibration_num);
2921
   INF("vibrations: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2922
   data_write_license(ef);
2923
   INF("license: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2924
   if (authors)
2925
     {
2926
        pending_threads++;
2927
        if (threads)
2928
          ecore_thread_run(data_thread_authors, data_thread_authors_end, NULL, ef);
2929
        else
2930
          {
2931
             data_thread_authors(ef, NULL);
2932
             data_thread_authors_end(ef, NULL);
2933
          }
2934
     }
2935
   data_write_color_class_register(ef);
2936
   data_write_images();
2937
   data_image_sets_init();
2938
   INF("images: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2939
   pending_threads--;
2940
   if (pending_threads + pending_image_threads > 0) ecore_main_loop_begin();
2941
   INF("THREADS: %3.5f", ecore_time_get() - t);
2942
   data_write_header(ef);
2943
   if (pending_threads + pending_image_threads > 0) ecore_main_loop_begin();
2944
   INF("THREADS: %3.5f", ecore_time_get() - t);
2945

2946
   if (threads)
2947
     {
2948
        /* probably caught signal, exit immediately to avoid crash */
2949
        if (pending_threads + pending_image_threads > 0) exit(-1);
2950
     }
2951

2952
   err = eet_close(ef);
2953
   if (err)
2954
     {
2955
        ERR("Couldn't write file: \"%s\"", file_out);
2956
        exit(-1);
2957
     }
2958

2959
   if (eina_log_domain_level_check(_edje_cc_log_dom, EINA_LOG_LEVEL_INFO))
2960
     {
2961
        printf("Summary:\n"
2962
               "  Wrote %i collections\n"
2963
               "  Wrote %i images\n"
2964
               "  Wrote %i sounds\n"
2965
               "  Wrote %i fonts\n"
2966
               ,
2967
               collection_num,
2968
               image_num,
2969
               sound_num,
2970
               font_num);
2971
     }
2972
}
2973

2974
void
2975
reorder_parts(void)
2976
{
2977
   Edje_Part_Collection *pc;
2978
   Edje_Part **parts;
2979
   Edje_Part_Parser *ep, *ep2;
2980
   Eina_List *l;
2981

2982
   /* sanity checks for parts and programs */
2983
   EINA_LIST_FOREACH(edje_collections, l, pc)
2984
     {
2985
        unsigned int i, j, k;
2986
        Eina_Bool found = EINA_FALSE;
2987

2988
        for (i = 0; i < pc->parts_count; i++)
2989
          {
2990
             ep = (Edje_Part_Parser *)pc->parts[i];
2991
             if (ep->reorder.insert_before && ep->reorder.insert_after)
2992
               error_and_abort(NULL, "In group \"%s\": Unable to use together insert_before and insert_after in part \"%s\".",
2993
                               pc->part, pc->parts[i]->name);
2994

2995
             if (ep->reorder.done)
2996
               {
2997
                  continue;
2998
               }
2999
             if (ep->reorder.insert_before || ep->reorder.insert_after)
3000
               {
3001
                  found = EINA_FALSE;
3002
                  for (j = 0; j < pc->parts_count; j++)
3003
                    {
3004
                       if (ep->reorder.insert_before &&
3005
                           !strcmp(ep->reorder.insert_before, pc->parts[j]->name))
3006
                         {
3007
                            ep2 = (Edje_Part_Parser *)pc->parts[j];
3008
                            if (ep2->reorder.after)
3009
                              error_and_abort(NULL, "In group \"%s\": The part \"%s\" is ambiguous ordered part.",
3010
                                              pc->part, pc->parts[i]->name);
3011
                            if (ep2->reorder.linked_prev)
3012
                              error_and_abort(NULL, "In group \"%s\": Unable to insert two or more parts in same part \"%s\".",
3013
                                              pc->part, pc->parts[j]->name);
3014
                            /* Need it to be able to insert an element before the first */
3015
                            if (j == 0) k = 0;
3016
                            else k = j - 1;
3017
                            found = EINA_TRUE;
3018
                            ep2->reorder.linked_prev += ep->reorder.linked_prev + 1;
3019
                            ep->reorder.before = (Edje_Part_Parser *)pc->parts[j];
3020
                            while (ep2->reorder.before)
3021
                              {
3022
                                 ep2->reorder.before->reorder.linked_prev = ep2->reorder.linked_prev + 1;
3023
                                 ep2 = ep2->reorder.before;
3024
                              }
3025
                            break;
3026
                         }
3027
                       else if (ep->reorder.insert_after &&
3028
                                !strcmp(ep->reorder.insert_after, pc->parts[j]->name))
3029
                         {
3030
                            ep2 = (Edje_Part_Parser *)pc->parts[j];
3031
                            if (ep2->reorder.before)
3032
                              error_and_abort(NULL, "In group \"%s\": The part \"%s\" is ambiguous ordered part.",
3033
                                              pc->part, pc->parts[i]->name);
3034
                            if (ep2->reorder.linked_next)
3035
                              error_and_abort(NULL, "In group \"%s\": Unable to insert two or more parts in same part \"%s\".",
3036
                                              pc->part, pc->parts[j]->name);
3037
                            k = j;
3038
                            found = EINA_TRUE;
3039
                            ep2->reorder.linked_next += ep->reorder.linked_next + 1;
3040
                            ep->reorder.after = (Edje_Part_Parser *)pc->parts[j];
3041
                            while (ep2->reorder.after)
3042
                              {
3043
                                 ep2->reorder.after->reorder.linked_next = ep2->reorder.linked_next + 1;
3044
                                 ep2 = ep2->reorder.after;
3045
                              }
3046
                            break;
3047
                         }
3048
                    }
3049
                  if (found)
3050
                    {
3051
                       unsigned int amount, linked;
3052

3053
                       if (((i > k) && ((i - ep->reorder.linked_prev) <= k))
3054
                           || ((i < k) && ((i + ep->reorder.linked_next) >= k)))
3055
                         error_and_abort(NULL, "In group \"%s\": The part order is wrong. It has circular dependency.", pc->part);
3056

3057
                       amount = ep->reorder.linked_prev + ep->reorder.linked_next + 1;
3058
                       linked = i - ep->reorder.linked_prev;
3059
                       parts = malloc(amount * sizeof(Edje_Part *));
3060
                       for (j = 0; j < amount; j++)
3061
                         {
3062
                            parts[j] = pc->parts[linked];
3063
                            linked++;
3064
                         }
3065
                       if (i > k)
3066
                         {
3067
                            for (j = i - ep->reorder.linked_prev; j > k; j--)
3068
                              {
3069
                                 pc->parts[j + amount - 1] = pc->parts[j - 1];
3070
                                 pc->parts[j + amount - 1]->id = j + amount - 1;
3071
                              }
3072
                            for (j = 0; j < amount; j++)
3073
                              {
3074
                                 pc->parts[j + k] = parts[j];
3075
                                 pc->parts[j + k]->id = j + k;
3076
                              }
3077
                         }
3078
                       else if (i < k)
3079
                         {
3080
                            for (j = i + ep->reorder.linked_next + 1; j <= k; j++)
3081
                              {
3082
                                 pc->parts[j - amount] = pc->parts[j];
3083
                                 pc->parts[j - amount]->id = j - amount;
3084
                              }
3085
                            for (j = 0; j < amount; j++)
3086
                              {
3087
                                 pc->parts[j + k - amount + 1] = parts[j];
3088
                                 pc->parts[j + k - amount + 1]->id = j + k - amount + 1;
3089
                              }
3090
                            i -= amount;
3091
                         }
3092
                       ep->reorder.done = EINA_TRUE;
3093
                       free(parts);
3094
                    }
3095
                  else
3096
                    {
3097
                       if (ep->reorder.insert_before)
3098
                         error_and_abort(NULL, "In group \"%s\": Unable to find part \"%s\" for insert_before in part \"%s\".",
3099
                                         pc->part, ep->reorder.insert_before, pc->parts[i]->name);
3100
                       else
3101
                         error_and_abort(NULL, "In group \"%s\": Unable to find part \"%s\" for insert_after in part \"%s\".",
3102
                                         pc->part, ep->reorder.insert_after, pc->parts[i]->name);
3103
                    }
3104
               }
3105
          }
3106
     }
3107
}
3108

3109
void
3110
data_queue_group_lookup(const char *name, Edje_Part *part)
3111
{
3112
   Group_Lookup *gl;
3113

3114
   if (!name || !name[0]) return;
3115

3116
   gl = mem_alloc(SZ(Group_Lookup));
3117
   group_lookups = eina_list_append(group_lookups, gl);
3118
   gl->name = mem_strdup(name);
3119
   gl->part = part;
3120
}
3121

3122
void
3123
data_queue_face_group_lookup(const char *name)
3124
{
3125
   char *group_name;
3126

3127
   if (!name || !name[0]) return;
3128

3129
   group_name = mem_strdup(name);
3130
   face_group_lookups = eina_list_append(face_group_lookups, group_name);
3131
}
3132

3133
void
3134
data_queue_part_lookup(Edje_Part_Collection *pc, const char *name, int *dest)
3135
{
3136
   data_queue_part_nest_lookup(pc, name, dest, NULL);
3137
}
3138

3139
void
3140
data_queue_part_nest_lookup(Edje_Part_Collection *pc, const char *name, int *dest, char **dest2)
3141
{
3142
   Part_Lookup_Key key;
3143
   Part_Lookup *pl = NULL;
3144
   Eina_List *list;
3145
   key.pc = pc;
3146
   key.mem.dest = dest;
3147
   key.stable = EINA_TRUE;
3148

3149
   pl = eina_hash_find(part_pc_dest_lookup, &key);
3150
   if (pl)
3151
     {
3152
        if (name[0])
3153
          {
3154
             free(pl->name);
3155
             pl->name = mem_strdup(name);
3156
          }
3157
        else
3158
          {
3159
             list = eina_hash_find(part_dest_lookup, &pl->key);
3160
             list = eina_list_remove(list, pl);
3161
             eina_hash_set(part_dest_lookup, &pl->key, list);
3162
             eina_hash_del(part_pc_dest_lookup, &key, pl);
3163
          }
3164
        return;
3165
     }
3166

3167
   if (!name[0]) return;
3168

3169
   pl = mem_alloc(SZ(Part_Lookup));
3170
   pl->name = mem_strdup(name);
3171
   pl->key.pc = pc;
3172
   pl->key.mem.dest = dest;
3173
   pl->key.dest2 = dest2;
3174
   pl->key.stable = EINA_TRUE;
3175

3176
   eina_hash_add(part_pc_dest_lookup, &key, pl);
3177

3178
   list = eina_hash_find(part_dest_lookup, &pl->key);
3179
   list = eina_list_prepend(list, pl);
3180
   eina_hash_set(part_dest_lookup, &pl->key, list);
3181
}
3182

3183
void
3184
data_queue_part_reallocated_lookup(Edje_Part_Collection *pc, const char *name,
3185
                                   unsigned char **base, int offset)
3186
{
3187
   Part_Lookup_Key key;
3188
   Part_Lookup *pl = NULL;
3189
   Eina_List *list;
3190
   key.pc = pc;
3191
   key.mem.reallocated.base = base;
3192
   key.mem.reallocated.offset = offset;
3193
   key.stable = EINA_FALSE;
3194

3195
   pl = eina_hash_find(part_pc_dest_lookup, &key);
3196
   if (pl)
3197
     {
3198
        if (name[0])
3199
          {
3200
             free(pl->name);
3201
             pl->name = mem_strdup(name);
3202
          }
3203
        else
3204
          {
3205
             list = eina_hash_find(part_dest_lookup, &pl->key);
3206
             list = eina_list_remove(list, pl);
3207
             eina_hash_set(part_dest_lookup, &pl->key, list);
3208
             eina_hash_del(part_pc_dest_lookup, &key, pl);
3209
          }
3210
        return;
3211
     }
3212

3213
   if (!name[0]) return;
3214

3215
   pl = mem_alloc(SZ(Part_Lookup));
3216
   pl->name = mem_strdup(name);
3217
   pl->key.pc = pc;
3218
   pl->key.mem.reallocated.base = base;
3219
   pl->key.mem.reallocated.offset = offset;
3220
   pl->key.stable = EINA_FALSE;
3221

3222
   eina_hash_add(part_pc_dest_lookup, &key, pl);
3223

3224
   list = eina_hash_find(part_dest_lookup, &pl->key);
3225
   list = eina_list_prepend(list, pl);
3226
   eina_hash_set(part_dest_lookup, &pl->key, list);
3227
}
3228

3229
void
3230
part_lookup_del(Edje_Part_Collection *pc, int *dest)
3231
{
3232
   Part_Lookup_Key key;
3233
   Part_Lookup *pl = NULL;
3234
   Eina_List *list;
3235
   key.pc = pc;
3236
   key.mem.dest = dest;
3237
   key.stable = EINA_TRUE;
3238

3239
   pl = eina_hash_find(part_pc_dest_lookup, &key);
3240
   if (!pl) return;
3241
   list = eina_hash_find(part_dest_lookup, &pl->key);
3242
   if (list)
3243
     eina_hash_del(part_dest_lookup, &pl->key, list);
3244
   eina_hash_del(part_pc_dest_lookup, &key, pl);
3245
}
3246

3247
void
3248
part_lookup_delete(Edje_Part_Collection *pc, const char *name, int *dest, char **dest2)
3249
{
3250
   Part_Lookup_Key key;
3251
   Part_Lookup *pl = NULL;
3252
   Part_Lookup *lpl;
3253
   Eina_List *list, *l, *ll;
3254
   key.pc = pc;
3255
   key.mem.dest = dest;
3256
   key.stable = EINA_TRUE;
3257

3258
   pl = eina_hash_find(part_pc_dest_lookup, &key);
3259
   if (!pl) return;
3260
   list = eina_hash_find(part_dest_lookup, &pl->key);
3261
   EINA_LIST_FOREACH_SAFE(list, l, ll, lpl)
3262
     {
3263
        if (strcmp(lpl->name, name) || (lpl->key.dest2 != dest2)) continue;
3264
        free(lpl->name);
3265
        list = eina_list_remove_list(list, l);
3266
        free(lpl);
3267
     }
3268
   eina_hash_set(part_dest_lookup, &pl->key, list);
3269
}
3270

3271
void
3272
data_queue_copied_part_lookup(Edje_Part_Collection *pc, int *src, int *dest)
3273
{
3274
   data_queue_copied_part_nest_lookup(pc, src, dest, NULL);
3275
}
3276

3277
void
3278
data_queue_copied_part_nest_lookup(Edje_Part_Collection *pc, int *src, int *dest, char **dest2)
3279
{
3280
   Eina_List *list;
3281
   Eina_List *l;
3282
   Part_Lookup *pl;
3283
   Part_Lookup_Key key;
3284

3285
   key.pc = NULL;
3286
   key.mem.dest = src;
3287
   key.stable = EINA_TRUE;
3288

3289
   list = eina_hash_find(part_dest_lookup, &key);
3290
   EINA_LIST_FOREACH(list, l, pl)
3291
     if (pl->key.stable)
3292
       data_queue_part_nest_lookup(pc, pl->name, dest, dest2);
3293
}
3294

3295
void
3296
data_queue_anonymous_lookup(Edje_Part_Collection *pc, Edje_Program *ep, int *dest)
3297
{
3298
   Eina_List *l, *l1, *l2, *l3;
3299
   Program_Lookup *pl;
3300

3301
   if (!ep) return;  /* FIXME: should we stop compiling ? */
3302

3303
   EINA_LIST_FOREACH_SAFE(program_lookups, l, l1, pl)
3304
     {
3305
        if (pl->u.ep == ep)
3306
          {
3307
             Code *cd;
3308
             Code_Program *cp;
3309

3310
             cd = eina_list_data_get(eina_list_last(codes));
3311

3312
             EINA_LIST_FOREACH_SAFE(cd->programs, l2, l3, cp)
3313
               {
3314
                  if (&(cp->id) == pl->dest)
3315
                    {
3316
                       cd->programs = eina_list_remove_list(cd->programs, l2);
3317
                       free(cp);
3318
                       cp = NULL;
3319
                    }
3320
               }
3321
             program_lookups = eina_list_remove_list(program_lookups, l);
3322
             free(pl);
3323
          }
3324
     }
3325

3326
   if (dest)
3327
     {
3328
        pl = mem_alloc(SZ(Program_Lookup));
3329
        program_lookups = eina_list_append(program_lookups, pl);
3330
        pl->pc = pc;
3331
        pl->u.ep = ep;
3332
        pl->dest = dest;
3333
        pl->anonymous = EINA_TRUE;
3334
     }
3335
}
3336

3337
void
3338
copied_program_anonymous_lookup_delete(Edje_Part_Collection *pc, int *dest)
3339
{
3340
   Program_Lookup *pl;
3341
   Eina_List *l, *ll;
3342

3343
   EINA_LIST_FOREACH_SAFE(program_lookups, l, ll, pl)
3344
     {
3345
        if ((!pl->anonymous) || (pl->pc != pc) || (dest != &pl->u.ep->id)) continue;
3346
        program_lookups = eina_list_remove_list(program_lookups, l);
3347

3348
        Code *cd;
3349
        Code_Program *cp;
3350
        Edje_Part_Collection_Directory_Entry *de;
3351
        Eina_List *l2, *ll2;
3352

3353
        de = eina_hash_find(edje_file->collection, pl->pc->part);
3354
        cd = eina_list_nth(codes, de->id);
3355

3356
        EINA_LIST_FOREACH_SAFE(cd->programs, l2, ll2, cp)
3357
          {
3358
             if (pl->dest == &cp->id)
3359
               {
3360
                  cd->programs = eina_list_remove_list(cd->programs, l2);
3361
                  free(cp);
3362
                  break;
3363
               }
3364
          }
3365

3366
        free(pl);
3367
     }
3368
}
3369

3370
void
3371
data_queue_copied_anonymous_lookup(Edje_Part_Collection *pc, int *src, int *dest)
3372
{
3373
   Eina_List *l;
3374
   Program_Lookup *pl;
3375
   unsigned int i;
3376

3377
   EINA_LIST_FOREACH(program_lookups, l, pl)
3378
     {
3379
        if (pl->dest == src && pl->u.ep->name)
3380
          {
3381
             for (i = 0; i < pc->programs.fnmatch_count; i++)
3382
               {
3383
                  if (pc->programs.fnmatch[i]->name &&
3384
                      !strcmp(pl->u.ep->name, pc->programs.fnmatch[i]->name))
3385
                    data_queue_anonymous_lookup(pc, pc->programs.fnmatch[i], dest);
3386
               }
3387
             for (i = 0; i < pc->programs.strcmp_count; i++)
3388
               {
3389
                  if (pc->programs.strcmp[i]->name &&
3390
                      !strcmp(pl->u.ep->name, pc->programs.strcmp[i]->name))
3391
                    data_queue_anonymous_lookup(pc, pc->programs.strcmp[i], dest);
3392
               }
3393
             for (i = 0; i < pc->programs.strncmp_count; i++)
3394
               {
3395
                  if (pc->programs.strncmp[i]->name &&
3396
                      !strcmp(pl->u.ep->name, pc->programs.strncmp[i]->name))
3397
                    data_queue_anonymous_lookup(pc, pc->programs.strncmp[i], dest);
3398
               }
3399
             for (i = 0; i < pc->programs.strrncmp_count; i++)
3400
               {
3401
                  if (pc->programs.strrncmp[i]->name &&
3402
                      !strcmp(pl->u.ep->name, pc->programs.strrncmp[i]->name))
3403
                    data_queue_anonymous_lookup(pc, pc->programs.strrncmp[i], dest);
3404
               }
3405
             for (i = 0; i < pc->programs.nocmp_count; i++)
3406
               {
3407
                  if (pc->programs.nocmp[i]->name &&
3408
                      !strcmp(pl->u.ep->name, pc->programs.nocmp[i]->name))
3409
                    data_queue_anonymous_lookup(pc, pc->programs.nocmp[i], dest);
3410
               }
3411
          }
3412
     }
3413
}
3414

3415
void *
3416
data_queue_program_lookup(Edje_Part_Collection *pc, const char *name, int *dest)
3417
{
3418
   Program_Lookup *pl;
3419
   Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser *)pc;
3420

3421
   if (pcp->inherit_only && (!current_group_inherit)) return NULL;
3422

3423
   if (!name) return NULL;  /* FIXME: should we stop compiling ? */
3424

3425
   pl = mem_alloc(SZ(Program_Lookup));
3426
   program_lookups = eina_list_append(program_lookups, pl);
3427
   pl->pc = pc;
3428
   pl->u.name = mem_strdup(name);
3429
   pl->dest = dest;
3430
   pl->anonymous = EINA_FALSE;
3431
   return pl;
3432
}
3433

3434
void
3435
program_lookup_rename(void *p, const char *name)
3436
{
3437
   Program_Lookup *pl = p;
3438

3439
   free(pl->u.name);
3440
   pl->u.name = strdup(name);
3441
}
3442

3443
void
3444
copied_program_lookup_delete(Edje_Part_Collection *pc, const char *name)
3445
{
3446
   Program_Lookup *pl;
3447
   Eina_List *l, *ll;
3448

3449
   EINA_LIST_FOREACH_SAFE(program_lookups, l, ll, pl)
3450
     {
3451
        if (pl->anonymous || (pl->pc != pc) || strcmp(pl->u.name, name)) continue;
3452
        free(pl->u.name);
3453
        program_lookups = eina_list_remove_list(program_lookups, l);
3454
        free(pl);
3455
     }
3456
}
3457

3458
Eina_Bool
3459
data_queue_copied_program_lookup(Edje_Part_Collection *pc, int *src, int *dest)
3460
{
3461
   Eina_List *l;
3462
   Program_Lookup *pl;
3463

3464
   EINA_LIST_FOREACH(program_lookups, l, pl)
3465
     {
3466
        if (pl->dest == src)
3467
          {
3468
             data_queue_program_lookup(pc, pl->u.name, dest);
3469
             return EINA_TRUE;
3470
          }
3471
     }
3472
   return EINA_FALSE;
3473
}
3474

3475
void
3476
data_queue_image_lookup(char *name, int *dest, Eina_Bool *set)
3477
{
3478
   Image_Lookup *il;
3479

3480
   il = mem_alloc(SZ(Image_Lookup));
3481
   image_lookups = eina_list_append(image_lookups, il);
3482
   il->name = mem_strdup(name);
3483
   il->dest = dest;
3484
   il->set = set;
3485
}
3486

3487
void
3488
data_queue_image_remove(int *dest, Eina_Bool *set)
3489
{
3490
   Eina_List *l;
3491
   Image_Lookup *il;
3492

3493
   EINA_LIST_FOREACH(image_lookups, l, il)
3494
     {
3495
        if (il->dest == dest && il->set == set)
3496
          {
3497
             image_lookups = eina_list_remove_list(image_lookups, l);
3498
             free(il->name);
3499
             free(il);
3500
             return;
3501
          }
3502
     }
3503
}
3504

3505
void
3506
data_queue_copied_image_lookup(int *src, int *dest, Eina_Bool *set)
3507
{
3508
   Eina_List *l;
3509
   Image_Lookup *il;
3510

3511
   EINA_LIST_FOREACH(image_lookups, l, il)
3512
     {
3513
        if (il->dest == src)
3514
          data_queue_image_lookup(il->name, dest, set);
3515
     }
3516
}
3517

3518
static Eina_Bool
3519
data_process_part_set(Part_Lookup *target, int value)
3520
{
3521
   if (target->key.stable)
3522
     {
3523
        *(target->key.mem.dest) = value;
3524
        if (target->key.dest2) return EINA_TRUE;
3525
     }
3526
   else
3527
     {
3528
        *((int *)(*target->key.mem.reallocated.base +
3529
                  target->key.mem.reallocated.offset)) = value;
3530
     }
3531
   return EINA_FALSE;
3532
}
3533

3534
static int
3535
_data_image_w_size_compare_cb(const void *data1, const void *data2)
3536
{
3537
   const Edje_Image_Directory_Set_Entry *img1 = data1;
3538
   const Edje_Image_Directory_Set_Entry *img2 = data2;
3539

3540
   if (img1->size.w < img2->size.w) return -1;
3541
   if (img1->size.w > img2->size.w) return 1;
3542

3543
   return 0;
3544
}
3545

3546
static int
3547
_data_image_h_size_compare_cb(const void *data1, const void *data2)
3548
{
3549
   const Edje_Image_Directory_Set_Entry *img1 = data1;
3550
   const Edje_Image_Directory_Set_Entry *img2 = data2;
3551

3552
   if (img1->size.h < img2->size.h) return -1;
3553
   if (img1->size.h > img2->size.h) return 1;
3554

3555
   return 0;
3556
}
3557

3558
static void
3559
_data_image_sets_size_set(void)
3560
{
3561
   Evas *evas;
3562
   Edje_Image_Directory_Set *set;
3563
   Edje_Image_Directory_Set_Entry *simg, *preimg;
3564
   Eina_List *l, *entries;
3565
   unsigned int i;
3566

3567
   if (!buffer_ee)
3568
     buffer_ee = ecore_evas_buffer_new(1, 1);
3569
   if (!buffer_ee)
3570
     {
3571
        ERR("Cannot create buffer engine canvas for image load.");
3572
        exit(-1);
3573
     }
3574
   evas = ecore_evas_get(buffer_ee);
3575

3576
   for (i = 0; i < edje_file->image_dir->sets_count; i++)
3577
     {
3578
        set = edje_file->image_dir->sets + i;
3579

3580
        if (!set->entries) continue;
3581
        EINA_LIST_FOREACH(set->entries, l, simg)
3582
          {
3583
             Evas_Object *im;
3584
             Eina_List *ll;
3585
             char *s;
3586

3587
             im = evas_object_image_add(evas);
3588
             EINA_LIST_FOREACH(img_dirs, ll, s)
3589
               {
3590
                  char buf[PATH_MAX];
3591
                  int load_err = EVAS_LOAD_ERROR_NONE;
3592

3593
                  snprintf(buf, sizeof(buf), "%s/%s", s, simg->name);
3594
                  evas_object_image_file_set(im, buf, NULL);
3595
                  load_err = evas_object_image_load_error_get(im);
3596
                  if (load_err == EVAS_LOAD_ERROR_NONE)
3597
                    {
3598
                       evas_object_image_size_get(im, &simg->size.w, &simg->size.h);
3599
                       break;
3600
                    }
3601
               }
3602
             evas_object_del(im);
3603
          }
3604

3605
        entries = eina_list_clone(set->entries);
3606

3607
        entries = eina_list_sort(entries, 0, _data_image_w_size_compare_cb);
3608
        preimg = eina_list_data_get(entries);
3609
        EINA_LIST_FOREACH(entries, l, simg)
3610
          {
3611
             if (simg == preimg) continue;
3612
             if (!(preimg->size.max.w) && !(simg->size.min.w))
3613
               {
3614
                  preimg->size.max.w = (preimg->size.w + simg->size.w) / 2;
3615
                  simg->size.min.w = preimg->size.max.w + 1;
3616
                  if (simg->size.min.w <= (simg->border.l + simg->border.r))
3617
                    {
3618
                       preimg->size.max.w = simg->border.l + simg->border.r;
3619
                       simg->size.min.w = preimg->size.max.w + 1;
3620
                    }
3621
               }
3622
             else if (preimg->size.max.w && !(simg->size.min.w))
3623
               simg->size.min.w = preimg->size.max.w + 1;
3624
             else if (!(preimg->size.max.w) && simg->size.min.w)
3625
               preimg->size.max.w = simg->size.min.w - 1;
3626
             preimg = simg;
3627
          }
3628
        simg = eina_list_data_get(eina_list_last(entries));
3629
        if (!(simg->size.max.w)) simg->size.max.w = 99999;
3630

3631
        entries = eina_list_sort(entries, 0, _data_image_h_size_compare_cb);
3632
        preimg = eina_list_data_get(entries);
3633
        EINA_LIST_FOREACH(entries, l, simg)
3634
          {
3635
             if (simg == preimg) continue;
3636
             if (!(preimg->size.max.h) && !(simg->size.min.h))
3637
               {
3638
                  preimg->size.max.h = (preimg->size.h + simg->size.h) / 2;
3639
                  simg->size.min.h = preimg->size.max.h + 1;
3640
                  if (simg->size.min.h <= (simg->border.t + simg->border.b))
3641
                    {
3642
                       preimg->size.max.h = simg->border.t + simg->border.b;
3643
                       simg->size.min.h = preimg->size.max.h + 1;
3644
                    }
3645
               }
3646
             else if (preimg->size.max.h && !(simg->size.min.h))
3647
               simg->size.min.h = preimg->size.max.h + 1;
3648
             else if (!(preimg->size.max.h) && simg->size.min.h)
3649
               preimg->size.max.h = simg->size.min.h - 1;
3650
             preimg = simg;
3651
          }
3652
        simg = eina_list_data_get(eina_list_last(entries));
3653
        if (!(simg->size.max.h)) simg->size.max.h = 99999;
3654

3655
        eina_list_free(entries);
3656
     }
3657
}
3658

3659
/*
3660
static void
3661
_data_image_id_update(Eina_List *images_unused_list)
3662
{
3663
   Image_Unused_Ids *iui;
3664
   Edje_Part_Collection *pc;
3665
   Edje_Part *part;
3666
   Edje_Part_Description_Image *part_desc_image;
3667
   Edje_Part_Image_Id *tween_id;
3668
   unsigned int i, j, desc_it;
3669
   Eina_List *l, *l2, *l3;
3670

3671
#define PART_DESC_IMAGE_ID_UPDATE                                             \
3672
  EINA_LIST_FOREACH(images_unused_list, l3, iui)                             \
3673
    {                                                                         \
3674
       if ((iui) && (part_desc_image->image.id == iui->old_id))               \
3675
         {                                                                    \
3676
            part_desc_image->image.id = iui->new_id;                          \
3677
            break;                                                            \
3678
         }                                                                    \
3679
    }                                                                         \
3680
  for (desc_it = 0; desc_it < part_desc_image->image.tweens_count; desc_it++) \
3681
    {                                                                         \
3682
       tween_id = part_desc_image->image.tweens[desc_it];                     \
3683
       EINA_LIST_FOREACH(images_unused_list, l3, iui)                        \
3684
         {                                                                    \
3685
            if ((iui) && (tween_id->id == iui->old_id))                       \
3686
              {                                                               \
3687
                 tween_id->id = iui->new_id;                                  \
3688
                 break;                                                       \
3689
              }                                                               \
3690
         }                                                                    \
3691
    }
3692

3693
   EINA_LIST_FOREACH_SAFE(edje_collections, l, l2, pc)
3694
     {
3695
        for (i = 0; i < pc->parts_count; i++)
3696
          {
3697
             part = pc->parts[i];
3698
             if (part->type == EDJE_PART_TYPE_IMAGE)
3699
               {
3700
                  part_desc_image = (Edje_Part_Description_Image *)part->default_desc;
3701
                  if (!part_desc_image) continue;
3702
                  PART_DESC_IMAGE_ID_UPDATE
3703
                  for (j = 0; j < part->other.desc_count; j++)
3704
                    {
3705
                       part_desc_image = (Edje_Part_Description_Image *)part->other.desc[j];
3706
                       PART_DESC_IMAGE_ID_UPDATE
3707
                    }
3708
               }
3709
          }
3710
     }
3711
   for (i = 0; i < edje_file->image_dir->sets_count; i++)
3712
     {
3713
        Eina_List *entries, *list;
3714
        Edje_Image_Directory_Set_Entry *entry;
3715

3716
        entries = edje_file->image_dir->sets[i].entries;
3717
        EINA_LIST_FOREACH(entries, list, entry)
3718
          {
3719
             EINA_LIST_FOREACH(images_unused_list, l3, iui)
3720
               {
3721
                  if ((iui) && (entry->id == iui->old_id))
3722
                    {
3723
                       entry->id = iui->new_id;
3724
                       break;
3725
                    }
3726
               }
3727
          }
3728
     }
3729
}
3730
 */
3731

3732
void
3733
data_process_lookups(void)
3734
{
3735
   Edje_Part_Collection *pc;
3736
   Eina_Iterator *it;
3737
   Part_Lookup *part;
3738
   Program_Lookup *program;
3739
   Group_Lookup *group;
3740
   Image_Lookup *image;
3741
   Eina_List *l2;
3742
   Eina_List *l;
3743
   Eina_Hash *images_in_use;
3744
   char *group_name;
3745
   Eina_Bool is_lua = EINA_FALSE;
3746
//   Image_Unused_Ids *iui;
3747

3748
   /* remove all unreferenced Edje_Part_Collection */
3749
   EINA_LIST_FOREACH_SAFE(edje_collections, l, l2, pc)
3750
     {
3751
        Edje_Part_Collection_Directory_Entry *alias;
3752
        Edje_Part_Collection_Directory_Entry *find;
3753
        Eina_List *l3;
3754
        unsigned int id = 0;
3755
        unsigned int i;
3756

3757
        if (!pc->part)
3758
          {
3759
             ERR("A collection without a name was detected, that's not allowed.");
3760
             exit(-1);
3761
          }
3762

3763
        find = eina_hash_find(edje_file->collection, pc->part);
3764
        if (find && find->id == pc->id)
3765
          {
3766
             if (((Edje_Part_Collection_Parser *)pc)->inherit_only)
3767
               eina_hash_del_by_data(edje_file->collection, find);
3768
             else
3769
               continue;
3770
          }
3771

3772
        EINA_LIST_FOREACH(aliases, l3, alias)
3773
          if (alias->id == pc->id)
3774
            continue;
3775

3776
        /* This Edje_Part_Collection is not used at all */
3777
        edje_collections = eina_list_remove_list(edje_collections, l);
3778
        l3 = eina_list_nth_list(codes, pc->id);
3779
        codes = eina_list_remove_list(codes, l3);
3780

3781
        /* Unref all image used by that group */
3782
        for (i = 0; i < pc->parts_count; ++i)
3783
          part_description_image_cleanup(pc->parts[i]);
3784

3785
        /* Correct all id */
3786
        EINA_LIST_FOREACH(edje_collections, l3, pc)
3787
          {
3788
             Eina_List *l4;
3789
             Edje_Part_Collection_Directory_Entry *de;
3790

3791
             /* Some group could be removed from the collection, but still be referenced by alias */
3792
             /* Update all matching alias */
3793
             EINA_LIST_FOREACH(aliases, l4, alias)
3794
               if (pc->id == alias->id)
3795
                 alias->id = id;
3796

3797
             find = eina_hash_find(edje_file->collection, pc->part);
3798
             if (pc->id != find->id) find = NULL;
3799

3800
             de = eina_hash_find(edje_collections_lookup, &pc->id);
3801
             eina_hash_set(edje_collections_lookup, &pc->id, NULL);
3802
             de->id = pc->id = id++;
3803
             eina_hash_set(edje_collections_lookup, &pc->id, de);
3804
             if (find) find->id = pc->id;
3805
          }
3806
     }
3807

3808
   EINA_LIST_FOREACH(edje_collections, l, pc)
3809
     {
3810
        unsigned int count = 0;
3811
        unsigned int i;
3812

3813
        if (pc->lua_script_only)
3814
          is_lua = EINA_TRUE;
3815
#define PROGRAM_ID_SET(Type, Pc, It, Count)            \
3816
  for (It = 0; It < Pc->programs.Type ## _count; ++It) \
3817
    {                                                  \
3818
       Pc->programs.Type[It]->id = Count++;            \
3819
    }
3820

3821
        PROGRAM_ID_SET(fnmatch, pc, i, count);
3822
        PROGRAM_ID_SET(strcmp, pc, i, count);
3823
        PROGRAM_ID_SET(strncmp, pc, i, count);
3824
        PROGRAM_ID_SET(strrncmp, pc, i, count);
3825
        PROGRAM_ID_SET(nocmp, pc, i, count);
3826

3827
#undef PROGRAM_ID_SET
3828
     }
3829

3830
   it = eina_hash_iterator_data_new(part_pc_dest_lookup);
3831
   EINA_ITERATOR_FOREACH(it, part)
3832
     {
3833
        Edje_Part *ep;
3834
        unsigned int i;
3835

3836
        if (!strcmp(part->name, "-"))
3837
          {
3838
             data_process_part_set(part, -1);
3839
          }
3840
        else
3841
          {
3842
             char *alias, *ap;
3843

3844
             alias = eina_hash_find(part->key.pc->alias, part->name);
3845
             if (!alias)
3846
               alias = part->name;
3847
             ap = strchr(alias, EDJE_PART_PATH_SEPARATOR);
3848
             if (ap)
3849
               {
3850
                  char *tmp;
3851

3852
                  tmp = alloca(strlen(alias) + 1);
3853
                  memcpy(tmp, alias, ap - alias);
3854
                  tmp[ap - alias] = 0;
3855
                  ap += 1;
3856
                  alias = tmp;
3857
               }
3858
             for (i = 0; i < part->key.pc->parts_count; ++i)
3859
               {
3860
                  ep = part->key.pc->parts[i];
3861

3862
                  if ((ep->name) && (!strcmp(ep->name, alias)))
3863
                    {
3864
                       if (data_process_part_set(part, ep->id))
3865
                         *part->key.dest2 = ap;
3866
                       break;
3867
                    }
3868
               }
3869

3870
             if ((i == part->key.pc->parts_count) && (!((Edje_Part_Collection_Parser *)part->key.pc)->inherit_only))
3871
               {
3872
                  ERR("Unable to find part name \"%s\" needed in group '%s'.",
3873
                      alias, part->key.pc->part);
3874
                  exit(-1);
3875
               }
3876
          }
3877
     }
3878
   eina_iterator_free(it);
3879
   eina_hash_free(part_dest_lookup);
3880
   eina_hash_free(part_pc_dest_lookup);
3881

3882
   EINA_LIST_FREE(program_lookups, program)
3883
     {
3884
        unsigned int i;
3885
        Eina_Bool find = EINA_FALSE;
3886

3887
#define PROGRAM_MATCH(Type, Pl, It)                                             \
3888
  for (It = 0; It < Pl->pc->programs.Type ## _count; ++It)                      \
3889
    {                                                                           \
3890
       Edje_Program *ep;                                                        \
3891
                                                                                \
3892
       ep = Pl->pc->programs.Type[It];                                          \
3893
                                                                                \
3894
       if ((Pl->anonymous && ep == Pl->u.ep) ||                                 \
3895
           ((!Pl->anonymous) && (ep->name) && (!strcmp(ep->name, Pl->u.name)))) \
3896
         {                                                                      \
3897
            *(Pl->dest) = ep->id;                                               \
3898
            find = EINA_TRUE;                                                   \
3899
            break;                                                              \
3900
         }                                                                      \
3901
    }
3902

3903
        PROGRAM_MATCH(fnmatch, program, i);
3904
        PROGRAM_MATCH(strcmp, program, i);
3905
        PROGRAM_MATCH(strncmp, program, i);
3906
        PROGRAM_MATCH(strrncmp, program, i);
3907
        PROGRAM_MATCH(nocmp, program, i);
3908

3909
#undef PROGRAM_MATCH
3910

3911
        if (!find)
3912
          {
3913
             if (!program->anonymous)
3914
               ERR("Unable to find program name \"%s\".",
3915
                   program->u.name);
3916
             else
3917
               ERR("Unable to find anonymous program.");
3918
             exit(-1);
3919
          }
3920

3921
        if (!program->anonymous)
3922
          free(program->u.name);
3923
        free(program);
3924
     }
3925

3926
   groups_sourced = eina_hash_string_superfast_new(NULL);
3927
   EINA_LIST_FREE(group_lookups, group)
3928
     {
3929
        Edje_Part_Collection_Directory_Entry *de;
3930

3931
        if (group->part)
3932
          {
3933
             if (group->part->type != EDJE_PART_TYPE_GROUP
3934
                 && group->part->type != EDJE_PART_TYPE_TEXTBLOCK
3935
                 && group->part->type != EDJE_PART_TYPE_BOX
3936
                 && group->part->type != EDJE_PART_TYPE_TABLE)
3937
               goto free_group;
3938
          }
3939

3940
        de = eina_hash_find(edje_file->collection, group->name);
3941

3942
        if (!de)
3943
          {
3944
             Eina_Bool found = EINA_FALSE;
3945

3946
             EINA_LIST_FOREACH(aliases, l, de)
3947
               if (strcmp(de->entry, group->name) == 0)
3948
                 {
3949
                    found = EINA_TRUE;
3950
                    break;
3951
                 }
3952
             if (!found) de = NULL;
3953
          }
3954

3955
        if (!de)
3956
          {
3957
             ERR("Unable to find group name \"%s\".", group->name);
3958
             exit(-1);
3959
          }
3960

3961
        eina_hash_add(groups_sourced, group->name, (void*)1);
3962
free_group:
3963
        free(group->name);
3964
        free(group);
3965
     }
3966

3967
   EINA_LIST_FREE(face_group_lookups, group_name)
3968
     {
3969
        Edje_Part_Collection_Directory_Entry *de;
3970

3971
        de = eina_hash_find(edje_file->collection, group_name);
3972

3973
        if (!de)
3974
          {
3975
             Eina_Bool found = EINA_FALSE;
3976

3977
             EINA_LIST_FOREACH(aliases, l, de)
3978
               if (strcmp(de->entry, group_name) == 0)
3979
                 {
3980
                    found = EINA_TRUE;
3981
                    break;
3982
                 }
3983
             if (!found) de = NULL;
3984
          }
3985

3986
        if (!de)
3987
          {
3988
             ERR("Unable to find group name \"%s\".", group_name);
3989
             exit(-1);
3990
          }
3991

3992
        free(group_name);
3993
     }
3994

3995
   images_in_use = eina_hash_string_superfast_new(NULL);
3996

3997
   EINA_LIST_FREE(image_lookups, image)
3998
     {
3999
        Eina_Bool find = EINA_FALSE;
4000

4001
        if (edje_file->image_dir)
4002
          {
4003
             Edje_Image_Directory_Entry *de;
4004
             unsigned int i;
4005

4006
             for (i = 0; i < edje_file->image_dir->entries_count; ++i)
4007
               {
4008
                  de = edje_file->image_dir->entries + i;
4009

4010
                  if ((de->entry) && (!strcmp(de->entry, image->name)))
4011
                    {
4012
                       if (de->source_type >= EDJE_IMAGE_SOURCE_TYPE_USER)
4013
                         *(image->dest) = -de->id - 1;
4014
                       else
4015
                         *(image->dest) = de->id;
4016
                       *(image->set) = EINA_FALSE;
4017
                       find = EINA_TRUE;
4018

4019
                       if (!eina_hash_find(images_in_use, image->name))
4020
                         eina_hash_direct_add(images_in_use, de->entry, de);
4021
                       break;
4022
                    }
4023
               }
4024

4025
             if (!find)
4026
               {
4027
                  Edje_Image_Directory_Set *set;
4028

4029
                  for (i = 0; i < edje_file->image_dir->sets_count; ++i)
4030
                    {
4031
                       set = edje_file->image_dir->sets + i;
4032

4033
                       if ((set->name) && (!strcmp(set->name, image->name)))
4034
                         {
4035
                            Edje_Image_Directory_Set_Entry *child;
4036
                            Eina_List *lc;
4037

4038
                            *(image->dest) = set->id;
4039
                            *(image->set) = EINA_TRUE;
4040
                            find = EINA_TRUE;
4041

4042
                            EINA_LIST_FOREACH(set->entries, lc, child)
4043
                              if (!eina_hash_find(images_in_use, child->name))
4044
                                eina_hash_direct_add(images_in_use, child->name, child);
4045

4046
                            if (!eina_hash_find(images_in_use, image->name))
4047
                              eina_hash_direct_add(images_in_use, set->name, set);
4048
                            break;
4049
                         }
4050
                       else
4051
                         *(image->set) = EINA_FALSE;
4052
                    }
4053
               }
4054
          }
4055

4056
        if (!find)
4057
          {
4058
             ERR("Unable to find image name \"%s\".", image->name);
4059
             exit(-1);
4060
          }
4061

4062
        free(image->name);
4063
        free(image);
4064
     }
4065

4066
   if (edje_file->image_dir && !is_lua)
4067
     {
4068
        Edje_Image_Directory_Entry *de/*, *de_last, *img*/;
4069
        Edje_Image_Directory_Set *set;
4070
        Edje_Image_Directory_Set_Entry *set_e;
4071
//        Eina_List *images_unused_list = NULL;
4072
        unsigned int i;
4073

4074
        for (i = 0; i < edje_file->image_dir->entries_count; ++i)
4075
          {
4076
             de = edje_file->image_dir->entries + i;
4077

4078
             if (de->entry && eina_hash_find(images_in_use, de->entry))
4079
               continue;
4080

4081
             if (!no_warn_unused_images)
4082
               printf("Warning: Image '%s' not used\n", de->entry);
4083
//             INF("Image '%s' in resource 'edje/image/%i' will not be included as it is unused.",
4084
//                 de->entry, de->id);
4085

4086
             // so as not to write the unused images, moved last image in the
4087
             // list to unused image position and check it
4088
/*
4089
             free((void *)de->entry);
4090
             de->entry = NULL;
4091
             de_last = edje_file->image_dir->entries + edje_file->image_dir->entries_count - 1;
4092
             iui = mem_alloc(SZ(Image_Unused_Ids));
4093
             iui->old_id = de_last->id;
4094
             images_unused_list = eina_list_append(images_unused_list, iui);
4095
             iui->new_id = i;
4096
             de_last->id = i;
4097
             memcpy(de, de_last, sizeof(Edje_Image_Directory_Entry));
4098
             --i; // need to check a moved image on this index
4099
             edje_file->image_dir->entries_count--;
4100
             img = realloc(edje_file->image_dir->entries,
4101
                           sizeof (Edje_Image_Directory_Entry) * edje_file->image_dir->entries_count);
4102
             edje_file->image_dir->entries = img;
4103
 */
4104
          }
4105

4106
        for (i = 0; i < edje_file->image_dir->sets_count; ++i)
4107
          {
4108
             set = edje_file->image_dir->sets + i;
4109

4110
             if (set->name && eina_hash_find(images_in_use, set->name))
4111
               continue;
4112

4113
             if (!no_warn_unused_images)
4114
               {
4115
                  printf("Warning: Image set '%s' not used\n", set->name);
4116
                  EINA_LIST_FOREACH(set->entries, l, set_e)
4117
                    {
4118
                       printf("  Contains '%s' size %ix%i -> %ix%i\n",
4119
                              set_e->name,
4120
                              set_e->size.min.w, set_e->size.min.h,
4121
                              set_e->size.max.w, set_e->size.max.h);
4122
                    }
4123
               }
4124
/* No need to redo id's - we will warn of unused images - fix in src
4125
 * Also .. this is broken and messes up id's ... so easyer - complain
4126
 * to develoepr to clean up the theme...
4127
             INF("Set '%s' will not be included as it is unused.", set->name);
4128

4129
             free((void *)set->name);
4130
             EINA_LIST_FREE(set->entries, set_e)
4131
               {
4132
                  free((void *)set_e->name);
4133
                  free(set_e);
4134
               }
4135
             set->entries = NULL;
4136
             set_last = edje_file->image_dir->sets + edje_file->image_dir->sets_count - 1;
4137
             iui = mem_alloc(SZ(Image_Unused_Ids));
4138
             iui->old_id = set_last->id;
4139
             images_unused_list = eina_list_append(images_unused_list, iui);
4140
             iui->new_id = i;
4141
             set_last->id = i;
4142
             memcpy(set, set_last, sizeof(Edje_Image_Directory_Set));
4143
             --i;
4144
             edje_file->image_dir->sets_count--;
4145
             set_realloc = realloc(edje_file->image_dir->sets,
4146
                                   sizeof(Edje_Image_Directory_Set) * edje_file->image_dir->sets_count);
4147
             edje_file->image_dir->sets = set_realloc;
4148
 */
4149
          }
4150

4151
        /* update image id in parts */
4152
//        if (images_unused_list) _data_image_id_update(images_unused_list);
4153
//        EINA_LIST_FREE(images_unused_list, iui)
4154
//          free(iui);
4155

4156
        _data_image_sets_size_set();
4157
     }
4158

4159
   eina_hash_free(images_in_use);
4160
}
4161

4162
static void
4163
data_process_string(Edje_Part_Collection *pc, const char *prefix, char *s, void (*func)(Edje_Part_Collection *pc, char *name, char *ptr, int len))
4164
{
4165
   char *p;
4166
   char *key;
4167
   int keyl;
4168
   int quote, escape;
4169

4170
   keyl = strlen(prefix) + 2;
4171
   key = alloca(keyl + 1);
4172
   if (!key) return;
4173
   strcpy(key, prefix);
4174
   strcat(key, ":\"");
4175
   quote = 0;
4176
   escape = 0;
4177
   for (p = s; (p) && (*p); p++)
4178
     {
4179
        if (!quote)
4180
          {
4181
             if (*p == '\"')
4182
               {
4183
                  quote = 1;
4184
                  p++;
4185
               }
4186
          }
4187
        if (!quote)
4188
          {
4189
             if (!strncmp(p, key, keyl))
4190
               {
4191
                  char *ptr;
4192
                  int len;
4193
                  int inesc = 0;
4194
                  char *name;
4195

4196
                  ptr = p;
4197
                  p += keyl;
4198
                  while ((*p))
4199
                    {
4200
                       if (!inesc)
4201
                         {
4202
                            if (*p == '\\') inesc = 1;
4203
                            else if (*p == '\"')
4204
                              {
4205
                                 /* string concatenation, see below */
4206
                                 if (*(p + 1) != '\"')
4207
                                   break;
4208
                                 else
4209
                                   p++;
4210
                              }
4211
                         }
4212
                       else
4213
                         inesc = 0;
4214
                       p++;
4215
                    }
4216
                  len = p - ptr + 1;
4217
                  name = alloca(len);
4218
                  if (name)
4219
                    {
4220
                       char *pp;
4221
                       int i;
4222

4223
                       name[0] = 0;
4224
                       pp = ptr + keyl;
4225
                       inesc = 0;
4226
                       i = 0;
4227
                       while (*pp)
4228
                         {
4229
                            if (!inesc)
4230
                              {
4231
                                 if (*pp == '\\') inesc = 1;
4232
                                 else if (*pp == '\"')
4233
                                   {
4234
                                      /* concat strings like "foo""bar" to "foobar" */
4235
                                      if (*(pp + 1) == '\"')
4236
                                        pp++;
4237
                                      else
4238
                                        {
4239
                                           name[i] = 0;
4240
                                           break;
4241
                                        }
4242
                                   }
4243
                                 else
4244
                                   {
4245
                                      name[i] = *pp;
4246
                                      name[i + 1] = 0;
4247
                                      i++;
4248
                                   }
4249
                              }
4250
                            else
4251
                              inesc = 0;
4252
                            pp++;
4253
                         }
4254
                       func(pc, name, ptr, len);
4255
                    }
4256
               }
4257
          }
4258
        else
4259
          {
4260
             if (!escape)
4261
               {
4262
                  if (*p == '\"') quote = 0;
4263
                  else if (*p == '\\')
4264
                    escape = 1;
4265
               }
4266
             else if (escape)
4267
               {
4268
                  escape = 0;
4269
               }
4270
          }
4271
     }
4272
}
4273

4274
static void
4275
_data_queue_part_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
4276
{
4277
   Code_Lookup *cl;
4278

4279
   cl = mem_alloc(SZ(Code_Lookup));
4280
   cl->ptr = ptr;
4281
   cl->len = len;
4282

4283
   data_queue_part_lookup(pc, name, &(cl->val));
4284

4285
   code_lookups = eina_list_append(code_lookups, cl);
4286
}
4287

4288
static void
4289
_data_queue_program_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
4290
{
4291
   Code_Lookup *cl;
4292

4293
   cl = mem_alloc(SZ(Code_Lookup));
4294
   cl->ptr = ptr;
4295
   cl->len = len;
4296

4297
   data_queue_program_lookup(pc, name, &(cl->val));
4298

4299
   code_lookups = eina_list_append(code_lookups, cl);
4300
}
4301

4302
static void
4303
_data_queue_group_lookup(Edje_Part_Collection *pc EINA_UNUSED, char *name, char *ptr EINA_UNUSED, int len EINA_UNUSED)
4304
{
4305
   data_queue_group_lookup(name, NULL);
4306
}
4307

4308
static void
4309
_data_queue_image_pc_lookup(Edje_Part_Collection *pc EINA_UNUSED, char *name, char *ptr, int len)
4310
{
4311
   Code_Lookup *cl;
4312

4313
   cl = mem_alloc(SZ(Code_Lookup));
4314
   cl->ptr = ptr;
4315
   cl->len = len;
4316

4317
   data_queue_image_lookup(name, &(cl->val), &(cl->set));
4318

4319
   code_lookups = eina_list_append(code_lookups, cl);
4320
}
4321

4322
void
4323
data_process_scripts(void)
4324
{
4325
   Eina_List *l, *l2;
4326

4327
   for (l = codes, l2 = edje_collections; (l) && (l2); l = eina_list_next(l), l2 = eina_list_next(l2))
4328
     {
4329
        Edje_Part_Collection *pc;
4330
        Code *cd;
4331

4332
        cd = eina_list_data_get(l);
4333
        pc = eina_list_data_get(l2);
4334

4335
        if ((cd->shared) && (!cd->is_lua))
4336
          {
4337
             data_process_string(pc, "PART", cd->shared, _data_queue_part_lookup);
4338
             data_process_string(pc, "PROGRAM", cd->shared, _data_queue_program_lookup);
4339
             data_process_string(pc, "IMAGE", cd->shared, _data_queue_image_pc_lookup);
4340
             data_process_string(pc, "GROUP", cd->shared, _data_queue_group_lookup);
4341
          }
4342

4343
        if (cd->programs)
4344
          {
4345
             Code_Program *cp;
4346
             Eina_List *ll;
4347

4348
             EINA_LIST_FOREACH(cd->programs, ll, cp)
4349
               {
4350
                  if (cp->script)
4351
                    {
4352
                       data_process_string(pc, "PART", cp->script, _data_queue_part_lookup);
4353
                       data_process_string(pc, "PROGRAM", cp->script, _data_queue_program_lookup);
4354
                       data_process_string(pc, "IMAGE", cp->script, _data_queue_image_pc_lookup);
4355
                       data_process_string(pc, "GROUP", cp->script, _data_queue_group_lookup);
4356
                    }
4357
               }
4358
          }
4359
     }
4360
}
4361

4362
void
4363
data_process_script_lookups(void)
4364
{
4365
   Eina_List *l;
4366
   Code_Lookup *cl;
4367

4368
   EINA_LIST_FOREACH(code_lookups, l, cl)
4369
     {
4370
        char buf[12];
4371
        int n;
4372

4373
        /* FIXME !! Handle set in program */
4374
        n = eina_convert_itoa(cl->val, buf);
4375
        if (n > cl->len)
4376
          {
4377
             ERR("The unexpected happened. A numeric replacement string was larger than the original!");
4378
             exit(-1);
4379
          }
4380
        memset(cl->ptr, ' ', cl->len);
4381
        strncpy(cl->ptr, buf, n);
4382
     }
4383
}
4384

4385
void
4386
using_file(const char *filename, const char type)
4387
{
4388
   FILE *f;
4389

4390
   if (depfile)
4391
     {
4392
        f = fopen(depfile, "ab");
4393
        if (!f) return;
4394
        if (type != 'O')
4395
          {
4396
             fprintf(f, " \\\n  %s", filename);
4397
          }
4398
        fclose(f);
4399
     }
4400
   else if (watchfile)
4401
     {
4402
        f = fopen(watchfile, "ab");
4403
        if (!f) return;
4404
        if (annotate)
4405
          {
4406
             fprintf(f, "%c: %s\n", type, filename);
4407
          }
4408
        else
4409
          {
4410
             fputs(filename, f);
4411
             fputc('\n', f);
4412
          }
4413
        fclose(f);
4414
     }
4415
}
4416

4417
void
4418
color_tree_root_free(void)
4419
{
4420
   char *name;
4421

4422
   EINA_LIST_FREE(color_tree_root, name)
4423
     free(name);
4424
}
4425

4426
char *
4427
color_tree_token_next(char *dst, char *src, int *ln)
4428
{
4429
   Eina_Bool begin = EINA_FALSE, next = EINA_FALSE;
4430

4431
   while (!next)
4432
     {
4433
        if (*src == '\0') break;
4434

4435
        if (*src == '"')
4436
          {
4437
             if (!begin) begin = EINA_TRUE;
4438
             else next = EINA_TRUE;
4439
          }
4440
        else if ((!begin) && ((*src == '{') || (*src == '}') || (*src == ';')))
4441
          {
4442
             *dst++ = *src;
4443
             next = EINA_TRUE;
4444
          }
4445
        else if ((!begin) && (*src == '\n'))
4446
          {
4447
             (*ln)++;
4448
          }
4449
        else if (begin)
4450
          {
4451
             *dst++ = *src;
4452
          }
4453
        src++;
4454
     }
4455
   *dst = '\0';
4456
   return src;
4457
}
4458

4459
Edje_Color_Tree_Node *
4460
color_tree_parent_node_get(const char *color_class)
4461
{
4462
   Edje_Color_Tree_Node *ctn;
4463
   Eina_List *l, *ll;
4464
   char *name;
4465

4466
   EINA_LIST_FOREACH(edje_file->color_tree, l, ctn)
4467
     if (ctn->color_classes)
4468
       EINA_LIST_FOREACH(ctn->color_classes, ll, name)
4469
         if (!strcmp(name, color_class))
4470
           return ctn;
4471

4472
   return NULL;
4473
}
4474

4475
void
4476
process_color_tree(char *s, const char *f_in, int ln)
4477
{
4478
   char token[2][1024];
4479
   int id = 0;
4480
   Eina_Array *array;
4481
   Edje_Color_Tree_Node *ctn;
4482
   Eina_List *l;
4483
   char *name;
4484

4485
   if (!s) return;
4486

4487
   array = eina_array_new(4);
4488

4489
   do
4490
     {
4491
        s = color_tree_token_next(token[id], s, &ln);
4492

4493
        if (!strcmp(token[id], "{"))
4494
          {
4495
             if (!token[!id][0])
4496
               error_and_abort(NULL, "parse error %s:%i. color class is not set to newly opened node block.",
4497
                               f_in, ln - 1);
4498

4499
             ctn = mem_alloc(SZ(Edje_Color_Tree_Node));
4500
             ctn->name = strdup(token[!id]);
4501
             color_class_register(ctn->name);
4502
             ctn->color_classes = NULL;
4503

4504
             edje_file->color_tree = eina_list_append(edje_file->color_tree, ctn);
4505

4506
             eina_array_push(array, ctn);
4507
             token[id][0] = '\0';
4508
          }
4509
        else if (!strcmp(token[id], "}"))
4510
          {
4511
             eina_array_pop(array);
4512
             token[id][0] = '\0';
4513
          }
4514
        else if (!strcmp(token[id], ";"))
4515
          {
4516
             token[id][0] = '\0';
4517
          }
4518
        else if (*s != '\0')
4519
          {
4520
             if (eina_array_count(array))
4521
               {
4522
                  if (color_tree_root)
4523
                    EINA_LIST_FOREACH(color_tree_root, l, name)
4524
                      if (!strcmp(name, token[id]))
4525
                        {
4526
                           error_and_abort(NULL, "parse error %s:%i. The color class \"%s\" already belongs to the root node.",
4527
                                           f_in, ln - 1, token[id]);
4528
                        }
4529

4530
                  if ((ctn = color_tree_parent_node_get(token[id])))
4531
                    error_and_abort(NULL, "parse error %s:%i. The color class \"%s\" already belongs to the \"%s\" node.",
4532
                                    f_in, ln - 1, token[id], ctn->name);
4533

4534
                  ctn = eina_array_data_get(array, eina_array_count(array) - 1);
4535
                  ctn->color_classes = eina_list_append(ctn->color_classes, strdup(token[id]));
4536
               }
4537
             else
4538
               {
4539
                  if ((ctn = color_tree_parent_node_get(token[id])))
4540
                    error_and_abort(NULL, "parse error %s:%i. The color class \"%s\" already belongs to the \"%s\" node.",
4541
                                    f_in, ln - 1, token[id], ctn->name);
4542

4543
                  color_tree_root = eina_list_append(color_tree_root, strdup(token[id]));
4544
               }
4545
          }
4546

4547
        id = !id;
4548
     } while (*s);
4549

4550
   if (eina_array_count(array))
4551
     error_and_abort(NULL, "parse error %s:%i. check pair of parens.", f_in, ln - 1);
4552

4553
   eina_array_clean(array);
4554
   eina_array_free(array);
4555
}
4556

4557
char
4558
validate_hex_digit(char c)
4559
{
4560
   if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
4561
     return c;
4562

4563
   ERR("%s:%i. invalid character '%c' is used in color code.",
4564
       file_in, line - 1, c);
4565
   exit(-1);
4566
}
4567

4568
void
4569
convert_color_code(char *str, int *r, int *g, int *b, int *a)
4570
{
4571
   char buf[3];
4572
   int len;
4573

4574
   len = strlen(str);
4575

4576
   if ((str[0] != '#') || (len != 4 && len != 5 && len != 7 && len != 9))
4577
     {
4578
        ERR("%s:%i color code should start with '#' and have 4 or 8 digit hex number. (3 or 6 digits are allowed to omit alpha value of 255)",
4579
            file_in, line - 1);
4580
        exit(-1);
4581
     }
4582

4583
   buf[2] = '\0';
4584

4585
   if (r)
4586
     {
4587
        if ((len == 4) || (len == 5))
4588
          {
4589
             buf[0] = validate_hex_digit(str[1]);
4590
             buf[1] = validate_hex_digit(str[1]);
4591
          }
4592
        else
4593
          {
4594
             buf[0] = validate_hex_digit(str[1]);
4595
             buf[1] = validate_hex_digit(str[2]);
4596
          }
4597

4598
        *r = (int)strtol(buf, NULL, 16);
4599
     }
4600
   if (g)
4601
     {
4602
        if ((len == 4) || (len == 5))
4603
          {
4604
             buf[0] = validate_hex_digit(str[2]);
4605
             buf[1] = validate_hex_digit(str[2]);
4606
          }
4607
        else
4608
          {
4609
             buf[0] = validate_hex_digit(str[3]);
4610
             buf[1] = validate_hex_digit(str[4]);
4611
          }
4612

4613
        *g = (int)strtol(buf, NULL, 16);
4614
     }
4615
   if (b)
4616
     {
4617
        if ((len == 4) || (len == 5))
4618
          {
4619
             buf[0] = validate_hex_digit(str[3]);
4620
             buf[1] = validate_hex_digit(str[3]);
4621
          }
4622
        else
4623
          {
4624
             buf[0] = validate_hex_digit(str[5]);
4625
             buf[1] = validate_hex_digit(str[6]);
4626
          }
4627

4628
        *b = (int)strtol(buf, NULL, 16);
4629
     }
4630
   if (a)
4631
     {
4632
        if ((len == 5) || (len == 9))
4633
          {
4634
             if (len == 5)
4635
               {
4636
                  buf[0] = validate_hex_digit(str[4]);
4637
                  buf[1] = validate_hex_digit(str[4]);
4638
               }
4639
             else
4640
               {
4641
                  buf[0] = validate_hex_digit(str[7]);
4642
                  buf[1] = validate_hex_digit(str[8]);
4643
               }
4644

4645
             *a = (int)strtol(buf, NULL, 16);
4646
          }
4647
        else
4648
          {
4649
             *a = 255;
4650
          }
4651
     }
4652

4653
   free(str);
4654
}
4655

4656

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

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

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

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