#include #include #include unsigned char input[131072]; unsigned short peek2mem(const unsigned char *buf, unsigned long addr) { return ((unsigned short)(buf[addr+1]) << 8) | ((unsigned short)(buf[addr])); } void poke2mem(unsigned char *buf, unsigned long addr, unsigned short v) { buf[addr] = v & 0xFF; buf[addr+1] = (v >> 8) & 0xFF; } unsigned short peek2(unsigned long addr) { return ((unsigned short)(input[addr+1]) << 8) | ((unsigned short)(input[addr])); } unsigned long peek4(unsigned long addr) { return ((unsigned long)(input[addr+3]) << 24) | ((unsigned long)(input[addr+2]) << 16) | ((unsigned long)(input[addr+1]) << 8) | ((unsigned long)(input[addr])); } const char *typeext(unsigned short rtTypeId) { if (rtTypeId & 0x8000) { switch (rtTypeId & 0x7FFF) { case 1: return "CUR"; case 2: return "BMP"; case 3: return "ICO"; } } return "BIN"; } const char *typename(unsigned long rtbl, unsigned short rtTypeId) { static char buf[200]; if (rtTypeId & 0x8000) { switch (rtTypeId & 0x7FFF) { case 1: return "CURSOR"; case 2: return "BITMAP"; case 3: return "ICON"; } sprintf(buf, "RT%d", rtTypeId & 0x7F); return buf; } else { unsigned char *s = &input[rtTypeId + rtbl]; sprintf(buf, "%-*.*s", s[0], s[0], s + 1); return buf; } } void write_cur(const unsigned char *buf, FILE *fp) { unsigned short h = peek2mem(buf, 0x08); unsigned short wb = peek2mem(buf, 0x0A); unsigned short bitlen = h * wb; fputc(3, fp); /* Windows version? */ fputc(2, fp); fwrite(buf + 2, 1, 12, fp); /* Header */ fwrite(buf + 14, 1, bitlen, fp); /* AND mask */ fwrite(buf + 14 + bitlen, 1, bitlen, fp); /* XOR mask */ /* Second copy? */ fwrite(buf + 2, 1, 12, fp); /* Header */ fwrite(buf + 14, 1, bitlen, fp); /* AND mask */ fwrite(buf + 14 + bitlen, 1, bitlen, fp); /* XOR mask */ } unsigned char iconbuf[2048]; int getpixel(const unsigned char *buf, unsigned short base, int x, int y, unsigned short wb) { unsigned short addr = base + (y * wb) + (x / 8); unsigned short mask = 0x80 >> (x & 7); return buf[addr] & mask; } void putpixel(unsigned char *buf, unsigned short base, int x, int y, unsigned short wb, int v) { unsigned short addr = base + (y * wb) + (x / 8); unsigned short mask = 0x80 >> (x & 7); if (v) buf[addr] |= mask; else buf[addr] &= ~mask; } void write_ico(const unsigned char *buf, FILE *fp) { unsigned short w = peek2mem(buf, 0x06); unsigned short h = peek2mem(buf, 0x08); unsigned short wb = peek2mem(buf, 0x0A); unsigned short bitlen = h * wb; unsigned short y, x; unsigned short offsetr1, offsetr2, offsetw1, offsetw2; memset(iconbuf, 0, sizeof(iconbuf)); poke2mem(iconbuf, 0, 0x201); /* Both DI and DD bitmaps */ /* ICO is a bit funny, because we have to write a scaled-up version * of the icon */ poke2mem(iconbuf, 6, 2 * peek2mem(buf, 6)); poke2mem(iconbuf, 8, 2 * peek2mem(buf, 8)); poke2mem(iconbuf,10, 2 * peek2mem(buf, 10)); offsetr1 = 14; offsetr2 = 14 + bitlen; offsetw1 = 14; offsetw2 = 14 + 4 * bitlen; for (y = 0; y < h*2; y++) { for (x = 0; x < 2*w; x++) { putpixel(iconbuf, offsetw1, x, y, 2*wb, getpixel(buf, offsetr1, x/2, y/2, wb)); putpixel(iconbuf, offsetw2, x, y, 2*wb, getpixel(buf, offsetr2, x/2, y/2, wb)); } } /* Write device-independent icon */ fwrite(iconbuf, 1, 14 + (wb * h * 8), fp); fwrite(buf + 2, 1, 12, fp); /* Header */ fwrite(buf + 14, 1, bitlen, fp); /* AND mask */ fwrite(buf + 14 + bitlen, 1, bitlen, fp); /* XOR mask */ } void derezz(const char *s) { FILE *fp = fopen(s, "rb"); unsigned long ne_header = 0; unsigned long rtbl = 0, rptr = 0; unsigned short rscAlignShift; unsigned short rtTypeId; unsigned short rtResourceCount; unsigned long rtReserved; unsigned short n; unsigned long rnOffset; unsigned short rnLength, rnFlags, rnID, rnHandle, rnUsage; char filename[200]; if (!fp) { perror(s); return; } memset(input, 0, sizeof(input)); fread(input, 1, sizeof(input), fp); fclose(fp); if (memcmp(input, "MZ", 2)) { fprintf(stderr, "%s: No MZ header found\n", s); return; } if (peek2(0x18) >= 0x40) ne_header = peek4(0x3C); if (!ne_header || memcmp(input + ne_header, "NE", 2)) { fprintf(stderr, "%s: No NE header found\n", s); return; } fprintf(stderr, "%s: NE header at 0x%04lx\n", s, ne_header); rptr = rtbl = ne_header + peek2(ne_header + 0x24); fprintf(stderr, "%s: Resource table at 0x%04lx\n", s, rtbl); rscAlignShift = peek2(rptr); rptr += 2; while ((rtTypeId = peek2(rptr))) { rptr += 2; rtResourceCount = peek2(rptr); rptr += 2; rtReserved = peek4(rptr); rptr += 4; fprintf(stderr, "rtTypeId=%s rtResourceCount=%04x rtReserved=%08lx\n", typename(rtbl, rtTypeId), rtResourceCount, rtReserved); for (n = 0; n < rtResourceCount; n++) { rnOffset = ((unsigned long)peek2(rptr)) << rscAlignShift; rptr += 2; rnLength = peek2(rptr) << rscAlignShift; rptr += 2; rnFlags = peek2(rptr); rptr += 2; rnID = peek2(rptr); rptr += 2; rnHandle = peek2(rptr); rptr += 2; rnUsage = peek2(rptr); rptr += 2; fprintf(stderr, "rnOffset=%08lx rnLength=%04x rnFlags=%04x rnID=%04x rnHandle=%04x rnUsage=%04x\n", rnOffset, rnLength, rnFlags, rnID, rnHandle, rnUsage); sprintf(filename, "%s_%d.%s", typename(rtbl, rtTypeId), n + 1, typeext(rtTypeId)); fp = fopen(filename, "wb"); switch (rtTypeId) /* CUR */ { case 0x8001: write_cur(input + rnOffset, fp); break; case 0x8003: write_ico(input + rnOffset, fp); break; default: fwrite(input + rnOffset, 1, rnLength, fp); break; } fclose(fp); } } } int main(int argc, char **argv) { int n; if (argc < 2) { fprintf(stderr, "%s: Syntax is %s file\n", argv[0], argv[0]); return 1; } for (n = 1; n < argc; n++) { derezz(argv[n]); } }