1/* minigzip.c -- simulate gzip using the zlib compression library 2 * Copyright (C) 1995-1998 Jean-loup Gailly. 3 * For conditions of distribution and use, see copyright notice in zlib.h 4 */ 5 6/* 7 * minigzip is a minimal implementation of the gzip utility. This is 8 * only an example of using zlib and isn't meant to replace the 9 * full-featured gzip. No attempt is made to deal with file systems 10 * limiting names to 14 or 8+3 characters, etc... Error checking is 11 * very limited. So use minigzip only for testing; use gzip for the 12 * real thing. On MSDOS, use only on file names without extension 13 * or in pipe mode. 14 */ 15 16/* @(#) $Id: minigzip.c 241205 2011-02-17 21:57:41Z $ */ 17 18#include <stdio.h> 19#include "zlib.h" 20 21#ifdef STDC 22# include <string.h> 23# include <stdlib.h> 24#else 25 extern void exit OF((int)); 26#endif 27 28#ifdef USE_MMAP 29# include <sys/types.h> 30# include <sys/mman.h> 31# include <sys/stat.h> 32#endif 33 34#if defined(MSDOS) || defined(OS2) || defined(WIN32) 35# include <fcntl.h> 36# include <io.h> 37# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) 38#else 39# define SET_BINARY_MODE(file) 40#endif 41 42#ifdef VMS 43# define unlink delete 44# define GZ_SUFFIX "-gz" 45#endif 46#ifdef RISCOS 47# define unlink remove 48# define GZ_SUFFIX "-gz" 49# define fileno(file) file->__file 50#endif 51#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os 52# include <unix.h> /* for fileno */ 53#endif 54 55#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ 56 extern int unlink OF((const char *)); 57#endif 58 59#ifndef GZ_SUFFIX 60# define GZ_SUFFIX ".gz" 61#endif 62#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) 63 64#define BUFLEN 16384 65#define MAX_NAME_LEN 1024 66 67#ifdef MAXSEG_64K 68# define local static 69 /* Needed for systems with limitation on stack size. */ 70#else 71# define local 72#endif 73 74char *prog; 75 76void error OF((const char *msg)); 77void gz_compress OF((FILE *in, gzFile out)); 78#ifdef USE_MMAP 79int gz_compress_mmap OF((FILE *in, gzFile out)); 80#endif 81void gz_uncompress OF((gzFile in, FILE *out)); 82void file_compress OF((char *file, char *mode)); 83void file_uncompress OF((char *file)); 84int main OF((int argc, char *argv[])); 85 86/* =========================================================================== 87 * Display error message and exit 88 */ 89void error(msg) 90 const char *msg; 91{ 92 fprintf(stderr, "%s: %s\n", prog, msg); 93 exit(1); 94} 95 96/* =========================================================================== 97 * Compress input to output then close both files. 98 */ 99 100void gz_compress(in, out) 101 FILE *in; 102 gzFile out; 103{ 104 local char buf[BUFLEN]; 105 int len; 106 int err; 107 108#ifdef USE_MMAP 109 /* Try first compressing with mmap. If mmap fails (minigzip used in a 110 * pipe), use the normal fread loop. 111 */ 112 if (gz_compress_mmap(in, out) == Z_OK) return; 113#endif 114 for (;;) { 115 len = fread(buf, 1, sizeof(buf), in); 116 if (ferror(in)) { 117 perror("fread"); 118 exit(1); 119 } 120 if (len == 0) break; 121 122 if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); 123 } 124 fclose(in); 125 if (gzclose(out) != Z_OK) error("failed gzclose"); 126} 127 128#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ 129 130/* Try compressing the input file at once using mmap. Return Z_OK if 131 * if success, Z_ERRNO otherwise. 132 */ 133int gz_compress_mmap(in, out) 134 FILE *in; 135 gzFile out; 136{ 137 int len; 138 int err; 139 int ifd = fileno(in); 140 caddr_t buf; /* mmap'ed buffer for the entire input file */ 141 off_t buf_len; /* length of the input file */ 142 struct stat sb; 143 144 /* Determine the size of the file, needed for mmap: */ 145 if (fstat(ifd, &sb) < 0) return Z_ERRNO; 146 buf_len = sb.st_size; 147 if (buf_len <= 0) return Z_ERRNO; 148 149 /* Now do the actual mmap: */ 150 buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); 151 if (buf == (caddr_t)(-1)) return Z_ERRNO; 152 153 /* Compress the whole file at once: */ 154 len = gzwrite(out, (char *)buf, (unsigned)buf_len); 155 156 if (len != (int)buf_len) error(gzerror(out, &err)); 157 158 munmap(buf, buf_len); 159 fclose(in); 160 if (gzclose(out) != Z_OK) error("failed gzclose"); 161 return Z_OK; 162} 163#endif /* USE_MMAP */ 164 165/* =========================================================================== 166 * Uncompress input to output then close both files. 167 */ 168void gz_uncompress(in, out) 169 gzFile in; 170 FILE *out; 171{ 172 local char buf[BUFLEN]; 173 int len; 174 int err; 175 176 for (;;) { 177 len = gzread(in, buf, sizeof(buf)); 178 if (len < 0) error (gzerror(in, &err)); 179 if (len == 0) break; 180 181 if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { 182 error("failed fwrite"); 183 } 184 } 185 if (fclose(out)) error("failed fclose"); 186 187 if (gzclose(in) != Z_OK) error("failed gzclose"); 188} 189 190 191/* =========================================================================== 192 * Compress the given file: create a corresponding .gz file and remove the 193 * original. 194 */ 195void file_compress(file, mode) 196 char *file; 197 char *mode; 198{ 199 local char outfile[MAX_NAME_LEN]; 200 FILE *in; 201 gzFile out; 202 203 strcpy(outfile, file); 204 strcat(outfile, GZ_SUFFIX); 205 206 in = fopen(file, "rb"); 207 if (in == NULL) { 208 perror(file); 209 exit(1); 210 } 211 out = gzopen(outfile, mode); 212 if (out == NULL) { 213 fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); 214 exit(1); 215 } 216 gz_compress(in, out); 217 218 unlink(file); 219} 220 221 222/* =========================================================================== 223 * Uncompress the given file and remove the original. 224 */ 225void file_uncompress(file) 226 char *file; 227{ 228 local char buf[MAX_NAME_LEN]; 229 char *infile, *outfile; 230 FILE *out; 231 gzFile in; 232 int len = strlen(file); 233 234 strcpy(buf, file); 235 236 if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { 237 infile = file; 238 outfile = buf; 239 outfile[len-3] = '\0'; 240 } else { 241 outfile = file; 242 infile = buf; 243 strcat(infile, GZ_SUFFIX); 244 } 245 in = gzopen(infile, "rb"); 246 if (in == NULL) { 247 fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); 248 exit(1); 249 } 250 out = fopen(outfile, "wb"); 251 if (out == NULL) { 252 perror(file); 253 exit(1); 254 } 255 256 gz_uncompress(in, out); 257 258 unlink(infile); 259} 260 261 262/* =========================================================================== 263 * Usage: minigzip [-d] [-f] [-h] [-1 to -9] [files...] 264 * -d : decompress 265 * -f : compress with Z_FILTERED 266 * -h : compress with Z_HUFFMAN_ONLY 267 * -1 to -9 : compression level 268 */ 269 270int main(argc, argv) 271 int argc; 272 char *argv[]; 273{ 274 int uncompr = 0; 275 gzFile file; 276 char outmode[20]; 277 278 strcpy(outmode, "wb6 "); 279 280 prog = argv[0]; 281 argc--, argv++; 282 283 while (argc > 0) { 284 if (strcmp(*argv, "-d") == 0) 285 uncompr = 1; 286 else if (strcmp(*argv, "-f") == 0) 287 outmode[3] = 'f'; 288 else if (strcmp(*argv, "-h") == 0) 289 outmode[3] = 'h'; 290 else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && 291 (*argv)[2] == 0) 292 outmode[2] = (*argv)[1]; 293 else 294 break; 295 argc--, argv++; 296 } 297 if (argc == 0) { 298 SET_BINARY_MODE(stdin); 299 SET_BINARY_MODE(stdout); 300 if (uncompr) { 301 file = gzdopen(fileno(stdin), "rb"); 302 if (file == NULL) error("can't gzdopen stdin"); 303 gz_uncompress(file, stdout); 304 } else { 305 file = gzdopen(fileno(stdout), outmode); 306 if (file == NULL) error("can't gzdopen stdout"); 307 gz_compress(stdin, file); 308 } 309 } else { 310 do { 311 if (uncompr) { 312 file_uncompress(*argv); 313 } else { 314 file_compress(*argv, outmode); 315 } 316 } while (argv++, --argc); 317 } 318 exit(0); 319 return 0; /* to avoid warning */ 320} 321