1 #include <stdio.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <limits.h>
6 #include "zlib.h"
7 
8 #define GZBUFSIZE 115200    /* 40 FITS blocks */
9 #define BUFFINCR   28800    /* 10 FITS blocks */
10 
11 /* prototype for the following functions */
12 int uncompress2mem(char *filename,
13              FILE *diskfile,
14              char **buffptr,
15              size_t *buffsize,
16              void *(*mem_realloc)(void *p, size_t newsize),
17              size_t *filesize,
18              int *status);
19 
20 int uncompress2mem_from_mem(
21              char *inmemptr,
22              size_t inmemsize,
23              char **buffptr,
24              size_t *buffsize,
25              void *(*mem_realloc)(void *p, size_t newsize),
26              size_t *filesize,
27              int *status);
28 
29 int uncompress2file(char *filename,
30              FILE *indiskfile,
31              FILE *outdiskfile,
32              int *status);
33 
34 
35 int compress2mem_from_mem(
36              char *inmemptr,
37              size_t inmemsize,
38              char **buffptr,
39              size_t *buffsize,
40              void *(*mem_realloc)(void *p, size_t newsize),
41              size_t *filesize,
42              int *status);
43 
44 int compress2file_from_mem(
45              char *inmemptr,
46              size_t inmemsize,
47              FILE *outdiskfile,
48              size_t *filesize,   /* O - size of file, in bytes              */
49              int *status);
50 
51 
52 /*--------------------------------------------------------------------------*/
uncompress2mem(char * filename,FILE * diskfile,char ** buffptr,size_t * buffsize,void * (* mem_realloc)(void * p,size_t newsize),size_t * filesize,int * status)53 int uncompress2mem(char *filename,  /* name of input file                 */
54              FILE *diskfile,     /* I - file pointer                        */
55              char **buffptr,   /* IO - memory pointer                     */
56              size_t *buffsize,   /* IO - size of buffer, in bytes           */
57              void *(*mem_realloc)(void *p, size_t newsize), /* function     */
58              size_t *filesize,   /* O - size of file, in bytes              */
59              int *status)        /* IO - error status                       */
60 
61 /*
62   Uncompress the disk file into memory.  Fill whatever amount of memory has
63   already been allocated, then realloc more memory, using the supplied
64   input function, if necessary.
65 */
66 {
67     int err, len;
68     char *filebuff;
69     z_stream d_stream;   /* decompression stream */
70     /* Input args buffptr and buffsize may refer to a block of memory
71         larger than the 2^32 4 byte limit.  If so, must be broken
72         up into "pages" when assigned to d_stream.
73         (d_stream.avail_out is a uInt type, which might be smaller
74         than buffsize's size_t type.)
75     */
76     const uLong nPages = (uLong)(*buffsize)/(uLong)UINT_MAX;
77     uLong iPage=0;
78     uInt outbuffsize = (nPages > 0) ? UINT_MAX : (uInt)(*buffsize);
79 
80 
81     if (*status > 0)
82         return(*status);
83 
84     /* Allocate memory to hold compressed bytes read from the file. */
85     filebuff = (char*)malloc(GZBUFSIZE);
86     if (!filebuff) return(*status = 113); /* memory error */
87 
88     d_stream.zalloc = (alloc_func)0;
89     d_stream.zfree = (free_func)0;
90     d_stream.opaque = (voidpf)0;
91     d_stream.next_out = (unsigned char*) *buffptr;
92     d_stream.avail_out = outbuffsize;
93 
94     /* Initialize the decompression.  The argument (15+16) tells the
95        decompressor that we are to use the gzip algorithm */
96 
97     err = inflateInit2(&d_stream, (15+16));
98     if (err != Z_OK) return(*status = 414);
99 
100     /* loop through the file, reading a buffer and uncompressing it */
101     for (;;)
102     {
103         len = fread(filebuff, 1, GZBUFSIZE, diskfile);
104 	if (ferror(diskfile)) {
105               inflateEnd(&d_stream);
106               free(filebuff);
107               return(*status = 414);
108 	}
109 
110         if (len == 0) break;  /* no more data */
111 
112         d_stream.next_in = (unsigned char*)filebuff;
113         d_stream.avail_in = len;
114 
115         for (;;) {
116             /* uncompress as much of the input as will fit in the output */
117             err = inflate(&d_stream, Z_NO_FLUSH);
118 
119             if (err == Z_STREAM_END ) { /* We reached the end of the input */
120 	        break;
121             } else if (err == Z_OK ) {
122 
123                 if (!d_stream.avail_in) break; /* need more input */
124 
125                 /* need more space in output buffer */
126                 /* First check if more memory is available above the
127                     4Gb limit in the originally input buffptr array */
128                 if (iPage < nPages)
129                 {
130                    ++iPage;
131                    d_stream.next_out = (unsigned char*)(*buffptr + iPage*(uLong)UINT_MAX);
132                    if (iPage < nPages)
133                       d_stream.avail_out = UINT_MAX;
134                    else
135                       d_stream.avail_out = (uInt)((uLong)(*buffsize) % (uLong)UINT_MAX);
136                 }
137                 else if (mem_realloc) {
138                     *buffptr = mem_realloc(*buffptr,*buffsize + BUFFINCR);
139                     if (*buffptr == NULL){
140                         inflateEnd(&d_stream);
141                         free(filebuff);
142                         return(*status = 414);  /* memory allocation failed */
143                     }
144 
145                     d_stream.avail_out = BUFFINCR;
146                     d_stream.next_out = (unsigned char*) (*buffptr + *buffsize);
147                     *buffsize = *buffsize + BUFFINCR;
148                 } else  { /* error: no realloc function available */
149                     inflateEnd(&d_stream);
150                     free(filebuff);
151                     return(*status = 414);
152                 }
153             } else {  /* some other error */
154                 inflateEnd(&d_stream);
155                 free(filebuff);
156                 return(*status = 414);
157             }
158         }
159 
160 	if (feof(diskfile))  break;
161 /*
162         These settings for next_out and avail_out appear to be redundant,
163         as the inflate() function should already be re-setting these.
164         For case where *buffsize < 4Gb this did not matter, but for
165         > 4Gb it would produce the wrong value in the avail_out assignment.
166         (C. Gordon Jul 2016)
167         d_stream.next_out = (unsigned char*) (*buffptr + d_stream.total_out);
168         d_stream.avail_out = *buffsize - d_stream.total_out;
169 */    }
170 
171     /* Set the output file size to be the total output data */
172     *filesize = d_stream.total_out;
173 
174     free(filebuff); /* free temporary output data buffer */
175 
176     err = inflateEnd(&d_stream); /* End the decompression */
177     if (err != Z_OK) return(*status = 414);
178 
179     return(*status);
180 }
181 /*--------------------------------------------------------------------------*/
uncompress2mem_from_mem(char * inmemptr,size_t inmemsize,char ** buffptr,size_t * buffsize,void * (* mem_realloc)(void * p,size_t newsize),size_t * filesize,int * status)182 int uncompress2mem_from_mem(
183              char *inmemptr,     /* I - memory pointer to compressed bytes */
184              size_t inmemsize,   /* I - size of input compressed file      */
185              char **buffptr,   /* IO - memory pointer                      */
186              size_t *buffsize,   /* IO - size of buffer, in bytes           */
187              void *(*mem_realloc)(void *p, size_t newsize), /* function     */
188              size_t *filesize,   /* O - size of file, in bytes              */
189              int *status)        /* IO - error status                       */
190 
191 /*
192   Uncompress the file in memory into memory.  Fill whatever amount of memory has
193   already been allocated, then realloc more memory, using the supplied
194   input function, if necessary.
195 */
196 {
197     int err;
198     z_stream d_stream;   /* decompression stream */
199 
200     if (*status > 0)
201         return(*status);
202 
203     d_stream.zalloc = (alloc_func)0;
204     d_stream.zfree = (free_func)0;
205     d_stream.opaque = (voidpf)0;
206 
207     /* Initialize the decompression.  The argument (15+16) tells the
208        decompressor that we are to use the gzip algorithm */
209     err = inflateInit2(&d_stream, (15+16));
210     if (err != Z_OK) return(*status = 414);
211 
212     d_stream.next_in = (unsigned char*)inmemptr;
213     d_stream.avail_in = inmemsize;
214 
215     d_stream.next_out = (unsigned char*) *buffptr;
216     d_stream.avail_out = *buffsize;
217 
218     for (;;) {
219         /* uncompress as much of the input as will fit in the output */
220         err = inflate(&d_stream, Z_NO_FLUSH);
221 
222         if (err == Z_STREAM_END) { /* We reached the end of the input */
223 	    break;
224         } else if (err == Z_OK ) { /* need more space in output buffer */
225 
226             if (mem_realloc) {
227                 *buffptr = mem_realloc(*buffptr,*buffsize + BUFFINCR);
228                 if (*buffptr == NULL){
229                     inflateEnd(&d_stream);
230                     return(*status = 414);  /* memory allocation failed */
231                 }
232 
233                 d_stream.avail_out = BUFFINCR;
234                 d_stream.next_out = (unsigned char*) (*buffptr + *buffsize);
235                 *buffsize = *buffsize + BUFFINCR;
236 
237             } else  { /* error: no realloc function available */
238                 inflateEnd(&d_stream);
239                 return(*status = 414);
240             }
241         } else {  /* some other error */
242             inflateEnd(&d_stream);
243             return(*status = 414);
244         }
245     }
246 
247     /* Set the output file size to be the total output data */
248     if (filesize) *filesize = d_stream.total_out;
249 
250     /* End the decompression */
251     err = inflateEnd(&d_stream);
252 
253     if (err != Z_OK) return(*status = 414);
254 
255     return(*status);
256 }
257 /*--------------------------------------------------------------------------*/
uncompress2file(char * filename,FILE * indiskfile,FILE * outdiskfile,int * status)258 int uncompress2file(char *filename,  /* name of input file                  */
259              FILE *indiskfile,     /* I - input file pointer                */
260              FILE *outdiskfile,    /* I - output file pointer               */
261              int *status)        /* IO - error status                       */
262 /*
263   Uncompress the file into another file.
264 */
265 {
266     int err, len;
267     unsigned long bytes_out = 0;
268     char *infilebuff, *outfilebuff;
269     z_stream d_stream;   /* decompression stream */
270 
271     if (*status > 0)
272         return(*status);
273 
274     /* Allocate buffers to hold compressed and uncompressed */
275     infilebuff = (char*)malloc(GZBUFSIZE);
276     if (!infilebuff) return(*status = 113); /* memory error */
277 
278     outfilebuff = (char*)malloc(GZBUFSIZE);
279     if (!outfilebuff) return(*status = 113); /* memory error */
280 
281     d_stream.zalloc = (alloc_func)0;
282     d_stream.zfree = (free_func)0;
283     d_stream.opaque = (voidpf)0;
284 
285     d_stream.next_out = (unsigned char*) outfilebuff;
286     d_stream.avail_out = GZBUFSIZE;
287 
288     /* Initialize the decompression.  The argument (15+16) tells the
289        decompressor that we are to use the gzip algorithm */
290 
291     err = inflateInit2(&d_stream, (15+16));
292     if (err != Z_OK) return(*status = 414);
293 
294     /* loop through the file, reading a buffer and uncompressing it */
295     for (;;)
296     {
297         len = fread(infilebuff, 1, GZBUFSIZE, indiskfile);
298 	if (ferror(indiskfile)) {
299               inflateEnd(&d_stream);
300               free(infilebuff);
301               free(outfilebuff);
302               return(*status = 414);
303 	}
304 
305         if (len == 0) break;  /* no more data */
306 
307         d_stream.next_in = (unsigned char*)infilebuff;
308         d_stream.avail_in = len;
309 
310         for (;;) {
311             /* uncompress as much of the input as will fit in the output */
312             err = inflate(&d_stream, Z_NO_FLUSH);
313 
314             if (err == Z_STREAM_END ) { /* We reached the end of the input */
315 	        break;
316             } else if (err == Z_OK ) {
317 
318                 if (!d_stream.avail_in) break; /* need more input */
319 
320                 /* flush out the full output buffer */
321                 if ((int)fwrite(outfilebuff, 1, GZBUFSIZE, outdiskfile) != GZBUFSIZE) {
322                     inflateEnd(&d_stream);
323                     free(infilebuff);
324                     free(outfilebuff);
325                     return(*status = 414);
326                 }
327                 bytes_out += GZBUFSIZE;
328                 d_stream.next_out = (unsigned char*) outfilebuff;
329                 d_stream.avail_out = GZBUFSIZE;
330 
331             } else {  /* some other error */
332                 inflateEnd(&d_stream);
333                 free(infilebuff);
334                 free(outfilebuff);
335                 return(*status = 414);
336             }
337         }
338 
339 	if (feof(indiskfile))  break;
340     }
341 
342     /* write out any remaining bytes in the buffer */
343     if (d_stream.total_out > bytes_out) {
344         if ((int)fwrite(outfilebuff, 1, (d_stream.total_out - bytes_out), outdiskfile)
345 	    != (d_stream.total_out - bytes_out)) {
346             inflateEnd(&d_stream);
347             free(infilebuff);
348             free(outfilebuff);
349             return(*status = 414);
350         }
351     }
352 
353     free(infilebuff); /* free temporary output data buffer */
354     free(outfilebuff); /* free temporary output data buffer */
355 
356     err = inflateEnd(&d_stream); /* End the decompression */
357     if (err != Z_OK) return(*status = 414);
358 
359     return(*status);
360 }
361 /*--------------------------------------------------------------------------*/
compress2mem_from_mem(char * inmemptr,size_t inmemsize,char ** buffptr,size_t * buffsize,void * (* mem_realloc)(void * p,size_t newsize),size_t * filesize,int * status)362 int compress2mem_from_mem(
363              char *inmemptr,     /* I - memory pointer to uncompressed bytes */
364              size_t inmemsize,   /* I - size of input uncompressed file      */
365              char **buffptr,   /* IO - memory pointer for compressed file    */
366              size_t *buffsize,   /* IO - size of buffer, in bytes           */
367              void *(*mem_realloc)(void *p, size_t newsize), /* function     */
368              size_t *filesize,   /* O - size of file, in bytes              */
369              int *status)        /* IO - error status                       */
370 
371 /*
372   Compress the file into memory.  Fill whatever amount of memory has
373   already been allocated, then realloc more memory, using the supplied
374   input function, if necessary.
375 */
376 {
377     int err;
378     z_stream c_stream;  /* compression stream */
379 
380     if (*status > 0)
381         return(*status);
382 
383     c_stream.zalloc = (alloc_func)0;
384     c_stream.zfree = (free_func)0;
385     c_stream.opaque = (voidpf)0;
386 
387     /* Initialize the compression.  The argument (15+16) tells the
388        compressor that we are to use the gzip algorythm.
389        Also use Z_BEST_SPEED for maximum speed with very minor loss
390        in compression factor. */
391     err = deflateInit2(&c_stream, Z_BEST_SPEED, Z_DEFLATED,
392                        (15+16), 8, Z_DEFAULT_STRATEGY);
393 
394     if (err != Z_OK) return(*status = 413);
395 
396     c_stream.next_in = (unsigned char*)inmemptr;
397     c_stream.avail_in = inmemsize;
398 
399     c_stream.next_out = (unsigned char*) *buffptr;
400     c_stream.avail_out = *buffsize;
401 
402     for (;;) {
403         /* compress as much of the input as will fit in the output */
404         err = deflate(&c_stream, Z_FINISH);
405 
406         if (err == Z_STREAM_END) {  /* We reached the end of the input */
407 	   break;
408         } else if (err == Z_OK ) { /* need more space in output buffer */
409 
410             if (mem_realloc) {
411                 *buffptr = mem_realloc(*buffptr,*buffsize + BUFFINCR);
412                 if (*buffptr == NULL){
413                     deflateEnd(&c_stream);
414                     return(*status = 413);  /* memory allocation failed */
415                 }
416 
417                 c_stream.avail_out = BUFFINCR;
418                 c_stream.next_out = (unsigned char*) (*buffptr + *buffsize);
419                 *buffsize = *buffsize + BUFFINCR;
420 
421             } else  { /* error: no realloc function available */
422                 deflateEnd(&c_stream);
423                 return(*status = 413);
424             }
425         } else {  /* some other error */
426             deflateEnd(&c_stream);
427             return(*status = 413);
428         }
429     }
430 
431     /* Set the output file size to be the total output data */
432     if (filesize) *filesize = c_stream.total_out;
433 
434     /* End the compression */
435     err = deflateEnd(&c_stream);
436 
437     if (err != Z_OK) return(*status = 413);
438 
439     return(*status);
440 }
441 /*--------------------------------------------------------------------------*/
compress2file_from_mem(char * inmemptr,size_t inmemsize,FILE * outdiskfile,size_t * filesize,int * status)442 int compress2file_from_mem(
443              char *inmemptr,     /* I - memory pointer to uncompressed bytes */
444              size_t inmemsize,   /* I - size of input uncompressed file      */
445              FILE *outdiskfile,
446              size_t *filesize,   /* O - size of file, in bytes              */
447              int *status)
448 
449 /*
450   Compress the memory file into disk file.
451 */
452 {
453     int err;
454     unsigned long bytes_out = 0;
455     char  *outfilebuff;
456     z_stream c_stream;  /* compression stream */
457 
458     if (*status > 0)
459         return(*status);
460 
461     /* Allocate buffer to hold compressed bytes */
462     outfilebuff = (char*)malloc(GZBUFSIZE);
463     if (!outfilebuff) return(*status = 113); /* memory error */
464 
465     c_stream.zalloc = (alloc_func)0;
466     c_stream.zfree = (free_func)0;
467     c_stream.opaque = (voidpf)0;
468 
469     /* Initialize the compression.  The argument (15+16) tells the
470        compressor that we are to use the gzip algorythm.
471        Also use Z_BEST_SPEED for maximum speed with very minor loss
472        in compression factor. */
473     err = deflateInit2(&c_stream, Z_BEST_SPEED, Z_DEFLATED,
474                        (15+16), 8, Z_DEFAULT_STRATEGY);
475 
476     if (err != Z_OK) return(*status = 413);
477 
478     c_stream.next_in = (unsigned char*)inmemptr;
479     c_stream.avail_in = inmemsize;
480 
481     c_stream.next_out = (unsigned char*) outfilebuff;
482     c_stream.avail_out = GZBUFSIZE;
483 
484     for (;;) {
485         /* compress as much of the input as will fit in the output */
486         err = deflate(&c_stream, Z_FINISH);
487 
488         if (err == Z_STREAM_END) {  /* We reached the end of the input */
489 	   break;
490         } else if (err == Z_OK ) { /* need more space in output buffer */
491 
492             /* flush out the full output buffer */
493             if ((int)fwrite(outfilebuff, 1, GZBUFSIZE, outdiskfile) != GZBUFSIZE) {
494                 deflateEnd(&c_stream);
495                 free(outfilebuff);
496                 return(*status = 413);
497             }
498             bytes_out += GZBUFSIZE;
499             c_stream.next_out = (unsigned char*) outfilebuff;
500             c_stream.avail_out = GZBUFSIZE;
501 
502 
503         } else {  /* some other error */
504             deflateEnd(&c_stream);
505             free(outfilebuff);
506             return(*status = 413);
507         }
508     }
509 
510     /* write out any remaining bytes in the buffer */
511     if (c_stream.total_out > bytes_out) {
512         if ((int)fwrite(outfilebuff, 1, (c_stream.total_out - bytes_out), outdiskfile)
513 	    != (c_stream.total_out - bytes_out)) {
514             deflateEnd(&c_stream);
515             free(outfilebuff);
516             return(*status = 413);
517         }
518     }
519 
520     free(outfilebuff); /* free temporary output data buffer */
521 
522     /* Set the output file size to be the total output data */
523     if (filesize) *filesize = c_stream.total_out;
524 
525     /* End the compression */
526     err = deflateEnd(&c_stream);
527 
528     if (err != Z_OK) return(*status = 413);
529 
530     return(*status);
531 }
532