/* decode.c - Don Yang (uguu.org) lclint +posixlib decode.c common.c 09/14/01 */ #ifdef _WIN32 #include #include #else #include #endif #include #include #include #include #include #include"common.h" #include"hufftree.h" static void Decode(FILE *infile, FILE *outfile); static void DecodeDebug(FILE *infile, FILE *outfile); static DWORD GetWord(FILE *infile); static void HuffmanDecode(int length, FILE *infile); static void ReadLiteral(DWORD tag, FILE *infile, FILE *outfile); static void ReadLiteralDebug(DWORD tag, FILE *infile, FILE *outfile); static void ReadSubstring(DWORD tag, FILE *infile, FILE *outfile); static void ReadSubstringDebug(DWORD tag, FILE *infile, FILE *outfile); /******************************************************************** main */ int main(int argc, char **argv) { FILE *infile, *outfile; /* Set input/output */ infile = stdin; outfile = stdout; if( argc > 1 && argv[1][0] != '-' ) { if( (infile = fopen(argv[1], "rb")) == NULL ) return printf("Can not open %s\n", argv[1]); } if( argc > 2 ) { if( (outfile = fopen(argv[2], "wb+")) == NULL ) { (void)fclose(infile); return printf("Can not create %s\n", argv[2]); } } #ifdef _WIN32 (void)setmode(fileno(infile), O_BINARY); (void)setmode(fileno(outfile), O_BINARY); #endif /* Initialize ring buffer */ memset(RingBuffer, 0, BUFFER_SIZE); iChecksum = oChecksum = ProcOffset = LimitOffset = 0; FileSize = 0x7ffffff; if( isatty(fileno(outfile)) != 0 ) { (void)puts("Output is a tty"); argc = 4; } if( argc > 3 ) { (void)puts("Using debug decoder"); DecodeDebug(infile, outfile); } else { Decode(infile, outfile); } /* End */ (void)fclose(infile); (void)fclose(outfile); return 0; } /* main() */ /****************************************************************** Decode */ static void Decode(FILE *infile, FILE *outfile) { DWORD tag; while( (tag = GetWord(infile)) != INPUT_EOF ) { if( (tag & 0x8000) == 0 ) ReadLiteral(tag, infile, outfile); else ReadSubstring(tag, infile, outfile); } if( iChecksum != oChecksum ) (void)fputs("Checksum failed\n", stderr); } /* Decode() */ /************************************************************* DecodeDebug */ static void DecodeDebug(FILE *infile, FILE *outfile) { DWORD tag; while( (tag = GetWord(infile)) != INPUT_EOF ) { if( (tag & 0x8000) == 0 ) ReadLiteralDebug(tag, infile, outfile); else ReadSubstringDebug(tag, infile, outfile); } printf("Checksum = %d\n", oChecksum); if( iChecksum != oChecksum ) (void)fputs("Checksum failed\n", stderr); } /* DecodeDebug() */ /***************************************************************** GetWord */ static DWORD GetWord(FILE *infile) { int byte1, byte2; if( (byte1 = fgetc(infile)) == EOF ) return INPUT_EOF; if( (byte2 = fgetc(infile)) == EOF ) { iChecksum = byte1; return INPUT_EOF; } return (DWORD)(((unsigned)byte2 << 8) | (unsigned)byte1); } /* GetWord() */ /*********************************************************** HuffmanDecode */ static void HuffmanDecode(int length, FILE *infile) { int bit, byte, i, x, *branch; bit = 8; for(i = x = byte = 0; i < length;) { if( bit > 7 ) { if( (byte = fgetc(infile)) == EOF ) break; bit = 0; } branch = ((byte & (1 << bit)) == 0) ? Left : Right; if( branch[x] <= 0 ) { RingBuffer[(ProcOffset + i) & BUFFER_MASK] = (BYTE)(-branch[x]); i++; x = 0; } else { x = branch[x]; } bit++; } } /* HuffmanDecode() */ /************************************************************* ReadLiteral */ static void ReadLiteral(DWORD tag, FILE *infile, FILE *outfile) { DWORD byte; int length, i; length = (int)(tag & 0x3fff); if( (tag & 0x4000) == 0 ) { /* Literal block */ for(i = 0; i < length; i++) { byte = GetByte(ProcOffset, infile); assert(byte != INPUT_EOF); ProcOffset++; PutByte((BYTE)byte, outfile); } } else { /* Huffman block */ HuffmanDecode(length, infile); for(i = 0; i < length; i++) PutByte(RingBuffer[(ProcOffset + i) & BUFFER_MASK], outfile); LimitOffset = ProcOffset += length; } } /* ReadLiteral() */ /******************************************************** ReadLiteralDebug */ static void ReadLiteralDebug(DWORD tag, FILE *infile, FILE *outfile) { int length, i; DWORD byte; length = (int)(tag & 0x3fff); if( (tag & 0x4000) == 0 ) { fprintf(outfile, "Literal:%7d bytes\n", length); for(i = 0; i < length; i++) { byte = GetByte(ProcOffset, infile); assert(byte != INPUT_EOF); oChecksum ^= (int)byte; ProcOffset++; } } else { fprintf(outfile, "Huffman:%7d bytes\n", length); HuffmanDecode(length, infile); for(i = 0; i < length; i++) oChecksum ^= (int)RingBuffer[(ProcOffset + i) & BUFFER_MASK]; LimitOffset = ProcOffset += length; } } /* ReadLiteralDebug() */ /*********************************************************** ReadSubstring */ static void ReadSubstring(DWORD tag, FILE *infile, FILE *outfile) { int length, negoffset, i; if( (tag & 0x4000) == 0 ) length = (int)fgetc(infile); else length = (int)GetWord(infile); negoffset = (int)(tag & 0x3fff); /* Copy bytes */ for(i = 0; i < length; i++) { PutByte(RingBuffer[ProcOffset & BUFFER_MASK] = RingBuffer[(ProcOffset - negoffset) & BUFFER_MASK], outfile); ProcOffset++; } LimitOffset = ProcOffset; } /* ReadSubstring() */ /****************************************************** ReadSubstringDebug */ static void ReadSubstringDebug(DWORD tag, FILE *infile, FILE *outfile) { int length, negoffset, i; if( (tag & 0x4000) == 0 ) length = (int)fgetc(infile); else length = (int)GetWord(infile); negoffset = (int)(tag & 0x3fff); fprintf(outfile, "Substring:%5d bytes (from %08x)\n", length, (DWORD)(ProcOffset - negoffset)); /* Copy bytes */ for(i = 0; i < length; i++) { oChecksum ^= (int)(RingBuffer[ProcOffset & BUFFER_MASK] = RingBuffer[(ProcOffset - negoffset) & BUFFER_MASK]); ProcOffset++; } LimitOffset = ProcOffset; } /* ReadSubstringDebug() */