/* decode.c - Don Yang (uguu.org) lclint +posixlib decode.c common.c 09/11/01 */ #ifdef _WIN32 #include #else #include #endif #include #include #include #include #include #include"common.h" static void Decode(FILE *infile, FILE *outfile); static void DecodeDebug(FILE *infile, FILE *outfile); static void FlushBytes(FILE *outfile); static void FlushBytesDebug(FILE *outfile); static DWORD GetWord(FILE *infile); /******************************************************************** 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]); } } /* Initialize ring buffer */ memset(RingBuffer, 0, BUFFER_SIZE); oChecksum = HistoryOffset = ProcOffset = 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, length, offset, i; int byte; while( (tag = GetWord(infile)) != INPUT_EOF ) { switch( tag >> 14 ) { case 0: /* Literal */ length = tag; for(i = 0; i < length; i++) { tag = GetByte(ProcOffset, infile); assert(tag != INPUT_EOF); ProcOffset++; } FlushBytes(outfile); break; case 1: /* Patch */ offset = tag & 0x3fff; byte = fgetc(infile); assert(byte != EOF); assert((DWORD)ProcOffset > offset); RingBuffer[(ProcOffset - offset) & BUFFER_MASK] = (BYTE)byte; break; default: /* Reference */ if( (tag & 0x4000) != 0 ) length = (DWORD)GetWord(infile); else length = (DWORD)fgetc(infile); assert(length > 0 && length < HALF_BUFFER_SIZE); offset = tag & 0x3fff; for(i = 0; i < length; i++) { RingBuffer[ProcOffset & BUFFER_MASK] = RingBuffer[(ProcOffset - offset) & BUFFER_MASK]; ProcOffset++; } InputOffset = ProcOffset; FlushBytes(outfile); break; } } while( ProcOffset > HistoryOffset ) PutByte(RingBuffer[(HistoryOffset++) & BUFFER_MASK], outfile); if( iChecksum != oChecksum ) (void)fputs("Checksum failed\n", stderr); } /* Decode() */ /************************************************************* DecodeDebug */ static void DecodeDebug(FILE *infile, FILE *outfile) { DWORD tag, length, offset, i; int cmpsize, byte; cmpsize = 0; while( (tag = GetWord(infile)) != INPUT_EOF ) { fprintf(outfile, "tag = %04x\n", tag); switch( tag >> 14 ) { case 0: /* Literal block */ length = tag; cmpsize += 2 + length; fprintf(outfile, "Literal: %u bytes\n", length); for(i = 0; i < length; i++) { tag = GetByte(ProcOffset, infile); assert(tag != INPUT_EOF); ProcOffset++; } FlushBytesDebug(outfile); break; case 1: /* Patch byte */ offset = tag & 0x3fff; byte = fgetc(infile); assert(byte != EOF); assert((DWORD)ProcOffset > offset); cmpsize += 3; fprintf(outfile, "patch %02x at %08x\n", (DWORD)byte, offset); RingBuffer[(ProcOffset - offset) & BUFFER_MASK] = (BYTE)byte; break; default: /* Substring reference */ if( (tag & 0x4000) != 0 ) length = (DWORD)GetWord(infile); else length = (DWORD)fgetc(infile); assert(length > 0 && length < HALF_BUFFER_SIZE); offset = tag & 0x3fff; cmpsize += (tag & 0x4000) != 0 ? 4 : 3; fprintf(outfile, "copy %u bytes from %08x\n", length, ProcOffset - offset); for(i = 0; i < length; i++) { RingBuffer[ProcOffset & BUFFER_MASK] = RingBuffer[(ProcOffset - offset) & BUFFER_MASK]; ProcOffset++; } InputOffset = ProcOffset; FlushBytesDebug(outfile); break; } } /* Flush unwritten data */ while( ProcOffset > HistoryOffset ) { byte = (int)RingBuffer[HistoryOffset & BUFFER_MASK]; if( isprint(byte) != 0 ) { fprintf(outfile, "%08x: %02x '%c'\n", (DWORD)HistoryOffset, (DWORD)byte, (char)byte); } else { fprintf(outfile, "%08x: %02x\n", (DWORD)HistoryOffset, (DWORD)byte); } HistoryOffset++; oChecksum ^= byte; } fprintf(outfile, "Checksum = %d\n", oChecksum); (void)fputs(iChecksum == oChecksum ? "Checksum OK\n" : "Checksum failed\n", outfile); fprintf(outfile, "Compressed size = %d bytes\nOriginal size = %d bytes\n", cmpsize, ProcOffset); } /* DecodeDebug() */ /************************************************************** FlushBytes */ static void FlushBytes(FILE *outfile) { while( ProcOffset - HistoryOffset >= HALF_BUFFER_SIZE ) PutByte(RingBuffer[(HistoryOffset++) & BUFFER_MASK], outfile); } /* FlushBytes() */ /********************************************************* FlushBytesDebug */ static void FlushBytesDebug(FILE *outfile) { int b; while( ProcOffset - HistoryOffset >= HALF_BUFFER_SIZE ) { b = (int)RingBuffer[HistoryOffset & BUFFER_MASK]; if( isprint(b) != 0 ) { fprintf(outfile, "%08x: %02x '%c'\n", (DWORD)HistoryOffset, (DWORD)b, (char)b); } else { fprintf(outfile, "%08x: %02x\n", (DWORD)HistoryOffset, (DWORD)b); } HistoryOffset++; oChecksum ^= b; } } /* FlushBytesDebug() */ /***************************************************************** 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() */