1 /* $Id: compress.c 119 2004-10-05 20:38:42Z oyvind $
2 
3    $Log$
4    Revision 1.1  2004/10/05 20:31:35  oyvind
5    	* added GCC to repository
6 
7    Revision 1.2  2000/12/14 18:45:35  ghazi
8    Warning fixes:
9 
10    	* compress.c: Include stdlib.h and compress.h.
11    	(rcsid): Delete.
12    	(report_str_error): Make static.
13    	(ez_inflate_str): Delete unused variable.  Add parens in if-stmt.
14    	(hrd_inflate_str): Likewise.
15 
16    	* compress.h (init_compression, end_compression, init_inflation,
17    	end_inflation): Prototype void arguments.
18 
19    	* dostime.c (rcsid): Delete.
20 
21    	* jargrep.c: Include ctype.h, stdlib.h, zlib.h and compress.h.
22    	Make functions static.  Cast ctype function argument to `unsigned
23    	char'.  Add parens in if-stmts.  Constify.
24    	(Usage): Change into a macro.
25    	(jargrep): Remove unused parameter.
26 
27    	* jartool.c: Constify.  Add parens in if-stmts.  Align
28    	signed/unsigned char pointers in functions calls using casts.
29    	(rcsid): Delete.
30    	(list_jar): Fix printf format specifier.
31    	(usage): Chop long string into bits.  Reformat.
32 
33    	* pushback.c (rcsid): Delete.
34 
35    Revision 1.1  2000/12/09 03:08:23  apbianco
36    2000-12-08  Alexandre Petit-Bianco  <apbianco@cygnus.com>
37 
38            * fastjar: Imported.
39 
40    Revision 1.7  2000/09/13 14:02:02  cory
41    Reformatted some of the code to more closly match the layout of the orriginal
42    fastjar utility.
43 
44    Revision 1.6  2000/09/12 22:29:36  cory
45    Jargrep now seems to do what I want it to do.  Performs properly on Linux x86,
46    will test some other platforms later.
47 
48    Revision 1.1.1.1  1999/12/06 03:09:16  toast
49    initial checkin..
50 
51 
52 
53    Revision 1.7  1999/05/10 08:50:05  burnsbr
54    *** empty log message ***
55 
56    Revision 1.6  1999/05/10 08:38:44  burnsbr
57    *** empty log message ***
58 
59    Revision 1.5  1999/05/10 08:30:29  burnsbr
60    added inflation code
61 
62    Revision 1.4  1999/04/27 10:03:33  burnsbr
63    added configure support
64 
65    Revision 1.3  1999/04/26 02:35:32  burnsbr
66    compression now works.. yahoo
67 
68    Revision 1.2  1999/04/23 12:01:59  burnsbr
69    added licence stuff.
70 
71    Revision 1.1  1999/04/23 11:58:25  burnsbr
72    Initial revision
73 
74 
75 */
76 
77 /*
78   compress.c - code for handling deflation
79   Copyright (C) 1999  Bryan Burns
80 
81   This program is free software; you can redistribute it and/or
82   modify it under the terms of the GNU General Public License
83   as published by the Free Software Foundation; either version 2
84   of the License, or (at your option) any later version.
85 
86   This program is distributed in the hope that it will be useful,
87   but WITHOUT ANY WARRANTY; without even the implied warranty of
88   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
89   GNU General Public License for more details.
90 
91   You should have received a copy of the GNU General Public License
92   along with this program; if not, write to the Free Software
93   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
94  */
95 
96 #include "config.h"
97 
98 #include <zlib.h>
99 #include <string.h>
100 #include <stdio.h>
101 #include <errno.h>
102 
103 #ifdef HAVE_UNISTD_H
104 #include <unistd.h>
105 #endif
106 #ifdef STDC_HEADERS
107 #include <stdlib.h>
108 #endif
109 
110 #include <sys/types.h>
111 
112 #include "jartool.h"
113 #include "pushback.h"
114 #include "compress.h"
115 
116 extern int seekable;
117 
118 static z_stream zs;
119 
init_compression()120 void init_compression(){
121 
122   memset(&zs, 0, sizeof(z_stream));
123 
124   zs.zalloc = Z_NULL;
125   zs.zfree = Z_NULL;
126   zs.opaque = Z_NULL;
127 
128   /* Why -MAX_WBITS?  zlib has an undocumented feature, where if the windowbits
129      parameter is negative, it omits the zlib header, which seems to kill
130      any other zip/unzip program.  This caused me SO much pain.. */
131   if(deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
132                   9, Z_DEFAULT_STRATEGY) != Z_OK){
133 
134     fprintf(stderr, "Error initializing deflation!\n");
135     exit(1);
136   }
137 }
138 
compress_file(int in_fd,int out_fd,struct zipentry * ze)139 int compress_file(int in_fd, int out_fd, struct zipentry *ze){
140   Bytef in_buff[RDSZ];
141   Bytef out_buff[RDSZ];
142   unsigned int rdamt, wramt;
143   unsigned long tr = 0;
144   int rtval;
145 
146   rdamt = 0;
147 
148   zs.avail_in = 0;
149   zs.next_in = in_buff;
150 
151   zs.next_out = out_buff;
152   zs.avail_out = (uInt)RDSZ;
153 
154   ze->crc = crc32(0L, Z_NULL, 0);
155 
156   for(; ;){
157 
158     /* If deflate is out of input, fill the input buffer for it */
159     if(zs.avail_in == 0 && zs.avail_out > 0){
160       if((rtval = read(in_fd, in_buff, RDSZ)) == 0)
161         break;
162 
163       if(rtval == -1){
164         perror("read");
165         exit(1);
166       }
167 
168       rdamt = rtval;
169 
170       /* compute the CRC while we're at it */
171       ze->crc = crc32(ze->crc, in_buff, rdamt);
172 
173       /* update the total amount read sofar */
174       tr += rdamt;
175 
176       zs.next_in = in_buff;
177       zs.avail_in = rdamt;
178     }
179 
180     /* deflate the data */
181     if(deflate(&zs, 0) != Z_OK){
182       fprintf(stderr, "Error deflating! %s:%d\n", __FILE__, __LINE__);
183       exit(1);
184     }
185 
186     /* If the output buffer is full, dump it to disk */
187     if(zs.avail_out == 0){
188 
189       if(write(out_fd, out_buff, RDSZ) != RDSZ){
190         perror("write");
191         exit(1);
192       }
193 
194       /* clear the output buffer */
195       zs.next_out = out_buff;
196       zs.avail_out = (uInt)RDSZ;
197     }
198 
199   }
200 
201   /* If we have any data waiting in the buffer after we're done with the file
202      we can flush it */
203   if(zs.avail_out < RDSZ){
204 
205     wramt = RDSZ - zs.avail_out;
206 
207     if(write(out_fd, out_buff, wramt) != (int)wramt){
208       perror("write");
209       exit(1);
210     }
211     /* clear the output buffer */
212     zs.next_out = out_buff;
213     zs.avail_out = (uInt)RDSZ;
214   }
215 
216 
217   /* finish deflation.  This purges zlib's internal data buffers */
218   while(deflate(&zs, Z_FINISH) == Z_OK){
219     wramt = RDSZ - zs.avail_out;
220 
221     if(write(out_fd, out_buff, wramt) != (int)wramt){
222       perror("write");
223       exit(1);
224     }
225 
226     zs.next_out = out_buff;
227     zs.avail_out = (uInt)RDSZ;
228   }
229 
230   /* If there's any data left in the buffer, write it out */
231   if(zs.avail_out != RDSZ){
232     wramt = RDSZ - zs.avail_out;
233 
234     if(write(out_fd, out_buff, wramt) != (int)wramt){
235       perror("write");
236       exit(1);
237     }
238   }
239 
240   /* update fastjar's entry information */
241   ze->usize = (ub4)zs.total_in;
242   ze->csize = (ub4)zs.total_out;
243 
244   /* Reset the deflation for the next time around */
245   if(deflateReset(&zs) != Z_OK){
246     fprintf(stderr, "Error resetting deflation\n");
247     exit(1);
248   }
249 
250   return 0;
251 }
252 
end_compression()253 void end_compression(){
254   int rtval;
255 
256   /* Oddly enough, zlib always returns Z_DATA_ERROR if you specify no
257      zlib header.  Go fig. */
258   if((rtval = deflateEnd(&zs)) != Z_OK && rtval != Z_DATA_ERROR){
259     fprintf(stderr, "Error calling deflateEnd\n");
260     fprintf(stderr, "error: (%d) %s\n", rtval, zs.msg);
261     exit(1);
262   }
263 }
264 
265 
init_inflation()266 void init_inflation(){
267 
268   memset(&zs, 0, sizeof(z_stream));
269 
270   zs.zalloc = Z_NULL;
271   zs.zfree = Z_NULL;
272   zs.opaque = Z_NULL;
273 
274   if(inflateInit2(&zs, -15) != Z_OK){
275     fprintf(stderr, "Error initializing deflation!\n");
276     exit(1);
277   }
278 
279 }
280 
inflate_file(pb_file * pbf,int out_fd,struct zipentry * ze)281 int inflate_file(pb_file *pbf, int out_fd, struct zipentry *ze){
282   Bytef in_buff[RDSZ];
283   Bytef out_buff[RDSZ];
284   unsigned int rdamt;
285   int rtval;
286   ub4 crc = 0;
287 
288   zs.avail_in = 0;
289 
290   crc = crc32(crc, NULL, 0); /* initialize crc */
291 
292   /* loop until we've consumed all the compressed data */
293   for(;;){
294 
295     if(zs.avail_in == 0){
296       if((rdamt = pb_read(pbf, in_buff, RDSZ)) == 0)
297         break;
298       else if((int)rdamt < 0){
299         perror("read");
300         exit(1);
301       }
302 
303 #ifdef DEBUG
304       printf("%d bytes read\n", rdamt);
305 #endif
306 
307       zs.next_in = in_buff;
308       zs.avail_in = rdamt;
309     }
310 
311     zs.next_out = out_buff;
312     zs.avail_out = RDSZ;
313 
314     if((rtval = inflate(&zs, 0)) != Z_OK){
315       if(rtval == Z_STREAM_END){
316 #ifdef DEBUG
317         printf("end of stream\n");
318 #endif
319         if(zs.avail_out != RDSZ){
320           crc = crc32(crc, out_buff, (RDSZ - zs.avail_out));
321 
322           if(out_fd >= 0)
323             if(write(out_fd, out_buff, (RDSZ - zs.avail_out)) !=
324                (int)(RDSZ - zs.avail_out)){
325               perror("write");
326               exit(1);
327             }
328         }
329 
330         break;
331       } else {
332         fprintf(stderr, "Error inflating file! (%d)\n", rtval);
333         exit(1);
334       }
335     } else {
336       if(zs.avail_out != RDSZ){
337         crc = crc32(crc, out_buff, (RDSZ - zs.avail_out));
338 
339         if(out_fd >= 0)
340           if(write(out_fd, out_buff, (RDSZ - zs.avail_out)) !=
341              (int)(RDSZ - zs.avail_out)){
342             perror("write");
343             exit(1);
344           }
345         zs.next_out = out_buff;
346         zs.avail_out = RDSZ;
347       }
348     }
349   }
350 #ifdef DEBUG
351   printf("done inflating\n");
352 #endif
353 
354 #ifdef DEBUG
355   printf("%d bytes left over\n", zs.avail_in);
356 #endif
357 
358 #ifdef DEBUG
359   printf("CRC is %x\n", crc);
360 #endif
361 
362   ze->crc = crc;
363 
364   pb_push(pbf, zs.next_in, zs.avail_in);
365 
366   ze->usize = zs.total_out;
367 
368   inflateReset(&zs);
369   return 0;
370 }
371 
372 /*
373 Function name: report_str_error
374 args:	val	Error code returned from zlib.
375 purpose: Put out an error message corresponding to error code returned from zlib.
376 Be suitably cryptic seeing I don't really know exactly what these errors mean.
377 */
378 
report_str_error(int val)379 static void report_str_error(int val) {
380 	switch(val) {
381 	case Z_STREAM_END:
382 		break;
383 	case Z_NEED_DICT:
384 		fprintf(stderr, "Need a dictionary?\n");
385 		exit(1);
386 	case Z_DATA_ERROR:
387 		fprintf(stderr, "Z_DATA_ERROR\n");
388 		exit(1);
389 	case Z_STREAM_ERROR:
390 		fprintf(stderr, "Z_STREAM_ERROR\n");
391 		exit(1);
392 	case Z_MEM_ERROR:
393 		fprintf(stderr, "Z_MEM_ERROR\n");
394 		exit(1);
395 	case Z_BUF_ERROR:
396 		fprintf(stderr, "Z_BUF_ERROR\n");
397 		exit(1);
398 	case Z_OK:
399 		break;
400 	default:
401 		fprintf(stderr, "Unknown behavior from inflate\n");
402 		exit(1);
403 	}
404 }
405 
406 /*
407 Function name: ez_inflate_str
408 args:	pbf		Pointer to pushback handle for file.
409 		csize	Compressed size of embedded file.
410 		usize	Uncompressed size of embedded file.
411 purpose: Read in and decompress the contents of an embedded file and store it in a
412 byte array.
413 returns: Byte array of uncompressed embedded file.
414 */
415 
ez_inflate_str(pb_file * pbf,ub4 csize,ub4 usize)416 static Bytef *ez_inflate_str(pb_file *pbf, ub4 csize, ub4 usize) {
417 	Bytef *out_buff;
418 	Bytef *in_buff;
419 	unsigned int rdamt;
420 
421 	if((zs.next_in = in_buff = (Bytef *) malloc(csize))) {
422 		if((zs.next_out = out_buff = (Bytef *) malloc(usize + 1))) {
423 			if((rdamt = pb_read(pbf, zs.next_in, csize)) == csize) {
424 				zs.avail_in = csize;
425 				zs.avail_out = usize;
426 				report_str_error(inflate(&zs, 0));
427 				free(in_buff);
428 				inflateReset(&zs);
429 				out_buff[usize] = '\0';
430 			}
431 			else {
432 				fprintf(stderr, "Read failed on input file.\n");
433 				fprintf(stderr, "Tried to read %u but read %u instead.\n", csize, rdamt);
434 				free(in_buff);
435 				free(out_buff);
436 				exit(1);
437 			}
438 		}
439 		else {
440 			fprintf(stderr, "Malloc of out_buff failed.\n");
441 			fprintf(stderr, "Error: %s\n", strerror(errno));
442 			free(in_buff);
443 			exit(1);
444 		}
445 	}
446 	else {
447 		fprintf(stderr, "Malloc of in_buff failed.\n");
448 		fprintf(stderr, "Error: %s\n", strerror(errno));
449 		exit(1);
450 	}
451 
452 	return out_buff;
453 }
454 
455 /*
456 Function name: hrd_inflate_str
457 args:	pbf		Pointer to pushback handle for file.
458 		csize	Pointer to compressed size of embedded file.
459 		usize	Pointer to uncompressed size of embedded file.
460 purpose: Read and decompress an embedded file into a string.  Set csize and usize
461 accordingly.  This function does the reading for us in the case there is not size
462 information in the header for the embedded file.
463 returns: Byte array of the contents of the embedded file.
464 */
465 
hrd_inflate_str(pb_file * pbf,ub4 * csize,ub4 * usize)466 static Bytef *hrd_inflate_str(pb_file *pbf, ub4 *csize, ub4 *usize) {
467 	Bytef *out_buff;
468 	Bytef *tmp;
469 	Bytef in_buff[RDSZ];
470 	unsigned int rdamt;
471 	int i;
472 	int zret;
473 
474 	i = 1;
475 	out_buff = NULL;
476 	zret = Z_OK;
477 	while(zret != Z_STREAM_END && (rdamt = pb_read(pbf, in_buff, RDSZ)))
478 	{
479 		zs.avail_in = rdamt;
480 		zs.avail_out = 0;
481 		zs.next_in = in_buff;
482 		do {
483 			if((tmp = (Bytef *) realloc(out_buff, (RDSZ * i) + 1))) {
484 				out_buff = tmp;
485 				zs.next_out = &(out_buff[(RDSZ * (i - 1)) - zs.avail_out]);
486 				zs.avail_out += RDSZ;
487 				i++;
488 			}
489 			else {
490 				fprintf(stderr, "Realloc of out_buff failed.\n");
491 				fprintf(stderr, "Error: %s\n", strerror(errno));
492 				exit(1);
493 			}
494 		} while((zret = inflate(&zs, 0)) == Z_OK);
495 		report_str_error(zret);
496 	}
497 	pb_push(pbf, zs.next_in, zs.avail_in);
498 
499 	out_buff[(RDSZ * (i - 1)) - zs.avail_out] = '\0';
500 	*usize = zs.total_out;
501 	*csize = zs.total_in;
502 
503 	inflateReset(&zs);
504 
505 	return out_buff;
506 }
507 
508 /*
509 Function name: inflate_string
510 args:	pbf		Pointer to pushback handle for file.
511 		csize	Pointer to compressed size of embedded file.  May be 0 if not set.
512 		usize	Pointer to uncompressed size of embedded file. May be 0 if not set.
513 purpose: Decide the easiest (in computer terms) methos of decompressing this embedded
514 file to a string.
515 returns: Pointer to a string containing the decompressed contents of the embedded file.
516 If csize and usize are not set set them to correct numbers.
517 */
518 
inflate_string(pb_file * pbf,ub4 * csize,ub4 * usize)519 Bytef *inflate_string(pb_file *pbf, ub4 *csize, ub4 *usize) {
520 Bytef *ret_buf;
521 
522 	if(*csize && *usize) ret_buf = ez_inflate_str(pbf, *csize, *usize);
523 	else ret_buf = hrd_inflate_str(pbf, csize, usize);
524 
525 	return ret_buf;
526 }
527