#ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_ALLOCA_H # include #elif defined __GNUC__ # define alloca __builtin_alloca #elif defined _AIX # define alloca __alloca #elif defined _MSC_VER # include # define alloca _alloca #else # include # ifdef __cplusplus extern "C" # endif void *alloca (size_t); #endif #include #include #include #include #include #include "edje_cc.h" #include "edje_convert.h" #include #include typedef struct _External_Lookup External_Lookup; typedef struct _Part_Lookup Part_Lookup; typedef struct _Program_Lookup Program_Lookup; typedef struct _Group_Lookup Group_Lookup; typedef struct _Image_Lookup Image_Lookup; typedef struct _Slave_Lookup Slave_Lookup; typedef struct _Code_Lookup Code_Lookup; struct _External_Lookup { char *name; }; struct _Part_Lookup { Edje_Part_Collection *pc; char *name; int *dest; }; struct _Program_Lookup { Edje_Part_Collection *pc; union { char *name; Edje_Program *ep; } u; int *dest; Eina_Bool anonymous : 1; }; struct _Group_Lookup { char *name; }; struct _String_Lookup { char *name; int *dest; }; struct _Image_Lookup { char *name; int *dest; Eina_Bool *set; }; struct _Slave_Lookup { int *master; int *slave; }; struct _Code_Lookup { char *ptr; int len; int val; Eina_Bool set; }; 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)); Edje_File *edje_file = NULL; Eina_List *edje_collections = NULL; Eina_List *externals = NULL; Eina_List *fonts = NULL; Eina_List *codes = NULL; Eina_List *code_lookups = NULL; Eina_List *aliases = NULL; static Eet_Data_Descriptor *edd_edje_file = NULL; static Eet_Data_Descriptor *edd_edje_part_collection = NULL; static Eina_List *part_lookups = NULL; static Eina_List *program_lookups = NULL; static Eina_List *group_lookups = NULL; static Eina_List *image_lookups = NULL; static Eina_List *part_slave_lookups = NULL; static Eina_List *image_slave_lookups= NULL; #define ABORT_WRITE(eet_file, file) \ eet_close(eet_file); \ unlink(file); \ exit(-1); void error_and_abort(Eet_File *ef, const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: Error. ", progname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); ABORT_WRITE(ef, file_out); } void data_setup(void) { edd_edje_file = _edje_edd_edje_file; edd_edje_part_collection = _edje_edd_edje_part_collection; } static void check_image_part_desc (Edje_Part_Collection *pc, Edje_Part *ep, Edje_Part_Description_Image *epd, Eet_File *ef) { unsigned int i; #if 0 /* FIXME: This check sounds like not a useful one */ if (epd->image.id == -1) ERR(ef, "Collection %s(%i): image attributes missing for " "part \"%s\", description \"%s\" %f\n", pc->part, pc->id, ep->name, epd->common.state.name, epd->common.state.value); #endif for (i = 0; i < epd->image.tweens_count; ++i) { if (epd->image.tweens[i]->id == -1) error_and_abort(ef, "Collection %i: tween image id missing for " "part \"%s\", description \"%s\" %f\n", pc->id, ep->name, epd->common.state.name, epd->common.state.value); } } static void check_packed_items(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef) { unsigned int i; for (i = 0; i < ep->items_count; ++i) { if (ep->items[i]->type == EDJE_PART_TYPE_GROUP && !ep->items[i]->source) error_and_abort(ef, "Collection %i: missing source on packed item " "of type GROUP in part \"%s\"\n", pc->id, ep->name); if (ep->type == EDJE_PART_TYPE_TABLE && (ep->items[i]->col < 0 || ep->items[i]->row < 0)) error_and_abort(ef, "Collection %i: missing col/row on packed item " "for part \"%s\" of type TABLE\n", pc->id, ep->name); } } static void check_nameless_state(Edje_Part_Collection *pc, Edje_Part *ep, Edje_Part_Description_Common *ed, Eet_File *ef) { if (!ed->state.name) error_and_abort(ef, "Collection %i: description with state missing on part \"%s\"\n", pc->id, ep->name); } static void check_part (Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef) { unsigned int i; /* FIXME: check image set and sort them. */ if (!ep->default_desc) error_and_abort(ef, "Collection %i: default description missing " "for part \"%s\"\n", pc->id, ep->name); for (i = 0; i < ep->other.desc_count; ++i) check_nameless_state(pc, ep, ep->other.desc[i], ef); if (ep->type == EDJE_PART_TYPE_IMAGE) { check_image_part_desc(pc, ep, (Edje_Part_Description_Image*) ep->default_desc, ef); for (i = 0; i < ep->other.desc_count; ++i) check_image_part_desc (pc, ep, (Edje_Part_Description_Image*) ep->other.desc[i], ef); } else if ((ep->type == EDJE_PART_TYPE_BOX) || (ep->type == EDJE_PART_TYPE_TABLE)) check_packed_items(pc, ep, ef); } static void check_program (Edje_Part_Collection *pc, Edje_Program *ep, Eet_File *ef) { switch (ep->action) { case EDJE_ACTION_TYPE_STATE_SET: case EDJE_ACTION_TYPE_ACTION_STOP: case EDJE_ACTION_TYPE_DRAG_VAL_SET: case EDJE_ACTION_TYPE_DRAG_VAL_STEP: case EDJE_ACTION_TYPE_DRAG_VAL_PAGE: if (!ep->targets) error_and_abort(ef, "Collection %i: target missing in program " "\"%s\"\n", pc->id, ep->name); break; default: break; } } static int data_write_header(Eet_File *ef) { int bytes = 0; if (edje_file) { if (edje_file->collection) { Edje_Part_Collection_Directory_Entry *ce; /* copy aliases into collection directory */ EINA_LIST_FREE(aliases, ce) { Edje_Part_Collection_Directory_Entry *sce; Eina_Iterator *it; if (!ce->entry) error_and_abort(ef, "Collection %i: name missing.\n", ce->id); it = eina_hash_iterator_data_new(edje_file->collection); EINA_ITERATOR_FOREACH(it, sce) if (ce->id == sce->id) { memcpy(&ce->count, &sce->count, sizeof (ce->count)); break; } if (!sce) error_and_abort(ef, "Collection %s (%i) can't find an correct alias.\n", ce->entry, ce->id); eina_iterator_free(it); eina_hash_direct_add(edje_file->collection, ce->entry, ce); } } bytes = eet_data_write(ef, edd_edje_file, "edje/file", edje_file, 1); if (bytes <= 0) error_and_abort(ef, "Unable to write \"edje_file\" entry to \"%s\" \n", file_out); } if (verbose) { printf("%s: Wrote %9i bytes (%4iKb) for \"edje_file\" header\n", progname, bytes, (bytes + 512) / 1024); } return bytes; } static int data_write_fonts(Eet_File *ef, int *font_num, int *input_bytes, int *input_raw_bytes) { Eina_Iterator *it; int bytes = 0; int total_bytes = 0; Font *fn; if (!edje_file->fonts) return 0; it = eina_hash_iterator_data_new(edje_file->fonts); EINA_ITERATOR_FOREACH(it, fn) { void *fdata = NULL; int fsize = 0; Eina_List *ll; FILE *f; f = fopen(fn->file, "rb"); if (f) { long pos; fseek(f, 0, SEEK_END); pos = ftell(f); rewind(f); fdata = malloc(pos); if (fdata) { if (fread(fdata, pos, 1, f) != 1) error_and_abort(ef, "Unable to read all of font " "file \"%s\"\n", fn->file); fsize = pos; } fclose(f); } else { char *data; EINA_LIST_FOREACH(fnt_dirs, ll, data) { char buf[4096]; snprintf(buf, sizeof(buf), "%s/%s", data, fn->file); f = fopen(buf, "rb"); if (f) { long pos; fseek(f, 0, SEEK_END); pos = ftell(f); rewind(f); fdata = malloc(pos); if (fdata) { if (fread(fdata, pos, 1, f) != 1) error_and_abort(ef, "Unable to read all of font " "file \"%s\"\n", buf); fsize = pos; } fclose(f); if (fdata) break; } } } if (!fdata) { error_and_abort(ef, "Unable to load font part \"%s\" entry " "to %s \n", fn->file, file_out); } else { char buf[4096]; snprintf(buf, sizeof(buf), "edje/fonts/%s", fn->name); bytes = eet_write(ef, buf, fdata, fsize, 1); if (bytes <= 0) error_and_abort(ef, "Unable to write font part \"%s\" as \"%s\" " "part entry to %s \n", fn->file, buf, file_out); *font_num += 1; total_bytes += bytes; *input_bytes += fsize; *input_raw_bytes += fsize; if (verbose) { printf("%s: Wrote %9i bytes (%4iKb) for \"%s\" font entry \"%s\" compress: [real: %2.1f%%]\n", progname, bytes, (bytes + 512) / 1024, buf, fn->file, 100 - (100 * (double)bytes) / ((double)(fsize)) ); } free(fdata); } } eina_iterator_free(it); return total_bytes; } static void error_and_abort_image_load_error(Eet_File *ef, const char *file, int error) { const char *errmsg = evas_load_error_str(error); char hint[1024] = ""; if (error == EVAS_LOAD_ERROR_DOES_NOT_EXIST) { snprintf (hint, sizeof(hint), " Check if path to file \"%s\" is correct " "(both directory and file name).", file); } else if (error == EVAS_LOAD_ERROR_CORRUPT_FILE) { snprintf (hint, sizeof(hint), " Check if file \"%s\" is consistent.", file); } else if (error == EVAS_LOAD_ERROR_UNKNOWN_FORMAT) { const char *ext = strrchr(file, '.'); const char **itr, *known_loaders[] = { /* list from evas_image_load.c */ "png", "jpg", "jpeg", "jfif", "eet", "edj", "eap", "edb", "xpm", "tiff", "tif", "svg", "svgz", "gif", "pbm", "pgm", "ppm", "pnm", NULL }; if (!ext) { snprintf (hint, sizeof(hint), " File \"%s\" does not have an extension, " "maybe it should?", file); goto show_err; } ext++; for (itr = known_loaders; *itr; itr++) { if (strcasecmp(ext, *itr) == 0) { snprintf (hint, sizeof(hint), " Check if Evas was compiled with %s module enabled and " "all required dependencies exist.", ext); goto show_err; } } snprintf(hint, sizeof(hint), " Check if Evas supports loading files of type \"%s\" (%s) " "and this module was compiled and all its dependencies exist.", ext, file); } show_err: error_and_abort (ef, "Unable to load image \"%s\" used by file \"%s\": %s.%s\n", file, file_out, errmsg, hint); } static int data_write_images(Eet_File *ef, int *image_num, int *input_bytes, int *input_raw_bytes) { unsigned int i; int bytes = 0; int total_bytes = 0; if ((edje_file) && (edje_file->image_dir)) { Ecore_Evas *ee; Evas *evas; Edje_Image_Directory_Entry *img; ecore_init(); ecore_evas_init(); ee = ecore_evas_buffer_new(1, 1); if (!ee) error_and_abort(ef, "Cannot create buffer engine canvas for image " "load.\n"); evas = ecore_evas_get(ee); for (i = 0; i < edje_file->image_dir->entries_count; i++) { img = &edje_file->image_dir->entries[i]; if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) { } else { Evas_Object *im; Eina_List *ll; char *data; int load_err = EVAS_LOAD_ERROR_NONE; im = NULL; EINA_LIST_FOREACH(img_dirs, ll, data) { char buf[4096]; snprintf(buf, sizeof(buf), "%s/%s", data, img->entry); im = evas_object_image_add(evas); if (im) { evas_object_image_file_set(im, buf, NULL); load_err = evas_object_image_load_error_get(im); if (load_err == EVAS_LOAD_ERROR_NONE) break; evas_object_del(im); im = NULL; if (load_err != EVAS_LOAD_ERROR_DOES_NOT_EXIST) break; } } if ((!im) && (load_err == EVAS_LOAD_ERROR_DOES_NOT_EXIST)) { im = evas_object_image_add(evas); if (im) { evas_object_image_file_set(im, img->entry, NULL); load_err = evas_object_image_load_error_get(im); if (load_err != EVAS_LOAD_ERROR_NONE) { evas_object_del(im); im = NULL; } } } if (im) { void *im_data; int im_w, im_h; int im_alpha; char buf[256]; evas_object_image_size_get(im, &im_w, &im_h); im_alpha = evas_object_image_alpha_get(im); im_data = evas_object_image_data_get(im, 0); if ((im_data) && (im_w > 0) && (im_h > 0)) { int mode, qual; snprintf(buf, sizeof(buf), "edje/images/%i", img->id); qual = 80; if ((img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) && (img->source_param == 0)) mode = 0; /* RAW */ else if ((img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) && (img->source_param == 1)) mode = 1; /* COMPRESS */ else mode = 2; /* LOSSY */ if ((mode == 0) && (no_raw)) { mode = 1; /* promote compression */ img->source_param = 95; } if ((mode == 2) && (no_lossy)) mode = 1; /* demote compression */ if ((mode == 1) && (no_comp)) { if (no_lossy) mode = 0; /* demote compression */ else if (no_raw) { img->source_param = 90; mode = 2; /* no choice. lossy */ } } if (mode == 2) { qual = img->source_param; if (qual < min_quality) qual = min_quality; if (qual > max_quality) qual = max_quality; } if (mode == 0) bytes = eet_data_image_write(ef, buf, im_data, im_w, im_h, im_alpha, 0, 0, 0); else if (mode == 1) bytes = eet_data_image_write(ef, buf, im_data, im_w, im_h, im_alpha, 1, 0, 0); else if (mode == 2) bytes = eet_data_image_write(ef, buf, im_data, im_w, im_h, im_alpha, 0, qual, 1); if (bytes <= 0) error_and_abort(ef, "Unable to write image part " "\"%s\" as \"%s\" part entry to " "%s\n", img->entry, buf, file_out); *image_num += 1; total_bytes += bytes; } else { error_and_abort_image_load_error (ef, img->entry, load_err); } if (verbose) { struct stat st; const char *file = NULL; evas_object_image_file_get(im, &file, NULL); if (!file || (stat(file, &st) != 0)) st.st_size = 0; *input_bytes += st.st_size; *input_raw_bytes += im_w * im_h * 4; printf("%s: Wrote %9i bytes (%4iKb) for \"%s\" image entry \"%s\" compress: [raw: %2.1f%%] [real: %2.1f%%]\n", progname, bytes, (bytes + 512) / 1024, buf, img->entry, 100 - (100 * (double)bytes) / ((double)(im_w * im_h * 4)), 100 - (100 * (double)bytes) / ((double)(st.st_size)) ); } evas_object_del(im); } else { error_and_abort_image_load_error (ef, img->entry, load_err); } } } ecore_evas_free(ee); ecore_evas_shutdown(); ecore_shutdown(); } return total_bytes; } static void check_groups(Eet_File *ef) { Edje_Part_Collection *pc; Eina_List *l; /* sanity checks for parts and programs */ EINA_LIST_FOREACH(edje_collections, l, pc) { unsigned int i; for (i = 0; i < pc->parts_count; ++i) check_part(pc, pc->parts[i], ef); #define CHECK_PROGRAM(Type, Pc, It) \ for (It = 0; It < Pc->programs.Type ## _count; ++It) \ check_program(Pc, Pc->programs.Type[i], ef); \ CHECK_PROGRAM(fnmatch, pc, i); CHECK_PROGRAM(strcmp, pc, i); CHECK_PROGRAM(strncmp, pc, i); CHECK_PROGRAM(strrncmp, pc, i); CHECK_PROGRAM(nocmp, pc, i); } } static int data_write_groups(Eet_File *ef, int *collection_num) { Eina_List *l; Edje_Part_Collection *pc; int bytes = 0; int total_bytes = 0; EINA_LIST_FOREACH(edje_collections, l, pc) { char buf[4096]; snprintf(buf, sizeof(buf), "edje/collections/%i", pc->id); bytes = eet_data_write(ef, edd_edje_part_collection, buf, pc, 1); if (bytes <= 0) error_and_abort(ef, "Error. Unable to write \"%s\" part entry " "to %s\n", buf, file_out); *collection_num += 1; total_bytes += bytes; if (verbose) { printf("%s: Wrote %9i bytes (%4iKb) for \"%s\" collection entry\n", progname, bytes, (bytes + 512) / 1024, buf); } } return total_bytes; } static void create_script_file(Eet_File *ef, const char *filename, const Code *cd) { FILE *f = fopen(filename, "wb"); if (!f) error_and_abort(ef, "Unable to open temp file \"%s\" for script " "compilation.\n", filename); Eina_List *ll; Code_Program *cp; fprintf(f, "#include \n"); int ln = 2; if (cd->shared) { while (ln < (cd->l1 - 1)) { fprintf(f, " \n"); ln++; } { char *sp; int hash = 0; int newlined = 0; for (sp = cd->shared; *sp; sp++) { if ((sp[0] == '#') && (newlined)) { hash = 1; } newlined = 0; if (sp[0] == '\n') newlined = 1; if (!hash) fputc(sp[0], f); else if (sp[0] == '\n') hash = 0; } fputc('\n', f); } ln += cd->l2 - cd->l1 + 1; } EINA_LIST_FOREACH(cd->programs, ll, cp) { if (cp->script) { while (ln < (cp->l1 - 1)) { fprintf(f, " \n"); ln++; } /* FIXME: this prototype needs to be */ /* formalised and set in stone */ fprintf(f, "public _p%i(sig[], src[]) {", cp->id); { char *sp; int hash = 0; int newlined = 0; for (sp = cp->script; *sp; sp++) { if ((sp[0] == '#') && (newlined)) { hash = 1; } newlined = 0; if (sp[0] == '\n') newlined = 1; if (!hash) fputc(sp[0], f); else if (sp[0] == '\n') hash = 0; } } fprintf(f, "}"); ln += cp->l2 - cp->l1 + 1; } } fclose(f); } static void compile_script_file(Eet_File *ef, const char *source, const char *output, int script_num) { FILE *f; char buf[4096]; int ret; snprintf(buf, sizeof(buf), "embryo_cc -i %s/include -o %s %s", eina_prefix_data_get(pfx), output, source); ret = system(buf); /* accept warnings in the embryo code */ if (ret < 0 || ret > 1) error_and_abort(ef, "Compiling script code not clean.\n"); f = fopen(output, "rb"); if (!f) error_and_abort(ef, "Unable to open script object \"%s\" for reading.\n", output); fseek(f, 0, SEEK_END); int size = ftell(f); rewind(f); if (size > 0) { void *data = malloc(size); if (data) { if (fread(data, size, 1, f) != 1) error_and_abort(ef, "Unable to read all of script object " "\"%s\"\n", output); snprintf(buf, sizeof(buf), "edje/scripts/embryo/compiled/%i", script_num); eet_write(ef, buf, data, size, 1); free(data); } } fclose(f); } static void data_write_scripts(Eet_File *ef) { Eina_List *l; int i; if (!tmp_dir) #ifdef HAVE_EVIL tmp_dir = (char *)evil_tmpdir_get(); #else tmp_dir = "/tmp"; #endif for (i = 0, l = codes; l; l = eina_list_next(l), i++) { char tmpn[PATH_MAX]; char tmpo[PATH_MAX]; char buf[PATH_MAX]; int fd; Code *cd = eina_list_data_get(l); Eina_List *ll; Code_Program *cp; if (cd->is_lua) continue; if ((!cd->shared) && (!cd->programs)) continue; snprintf(tmpn, PATH_MAX, "%s/edje_cc.sma-tmp-XXXXXX", tmp_dir); fd = mkstemp(tmpn); if (fd < 0) error_and_abort(ef, "Unable to open temp file \"%s\" for script " "compilation.\n", tmpn); create_script_file(ef, tmpn, cd); close(fd); snprintf(tmpo, PATH_MAX, "%s/edje_cc.amx-tmp-XXXXXX", tmp_dir); fd = mkstemp(tmpo); if (fd < 0) { unlink(tmpn); error_and_abort(ef, "Unable to open temp file \"%s\" for script " "compilation.\n", tmpn); } compile_script_file(ef, tmpn, tmpo, i); close(fd); unlink(tmpn); unlink(tmpo); if (cd->original) { snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i", i); eet_write(ef, buf, cd->original, strlen(cd->original) + 1, 1); } EINA_LIST_FOREACH(cd->programs, ll, cp) { if (!cp->original) continue; snprintf(buf, PATH_MAX, "edje/scripts/embryo/source/%i/%i", i, cp->id); eet_write(ef, buf, cp->original, strlen(cp->original) + 1, 1); } } } typedef struct _Edje_Lua_Script_Writer_Struct Edje_Lua_Script_Writer_Struct; struct _Edje_Lua_Script_Writer_Struct { char *buf; int size; }; #ifdef LUA_BINARY static int _edje_lua_script_writer(lua_State *L __UNUSED__, const void *chunk_buf, size_t chunk_size, void *_data) { Edje_Lua_Script_Writer_Struct *data; void *old; data = (Edje_Lua_Script_Writer_Struct *)_data; old = data->buf; data->buf = malloc (data->size + chunk_size); memcpy (data->buf, old, data->size); memcpy (&((data->buf)[data->size]), chunk_buf, chunk_size); if (old) free (old); data->size += chunk_size; return 0; } #endif void _edje_lua_error_and_abort(lua_State * L, int err_code, Eet_File *ef) { char *err_type; switch (err_code) { case LUA_ERRRUN: err_type = "runtime"; break; case LUA_ERRSYNTAX: err_type = "syntax"; break; case LUA_ERRMEM: err_type = "memory allocation"; break; case LUA_ERRERR: err_type = "error handler"; break; default: err_type = "unknown"; break; } error_and_abort(ef, "Lua %s error: %s\n", err_type, lua_tostring(L, -1)); } static void data_write_lua_scripts(Eet_File *ef) { Eina_List *l; Eina_List *ll; Code_Program *cp; int i; for (i = 0, l = codes; l; l = eina_list_next(l), i++) { char buf[4096]; Code *cd; lua_State *L; int ln = 1; luaL_Buffer b; Edje_Lua_Script_Writer_Struct data; #ifdef LUA_BINARY int err_code; #endif cd = (Code *)eina_list_data_get(l); if (!cd->is_lua) continue; if ((!cd->shared) && (!cd->programs)) continue; L = luaL_newstate(); if (!L) error_and_abort(ef, "Lua error: Lua state could not be initialized\n"); luaL_buffinit(L, &b); data.buf = NULL; data.size = 0; if (cd->shared) { while (ln < (cd->l1 - 1)) { luaL_addchar(&b, '\n'); ln++; } luaL_addstring(&b, cd->shared); ln += cd->l2 - cd->l1; } EINA_LIST_FOREACH(cd->programs, ll, cp) { if (cp->script) { while (ln < (cp->l1 - 1)) { luaL_addchar(&b, '\n'); ln++; } luaL_addstring(&b, "_G["); lua_pushnumber(L, cp->id); luaL_addvalue(&b); luaL_addstring(&b, "] = function (ed, signal, source)"); luaL_addstring(&b, cp->script); luaL_addstring(&b, "end\n"); ln += cp->l2 - cp->l1 + 1; } } luaL_pushresult(&b); #ifdef LUA_BINARY if (err_code = luaL_loadstring(L, lua_tostring (L, -1))) _edje_lua_error_and_abort(L, err_code, ef); lua_dump(L, _edje_lua_script_writer, &data); #else // LUA_PLAIN_TEXT data.buf = (char *)lua_tostring(L, -1); data.size = strlen(data.buf); #endif //printf("lua chunk size: %d\n", data.size); /* * TODO load and test Lua chunk */ /* if (luaL_loadbuffer(L, globbuf, globbufsize, "edje_lua_script")) printf("lua load error: %s\n", lua_tostring (L, -1)); if (lua_pcall(L, 0, 0, 0)) printf("lua call error: %s\n", lua_tostring (L, -1)); */ snprintf(buf, sizeof(buf), "edje/scripts/lua/%i", i); eet_write(ef, buf, data.buf, data.size, 1); #ifdef LUA_BINARY free(data.buf); #endif lua_close(L); } } void data_write(void) { Eet_File *ef; int input_bytes = 0; int total_bytes = 0; int src_bytes = 0; int fmap_bytes = 0; int input_raw_bytes = 0; int image_num = 0; int font_num = 0; int collection_num = 0; if (!edje_file) { ERR("%s: Error. No data to put in \"%s\"", progname, file_out); exit(-1); } ef = eet_open(file_out, EET_FILE_MODE_WRITE); if (!ef) { ERR("%s: Error. Unable to open \"%s\" for writing output", progname, file_out); exit(-1); } check_groups(ef); total_bytes += data_write_header(ef); total_bytes += data_write_fonts(ef, &font_num, &input_bytes, &input_raw_bytes); total_bytes += data_write_images(ef, &image_num, &input_bytes, &input_raw_bytes); total_bytes += data_write_groups(ef, &collection_num); data_write_scripts(ef); data_write_lua_scripts(ef); src_bytes = source_append(ef); total_bytes += src_bytes; fmap_bytes = source_fontmap_save(ef, fonts); total_bytes += fmap_bytes; eet_close(ef); if (verbose) { struct stat st; if (stat(file_in, &st) != 0) st.st_size = 0; input_bytes += st.st_size; input_raw_bytes += st.st_size; printf("Summary:\n" " Wrote %i collections\n" " Wrote %i images\n" " Wrote %i fonts\n" " Wrote %i bytes (%iKb) of original source data\n" " Wrote %i bytes (%iKb) of original source font map\n" "Conservative compression summary:\n" " Wrote total %i bytes (%iKb) from %i (%iKb) input data\n" " Output file is %3.1f%% the size of the input data\n" " Saved %i bytes (%iKb)\n" "Raw compression summary:\n" " Wrote total %i bytes (%iKb) from %i (%iKb) raw input data\n" " Output file is %3.1f%% the size of the raw input data\n" " Saved %i bytes (%iKb)\n" , collection_num, image_num, font_num, src_bytes, (src_bytes + 512) / 1024, fmap_bytes, (fmap_bytes + 512) / 1024, total_bytes, (total_bytes + 512) / 1024, input_bytes, (input_bytes + 512) / 1024, (100.0 * (double)total_bytes) / (double)input_bytes, input_bytes - total_bytes, (input_bytes - total_bytes + 512) / 1024, total_bytes, (total_bytes + 512) / 1024, input_raw_bytes, (input_raw_bytes + 512) / 1024, (100.0 * (double)total_bytes) / (double)input_raw_bytes, input_raw_bytes - total_bytes, (input_raw_bytes - total_bytes + 512) / 1024); } } void data_queue_group_lookup(char *name) { Group_Lookup *gl; gl = mem_alloc(SZ(Group_Lookup)); group_lookups = eina_list_append(group_lookups, gl); gl->name = mem_strdup(name); } void data_queue_part_lookup(Edje_Part_Collection *pc, const char *name, int *dest) { Part_Lookup *pl; pl = mem_alloc(SZ(Part_Lookup)); part_lookups = eina_list_append(part_lookups, pl); pl->pc = pc; pl->name = mem_strdup(name); pl->dest = dest; } void data_queue_anonymous_lookup(Edje_Part_Collection *pc, Edje_Program *ep, int *dest) { Program_Lookup *pl; if (!ep) return ; /* FIXME: should we stop compiling ? */ pl = mem_alloc(SZ(Program_Lookup)); program_lookups = eina_list_append(program_lookups, pl); pl->pc = pc; pl->u.ep = ep; pl->dest = dest; pl->anonymous = EINA_TRUE; } void data_queue_program_lookup(Edje_Part_Collection *pc, const char *name, int *dest) { Program_Lookup *pl; if (!name) return ; /* FIXME: should we stop compiling ? */ pl = mem_alloc(SZ(Program_Lookup)); program_lookups = eina_list_append(program_lookups, pl); pl->pc = pc; pl->u.name = mem_strdup(name); pl->dest = dest; pl->anonymous = EINA_FALSE; } void data_queue_image_lookup(char *name, int *dest, Eina_Bool *set) { Image_Lookup *il; il = mem_alloc(SZ(Image_Lookup)); image_lookups = eina_list_append(image_lookups, il); il->name = mem_strdup(name); il->dest = dest; il->set = set; } void data_queue_part_slave_lookup(int *master, int *slave) { Slave_Lookup *sl; sl = mem_alloc(SZ(Slave_Lookup)); part_slave_lookups = eina_list_append(part_slave_lookups, sl); sl->master = master; sl->slave = slave; } void data_queue_image_slave_lookup(int *master, int *slave) { Slave_Lookup *sl; sl = mem_alloc(SZ(Slave_Lookup)); image_slave_lookups = eina_list_append(image_slave_lookups, sl); sl->master = master; sl->slave = slave; } void handle_slave_lookup(Eina_List *list, int *master, int value) { Eina_List *l; Slave_Lookup *sl; EINA_LIST_FOREACH(list, l, sl) if (sl->master == master) *sl->slave = value; } void data_process_lookups(void) { Edje_Part_Collection *pc; Part_Lookup *part; Program_Lookup *program; Group_Lookup *group; Image_Lookup *image; Eina_List *l; void *data; EINA_LIST_FOREACH(edje_collections, l, pc) { unsigned int count = 0; unsigned int i; #define PROGRAM_ID_SET(Type, Pc, It, Count) \ for (It = 0; It < Pc->programs.Type ## _count; ++It) \ { \ Pc->programs.Type[It]->id = Count++; \ } PROGRAM_ID_SET(fnmatch, pc, i, count); PROGRAM_ID_SET(strcmp, pc, i, count); PROGRAM_ID_SET(strncmp, pc, i, count); PROGRAM_ID_SET(strrncmp, pc, i, count); PROGRAM_ID_SET(nocmp, pc, i, count); #undef PROGRAM_ID_SET } EINA_LIST_FREE(part_lookups, part) { Edje_Part *ep; unsigned int i; for (i = 0; i < part->pc->parts_count; ++i) { ep = part->pc->parts[i]; if ((ep->name) && (!strcmp(ep->name, part->name))) { handle_slave_lookup(part_slave_lookups, part->dest, ep->id); *(part->dest) = ep->id; break; } } if (i == part->pc->parts_count) { ERR("%s: Error. Unable to find part name \"%s\".", progname, part->name); exit(-1); } free(part->name); free(part); } EINA_LIST_FREE(program_lookups, program) { unsigned int i; Eina_Bool find = EINA_FALSE; #define PROGRAM_MATCH(Type, Pl, It) \ for (It = 0; It < Pl->pc->programs.Type ## _count; ++It) \ { \ Edje_Program *ep; \ \ ep = Pl->pc->programs.Type[It]; \ \ if ((Pl->anonymous && ep == Pl->u.ep) || \ ((!Pl->anonymous) && (ep->name) && (!strcmp(ep->name, Pl->u.name)))) \ { \ *(Pl->dest) = ep->id; \ find = EINA_TRUE; \ break; \ } \ } PROGRAM_MATCH(fnmatch, program, i); PROGRAM_MATCH(strcmp, program, i); PROGRAM_MATCH(strncmp, program, i); PROGRAM_MATCH(strrncmp, program, i); PROGRAM_MATCH(nocmp, program, i); #undef PROGRAM_MATCH if (!find) { if (!program->anonymous) ERR("%s: Error. Unable to find program name \"%s\".", progname, program->u.name); else ERR("%s: Error. Unable to find anonymous program.", progname); exit(-1); } if (!program->anonymous) free(program->u.name); free(program); } EINA_LIST_FREE(group_lookups, group) { Edje_Part_Collection_Directory_Entry *de; de = eina_hash_find(edje_file->collection, group->name); if (!de) { ERR("%s: Error. Unable to find group name \"%s\".", progname, group->name); exit(-1); } free(group->name); free(group); } EINA_LIST_FREE(image_lookups, image) { Edje_Image_Directory_Entry *de; Eina_Bool find = EINA_FALSE; if (edje_file->image_dir) { unsigned int i; for (i = 0; i < edje_file->image_dir->entries_count; ++i) { de = edje_file->image_dir->entries + i; if ((de->entry) && (!strcmp(de->entry, image->name))) { handle_slave_lookup(image_slave_lookups, image->dest, de->id); if (de->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) *(image->dest) = -de->id - 1; else *(image->dest) = de->id; *(image->set) = EINA_FALSE; find = EINA_TRUE; break; } } if (!find) { Edje_Image_Directory_Set *set; for (i = 0; i < edje_file->image_dir->sets_count; ++i) { set = edje_file->image_dir->sets + i; if ((set->name) && (!strcmp(set->name, image->name))) { handle_slave_lookup(image_slave_lookups, image->dest, set->id); *(image->dest) = set->id; *(image->set) = EINA_TRUE; find = EINA_TRUE; break; } } } } if (!find) { ERR("%s: Error. Unable to find image name \"%s\".", progname, image->name); exit(-1); } free(image->name); free(image); } EINA_LIST_FREE(part_slave_lookups, data) free(data); EINA_LIST_FREE(image_slave_lookups, data) free(data); } 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)) { char *p; char *key; int keyl; int quote, escape; key = alloca(strlen(prefix) + 2 + 1); if (!key) return; strcpy(key, prefix); strcat(key, ":\""); keyl = strlen(key); quote = 0; escape = 0; for (p = s; (p) && (*p); p++) { if (!quote) { if (*p == '\"') { quote = 1; p++; } } if (!quote) { if (!strncmp(p, key, keyl)) { char *ptr; int len; int inesc = 0; char *name; ptr = p; p += keyl; while ((*p)) { if (!inesc) { if (*p == '\\') inesc = 1; else if (*p == '\"') { /* string concatenation, see below */ if (*(p + 1) != '\"') break; else p++; } } else inesc = 0; p++; } len = p - ptr + 1; name = alloca(len); if (name) { char *pp; int i; name[0] = 0; pp = ptr + keyl; inesc = 0; i = 0; while (*pp) { if (!inesc) { if (*pp == '\\') inesc = 1; else if (*pp == '\"') { /* concat strings like "foo""bar" to "foobar" */ if (*(pp + 1) == '\"') pp++; else { name[i] = 0; break; } } else { name[i] = *pp; name[i + 1] = 0; i++; } } else inesc = 0; pp++; } func(pc, name, ptr, len); } } } else { if (!escape) { if (*p == '\"') quote = 0; else if (*p == '\\') escape = 1; } else if (escape) { escape = 0; } } } } static void _data_queue_part_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len) { Code_Lookup *cl; cl = mem_alloc(SZ(Code_Lookup)); cl->ptr = ptr; cl->len = len; data_queue_part_lookup(pc, name, &(cl->val)); code_lookups = eina_list_append(code_lookups, cl); } static void _data_queue_program_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len) { Code_Lookup *cl; cl = mem_alloc(SZ(Code_Lookup)); cl->ptr = ptr; cl->len = len; data_queue_program_lookup(pc, name, &(cl->val)); code_lookups = eina_list_append(code_lookups, cl); } static void _data_queue_group_lookup(Edje_Part_Collection *pc __UNUSED__, char *name, char *ptr __UNUSED__, int len __UNUSED__) { data_queue_group_lookup(name); } static void _data_queue_image_pc_lookup(Edje_Part_Collection *pc __UNUSED__, char *name, char *ptr, int len) { Code_Lookup *cl; cl = mem_alloc(SZ(Code_Lookup)); cl->ptr = ptr; cl->len = len; data_queue_image_lookup(name, &(cl->val), &(cl->set)); code_lookups = eina_list_append(code_lookups, cl); } void data_process_scripts(void) { Eina_List *l, *l2; for (l = codes, l2 = edje_collections; (l) && (l2); l = eina_list_next(l), l2 = eina_list_next(l2)) { Edje_Part_Collection *pc; Code *cd; cd = eina_list_data_get(l); pc = eina_list_data_get(l2); if ((cd->shared) && (!cd->is_lua)) { data_process_string(pc, "PART", cd->shared, _data_queue_part_lookup); data_process_string(pc, "PROGRAM", cd->shared, _data_queue_program_lookup); data_process_string(pc, "IMAGE", cd->shared, _data_queue_image_pc_lookup); data_process_string(pc, "GROUP", cd->shared, _data_queue_group_lookup); } if (cd->programs) { Code_Program *cp; Eina_List *ll; EINA_LIST_FOREACH(cd->programs, ll, cp) { if (cp->script) { data_process_string(pc, "PART", cp->script, _data_queue_part_lookup); data_process_string(pc, "PROGRAM", cp->script, _data_queue_program_lookup); data_process_string(pc, "IMAGE", cp->script, _data_queue_image_pc_lookup); data_process_string(pc, "GROUP", cp->script, _data_queue_group_lookup); } } } } } void data_process_script_lookups(void) { Eina_List *l; Code_Lookup *cl; EINA_LIST_FOREACH(code_lookups, l, cl) { char buf[12]; int n; /* FIXME !! Handle set in program */ n = eina_convert_itoa(cl->val, buf); if (n > cl->len) { ERR("%s: Error. The unexpected happened. A numeric replacement string was larger than the original!", progname); exit(-1); } memset(cl->ptr, ' ', cl->len); strncpy(cl->ptr, buf, n); } }