/* ************************************************************************* Module: mydeflate.c Author: Matt Simpson Arlington, TX matthewsimpson@home.com Date: August, 2000 Description: Compresses a file using zlib (deflate). Output is either binary or base64 encoded text strings. This file is not included in Pup's Makefile, but rather compiled separately and used for adding compressed arrays into an include file to be called and decompressed by Pup. Used for compressing images or other large items. To compile: gcc -g -Wall -O2 mydeflate.c -o mydeflate -lz Procedure: If you have a large image in PostScript or xpm format, compress it with mydeflate like this: mydeflate -m image image.h image.h will be a text file containing the compressed image as base64 encoded printable ASCII characters. Edit image.h and put this around the entire set of strings: char name[] = {" XXXXXXXXX XXXXXXXXX XXXXXXXXX ===="}; In this example XXXXXXXXX represents the characters of the strings and name is whatever you want to call it. There is a quote at the beginning and at the end of the entire set. For IRIX cc compiler: put beginning and ending quotes on each line, with a \n before the ending quote, like this: char name[] = { "XXXXXXXXX\n" "XXXXXXXXX\n" "XXXXXXXXX\n" "====\n"}; Both methods above are supported by gcc, but IRIX cc complains if a string takes more than 1 line without quotes. The \n is required because the decoding routine looks for it. In the first method above the \n is really there, you just see it as a carriage return that happens to also reside with the characters. If you know the vi editor, the task of adding the quotes and \n marks is very easy :0) Then include this file in the .c file that will call this array and use the code in ptp.c to design your own decoding & inflation function. Pup does this starting in the function uue_inflate(). **************************************************************************** COPYRIGHT (C) 2000 Matt Simpson GNU General Public License See lexgui.c for full notice. zlib is a free library, Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler The base64 encoding is done with included source code from the uuencode program. See NOTICE in the encode() function header below. **************************************************************************** */ #include #include #include #include #define BUFSIZE 32768 typedef struct { FILE *out; unsigned char *buf; int cur_size; int i; int format; } out_struct; /* Function Prototypes */ void encode (out_struct *out); void check_err(int err, char *msg); void output(z_stream *z, char *out_buf, out_struct *out); void call_deflate(FILE *fp_in, out_struct *out); /* ------------------------------------------------------------------------- encode () Copy from IN to OUT, encoding as you go along. ********************************* NOTICE ******************************** The code in this function was taken from source code in the uuencode program. It was modified to only use base64 encoding. The input and output methods were also modified. The uuencode program is: Copyright (c) 1983 Regents of the University of California. Copyright (C) 1994, 1995 Free Software Foundation, Inc. All rights reserved. The uuencode program is licensed with the GNU General Public License. A notice is required to use this source code. The notice is contained in the README file accompanying Pup. The source code used came from: ftp://ftp.gnu.org/pub/gnu/sharutils/sharutils-4.2.1.tar.gz ************************************************************************* ------------------------------------------------------------------------- */ void encode (out_struct *out) { int end; const char *trans_ptr; register int ch, n; register char *p = NULL; char buf[80]; char c1, c2; const char uu_base64[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; /* I am hard coding this to use base64 */ trans_ptr = uu_base64; /* ENC is the basic 1 character encoding function to make a char printing. */ #define ENC(Char) (trans_ptr[(Char) & 077]) fprintf(out->out, "begin-base64 664 /dev/stdout\n"); end = out->i; /* end of string, at the NULL terminator position */ out->i = 0; while (1) { /*--------------------------------------------------- The following is used to read from stdin. I replaced it with reading from out->buf ----------------------------------------------------- */ #ifdef COMMENTED_OUT n = 0; do { register int m = fread (buf, 1, 45 - n, stdin); if (m == 0) break; n += m; } while (n < 45); #endif /*----------------------------------------------------*/ for(n = 0; n < 45; n++) { if(out->i == end) /* if at the end (don't need the NULL) */ break; buf[n] = out->buf[out->i++]; } /*----------------------------------------------------*/ if (n == 0) break; for (p = buf; n > 2; n -= 3, p += 3) { ch = *p >> 2; ch = ENC (ch); if (putc (ch, out->out) == EOF) break; ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017); ch = ENC (ch); if (putc (ch, out->out) == EOF) break; ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03); ch = ENC (ch); if (putc (ch, out->out) == EOF) break; ch = p[2] & 077; ch = ENC (ch); if (putc (ch, out->out) == EOF) break; } if (n != 0) break; if (putc ('\n', out->out) == EOF) break; } while (n != 0) { c1 = *p; c2 = n == 1 ? 0 : p[1]; ch = c1 >> 2; ch = ENC (ch); if (putc (ch, out->out) == EOF) break; ch = ((c1 << 4) & 060) | ((c2 >> 4) & 017); ch = ENC (ch); if (putc (ch, out->out) == EOF) break; if (n == 1) ch = '='; else { ch = (c2 << 2) & 074; ch = ENC (ch); } if (putc (ch, out->out) == EOF) break; ch = '='; if (putc (ch, out->out) == EOF) break; putc ('\n', out->out); break; } fprintf (out->out, "====\n"); } /* ------------------------------------------------------------------------- check_err() ------------------------------------------------------------------------- */ void check_err(int err, char *msg) { if(err != Z_OK) { fprintf(stderr, "%s error: %d\n", msg, err); exit(1); } } /* ------------------------------------------------------------------------- output() Writes compressed file or packs out->out for later encoding. ------------------------------------------------------------------------- */ void output(z_stream *z, char *out_buf, out_struct *out) { int i; int count; count = BUFSIZE - z->avail_out; if ( count ) { if(!out->format) fwrite(out_buf, 1, count, out->out); else { if(out->i + count > out->cur_size - 1) { out->cur_size += BUFSIZE + 1; out->buf = (unsigned char *) realloc(out->buf, out->cur_size * sizeof(char)); if(out->buf == NULL) { fprintf(stderr, "\nError allocating memory.\n\n"); exit(1); } } for(i = 0; i < count; i++) out->buf[out->i++] = out_buf[i]; out->buf[out->i] = 0; } } } /* ------------------------------------------------------------------------- call_deflate() ------------------------------------------------------------------------- */ void call_deflate(FILE *fp_in, out_struct *out) { int i; z_stream z; char in_buf[BUFSIZE + 1] = {"\0"}; char out_buf[BUFSIZE + 1] = {"\0"}; int err; for(i = 0; i < BUFSIZE + 1; i++) out_buf[i] = 0; z.zalloc = (alloc_func)0; z.zfree = (free_func)0; z.opaque = (voidpf)0; /* Deflate */ err = deflateInit(&z, Z_DEFAULT_COMPRESSION); check_err(err, "deflateInit"); z.avail_in = 0; z.next_out = out_buf; z.avail_out = BUFSIZE; for ( ; ; ) { if ( z.avail_in == 0 ) { z.next_in = in_buf; z.avail_in = fread( in_buf, 1, BUFSIZE, fp_in ); } if ( z.avail_in == 0 ) { err = deflate( &z, Z_FINISH); output(&z, out_buf, out); break; } err = deflate( &z, Z_NO_FLUSH ); check_err(err, "deflate"); output(&z, out_buf, out); z.next_out = out_buf; z.avail_out = BUFSIZE; } err = deflateEnd(&z); check_err(err, "deflateEnd"); } /* ------------------------------------------------------------------------- ------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { int i; char INFILE[256], OUTFILE[256]; FILE *fp_in = NULL; out_struct out; strcpy(INFILE, "\0"); strcpy(OUTFILE, "\0"); out.out = NULL; out.buf = NULL; out.cur_size = 0; out.i = 0; out.format = 0; if(argc < 3) { fprintf(stderr, "\nCompress a file using zlib (deflate).\n"); fprintf(stderr, "Usage: mydeflate [ -m ] \n"); fprintf(stderr, " Options:\n"); fprintf(stderr, " (none) Output in binary format.\n"); fprintf(stderr, " -m Output in base64 encoded printable ASCII characters.\n\n"); exit(1); } /* Look for keywords in the command line */ for(i = 1; i < argc; i++) { if(!strcmp(argv[i], "-m")) { out.format = 1; argv[i][0] = 0; break; } } /* Get first 2 command line words as the input & output filenames */ for(i = 1; i < argc; i++) { if(strcmp(argv[i], "\0")) { if(strcmp(INFILE, "\0")) { strcpy(OUTFILE, argv[i]); break; } else strcpy(INFILE, argv[i]); } } if(!strcmp(OUTFILE, "\0")) { fprintf(stderr, "\nOutput not given. Program aborted.\n\n"); exit(1); } if(out.format) { out.buf = (unsigned char *) malloc((BUFSIZE + 1) * sizeof(char)); if(out.buf == NULL) { fprintf(stderr, "\nError initializing memory.\n\n"); exit(1); } out.buf[0] = 0; out.cur_size = BUFSIZE + 1; } fp_in = fopen (INFILE, "r"); if(fp_in == NULL) { fprintf(stderr, "\nError opening input. Program aborted.\n\n"); exit(1); } out.out = fopen(OUTFILE, "w"); if(out.out == NULL) { fprintf(stderr, "\nError opening output. Program aborted.\n\n"); exit(1); } call_deflate(fp_in, &out); if(out.format) encode(&out); fclose(fp_in); fclose(out.out); exit(0); }