home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_C
/
COMP_JCM.ZIP
/
COMPRESS.C
next >
Wrap
C/C++ Source or Header
|
1994-01-14
|
9KB
|
372 lines
/*
Compress.c from Jeffrey C. Moxon, CIS: 73561,1431
GIF file writer converted to file compression routine. Original GIF file
reader is from "Bitmapped Graphics, 2nd Edition" by Steve Rimmer from
McGraw Hill books. The original GIF writer source can be purchased from:
Alchemy Mindworks Inc.
P.O. Box 500
Beeton, Ontario
L0G 1A0, Canada
Although I wouldn't recomend the book because the code is complex and
sloppy (like mine is neat!), I spent some time playing with the GIF
file reader and came up with this. I don't hold any responsibilities
for the code, nor do I make any claims to its effectiveness. It works
moderately well, is written entirely in C and is totally free - I typed
in the code from the book, and corrected the 50 some-odd warning messages.
I would like to see a copy with performance improvements if you manage
any, and/or anything that you produce using this. As it is, I put minimal
effort into this, and it still worked out to be fairly valuable. I also
have no understanding of the mechanics behind the routine.
Have fun,
-JCM-
PS,
The header and main routine aren't necessary. If you open two files
and run them through the compress routine the data from the source
file will be compressed into the target file.
Also, a 'self extracting' module can be made using the dos copy
command with the /B option and a few changes to the explode routine
as follows:
1. compress the files normally
2. copy /B explode.exe + compressedfile
3. modify explode routine to open itself as a source file
4. position file pointer at end of explode.exe/start of data
5. de-compress normally.
*/
// Link with wildargs.obj
#include <process.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <stdio.h>
#include <io.h>
#define largest_code 4095 //<- This number is based on the number
#define table_size 5003 // of bits somehow.
FILE *sf,*tf;
unsigned char code_buffer[259];
int oldcode[table_size];
int currentcode[table_size];
unsigned char newcode[table_size];
int min_code_size = 7; //<- This is the key number for bits stored
int hx,d;
int code_size;
int clear_code;
int eof_code;
int bit_offset;
int bits_left;
int byte_offset;
int max_code;
int free_code;
float percent;
double total_size, compressed_size;
void compress(void);
void init_table(int min_code_size);
void write_code(int code);
void flush(int n);
void strmfe(char *new, char *old, char *ext);
struct file
{
struct ftime i_date; //Original date of file
char name[13]; //Original file name
long initial_size; //Size of original file
long stored_size; //Size of compressed file
char reserved[32]; //Future Use
} files;
struct head
{
char sig[5];
int bytes;
int num_files;
char reserved[32];
} header;
void display_percent(int c_per);
long ten_percent; //Ten percent of file size for display
long c_pos; //Current offset in file used for display of percent done
void main(int argc, char *argv[])
{
struct ftime f_date;
int file_number;
long pos;
char path[69];
total_size = compressed_size = 0;
if (argc < 2)
{
printf("Usage:\nCOMPRESS source target\n");
return;
}
if ((tf = fopen(argv[argc-1], "rb")) != NULL)
{
printf("Target file already exists.\n");
return;
}
if ((tf = fopen(argv[argc-1], "wb")) == NULL)
{
printf("Error creating target file.\n");
return;
}
for(file_number=0;file_number < argc;file_number++)
{
argv[argc] = strupr(argv[file_number]);
strcpy(argv[file_number], argv[argc]);
}
strcpy(header.sig, "MOX94");
strncpy(path, argv[0], strlen(argv[0]) - strlen("COMPRESS.EXE"));
path[strlen(argv[0]) - strlen("COMPRESS.EXE")] = '\0';
header.bytes = (argc-2) * sizeof(files) + sizeof(header);
header.num_files = argc - 1;
/* Create Header Structure */
fwrite(&header, sizeof(header), 1, tf);
fwrite(&files, sizeof(files), argc-2, tf);
for(file_number = 1;file_number < argc - 1;file_number++)
{
printf("Compressing: %13s",argv[file_number]);
if ((sf = fopen(argv[file_number], "rb")) == NULL)
{
printf("Error opening source file.\n");
return;
}
strcpy(files.name, argv[file_number]);
getftime(fileno(sf), &f_date);
files.i_date = f_date;
fseek(sf, 0, SEEK_END);
files.initial_size = ftell(sf);
total_size += files.initial_size;
rewind(sf);
//Determine if text file or binary, and adjust number of bits accordingly
while(!feof(sf))
if (fgetc(sf) > 128)
{
min_code_size = 8;
break;
}
rewind(sf);
fseek(tf, 0, SEEK_END);
pos = ftell(tf);
compress();
pos = ftell(tf) - pos;
fflush(tf);
files.stored_size = pos;
compressed_size += files.stored_size;
percent = (float) files.stored_size/files.initial_size * 100;
printf("%2.02f%%\n", percent);
fseek(tf, sizeof(header) + sizeof(files)*(file_number-1), SEEK_SET);
fwrite(&files, sizeof(files), 1, tf);
fclose(sf);
}
fseek(tf, 0, SEEK_END);
compressed_size = ftell(tf);
fclose(tf);
compressed_size /= 1000;
total_size /= 1000;
percent = (float) compressed_size/total_size * 100;
printf("\nTotal: %.02f kb compressed to %.02f (%3.02f%% of original)\n",
total_size, compressed_size, percent);
return;
}
void compress(void)
{
int prefix_code;
int suffix_char;
static int c_per;
ten_percent = (long) files.initial_size * 0.10;
c_pos = 0;
c_per = 0;
/* write initial code size */
fputc(min_code_size,tf);
/* initialize the encoder */
bit_offset=0;
/* initialize the prefix */
prefix_code = 0;
init_table(min_code_size);
/* get a character to compress */
while((suffix_char=fgetc(sf)) != EOF)
{
if (c_pos++ >= ten_percent)
{
display_percent(c_per+=10);
c_pos = 0;
}
/* derive an index into the code table */
hx=(prefix_code ^ (suffix_char << 5)) % table_size;
d=1;
for(;;)
{
/* see if the code is in the table */
if(currentcode[hx] == 0)
{
/* if not, put it there */
write_code(prefix_code);
d = free_code;
/* find the next free code */
if(free_code <= largest_code)
{
oldcode[hx] = prefix_code;
newcode[hx] = suffix_char;
currentcode[hx] = free_code;
free_code++;
}
/* expand the code size or scrap the table */
if(d == max_code)
{
if(code_size < 12)
{
code_size++;
max_code <<= 1;
}
else
{
write_code(clear_code);
init_table(min_code_size);
}
}
prefix_code = suffix_char;
break;
}
if(oldcode[hx] == prefix_code &&
newcode[hx] == suffix_char)
{
prefix_code = currentcode[hx];
break;
}
hx += d;
d += 2;
if(hx >= table_size) hx -= table_size;
}
}
/* write the prefix code */
write_code(prefix_code);
/* and the end of file code */
write_code(eof_code);
/* flush the buffer */
if(bit_offset > 0) flush((bit_offset+7)/8);
/* write a zero length block */
flush(0);
return;
}
/* initialize the code table */
void init_table(int min_code_size)
{
int i;
code_size=min_code_size+1;
clear_code=(1<<min_code_size);
eof_code=clear_code+1;
free_code=clear_code+2;
max_code=(1<<code_size);
for(i=0;i<table_size;i++) currentcode[i]=0;
return;
}
/* flush the code buffer */
void flush(int n)
{
fputc(n,tf);
fwrite(code_buffer,1,n,tf);
return;
}
/* write a code to the code buffer */
void write_code(int code)
{
long temp;
byte_offset = bit_offset >> 3;
bits_left = bit_offset & 7;
if(byte_offset >= 254)
{
flush(byte_offset);
code_buffer[0] = code_buffer[byte_offset];
bit_offset = bits_left;
byte_offset = 0;
}
if(bits_left > 0)
{
temp = ((long) code << bits_left) | code_buffer[byte_offset];
code_buffer[byte_offset]=temp;
code_buffer[byte_offset+1]=(temp >> 8);
code_buffer[byte_offset+2]=(temp >> 16);
}
else
{
code_buffer[byte_offset] = code;
code_buffer[byte_offset+1]=(code >> 8);
}
bit_offset += code_size;
return;
}
void display_percent(int c_per)
{
int x, y;
if (c_per <= 10) //First trip
x = wherex() + 2;
else
x = wherex() - 4;
y = wherey();
gotoxy(x, y);
printf("%i %", c_per);
if (c_per >= 90) gotoxy(x,y); //Reset for final percentage
return;
}