From f076a6cccee804712f049d72c4fa12627992e200 Mon Sep 17 00:00:00 2001 From: Sergey Kvachonok Date: Wed, 11 Aug 2010 18:41:52 +0300 Subject: [PATCH] Add MGD to PNG extraction filter. --- fjfix.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 6 deletions(-) diff --git a/fjfix.c b/fjfix.c index 2cab963..d831530 100644 --- a/fjfix.c +++ b/fjfix.c @@ -202,6 +202,15 @@ unsigned fjentry_size(fjentry_t s) return s->fjfile->tab[s->tabind].data_size; } +int fjentry_seek(fjentry_t s, unsigned seekpos) +{ + if (seekpos > s->fjfile->tab[s->tabind].data_size) + return -1; + + s->seekpos = seekpos; + return 0; +} + unsigned fjentry_read(fjentry_t s, void* buf, unsigned size) { struct fjtabent* te = &s->fjfile->tab[s->tabind]; @@ -435,6 +444,8 @@ static int entry_extract(fjentry_t s, const char* fname) fjentry_name(s), fname, fjentry_size(s)); fflush(stdout); + fjentry_seek(s, 0); + size_t n, sz = 0; char buf[COPYBUF_SZ]; while ((n = fjentry_read(s, buf, sizeof(buf))) > 0) { @@ -459,7 +470,83 @@ err: return -1; } -static int extract(fjfile_t fjf, const char* destdir) +#define MGDHDR_SZ 0x60 +#define MGD_MAGIC "MGD " + +struct mgdhdr +{ + char magic[4]; + char padding[MGDHDR_SZ - 8]; + unsigned png_size; +}; + +#define PNG_MAGIC "\x89PNG\r\n\x1A\n" + +static int filter_mgd_test(fjentry_t s) +{ + struct mgdhdr hdr; + unsigned sz; + + sz = fjentry_read(s, &hdr, sizeof(hdr)); + if (sz != sizeof(hdr)) + return 0; + + if (strncmp(hdr.magic, MGD_MAGIC, sizeof(hdr.magic))) + return 0; + + char magic[sizeof(PNG_MAGIC) - 1]; + sz = fjentry_read(s, magic, sizeof(magic)); + if (strncmp(magic, PNG_MAGIC, sizeof(magic))) + return 0; + + return 1; +} + +static int entry_mgd_extract(fjentry_t s, const char* fname) +{ + FILE* f = fopen(fname, "wb"); + if (!f) + goto err; + + struct mgdhdr hdr; + fjentry_seek(s, 0); + fjentry_read(s, &hdr, sizeof(hdr)); + + printf("PNG extracting '%s' to '%s', size %d bytes\n", + fjentry_name(s), fname, hdr.png_size); + fflush(stdout); + + size_t n, sz = 0; + char buf[COPYBUF_SZ]; + while ((n = fjentry_read(s, buf, sizeof(buf))) > 0) { + if (sz + n > hdr.png_size) + n = hdr.png_size - sz; + if (!n) + break; + if (fwrite(buf, n, 1, f) != 1) + goto err; + sz += n; + } + + fclose(f); + + if (sz != hdr.png_size) { + fprintf(stderr, "PNG extract truncated file '%s': %d of %d bytes written\n", + fjentry_name(s), sz, fjentry_size(s)); + return -1; + } + + return 0; +err: + if (f) + fclose(f); + fprintf(stderr, "Can't extract PNG to file '%s': %s\n", fname, strerror(errno)); + return -1; +} + +enum {EX_FILTER_MGD = 0x1}; + +static int extract(fjfile_t fjf, const char* destdir, unsigned filters) { char fname[PATH_MAX]; char* ddir = format_destdir(fjfile_name(fjf), destdir); @@ -471,8 +558,16 @@ static int extract(fjfile_t fjf, const char* destdir) fjentry_t ent; for (ent = fjfile_first_entry(fjf); ent; ent = fjentry_next(ent)) { - sprintf(fname, "%s/%s", ddir, fjentry_name(ent)); - entry_extract(ent, fname); + if ((filters & EX_FILTER_MGD) && filter_mgd_test(ent)) { + int l = sprintf(fname, "%s/%s.png", ddir, fjentry_name(ent)); + char* ext = fname + l - (sizeof(".mgd.png") - 1); + if (ext > fname && !strcasecmp(ext, ".mgd.png")) + strcpy(ext, ".png"); + entry_mgd_extract(ent, fname); + } else { + sprintf(fname, "%s/%s", ddir, fjentry_name(ent)); + entry_extract(ent, fname); + } } free(ddir); @@ -494,6 +589,7 @@ static const char* usage = " -t - test entry index, do not fix it. Enabled by default.\n" " -x - extract entries as files to DESTDIR or FILE.d if DESDIR not specified.\n" " -v - verbose. Print additional data which might be useful for problem analysis and reporting.\n" + " -G - additionally extract PNG files embedded in MGD container entries. Must be used with -x.\n" "Version " VERSION " built " __DATE__ "\n"; enum { @@ -505,12 +601,16 @@ enum { int main(int argc, char* argv[0]) { int opt; - int options = OPT_TEST | OPT_BACKUP; + unsigned options = OPT_TEST | OPT_BACKUP; + unsigned ext_filters = 0; int needfix = 0; char* fname; - while ((opt = getopt(argc, argv, "blvtfhx")) != -1) { + while ((opt = getopt(argc, argv, "Gblvtfhx")) != -1) { switch (opt) { + case 'G': + ext_filters |= EX_FILTER_MGD; + break; case 'b': options &= ~OPT_BACKUP; break; @@ -570,7 +670,7 @@ int main(int argc, char* argv[0]) if (optind + 1 < argc) destdir = argv[optind + 1]; - extract(fjf, destdir); + extract(fjf, destdir, ext_filters); } if (options & (OPT_TEST | OPT_FIX)) { -- 2.11.4.GIT