/* $Id: gzip.c,v 1.3 2021/11/06 17:35:07 khorben Exp $ */ /* Copyright (c) 2010 khorben of UberWall */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "plugin.h" /* gzip */ /* public */ /* types */ #pragma pack(1) struct gzip { uint16_t magic; uint8_t method; uint8_t flags; uint32_t mtime; uint8_t deflate; uint8_t os; }; #pragma pack() /* variables */ /* magic */ static unsigned char sig[] = "\x1f\x8b"; static PluginMagic gzip_magic[] = { { sizeof(struct gzip), 0, sig, sizeof(sig)-1 }, { 0, 0, NULL, 0 } }; /* functions */ static int gzip_callback(PluginHelper * ph, int signature, FILE * fp); /* plugin */ Plugin plugin = { PT_ARCHIVE | PT_COMPRESSION, "GZIP", gzip_magic, gzip_callback }; /* private */ /* functions */ /* gzip_callback */ static int _callback_method(PluginHelper * ph, uint8_t method); static int _callback_flags(PluginHelper * ph, uint8_t flags); static int _callback_mtime(PluginHelper * ph, time_t mtime); static int _callback_deflate(uint8_t method, uint8_t deflate); static int _callback_os(PluginHelper * ph, uint8_t os); static int _callback_extract(PluginHelper * ph, FILE * fp, struct gzip * hdr); static int gzip_callback(PluginHelper * ph, int signature, FILE * fp) { int score = 0; struct gzip hdr; (void) signature; if(fread(&hdr, sizeof(hdr), 1, fp) != 1) return -1; score += _callback_method(ph, hdr.method); score += _callback_flags(ph, hdr.flags); score += _callback_mtime(ph, hdr.mtime); score += _callback_deflate(hdr.method, hdr.deflate); score += _callback_os(ph, hdr.os); ph->printf(ph, "\n"); _callback_extract(ph, fp, &hdr); return score / 5; } static int _callback_method(PluginHelper * ph, uint8_t method) { struct { int method; char * string; int score; } name[] = { { 0x08, "deflate", 100 }, { -1, "unknown", 30 } }; unsigned int i; for(i = 0; name[i].method != -1 && method != name[i].method; i++); ph->printf(ph, "%s%s", "compression ", name[i].string); return name[i].score; } static int _callback_flags(PluginHelper * ph, uint8_t flags) { struct { uint8_t flag; char * string; } name[] = { { 0x01, "FTEXT" }, { 0x02, "FHCRC" }, { 0x04, "FEXTRA" }, { 0x08, "FNAME" }, { 0x10, "FCOMMENT" }, { 0x00, NULL } }; unsigned int i; char * prefix = ", flags"; for(i = 0; name[i].string != NULL; i++) { if((flags & name[i].flag) != name[i].flag) continue; ph->printf(ph, "%s %s", prefix, name[i].string); prefix = ""; } if(prefix[0] != '\0') ph->printf(ph, "%s", ", no flags"); return flags & 0xe0 ? 30 : 100; } static int _callback_mtime(PluginHelper * ph, time_t mtime) /* FIXME implement endian interpretation */ { struct tm tm; char tmp[22] = ""; if(mtime == 0) return 100; if(gmtime_r(&mtime, &tm) == NULL || strftime(tmp, sizeof(tmp), ", %d/%m/%Y %H:%M:%S", &tm) == 0) { ph->printf(ph, "%s", ", unknown date"); return 0; } ph->printf(ph, "%s", tmp); /* between Wed May 1 00:00:00 CEST 1996 and now */ return mtime > 830901600 && mtime < time(NULL) ? 100 : 0; } static int _callback_deflate(uint8_t method, uint8_t deflate) { if(method == 0) return 0; if(deflate != 0x02 && deflate != 0x04) return 0; return 100; } static int _callback_os(PluginHelper * ph, uint8_t os) { struct { int os; char * string; int score; } name[] = { { 0, "MS-DOS or OS/2 or NT/Win32 on FAT", 100 }, { 1, "Amiga", 30 }, { 2, "VMS or OpenVMS", 30 }, { 3, "Unix", 100 }, { 4, "VM/CMS", 30 }, { 5, "Atari TOS", 30 }, { 6, "OS/2 or NT on HPFS", 100 }, { 7, "Macintosh", 100 }, { 8, "Z-System", 30 }, { 9, "CP/M", 30 }, { 10, "TOPS-20", 30 }, { 11, "NT on NTFS", 100 }, { 12, "QDOS", 30 }, { 13, "Acorn RISCOS", 100 }, { -1, "unknown", 20 } }; unsigned int i; for(i = 0; name[i].os != -1 && os != name[i].os; i++); ph->printf(ph, "%s%s", ", OS ", name[i].string); return name[i].score; } static int _callback_extract(PluginHelper * ph, FILE * fp, struct gzip * hdr) { FILE * xfp; char buf[1024]; size_t i; if((xfp = ph->fopen(ph, "GZIP")) == NULL) /* XXX fetch filename */ return -1; if(ph->fwrite(hdr, sizeof(*hdr), 1, xfp) != 1) return -1; while((i = fread(buf, sizeof(char), sizeof(buf), fp)) > 0) if(ph->fwrite(buf, sizeof(char), i, xfp) != i) break; return ph->fclose(xfp); }