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 
228 static Eet_Data_Descriptor *edd_edje_file = NULL;
229 static Eet_Data_Descriptor *edd_edje_part_collection = NULL;
230 
231 static Eina_List *program_lookups = NULL;
232 static Eina_List *group_lookups = NULL;
233 static Eina_List *face_group_lookups = NULL;
234 static Eina_List *image_lookups = NULL;
235 
236 static Eina_Hash *part_dest_lookup = NULL;
237 static Eina_Hash *part_pc_dest_lookup = NULL;
238 static Eina_Hash *groups_sourced = NULL;
239 
240 static Eet_File *cur_ef;
241 static int image_num;
242 static Ecore_Evas *buffer_ee;
243 static int cur_image_entry;
244 
245 static void data_write_images(void);
246 
247 void
error_and_abort(Eet_File * ef EINA_UNUSED,const char * fmt,...)248 error_and_abort(Eet_File *ef EINA_UNUSED, const char *fmt, ...)
249 {
250    va_list ap;
251 
252    va_start(ap, fmt);
253    eina_log_vprint(_edje_cc_log_dom, EINA_LOG_LEVEL_CRITICAL,
254                    "unknown", "unknown", 0, fmt, ap);
255    va_end(ap);
256    unlink(file_out);
257    if (watchfile) unlink(watchfile);
258    exit(-1);
259 }
260 
261 static void
thread_end(Eina_Bool img)262 thread_end(Eina_Bool img)
263 {
264    if (img)
265      pending_image_threads--;
266    else
267      pending_threads--;
268    if (threads)
269      {
270         if ((pending_image_threads + pending_threads) < (int)max_open_files - 2)
271           data_write_images();
272      }
273    if (pending_threads + pending_image_threads <= 0) ecore_main_loop_quit();
274 }
275 
276 static unsigned int
_part_lookup_key_length(const void * key EINA_UNUSED)277 _part_lookup_key_length(const void *key EINA_UNUSED)
278 {
279    return sizeof (Part_Lookup_Key);
280 }
281 
282 static int
_part_lookup_key_pc_cmp(const void * key1,int key1_length EINA_UNUSED,const void * key2,int key2_length EINA_UNUSED)283 _part_lookup_key_pc_cmp(const void *key1, int key1_length EINA_UNUSED,
284                         const void *key2, int key2_length EINA_UNUSED)
285 {
286    const Part_Lookup_Key *a = key1;
287    const Part_Lookup_Key *b = key2;
288    uintptr_t delta;
289 
290    delta = a->pc - b->pc;
291    if (delta) return delta;
292 
293    if (a->stable) return a->mem.dest - b->mem.dest;
294 
295    delta = a->mem.reallocated.base - b->mem.reallocated.base;
296    if (delta) return delta;
297    return a->mem.reallocated.offset - b->mem.reallocated.offset;
298 }
299 
300 static int
_part_lookup_key_pc_hash(const void * key,int key_length EINA_UNUSED)301 _part_lookup_key_pc_hash(const void *key, int key_length EINA_UNUSED)
302 {
303    const Part_Lookup_Key *a = key;
304 
305    if (a->stable)
306      {
307 #ifdef EFL64
308         return eina_hash_int64((unsigned long long int *)&a->pc, sizeof (void *)) ^
309                eina_hash_int64((unsigned long long int *)&a->mem.dest, sizeof (void *));
310 #else
311         return eina_hash_int32((uintptr_t *)&a->pc, sizeof (void *)) ^
312                eina_hash_int32((uintptr_t *)&a->mem.dest, sizeof (void *));
313 #endif
314      }
315    else
316      {
317 #ifdef EFL64
318         return eina_hash_int64((unsigned long long int *)&a->pc, sizeof (void *)) ^
319                eina_hash_int64((unsigned long long int *)&a->mem.reallocated.base, sizeof (void *)) ^
320                eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
321 #else
322         return eina_hash_int32((uintptr_t *)&a->pc, sizeof (void *)) ^
323                eina_hash_int32((uintptr_t *)&a->mem.reallocated.base, sizeof (void *)) ^
324                eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
325 #endif
326      }
327 }
328 
329 static int
_part_lookup_key_cmp(const void * key1,int key1_length EINA_UNUSED,const void * key2,int key2_length EINA_UNUSED)330 _part_lookup_key_cmp(const void *key1, int key1_length EINA_UNUSED,
331                      const void *key2, int key2_length EINA_UNUSED)
332 {
333    const Part_Lookup_Key *a = key1;
334    const Part_Lookup_Key *b = key2;
335    uintptr_t delta;
336 
337    if (a->stable) return a->mem.dest - b->mem.dest;
338 
339    delta = a->mem.reallocated.base - b->mem.reallocated.base;
340    if (delta) return delta;
341    return a->mem.reallocated.offset - b->mem.reallocated.offset;
342 }
343 
344 static int
_part_lookup_key_hash(const void * key,int key_length EINA_UNUSED)345 _part_lookup_key_hash(const void *key, int key_length EINA_UNUSED)
346 {
347    const Part_Lookup_Key *a = key;
348 
349    if (a->stable)
350      {
351 #ifdef EFL64
352         return eina_hash_int64((unsigned long long int *)&a->mem.dest, sizeof (void *));
353 #else
354         return eina_hash_int32((uintptr_t *)&a->mem.dest, sizeof (void *));
355 #endif
356      }
357    else
358      {
359 #ifdef EFL64
360         return eina_hash_int64((unsigned long long int *)&a->mem.reallocated.base, sizeof (void *)) ^
361                eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
362 #else
363         return eina_hash_int32((uintptr_t *)&a->mem.reallocated.base, sizeof (void *)) ^
364                eina_hash_int32((unsigned int *)&a->mem.reallocated.offset, sizeof (int));
365 #endif
366      }
367 }
368 
369 static void
data_part_lookup_free(Part_Lookup * pl)370 data_part_lookup_free(Part_Lookup *pl)
371 {
372    free(pl->name);
373    free(pl);
374 }
375 
376 static void
list_free(void * list)377 list_free(void *list)
378 {
379    eina_list_free(list);
380 }
381 
382 void
data_setup(void)383 data_setup(void)
384 {
385    edd_edje_file = _edje_edd_edje_file;
386    edd_edje_part_collection = _edje_edd_edje_part_collection;
387 
388    part_dest_lookup = eina_hash_new(EINA_KEY_LENGTH(_part_lookup_key_length),
389                                     EINA_KEY_CMP(_part_lookup_key_cmp),
390                                     EINA_KEY_HASH(_part_lookup_key_hash),
391                                     EINA_FREE_CB(list_free),
392                                     8);
393    part_pc_dest_lookup = eina_hash_new(EINA_KEY_LENGTH(_part_lookup_key_length),
394                                        EINA_KEY_CMP(_part_lookup_key_pc_cmp),
395                                        EINA_KEY_HASH(_part_lookup_key_pc_hash),
396                                        EINA_FREE_CB(data_part_lookup_free),
397                                        8);
398 }
399 
400 static void
check_image_part_desc(Edje_Part_Collection * pc,Edje_Part * ep,Edje_Part_Description_Image * epd,Eet_File * ef)401 check_image_part_desc(Edje_Part_Collection *pc, Edje_Part *ep,
402                       Edje_Part_Description_Image *epd, Eet_File *ef)
403 {
404    unsigned int i;
405    Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser *)pc;
406 
407    if (pcp->inherit_only) return;
408 
409    if (epd->image.id == -1 && epd->common.visible)
410      WRN("Collection %s(%i): image attributes missing for "
411          "part \"%s\", description \"%s\" %f",
412          pc->part, pc->id, ep->name, epd->common.state.name, epd->common.state.value);
413 
414    for (i = 0; i < epd->image.tweens_count; ++i)
415      {
416         if (epd->image.tweens[i]->id == -1)
417           error_and_abort(ef, "Collection %i: tween image id missing for "
418                               "part \"%s\", description \"%s\" %f",
419                           pc->id, ep->name, epd->common.state.name, epd->common.state.value);
420      }
421 }
422 
423 static Edje_Part_Collection *
_source_group_find(const char * source)424 _source_group_find(const char *source)
425 {
426    Edje_Part_Collection *pc2;
427    Eina_List *l;
428    if (!source) return NULL;
429    EINA_LIST_FOREACH(edje_collections, l, pc2)
430      {
431         if (!strcmp(pc2->part, source))
432           return pc2;
433      }
434    return NULL;
435 }
436 
437 static Edje_Part *
_aliased_text_part_find(Edje_Part_Collection * pc,int id_source,const char * id_source_part)438 _aliased_text_part_find(Edje_Part_Collection *pc,
439                         int id_source, const char *id_source_part)
440 {
441    Edje_Part_Collection *group;
442    unsigned int i;
443 
444    if (!pc->parts[id_source]->source)
445      return NULL;
446 
447    group = _source_group_find(pc->parts[id_source]->source);
448    if (!group) return NULL;
449 
450    for (i = 0; i < group->parts_count; i++)
451      {
452         if (!strcmp(group->parts[i]->name, id_source_part))
453           return group->parts[i];
454      }
455    return NULL;
456 }
457 
458 static void
check_text_part_desc(Edje_Part_Collection * pc,Edje_Part * ep,Edje_Part_Description_Text * epd,Eet_File * ef)459 check_text_part_desc(Edje_Part_Collection *pc, Edje_Part *ep,
460                      Edje_Part_Description_Text *epd, Eet_File *ef)
461 {
462    Edje_Part *ep2;
463 
464    if (epd->text.id_source != -1)
465      {
466         if ((pc->parts[epd->text.id_source]->type == EDJE_PART_TYPE_TEXT) ||
467             (pc->parts[epd->text.id_source]->type == EDJE_PART_TYPE_TEXTBLOCK))
468           return;
469 
470         if (epd->text.id_source_part)
471           {
472              ep2 = _aliased_text_part_find(pc, epd->text.id_source, epd->text.id_source_part);
473              if (ep2 && ((ep2->type == EDJE_PART_TYPE_TEXT) ||
474                          (ep2->type == EDJE_PART_TYPE_TEXTBLOCK)))
475                return;
476           }
477 
478         error_and_abort(ef, "Collection \"%s\" Part \"%s\" Description \"%s\" [%.3f]: "
479                             "text.source point to a non TEXT part \"%s\"!",
480                         pc->part, ep->name, epd->common.state.name,
481                         epd->common.state.value, pc->parts[epd->text.id_source]->name);
482      }
483 
484    if (epd->text.id_text_source != -1)
485      {
486         if ((pc->parts[epd->text.id_text_source]->type == EDJE_PART_TYPE_TEXT) ||
487             (pc->parts[epd->text.id_text_source]->type == EDJE_PART_TYPE_TEXTBLOCK))
488           return;
489 
490         if (epd->text.id_text_source_part)
491           {
492              ep2 = _aliased_text_part_find(pc, epd->text.id_text_source, epd->text.id_text_source_part);
493              if (ep2 && ((ep2->type == EDJE_PART_TYPE_TEXT) ||
494                          (ep2->type == EDJE_PART_TYPE_TEXTBLOCK)))
495                return;
496           }
497 
498         error_and_abort(ef, "Collection \"%s\" Part \"%s\" Description \"%s\" [%.3f]: "
499                             "text.text_source point to a non TEXT part \"%s\"!",
500                         pc->part, ep->name, epd->common.state.name,
501                         epd->common.state.value, pc->parts[epd->text.id_text_source]->name);
502      }
503 }
504 
505 /* This function check loops between groups.
506    For example:
507    > part in group A. It's source is B.
508    > part in group B. It's source is C.
509    > part in group C. It's source is A <- here is error.
510    It's loop that we need to avoid! */
511 static void
check_source_links(Edje_Part_Collection * pc,Edje_Part * ep,Eet_File * ef,Eina_List * group_path)512 check_source_links(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef, Eina_List *group_path)
513 {
514    unsigned int i;
515    char *data;
516    Edje_Part_Collection *pc_source;
517    Eina_List *l;
518 
519    EINA_LIST_FOREACH(edje_collections, l, pc_source)
520      {
521         /* Find sourced group */
522         if (ep->source && pc_source->part && strcmp(ep->source, pc_source->part) == 0)
523           {
524              /* Go through every part to find parts with type GROUP */
525              for (i = 0; i < pc_source->parts_count; ++i)
526                {
527                   if ((pc_source->parts[i]->type == EDJE_PART_TYPE_GROUP) &&
528                       (pc_source->parts[i]->source))
529                     {
530                        /* Make sure that this group isn't already in the tree of parents */
531                        EINA_LIST_FOREACH(group_path, l, data)
532                          {
533                             if (data == pc_source->parts[i]->source)
534                               {
535                                  error_and_abort(ef, "Recursive loop group '%s' "
536                                                      "already included inside "
537                                                      "part '%s' of group '%s'",
538                                                  data, pc_source->parts[i]->name,
539                                                  pc->part);
540                               }
541                          }
542                        group_path = eina_list_append(group_path, ep->source);
543                        check_source_links(pc, pc_source->parts[i], ef, group_path);
544                     }
545                }
546           }
547      }
548 }
549 
550 static void
check_packed_items(Edje_Part_Collection * pc,Edje_Part * ep,Eet_File * ef)551 check_packed_items(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
552 {
553    unsigned int i;
554 
555    for (i = 0; i < ep->items_count; ++i)
556      {
557         if (ep->items[i]->type == EDJE_PART_TYPE_GROUP && !ep->items[i]->source)
558           error_and_abort(ef, "Collection %i: missing source on packed item "
559                               "of type GROUP in part \"%s\"",
560                           pc->id, ep->name);
561         if (ep->type == EDJE_PART_TYPE_TABLE && (ep->items[i]->col < 0 || ep->items[i]->row < 0))
562           error_and_abort(ef, "Collection %i: missing col/row on packed item "
563                               "for part \"%s\" of type TABLE",
564                           pc->id, ep->name);
565      }
566 }
567 
568 static void
check_nameless_state(Edje_Part_Collection * pc,Edje_Part * ep,Edje_Part_Description_Common * ed,Eet_File * ef)569 check_nameless_state(Edje_Part_Collection *pc, Edje_Part *ep, Edje_Part_Description_Common *ed, Eet_File *ef)
570 {
571    Edje_Part_Collection_Directory_Entry *de;
572 
573    if (ed->state.name) return;
574 
575    de = eina_hash_find(edje_collections_lookup, &pc->id);
576    error_and_abort(ef, "Group '%s': part \"%s\" has description with missing state",
577                    de->entry, ep->name);
578 }
579 
580 static void
check_state(Edje_Part_Collection * pc,Edje_Part * ep,Edje_Part_Description_Common * ed,Eet_File * ef)581 check_state(Edje_Part_Collection *pc, Edje_Part *ep, Edje_Part_Description_Common *ed, Eet_File *ef)
582 {
583    check_nameless_state(pc, ep, ed, ef);
584 }
585 
586 static void
_part_namespace_verify(Edje_Part_Collection * pc,Edje_Part * ep,Eet_File * ef,Eina_Bool ns_required)587 _part_namespace_verify(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef, Eina_Bool ns_required)
588 {
589    char buf[1024], *p;
590    size_t len;
591    Edje_Part_Collection_Directory_Entry *de;
592 
593    if (!namespace_verify) return;
594    /* this is from a group used as a source, either GROUP or TEXTBLOCK
595     * namespacing not required
596     */
597    if (eina_hash_find(groups_sourced, pc->part)) return;
598 
599    de = eina_hash_find(edje_collections_lookup, &pc->id);
600 
601    p = strchr(de->entry, '/');
602    if (!p) return;
603 
604    len = p - de->entry;
605    if (eina_strlcpy(buf, de->entry, len + 1) >= sizeof(buf)) return;
606 
607    p = strchr(ep->name, '.');
608    /* ignore part types without required namespacing or without '.' in name */
609    if ((!ns_required) && (!p)) return;
610 
611    if (strncmp(ep->name, buf, len))
612      error_and_abort(ef, "Part '%s' from group %s is not properly namespaced (should begin with '%s.')!", ep->name, de->entry, buf);
613 }
614 
615 static void
check_part(Edje_Part_Collection * pc,Edje_Part * ep,Eet_File * ef)616 check_part(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
617 {
618    Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser*)pc;
619    unsigned int i;
620    Eina_List *group_path = NULL;
621    /* FIXME: check image set and sort them. */
622    if (!ep->default_desc)
623      error_and_abort(ef, "Collection %i: default description missing "
624                          "for part \"%s\"", pc->id, ep->name);
625 
626    check_state(pc, ep, ep->default_desc, ef);
627    for (i = 0; i < ep->other.desc_count; ++i)
628      check_state(pc, ep, ep->other.desc[i], ef);
629 
630    if (ep->type == EDJE_PART_TYPE_IMAGE)
631      {
632         check_image_part_desc(pc, ep, (Edje_Part_Description_Image *)ep->default_desc, ef);
633 
634         for (i = 0; i < ep->other.desc_count; ++i)
635           check_image_part_desc(pc, ep, (Edje_Part_Description_Image *)ep->other.desc[i], ef);
636      }
637    else if ((ep->type == EDJE_PART_TYPE_BOX) ||
638             (ep->type == EDJE_PART_TYPE_TABLE))
639      check_packed_items(pc, ep, ef);
640    else if (ep->type == EDJE_PART_TYPE_GROUP)
641      check_source_links(pc, ep, ef, group_path);
642    else if (ep->type == EDJE_PART_TYPE_TEXT)
643      {
644         check_text_part_desc(pc, ep, (Edje_Part_Description_Text *)ep->default_desc, ef);
645 
646         for (i = 0; i < ep->other.desc_count; ++i)
647           check_text_part_desc(pc, ep, (Edje_Part_Description_Text *)ep->other.desc[i], ef);
648      }
649 
650    if (!pcp->skip_namespace_validation)
651      {
652         switch (ep->type)
653           {
654            case EDJE_PART_TYPE_BOX:
655            case EDJE_PART_TYPE_TABLE:
656            case EDJE_PART_TYPE_SWALLOW:
657              _part_namespace_verify(pc, ep, ef, 1);
658              break;
659            case EDJE_PART_TYPE_TEXT:
660            case EDJE_PART_TYPE_TEXTBLOCK:
661            case EDJE_PART_TYPE_SPACER:
662              _part_namespace_verify(pc, ep, ef, 0);
663              break;
664            default: break;
665           }
666      }
667 }
668 
669 static void
_program_signal_namespace_verify(Edje_Part_Collection * pc,Eet_File * ef,const char * sig,const char * src)670 _program_signal_namespace_verify(Edje_Part_Collection *pc, Eet_File *ef, const char *sig, const char *src)
671 {
672    char buf[1024], *p;
673    size_t len;
674    Edje_Part_Collection_Directory_Entry *de;
675 
676    if (!namespace_verify) return;
677    /* this is from a group used as a source, either GROUP or TEXTBLOCK
678     * namespacing not required
679     */
680    if (eina_hash_find(groups_sourced, pc->part)) return;
681 
682    /* ignore propagation to GROUP parts */
683    if (strchr(sig, ':')) return;
684 
685    de = eina_hash_find(edje_collections_lookup, &pc->id);
686 
687    p = strchr(de->entry, '/');
688    if (!p) return;
689    len = p - de->entry;
690    if (eina_strlcpy(buf, de->entry, len + 1) >= sizeof(buf)) return;
691 
692    if (strncmp(sig, buf, len))
693      error_and_abort(ef, "SIGNAL_EMIT (%s:%s) does not match group namespace (%s)!", sig, src, de->entry);
694 }
695 
696 static void
check_program(Edje_Part_Collection * pc,Edje_Program * ep,Eet_File * ef)697 check_program(Edje_Part_Collection *pc, Edje_Program *ep, Eet_File *ef)
698 {
699    Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser*)pc;
700    switch (ep->action)
701      {
702       case EDJE_ACTION_TYPE_STATE_SET:
703       case EDJE_ACTION_TYPE_ACTION_STOP:
704       case EDJE_ACTION_TYPE_DRAG_VAL_SET:
705       case EDJE_ACTION_TYPE_DRAG_VAL_STEP:
706       case EDJE_ACTION_TYPE_DRAG_VAL_PAGE:
707         if (!ep->targets)
708           error_and_abort(ef, "Collection %i: target missing in program "
709                               "\"%s\"", pc->id, ep->name);
710         break;
711 
712       default:
713         break;
714      }
715    Edje_Program_Target *et;
716    Eina_List *l;
717    unsigned int i = 0;
718 
719     if ((!ep->targets) && (ep->action == EDJE_ACTION_TYPE_SIGNAL_EMIT))
720       {
721          if (!pcp->skip_namespace_validation)
722            _program_signal_namespace_verify(pc, ef, ep->state, ep->state2);
723       }
724 
725    EINA_LIST_FOREACH(ep->targets, l, et)
726      {
727         Edje_Part *part;
728 
729         /*
730          * we are accessing part with an id,
731          * if actions is ACTION_STOP or ACTION_TYPE_SCRIPT, then id is NOT from the parts array.
732          * In order to not crash here, we should continue here.
733          */
734         if (ep->action == EDJE_ACTION_TYPE_ACTION_STOP || ep->action == EDJE_ACTION_TYPE_SCRIPT)
735           continue;
736 
737         if (et->id >= (int) pc->parts_count)
738           {
739              ERR("In group '%s' program '%s', target id '%d' greater than possible index '%d'.",
740                  pc->part ? pc->part : "", ep->name ? ep->name : "", et->id, (int) pc->parts_count - 1);
741              exit(-1);
742           }
743 
744         part = pc->parts[et->id];
745         /* verify existence of description in part */
746         if (ep->action == EDJE_ACTION_TYPE_STATE_SET)
747           {
748              if ((!eina_streq(ep->state, "custom")) &&
749                ((!eina_streq(ep->state, "default")) || (!EINA_DBL_EQ(ep->value, 0.0))))
750                {
751                   Edje_Part_Collection_Directory_Entry *de;
752                   Eina_Bool found = EINA_FALSE;
753                   for (i = 0; i < part->other.desc_count; i++)
754                     {
755                        Edje_Part_Description_Common *ed = part->other.desc[i];
756                        if (eina_streq(ed->state.name, ep->state) && EINA_DBL_EQ(ep->value, ed->state.value))
757                          {
758                             found = EINA_TRUE;
759                             break;
760                          }
761                     }
762                   if (!found)
763                     {
764                        de = eina_hash_find(edje_collections_lookup, &pc->id);
765                        error_and_abort(NULL, "GROUP %s - state '%s:%g' does not exist for part '%s'; set in program '%s'",
766                          de->entry, ep->state, ep->value, part->name, ep->name);
767                     }
768                }
769           }
770      }
771 }
772 
773 /* reset part counters for alias */
774 static void
_alias_clean(Edje_Part_Collection_Directory_Entry * ce)775 _alias_clean(Edje_Part_Collection_Directory_Entry *ce)
776 {
777    if (ce)
778      {
779         ce->count.RECTANGLE = 0;
780         ce->count.TEXT = 0;
781         ce->count.IMAGE = 0;
782         ce->count.SWALLOW = 0;
783         ce->count.TEXTBLOCK = 0;
784         ce->count.GROUP = 0;
785         ce->count.BOX = 0;
786         ce->count.TABLE = 0;
787         ce->count.EXTERNAL = 0;
788         ce->count.PROXY = 0;
789         ce->count.SPACER = 0;
790         ce->count.VECTOR = 0;
791         ce->count.part = 0;
792      }
793 }
794 
795 static void
data_thread_head(void * data,Ecore_Thread * thread EINA_UNUSED)796 data_thread_head(void *data, Ecore_Thread *thread EINA_UNUSED)
797 {
798    Head_Write *hw = data;
799    int bytes = 0;
800    char buf[EINA_PATH_MAX];
801 
802    if (edje_file)
803      {
804         if (edje_file->collection)
805           {
806              Edje_Part_Collection_Directory_Entry *ce;
807 
808              EINA_LIST_FREE(aliases, ce)
809                {
810                   Edje_Part_Collection_Directory_Entry *sce;
811 
812                   if (!ce->entry)
813                     {
814                        snprintf(buf, sizeof(buf),
815                                 "Collection %i: name missing.", ce->id);
816                        hw->errstr = strdup(buf);
817                        return;
818                     }
819 
820                   sce = eina_hash_find(edje_collections_lookup, &ce->id);
821                   if (sce)
822                     {
823                        memcpy(&ce->count, &sce->count, sizeof (ce->count));
824                     }
825                   else
826                     {
827                        snprintf(buf, sizeof(buf),
828                                 "Collection %s (%i) can't find an correct alias.",
829                                 ce->entry, ce->id);
830                        hw->errstr = strdup(buf);
831                        return;
832                     }
833 
834                   _alias_clean(ce);
835                   eina_hash_direct_add(edje_file->collection, ce->entry, ce);
836                }
837           }
838         bytes = eet_data_write(hw->ef, edd_edje_file, "edje/file", edje_file,
839                                compress_mode);
840         if (bytes <= 0)
841           {
842              snprintf(buf, sizeof(buf),
843                       "Unable to write \"edje_file\" entry to \"%s\"",
844                       file_out);
845              hw->errstr = strdup(buf);
846              return;
847           }
848      }
849 
850    INF("Wrote %9i bytes (%4iKb) for \"edje_file\" header",
851        bytes, (bytes + 512) / 1024);
852 }
853 
854 static void
data_thread_head_end(void * data,Ecore_Thread * thread EINA_UNUSED)855 data_thread_head_end(void *data, Ecore_Thread *thread EINA_UNUSED)
856 {
857    Head_Write *hw = data;
858 
859    if (hw->errstr)
860      {
861         error_and_abort(hw->ef, hw->errstr);
862         free(hw->errstr);
863      }
864    free(hw);
865    thread_end(0);
866 }
867 
868 static void
data_write_header(Eet_File * ef)869 data_write_header(Eet_File *ef)
870 {
871    Head_Write *hw;
872 
873    hw = calloc(1, sizeof(Head_Write));
874    hw->ef = ef;
875    pending_threads++;
876    if (threads)
877      ecore_thread_run(data_thread_head, data_thread_head_end, NULL, hw);
878    else
879      {
880         data_thread_head(hw, NULL);
881         data_thread_head_end(hw, NULL);
882      }
883 }
884 
885 static void
data_thread_fonts(void * data,Ecore_Thread * thread EINA_UNUSED)886 data_thread_fonts(void *data, Ecore_Thread *thread EINA_UNUSED)
887 {
888    Fonts_Write *fc = data;
889    Eina_List *ll;
890    Eina_File *f = NULL;
891    void *m = NULL;
892    int bytes = 0;
893    char buf[EINA_PATH_MAX];
894    char buf2[EINA_PATH_MAX + EINA_PATH_MAX + 128];
895    size_t size;
896 
897    f = eina_file_open(fc->fn->file, 0);
898    if (f)
899      {
900         using_file(fc->fn->file, 'F');
901         m = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
902      }
903    else
904      {
905         char *dat;
906 
907         EINA_LIST_FOREACH(fnt_dirs, ll, dat)
908           {
909              snprintf(buf, sizeof(buf), "%s/%s", dat, fc->fn->file);
910              f = eina_file_open(buf, 0);
911              if (f)
912                {
913                   using_file(buf, 'F');
914                   m = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
915                   if (m) break;
916                   eina_file_close(f);
917                   f = NULL;
918                }
919           }
920      }
921    if (!m)
922      {
923         if (f) eina_file_close(f);
924         snprintf(buf, sizeof(buf),
925                  "Unable to load font part \"%s\" entry to %s",
926                  fc->fn->file, file_out);
927         fc->errstr = strdup(buf);
928         return;
929      }
930 
931    snprintf(buf, sizeof(buf), "edje/fonts/%s", fc->fn->name);
932    bytes = eet_write(fc->ef, buf, m, eina_file_size_get(f), compress_mode);
933 
934    if ((bytes <= 0) || eina_file_map_faulted(f, m))
935      {
936         eina_file_map_free(f, m);
937         eina_file_close(f);
938         snprintf(buf2, sizeof(buf2),
939                  "Unable to write font part \"%s\" as \"%s\" "
940                  "part entry to %s", fc->fn->file, buf, file_out);
941         fc->errstr = strdup(buf2);
942         return;
943      }
944 
945    size = eina_file_size_get(f);
946    INF("Wrote %9i bytes (%4iKb) for \"%s\" font entry \"%s\" compress: [real: %2.1f%%]",
947        bytes, (bytes + 512) / 1024, buf, fc->fn->file,
948        100 - (100 * (double)bytes) / ((double)((size > 0) ? size : 1))
949        );
950    eina_file_map_free(f, m);
951    eina_file_close(f);
952 }
953 
954 static void
data_thread_fonts_end(void * data,Ecore_Thread * thread EINA_UNUSED)955 data_thread_fonts_end(void *data, Ecore_Thread *thread EINA_UNUSED)
956 {
957    Fonts_Write *fc = data;
958    if (fc->errstr)
959      {
960         error_and_abort(fc->ef, fc->errstr);
961         free(fc->errstr);
962      }
963    free(fc);
964    thread_end(0);
965 }
966 
967 static void
data_write_fonts(Eet_File * ef,int * font_num)968 data_write_fonts(Eet_File *ef, int *font_num)
969 {
970    Eina_Iterator *it;
971    Edje_Font *fn;
972 
973    if (!edje_file->fonts) return;
974 
975    it = eina_hash_iterator_data_new(edje_file->fonts);
976    EINA_ITERATOR_FOREACH(it, fn)
977      {
978         Fonts_Write *fc;
979 
980         fc = calloc(1, sizeof(Fonts_Write));
981         if (!fc) continue;
982         fc->ef = ef;
983         fc->fn = fn;
984         pending_threads++;
985         if (threads)
986           ecore_thread_run(data_thread_fonts, data_thread_fonts_end, NULL, fc);
987         else
988           {
989              data_thread_fonts(fc, NULL);
990              data_thread_fonts_end(fc, NULL);
991           }
992         *font_num += 1;
993      }
994    eina_iterator_free(it);
995 }
996 
997 static void
error_and_abort_image_load_error(Eet_File * ef,const char * file,int error)998 error_and_abort_image_load_error(Eet_File *ef, const char *file, int error)
999 {
1000    const char *errmsg = evas_load_error_str(error);
1001    char hint[1024] = "";
1002 
1003    if (error == EVAS_LOAD_ERROR_DOES_NOT_EXIST)
1004      {
1005         snprintf
1006           (hint, sizeof(hint),
1007           " Check if path to file \"%s\" is correct "
1008           "(both directory and file name).",
1009           file);
1010      }
1011    else if (error == EVAS_LOAD_ERROR_CORRUPT_FILE)
1012      {
1013         snprintf
1014           (hint, sizeof(hint),
1015           " Check if file \"%s\" is consistent.",
1016           file);
1017      }
1018    else if (error == EVAS_LOAD_ERROR_UNKNOWN_FORMAT)
1019      {
1020         const char *ext = strrchr(file, '.');
1021         const char **itr, *known_loaders[] = {
1022            /* list from evas_image_load.c */
1023            "png",
1024            "jpg",
1025            "jpeg",
1026            "jfif",
1027            "eet",
1028            "edj",
1029            "eap",
1030            "edb",
1031            "xpm",
1032            "tiff",
1033            "tif",
1034            "svg",
1035            "svgz",
1036            "gif",
1037            "pbm",
1038            "pgm",
1039            "ppm",
1040            "pnm",
1041            "bmp",
1042            "ico",
1043            "tga",
1044            "tgv",
1045            NULL
1046         };
1047 
1048         if (!ext)
1049           {
1050              snprintf
1051                (hint, sizeof(hint),
1052                " File \"%s\" does not have an extension, "
1053                "maybe it should?",
1054                file);
1055              goto show_err;
1056           }
1057 
1058         ext++;
1059         for (itr = known_loaders; *itr; itr++)
1060           {
1061              if (strcasecmp(ext, *itr) == 0)
1062                {
1063                   snprintf
1064                     (hint, sizeof(hint),
1065                     " Check if Evas was compiled with %s module enabled and "
1066                     "all required dependencies exist.",
1067                     ext);
1068                   goto show_err;
1069                }
1070           }
1071 
1072         snprintf(hint, sizeof(hint),
1073                  " Check if Evas supports loading files of type \"%s\" (%s) "
1074                  "and this module was compiled and all its dependencies exist.",
1075                  ext, file);
1076      }
1077 show_err:
1078    error_and_abort
1079      (ef, "Unable to load image \"%s\" used by file \"%s\": %s.%s",
1080      file, file_out, errmsg, hint);
1081 }
1082 
1083 static void
data_thread_image(void * data,Ecore_Thread * thread EINA_UNUSED)1084 data_thread_image(void *data, Ecore_Thread *thread EINA_UNUSED)
1085 {
1086    Image_Write *iw = data;
1087    char buf[PATH_MAX], buf2[EINA_PATH_MAX];
1088    unsigned int *start, *end;
1089    Eina_Bool opaque = EINA_TRUE;
1090    int bytes = 0;
1091 
1092    if ((iw->data) && (iw->w > 0) && (iw->h > 0))
1093      {
1094         Eet_Image_Encoding lossy = EET_IMAGE_LOSSLESS;
1095         int mode, qual, comp = 0;
1096 
1097         snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
1098         qual = 80;
1099         if ((iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
1100             (iw->img->source_param == 0))
1101           mode = 0;  /* RAW */
1102         else if ((iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
1103                  (iw->img->source_param == 1))
1104           mode = 1;  /* COMPRESS */
1105         else if (iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1)
1106           mode = 3;  /* LOSSY_ETC1 */
1107         else if (iw->img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
1108           mode = 4;  /* LOSSY_ETC2 */
1109         else
1110           mode = 2;  /* LOSSY */
1111         if ((mode == 0) && (no_raw))
1112           {
1113              mode = 1; /* promote compression */
1114              iw->img->source_param = 95;
1115           }
1116         if ((mode == 4) && (no_etc2)) mode = 2;  /* demote etc2 to jpeg */
1117         if ((mode == 3) && (no_etc1)) mode = 2;  /* demote etc1 to jpeg */
1118         if ((mode == 2) && (no_lossy)) mode = 1;  /* demote compression */
1119         if ((mode == 1) && (no_comp))
1120           {
1121              if (no_lossy) mode = 0;  /* demote compression */
1122              else if (no_raw)
1123                {
1124                   iw->img->source_param = 90;
1125                   mode = 2; /* no choice. lossy */
1126                }
1127           }
1128         if (mode == 2)
1129           {
1130              qual = iw->img->source_param;
1131              if (qual < min_quality) qual = min_quality;
1132              if (qual > max_quality) qual = max_quality;
1133              lossy = EET_IMAGE_JPEG;
1134           }
1135         if (iw->alpha)
1136           {
1137              start = (unsigned int *)iw->data;
1138              end = start + (iw->w * iw->h);
1139              while (start < end)
1140                {
1141                   if ((*start & 0xff000000) != 0xff000000)
1142                     {
1143                        opaque = EINA_FALSE;
1144                        break;
1145                     }
1146                   start++;
1147                }
1148              if (opaque) iw->alpha = 0;
1149           }
1150         if (mode == 3)
1151           {
1152              qual = iw->img->source_param;
1153              if (qual < min_quality) qual = min_quality;
1154              if (qual > max_quality) qual = max_quality;
1155              // Enable TGV with LZ4. A bit redundant with EET compression.
1156              comp = !no_comp;
1157              lossy = opaque ? EET_IMAGE_ETC1 : EET_IMAGE_ETC1_ALPHA;
1158           }
1159         if (mode == 4)
1160           {
1161              qual = iw->img->source_param;
1162              if (qual < min_quality) qual = min_quality;
1163              if (qual > max_quality) qual = max_quality;
1164              lossy = opaque ? EET_IMAGE_ETC2_RGB : EET_IMAGE_ETC2_RGBA;
1165           }
1166         if (mode == 0)
1167           bytes = eet_data_image_write(iw->ef, buf,
1168                                        iw->data, iw->w, iw->h,
1169                                        iw->alpha,
1170                                        0, 0, 0);
1171         else if (mode == 1)
1172           bytes = eet_data_image_write(iw->ef, buf,
1173                                        iw->data, iw->w, iw->h,
1174                                        iw->alpha,
1175                                        compress_mode,
1176                                        0, 0);
1177         else if (mode >= 2)
1178           bytes = eet_data_image_write(iw->ef, buf,
1179                                        iw->data, iw->w, iw->h,
1180                                        iw->alpha,
1181                                        comp, qual, lossy);
1182         if (bytes <= 0)
1183           {
1184              snprintf(buf2, sizeof(buf2),
1185                       "Unable to write image part "
1186                       "\"%s\" as \"%s\" part entry to "
1187                       "%s", iw->img->entry, buf, file_out);
1188              iw->errstr = strdup(buf2);
1189              return;
1190           }
1191      }
1192    else
1193      {
1194         snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
1195         snprintf(buf2, sizeof(buf2),
1196                  "Unable to load image part "
1197                  "\"%s\" as \"%s\" part entry to "
1198                  "%s", iw->img->entry, buf, file_out);
1199         iw->errstr = strdup(buf2);
1200         return;
1201      }
1202 
1203    if (eina_log_domain_level_check(_edje_cc_log_dom, EINA_LOG_LEVEL_INFO))
1204      {
1205         struct stat st;
1206 
1207         if (!iw->path || (stat(iw->path, &st))) st.st_size = 0;
1208         if (st.st_size > 0)
1209           {
1210              INF("Wrote %9i bytes (%4iKb) for \"%s\" image entry \"%s\" compress: [raw: %2.1f%%] [real: %2.1f%%]",
1211                  bytes, (bytes + 512) / 1024, buf, iw->img->entry,
1212                  100 - (100 * (double)bytes) / ((double)(iw->w * iw->h * 4)),
1213                  100 - (100 * (double)bytes) / ((double)(st.st_size))
1214                  );
1215           }
1216      }
1217 }
1218 
1219 static void
data_thread_image_end(void * data,Ecore_Thread * thread EINA_UNUSED)1220 data_thread_image_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1221 {
1222    Image_Write *iw = data;
1223 
1224    if (iw->errstr)
1225      {
1226         error_and_abort(iw->ef, iw->errstr);
1227         free(iw->errstr);
1228      }
1229    free(iw->path);
1230    evas_object_del(iw->im);
1231    free(iw);
1232    thread_end(1);
1233 }
1234 
1235 static void
data_image_preload_done(void * data,Evas * e EINA_UNUSED,Evas_Object * o,void * event_info EINA_UNUSED)1236 data_image_preload_done(void *data, Evas *e EINA_UNUSED, Evas_Object *o, void *event_info EINA_UNUSED)
1237 {
1238    Image_Write *iw = data;
1239 
1240    evas_object_image_size_get(o, &iw->w, &iw->h);
1241    iw->alpha = evas_object_image_alpha_get(o);
1242    iw->data = evas_object_image_data_get(o, 0);
1243    if (threads)
1244      ecore_thread_run(data_thread_image, data_thread_image_end, NULL, iw);
1245    else
1246      {
1247         data_thread_image(iw, NULL);
1248         data_thread_image_end(iw, NULL);
1249      }
1250 }
1251 
1252 static void
tgv_file_thread(void * data,Ecore_Thread * thread EINA_UNUSED)1253 tgv_file_thread(void *data, Ecore_Thread *thread EINA_UNUSED)
1254 {
1255    Image_Write *iw = data;
1256    char buf[256];
1257    size_t len;
1258 
1259    snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
1260 
1261    len = eina_file_size_get(iw->f);
1262    eet_write_cipher(iw->ef, buf, iw->data, len, EINA_FALSE /*!no_comp*/, NULL);
1263 }
1264 
1265 static void
tgv_file_thread_end(void * data,Ecore_Thread * thread EINA_UNUSED)1266 tgv_file_thread_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1267 {
1268    Image_Write *iw = data;
1269 
1270    if (iw->errstr)
1271      {
1272         error_and_abort(iw->ef, iw->errstr);
1273         free(iw->errstr);
1274      }
1275    free(iw->path);
1276    emile_image_close(iw->emi);
1277    eina_file_map_free(iw->f, iw->data);
1278    eina_file_close(iw->f);
1279    free(iw);
1280    thread_end(1);
1281 }
1282 
1283 static Eina_Bool
tgv_file_check_and_add(Eet_File * ef,Edje_Image_Directory_Entry * img)1284 tgv_file_check_and_add(Eet_File *ef, Edje_Image_Directory_Entry *img)
1285 {
1286    Emile_Image_Load_Error err;
1287    Emile_Image *emi = NULL;
1288    Image_Write *iw = NULL;
1289    Eina_List *li;
1290    const char *s;
1291    Eina_File *f = NULL;
1292    void *data;
1293 
1294    EINA_LIST_FOREACH(img_dirs, li, s)
1295      {
1296         char buf[PATH_MAX];
1297         snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
1298         f = eina_file_open(buf, EINA_FALSE);
1299         if (f) break;
1300      }
1301    if (!f) return EINA_FALSE;
1302 
1303    data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
1304    if (!data) goto on_error;
1305 
1306    using_file(img->entry, 'I');
1307 
1308    emi = emile_image_tgv_file_open(f, NULL, NULL, &err);
1309    if (!emi || (err != EMILE_IMAGE_LOAD_ERROR_NONE)) goto on_error;
1310 
1311    iw = calloc(1, sizeof(*iw));
1312 
1313    if (!emile_image_head(emi, &iw->prop, sizeof(iw->prop), &err) ||
1314        (err != EMILE_IMAGE_LOAD_ERROR_NONE))
1315      goto on_error;
1316 
1317    if (!iw->prop.cspaces || !iw->prop.w || !iw->prop.h)
1318      goto on_error;
1319 
1320    iw->f = f;
1321    iw->ef = ef;
1322    iw->img = img;
1323    iw->emi = emi;
1324    iw->data = (unsigned int *)data;
1325    iw->w = iw->prop.w;
1326    iw->h = iw->prop.h;
1327 
1328    iw->prop.cspace = iw->prop.cspaces[0];
1329    if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1)
1330      {
1331         if (no_etc1) goto on_error;
1332         if (iw->prop.cspace == EMILE_COLORSPACE_ETC1)
1333           iw->alpha = 0;
1334         else if (iw->prop.cspace == EMILE_COLORSPACE_ETC1_ALPHA)
1335           iw->alpha = 1;
1336         else
1337           goto on_error;
1338      }
1339    else if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
1340      {
1341         if (no_etc2) goto on_error;
1342         if (iw->prop.cspace == EMILE_COLORSPACE_RGB8_ETC2)
1343           iw->alpha = 0;
1344         else if (iw->prop.cspace == EMILE_COLORSPACE_RGBA8_ETC2_EAC)
1345           iw->alpha = 1;
1346         else
1347           goto on_error;
1348      }
1349 
1350    image_num += 1;
1351    iw->path = strdup(img->entry);
1352 
1353    pending_image_threads++;
1354    if (threads)
1355      ecore_thread_run(tgv_file_thread, tgv_file_thread_end, NULL, iw);
1356    else
1357      {
1358         tgv_file_thread(iw, NULL);
1359         tgv_file_thread_end(iw, NULL);
1360      }
1361 
1362    return EINA_TRUE;
1363 
1364 on_error:
1365    free(iw);
1366    emile_image_close(emi);
1367    if (data) eina_file_map_free(f, data);
1368    eina_file_close(f);
1369    return EINA_FALSE;
1370 }
1371 
1372 static void
data_write_vectors(Eet_File * ef,int * vector_num)1373 data_write_vectors(Eet_File *ef, int *vector_num)
1374 {
1375    unsigned int i;
1376    Eina_List *ll;
1377    char *s;
1378    Eina_File *f = NULL;
1379    Edje_Vector_Directory_Entry *vector;
1380    Eina_Strbuf *buf;
1381    Eina_Bool found = EINA_FALSE;
1382    Evas *evas;
1383    Evas_Object *vg;
1384 
1385    if (!((edje_file) && (edje_file->image_dir))) return;
1386 
1387    if (!buffer_ee)
1388      buffer_ee = ecore_evas_buffer_new(1, 1);
1389    if (!buffer_ee)
1390      error_and_abort(ef, "Cannot create buffer engine canvas for image load.");
1391    evas = ecore_evas_get(buffer_ee);
1392    vg = evas_object_vg_add(evas);
1393    buf = eina_strbuf_new();
1394    for (i = 0; i < edje_file->image_dir->vectors_count; i++)
1395      {
1396         vector = &edje_file->image_dir->vectors[i];
1397         EINA_LIST_FOREACH(img_dirs, ll, s)
1398           {
1399              eina_strbuf_reset(buf);
1400              eina_strbuf_append_printf(buf, "%s" EINA_PATH_SEP_S "%s", s, vector->entry);
1401              f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
1402              if (!f) continue;
1403              eina_file_close(f);
1404 
1405              if (vector->type == EDJE_VECTOR_FILE_TYPE_LOTTIE)
1406                {
1407                   char *lottie_data = NULL;
1408                   int lottie_data_len = 0;
1409 
1410                   f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
1411                   if (!f) continue;
1412 
1413                   lottie_data_len = (int) eina_file_size_get(f);
1414                   lottie_data = eina_file_map_all(f, EINA_FILE_POPULATE);
1415 
1416                   eina_strbuf_reset(buf);
1417                   eina_strbuf_append_printf(buf, "edje/vectors/%i", vector->id);
1418                   eet_write(ef, eina_strbuf_string_get(buf), lottie_data, lottie_data_len, EET_COMPRESSION_NONE);
1419 
1420                   eina_file_map_free(f, lottie_data);
1421                   eina_file_close(f);
1422 
1423                   *vector_num += 1;
1424                   found = EINA_TRUE;
1425                   break;
1426                }
1427              else
1428                {
1429                   f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
1430                   if (!f) continue;
1431                   eina_file_close(f);
1432 
1433                   if (efl_file_set(vg, eina_strbuf_string_get(buf)))
1434                     error_and_abort(ef, "Failed to parse svg : %s", vector->entry);
1435                   if (efl_file_load(vg))
1436                     error_and_abort(ef, "Failed to parse svg : %s", vector->entry);
1437 
1438                   eina_strbuf_reset(buf);
1439                   eina_strbuf_append_printf(buf, "edje/vectors/%i", vector->id);
1440                   if (!efl_file_save(vg, eet_file_get(ef), eina_strbuf_string_get(buf), NULL))
1441                     error_and_abort(ef, "Failed to write data in Eet for svg :%s", vector->entry);
1442 
1443                   *vector_num += 1;
1444                   found = EINA_TRUE;
1445                   break;
1446                }
1447           }
1448         if (!found)
1449           error_and_abort(ef, "Unable to find the svg :%s", vector->entry);
1450         found = EINA_FALSE;
1451      }
1452    eina_strbuf_free(buf);
1453 }
1454 
1455 static void
data_image_sets_init(void)1456 data_image_sets_init(void)
1457 {
1458    int i;
1459 
1460    if (!((edje_file) && (edje_file->image_dir))) return;
1461    for (i = 0; i < (int)edje_file->image_dir->sets_count; i++)
1462      {
1463         Edje_Image_Directory_Set *set;
1464         Edje_Image_Directory_Set_Entry *set_entry;
1465         Edje_Image_Directory_Entry *img;
1466         Eina_List *ll = NULL;
1467 
1468         set = edje_file->image_dir->sets + i;
1469         if (!set->entries) continue;
1470         EINA_LIST_FOREACH(set->entries, ll, set_entry)
1471           {
1472              img = &edje_file->image_dir->entries[set_entry->id];
1473              set_entry->name = img->entry;
1474           }
1475      }
1476 }
1477 
1478 static void
data_write_images(void)1479 data_write_images(void)
1480 {
1481    Evas *evas;
1482    const char *ext = NULL;
1483 
1484    if (!((edje_file) && (edje_file->image_dir))) return;
1485 
1486    if (!buffer_ee)
1487      buffer_ee = ecore_evas_buffer_new(1, 1);
1488    if (!buffer_ee)
1489      error_and_abort(cur_ef, "Cannot create buffer engine canvas for image load.");
1490    evas = ecore_evas_get(buffer_ee);
1491 
1492    for (; cur_image_entry < (int)edje_file->image_dir->entries_count; cur_image_entry++)
1493      {
1494         Edje_Image_Directory_Entry *img;
1495         Evas_Object *im;
1496         Eina_List *ll;
1497         char *s;
1498         int load_err = EVAS_LOAD_ERROR_NONE;
1499         Image_Write *iw;
1500 
1501         img = &edje_file->image_dir->entries[cur_image_entry];
1502         if ((img->source_type >= EDJE_IMAGE_SOURCE_TYPE_USER) || !img->entry)
1503           continue;
1504 
1505         if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1 ||
1506             img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
1507           {
1508              ext = strrchr(img->entry, '.');
1509              if (ext && !strcasecmp(ext, ".tgv"))
1510                {
1511                   if (tgv_file_check_and_add(cur_ef, img))
1512                     {
1513                        DBG("Directly copying data from TGV file into EDJ");
1514                        continue;
1515                     }
1516                   else
1517                     ERR("Source '%s' has incompatible ETC format.", img->entry);
1518                }
1519           }
1520 
1521         iw = calloc(1, sizeof(Image_Write));
1522         iw->ef = cur_ef;
1523         iw->img = img;
1524         iw->im = im = evas_object_image_add(evas);
1525         if (threads)
1526           evas_object_event_callback_add(im,
1527                                          EVAS_CALLBACK_IMAGE_PRELOADED,
1528                                          data_image_preload_done,
1529                                          iw);
1530         EINA_LIST_FOREACH(img_dirs, ll, s)
1531           {
1532              char buf[PATH_MAX];
1533 
1534              snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
1535              evas_object_image_file_set(im, buf, NULL);
1536              load_err = evas_object_image_load_error_get(im);
1537              if (load_err == EVAS_LOAD_ERROR_NONE)
1538                {
1539                   image_num += 1;
1540                   iw->path = strdup(buf);
1541                   pending_image_threads++;
1542                   if (threads)
1543                     evas_object_image_preload(im, 0);
1544                   using_file(buf, 'I');
1545                   if (!threads)
1546                     data_image_preload_done(iw, evas, im, NULL);
1547                   break;
1548                }
1549           }
1550         if (!img_dirs || (load_err != EVAS_LOAD_ERROR_NONE))
1551           {
1552              evas_object_image_file_set(im, img->entry, NULL);
1553              load_err = evas_object_image_load_error_get(im);
1554              if (load_err == EVAS_LOAD_ERROR_NONE)
1555                {
1556                   image_num += 1;
1557                   iw->path = strdup(img->entry);
1558                   pending_image_threads++;
1559                   if (threads)
1560                     evas_object_image_preload(im, 0);
1561                   using_file(img->entry, 'I');
1562                   if (!threads)
1563                     data_image_preload_done(iw, evas, im, NULL);
1564                }
1565              else
1566                {
1567                   free(iw);
1568                   error_and_abort_image_load_error(cur_ef, img->entry, load_err);
1569                   exit(1); // ensure static analysis tools know we exit
1570                }
1571           }
1572 
1573         if (img->source_type < EDJE_IMAGE_SOURCE_TYPE_USER)
1574           {
1575              ext = strrchr(img->entry, '.');
1576              if (ext && (!strcasecmp(ext, ".svg") || !strcasecmp(ext, ".svgz")))
1577                {
1578                   int size = strlen(img->entry) + strlen(".png") + 1;
1579                   char *tmp = malloc(size);
1580                   snprintf(tmp, size, "%s.png", img->entry);
1581                   INF("Vector '%s' used as image, convert to bitmap '%s'", img->entry, tmp);
1582                   free((void *)img->entry);
1583                   img->entry = tmp;
1584                }
1585           }
1586         if (threads)
1587           {
1588              if (pending_threads + pending_image_threads > (int)max_open_files - 2) break;
1589           }
1590      }
1591 }
1592 
1593 static void
data_thread_sounds(void * data,Ecore_Thread * thread EINA_UNUSED)1594 data_thread_sounds(void *data, Ecore_Thread *thread EINA_UNUSED)
1595 {
1596    Sound_Write *sw = data;
1597    Eina_List *ll;
1598 #ifdef HAVE_LIBSNDFILE
1599    Edje_Sound_Encode *enc_info;
1600 #endif
1601    char *dir_path = NULL;
1602    char snd_path[PATH_MAX];
1603    char sndid_str[15];
1604    Eina_File *f = NULL;
1605    void *m = NULL;
1606    int bytes = 0;
1607 
1608    // Search the Sound file in all the -sd ( sound directory )
1609    EINA_LIST_FOREACH(snd_dirs, ll, dir_path)
1610      {
1611         snprintf((char *)snd_path, sizeof(snd_path), "%s/%s", dir_path,
1612                  sw->sample->snd_src);
1613         f = eina_file_open(snd_path, 0);
1614         if (f) break;
1615      }
1616    if (!f)
1617      {
1618         snprintf((char *)snd_path, sizeof(snd_path), "%s",
1619                  sw->sample->snd_src);
1620         f = eina_file_open(snd_path, 0);
1621      }
1622 #ifdef HAVE_LIBSNDFILE
1623    if (f) eina_file_close(f);
1624    enc_info = _edje_multisense_encode(snd_path, sw->sample,
1625                                       sw->sample->quality);
1626    f = eina_file_open(enc_info->file, 0);
1627    if (f) using_file(enc_info->file, 'S');
1628 #else
1629    if (f) using_file(snd_path, 'S');
1630 #endif
1631    if (!f)
1632      {
1633         ERR("Unable to load sound data of: %s", sw->sample->name);
1634         exit(-1);
1635      }
1636 
1637    snprintf(sndid_str, sizeof(sndid_str), "edje/sounds/%i", sw->sample->id);
1638    m = eina_file_map_all(f, EINA_FILE_WILLNEED);
1639    if (m)
1640      {
1641         bytes = eet_write(sw->ef, sndid_str, m, eina_file_size_get(f),
1642                           EET_COMPRESSION_NONE);
1643         if (eina_file_map_faulted(f, m))
1644           {
1645              ERR("File access error when reading '%s'",
1646                  eina_file_filename_get(f));
1647              exit(-1);
1648           }
1649         eina_file_map_free(f, m);
1650      }
1651    eina_file_close(f);
1652 
1653 #ifdef HAVE_LIBSNDFILE
1654    //If encoded temporary file, delete it.
1655    if (enc_info->encoded) unlink(enc_info->file);
1656 #endif
1657 #ifdef HAVE_LIBSNDFILE
1658    INF("Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry \"%s\"",
1659        bytes, (bytes + 512) / 1024,
1660        sndid_str, enc_info->comp_type, sw->sample->name);
1661 #else
1662    INF("Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry \"%s\"",
1663        bytes, (bytes + 512) / 1024,
1664        sndid_str, "RAW PCM", sw->sample->name);
1665 #endif
1666 
1667 #ifdef HAVE_LIBSNDFILE
1668    if ((enc_info->file) && (!enc_info->encoded))
1669      eina_stringshare_del(enc_info->file);
1670    free(enc_info);
1671    enc_info = NULL;
1672 #endif
1673 }
1674 
1675 static void
data_thread_sounds_end(void * data,Ecore_Thread * thread EINA_UNUSED)1676 data_thread_sounds_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1677 {
1678    Sound_Write *sw = data;
1679    free(sw);
1680    thread_end(0);
1681 }
1682 
1683 static void
data_write_sounds(Eet_File * ef,int * sound_num)1684 data_write_sounds(Eet_File *ef, int *sound_num)
1685 {
1686    if ((edje_file) && (edje_file->sound_dir))
1687      {
1688         int i;
1689 
1690         for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
1691           {
1692              Sound_Write *sw;
1693 
1694              sw = calloc(1, sizeof(Sound_Write));
1695              if (!sw) continue;
1696              sw->ef = ef;
1697              sw->sample = &edje_file->sound_dir->samples[i];
1698              sw->i = i;
1699              *sound_num += 1;
1700              pending_threads++;
1701              if (threads)
1702                ecore_thread_run(data_thread_sounds, data_thread_sounds_end, NULL, sw);
1703              else
1704                {
1705                   data_thread_sounds(sw, NULL);
1706                   data_thread_sounds_end(sw, NULL);
1707                }
1708           }
1709      }
1710 }
1711 
1712 static void
data_thread_mo(void * data,Ecore_Thread * thread EINA_UNUSED)1713 data_thread_mo(void *data, Ecore_Thread *thread EINA_UNUSED)
1714 {
1715    Mo_Write *mw = data;
1716    char buf[EINA_PATH_MAX];
1717    Eina_List *ll;
1718 
1719    char *dir_path = NULL;
1720    char mo_path[PATH_MAX] = {0};
1721    char moid_str[50];
1722    Eina_File *f = NULL;
1723    void *m = NULL;
1724    int bytes = 0;
1725 
1726    if (mw->mo_path)
1727      f = eina_file_open(mw->mo_path, 0);
1728    if (!f)
1729      {
1730         // Search the mo file in all the -md ( mo directory )
1731         EINA_LIST_FOREACH(mo_dirs, ll, dir_path)
1732           {
1733              snprintf((char *)mo_path, sizeof(mo_path), "%s/%s/%s", dir_path, mw->mo_entry->locale, mw->mo_entry->mo_src);
1734              f = eina_file_open(mo_path, 0);
1735              if (f) break;
1736           }
1737      }
1738    if (!f)
1739      {
1740         snprintf((char *)mo_path, sizeof(mo_path), "%s", mw->mo_entry->mo_src);
1741         f = eina_file_open(mo_path, 0);
1742      }
1743 
1744    if (f) using_file(mo_path, 'S');
1745 
1746    if (!f)
1747      {
1748         snprintf(buf, sizeof(buf), "Unable to load mo data of: %s", mo_path);
1749         ERR("%s", buf);
1750         mw->errstr = strdup(buf);
1751         exit(-1);
1752      }
1753 
1754    snprintf(moid_str, sizeof(moid_str), "edje/mo/%i/%s/LC_MESSAGES", mw->mo_entry->id, mw->mo_entry->locale);
1755    m = eina_file_map_all(f, EINA_FILE_WILLNEED);
1756    if (m)
1757      {
1758         bytes = eet_write(mw->ef, moid_str, m, eina_file_size_get(f), EET_COMPRESSION_NONE);
1759         if (eina_file_map_faulted(f, m))
1760           {
1761              snprintf(buf, sizeof(buf), "File access error when reading '%s'",
1762                       eina_file_filename_get(f));
1763              ERR("%s", buf);
1764              mw->errstr = strdup(buf);
1765              eina_file_close(f);
1766              exit(-1);
1767           }
1768         eina_file_map_free(f, m);
1769      }
1770    eina_file_close(f);
1771    if (mw->mo_path)
1772      ecore_file_remove(mo_path);
1773 
1774    INF("Wrote %9i bytes (%4iKb) for \"%s\" %s mo entry \"%s\"",
1775        bytes, (bytes + 512) / 1024, moid_str, "RAW PCM", mw->mo_entry->locale);
1776 }
1777 
1778 static void
data_thread_mo_end(void * data,Ecore_Thread * thread EINA_UNUSED)1779 data_thread_mo_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1780 {
1781    Mo_Write *mw = data;
1782    if (mw->errstr)
1783      {
1784         error_and_abort(mw->ef, mw->errstr);
1785         free(mw->errstr);
1786      }
1787    if (mw->mo_path)
1788      free(mw->mo_path);
1789    free(mw);
1790    thread_end(0);
1791 }
1792 
1793 Eina_Bool
_exe_del_cb(void * data EINA_UNUSED,int evtype EINA_UNUSED,void * evinfo)1794 _exe_del_cb(void *data EINA_UNUSED, int evtype EINA_UNUSED, void *evinfo)
1795 {
1796    Mo_Write *mw = data;
1797    Ecore_Exe_Event_Del *ev = evinfo;
1798    if (!ev->exe) return ECORE_CALLBACK_RENEW;
1799    if (ecore_exe_data_get(ev->exe) != mw) return ECORE_CALLBACK_RENEW;
1800    if (ev->exit_code != 0)
1801      {
1802         error_and_abort(mw->ef, "Creation of .mo from .po failed.");
1803         return ECORE_CALLBACK_CANCEL;
1804      }
1805    if (ecore_file_exists(mw->mo_path))
1806      {
1807         if (threads)
1808           ecore_thread_run(data_thread_mo, data_thread_mo_end, NULL, mw);
1809         else
1810           {
1811              data_thread_mo(mw, NULL);
1812              data_thread_mo_end(mw, NULL);
1813           }
1814      }
1815    else
1816      return ECORE_CALLBACK_RENEW;
1817    if (pending_threads + pending_image_threads <= 0) ecore_main_loop_quit();
1818    return ECORE_CALLBACK_CANCEL;
1819 }
1820 
1821 static void
data_write_mo(Eet_File * ef,int * mo_num)1822 data_write_mo(Eet_File *ef, int *mo_num)
1823 {
1824    if ((edje_file) && (edje_file->mo_dir))
1825      {
1826         int i;
1827         char *po_entry;
1828         char *sub_str;
1829         char buf[EINA_PATH_MAX + PATH_MAX + PATH_MAX + 128];
1830         Eina_List *ll;
1831         char *dir_path = NULL;
1832         char mo_path[PATH_MAX];
1833         char po_path[PATH_MAX];
1834 
1835         for (i = 0; i < (int)edje_file->mo_dir->mo_entries_count; i++)
1836           {
1837              Mo_Write *mw, *mw2;
1838              mw = calloc(1, sizeof(Mo_Write));
1839              if (!mw) continue;
1840              mw->ef = ef;
1841              mw->mo_entry = &edje_file->mo_dir->mo_entries[i];
1842              *mo_num += 1;
1843              pending_threads++;
1844 
1845              po_entry = strdup(mw->mo_entry->mo_src);
1846              sub_str = strstr(mw->mo_entry->mo_src, ".po");
1847 
1848              if (sub_str)
1849                {
1850                   sub_str[1] = 'm';
1851                   EINA_LIST_FOREACH(mo_dirs, ll, dir_path)
1852                     {
1853                        snprintf((char *)po_path, sizeof(po_path), "%s/%s/%s", dir_path, mw->mo_entry->locale, po_entry);
1854                        if (ecore_file_exists(po_path))
1855                          {
1856                             char *mo_dir = ecore_file_dir_get(eet_file_get(ef));
1857                             snprintf((char *)mo_path, sizeof(mo_path), "%s/%s", mo_dir, mw->mo_entry->locale);
1858                             ecore_file_mkpath(mo_path);
1859                             snprintf((char *)mo_path, sizeof(mo_path), "%s/%s/%s", mo_dir, mw->mo_entry->locale, mw->mo_entry->mo_src);
1860                             snprintf(buf, sizeof(buf), "msgfmt -o %s %s", mo_path, po_path);
1861                             mw2 = malloc(sizeof(Mo_Write));
1862                             if (mw2)
1863                               {
1864                                  memcpy(mw2, mw, sizeof(Mo_Write));
1865                                  mw2->mo_path = strdup(mo_path);
1866                                  mw2->exe = ecore_exe_run(buf, mw2);
1867                                  ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
1868                                                          _exe_del_cb, mw2);
1869                               }
1870                             free(mo_dir);
1871                          }
1872                        else
1873                          error_and_abort(mw->ef, "Non-existent .po file specified: \"%s\".", po_path);
1874                     }
1875                   free(mw);
1876                }
1877              else
1878                {
1879                   if (threads)
1880                     ecore_thread_run(data_thread_mo, data_thread_mo_end, NULL, mw);
1881                   else
1882                     {
1883                        data_thread_mo(mw, NULL);
1884                        data_thread_mo_end(mw, NULL);
1885                     }
1886                }
1887              free(po_entry);
1888           }
1889      }
1890 }
1891 
1892 static void
data_thread_vibrations(void * data,Ecore_Thread * thread EINA_UNUSED)1893 data_thread_vibrations(void *data, Ecore_Thread *thread EINA_UNUSED)
1894 {
1895    Vibration_Write *vw = data;
1896    Eina_List *ll;
1897    char *dir_path = NULL;
1898    char path[PATH_MAX];
1899    char id_str[30];
1900    Eina_File *f = NULL;
1901    void *m = NULL;
1902    int bytes = 0;
1903 
1904    EINA_LIST_FOREACH(vibration_dirs, ll, dir_path)
1905      {
1906         snprintf((char *)path, sizeof(path), "%s/%s", dir_path,
1907                  vw->sample->src);
1908         f = eina_file_open(path, 0);
1909         if (f) break;
1910      }
1911    if (!f)
1912      {
1913         snprintf((char *)path, sizeof(path), "%s",
1914                  vw->sample->src);
1915         f = eina_file_open(path, 0);
1916      }
1917    if (f) using_file(path, 'S');
1918    if (!f)
1919      {
1920         ERR("Unable to load vibration data of: %s", vw->sample->src);
1921         exit(-1);
1922      }
1923 
1924    snprintf(id_str, sizeof(id_str), "edje/vibrations/%i", vw->sample->id);
1925    m = eina_file_map_all(f, EINA_FILE_WILLNEED);
1926    if (m)
1927      {
1928         bytes = eet_write(vw->ef, id_str, m, eina_file_size_get(f),
1929                           EET_COMPRESSION_NONE);
1930         if (eina_file_map_faulted(f, m))
1931           {
1932              ERR("File access error when reading '%s'",
1933                  eina_file_filename_get(f));
1934              exit(-1);
1935           }
1936         eina_file_map_free(f, m);
1937      }
1938    eina_file_close(f);
1939 
1940    INF("Wrote %9i bytes (%4iKb) for \"%s\" %s vibration entry \"%s\"",
1941        bytes, (bytes + 512) / 1024,
1942        id_str, "RAW", vw->sample->name);
1943 }
1944 
1945 static void
data_thread_vibrations_end(void * data,Ecore_Thread * thread EINA_UNUSED)1946 data_thread_vibrations_end(void *data, Ecore_Thread *thread EINA_UNUSED)
1947 {
1948    Vibration_Write *sw = data;
1949    free(sw);
1950    thread_end(0);
1951 }
1952 
1953 static void
data_write_vibrations(Eet_File * ef,int * num)1954 data_write_vibrations(Eet_File *ef, int *num)
1955 {
1956    if ((edje_file) && (edje_file->vibration_dir))
1957      {
1958         int i;
1959 
1960         for (i = 0; i < (int)edje_file->vibration_dir->samples_count; i++)
1961           {
1962              Vibration_Write *vw;
1963 
1964              vw = calloc(1, sizeof(Vibration_Write));
1965              if (!vw) continue;
1966              vw->ef = ef;
1967              vw->sample = &edje_file->vibration_dir->samples[i];
1968              vw->i = i;
1969              *num += 1;
1970              pending_threads++;
1971              if (threads)
1972                ecore_thread_run(data_thread_vibrations, data_thread_vibrations_end, NULL, vw);
1973              else
1974                {
1975                   data_thread_vibrations(vw, NULL);
1976                   data_thread_vibrations_end(vw, NULL);
1977                }
1978           }
1979      }
1980 }
1981 
1982 static void
check_groups(Eet_File * ef)1983 check_groups(Eet_File *ef)
1984 {
1985    Edje_Part_Collection *pc;
1986    Eina_List *l;
1987 
1988    /* sanity checks for parts and programs */
1989    EINA_LIST_FOREACH(edje_collections, l, pc)
1990      {
1991         unsigned int i;
1992 
1993         for (i = 0; i < pc->parts_count; ++i)
1994           check_part(pc, pc->parts[i], ef);
1995 
1996 #define CHECK_PROGRAM(Type, Pc, It)                    \
1997   for (It = 0; It < Pc->programs.Type ## _count; ++It) \
1998     check_program(Pc, Pc->programs.Type[i], ef);       \
1999 
2000         CHECK_PROGRAM(fnmatch, pc, i);
2001         CHECK_PROGRAM(strcmp, pc, i);
2002         CHECK_PROGRAM(strncmp, pc, i);
2003         CHECK_PROGRAM(strrncmp, pc, i);
2004         CHECK_PROGRAM(nocmp, pc, i);
2005      }
2006 }
2007 
2008 static void
data_thread_group(void * data,Ecore_Thread * thread EINA_UNUSED)2009 data_thread_group(void *data, Ecore_Thread *thread EINA_UNUSED)
2010 {
2011    Group_Write *gw = data;
2012    char buf[PATH_MAX];
2013 
2014    snprintf(buf, sizeof(buf), "edje/collections/%i", gw->pc->id);
2015    eet_data_write(gw->ef, edd_edje_part_collection, buf, gw->pc,
2016                   compress_mode);
2017    return;
2018 }
2019 
2020 static void
data_thread_group_end(void * data,Ecore_Thread * thread EINA_UNUSED)2021 data_thread_group_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2022 {
2023    Group_Write *gw = data;
2024    if (gw->errstr)
2025      {
2026         error_and_abort(gw->ef, gw->errstr);
2027         free(gw->errstr);
2028      }
2029    free(gw);
2030    thread_end(0);
2031 }
2032 
2033 static void
data_write_groups(Eet_File * ef,int * collection_num)2034 data_write_groups(Eet_File *ef, int *collection_num)
2035 {
2036    Eina_List *l;
2037    Edje_Part_Collection *pc;
2038 
2039    EINA_LIST_FOREACH(edje_collections, l, pc)
2040      {
2041         Group_Write *gw;
2042 
2043         gw = calloc(1, sizeof(Group_Write));
2044         if (!gw)
2045           {
2046              error_and_abort(ef, "Cannot allocate memory for group writer");
2047              return;
2048           }
2049         gw->ef = ef;
2050         gw->pc = pc;
2051         pending_threads++;
2052         if (threads)
2053           ecore_thread_run(data_thread_group, data_thread_group_end, NULL, gw);
2054         else
2055           {
2056              data_thread_group(gw, NULL);
2057              data_thread_group_end(gw, NULL);
2058           }
2059         *collection_num += 1;
2060      }
2061 }
2062 
2063 static void
create_script_file(Eet_File * ef,const char * filename,const Code * cd,int fd)2064 create_script_file(Eet_File *ef, const char *filename, const Code *cd, int fd)
2065 {
2066    FILE *f = fdopen(fd, "wb");
2067    if (!f)
2068      error_and_abort(ef, "Unable to open temp file \"%s\" for script "
2069                          "compilation.", filename);
2070 
2071    Eina_List *ll;
2072    Code_Program *cp;
2073 
2074    fprintf(f, "#include <edje>\n");
2075    int ln = 2;
2076 
2077    if (cd->shared)
2078      {
2079         while (ln < (cd->l1 - 1))
2080           {
2081              fprintf(f, " \n");
2082              ln++;
2083           }
2084         {
2085            char *sp;
2086            int hash = 0;
2087            int newlined = 0;
2088 
2089            for (sp = cd->shared; *sp; sp++)
2090              {
2091                 if ((sp[0] == '#') && (newlined))
2092                   {
2093                      hash = 1;
2094                   }
2095                 newlined = 0;
2096                 if (sp[0] == '\n') newlined = 1;
2097                 if (!hash) fputc(sp[0], f);
2098                 else if (sp[0] == '\n')
2099                   hash = 0;
2100              }
2101            fputc('\n', f);
2102         }
2103         ln += cd->l2 - cd->l1 + 1;
2104      }
2105    EINA_LIST_FOREACH(cd->programs, ll, cp)
2106      {
2107         if (cp->script)
2108           {
2109              while (ln < (cp->l1 - 1))
2110                {
2111                   fprintf(f, " \n");
2112                   ln++;
2113                }
2114              /* FIXME: this prototype needs to be */
2115              /* formalised and set in stone */
2116              fprintf(f, "public _p%i(sig[], src[]) {", cp->id);
2117              {
2118                 char *sp;
2119                 int hash = 0;
2120                 int newlined = 0;
2121 
2122                 for (sp = cp->script; *sp; sp++)
2123                   {
2124                      if ((sp[0] == '#') && (newlined))
2125                        {
2126                           hash = 1;
2127                        }
2128                      newlined = 0;
2129                      if (sp[0] == '\n') newlined = 1;
2130                      if (!hash) fputc(sp[0], f);
2131                      else if (sp[0] == '\n')
2132                        hash = 0;
2133                   }
2134              }
2135              fprintf(f, "}\n");
2136              ln += cp->l2 - cp->l1 + 1;
2137           }
2138      }
2139 
2140    fclose(f);
2141 }
2142 
2143 static void
data_thread_script(void * data,Ecore_Thread * thread EINA_UNUSED)2144 data_thread_script(void *data, Ecore_Thread *thread EINA_UNUSED)
2145 {
2146    Script_Write *sc = data;
2147    FILE *f;
2148    int size;
2149    char buf[PATH_MAX];
2150 
2151    f = fopen(sc->tmpo, "rb");
2152    if (!f)
2153      {
2154         snprintf(buf, sizeof(buf),
2155                  "Unable to open script object \"%s\" for reading.",
2156                  sc->tmpo);
2157         sc->errstr = strdup(buf);
2158         return;
2159      }
2160 
2161    if (fseek(f, 0, SEEK_END) < 0)
2162      ERR("Error seeking");
2163    size = ftell(f);
2164    rewind(f);
2165 
2166    if (size > 0)
2167      {
2168         void *dat = malloc(size);
2169 
2170         if (dat)
2171           {
2172              if (fread(dat, size, 1, f) != 1)
2173                {
2174                   snprintf(buf, sizeof(buf),
2175                            "Unable to read all of script object \"%s\"",
2176                            sc->tmpo);
2177                   sc->errstr = strdup(buf);
2178                   free(dat);
2179                   fclose(f);
2180                   return;
2181                }
2182              snprintf(buf, sizeof(buf), "edje/scripts/embryo/compiled/%i",
2183                       sc->i);
2184              eet_write(sc->ef, buf, dat, size, compress_mode);
2185              free(dat);
2186           }
2187         else
2188           {
2189              snprintf(buf, sizeof(buf),
2190                       "Alloc failed for %lu bytes", (unsigned long)size);
2191              sc->errstr = strdup(buf);
2192              fclose(f);
2193              return;
2194           }
2195      }
2196 
2197    if (no_save)
2198      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!");
2199    else
2200      {
2201         Eina_List *ll;
2202         Code_Program *cp;
2203 
2204         if (sc->cd->original)
2205           {
2206              snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i", sc->i);
2207              eet_write(sc->ef, buf, sc->cd->original,
2208                        strlen(sc->cd->original) + 1, compress_mode);
2209           }
2210         EINA_LIST_FOREACH(sc->cd->programs, ll, cp)
2211           {
2212              if (!cp->original) continue;
2213              snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i/%i",
2214                       sc->i, cp->id);
2215              eet_write(sc->ef, buf, cp->original,
2216                        strlen(cp->original) + 1, compress_mode);
2217           }
2218      }
2219    fclose(f);
2220 
2221    unlink(sc->tmpn);
2222    unlink(sc->tmpo);
2223    eina_tmpstr_del(sc->tmpn);
2224    eina_tmpstr_del(sc->tmpo);
2225 // closed by fclose(f) in create_script_file()
2226 //   close(sc->tmpn_fd);
2227 }
2228 
2229 typedef struct
2230 {
2231    char         *exe;
2232    Script_Write *sc;
2233 } Pending_Script_Write;
2234 
2235 #define PENDING_COMMANDS_MAX 8
2236 
2237 static int pending_write_commands = 0;
2238 static Eina_List *pending_script_writes = NULL;
2239 
2240 static void data_write_script_queue(Script_Write *sc, const char *exeline);
2241 
2242 static void
data_thread_script_end(void * data,Ecore_Thread * thread EINA_UNUSED)2243 data_thread_script_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2244 {
2245    Script_Write *sc = data;
2246    if (sc->errstr)
2247      {
2248         error_and_abort(sc->ef, sc->errstr);
2249         free(sc->errstr);
2250      }
2251    free(sc);
2252    thread_end(0);
2253 }
2254 
2255 static Eina_Bool
data_scripts_exe_del_cb(void * data EINA_UNUSED,int evtype EINA_UNUSED,void * evinfo)2256 data_scripts_exe_del_cb(void *data EINA_UNUSED, int evtype EINA_UNUSED, void *evinfo)
2257 {
2258    Script_Write *sc = data;
2259    Ecore_Exe_Event_Del *ev = evinfo;
2260 
2261    if (!ev->exe) return ECORE_CALLBACK_RENEW;
2262    if (ecore_exe_data_get(ev->exe) != sc) return ECORE_CALLBACK_RENEW;
2263    pending_write_commands--;
2264    if (pending_write_commands < PENDING_COMMANDS_MAX)
2265      {
2266         if (pending_script_writes)
2267           {
2268              Pending_Script_Write *pend = pending_script_writes->data;
2269 
2270              pending_script_writes = eina_list_remove_list
2271                  (pending_script_writes, pending_script_writes);
2272              data_write_script_queue(pend->sc, pend->exe);
2273              free(pend->exe);
2274              free(pend);
2275           }
2276      }
2277    if (ev->exit_code != 0)
2278      {
2279         error_and_abort(sc->ef, "Compiling script code not clean.");
2280         return ECORE_CALLBACK_CANCEL;
2281      }
2282    if (threads)
2283      {
2284         ecore_thread_run(data_thread_script, data_thread_script_end, NULL, sc);
2285      }
2286    else
2287      {
2288         data_thread_script(sc, NULL);
2289         data_thread_script_end(sc, NULL);
2290      }
2291    if (pending_threads + pending_image_threads <= 0) ecore_main_loop_quit();
2292    return ECORE_CALLBACK_CANCEL;
2293 }
2294 
2295 static void
data_write_script_queue(Script_Write * sc,const char * exeline)2296 data_write_script_queue(Script_Write *sc, const char *exeline)
2297 {
2298    if (pending_write_commands >= PENDING_COMMANDS_MAX)
2299      {
2300         Pending_Script_Write *pend = malloc(sizeof(Pending_Script_Write));
2301         if (pend)
2302           {
2303              pend->sc = sc;
2304              pend->exe = strdup(exeline);
2305              if (!pend->exe)
2306                {
2307                   error_and_abort(sc->ef,
2308                                   "Unable to allocate mem pending string.");
2309                   free(pend);
2310                   return;
2311                }
2312              pending_script_writes = eina_list_append(pending_script_writes,
2313                                                       pend);
2314           }
2315         else
2316           error_and_abort(sc->ef,
2317                           "Unable to allocate mem for pending script.");
2318      }
2319    else
2320      {
2321         pending_threads++;
2322         sc->exe = ecore_exe_run(exeline, sc);
2323         if (!sc->exe) error_and_abort(sc->ef, "Unable to fork off embryo_cc.");
2324         ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
2325                                 data_scripts_exe_del_cb, sc);
2326         pending_write_commands++;
2327      }
2328 }
2329 
2330 static void
data_write_scripts(Eet_File * ef)2331 data_write_scripts(Eet_File *ef)
2332 {
2333    Eina_List *l;
2334    char embryo_cc_path[PATH_MAX] = "";
2335    char inc_path[PATH_MAX] = "";
2336    int i;
2337 
2338 #ifdef _WIN32
2339 # define BIN_EXT ".exe"
2340 #else
2341 # define BIN_EXT
2342 #endif
2343 #ifdef NEED_RUN_IN_TREE
2344    if (getenv("EFL_RUN_IN_TREE"))
2345      {
2346         snprintf(embryo_cc_path, sizeof(embryo_cc_path),
2347                  "%s/src/bin/embryo/embryo_cc" BIN_EXT,
2348                  PACKAGE_BUILD_DIR);
2349         snprintf(inc_path, sizeof(inc_path),
2350                  "%s/data/edje/include", PACKAGE_SRC_DIR);
2351         if (!ecore_file_exists(embryo_cc_path))
2352           embryo_cc_path[0] = '\0';
2353      }
2354 #endif
2355 
2356    if (embryo_cc_path[0] == '\0')
2357      {
2358         snprintf(embryo_cc_path, sizeof(embryo_cc_path),
2359                  "%s/embryo_cc" BIN_EXT,
2360                  eina_prefix_bin_get(pfx));
2361         snprintf(inc_path, sizeof(inc_path),
2362                  "%s/include",
2363                  eina_prefix_data_get(pfx));
2364      }
2365 #undef BIN_EXT
2366 
2367    for (i = 0, l = codes; l; l = eina_list_next(l), i++)
2368      {
2369         Code *cd = eina_list_data_get(l);
2370         Script_Write *sc;
2371         int fd;
2372         char buf[EINA_PATH_MAX + PATH_MAX + PATH_MAX + 128];
2373 
2374         if (cd->is_lua)
2375           continue;
2376         if ((!cd->shared) && (!cd->programs))
2377           continue;
2378         sc = calloc(1, sizeof(Script_Write));
2379         sc->ef = ef;
2380         sc->cd = cd;
2381         sc->i = i;
2382         sc->tmpn_fd = eina_file_mkstemp("edje_cc.sma-tmp-XXXXXX", &sc->tmpn);
2383         if (sc->tmpn_fd < 0)
2384           error_and_abort(ef, "Unable to open temp file \"%s\" for script "
2385                               "compilation.", sc->tmpn);
2386         fd = eina_file_mkstemp("edje_cc.amx-tmp-XXXXXX", &sc->tmpo);
2387         if (fd < 0)
2388           {
2389              unlink(sc->tmpn);
2390              eina_tmpstr_del(sc->tmpn);
2391              error_and_abort(ef, "Unable to open temp file \"%s\" for script "
2392                                  "compilation.", sc->tmpo);
2393           }
2394         //do not carry the fd over the time
2395         //we should not unnesseserrily carry filedescriptors over time as this could excede system limits
2396         //which have been fetched earlier
2397         close(fd);
2398         create_script_file(ef, sc->tmpn, cd, sc->tmpn_fd);
2399         snprintf(buf, sizeof(buf),
2400                  "%s -i %s -o %s %s", embryo_cc_path, inc_path,
2401                  sc->tmpo, sc->tmpn);
2402         data_write_script_queue(sc, buf);
2403      }
2404 }
2405 
2406 #ifdef LUA_BINARY
2407 static int
_edje_lua_script_writer(lua_State * L EINA_UNUSED,const void * chunk_buf,size_t chunk_size,void * _data)2408 _edje_lua_script_writer(lua_State *L EINA_UNUSED, const void *chunk_buf, size_t chunk_size, void *_data)
2409 {
2410    Script_Lua_Writer *data;
2411    void *old;
2412 
2413    data = (Script_Lua_Writer *)_data;
2414    old = data->buf;
2415    data->buf = realloc(data->buf, data->size + chunk_size);
2416    if (data->buf)
2417      {
2418         memcpy(&((data->buf)[data->size]), chunk_buf, chunk_size);
2419         data->size += chunk_size;
2420      }
2421    else
2422      {
2423         ERR("Failed to copy chunk buffer.\n");
2424         data->buf = old;
2425      }
2426 
2427    return 0;
2428 }
2429 
2430 #endif
2431 
2432 void
_edje_lua_error_and_abort(lua_State * L,int err_code,Script_Write * sc)2433 _edje_lua_error_and_abort(lua_State *L, int err_code, Script_Write *sc)
2434 {
2435    char buf[PATH_MAX];
2436    char *err_type;
2437 
2438    switch (err_code)
2439      {
2440       case LUA_ERRRUN:
2441         err_type = "runtime";
2442         break;
2443 
2444       case LUA_ERRSYNTAX:
2445         err_type = "syntax";
2446         break;
2447 
2448       case LUA_ERRMEM:
2449         err_type = "memory allocation";
2450         break;
2451 
2452       case LUA_ERRERR:
2453         err_type = "error handler";
2454         break;
2455 
2456       default:
2457         err_type = "unknown";
2458         break;
2459      }
2460    snprintf(buf, sizeof(buf),
2461             "Lua %s error: %s", err_type, lua_tostring(L, -1));
2462    sc->errstr = strdup(buf);
2463 }
2464 
2465 static void
data_thread_lua_script(void * data,Ecore_Thread * thread EINA_UNUSED)2466 data_thread_lua_script(void *data, Ecore_Thread *thread EINA_UNUSED)
2467 {
2468    Script_Write *sc = data;
2469    char buf[PATH_MAX];
2470    lua_State *L;
2471    int ln = 1;
2472    luaL_Buffer b;
2473    Script_Lua_Writer dat;
2474    Eina_List *ll;
2475    Code_Program *cp;
2476 #ifdef LUA_BINARY
2477    int err_code;
2478 #endif
2479 
2480    L = luaL_newstate();
2481    if (!L)
2482      {
2483         snprintf(buf, sizeof(buf),
2484                  "Lua error: Lua state could not be initialized");
2485         sc->errstr = strdup(buf);
2486         return;
2487      }
2488 
2489    luaL_buffinit(L, &b);
2490 
2491    dat.buf = NULL;
2492    dat.size = 0;
2493    if (sc->cd->shared)
2494      {
2495         while (ln < (sc->cd->l1 - 1))
2496           {
2497              luaL_addchar(&b, '\n');
2498              ln++;
2499           }
2500         luaL_addstring(&b, sc->cd->shared);
2501         ln += sc->cd->l2 - sc->cd->l1;
2502      }
2503 
2504    EINA_LIST_FOREACH(sc->cd->programs, ll, cp)
2505      {
2506         if (cp->script)
2507           {
2508              while (ln < (cp->l1 - 1))
2509                {
2510                   luaL_addchar(&b, '\n');
2511                   ln++;
2512                }
2513              luaL_addstring(&b, "_G[");
2514              lua_pushnumber(L, cp->id);
2515              luaL_addvalue(&b);
2516              luaL_addstring(&b, "] = function (ed, signal, source)");
2517              luaL_addstring(&b, cp->script);
2518              luaL_addstring(&b, "end\n");
2519              ln += cp->l2 - cp->l1 + 1;
2520           }
2521      }
2522    luaL_pushresult(&b);
2523 #ifdef LUA_BINARY
2524    if (err_code = luaL_loadstring(L, lua_tostring(L, -1)))
2525      {
2526         _edje_lua_error_and_abort(L, err_code, sc);
2527         return;
2528      }
2529    lua_dump(L, _edje_lua_script_writer, &dat);
2530 #else // LUA_PLAIN_TEXT
2531    dat.buf = (char *)lua_tostring(L, -1);
2532    dat.size = strlen(dat.buf);
2533 #endif
2534    //printf("lua chunk size: %d\n", dat.size);
2535 
2536    /*
2537     * TODO load and test Lua chunk
2538     */
2539 
2540    /*
2541       if (luaL_loadbuffer(L, globbuf, globbufsize, "edje_lua_script"))
2542       printf("lua load error: %s\n", lua_tostring (L, -1));
2543       if (lua_pcall(L, 0, 0, 0))
2544       printf("lua call error: %s\n", lua_tostring (L, -1));
2545     */
2546 
2547    snprintf(buf, sizeof(buf), "edje/scripts/lua/%i", sc->i);
2548    if (eet_write(sc->ef, buf, dat.buf, dat.size, compress_mode) <= 0)
2549      {
2550         snprintf(buf, sizeof(buf),
2551                  "Unable to write script %i", sc->i);
2552         sc->errstr = strdup(buf);
2553         return;
2554      }
2555 #ifdef LUA_BINARY
2556    free(dat.buf);
2557 #endif
2558    lua_close(L);
2559 }
2560 
2561 static void
data_thread_lua_script_end(void * data,Ecore_Thread * thread EINA_UNUSED)2562 data_thread_lua_script_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2563 {
2564    Script_Write *sc = data;
2565    if (sc->errstr)
2566      {
2567         error_and_abort(sc->ef, sc->errstr);
2568         free(sc->errstr);
2569      }
2570    free(sc);
2571    thread_end(0);
2572 }
2573 
2574 static void
data_write_lua_scripts(Eet_File * ef)2575 data_write_lua_scripts(Eet_File *ef)
2576 {
2577    Eina_List *l;
2578    int i;
2579 
2580    for (i = 0, l = codes; l; l = eina_list_next(l), i++)
2581      {
2582         Code *cd;
2583         Script_Write *sc;
2584 
2585         cd = (Code *)eina_list_data_get(l);
2586         if (!cd->is_lua)
2587           continue;
2588         if ((!cd->shared) && (!cd->programs))
2589           continue;
2590 
2591         sc = calloc(1, sizeof(Script_Write));
2592         sc->ef = ef;
2593         sc->cd = cd;
2594         sc->i = i;
2595         pending_threads++;
2596         if (threads)
2597           ecore_thread_run(data_thread_lua_script, data_thread_lua_script_end, NULL, sc);
2598         else
2599           {
2600              data_thread_lua_script(sc, NULL);
2601              data_thread_lua_script_end(sc, NULL);
2602           }
2603      }
2604 }
2605 
2606 static void
data_thread_source(void * data,Ecore_Thread * thread EINA_UNUSED)2607 data_thread_source(void *data, Ecore_Thread *thread EINA_UNUSED)
2608 {
2609    Eet_File *ef = data;
2610    source_append(ef);
2611 }
2612 
2613 static void
data_thread_source_end(void * data EINA_UNUSED,Ecore_Thread * thread EINA_UNUSED)2614 data_thread_source_end(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
2615 {
2616    thread_end(0);
2617 }
2618 
2619 static void
data_thread_license(void * data,Ecore_Thread * thread EINA_UNUSED)2620 data_thread_license(void *data, Ecore_Thread *thread EINA_UNUSED)
2621 {
2622    License_Write *lw = data;
2623    Eet_File *ef = lw->ef;
2624    Eina_File *f;
2625    void *m;
2626    int bytes;
2627 
2628    f = eina_file_open(lw->file, 0);
2629    if (!f) return;
2630 
2631    m = eina_file_map_all(f, EINA_FILE_WILLNEED);
2632    if (!m) goto on_error;
2633 
2634    if (lw->master)
2635      {
2636         bytes = eet_write(ef, "edje/license", m, eina_file_size_get(f), compress_mode);
2637      }
2638    else
2639      {
2640         char *s = alloca(strlen(lw->file) + 1 + 13);
2641 
2642         strcpy(s, lw->file);
2643         sprintf(s, "edje/license/%s", basename(s));
2644 
2645         bytes = eet_write(ef, s, m, eina_file_size_get(f), compress_mode);
2646      }
2647 
2648    if ((bytes <= 0) || eina_file_map_faulted(f, m))
2649      {
2650         ERR("Unable to write license part \"%s\".", lw->file);
2651      }
2652    else
2653      {
2654         double fsize = eina_file_size_get(f);
2655 
2656         if (fsize <= 0.0) fsize = 1.0;
2657         INF("Wrote %9i bytes (%4iKb) for \"%s\" license entry compress: [real: %2.1f%%]",
2658             bytes, (bytes + 512) / 1024, license,
2659             100.0 - ((100.0 * (double)bytes) / fsize));
2660      }
2661 
2662    eina_file_map_free(f, m);
2663 
2664 on_error:
2665    eina_file_close(f);
2666 }
2667 
2668 static void
data_thread_license_end(void * data,Ecore_Thread * thread EINA_UNUSED)2669 data_thread_license_end(void *data, Ecore_Thread *thread EINA_UNUSED)
2670 {
2671    free(data);
2672    thread_end(0);
2673 }
2674 
2675 static void
data_write_license(Eet_File * ef)2676 data_write_license(Eet_File *ef)
2677 {
2678    License_Write *lw;
2679    Eina_List *l;
2680    const char *file;
2681 
2682    if (!license) return;
2683 
2684    lw = calloc(1, sizeof (License_Write));
2685    if (!lw) return;
2686 
2687    lw->ef = ef;
2688    lw->file = license;
2689    lw->master = EINA_TRUE;
2690 
2691    pending_threads++;
2692    if (threads)
2693      ecore_thread_run(data_thread_license, data_thread_license_end, NULL, lw);
2694    else
2695      {
2696         data_thread_license(lw, NULL);
2697         data_thread_license_end(lw, NULL);
2698      }
2699 
2700    EINA_LIST_FOREACH(licenses, l, file)
2701      {
2702         lw = calloc(1, sizeof (License_Write));
2703         if (!lw) return;
2704 
2705         lw->ef = ef;
2706         lw->file = file;
2707         lw->master = EINA_FALSE;
2708 
2709         pending_threads++;
2710         if (threads)
2711           ecore_thread_run(data_thread_license, data_thread_license_end, NULL, lw);
2712         else
2713           {
2714              data_thread_license(lw, NULL);
2715              data_thread_license_end(lw, NULL);
2716           }
2717      }
2718 }
2719 
2720 static void
data_thread_authors(void * data,Ecore_Thread * thread EINA_UNUSED)2721 data_thread_authors(void *data, Ecore_Thread *thread EINA_UNUSED)
2722 {
2723    Eet_File *ef = data;
2724    Eina_File *f;
2725    void *m;
2726    int bytes;
2727 
2728    f = eina_file_open(authors, 0);
2729    if (!f) return;
2730 
2731    m = eina_file_map_all(f, EINA_FILE_WILLNEED);
2732    if (!m) goto on_error;
2733 
2734    bytes = eet_write(ef, "edje/authors", m, eina_file_size_get(f), compress_mode);
2735    if ((bytes <= 0) || eina_file_map_faulted(f, m))
2736      {
2737         ERR("Unable to write authors part \"%s\".", authors);
2738      }
2739    else
2740      {
2741         double fsize = eina_file_size_get(f);
2742 
2743         if (fsize <= 0.0) fsize = 1.0;
2744         INF("Wrote %9i bytes (%4iKb) for \"%s\" authors entry compress: [real: %2.1f%%]",
2745             bytes, (bytes + 512) / 1024, license,
2746             100.0 - ((100.0 * (double)bytes) / fsize));
2747      }
2748 
2749    eina_file_map_free(f, m);
2750 
2751 on_error:
2752    eina_file_close(f);
2753 }
2754 
2755 static void
data_thread_authors_end(void * data EINA_UNUSED,Ecore_Thread * thread EINA_UNUSED)2756 data_thread_authors_end(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
2757 {
2758    thread_end(0);
2759 }
2760 
2761 static void
data_thread_fontmap(void * data,Ecore_Thread * thread EINA_UNUSED)2762 data_thread_fontmap(void *data, Ecore_Thread *thread EINA_UNUSED)
2763 {
2764    Eet_File *ef = data;
2765    source_fontmap_save(ef, fonts);
2766 }
2767 
2768 static void
data_thread_fontmap_end(void * data EINA_UNUSED,Ecore_Thread * thread EINA_UNUSED)2769 data_thread_fontmap_end(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
2770 {
2771    thread_end(0);
2772 }
2773 
2774 void
data_write(void)2775 data_write(void)
2776 {
2777    Eet_File *ef;
2778    Eet_Error err;
2779    int sound_num = 0;
2780    int mo_num = 0;
2781    int vibration_num = 0;
2782    int font_num = 0;
2783    int collection_num = 0;
2784    int vector_num = 0;
2785    double t;
2786 
2787    if (!edje_file)
2788      {
2789         ERR("No data to put in \"%s\"", file_out);
2790         exit(-1);
2791      }
2792 
2793    cur_ef = ef = eet_open(file_out, EET_FILE_MODE_WRITE);
2794    if (!ef)
2795      {
2796         ERR("Unable to open \"%s\" for writing output", file_out);
2797         exit(-1);
2798      }
2799 
2800    if ((edje_file->efl_version.major <= 1) && (edje_file->efl_version.minor <= 18)
2801        && edje_file->has_textblock_min_max)
2802      {
2803         WRN("This EDC file was designed for EFL 1.18. Until 1.19, EFL used an "
2804             "invalid calculation mechanism for textblock parts, where the value "
2805             "of text min/max was not properly taken into account. You might "
2806             "want to consider adding \"efl_version: %d %d;\" in your EDC "
2807             "file (before the \"collections\" block), and then check the sizing "
2808             "for all textblock parts that specify text min/max values (the bool "
2809             "defined as description.text.{min,max}).",
2810             EFL_VERSION_MAJOR, EFL_VERSION_MINOR);
2811      }
2812 
2813    if (eina_array_count(requires))
2814      {
2815         int i = 0;
2816 
2817         edje_file->requires_count = eina_array_count(requires);
2818         edje_file->requires = mem_alloc(edje_file->requires_count * sizeof(void*));
2819         do
2820           {
2821              edje_file->requires[i] = eina_array_pop(requires);
2822              i++;
2823           } while (eina_array_count(requires));
2824         eina_array_free(requires);
2825      }
2826 
2827    check_groups(ef);
2828 
2829    ecore_thread_max_set(ecore_thread_max_get() * 2);
2830 
2831    pending_threads++;
2832    t = ecore_time_get();
2833 
2834    INF("header: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2835    data_write_groups(ef, &collection_num);
2836    INF("groups: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2837    data_write_scripts(ef);
2838    INF("scripts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2839    data_write_lua_scripts(ef);
2840    INF("lua scripts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2841 
2842    if (!no_save)
2843      {
2844         pending_threads++;
2845         if (threads)
2846           ecore_thread_run(data_thread_source, data_thread_source_end, NULL, ef);
2847         else
2848           {
2849              data_thread_source(ef, NULL);
2850              data_thread_source_end(ef, NULL);
2851           }
2852      }
2853    INF("source: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2854    pending_threads++;
2855    if (threads)
2856      ecore_thread_run(data_thread_fontmap, data_thread_fontmap_end, NULL, ef);
2857    else
2858      {
2859         data_thread_fontmap(ef, NULL);
2860         data_thread_fontmap_end(ef, NULL);
2861      }
2862    INF("fontmap: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2863    data_write_vectors(ef, &vector_num);
2864    INF("vectors: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2865    data_write_fonts(ef, &font_num);
2866    INF("fonts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2867    data_write_sounds(ef, &sound_num);
2868    INF("sounds: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2869    data_write_mo(ef, &mo_num);
2870    INF("mo: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2871    data_write_vibrations(ef, &vibration_num);
2872    INF("vibrations: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2873    data_write_license(ef);
2874    INF("license: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2875    if (authors)
2876      {
2877         pending_threads++;
2878         if (threads)
2879           ecore_thread_run(data_thread_authors, data_thread_authors_end, NULL, ef);
2880         else
2881           {
2882              data_thread_authors(ef, NULL);
2883              data_thread_authors_end(ef, NULL);
2884           }
2885      }
2886    data_write_images();
2887    data_image_sets_init();
2888    INF("images: %3.5f", ecore_time_get() - t); t = ecore_time_get();
2889    pending_threads--;
2890    if (pending_threads + pending_image_threads > 0) ecore_main_loop_begin();
2891    INF("THREADS: %3.5f", ecore_time_get() - t);
2892    data_write_header(ef);
2893    if (pending_threads + pending_image_threads > 0) ecore_main_loop_begin();
2894    INF("THREADS: %3.5f", ecore_time_get() - t);
2895 
2896    if (threads)
2897      {
2898         /* probably caught signal, exit immediately to avoid crash */
2899         if (pending_threads + pending_image_threads > 0) exit(-1);
2900      }
2901 
2902    err = eet_close(ef);
2903    if (err)
2904      {
2905         ERR("Couldn't write file: \"%s\"", file_out);
2906         exit(-1);
2907      }
2908 
2909    if (eina_log_domain_level_check(_edje_cc_log_dom, EINA_LOG_LEVEL_INFO))
2910      {
2911         printf("Summary:\n"
2912                "  Wrote %i collections\n"
2913                "  Wrote %i images\n"
2914                "  Wrote %i sounds\n"
2915                "  Wrote %i fonts\n"
2916                ,
2917                collection_num,
2918                image_num,
2919                sound_num,
2920                font_num);
2921      }
2922 }
2923 
2924 void
reorder_parts(void)2925 reorder_parts(void)
2926 {
2927    Edje_Part_Collection *pc;
2928    Edje_Part **parts;
2929    Edje_Part_Parser *ep, *ep2;
2930    Eina_List *l;
2931 
2932    /* sanity checks for parts and programs */
2933    EINA_LIST_FOREACH(edje_collections, l, pc)
2934      {
2935         unsigned int i, j, k;
2936         Eina_Bool found = EINA_FALSE;
2937 
2938         for (i = 0; i < pc->parts_count; i++)
2939           {
2940              ep = (Edje_Part_Parser *)pc->parts[i];
2941              if (ep->reorder.insert_before && ep->reorder.insert_after)
2942                error_and_abort(NULL, "In group \"%s\": Unable to use together insert_before and insert_after in part \"%s\".",
2943                                pc->part, pc->parts[i]->name);
2944 
2945              if (ep->reorder.done)
2946                {
2947                   continue;
2948                }
2949              if (ep->reorder.insert_before || ep->reorder.insert_after)
2950                {
2951                   found = EINA_FALSE;
2952                   for (j = 0; j < pc->parts_count; j++)
2953                     {
2954                        if (ep->reorder.insert_before &&
2955                            !strcmp(ep->reorder.insert_before, pc->parts[j]->name))
2956                          {
2957                             ep2 = (Edje_Part_Parser *)pc->parts[j];
2958                             if (ep2->reorder.after)
2959                               error_and_abort(NULL, "In group \"%s\": The part \"%s\" is ambiguous ordered part.",
2960                                               pc->part, pc->parts[i]->name);
2961                             if (ep2->reorder.linked_prev)
2962                               error_and_abort(NULL, "In group \"%s\": Unable to insert two or more parts in same part \"%s\".",
2963                                               pc->part, pc->parts[j]->name);
2964                             /* Need it to be able to insert an element before the first */
2965                             if (j == 0) k = 0;
2966                             else k = j - 1;
2967                             found = EINA_TRUE;
2968                             ep2->reorder.linked_prev += ep->reorder.linked_prev + 1;
2969                             ep->reorder.before = (Edje_Part_Parser *)pc->parts[j];
2970                             while (ep2->reorder.before)
2971                               {
2972                                  ep2->reorder.before->reorder.linked_prev = ep2->reorder.linked_prev + 1;
2973                                  ep2 = ep2->reorder.before;
2974                               }
2975                             break;
2976                          }
2977                        else if (ep->reorder.insert_after &&
2978                                 !strcmp(ep->reorder.insert_after, pc->parts[j]->name))
2979                          {
2980                             ep2 = (Edje_Part_Parser *)pc->parts[j];
2981                             if (ep2->reorder.before)
2982                               error_and_abort(NULL, "In group \"%s\": The part \"%s\" is ambiguous ordered part.",
2983                                               pc->part, pc->parts[i]->name);
2984                             if (ep2->reorder.linked_next)
2985                               error_and_abort(NULL, "In group \"%s\": Unable to insert two or more parts in same part \"%s\".",
2986                                               pc->part, pc->parts[j]->name);
2987                             k = j;
2988                             found = EINA_TRUE;
2989                             ep2->reorder.linked_next += ep->reorder.linked_next + 1;
2990                             ep->reorder.after = (Edje_Part_Parser *)pc->parts[j];
2991                             while (ep2->reorder.after)
2992                               {
2993                                  ep2->reorder.after->reorder.linked_next = ep2->reorder.linked_next + 1;
2994                                  ep2 = ep2->reorder.after;
2995                               }
2996                             break;
2997                          }
2998                     }
2999                   if (found)
3000                     {
3001                        unsigned int amount, linked;
3002 
3003                        if (((i > k) && ((i - ep->reorder.linked_prev) <= k))
3004                            || ((i < k) && ((i + ep->reorder.linked_next) >= k)))
3005                          error_and_abort(NULL, "In group \"%s\": The part order is wrong. It has circular dependency.", pc->part);
3006 
3007                        amount = ep->reorder.linked_prev + ep->reorder.linked_next + 1;
3008                        linked = i - ep->reorder.linked_prev;
3009                        parts = malloc(amount * sizeof(Edje_Part *));
3010                        for (j = 0; j < amount; j++)
3011                          {
3012                             parts[j] = pc->parts[linked];
3013                             linked++;
3014                          }
3015                        if (i > k)
3016                          {
3017                             for (j = i - ep->reorder.linked_prev; j > k; j--)
3018                               {
3019                                  pc->parts[j + amount - 1] = pc->parts[j - 1];
3020                                  pc->parts[j + amount - 1]->id = j + amount - 1;
3021                               }
3022                             for (j = 0; j < amount; j++)
3023                               {
3024                                  pc->parts[j + k] = parts[j];
3025                                  pc->parts[j + k]->id = j + k;
3026                               }
3027                          }
3028                        else if (i < k)
3029                          {
3030                             for (j = i + ep->reorder.linked_next + 1; j <= k; j++)
3031                               {
3032                                  pc->parts[j - amount] = pc->parts[j];
3033                                  pc->parts[j - amount]->id = j - amount;
3034                               }
3035                             for (j = 0; j < amount; j++)
3036                               {
3037                                  pc->parts[j + k - amount + 1] = parts[j];
3038                                  pc->parts[j + k - amount + 1]->id = j + k - amount + 1;
3039                               }
3040                             i -= amount;
3041                          }
3042                        ep->reorder.done = EINA_TRUE;
3043                        free(parts);
3044                     }
3045                   else
3046                     {
3047                        if (ep->reorder.insert_before)
3048                          error_and_abort(NULL, "In group \"%s\": Unable to find part \"%s\" for insert_before in part \"%s\".",
3049                                          pc->part, ep->reorder.insert_before, pc->parts[i]->name);
3050                        else
3051                          error_and_abort(NULL, "In group \"%s\": Unable to find part \"%s\" for insert_after in part \"%s\".",
3052                                          pc->part, ep->reorder.insert_after, pc->parts[i]->name);
3053                     }
3054                }
3055           }
3056      }
3057 }
3058 
3059 void
data_queue_group_lookup(const char * name,Edje_Part * part)3060 data_queue_group_lookup(const char *name, Edje_Part *part)
3061 {
3062    Group_Lookup *gl;
3063 
3064    if (!name || !name[0]) return;
3065 
3066    gl = mem_alloc(SZ(Group_Lookup));
3067    group_lookups = eina_list_append(group_lookups, gl);
3068    gl->name = mem_strdup(name);
3069    gl->part = part;
3070 }
3071 
3072 void
data_queue_face_group_lookup(const char * name)3073 data_queue_face_group_lookup(const char *name)
3074 {
3075    char *group_name;
3076 
3077    if (!name || !name[0]) return;
3078 
3079    group_name = mem_strdup(name);
3080    face_group_lookups = eina_list_append(face_group_lookups, group_name);
3081 }
3082 
3083 void
data_queue_part_lookup(Edje_Part_Collection * pc,const char * name,int * dest)3084 data_queue_part_lookup(Edje_Part_Collection *pc, const char *name, int *dest)
3085 {
3086    data_queue_part_nest_lookup(pc, name, dest, NULL);
3087 }
3088 
3089 void
data_queue_part_nest_lookup(Edje_Part_Collection * pc,const char * name,int * dest,char ** dest2)3090 data_queue_part_nest_lookup(Edje_Part_Collection *pc, const char *name, int *dest, char **dest2)
3091 {
3092    Part_Lookup_Key key;
3093    Part_Lookup *pl = NULL;
3094    Eina_List *list;
3095    key.pc = pc;
3096    key.mem.dest = dest;
3097    key.stable = EINA_TRUE;
3098 
3099    pl = eina_hash_find(part_pc_dest_lookup, &key);
3100    if (pl)
3101      {
3102         if (name[0])
3103           {
3104              free(pl->name);
3105              pl->name = mem_strdup(name);
3106           }
3107         else
3108           {
3109              list = eina_hash_find(part_dest_lookup, &pl->key);
3110              list = eina_list_remove(list, pl);
3111              eina_hash_set(part_dest_lookup, &pl->key, list);
3112              eina_hash_del(part_pc_dest_lookup, &key, pl);
3113           }
3114         return;
3115      }
3116 
3117    if (!name[0]) return;
3118 
3119    pl = mem_alloc(SZ(Part_Lookup));
3120    pl->name = mem_strdup(name);
3121    pl->key.pc = pc;
3122    pl->key.mem.dest = dest;
3123    pl->key.dest2 = dest2;
3124    pl->key.stable = EINA_TRUE;
3125 
3126    eina_hash_add(part_pc_dest_lookup, &key, pl);
3127 
3128    list = eina_hash_find(part_dest_lookup, &pl->key);
3129    list = eina_list_prepend(list, pl);
3130    eina_hash_set(part_dest_lookup, &pl->key, list);
3131 }
3132 
3133 void
data_queue_part_reallocated_lookup(Edje_Part_Collection * pc,const char * name,unsigned char ** base,int offset)3134 data_queue_part_reallocated_lookup(Edje_Part_Collection *pc, const char *name,
3135                                    unsigned char **base, int offset)
3136 {
3137    Part_Lookup_Key key;
3138    Part_Lookup *pl = NULL;
3139    Eina_List *list;
3140    key.pc = pc;
3141    key.mem.reallocated.base = base;
3142    key.mem.reallocated.offset = offset;
3143    key.stable = EINA_FALSE;
3144 
3145    pl = eina_hash_find(part_pc_dest_lookup, &key);
3146    if (pl)
3147      {
3148         if (name[0])
3149           {
3150              free(pl->name);
3151              pl->name = mem_strdup(name);
3152           }
3153         else
3154           {
3155              list = eina_hash_find(part_dest_lookup, &pl->key);
3156              list = eina_list_remove(list, pl);
3157              eina_hash_set(part_dest_lookup, &pl->key, list);
3158              eina_hash_del(part_pc_dest_lookup, &key, pl);
3159           }
3160         return;
3161      }
3162 
3163    if (!name[0]) return;
3164 
3165    pl = mem_alloc(SZ(Part_Lookup));
3166    pl->name = mem_strdup(name);
3167    pl->key.pc = pc;
3168    pl->key.mem.reallocated.base = base;
3169    pl->key.mem.reallocated.offset = offset;
3170    pl->key.stable = EINA_FALSE;
3171 
3172    eina_hash_add(part_pc_dest_lookup, &key, pl);
3173 
3174    list = eina_hash_find(part_dest_lookup, &pl->key);
3175    list = eina_list_prepend(list, pl);
3176    eina_hash_set(part_dest_lookup, &pl->key, list);
3177 }
3178 
3179 void
part_lookup_del(Edje_Part_Collection * pc,int * dest)3180 part_lookup_del(Edje_Part_Collection *pc, int *dest)
3181 {
3182    Part_Lookup_Key key;
3183    Part_Lookup *pl = NULL;
3184    Eina_List *list;
3185    key.pc = pc;
3186    key.mem.dest = dest;
3187    key.stable = EINA_TRUE;
3188 
3189    pl = eina_hash_find(part_pc_dest_lookup, &key);
3190    if (!pl) return;
3191    list = eina_hash_find(part_dest_lookup, &pl->key);
3192    if (list)
3193      eina_hash_del(part_dest_lookup, &pl->key, list);
3194    eina_hash_del(part_pc_dest_lookup, &key, pl);
3195 }
3196 
3197 void
part_lookup_delete(Edje_Part_Collection * pc,const char * name,int * dest,char ** dest2)3198 part_lookup_delete(Edje_Part_Collection *pc, const char *name, int *dest, char **dest2)
3199 {
3200    Part_Lookup_Key key;
3201    Part_Lookup *pl = NULL;
3202    Part_Lookup *lpl;
3203    Eina_List *list, *l, *ll;
3204    key.pc = pc;
3205    key.mem.dest = dest;
3206    key.stable = EINA_TRUE;
3207 
3208    pl = eina_hash_find(part_pc_dest_lookup, &key);
3209    if (!pl) return;
3210    list = eina_hash_find(part_dest_lookup, &pl->key);
3211    EINA_LIST_FOREACH_SAFE(list, l, ll, lpl)
3212      {
3213         if (strcmp(lpl->name, name) || (lpl->key.dest2 != dest2)) continue;
3214         free(lpl->name);
3215         list = eina_list_remove_list(list, l);
3216         free(lpl);
3217      }
3218    eina_hash_set(part_dest_lookup, &pl->key, list);
3219 }
3220 
3221 void
data_queue_copied_part_lookup(Edje_Part_Collection * pc,int * src,int * dest)3222 data_queue_copied_part_lookup(Edje_Part_Collection *pc, int *src, int *dest)
3223 {
3224    data_queue_copied_part_nest_lookup(pc, src, dest, NULL);
3225 }
3226 
3227 void
data_queue_copied_part_nest_lookup(Edje_Part_Collection * pc,int * src,int * dest,char ** dest2)3228 data_queue_copied_part_nest_lookup(Edje_Part_Collection *pc, int *src, int *dest, char **dest2)
3229 {
3230    Eina_List *list;
3231    Eina_List *l;
3232    Part_Lookup *pl;
3233    Part_Lookup_Key key;
3234 
3235    key.pc = NULL;
3236    key.mem.dest = src;
3237    key.stable = EINA_TRUE;
3238 
3239    list = eina_hash_find(part_dest_lookup, &key);
3240    EINA_LIST_FOREACH(list, l, pl)
3241      if (pl->key.stable)
3242        data_queue_part_nest_lookup(pc, pl->name, dest, dest2);
3243 }
3244 
3245 void
data_queue_anonymous_lookup(Edje_Part_Collection * pc,Edje_Program * ep,int * dest)3246 data_queue_anonymous_lookup(Edje_Part_Collection *pc, Edje_Program *ep, int *dest)
3247 {
3248    Eina_List *l, *l1, *l2, *l3;
3249    Program_Lookup *pl;
3250 
3251    if (!ep) return;  /* FIXME: should we stop compiling ? */
3252 
3253    EINA_LIST_FOREACH_SAFE(program_lookups, l, l1, pl)
3254      {
3255         if (pl->u.ep == ep)
3256           {
3257              Code *cd;
3258              Code_Program *cp;
3259 
3260              cd = eina_list_data_get(eina_list_last(codes));
3261 
3262              EINA_LIST_FOREACH_SAFE(cd->programs, l2, l3, cp)
3263                {
3264                   if (&(cp->id) == pl->dest)
3265                     {
3266                        cd->programs = eina_list_remove_list(cd->programs, l2);
3267                        free(cp);
3268                        cp = NULL;
3269                     }
3270                }
3271              program_lookups = eina_list_remove_list(program_lookups, l);
3272              free(pl);
3273           }
3274      }
3275 
3276    if (dest)
3277      {
3278         pl = mem_alloc(SZ(Program_Lookup));
3279         program_lookups = eina_list_append(program_lookups, pl);
3280         pl->pc = pc;
3281         pl->u.ep = ep;
3282         pl->dest = dest;
3283         pl->anonymous = EINA_TRUE;
3284      }
3285 }
3286 
3287 void
copied_program_anonymous_lookup_delete(Edje_Part_Collection * pc,int * dest)3288 copied_program_anonymous_lookup_delete(Edje_Part_Collection *pc, int *dest)
3289 {
3290    Program_Lookup *pl;
3291    Eina_List *l, *ll;
3292 
3293    EINA_LIST_FOREACH_SAFE(program_lookups, l, ll, pl)
3294      {
3295         if ((!pl->anonymous) || (pl->pc != pc) || (dest != &pl->u.ep->id)) continue;
3296         program_lookups = eina_list_remove_list(program_lookups, l);
3297 
3298         Code *cd;
3299         Code_Program *cp;
3300         Edje_Part_Collection_Directory_Entry *de;
3301         Eina_List *l2, *ll2;
3302 
3303         de = eina_hash_find(edje_file->collection, pl->pc->part);
3304         cd = eina_list_nth(codes, de->id);
3305 
3306         EINA_LIST_FOREACH_SAFE(cd->programs, l2, ll2, cp)
3307           {
3308              if (pl->dest == &cp->id)
3309                {
3310                   cd->programs = eina_list_remove_list(cd->programs, l2);
3311                   free(cp);
3312                   break;
3313                }
3314           }
3315 
3316         free(pl);
3317      }
3318 }
3319 
3320 void
data_queue_copied_anonymous_lookup(Edje_Part_Collection * pc,int * src,int * dest)3321 data_queue_copied_anonymous_lookup(Edje_Part_Collection *pc, int *src, int *dest)
3322 {
3323    Eina_List *l;
3324    Program_Lookup *pl;
3325    unsigned int i;
3326 
3327    EINA_LIST_FOREACH(program_lookups, l, pl)
3328      {
3329         if (pl->dest == src && pl->u.ep->name)
3330           {
3331              for (i = 0; i < pc->programs.fnmatch_count; i++)
3332                {
3333                   if (pc->programs.fnmatch[i]->name &&
3334                       !strcmp(pl->u.ep->name, pc->programs.fnmatch[i]->name))
3335                     data_queue_anonymous_lookup(pc, pc->programs.fnmatch[i], dest);
3336                }
3337              for (i = 0; i < pc->programs.strcmp_count; i++)
3338                {
3339                   if (pc->programs.strcmp[i]->name &&
3340                       !strcmp(pl->u.ep->name, pc->programs.strcmp[i]->name))
3341                     data_queue_anonymous_lookup(pc, pc->programs.strcmp[i], dest);
3342                }
3343              for (i = 0; i < pc->programs.strncmp_count; i++)
3344                {
3345                   if (pc->programs.strncmp[i]->name &&
3346                       !strcmp(pl->u.ep->name, pc->programs.strncmp[i]->name))
3347                     data_queue_anonymous_lookup(pc, pc->programs.strncmp[i], dest);
3348                }
3349              for (i = 0; i < pc->programs.strrncmp_count; i++)
3350                {
3351                   if (pc->programs.strrncmp[i]->name &&
3352                       !strcmp(pl->u.ep->name, pc->programs.strrncmp[i]->name))
3353                     data_queue_anonymous_lookup(pc, pc->programs.strrncmp[i], dest);
3354                }
3355              for (i = 0; i < pc->programs.nocmp_count; i++)
3356                {
3357                   if (pc->programs.nocmp[i]->name &&
3358                       !strcmp(pl->u.ep->name, pc->programs.nocmp[i]->name))
3359                     data_queue_anonymous_lookup(pc, pc->programs.nocmp[i], dest);
3360                }
3361           }
3362      }
3363 }
3364 
3365 void *
data_queue_program_lookup(Edje_Part_Collection * pc,const char * name,int * dest)3366 data_queue_program_lookup(Edje_Part_Collection *pc, const char *name, int *dest)
3367 {
3368    Program_Lookup *pl;
3369    Edje_Part_Collection_Parser *pcp = (Edje_Part_Collection_Parser *)pc;
3370 
3371    if (pcp->inherit_only && (!current_group_inherit)) return NULL;
3372 
3373    if (!name) return NULL;  /* FIXME: should we stop compiling ? */
3374 
3375    pl = mem_alloc(SZ(Program_Lookup));
3376    program_lookups = eina_list_append(program_lookups, pl);
3377    pl->pc = pc;
3378    pl->u.name = mem_strdup(name);
3379    pl->dest = dest;
3380    pl->anonymous = EINA_FALSE;
3381    return pl;
3382 }
3383 
3384 void
program_lookup_rename(void * p,const char * name)3385 program_lookup_rename(void *p, const char *name)
3386 {
3387    Program_Lookup *pl = p;
3388 
3389    free(pl->u.name);
3390    pl->u.name = strdup(name);
3391 }
3392 
3393 void
copied_program_lookup_delete(Edje_Part_Collection * pc,const char * name)3394 copied_program_lookup_delete(Edje_Part_Collection *pc, const char *name)
3395 {
3396    Program_Lookup *pl;
3397    Eina_List *l, *ll;
3398 
3399    EINA_LIST_FOREACH_SAFE(program_lookups, l, ll, pl)
3400      {
3401         if (pl->anonymous || (pl->pc != pc) || strcmp(pl->u.name, name)) continue;
3402         free(pl->u.name);
3403         program_lookups = eina_list_remove_list(program_lookups, l);
3404         free(pl);
3405      }
3406 }
3407 
3408 Eina_Bool
data_queue_copied_program_lookup(Edje_Part_Collection * pc,int * src,int * dest)3409 data_queue_copied_program_lookup(Edje_Part_Collection *pc, int *src, int *dest)
3410 {
3411    Eina_List *l;
3412    Program_Lookup *pl;
3413 
3414    EINA_LIST_FOREACH(program_lookups, l, pl)
3415      {
3416         if (pl->dest == src)
3417           {
3418              data_queue_program_lookup(pc, pl->u.name, dest);
3419              return EINA_TRUE;
3420           }
3421      }
3422    return EINA_FALSE;
3423 }
3424 
3425 void
data_queue_image_lookup(char * name,int * dest,Eina_Bool * set)3426 data_queue_image_lookup(char *name, int *dest, Eina_Bool *set)
3427 {
3428    Image_Lookup *il;
3429 
3430    il = mem_alloc(SZ(Image_Lookup));
3431    image_lookups = eina_list_append(image_lookups, il);
3432    il->name = mem_strdup(name);
3433    il->dest = dest;
3434    il->set = set;
3435 }
3436 
3437 void
data_queue_image_remove(int * dest,Eina_Bool * set)3438 data_queue_image_remove(int *dest, Eina_Bool *set)
3439 {
3440    Eina_List *l;
3441    Image_Lookup *il;
3442 
3443    EINA_LIST_FOREACH(image_lookups, l, il)
3444      {
3445         if (il->dest == dest && il->set == set)
3446           {
3447              image_lookups = eina_list_remove_list(image_lookups, l);
3448              free(il->name);
3449              free(il);
3450              return;
3451           }
3452      }
3453 }
3454 
3455 void
data_queue_copied_image_lookup(int * src,int * dest,Eina_Bool * set)3456 data_queue_copied_image_lookup(int *src, int *dest, Eina_Bool *set)
3457 {
3458    Eina_List *l;
3459    Image_Lookup *il;
3460 
3461    EINA_LIST_FOREACH(image_lookups, l, il)
3462      {
3463         if (il->dest == src)
3464           data_queue_image_lookup(il->name, dest, set);
3465      }
3466 }
3467 
3468 static Eina_Bool
data_process_part_set(Part_Lookup * target,int value)3469 data_process_part_set(Part_Lookup *target, int value)
3470 {
3471    if (target->key.stable)
3472      {
3473         *(target->key.mem.dest) = value;
3474         if (target->key.dest2) return EINA_TRUE;
3475      }
3476    else
3477      {
3478         *((int *)(*target->key.mem.reallocated.base +
3479                   target->key.mem.reallocated.offset)) = value;
3480      }
3481    return EINA_FALSE;
3482 }
3483 
3484 static int
_data_image_w_size_compare_cb(const void * data1,const void * data2)3485 _data_image_w_size_compare_cb(const void *data1, const void *data2)
3486 {
3487    const Edje_Image_Directory_Set_Entry *img1 = data1;
3488    const Edje_Image_Directory_Set_Entry *img2 = data2;
3489 
3490    if (img1->size.w < img2->size.w) return -1;
3491    if (img1->size.w > img2->size.w) return 1;
3492 
3493    return 0;
3494 }
3495 
3496 static int
_data_image_h_size_compare_cb(const void * data1,const void * data2)3497 _data_image_h_size_compare_cb(const void *data1, const void *data2)
3498 {
3499    const Edje_Image_Directory_Set_Entry *img1 = data1;
3500    const Edje_Image_Directory_Set_Entry *img2 = data2;
3501 
3502    if (img1->size.h < img2->size.h) return -1;
3503    if (img1->size.h > img2->size.h) return 1;
3504 
3505    return 0;
3506 }
3507 
3508 static void
_data_image_sets_size_set(void)3509 _data_image_sets_size_set(void)
3510 {
3511    Evas *evas;
3512    Edje_Image_Directory_Set *set;
3513    Edje_Image_Directory_Set_Entry *simg, *preimg;
3514    Eina_List *l, *entries;
3515    unsigned int i;
3516 
3517    if (!buffer_ee)
3518      buffer_ee = ecore_evas_buffer_new(1, 1);
3519    if (!buffer_ee)
3520      {
3521         ERR("Cannot create buffer engine canvas for image load.");
3522         exit(-1);
3523      }
3524    evas = ecore_evas_get(buffer_ee);
3525 
3526    for (i = 0; i < edje_file->image_dir->sets_count; i++)
3527      {
3528         set = edje_file->image_dir->sets + i;
3529 
3530         if (!set->entries) continue;
3531         EINA_LIST_FOREACH(set->entries, l, simg)
3532           {
3533              Evas_Object *im;
3534              Eina_List *ll;
3535              char *s;
3536 
3537              im = evas_object_image_add(evas);
3538              EINA_LIST_FOREACH(img_dirs, ll, s)
3539                {
3540                   char buf[PATH_MAX];
3541                   int load_err = EVAS_LOAD_ERROR_NONE;
3542 
3543                   snprintf(buf, sizeof(buf), "%s/%s", s, simg->name);
3544                   evas_object_image_file_set(im, buf, NULL);
3545                   load_err = evas_object_image_load_error_get(im);
3546                   if (load_err == EVAS_LOAD_ERROR_NONE)
3547                     {
3548                        evas_object_image_size_get(im, &simg->size.w, &simg->size.h);
3549                        break;
3550                     }
3551                }
3552              evas_object_del(im);
3553           }
3554 
3555         entries = eina_list_clone(set->entries);
3556 
3557         entries = eina_list_sort(entries, 0, _data_image_w_size_compare_cb);
3558         preimg = eina_list_data_get(entries);
3559         EINA_LIST_FOREACH(entries, l, simg)
3560           {
3561              if (simg == preimg) continue;
3562              if (!(preimg->size.max.w) && !(simg->size.min.w))
3563                {
3564                   preimg->size.max.w = (preimg->size.w + simg->size.w) / 2;
3565                   simg->size.min.w = preimg->size.max.w + 1;
3566                   if (simg->size.min.w <= (simg->border.l + simg->border.r))
3567                     {
3568                        preimg->size.max.w = simg->border.l + simg->border.r;
3569                        simg->size.min.w = preimg->size.max.w + 1;
3570                     }
3571                }
3572              else if (preimg->size.max.w && !(simg->size.min.w))
3573                simg->size.min.w = preimg->size.max.w + 1;
3574              else if (!(preimg->size.max.w) && simg->size.min.w)
3575                preimg->size.max.w = simg->size.min.w - 1;
3576              preimg = simg;
3577           }
3578         simg = eina_list_data_get(eina_list_last(entries));
3579         if (!(simg->size.max.w)) simg->size.max.w = 99999;
3580 
3581         entries = eina_list_sort(entries, 0, _data_image_h_size_compare_cb);
3582         preimg = eina_list_data_get(entries);
3583         EINA_LIST_FOREACH(entries, l, simg)
3584           {
3585              if (simg == preimg) continue;
3586              if (!(preimg->size.max.h) && !(simg->size.min.h))
3587                {
3588                   preimg->size.max.h = (preimg->size.h + simg->size.h) / 2;
3589                   simg->size.min.h = preimg->size.max.h + 1;
3590                   if (simg->size.min.h <= (simg->border.t + simg->border.b))
3591                     {
3592                        preimg->size.max.h = simg->border.t + simg->border.b;
3593                        simg->size.min.h = preimg->size.max.h + 1;
3594                     }
3595                }
3596              else if (preimg->size.max.h && !(simg->size.min.h))
3597                simg->size.min.h = preimg->size.max.h + 1;
3598              else if (!(preimg->size.max.h) && simg->size.min.h)
3599                preimg->size.max.h = simg->size.min.h - 1;
3600              preimg = simg;
3601           }
3602         simg = eina_list_data_get(eina_list_last(entries));
3603         if (!(simg->size.max.h)) simg->size.max.h = 99999;
3604 
3605         eina_list_free(entries);
3606      }
3607 }
3608 
3609 static void
_data_image_id_update(Eina_List * images_unused_list)3610 _data_image_id_update(Eina_List *images_unused_list)
3611 {
3612    Image_Unused_Ids *iui;
3613    Edje_Part_Collection *pc;
3614    Edje_Part *part;
3615    Edje_Part_Description_Image *part_desc_image;
3616    Edje_Part_Image_Id *tween_id;
3617    unsigned int i, j, desc_it;
3618    Eina_List *l, *l2, *l3;
3619 
3620 #define PART_DESC_IMAGE_ID_UPDATE                                             \
3621   EINA_LIST_FOREACH(images_unused_list, l3, iui)                             \
3622     {                                                                         \
3623        if ((iui) && (part_desc_image->image.id == iui->old_id))               \
3624          {                                                                    \
3625             part_desc_image->image.id = iui->new_id;                          \
3626             break;                                                            \
3627          }                                                                    \
3628     }                                                                         \
3629   for (desc_it = 0; desc_it < part_desc_image->image.tweens_count; desc_it++) \
3630     {                                                                         \
3631        tween_id = part_desc_image->image.tweens[desc_it];                     \
3632        EINA_LIST_FOREACH(images_unused_list, l3, iui)                        \
3633          {                                                                    \
3634             if ((iui) && (tween_id->id == iui->old_id))                       \
3635               {                                                               \
3636                  tween_id->id = iui->new_id;                                  \
3637                  break;                                                       \
3638               }                                                               \
3639          }                                                                    \
3640     }
3641 
3642    EINA_LIST_FOREACH_SAFE(edje_collections, l, l2, pc)
3643      {
3644         for (i = 0; i < pc->parts_count; i++)
3645           {
3646              part = pc->parts[i];
3647              if (part->type == EDJE_PART_TYPE_IMAGE)
3648                {
3649                   part_desc_image = (Edje_Part_Description_Image *)part->default_desc;
3650                   if (!part_desc_image) continue;
3651                   PART_DESC_IMAGE_ID_UPDATE
3652                   for (j = 0; j < part->other.desc_count; j++)
3653                     {
3654                        part_desc_image = (Edje_Part_Description_Image *)part->other.desc[j];
3655                        PART_DESC_IMAGE_ID_UPDATE
3656                     }
3657                }
3658           }
3659      }
3660    for (i = 0; i < edje_file->image_dir->sets_count; i++)
3661      {
3662         Eina_List *entries, *list;
3663         Edje_Image_Directory_Set_Entry *entry;
3664 
3665         entries = edje_file->image_dir->sets[i].entries;
3666         EINA_LIST_FOREACH(entries, list, entry)
3667           {
3668              EINA_LIST_FOREACH(images_unused_list, l3, iui)
3669                {
3670                   if ((iui) && (entry->id == iui->old_id))
3671                     {
3672                        entry->id = iui->new_id;
3673                        break;
3674                     }
3675                }
3676           }
3677      }
3678 }
3679 
3680 void
data_process_lookups(void)3681 data_process_lookups(void)
3682 {
3683    Edje_Part_Collection *pc;
3684    Eina_Iterator *it;
3685    Part_Lookup *part;
3686    Program_Lookup *program;
3687    Group_Lookup *group;
3688    Image_Lookup *image;
3689    Eina_List *l2;
3690    Eina_List *l;
3691    Eina_Hash *images_in_use;
3692    char *group_name;
3693    Eina_Bool is_lua = EINA_FALSE;
3694    Image_Unused_Ids *iui;
3695 
3696    /* remove all unreferenced Edje_Part_Collection */
3697    EINA_LIST_FOREACH_SAFE(edje_collections, l, l2, pc)
3698      {
3699         Edje_Part_Collection_Directory_Entry *alias;
3700         Edje_Part_Collection_Directory_Entry *find;
3701         Eina_List *l3;
3702         unsigned int id = 0;
3703         unsigned int i;
3704 
3705         if (!pc->part)
3706           {
3707              ERR("A collection without a name was detected, that's not allowed.");
3708              exit(-1);
3709           }
3710 
3711         find = eina_hash_find(edje_file->collection, pc->part);
3712         if (find && find->id == pc->id)
3713           {
3714              if (((Edje_Part_Collection_Parser *)pc)->inherit_only)
3715                eina_hash_del_by_data(edje_file->collection, find);
3716              else
3717                continue;
3718           }
3719 
3720         EINA_LIST_FOREACH(aliases, l3, alias)
3721           if (alias->id == pc->id)
3722             continue;
3723 
3724         /* This Edje_Part_Collection is not used at all */
3725         edje_collections = eina_list_remove_list(edje_collections, l);
3726         l3 = eina_list_nth_list(codes, pc->id);
3727         codes = eina_list_remove_list(codes, l3);
3728 
3729         /* Unref all image used by that group */
3730         for (i = 0; i < pc->parts_count; ++i)
3731           part_description_image_cleanup(pc->parts[i]);
3732 
3733         /* Correct all id */
3734         EINA_LIST_FOREACH(edje_collections, l3, pc)
3735           {
3736              Eina_List *l4;
3737              Edje_Part_Collection_Directory_Entry *de;
3738 
3739              /* Some group could be removed from the collection, but still be referenced by alias */
3740              /* Update all matching alias */
3741              EINA_LIST_FOREACH(aliases, l4, alias)
3742                if (pc->id == alias->id)
3743                  alias->id = id;
3744 
3745              find = eina_hash_find(edje_file->collection, pc->part);
3746              if (pc->id != find->id) find = NULL;
3747 
3748              de = eina_hash_find(edje_collections_lookup, &pc->id);
3749              eina_hash_set(edje_collections_lookup, &pc->id, NULL);
3750              de->id = pc->id = id++;
3751              eina_hash_set(edje_collections_lookup, &pc->id, de);
3752              if (find) find->id = pc->id;
3753           }
3754      }
3755 
3756    EINA_LIST_FOREACH(edje_collections, l, pc)
3757      {
3758         unsigned int count = 0;
3759         unsigned int i;
3760 
3761         if (pc->lua_script_only)
3762           is_lua = EINA_TRUE;
3763 #define PROGRAM_ID_SET(Type, Pc, It, Count)            \
3764   for (It = 0; It < Pc->programs.Type ## _count; ++It) \
3765     {                                                  \
3766        Pc->programs.Type[It]->id = Count++;            \
3767     }
3768 
3769         PROGRAM_ID_SET(fnmatch, pc, i, count);
3770         PROGRAM_ID_SET(strcmp, pc, i, count);
3771         PROGRAM_ID_SET(strncmp, pc, i, count);
3772         PROGRAM_ID_SET(strrncmp, pc, i, count);
3773         PROGRAM_ID_SET(nocmp, pc, i, count);
3774 
3775 #undef PROGRAM_ID_SET
3776      }
3777 
3778    it = eina_hash_iterator_data_new(part_pc_dest_lookup);
3779    EINA_ITERATOR_FOREACH(it, part)
3780      {
3781         Edje_Part *ep;
3782         unsigned int i;
3783 
3784         if (!strcmp(part->name, "-"))
3785           {
3786              data_process_part_set(part, -1);
3787           }
3788         else
3789           {
3790              char *alias, *ap;
3791 
3792              alias = eina_hash_find(part->key.pc->alias, part->name);
3793              if (!alias)
3794                alias = part->name;
3795              ap = strchr(alias, EDJE_PART_PATH_SEPARATOR);
3796              if (ap)
3797                {
3798                   char *tmp;
3799 
3800                   tmp = alloca(strlen(alias) + 1);
3801                   memcpy(tmp, alias, ap - alias);
3802                   tmp[ap - alias] = 0;
3803                   ap += 1;
3804                   alias = tmp;
3805                }
3806              for (i = 0; i < part->key.pc->parts_count; ++i)
3807                {
3808                   ep = part->key.pc->parts[i];
3809 
3810                   if ((ep->name) && (!strcmp(ep->name, alias)))
3811                     {
3812                        if (data_process_part_set(part, ep->id))
3813                          *part->key.dest2 = ap;
3814                        break;
3815                     }
3816                }
3817 
3818              if ((i == part->key.pc->parts_count) && (!((Edje_Part_Collection_Parser *)part->key.pc)->inherit_only))
3819                {
3820                   ERR("Unable to find part name \"%s\" needed in group '%s'.",
3821                       alias, part->key.pc->part);
3822                   exit(-1);
3823                }
3824           }
3825      }
3826    eina_iterator_free(it);
3827    eina_hash_free(part_dest_lookup);
3828    eina_hash_free(part_pc_dest_lookup);
3829 
3830    EINA_LIST_FREE(program_lookups, program)
3831      {
3832         unsigned int i;
3833         Eina_Bool find = EINA_FALSE;
3834 
3835 #define PROGRAM_MATCH(Type, Pl, It)                                             \
3836   for (It = 0; It < Pl->pc->programs.Type ## _count; ++It)                      \
3837     {                                                                           \
3838        Edje_Program *ep;                                                        \
3839                                                                                 \
3840        ep = Pl->pc->programs.Type[It];                                          \
3841                                                                                 \
3842        if ((Pl->anonymous && ep == Pl->u.ep) ||                                 \
3843            ((!Pl->anonymous) && (ep->name) && (!strcmp(ep->name, Pl->u.name)))) \
3844          {                                                                      \
3845             *(Pl->dest) = ep->id;                                               \
3846             find = EINA_TRUE;                                                   \
3847             break;                                                              \
3848          }                                                                      \
3849     }
3850 
3851         PROGRAM_MATCH(fnmatch, program, i);
3852         PROGRAM_MATCH(strcmp, program, i);
3853         PROGRAM_MATCH(strncmp, program, i);
3854         PROGRAM_MATCH(strrncmp, program, i);
3855         PROGRAM_MATCH(nocmp, program, i);
3856 
3857 #undef PROGRAM_MATCH
3858 
3859         if (!find)
3860           {
3861              if (!program->anonymous)
3862                ERR("Unable to find program name \"%s\".",
3863                    program->u.name);
3864              else
3865                ERR("Unable to find anonymous program.");
3866              exit(-1);
3867           }
3868 
3869         if (!program->anonymous)
3870           free(program->u.name);
3871         free(program);
3872      }
3873 
3874    groups_sourced = eina_hash_string_superfast_new(NULL);
3875    EINA_LIST_FREE(group_lookups, group)
3876      {
3877         Edje_Part_Collection_Directory_Entry *de;
3878 
3879         if (group->part)
3880           {
3881              if (group->part->type != EDJE_PART_TYPE_GROUP
3882                  && group->part->type != EDJE_PART_TYPE_TEXTBLOCK
3883                  && group->part->type != EDJE_PART_TYPE_BOX
3884                  && group->part->type != EDJE_PART_TYPE_TABLE)
3885                goto free_group;
3886           }
3887 
3888         de = eina_hash_find(edje_file->collection, group->name);
3889 
3890         if (!de)
3891           {
3892              Eina_Bool found = EINA_FALSE;
3893 
3894              EINA_LIST_FOREACH(aliases, l, de)
3895                if (strcmp(de->entry, group->name) == 0)
3896                  {
3897                     found = EINA_TRUE;
3898                     break;
3899                  }
3900              if (!found) de = NULL;
3901           }
3902 
3903         if (!de)
3904           {
3905              ERR("Unable to find group name \"%s\".", group->name);
3906              exit(-1);
3907           }
3908 
3909         eina_hash_add(groups_sourced, group->name, (void*)1);
3910 free_group:
3911         free(group->name);
3912         free(group);
3913      }
3914 
3915    EINA_LIST_FREE(face_group_lookups, group_name)
3916      {
3917         Edje_Part_Collection_Directory_Entry *de;
3918 
3919         de = eina_hash_find(edje_file->collection, group_name);
3920 
3921         if (!de)
3922           {
3923              Eina_Bool found = EINA_FALSE;
3924 
3925              EINA_LIST_FOREACH(aliases, l, de)
3926                if (strcmp(de->entry, group_name) == 0)
3927                  {
3928                     found = EINA_TRUE;
3929                     break;
3930                  }
3931              if (!found) de = NULL;
3932           }
3933 
3934         if (!de)
3935           {
3936              ERR("Unable to find group name \"%s\".", group_name);
3937              exit(-1);
3938           }
3939 
3940         free(group_name);
3941      }
3942 
3943    images_in_use = eina_hash_string_superfast_new(NULL);
3944 
3945    EINA_LIST_FREE(image_lookups, image)
3946      {
3947         Eina_Bool find = EINA_FALSE;
3948 
3949         if (edje_file->image_dir)
3950           {
3951              Edje_Image_Directory_Entry *de;
3952              unsigned int i;
3953 
3954              for (i = 0; i < edje_file->image_dir->entries_count; ++i)
3955                {
3956                   de = edje_file->image_dir->entries + i;
3957 
3958                   if ((de->entry) && (!strcmp(de->entry, image->name)))
3959                     {
3960                        if (de->source_type >= EDJE_IMAGE_SOURCE_TYPE_USER)
3961                          *(image->dest) = -de->id - 1;
3962                        else
3963                          *(image->dest) = de->id;
3964                        *(image->set) = EINA_FALSE;
3965                        find = EINA_TRUE;
3966 
3967                        if (!eina_hash_find(images_in_use, image->name))
3968                          eina_hash_direct_add(images_in_use, de->entry, de);
3969                        break;
3970                     }
3971                }
3972 
3973              if (!find)
3974                {
3975                   Edje_Image_Directory_Set *set;
3976 
3977                   for (i = 0; i < edje_file->image_dir->sets_count; ++i)
3978                     {
3979                        set = edje_file->image_dir->sets + i;
3980 
3981                        if ((set->name) && (!strcmp(set->name, image->name)))
3982                          {
3983                             Edje_Image_Directory_Set_Entry *child;
3984                             Eina_List *lc;
3985 
3986                             *(image->dest) = set->id;
3987                             *(image->set) = EINA_TRUE;
3988                             find = EINA_TRUE;
3989 
3990                             EINA_LIST_FOREACH(set->entries, lc, child)
3991                               if (!eina_hash_find(images_in_use, child->name))
3992                                 eina_hash_direct_add(images_in_use, child->name, child);
3993 
3994                             if (!eina_hash_find(images_in_use, image->name))
3995                               eina_hash_direct_add(images_in_use, set->name, set);
3996                             break;
3997                          }
3998                        else
3999                          *(image->set) = EINA_FALSE;
4000                     }
4001                }
4002           }
4003 
4004         if (!find)
4005           {
4006              ERR("Unable to find image name \"%s\".", image->name);
4007              exit(-1);
4008           }
4009 
4010         free(image->name);
4011         free(image);
4012      }
4013 
4014    if (edje_file->image_dir && !is_lua)
4015      {
4016         Edje_Image_Directory_Entry *de, *de_last, *img;
4017         Edje_Image_Directory_Set *set;
4018         Edje_Image_Directory_Set_Entry *set_e;
4019         Eina_List *images_unused_list = NULL;
4020         unsigned int i;
4021 
4022         for (i = 0; i < edje_file->image_dir->entries_count; ++i)
4023           {
4024              de = edje_file->image_dir->entries + i;
4025 
4026              if (de->entry && eina_hash_find(images_in_use, de->entry))
4027                continue;
4028 
4029              printf("Warning: Image '%s' not used\n", de->entry);
4030              INF("Image '%s' in resource 'edje/image/%i' will not be included as it is unused.",
4031                  de->entry, de->id);
4032 
4033              // so as not to write the unused images, moved last image in the
4034              // list to unused image position and check it
4035              free((void *)de->entry);
4036              de->entry = NULL;
4037              de_last = edje_file->image_dir->entries + edje_file->image_dir->entries_count - 1;
4038              iui = mem_alloc(SZ(Image_Unused_Ids));
4039              iui->old_id = de_last->id;
4040              images_unused_list = eina_list_append(images_unused_list, iui);
4041              iui->new_id = i;
4042              de_last->id = i;
4043              memcpy(de, de_last, sizeof(Edje_Image_Directory_Entry));
4044              --i; // need to check a moved image on this index
4045              edje_file->image_dir->entries_count--;
4046              img = realloc(edje_file->image_dir->entries,
4047                            sizeof (Edje_Image_Directory_Entry) * edje_file->image_dir->entries_count);
4048              edje_file->image_dir->entries = img;
4049           }
4050 
4051         for (i = 0; i < edje_file->image_dir->sets_count; ++i)
4052           {
4053              set = edje_file->image_dir->sets + i;
4054 
4055              if (set->name && eina_hash_find(images_in_use, set->name))
4056                continue;
4057 
4058              printf("Warning: Image set '%s' not used\n", set->name);
4059              EINA_LIST_FOREACH(set->entries, l, set_e)
4060                {
4061                   printf("  Contains '%s' size %ix%i -> %ix%i\n",
4062                          set_e->name,
4063                          set_e->size.min.w, set_e->size.min.h,
4064                          set_e->size.max.w, set_e->size.max.h);
4065                }
4066 /* No need to redo id's - we will warn of unused images - fix in src
4067  * Also .. this is broken and messes up id's ... so easyer - complain
4068  * to develoepr to clean up the theme...
4069              INF("Set '%s' will not be included as it is unused.", set->name);
4070 
4071              free((void *)set->name);
4072              EINA_LIST_FREE(set->entries, set_e)
4073                {
4074                   free((void *)set_e->name);
4075                   free(set_e);
4076                }
4077              set->entries = NULL;
4078              set_last = edje_file->image_dir->sets + edje_file->image_dir->sets_count - 1;
4079              iui = mem_alloc(SZ(Image_Unused_Ids));
4080              iui->old_id = set_last->id;
4081              images_unused_list = eina_list_append(images_unused_list, iui);
4082              iui->new_id = i;
4083              set_last->id = i;
4084              memcpy(set, set_last, sizeof(Edje_Image_Directory_Set));
4085              --i;
4086              edje_file->image_dir->sets_count--;
4087              set_realloc = realloc(edje_file->image_dir->sets,
4088                                    sizeof(Edje_Image_Directory_Set) * edje_file->image_dir->sets_count);
4089              edje_file->image_dir->sets = set_realloc;
4090  */
4091           }
4092 
4093         /* update image id in parts */
4094         if (images_unused_list) _data_image_id_update(images_unused_list);
4095         EINA_LIST_FREE(images_unused_list, iui)
4096           free(iui);
4097 
4098         _data_image_sets_size_set();
4099      }
4100 
4101    eina_hash_free(images_in_use);
4102 }
4103 
4104 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))4105 data_process_string(Edje_Part_Collection *pc, const char *prefix, char *s, void (*func)(Edje_Part_Collection *pc, char *name, char *ptr, int len))
4106 {
4107    char *p;
4108    char *key;
4109    int keyl;
4110    int quote, escape;
4111 
4112    keyl = strlen(prefix) + 2;
4113    key = alloca(keyl + 1);
4114    if (!key) return;
4115    strcpy(key, prefix);
4116    strcat(key, ":\"");
4117    quote = 0;
4118    escape = 0;
4119    for (p = s; (p) && (*p); p++)
4120      {
4121         if (!quote)
4122           {
4123              if (*p == '\"')
4124                {
4125                   quote = 1;
4126                   p++;
4127                }
4128           }
4129         if (!quote)
4130           {
4131              if (!strncmp(p, key, keyl))
4132                {
4133                   char *ptr;
4134                   int len;
4135                   int inesc = 0;
4136                   char *name;
4137 
4138                   ptr = p;
4139                   p += keyl;
4140                   while ((*p))
4141                     {
4142                        if (!inesc)
4143                          {
4144                             if (*p == '\\') inesc = 1;
4145                             else if (*p == '\"')
4146                               {
4147                                  /* string concatenation, see below */
4148                                  if (*(p + 1) != '\"')
4149                                    break;
4150                                  else
4151                                    p++;
4152                               }
4153                          }
4154                        else
4155                          inesc = 0;
4156                        p++;
4157                     }
4158                   len = p - ptr + 1;
4159                   name = alloca(len);
4160                   if (name)
4161                     {
4162                        char *pp;
4163                        int i;
4164 
4165                        name[0] = 0;
4166                        pp = ptr + keyl;
4167                        inesc = 0;
4168                        i = 0;
4169                        while (*pp)
4170                          {
4171                             if (!inesc)
4172                               {
4173                                  if (*pp == '\\') inesc = 1;
4174                                  else if (*pp == '\"')
4175                                    {
4176                                       /* concat strings like "foo""bar" to "foobar" */
4177                                       if (*(pp + 1) == '\"')
4178                                         pp++;
4179                                       else
4180                                         {
4181                                            name[i] = 0;
4182                                            break;
4183                                         }
4184                                    }
4185                                  else
4186                                    {
4187                                       name[i] = *pp;
4188                                       name[i + 1] = 0;
4189                                       i++;
4190                                    }
4191                               }
4192                             else
4193                               inesc = 0;
4194                             pp++;
4195                          }
4196                        func(pc, name, ptr, len);
4197                     }
4198                }
4199           }
4200         else
4201           {
4202              if (!escape)
4203                {
4204                   if (*p == '\"') quote = 0;
4205                   else if (*p == '\\')
4206                     escape = 1;
4207                }
4208              else if (escape)
4209                {
4210                   escape = 0;
4211                }
4212           }
4213      }
4214 }
4215 
4216 static void
_data_queue_part_lookup(Edje_Part_Collection * pc,char * name,char * ptr,int len)4217 _data_queue_part_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
4218 {
4219    Code_Lookup *cl;
4220 
4221    cl = mem_alloc(SZ(Code_Lookup));
4222    cl->ptr = ptr;
4223    cl->len = len;
4224 
4225    data_queue_part_lookup(pc, name, &(cl->val));
4226 
4227    code_lookups = eina_list_append(code_lookups, cl);
4228 }
4229 
4230 static void
_data_queue_program_lookup(Edje_Part_Collection * pc,char * name,char * ptr,int len)4231 _data_queue_program_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
4232 {
4233    Code_Lookup *cl;
4234 
4235    cl = mem_alloc(SZ(Code_Lookup));
4236    cl->ptr = ptr;
4237    cl->len = len;
4238 
4239    data_queue_program_lookup(pc, name, &(cl->val));
4240 
4241    code_lookups = eina_list_append(code_lookups, cl);
4242 }
4243 
4244 static void
_data_queue_group_lookup(Edje_Part_Collection * pc EINA_UNUSED,char * name,char * ptr EINA_UNUSED,int len EINA_UNUSED)4245 _data_queue_group_lookup(Edje_Part_Collection *pc EINA_UNUSED, char *name, char *ptr EINA_UNUSED, int len EINA_UNUSED)
4246 {
4247    data_queue_group_lookup(name, NULL);
4248 }
4249 
4250 static void
_data_queue_image_pc_lookup(Edje_Part_Collection * pc EINA_UNUSED,char * name,char * ptr,int len)4251 _data_queue_image_pc_lookup(Edje_Part_Collection *pc EINA_UNUSED, char *name, char *ptr, int len)
4252 {
4253    Code_Lookup *cl;
4254 
4255    cl = mem_alloc(SZ(Code_Lookup));
4256    cl->ptr = ptr;
4257    cl->len = len;
4258 
4259    data_queue_image_lookup(name, &(cl->val), &(cl->set));
4260 
4261    code_lookups = eina_list_append(code_lookups, cl);
4262 }
4263 
4264 void
data_process_scripts(void)4265 data_process_scripts(void)
4266 {
4267    Eina_List *l, *l2;
4268 
4269    for (l = codes, l2 = edje_collections; (l) && (l2); l = eina_list_next(l), l2 = eina_list_next(l2))
4270      {
4271         Edje_Part_Collection *pc;
4272         Code *cd;
4273 
4274         cd = eina_list_data_get(l);
4275         pc = eina_list_data_get(l2);
4276 
4277         if ((cd->shared) && (!cd->is_lua))
4278           {
4279              data_process_string(pc, "PART", cd->shared, _data_queue_part_lookup);
4280              data_process_string(pc, "PROGRAM", cd->shared, _data_queue_program_lookup);
4281              data_process_string(pc, "IMAGE", cd->shared, _data_queue_image_pc_lookup);
4282              data_process_string(pc, "GROUP", cd->shared, _data_queue_group_lookup);
4283           }
4284 
4285         if (cd->programs)
4286           {
4287              Code_Program *cp;
4288              Eina_List *ll;
4289 
4290              EINA_LIST_FOREACH(cd->programs, ll, cp)
4291                {
4292                   if (cp->script)
4293                     {
4294                        data_process_string(pc, "PART", cp->script, _data_queue_part_lookup);
4295                        data_process_string(pc, "PROGRAM", cp->script, _data_queue_program_lookup);
4296                        data_process_string(pc, "IMAGE", cp->script, _data_queue_image_pc_lookup);
4297                        data_process_string(pc, "GROUP", cp->script, _data_queue_group_lookup);
4298                     }
4299                }
4300           }
4301      }
4302 }
4303 
4304 void
data_process_script_lookups(void)4305 data_process_script_lookups(void)
4306 {
4307    Eina_List *l;
4308    Code_Lookup *cl;
4309 
4310    EINA_LIST_FOREACH(code_lookups, l, cl)
4311      {
4312         char buf[12];
4313         int n;
4314 
4315         /* FIXME !! Handle set in program */
4316         n = eina_convert_itoa(cl->val, buf);
4317         if (n > cl->len)
4318           {
4319              ERR("The unexpected happened. A numeric replacement string was larger than the original!");
4320              exit(-1);
4321           }
4322         memset(cl->ptr, ' ', cl->len);
4323         strncpy(cl->ptr, buf, n);
4324      }
4325 }
4326 
4327 void
using_file(const char * filename,const char type)4328 using_file(const char *filename, const char type)
4329 {
4330    FILE *f;
4331 
4332    if (depfile)
4333      {
4334         f = fopen(depfile, "ab");
4335         if (!f) return;
4336         if (type != 'O')
4337           {
4338              fprintf(f, " \\\n  %s", filename);
4339           }
4340         fclose(f);
4341      }
4342    else if (watchfile)
4343      {
4344         f = fopen(watchfile, "ab");
4345         if (!f) return;
4346         if (annotate)
4347           {
4348              fprintf(f, "%c: %s\n", type, filename);
4349           }
4350         else
4351           {
4352              fputs(filename, f);
4353              fputc('\n', f);
4354           }
4355         fclose(f);
4356      }
4357 }
4358 
4359 void
color_tree_root_free(void)4360 color_tree_root_free(void)
4361 {
4362    char *name;
4363 
4364    EINA_LIST_FREE(color_tree_root, name)
4365      free(name);
4366 }
4367 
4368 char *
color_tree_token_next(char * dst,char * src,int * ln)4369 color_tree_token_next(char *dst, char *src, int *ln)
4370 {
4371    Eina_Bool begin = EINA_FALSE, next = EINA_FALSE;
4372 
4373    while (!next)
4374      {
4375         if (*src == '\0') break;
4376 
4377         if (*src == '"')
4378           {
4379              if (!begin) begin = EINA_TRUE;
4380              else next = EINA_TRUE;
4381           }
4382         else if ((!begin) && ((*src == '{') || (*src == '}') || (*src == ';')))
4383           {
4384              *dst++ = *src;
4385              next = EINA_TRUE;
4386           }
4387         else if ((!begin) && (*src == '\n'))
4388           {
4389              (*ln)++;
4390           }
4391         else if (begin)
4392           {
4393              *dst++ = *src;
4394           }
4395         src++;
4396      }
4397    *dst = '\0';
4398    return src;
4399 }
4400 
4401 Edje_Color_Tree_Node *
color_tree_parent_node_get(const char * color_class)4402 color_tree_parent_node_get(const char *color_class)
4403 {
4404    Edje_Color_Tree_Node *ctn;
4405    Eina_List *l, *ll;
4406    char *name;
4407 
4408    EINA_LIST_FOREACH(edje_file->color_tree, l, ctn)
4409      if (ctn->color_classes)
4410        EINA_LIST_FOREACH(ctn->color_classes, ll, name)
4411          if (!strcmp(name, color_class))
4412            return ctn;
4413 
4414    return NULL;
4415 }
4416 
4417 void
process_color_tree(char * s,const char * f_in,int ln)4418 process_color_tree(char *s, const char *f_in, int ln)
4419 {
4420    char token[2][1024];
4421    int id = 0;
4422    Eina_Array *array;
4423    Edje_Color_Tree_Node *ctn;
4424    Eina_List *l;
4425    char *name;
4426 
4427    if (!s) return;
4428 
4429    array = eina_array_new(4);
4430 
4431    do
4432      {
4433         s = color_tree_token_next(token[id], s, &ln);
4434 
4435         if (!strcmp(token[id], "{"))
4436           {
4437              if (!token[!id][0])
4438                error_and_abort(NULL, "parse error %s:%i. color class is not set to newly opened node block.",
4439                                f_in, ln - 1);
4440 
4441              ctn = mem_alloc(SZ(Edje_Color_Tree_Node));
4442              ctn->name = strdup(token[!id]);
4443              ctn->color_classes = NULL;
4444 
4445              edje_file->color_tree = eina_list_append(edje_file->color_tree, ctn);
4446 
4447              eina_array_push(array, ctn);
4448              token[id][0] = '\0';
4449           }
4450         else if (!strcmp(token[id], "}"))
4451           {
4452              eina_array_pop(array);
4453              token[id][0] = '\0';
4454           }
4455         else if (!strcmp(token[id], ";"))
4456           {
4457              token[id][0] = '\0';
4458           }
4459         else if (*s != '\0')
4460           {
4461              if (eina_array_count(array))
4462                {
4463                   if (color_tree_root)
4464                     EINA_LIST_FOREACH(color_tree_root, l, name)
4465                       if (!strcmp(name, token[id]))
4466                         {
4467                            error_and_abort(NULL, "parse error %s:%i. The color class \"%s\" already belongs to the root node.",
4468                                            f_in, ln - 1, token[id]);
4469                         }
4470 
4471                   if ((ctn = color_tree_parent_node_get(token[id])))
4472                     error_and_abort(NULL, "parse error %s:%i. The color class \"%s\" already belongs to the \"%s\" node.",
4473                                     f_in, ln - 1, token[id], ctn->name);
4474 
4475                   ctn = eina_array_data_get(array, eina_array_count(array) - 1);
4476                   ctn->color_classes = eina_list_append(ctn->color_classes, strdup(token[id]));
4477                }
4478              else
4479                {
4480                   if ((ctn = color_tree_parent_node_get(token[id])))
4481                     error_and_abort(NULL, "parse error %s:%i. The color class \"%s\" already belongs to the \"%s\" node.",
4482                                     f_in, ln - 1, token[id], ctn->name);
4483 
4484                   color_tree_root = eina_list_append(color_tree_root, strdup(token[id]));
4485                }
4486           }
4487 
4488         id = !id;
4489      } while (*s);
4490 
4491    if (eina_array_count(array))
4492      error_and_abort(NULL, "parse error %s:%i. check pair of parens.", f_in, ln - 1);
4493 
4494    eina_array_clean(array);
4495    eina_array_free(array);
4496 }
4497 
4498 char
validate_hex_digit(char c)4499 validate_hex_digit(char c)
4500 {
4501    if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
4502      return c;
4503 
4504    ERR("%s:%i. invalid character '%c' is used in color code.",
4505        file_in, line - 1, c);
4506    exit(-1);
4507 }
4508 
4509 void
convert_color_code(char * str,int * r,int * g,int * b,int * a)4510 convert_color_code(char *str, int *r, int *g, int *b, int *a)
4511 {
4512    char buf[3];
4513    int len;
4514 
4515    len = strlen(str);
4516 
4517    if ((str[0] != '#') || (len != 4 && len != 5 && len != 7 && len != 9))
4518      {
4519         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)",
4520             file_in, line - 1);
4521         exit(-1);
4522      }
4523 
4524    buf[2] = '\0';
4525 
4526    if (r)
4527      {
4528         if ((len == 4) || (len == 5))
4529           {
4530              buf[0] = validate_hex_digit(str[1]);
4531              buf[1] = validate_hex_digit(str[1]);
4532           }
4533         else
4534           {
4535              buf[0] = validate_hex_digit(str[1]);
4536              buf[1] = validate_hex_digit(str[2]);
4537           }
4538 
4539         *r = (int)strtol(buf, NULL, 16);
4540      }
4541    if (g)
4542      {
4543         if ((len == 4) || (len == 5))
4544           {
4545              buf[0] = validate_hex_digit(str[2]);
4546              buf[1] = validate_hex_digit(str[2]);
4547           }
4548         else
4549           {
4550              buf[0] = validate_hex_digit(str[3]);
4551              buf[1] = validate_hex_digit(str[4]);
4552           }
4553 
4554         *g = (int)strtol(buf, NULL, 16);
4555      }
4556    if (b)
4557      {
4558         if ((len == 4) || (len == 5))
4559           {
4560              buf[0] = validate_hex_digit(str[3]);
4561              buf[1] = validate_hex_digit(str[3]);
4562           }
4563         else
4564           {
4565              buf[0] = validate_hex_digit(str[5]);
4566              buf[1] = validate_hex_digit(str[6]);
4567           }
4568 
4569         *b = (int)strtol(buf, NULL, 16);
4570      }
4571    if (a)
4572      {
4573         if ((len == 5) || (len == 9))
4574           {
4575              if (len == 5)
4576                {
4577                   buf[0] = validate_hex_digit(str[4]);
4578                   buf[1] = validate_hex_digit(str[4]);
4579                }
4580              else
4581                {
4582                   buf[0] = validate_hex_digit(str[7]);
4583                   buf[1] = validate_hex_digit(str[8]);
4584                }
4585 
4586              *a = (int)strtol(buf, NULL, 16);
4587           }
4588         else
4589           {
4590              *a = 255;
4591           }
4592      }
4593 
4594    free(str);
4595 }
4596 
4597