1 /* $Id: compress.c,v 1.1.1.1 2006/04/17 18:44:35 tromey Exp $
2 
3    $Log: compress.c,v $
4    Revision 1.1.1.1  2006/04/17 18:44:35  tromey
5    Imported fastjar
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   Copyright (C) 2004  Free Software Foundation, Inc.
81 
82   This program is free software; you can redistribute it and/or
83   modify it under the terms of the GNU General Public License
84   as published by the Free Software Foundation; either version 2
85   of the License, or (at your option) any later version.
86 
87   This program is distributed in the hope that it will be useful,
88   but WITHOUT ANY WARRANTY; without even the implied warranty of
89   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
90   GNU General Public License for more details.
91 
92   You should have received a copy of the GNU General Public License
93   along with this program; if not, write to the Free Software
94   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
95  */
96 
97 #include "config.h"
98 
99 #include <zlib.h>
100 #include <string.h>
101 #include <stdio.h>
102 #include <errno.h>
103 
104 #ifdef HAVE_UNISTD_H
105 #include <unistd.h>
106 #endif
107 #ifdef STDC_HEADERS
108 #include <stdlib.h>
109 #endif
110 
111 #include <sys/types.h>
112 
113 #include "jartool.h"
114 #include "pushback.h"
115 #include "compress.h"
116 #include "shift.h"
117 
118 int write_data (int, void *, size_t, struct zipentry *);
119 
120 extern int seekable;
121 extern off_t end_of_entries;
122 
123 static z_stream zs;
124 
init_compression()125 void init_compression(){
126 
127   memset(&zs, 0, sizeof(z_stream));
128 
129   zs.zalloc = Z_NULL;
130   zs.zfree = Z_NULL;
131   zs.opaque = Z_NULL;
132 
133   /* Why -MAX_WBITS?  zlib has an undocumented feature, where if the windowbits
134      parameter is negative, it omits the zlib header, which seems to kill
135      any other zip/unzip program.  This caused me SO much pain.. */
136   if(deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
137                   9, Z_DEFAULT_STRATEGY) != Z_OK){
138 
139     fprintf(stderr, "Error initializing deflation!\n");
140     exit(1);
141   }
142 }
143 
144 int
write_data(int fd,void * buf,size_t len,struct zipentry * ze)145 write_data (int fd, void *buf, size_t len,
146 	    struct zipentry *ze __attribute__((unused)))
147 {
148 #ifdef WITH_SHIFT_DOWN
149   struct zipentry *next = NULL;
150   off_t here = lseek (fd, 0, SEEK_CUR);
151   /*
152    * If we are updating and there is not enough space before the next
153    * entry, expand the file.
154    */
155   if (ze)
156     {
157       next = ze->next_entry;
158       if (next && here + len >= next->offset)
159 	{
160 	  if (shift_down (fd, next->offset, (here + len) - next->offset, next))
161 	    {
162 	      perror ("can't expand file");
163 	      exit (1);
164 	    }
165 	}
166     }
167 #endif /* WITH_SHIFT_DOWN */
168 
169   return write (fd, buf, len);
170 }
171 
compress_file(int in_fd,int out_fd,struct zipentry * ze,struct zipentry * existing)172 int compress_file(int in_fd, int out_fd, struct zipentry *ze,
173 		  struct zipentry *existing)
174 {
175   Bytef in_buff[RDSZ];
176   Bytef out_buff[RDSZ];
177   unsigned int rdamt, wramt;
178   unsigned long tr = 0;
179   int rtval;
180 
181   rdamt = 0;
182 
183   zs.avail_in = 0;
184   zs.next_in = in_buff;
185 
186   zs.next_out = out_buff;
187   zs.avail_out = (uInt)RDSZ;
188 
189   ze->crc = crc32(0L, Z_NULL, 0);
190 
191   for(; ;){
192 
193     /* If deflate is out of input, fill the input buffer for it */
194     if(zs.avail_in == 0 && zs.avail_out > 0){
195       if((rtval = read(in_fd, in_buff, RDSZ)) == 0)
196         break;
197 
198       if(rtval == -1){
199         perror("read");
200         exit(1);
201       }
202 
203       rdamt = rtval;
204 
205       /* compute the CRC while we're at it */
206       ze->crc = crc32(ze->crc, in_buff, rdamt);
207 
208       /* update the total amount read sofar */
209       tr += rdamt;
210 
211       zs.next_in = in_buff;
212       zs.avail_in = rdamt;
213     }
214 
215     /* deflate the data */
216     if(deflate(&zs, 0) != Z_OK){
217       fprintf(stderr, "Error deflating! %s:%d\n", __FILE__, __LINE__);
218       exit(1);
219     }
220 
221     /* If the output buffer is full, dump it to disk */
222     if(zs.avail_out == 0){
223 
224       if (write_data (out_fd, out_buff, RDSZ, existing) != RDSZ)
225 	{
226 	  perror("write");
227 	  exit(1);
228 	}
229 
230       /* clear the output buffer */
231       zs.next_out = out_buff;
232       zs.avail_out = (uInt)RDSZ;
233     }
234 
235   }
236 
237   /* If we have any data waiting in the buffer after we're done with the file
238      we can flush it */
239   if(zs.avail_out < RDSZ){
240 
241     wramt = RDSZ - zs.avail_out;
242 
243     if (write_data (out_fd, out_buff, wramt, existing) != (int)wramt)
244       {
245 	perror("write");
246 	exit(1);
247       }
248     /* clear the output buffer */
249     zs.next_out = out_buff;
250     zs.avail_out = (uInt)RDSZ;
251   }
252 
253 
254   /* finish deflation.  This purges zlib's internal data buffers */
255   while(deflate(&zs, Z_FINISH) == Z_OK){
256     wramt = RDSZ - zs.avail_out;
257 
258     if (write_data (out_fd, out_buff, wramt, existing) != (int)wramt)
259       {
260 	perror("write");
261 	exit(1);
262       }
263 
264     zs.next_out = out_buff;
265     zs.avail_out = (uInt)RDSZ;
266   }
267 
268   /* If there's any data left in the buffer, write it out */
269   if(zs.avail_out != RDSZ){
270     wramt = RDSZ - zs.avail_out;
271 
272     if (write_data (out_fd, out_buff, wramt, existing) != (int)wramt)
273       {
274 	perror("write");
275 	exit(1);
276       }
277   }
278 
279   /* update fastjar's entry information */
280   ze->usize = (ub4)zs.total_in;
281   ze->csize = (ub4)zs.total_out;
282 
283   /* Reset the deflation for the next time around */
284   if(deflateReset(&zs) != Z_OK){
285     fprintf(stderr, "Error resetting deflation\n");
286     exit(1);
287   }
288 
289   return 0;
290 }
291 
end_compression()292 void end_compression(){
293   int rtval;
294 
295   /* Oddly enough, zlib always returns Z_DATA_ERROR if you specify no
296      zlib header.  Go fig. */
297   if((rtval = deflateEnd(&zs)) != Z_OK && rtval != Z_DATA_ERROR){
298     fprintf(stderr, "Error calling deflateEnd\n");
299     fprintf(stderr, "error: (%d) %s\n", rtval, zs.msg);
300     exit(1);
301   }
302 }
303 
304 
init_inflation()305 void init_inflation(){
306 
307   memset(&zs, 0, sizeof(z_stream));
308 
309   zs.zalloc = Z_NULL;
310   zs.zfree = Z_NULL;
311   zs.opaque = Z_NULL;
312 
313   if(inflateInit2(&zs, -15) != Z_OK){
314     fprintf(stderr, "Error initializing deflation!\n");
315     exit(1);
316   }
317 
318 }
319 
inflate_file(pb_file * pbf,int out_fd,struct zipentry * ze)320 int inflate_file(pb_file *pbf, int out_fd, struct zipentry *ze){
321   Bytef in_buff[RDSZ];
322   Bytef out_buff[RDSZ];
323   unsigned int rdamt;
324   int rtval;
325   ub4 crc = 0;
326 
327   zs.avail_in = 0;
328 
329   crc = crc32(crc, NULL, 0); /* initialize crc */
330 
331   /* loop until we've consumed all the compressed data */
332   for(;;){
333 
334     if(zs.avail_in == 0){
335       if((rdamt = pb_read(pbf, in_buff, RDSZ)) == 0)
336         break;
337       else if((int)rdamt < 0){
338         perror("read");
339         exit(1);
340       }
341 
342 #ifdef DEBUG
343       printf("%d bytes read\n", rdamt);
344 #endif
345 
346       zs.next_in = in_buff;
347       zs.avail_in = rdamt;
348     }
349 
350     zs.next_out = out_buff;
351     zs.avail_out = RDSZ;
352 
353     if((rtval = inflate(&zs, 0)) != Z_OK){
354       if(rtval == Z_STREAM_END){
355 #ifdef DEBUG
356         printf("end of stream\n");
357 #endif
358         if(zs.avail_out != RDSZ){
359           crc = crc32(crc, out_buff, (RDSZ - zs.avail_out));
360 
361           if(out_fd >= 0)
362             if(write(out_fd, out_buff, (RDSZ - zs.avail_out)) !=
363                (int)(RDSZ - zs.avail_out)){
364               perror("write");
365               exit(1);
366             }
367         }
368 
369         break;
370       } else {
371         fprintf(stderr, "Error inflating file! (%d)\n", rtval);
372         exit(1);
373       }
374     } else {
375       if(zs.avail_out != RDSZ){
376         crc = crc32(crc, out_buff, (RDSZ - zs.avail_out));
377 
378         if(out_fd >= 0)
379           if(write(out_fd, out_buff, (RDSZ - zs.avail_out)) !=
380              (int)(RDSZ - zs.avail_out)){
381             perror("write");
382             exit(1);
383           }
384         zs.next_out = out_buff;
385         zs.avail_out = RDSZ;
386       }
387     }
388   }
389 #ifdef DEBUG
390   printf("done inflating\n");
391 #endif
392 
393 #ifdef DEBUG
394   printf("%d bytes left over\n", zs.avail_in);
395 #endif
396 
397 #ifdef DEBUG
398   printf("CRC is %x\n", crc);
399 #endif
400 
401   ze->crc = crc;
402 
403   pb_push(pbf, zs.next_in, zs.avail_in);
404 
405   ze->usize = zs.total_out;
406 
407   inflateReset(&zs);
408   return 0;
409 }
410 
411 /*
412 Function name: report_str_error
413 args:	val	Error code returned from zlib.
414 purpose: Put out an error message corresponding to error code returned from zlib.
415 Be suitably cryptic seeing I don't really know exactly what these errors mean.
416 */
417 
report_str_error(int val)418 static void report_str_error(int val) {
419 	switch(val) {
420 	case Z_STREAM_END:
421 		break;
422 	case Z_NEED_DICT:
423 		fprintf(stderr, "Need a dictionary?\n");
424 		exit(1);
425 	case Z_DATA_ERROR:
426 		fprintf(stderr, "Z_DATA_ERROR\n");
427 		exit(1);
428 	case Z_STREAM_ERROR:
429 		fprintf(stderr, "Z_STREAM_ERROR\n");
430 		exit(1);
431 	case Z_MEM_ERROR:
432 		fprintf(stderr, "Z_MEM_ERROR\n");
433 		exit(1);
434 	case Z_BUF_ERROR:
435 		fprintf(stderr, "Z_BUF_ERROR\n");
436 		exit(1);
437 	case Z_OK:
438 		break;
439 	default:
440 		fprintf(stderr, "Unknown behavior from inflate\n");
441 		exit(1);
442 	}
443 }
444 
445 /*
446 Function name: ez_inflate_str
447 args:	pbf		Pointer to pushback handle for file.
448 		csize	Compressed size of embedded file.
449 		usize	Uncompressed size of embedded file.
450 purpose: Read in and decompress the contents of an embedded file and store it in a
451 byte array.
452 returns: Byte array of uncompressed embedded file.
453 */
454 
ez_inflate_str(pb_file * pbf,ub4 csize,ub4 usize)455 static Bytef *ez_inflate_str(pb_file *pbf, ub4 csize, ub4 usize) {
456 	Bytef *out_buff;
457 	Bytef *in_buff;
458 	unsigned int rdamt;
459 
460 	if((zs.next_in = in_buff = (Bytef *) malloc(csize))) {
461 		if((zs.next_out = out_buff = (Bytef *) malloc(usize + 1))) {
462 			if((rdamt = pb_read(pbf, zs.next_in, csize)) == csize) {
463 				zs.avail_in = csize;
464 				zs.avail_out = usize;
465 				report_str_error(inflate(&zs, 0));
466 				free(in_buff);
467 				inflateReset(&zs);
468 				out_buff[usize] = '\0';
469 			}
470 			else {
471 				fprintf(stderr, "Read failed on input file.\n");
472 				fprintf(stderr, "Tried to read %u but read %u instead.\n", csize, rdamt);
473 				free(in_buff);
474 				free(out_buff);
475 				exit(1);
476 			}
477 		}
478 		else {
479 			fprintf(stderr, "Malloc of out_buff failed.\n");
480 			fprintf(stderr, "Error: %s\n", strerror(errno));
481 			free(in_buff);
482 			exit(1);
483 		}
484 	}
485 	else {
486 		fprintf(stderr, "Malloc of in_buff failed.\n");
487 		fprintf(stderr, "Error: %s\n", strerror(errno));
488 		exit(1);
489 	}
490 
491 	return out_buff;
492 }
493 
494 /*
495 Function name: hrd_inflate_str
496 args:	pbf		Pointer to pushback handle for file.
497 		csize	Pointer to compressed size of embedded file.
498 		usize	Pointer to uncompressed size of embedded file.
499 purpose: Read and decompress an embedded file into a string.  Set csize and usize
500 accordingly.  This function does the reading for us in the case there is not size
501 information in the header for the embedded file.
502 returns: Byte array of the contents of the embedded file.
503 */
504 
hrd_inflate_str(pb_file * pbf,ub4 * csize,ub4 * usize)505 static Bytef *hrd_inflate_str(pb_file *pbf, ub4 *csize, ub4 *usize) {
506 	Bytef *out_buff;
507 	Bytef *tmp;
508 	Bytef in_buff[RDSZ];
509 	unsigned int rdamt;
510 	int i;
511 	int zret;
512 
513 	i = 1;
514 	out_buff = NULL;
515 	zret = Z_OK;
516 	while(zret != Z_STREAM_END && (rdamt = pb_read(pbf, in_buff, RDSZ)))
517 	{
518 		zs.avail_in = rdamt;
519 		zs.avail_out = 0;
520 		zs.next_in = in_buff;
521 		do {
522 			if((tmp = (Bytef *) realloc(out_buff, (RDSZ * i) + 1))) {
523 				out_buff = tmp;
524 				zs.next_out = &(out_buff[(RDSZ * (i - 1)) - zs.avail_out]);
525 				zs.avail_out += RDSZ;
526 				i++;
527 			}
528 			else {
529 				fprintf(stderr, "Realloc of out_buff failed.\n");
530 				fprintf(stderr, "Error: %s\n", strerror(errno));
531 				exit(1);
532 			}
533 		} while((zret = inflate(&zs, 0)) == Z_OK);
534 		report_str_error(zret);
535 	}
536 	pb_push(pbf, zs.next_in, zs.avail_in);
537 
538 	out_buff[(RDSZ * (i - 1)) - zs.avail_out] = '\0';
539 	*usize = zs.total_out;
540 	*csize = zs.total_in;
541 
542 	inflateReset(&zs);
543 
544 	return out_buff;
545 }
546 
547 /*
548 Function name: inflate_string
549 args:	pbf		Pointer to pushback handle for file.
550 		csize	Pointer to compressed size of embedded file.  May be 0 if not set.
551 		usize	Pointer to uncompressed size of embedded file. May be 0 if not set.
552 purpose: Decide the easiest (in computer terms) methos of decompressing this embedded
553 file to a string.
554 returns: Pointer to a string containing the decompressed contents of the embedded file.
555 If csize and usize are not set set them to correct numbers.
556 */
557 
inflate_string(pb_file * pbf,ub4 * csize,ub4 * usize)558 Bytef *inflate_string(pb_file *pbf, ub4 *csize, ub4 *usize) {
559 Bytef *ret_buf;
560 
561 	if(*csize && *usize) ret_buf = ez_inflate_str(pbf, *csize, *usize);
562 	else ret_buf = hrd_inflate_str(pbf, csize, usize);
563 
564 	return ret_buf;
565 }
566