/* encode.c - Don Yang (uguu.org) lclint +posixlib encode.c common.c 09/11/01 */ #ifdef _WIN32 #include #else #include #endif #include #include #include #include #include #include"common.h" /* Performance tuning variables */ #define MIN_SUBSTRING_LENGTH 5 static void Encode(FILE *infile, FILE *outfile); static void EncodeDebug(FILE *infile, FILE *outfile); static int FindPreviousSubstring(FILE *infile, /*@out@*/int *length); static void WriteLiteral(int length, FILE *outfile); static int WriteLiteralDebug(int length, FILE *outfile); static void WriteSubstring(int length, int negoffset, FILE *outfile); static int WriteSubstringDebug(int length, int negoffset, 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]); } } /* Initialize ring buffer */ memset(RingBuffer, 0, BUFFER_SIZE); iChecksum = ProcOffset = InputOffset = 0; FileSize = 0x7fffffff; /* Compress stream */ if( isatty(fileno(outfile)) != 0 ) { (void)puts("Output is a tty"); argc = 4; } if( argc > 3 ) { (void)puts("Using debug encoder"); EncodeDebug(infile, outfile); } else { Encode(infile, outfile); } /* End */ (void)fclose(infile); (void)fclose(outfile); return 0; } /* main() */ /****************************************************************** Encode */ static void Encode(FILE *infile, FILE *outfile) { int runlength, duplength, dupoffset; runlength = 0; while( GetByte(ProcOffset, infile) != INPUT_EOF ) { if( (dupoffset = FindPreviousSubstring(infile, &duplength)) != 0 ) { /* Found matched substring, check minimum length */ if( duplength >= MIN_SUBSTRING_LENGTH ) { if( runlength > 0 ) WriteLiteral(runlength, outfile); WriteSubstring(duplength, dupoffset, outfile); ProcOffset += duplength; runlength = 0; continue; } } /* No qualifying substring, keep literal byte in buffer */ ProcOffset++; runlength++; if( runlength >= HALF_BUFFER_SIZE ) { /* Flush literal block */ WriteLiteral(runlength, outfile); runlength = 0; } } /* Flush literal block */ if( runlength > 0 ) WriteLiteral(runlength, outfile); /* Write checksum */ (void)fputc(iChecksum, outfile); } /* Encode() */ /************************************************************* EncodeDebug */ static void EncodeDebug(FILE *infile, FILE *outfile) { int runlength, duplength, dupoffset, cmpsize; DWORD byte; runlength = cmpsize = 0; while( (byte = GetByte(ProcOffset, infile)) != INPUT_EOF ) { if( isprint((int)byte) ) { fprintf(outfile, "%08x: %02x '%c'\n", (DWORD)ProcOffset, byte, (char)byte); } else { fprintf(outfile, "%08x: %02x\n", (DWORD)ProcOffset, byte); } if( (dupoffset = FindPreviousSubstring(infile, &duplength)) != 0 ) { /* Found matched substring, check minimum length */ if( duplength >= MIN_SUBSTRING_LENGTH ) { if( runlength > 0 ) cmpsize += WriteLiteralDebug(runlength, outfile); cmpsize += WriteSubstringDebug(duplength, dupoffset, outfile); ProcOffset += duplength; runlength = 0; continue; } } /* No qualifying substring, keep literal byte in buffer */ ProcOffset++; runlength++; if( runlength >= HALF_BUFFER_SIZE ) { /* Flush literal block */ cmpsize += WriteLiteralDebug(runlength, outfile); runlength = 0; } } /* Flush literal block */ if( runlength > 0 ) cmpsize += WriteLiteralDebug(runlength, outfile); fprintf(outfile, "Checksum = %d\n" "Original size = %d bytes\n" "Compressed size = %d bytes\n", iChecksum, FileSize, cmpsize); } /* EncodeDebug() */ /*************************************************** FindPreviousSubstring */ static int FindPreviousSubstring(FILE *infile, int *length) { int maxindex, maxlen; int negoffset, i; maxlen = maxindex = 0; /* Try each position (using very slow brute force search) */ for(negoffset = HALF_BUFFER_SIZE - 1; negoffset >= 0; negoffset--) { /* Stop if longer match is not possible */ if( negoffset < maxlen ) break; /* Compare substring bytes up to current position */ for(i = 0; i < negoffset; i++) { assert(ProcOffset + i - negoffset < ProcOffset); if( GetByte(ProcOffset + i - negoffset, infile) != GetByte(ProcOffset + i, infile) ) break; } if( i > maxlen ) { maxindex = negoffset; maxlen = i; } } *length = maxlen; return maxindex; } /* FindPreviousSubstring() */ /************************************************************ WriteLiteral */ static void WriteLiteral(int length, FILE *outfile) { int i; assert(length <= HALF_BUFFER_SIZE); PutWord((WORD)length, outfile); for(i = 0; i < length; i++) PutByte(RingBuffer[(ProcOffset - length + i) & BUFFER_MASK], outfile); } /* WriteLiteral() */ /******************************************************* WriteLiteralDebug */ static int WriteLiteralDebug(int length, FILE *outfile) { int i; (void)fputs("literal:", outfile); for(i = 0; i < length && i < 16; i++) { fprintf(outfile, " %02x", (DWORD)RingBuffer[(ProcOffset - length + i) & BUFFER_MASK]); } if( length > 16 ) (void)fputs(" ...", outfile); fprintf(outfile, " (%d bytes)\n", length); return 2 + length; } /* WriteLiteralDebug() */ /********************************************************** WriteSubstring */ static void WriteSubstring(int length, int negoffset, FILE *outfile) { if( length < 256 ) { PutWord((WORD)(0x8000 | negoffset), outfile); PutByte((BYTE)length, outfile); } else { PutWord((WORD)(0xc000 | negoffset), outfile); PutWord((WORD)length, outfile); } } /* WriteSubstring() */ /***************************************************** WriteSubstringDebug */ static int WriteSubstringDebug(int length, int negoffset, FILE *outfile) { int i; fprintf(outfile, "substring: matched %08x, %d bytes\n ", (DWORD)(ProcOffset - negoffset), length); for(i = 0; i < length && i < 16; i++) { fprintf(outfile, " %02x", (DWORD)RingBuffer[(ProcOffset - negoffset + i) & BUFFER_MASK]); } if( length > 16 ) (void)fputs(" ...", outfile); (void)fputc('\n', outfile); return (length < 256) ? 3 : 4; } /* WriteSubstringDebug() */