#include #include #include #include /* log2 */ #include /* isprint() */ void PutLiteral(FILE *fp, int sym); void PutLz(FILE *fpout, short maxlen, short maxpos); /**************************************************************** Huffman tree structures, variables and related routines ****************************************************************/ int IsPat(void); int Rec(unsigned short value); int CreateTree(int numval, unsigned char *lengths, unsigned short *values); #define LITERALS 288 static unsigned char flen; static short fpos[17]; static unsigned char *flens; static unsigned short *fvals; static short fmax; int IsPat() { while (1) { if (fpos[flen] >= fmax) return -1; if (flens[fpos[flen]] == flen) return fpos[flen]++; fpos[flen]++; } } /* A recursive routine which creates the Huffman decode tables No presorting of code lengths are needed, because a counting sort is perfomed on the fly. */ /* Maximum recursion depth is equal to the maximum Huffman code length, which is 15 in the deflate algorithm. (16 in Inflate!) */ int Rec(unsigned short value) { int tmp; if (flen==17) { return -1; } flen++; value <<= 1; tmp = IsPat(); if (tmp >= 0) { fvals[tmp] = value; /* leaf cell for 0-bit */ } else { /* Not a Leaf cell */ if (Rec(value)) return -1; } value++; tmp = IsPat(); if (tmp >= 0) { fvals[tmp] = value; /* leaf cell for 1-bit */ } else { /* Not a Leaf cell */ if (Rec(value)) return -1; } flen--; return 0; } int CreateTree(int numval, unsigned char *lengths, unsigned short *values) { int i; /* Create the Huffman decode tree/table */ flens = lengths; fmax = numval; fvals = values; for (i=0;i<17;i++) fpos[i] = 0; flen = 0; if (Rec(0)) { fprintf(stderr, "invalid huffman tree\n"); return -1; } return 0; } static unsigned char hlens[2*288]; long hhist[2*288]; short hidx[2*288]; /* Calculate code lengths from the frequencies */ void PackHuf(int n, long *s) { int i, z = n, low = 0; for (i=0; i 0) { if (minv == 0 || minv > hhist[i]) { minv2 = minv; mind2 = mind; minv = hhist[i]; mind = i; } else if (minv2 == 0 || minv2 > hhist[i]) { minv2 = hhist[i]; mind2 = i; } } } /*fprintf(stderr, "%ld@%d %ld@%d\n", minv, mind, minv2, mind2);*/ if (minv2 == 0) { for (i=z-2;i>=0;i--) { if (hidx[i]) hlens[i] = hlens[hidx[i]] + 1; } return; } /* create new combined node */ hidx[z] = 0; hlens[z] = 0; hhist[z] = minv + minv2; /* disable old nodes */ hhist[mind] = hhist[mind2] = 0; /* link to new node */ hidx[mind] = z; hidx[mind2] = z; z++; } } void putdec(FILE *fp, unsigned long a) { static const dec[] = {1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1}; int i, s = 0; for (i=0; i<10; i++) { int j = 0; while (a >= dec[i]) { j++; a -= dec[i]; } if (j || s || i==9) { fprintf(fp, "%c", j + '0'); s = 1; } } } /* ======================================================================== * Table of CRC-32's of all single-byte values (made by makecrc.c) */ #define CRC32_BITS 8 /* must be 4 or 8 */ #define CRC32_SIZE (1<>= 1; /* 1$: lsr c3 ; ror c2 ; ror c1 ; ror c0 */ if (cf) { /* bcc 0$ */ c ^= e; /* lda c3 ; eor #ed ; sta c3 */ /*0xedb88320*/ /* lda c2 ; eor #b8 ; sta c2 */ /* lda c1 ; eor #83 ; sta c1 */ /* lda c0 ; eor #20 ; sta c0 */ } /* 0$: */ } /* dex ; bne 1$ */ crc_32_tab[i] = c; } } #define updcrc2(cp, crc) (crc_32_tab[((int)crc ^ cp) & (CRC32_SIZE-1)] ^ (crc >> CRC32_BITS)) /* Note: that last part "^ (crc >> 4)" would be too slow to implement in 6502 */ #if CRC32_BITS == 4 unsigned long updcrc(unsigned char cp, unsigned long crc) { unsigned long tmp = updcrc2(cp, crc); return updcrc2(cp>>4, tmp); } #else #define updcrc(cp,crc) updcrc2(cp,crc) #endif /**************************************************************** Tables for deflate from PKZIP's appnote.txt ****************************************************************/ /* Order of the bit length code lengths */ static const unsigned border[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Copy lengths for literal codes 257..285 */ static const unsigned short cplens[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 999, 0}; /* Extra bits for literal codes 257..285 */ static const unsigned short cplext[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ /* Copy offsets for distance codes 0..29 */ static const unsigned short cpdist[] = { 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01, 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001, 0xffff}; /* Extra bits for distance codes */ static const unsigned short cpdext[] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; /****************************************************************/ struct datadesc { unsigned long crc32; unsigned long csize; unsigned long usize; }; struct central { struct datadesc dd; unsigned long lhdroff; char *name; }; #define MAXFILES 256 struct central CA[MAXFILES]; struct ecentral { unsigned char id[4]; /* 50 4b 05 06 */ unsigned char numdisk[2]; unsigned char cendisk[2]; unsigned char numthis[2]; unsigned char censize[4]; unsigned char censtart[4]; unsigned char commentsize[2]; }; static unsigned long outSize = 0; static int bits = 0, byte = 0; void FlushBits(FILE *fp) { if (bits) { while(bits!=8) { byte = (byte>>1); bits++; } fputc(byte, fp); outSize++; } bits = 0; } void PutBits(FILE *fp, int num, int val) { if (num > 8) { fprintf(stderr, "PutBits(fp, %d, 0x%x)!\n", num, val); } while (num--) { bits++; byte = (byte>>1) | ((val & 1)?0x80:0); val >>= 1; if (bits==8) { fputc(byte, fp); bits = 0; outSize++; } } } void PutBitsR(FILE *fp, int num, int val) { static const short maskTab[] = {1,2,4,8,16,32,64,128 ,256,512}; short mask; if (!num) return; mask = maskTab[num-1]; if (num > 8) { fprintf(stderr, "PutBitsR(fp, %d, 0x%x)!\n", num, val); } while (num--) { byte = (byte>>1) | ((val & mask)?0x80:0); mask >>= 1; bits++; if (bits==8) { fputc(byte, fp); bits = 0; outSize++; } } } #define DYNSAVESIZE 58*1024 static unsigned char dynSave[DYNSAVESIZE]; static int dynSaved, dynRead; short PutDynSave(unsigned char c) { if (dynSaved >= DYNSAVESIZE-3) return 1; /* no room */ dynSave[dynSaved++] = c; return 0; } short GetDynSave(void) { if (dynRead == dynSaved) return -1; return dynSave[dynRead++]; } static int started = 0, dynamic = 0; static long stats[288+32] = {0}; static unsigned short dynPat[288+32+19]; static unsigned char dynLen[288+32+19]; static int dynLits; void InitDynamic(FILE *fp, int dyn) { if ((dynamic = dyn)) { int i; for (i=0;i<288+32;i++) stats[i] = 0; started = 0; dynSaved = 0; dynRead = 0; } else { PutBits(fp, 1, 1); /* last block */ PutBits(fp, 2, 1); /* fixed huffman */ started = 1; } } void CreateDynamic(FILE *fp, int full) { unsigned char lenTab[288+32]; int i, nlens, ntab = 0, last; long save = 0; long lstats[19] = {0}; /* If statistics only from part of the file */ if (!full) { for (i=0;i<288+32;i++) { if (!stats[i]) stats[i] = 1; } } /* Create Literal Table */ PackHuf(286, stats); if(CreateTree(286 /*Codes*/, hlens, dynPat)) { } dynLits = 286; for (i=0;i= 138) ? 138 : j; lstats[18]++; lenTab[ntab++] = (1<<7) + (k-11); j -= k; } } } else if (dynLen[i] == last) { while (dynLen[++i] == last && i= 6) ? 6 : j; lstats[16]++; lenTab[ntab++] = (1<<5) + (k-3); j -= k; } } } else { lstats[dynLen[i]]++; lenTab[ntab++] = dynLen[i++]; } last = lenTab[ntab-1]; } /* Create Len Table */ lagain: PackHuf(19, lstats); for (i=0; i<19; i++) { /* Code lengths must be <= 7 If too long codes, make the distribution flatter */ if (hlens[i] > 7) { int j; for (j=0;j<19;j++) { lstats[j] = (lstats[j]+1)/2; } goto lagain; } } if(CreateTree(19, hlens, dynPat+288+32)) { } for (i=0;i<19;i++) { save -= hlens[i] * lstats[i]; } fprintf(stderr, "Header\n"); PutBits(fp, 1, 1); /* last block */ PutBits(fp, 2, 2); /* dynamic huffman */ started = 1; PutBits(fp, 5, dynLits-257); /* # of literals - 257 */ PutBits(fp, 5, nlens-dynLits-1); /* # of dist codes - 1 */ PutBits(fp, 4, 19-4); /* # of length codes - 4 */ /*fprintf(stderr, "Bit lengths\n");*/ for (i=0;i<19;i++) { /*fprintf(stderr, "%d ", hlens[border[i]]);*/ PutBits(fp, 3, hlens[border[i]]); } /*fprintf(stderr, "\n");*/ for (i=0;i= 256 && i <= 279) { real = 7; } else if (i >= 280 && i <= 287) { real = 8; } else if (i >= 0 && i <= 143) { real = 8; } else if (i >= 144 && i <= 255) { real = 9; } if (stats[i]) { save += stats[i] * (real - dynLen[i]); } #if 0 fprintf(stdout, "%3d: %2d %4x %10ld\n", i, dynLen[i], dynLen[i]?dynPat[i]:0, stats[i]); #endif } for (i=0; i<30; i++) { if (stats[288+i]) { save += stats[288+i] * (5 - dynLen[dynLits + i]); } #if 0 fprintf(stdout, "%3d: %2d %4x %10ld\n", i, dynLen[dynLits + i], dynLen[dynLits+i]?dynPat[dynLits+i]:0, stats[288+i]); #endif } fprintf(stderr, "saves %ld bytes\n", save/8); fprintf(stderr, "Accumulated Data\n"); /* then save the accumulated data */ while (1) { int i = GetDynSave(); if (i < 0) break; if (i == 0) { PutLiteral(fp, GetDynSave()); } else { int l = (GetDynSave()<<8); l |= GetDynSave(); PutLz(fp, 2+i, l); } } fprintf(stderr, "New Data\n"); } /* 256 0000000 0 : : : 279 0010111 23 0 00110000 48 : : : 143 10111111 191 280 11000000 192 : : : 287 11000111 199 144 110010000 400 : : : 255 111111111 511 Note the bit order! */ void PutLiteral(FILE *fp, int sym) { if (!started) { stats[sym]++; if (PutDynSave(0)) { CreateDynamic(fp, 0); /* Then fall through to output this sym */ } else { PutDynSave(sym); return; } } if (dynamic) { if (dynLen[sym] > 8) { PutBitsR(fp, dynLen[sym]-8, dynPat[sym]>>8); PutBitsR(fp, 8, dynPat[sym]); } else { PutBitsR(fp, dynLen[sym], dynPat[sym]); } return; } if (sym >= 256 && sym <= 279) { PutBitsR(fp, 7, sym - 256 + 0); } else if (sym >= 280 && sym <= 287) { PutBitsR(fp, 8, sym -280+192); } else if (sym >= 0 && sym <= 143) { PutBitsR(fp, 8, sym - 0 + 48); } else if (sym >= 144 && sym <= 255) { PutBits(fp, 1, 1); PutBitsR(fp, 8, sym); } else { fprintf(stderr, "invalid fixed huffman\n"); } } void PutDist(FILE *fp, int k) { if (dynamic) { if (dynLen[dynLits+k] > 8) { PutBitsR(fp, dynLen[dynLits+k]-8, dynPat[dynLits+k]>>8); PutBitsR(fp, 8, dynPat[dynLits+k]); } else { PutBitsR(fp, dynLen[dynLits+k], dynPat[dynLits+k]); } } else { PutBitsR(fp, 5, k); } } void PutLz(FILE *fpout, short maxlen, short maxpos) { int j, k; j = 0; while (maxlen >= cplens[j]) j++; j--; k = 0; while (maxpos >= cpdist[k]) k++; k--; if (!started) { if (PutDynSave(maxlen-2)) { CreateDynamic(fpout, 0); } else { stats[257+j]++; stats[288+k]++; PutDynSave(maxpos>>8); PutDynSave(maxpos & 0xff); return; } } #if 0 fprintf(stderr, "@%d (l%d,d%d) %d +%d ", p, maxlen, maxpos, 257+j, cplext[j]); fprintf(stderr, "%d +%d\n", k, cpdext[k]); #endif PutLiteral(fpout, 257+j); if (cplext[j]) { PutBits(fpout, cplext[j], maxlen-cplens[j]); } PutDist(fpout, k); if (cpdext[k]) { if (cpdext[k] > 8) { PutBits(fpout, 8, maxpos-cpdist[k]); PutBits(fpout, cpdext[k]-8, (maxpos-cpdist[k])>>8); } else { PutBits(fpout, cpdext[k], maxpos-cpdist[k]); } } } /* 258/32768 107741 174848 61% 255/32768 107764 174848 61% 255/16384 111909 174848 64% 255/8192 113639 174848 64% 255/4096 114695 174848 65% 255/2048 119371 174848 68% 255/1024 122362 174848 69% 8k 174848 Defl:N 113639 35% c4d2f886 t 16k 174848 Defl:N 111909 36% c4d2f886 t 32k 174848 Defl:N 107764 38% c4d2f886 t */ #define MAX_MATCH 255 /* 258 */ #define BLOCK_SIZE 32768 /* must be a power of 2 */ static unsigned short bSkip[BLOCK_SIZE]; #define LSHIFT 7 /* 4-74s 5-55s 6-45s 7-38s 8-34s */ #define LSIZE (1< 3) speed = 3; if (speed < 0) speed = 0; leftSpeed = (BLOCK_SIZE-MAX_MATCH); { int j = speed; while (j--) leftSpeed >>= 1; } CA[files].name = argv[i]; CA[files].lhdroff = outSize; fwrite("\x50\x4b\x03\x04", 4, 1, fpout); fwrite("\x14\x00\x08\x00", 4, 1, fpout); /* vers, gpflag */ fwrite("\x08\x00", 2, 1, fpout); /* method -- deflate */ fwrite("\x9f\x05\x00\x00", 4, 1, fpout); /* modtime/date */ fwrite("\x00\x00\x00\x00", 4, 1, fpout); /* CRC32 */ fwrite("\x00\x00\x00\x00", 4, 1, fpout); /* compressed size */ fwrite("\x00\x00\x00\x00", 4, 1, fpout); /* uncompressed size */ temp[0] = len & 0xff; temp[1] = (len >> 8); temp[2] = temp[3] = '\0'; fwrite(temp, 4, 1, fpout); /* filename length */ fwrite(argv[i], len, 1, fpout); /* filename */ outSize += 30 + len; crc32 = ~0; usize = 0; cstart = outSize; if (stored) { while (1) { int j; len = fread(buffer, 1, BLOCK_SIZE, fp); PutBits(fpout, 1, (len>8; temp[2] = ~temp[0]; temp[3] = ~temp[1]; fwrite(temp, 1, 4, fpout); fwrite(buffer, 1, len, fpout); usize += len; outSize += 4 + len; for (j=0; j 1) { long off; unsigned short index = ((*rPtr & (LSIZE-1)) << LSHIFT) | (*(rPtr+1) & (LSIZE-1)); long *lPairPtr = &lPair[index]; unsigned short *tmp = &bSkip[p & (BLOCK_SIZE-1)]; off = p - *lPairPtr; #if 1 if (off < (BLOCK_SIZE-MAX_MATCH)) { #else if (off < 65536 && (off >> 8) < ((BLOCK_SIZE-MAX_MATCH)>>8)) { #endif *tmp = off; } else { *tmp = 0; } *lPairPtr = p; } if (skip) { skip--; } else { short maxlen = 1, maxpos = 0, j; int left = leftSpeed; /*, loops = 255;*/ unsigned short im = p & (BLOCK_SIZE-1); unsigned char nChar = *rPtr; while ((j = bSkip[im])) { char *bp = rPtr; char *ap; /* if (!--loops) break; */ left -= j; if (left < 0) { break; } im = (im - j) & (BLOCK_SIZE-1); ap = &buffer[im]; j = 0; while (*ap++ == *bp++ && ++j < MAX_MATCH) ; if (j > maxlen) { maxlen = j; maxpos = (int)(bp - ap) & (BLOCK_SIZE-1); if (maxlen == MAX_MATCH || nChar == *(rPtr+1)) { break; } } } if (maxlen > bu) { maxlen = bu; } if (maxlen >= 3) { if (speed!=0) { PutLz(fpout, maxlen, maxpos); skip = maxlen-1; oMaxlen = 0; /* nothing in fifo */ } else if (oMaxlen >= maxlen) { /*fprintf(stderr, "Lz %d %d\n", oMaxlen, oMaxpos);*/ PutLz(fpout, oMaxlen, oMaxpos); skip = oMaxlen-2; oMaxlen = 0; /* nothing in fifo */ } else { if (oMaxlen) { /*fprintf(stderr, "%d\n", oChar);*/ PutLiteral(fpout, oChar); } oMaxlen = maxlen; oMaxpos = maxpos; } #if 0 /*fprintf(stderr, "%d loops\n", loops);*/ #endif } else { if (speed!=0) { PutLiteral(fpout, nChar); oMaxlen = 0; } else if (oMaxlen >= 3) { /*fprintf(stderr, "Lz %d %d\n", oMaxlen, oMaxpos);*/ PutLz(fpout, oMaxlen, oMaxpos); skip = oMaxlen-2; oMaxlen = 0; /* nothing in fifo */ } else { if (oMaxlen) { /*fprintf(stderr, "%d\n", oChar);*/ PutLiteral(fpout, oChar); } oMaxlen = 1; } } oChar = nChar; } p++; rPtr++; if (rPtr == &buffer[BLOCK_SIZE]) { rPtr = &buffer[0]; } bu--; if (!bu && eof) { break; } if (!(p & 4095)) { fprintf(stderr, "\r%d", p); fflush(stderr); } } if (speed!=0) { } else { if (oMaxlen >= 3) { /*fprintf(stderr, "Lz %d %d\n", oMaxlen, oMaxpos);*/ PutLz(fpout, oMaxlen, oMaxpos); } else if (oMaxlen) { /*fprintf(stderr, "%d\n", oChar);*/ PutLiteral(fpout, oChar); } } usize = p; fprintf(stderr, "\r%d\n", p); PutLiteral(fpout, 256); /* EOF */ if (!started) { CreateDynamic(fpout, 1); } FlushBits(fpout); fileEnd: csize = outSize-cstart; fprintf(stderr, "%d%%\n", 100*csize/usize); if (usize) { long a = csize, b = usize, val = 0; int i, sh = 0; while (a > b) { b <<= 1; sh++; } for (i=0; i<17; i++) { val <<= 1; if (a >= b) { a -= b; val |= 1; } a <<= 1; } val <<= sh; putdec(stderr, csize); fprintf(stderr, " "); putdec(stderr, usize); fprintf(stderr, " "); putdec(stderr, 100*val/65536); fprintf(stderr, "%%\n"); } /* put data descriptor */ temp[0] = 0x50; temp[1] = 0x4b; temp[2] = 0x07; temp[3] = 0x08; fwrite(temp, 4, 1, fpout); temp[0] = ~crc32; temp[1] = ~crc32>>8; temp[2] = ~crc32>>16; temp[3] = ~crc32>>24; fwrite(temp, 4, 1, fpout); temp[0] = csize; temp[1] = csize>>8; temp[2] = csize>>16; temp[3] = csize>>24; fwrite(temp, 4, 1, fpout); /* compressed size */ temp[0] = usize; temp[1] = usize>>8; temp[2] = usize>>16; temp[3] = usize>>24; fwrite(temp, 4, 1, fpout); /* uncompressed size */ outSize += 16; CA[files].dd.crc32 = crc32; CA[files].dd.csize = csize; CA[files].dd.usize = usize; fclose(fp); files++; } } cstart = outSize; csize = 0; for (i=0; i>8; temp[2] = ~CA[i].dd.crc32>>16; temp[3] = ~CA[i].dd.crc32>>24; fwrite(temp, 4, 1, fpout); temp[0] = CA[i].dd.csize; temp[1] = CA[i].dd.csize>>8; temp[2] = CA[i].dd.csize>>16; temp[3] = CA[i].dd.csize>>24; fwrite(temp, 4, 1, fpout); /* compressed size */ temp[0] = CA[i].dd.usize; temp[1] = CA[i].dd.usize>>8; temp[2] = CA[i].dd.usize>>16; temp[3] = CA[i].dd.usize>>24; fwrite(temp, 4, 1, fpout); /* uncompressed size */ temp[0] = len & 0xff; temp[1] = (len >> 8); fwrite(temp, 2, 1, fpout); /* name len */ temp[0] = temp[1] = 0; fwrite(temp, 2, 1, fpout); /* extra len */ temp[0] = temp[1] = 0; fwrite(temp, 2, 1, fpout); /* comment len */ temp[0] = temp[1] = 0; fwrite(temp, 2, 1, fpout); /* disk number start */ temp[0] = temp[1] = 0; fwrite(temp, 2, 1, fpout); /* int attr */ temp[0] = 0x00; temp[1] = 0x00; temp[2] = 0xb4; temp[3] = 0x80; fwrite(temp, 4, 1, fpout); /* ext attr */ temp[0] = CA[i].lhdroff; temp[1] = CA[i].lhdroff>>8; temp[2] = CA[i].lhdroff>>16; temp[3] = CA[i].lhdroff>>24; fwrite(temp, 4, 1, fpout); /* relative offset of local header */ fwrite(CA[i].name, 1, len, fpout); csize += 46 + len; } if (files) { char temp[4]; fwrite("\x50\x4b\x05\x06", 4, 1, fpout); fwrite("\x00\x00\x00\x00", 4, 1, fpout); temp[0] = files; temp[1] = files>>8; fwrite(temp, 2, 1, fpout); fwrite(temp, 2, 1, fpout); temp[0] = csize; temp[1] = csize>>8; temp[2] = csize>>16; temp[3] = csize>>24; fwrite(temp, 4, 1, fpout); temp[0] = cstart; temp[1] = cstart>>8; temp[2] = cstart>>16; temp[3] = cstart>>24; fwrite(temp, 4, 1, fpout); fwrite("\x00\x00", 2, 1, fpout); } }