/* Program: CMP Author : Kim Moser Date : 12/23/88 System : IBM PC / Borland Turbo-C 2.0 Descrip: Compresses and decompresses files. Model: Small */ #include #include /* O_BINARY */ #include /* setmode */ #include /* Action: */ #define NEITHER 0 #define COMP 1 #define DECOMP 2 static int method=0; /* Compression/decompression method */ #define MAXMETHOD 2 /* Largest known method (1 is smallest) */ static unsigned long int INCOUNT, OUTCOUNT; /* How many characters read and written */ static int append_zero=0; /* Whether to append a zero byte when done compressing */ void halt(char *s) { fprintf(stderr,s); exit(-1); } void usage(void) { fputs("CMP v1.1 09/23/88 Copyright (c) Kim Moser All Rights Reserved\n", stderr ); fputs("Usage: CMP -[switches]\n", stderr); fputs("SWITCH MEANING\n", stderr); fputs(" c1|2 compress stdin to stdout using method 1 or 2\n", stderr); fputs(" d1|2 decompress stdin to stdout using method 1 or 2\n", stderr); fputs(" m output byte containing compression method used\n", stderr); fputs(" z append a zero when done compressing\n", stderr); halt(""); } int parseflags(char *s) /* Parses string 's' of flags and returns either COMP, DECOMP, or NEITHER (error) */ { int r=NEITHER; /* Return value */ int i; for (i=0; s[i]; i++) { switch(s[i]) { case 'C': case 'c': if (r!=NEITHER) usage(); r=COMP; i++; if (!s[i]>='1' || !s[i]<=MAXMETHOD) usage(); method=s[i]-'0'; break; case 'D': case 'd': if (r!=NEITHER) usage(); r=DECOMP; i++; if (!s[i]>='1' || !s[i]-'0'+1<=MAXMETHOD) usage(); method=s[i]-'0'; break; case 'Z': case 'z': append_zero=1; break; default: usage(); } } return r; } void comp1(FILE *fin, FILE *fout) { int character, ch, count; character = ch = getc(fin); count = 1; while (ch != EOF) { INCOUNT++; ch = getc(fin); if ( (ch!=character) || (count==255) ) { /* New character found so write old count and char */ putc( (unsigned char) count, fout ); putc( (unsigned char) character, fout ); OUTCOUNT+=2; count = 1; character = ch; } else { count++; } } } long where(FILE *fp) /* Returns current file pos */ { long r; if ( (r=ftell(fp)) == -1L ) { fputs("Error reading file pointer for stdin.\n"); exit(-1); } } void here(FILE *fp, long p) /* Sets file pointer for 'fp' to 'p' */ { if ( fseek(fp, p, SEEK_SET) ) { fputs("Error setting file pointer for stdin.\n"); exit(-1); } } #define THRESH 3 /* THRESH or more consecutive identical bytes will be written as how_many, the_byte */ void comp2(fin,fout) FILE *fin, *fout; { /* 0 n : the next 'n' bytes are verbatim data (0 0 == end of data) n c : repeat byte 'c' 'n' times Ex: 12 3 3 8 6 6 6 2 2 2 2 -> 0 4 12 3 3 8 3 6 4 2 */ int prev, ch, count; long pos, oldpos; pos = where(fin); prev = ch = getc(fin); count = 1; while (ch != EOF) { INCOUNT++; ch = getc(fin); if ( (ch!=prev) || (count==255) ) { /* It's a run of bytes */ /* Write old count and char: */ putc( (unsigned char) count, fout ); putc( (unsigned char) prev, fout ); OUTCOUNT+=2; pos = where(fin); } else { /* Verbatim chars */ oldpos = where(fin); here(pos); putc( '\0', fout ); OUTCOUNT++; while (count--) { if ( putc( (unsigned char), getc(fin), fout ) == EOF ) { fputs("comp2(): EOF reached while putting verbatim chars.\n", stderr); exit(-1); } OUTCOUNT++; } here(oldpos); } count = 1; prev = ch; } else { count++; } } } void compress(fin, fout) FILE *fin, *fout; { INCOUNT = OUTCOUNT = 0; switch(method) { case 1: comp1(fin,fout); break; default: fprintf(stderr, "compress(): invalid method (%d).\n", method); exit(-1); } if (append_zero) { putc( (unsigned char) 0, fout ); OUTCOUNT++; } } void decomp1(fin, fout) FILE *fin, *fout; { int character, count, i; while ( ((count=getc(fin))!=EOF) && (count!=0) && ((character=getc(fin))!=EOF) ) { INCOUNT+=2; OUTCOUNT += (unsigned long int)count; for (i=0; i