ÜberWall

UWfirmforce

/* $Id: zip.c,v 1.1 2009/02/21 21:25:21 khorben Exp $ */
/* Copyright (c) 2007 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 <stdint.h>
#include <stdlib.h>
#include <time.h>
#include "plugin.h"
/* zip */
/* public */
/* types */
#pragma pack(1)
struct zip_lfh
{
unsigned char signature[4];
uint16_t version;
uint16_t general;
uint16_t method;
uint16_t mtime;
uint16_t mdate;
uint32_t crc;
uint32_t csize;
uint32_t usize;
uint16_t filename;
uint16_t extra;
};
struct zip_dd
{
unsigned char signature[4]; /* XXX may not be present */
uint32_t crc;
uint32_t csize;
uint32_t usize;
};
struct zip64_dd
{
unsigned char signature[4]; /* XXX may not be present */
uint32_t crc;
uint64_t csize;
uint64_t usize;
};
struct zip_xd
{
unsigned char signature[4];
uint32_t length;
};
struct zip_cdfh
{
unsigned char signature[4];
uint16_t version;
uint16_t needed;
uint16_t general;
uint16_t method;
uint16_t mtime;
uint16_t mdate;
uint32_t crc;
uint32_t csize;
uint32_t usize;
uint16_t filename;
uint16_t extra;
uint16_t comment;
uint16_t disk;
uint16_t internal;
uint32_t external;
uint32_t offset;
};
struct zip_ds
{
unsigned char signature[4];
uint16_t length;
};
struct zip_ecdr
{
unsigned char signature[4];
uint16_t disk;
uint16_t start;
uint16_t diskentries;
uint16_t entries;
uint32_t size;
uint32_t offset;
uint16_t comment;
};
#pragma pack()
/* constants */
enum
{
ZIP_LFH = 0, /* local file header */
ZIP_DD, /* data descriptor */
ZIP_XD, /* extra data */
ZIP_CDFH, /* central directory file header */
ZIP_DS, /* digital signature */
ZIP64_ECDR, /* zip64 end of central directory record */
ZIP64_ECDL, /* zip64 end of central directory locator */
ZIP_ECDR /* end of central directory record */
};
/* variables */
/* magic */
static unsigned char siglfh[] = "PK\x03\x04";
static unsigned char sigdd[] = "PK\x07\x08";
static unsigned char sigxd[] = "PK\x06\x08";
static unsigned char sigcdfh[] = "PK\x01\x02";
static unsigned char sigds[] = "PK\x05\x05";
static unsigned char sig64ecdr[] = "PK\x06\x06";
static unsigned char sig64ecdl[] = "PK\x06\x07";
static unsigned char sigecdr[] = "PK\x05\x06";
PluginMagic zip_magic[] =
{
{ 4, 0, siglfh, sizeof(siglfh)-1 },
{ 4, 0, sigdd, sizeof(sigdd)-1 },
{ 4, 0, sigxd, sizeof(sigxd)-1 },
{ 4, 0, sigcdfh, sizeof(sigcdfh)-1 },
{ 4, 0, sigds, sizeof(sigds)-1 },
{ 4, 0, sig64ecdr, sizeof(sig64ecdr)-1 },
{ 4, 0, sig64ecdl, sizeof(sig64ecdl)-1 },
{ 4, 0, sigecdr, sizeof(sigecdr)-1 },
{ 0, 0, NULL, 0 }
};
/* functions */
static int zip_callback(PluginHelper * ph, int signature, FILE * fp);
/* plugin */
Plugin plugin =
{
PT_ARCHIVE | PT_COMPRESSION,
"ZIP",
zip_magic,
zip_callback
};
/* private */
/* functions */
static int _zip_version(PluginHelper * ph, uint16_t version);
static int _zip_general(PluginHelper * ph, uint16_t general);
static int _zip_method(PluginHelper * ph, uint16_t method);
static int _zip_mdatetime(PluginHelper * ph, uint16_t date, uint16_t time);
static int _zip_size(PluginHelper * ph, uint32_t csize, uint32_t usize);
static int _zip_filename(PluginHelper * ph, uint16_t length, FILE * fp);
static int _zip_comment(PluginHelper * ph, uint16_t length, FILE * fp);
/* zip_callback */
static int _callback_lfh(PluginHelper * ph, FILE * fp);
static int _callback_dd(PluginHelper * ph, FILE * fp);
static int _callback_xd(PluginHelper * ph, FILE * fp);
static int _callback_cdfh(PluginHelper * ph, FILE * fp);
static int _callback_ds(PluginHelper * ph, FILE * fp);
static int _callback_ecdr(PluginHelper * ph, FILE * fp);
static int zip_callback(PluginHelper * ph, int signature, FILE * fp)
{
struct
{
int signature;
char * string;
} name[] =
{
{ ZIP_LFH, "local file header" },
{ ZIP_DD, "data descriptor" },
{ ZIP_XD, "extra data", },
{ ZIP_CDFH, "central directory file header" },
{ ZIP_DS, "digital signature", },
{ ZIP64_ECDR, "zip64 end of central directory record" },
{ ZIP64_ECDL, "zip64 end of central directory locator"},
{ ZIP_ECDR, "end of central directory record" },
{ -1, "unknown" }
};
size_t i;
for(i = 0; name[i].signature != -1 && signature != name[i].signature;
i++);
ph->printf(ph, "%s", name[i].string);
switch(signature)
{
case ZIP_LFH:
return _callback_lfh(ph, fp);
case ZIP_DD:
return _callback_dd(ph, fp);
case ZIP_XD:
return _callback_xd(ph, fp);
case ZIP_CDFH:
return _callback_cdfh(ph, fp);
case ZIP_DS:
return _callback_ds(ph, fp);
case ZIP_ECDR:
return _callback_ecdr(ph, fp);
default:
break; /* FIXME implement */
}
ph->printf(ph, "%s", ", not implemented\n");
return 0;
}
static int _callback_lfh(PluginHelper * ph, FILE * fp)
{
int score = 0;
struct zip_lfh buf;
if(fread(&buf, sizeof(buf), 1, fp) != 1)
return -1;
score += _zip_version(ph, buf.version);
score += _zip_general(ph, buf.general);
score += _zip_method(ph, buf.method);
score += _zip_mdatetime(ph, buf.mdate, buf.mtime);
score += _zip_size(ph, buf.csize, buf.usize);
score += _zip_filename(ph, buf.filename, fp);
ph->printf(ph, "\n");
return score / 6;
}
static int _callback_dd(PluginHelper * ph, FILE * fp)
{
int score = 0;
struct zip_dd buf;
if(fread(&buf, sizeof(buf), 1, fp) != 1)
return -1;
score += _zip_size(ph, buf.csize, buf.usize);
ph->printf(ph, "\n");
return score;
}
static int _callback_xd(PluginHelper * ph, FILE * fp)
{
struct zip_xd buf;
if(fread(&buf, sizeof(buf), 1, fp) != 1)
return -1;
ph->printf(ph, "length %u\n", htol32(buf.length));
return 100;
}
static int _callback_cdfh(PluginHelper * ph, FILE * fp)
{
int score = 0;
struct zip_cdfh buf;
if(fread(&buf, sizeof(buf), 1, fp) != 1)
return -1;
score += _zip_version(ph, buf.version);
score += _zip_general(ph, buf.general);
score += _zip_method(ph, buf.method);
score += _zip_mdatetime(ph, buf.mdate, buf.mtime);
score += _zip_size(ph, buf.csize, buf.usize);
ph->printf(ph, "\n");
return score / 5;
}
static int _callback_ds(PluginHelper * ph, FILE * fp)
{
struct zip_ds buf;
if(fread(&buf, sizeof(buf), 1, fp) != 1)
return -1;
ph->printf(ph, "length %u\n", htol16(buf.length));
return 100;
}
static int _callback_ecdr(PluginHelper * ph, FILE * fp)
{
int score = 0;
struct zip_ecdr buf;
if(fread(&buf, sizeof(buf), 1, fp) != 1)
return -1;
score += _zip_comment(ph, buf.comment, fp);
ph->printf(ph, "\n");
return score;
}
/* _zip_version */
static int _zip_version(PluginHelper * ph, uint16_t version)
{
struct
{
int os;
char * string;
int score;
}
name[] =
{
{ 0, "MS-DOS and OS/2 (FAT/VFAT/FAT32)", 100 },
{ 1, "Amiga", 30 },
{ 2, "OpenVMS", 30 },
{ 3, "UNIX", 100 },
{ 4, "VM/CMS", 30 },
{ 5, "Atari ST", 30 },
{ 6, "OS/2 HPFS", 100 },
{ 7, "Macintosh", 100 },
{ 8, "Z-System", 30 },
{ 9, "CP/M", 30 },
{ 10, "Windows NTFS", 100 },
{ 11, "MVS (OS/390 - Z/OS)", 30 },
{ 12, "VSE", 30 },
{ 13, "Acorn Risc", 30 },
{ 14, "VFAT", 100 },
{ 15, "alternate MVS", 30 },
{ 16, "BeOS", 30 },
{ 17, "Tandem", 30 },
{ 18, "OS/400", 30 },
{ 19, "OS/X (Darwin)", 100 },
{ -1, "unknown", 20 }
};
size_t i;
version = htol16(version);
for(i = 0; name[i].os != -1 && (version >> 8) != name[i].os; i++);
ph->printf(ph, "%s%s%s%u.%u", ", OS ", name[i].string,
", specification ", (version & 0xff) / 10,
(version & 0xff) % 10);
return name[i].score;
}
/* _zip_general */
static int _zip_general(PluginHelper * ph, uint16_t general)
{
general = htol16(general);
if(general & 0x1)
ph->printf(ph, "%s", ", encrypted");
if(general & 0x800)
ph->printf(ph, "%s", ", filename in UTF-8");
if(general & 0x1000)
ph->printf(ph, "%s", ", enhanced compression");
if(general & 0x2000)
ph->printf(ph, "%s", ", central directory encrypted");
return 100; /* FIXME improve */
}
/* _zip_method */
static int _zip_method(PluginHelper * ph, uint16_t method)
{
struct
{
int method;
char * string;
int score;
}
name[] =
{
{ 0, "none", 100 },
{ 1, "shrunk", 30 },
{ 2, "factor 1", 30 },
{ 3, "factor 2", 30 },
{ 4, "factor 3", 30 },
{ 5, "factor 4", 30 },
{ 6, "imploded", 30 },
{ 7, "tokenizing", 30 },
{ 8, "deflated", 100 },
{ 9, "Deflate64 (tm)", 30 },
{ 10, "PKWARE DCLI/old IBM TERSE", 30 },
{ 11, "reserved", 20 },
{ 12, "BZIP2", 30 },
{ 13, "reserved", 20 },
{ 14, "LZMA", 30 },
{ 15, "reserved", 20 },
{ 16, "reserved", 20 },
{ 17, "reserved", 20 },
{ 18, "new IBM TERSE", 30 },
{ 19, "IBM LZ77 z Architecture (PFS)", 30 },
{ 98, "PPMd version I, Rev 1", 30 },
{ -1, "unknown", 20 }
};
size_t i;
method = htol16(method);
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;
}
/* _zip_mdatetime */
static int _zip_mdatetime(PluginHelper * ph, uint16_t mdate, uint16_t mtime)
{
static int day_n[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304,
334, 0, 0, 0, 0 };
int month; /* from Linux fs/fat/misc.c date_dos2unix() */
int year;
time_t secs;
struct tm tm;
char tmp[22] = "";
month = ((mdate >> 5) - 1) & 15;
year = mdate >> 9;
secs = (mtime & 31)*2+60*((mtime >> 5) & 63)+(mtime >> 11)*3600+86400*
((mdate & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0
&& month < 2 ? 1 : 0)+3653);
if(secs == 0)
return 0;
if(gmtime_r(&secs, &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 secs > 830901600 && secs < time(NULL) ? 100 : 0;
}
/* _zip_size */
static int _zip_size(PluginHelper * ph, uint32_t csize, uint32_t usize)
{
ph->printf(ph, "%s%u%s%u", ", compressed size ", csize,
", uncompressed size ", usize);
if(htol32(usize) < htol32(csize))
return 0;
return 100;
}
/* _zip_filename */
static int _zip_filename(PluginHelper * ph, uint16_t length, FILE * fp)
{
char * p;
if((length = htol16(length)) == 0)
{
ph->printf(ph, "%s", ", no filename");
return 100;
}
ph->printf(ph, "%s%u", ", filename length ", length);
if((p = malloc(length + 1)) == NULL)
return 0;
if(fread(p, sizeof(char), length, fp) != length)
{
free(p);
return 0;
}
p[length] = '\0';
ph->printf(ph, "%s%s%s", " => \"", p, "\"");
free(p);
return 100;
}
/* _zip_comment */
static int _zip_comment(PluginHelper * ph, uint16_t length, FILE * fp)
{
char * p;
if((length = htol16(length)) == 0)
{
ph->printf(ph, "%s", ", no comment");
return 100;
}
ph->printf(ph, "%s%u", ", comment length ", length);
if((p = malloc(length + 1)) == NULL)
return 0;
if(fread(p, sizeof(char), length, fp) != length)
{
free(p);
return 0;
}
p[length] = '\0';
ph->printf(ph, "%s%s%s", " => \"", p, "\"");
free(p);
return 100;
}