OSDN Git Service

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