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