/* * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 */ /* ugly ugly. avert your eyes. */ #include "edje_decc.h" #include #include #include #include char *progname = NULL; char *file_in = NULL; Edje_File *edje_file = NULL; SrcFile_List *srcfiles = NULL; Font_List *fontlist = NULL; int line = 0; int decomp(void); void output(void); int e_file_is_dir(char *file); int e_file_mkdir(char *dir); int e_file_mkpath(char *path); static int compiler_cmd_is_sane(); static int root_filename_is_sane(); static void main_help(void) { printf ("Usage:\n" "\t%s input_file.edj \n" "\n" ,progname); } int main(int argc, char **argv) { int i; setlocale(LC_NUMERIC, "C"); progname = argv[0]; for (i = 1; i < argc; i++) { if (!file_in) file_in = argv[i]; } if (!file_in) { fprintf(stderr, "%s: Error: no input file specified.\n", progname); main_help(); exit(-1); } edje_init(); eet_init(); source_edd(); if (!decomp()) return -1; output(); eet_shutdown(); return 0; } int decomp(void) { Eet_File *ef; ef = eet_open(file_in, EET_FILE_MODE_READ); if (!ef) { printf("ERROR: cannot open %s\n", file_in); return 0; } srcfiles = source_load(ef); if (!srcfiles || !srcfiles->list) { printf("ERROR: %s has no decompile information\n", file_in); eet_close(ef); return 0; } if (!srcfiles->list->data || !root_filename_is_sane()) { printf("ERROR: Invalid root filename: '%s'\n", (char *) srcfiles->list->data); eet_close(ef); return 0; } edje_file = eet_data_read(ef, _edje_edd_edje_file, "edje_file"); if (!edje_file) { printf("ERROR: %s does not appear to be an edje file\n", file_in); eet_close(ef); return 0; } if (!edje_file->compiler) { edje_file->compiler = strdup("edje_cc"); } else if (!compiler_cmd_is_sane()) { printf("ERROR: invalid compiler executable: '%s'\n", edje_file->compiler); eet_close(ef); return 0; } fontlist = source_fontmap_load(ef); eet_close(ef); return 1; } void output(void) { Evas_List *l; Eet_File *ef; char *outdir, *p; p = strrchr(file_in, '/'); if (p) outdir = strdup(p + 1); else outdir = strdup(file_in); p = strrchr(outdir, '.'); if (p) *p = 0; e_file_mkpath(outdir); ef = eet_open(file_in, EET_FILE_MODE_READ); if (edje_file->image_dir) { for (l = edje_file->image_dir->entries; l; l = l->next) { Edje_Image_Directory_Entry *ei; ei = l->data; if ((ei->source_type) && (ei->entry)) { Ecore_Evas *ee; Evas *evas; Evas_Object *im; char buf[4096]; char out[4096]; char *pp; ecore_init(); ecore_evas_init(); ee = ecore_evas_buffer_new(1, 1); if (!ee) { fprintf(stderr, "Error. cannot create buffer engine canvas for image save.\n"); exit(-1); } evas = ecore_evas_get(ee); im = evas_object_image_add(evas); if (!im) { fprintf(stderr, "Error. cannot create image object for save.\n"); exit(-1); } snprintf(buf, sizeof(buf), "images/%i", ei->id); evas_object_image_file_set(im, file_in, buf); snprintf(out, sizeof(out), "%s/%s", outdir, ei->entry); printf("Output Image: %s\n", out); pp = strdup(out); p = strrchr(pp, '/'); *p = 0; if (strstr(pp, "../")) { printf("ERROR: potential security violation. attempt to write in parent dir.\n"); exit(-1); } e_file_mkpath(pp); free(pp); if (!evas_object_image_save(im, out, NULL, "quality=100 compress=9")) { printf("ERROR: cannot write file %s. Perhaps missing JPEG or PNG saver modules for Evas.\n", out); exit(-1); } evas_object_del(im); ecore_evas_free(ee); ecore_evas_shutdown(); ecore_shutdown(); } } } for (l = srcfiles->list; l; l = l->next) { SrcFile *sf; char out[4096]; FILE *f; char *pp; sf = l->data; snprintf(out, sizeof(out), "%s/%s", outdir, sf->name); printf("Output Source File: %s\n", out); pp = strdup(out); p = strrchr(pp, '/'); *p = 0; if (strstr(pp, "../")) { printf("ERROR: potential security violation. attempt to write in parent dir.\n"); exit (-1); } e_file_mkpath(pp); free(pp); if (strstr(out, "../")) { printf("ERROR: potential security violation. attempt to write in parent dir.\n"); exit (-1); } f = fopen(out, "w"); if (!f) { printf("ERROR: unable to write file (%s).\n", out); exit (-1); } /* if the file is empty, sf->file will be NULL. * note that that's not an error */ if (sf->file) fputs(sf->file, f); fclose(f); } if (fontlist) { for (l = fontlist->list; l; l = l->next) { Font *fn; void *font; int fontsize; char out[4096]; fn = l->data; snprintf(out, sizeof(out), "fonts/%s", fn->name); font = eet_read(ef, out, &fontsize); if (font) { FILE *f; char *pp; snprintf(out, sizeof(out), "%s/%s", outdir, fn->file); printf("Output Font: %s\n", out); pp = strdup(out); p = strrchr(pp, '/'); *p = 0; if (strstr(pp, "../")) { printf("ERROR: potential security violation. attempt to write in parent dir.\n"); exit (-1); } e_file_mkpath(pp); free(pp); if (strstr(out, "../")) { printf("ERROR: potential security violation. attempt to write in parent dir.\n"); exit (-1); } f = fopen(out, "wb"); fwrite(font, fontsize, 1, f); fclose(f); free(font); } } } { char out[4096]; FILE *f; SrcFile *sf = srcfiles->list->data; snprintf(out, sizeof(out), "%s/build.sh", outdir); printf("Output Build Script: %s\n", out); if (strstr(out, "../")) { printf("ERROR: potential security violation. attempt to write in parent dir.\n"); exit (-1); } f = fopen(out, "w"); fprintf(f, "#!/bin/sh\n"); fprintf(f, "%s $@ -id . -fd . %s -o %s.edj\n", edje_file->compiler, sf->name, outdir); fclose(f); #ifndef WIN32 chmod(out, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP); #endif printf("\n*** CAUTION ***\n" "Please check the build script for anything malicious " "before running it!\n\n"); } eet_close(ef); } int e_file_is_dir(char *file) { struct stat st; if (stat(file, &st) < 0) return 0; if (S_ISDIR(st.st_mode)) return 1; return 0; } int e_file_mkdir(char *dir) { #ifndef WIN32 static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; if (mkdir(dir, default_mode) < 0) return 0; #else if (mkdir(dir) < 0) return 0; #endif return 1; } int e_file_mkpath(char *path) { char ss[PATH_MAX]; int i, ii; ss[0] = 0; i = 0; ii = 0; while (path[i]) { if (ii == sizeof(ss) - 1) return 0; ss[ii++] = path[i]; ss[ii] = 0; if (path[i] == '/') { if (!e_file_is_dir(ss)) e_file_mkdir(ss); else if (!e_file_is_dir(ss)) return 0; } i++; } if (!e_file_is_dir(ss)) e_file_mkdir(ss); else if (!e_file_is_dir(ss)) return 0; return 1; } static int compiler_cmd_is_sane() { char *c = edje_file->compiler, *ptr; if (!c || !*c) { return 0; } for (ptr = c; ptr && *ptr; ptr++) { /* only allow [a-z][A-Z][0-9]_- */ if (!isalnum(*ptr) && *ptr != '_' && *ptr != '-') { return 0; } } return 1; } static int root_filename_is_sane() { SrcFile *sf = srcfiles->list->data; char *f = sf->name, *ptr; if (!f || !*f) { return 0; } for (ptr = f; ptr && *ptr; ptr++) { /* only allow [a-z][A-Z][0-9]_-./ */ switch (*ptr) { case '_': case '-': case '.': case '/': break; default: if (!isalnum(*ptr)) { return 0; } } } return 1; }