:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / lib / bzip2 / bzip2.c
1
2 /*-----------------------------------------------------------*/
3 /*--- A block-sorting, lossless compressor        bzip2.c ---*/
4 /*-----------------------------------------------------------*/
5
6 /*--
7   This file is a part of bzip2 and/or libbzip2, a program and
8   library for lossless, block-sorting data compression.
9
10   Copyright (C) 1996-2000 Julian R Seward.  All rights reserved.
11
12   Redistribution and use in source and binary forms, with or without
13   modification, are permitted provided that the following conditions
14   are met:
15
16   1. Redistributions of source code must retain the above copyright
17      notice, this list of conditions and the following disclaimer.
18
19   2. The origin of this software must not be misrepresented; you must 
20      not claim that you wrote the original software.  If you use this 
21      software in a product, an acknowledgment in the product 
22      documentation would be appreciated but is not required.
23
24   3. Altered source versions must be plainly marked as such, and must
25      not be misrepresented as being the original software.
26
27   4. The name of the author may not be used to endorse or promote 
28      products derived from this software without specific prior written 
29      permission.
30
31   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
32   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
35   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
37   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
43   Julian Seward, Cambridge, UK.
44   jseward@acm.org
45   bzip2/libbzip2 version 1.0 of 21 March 2000
46
47   This program is based on (at least) the work of:
48      Mike Burrows
49      David Wheeler
50      Peter Fenwick
51      Alistair Moffat
52      Radford Neal
53      Ian H. Witten
54      Robert Sedgewick
55      Jon L. Bentley
56
57   For more information on these sources, see the manual.
58 --*/
59
60
61 /*----------------------------------------------------*/
62 /*--- IMPORTANT                                    ---*/
63 /*----------------------------------------------------*/
64
65 /*--
66    WARNING:
67       This program and library (attempts to) compress data by 
68       performing several non-trivial transformations on it.  
69       Unless you are 100% familiar with *all* the algorithms 
70       contained herein, and with the consequences of modifying them, 
71       you should NOT meddle with the compression or decompression 
72       machinery.  Incorrect changes can and very likely *will* 
73       lead to disasterous loss of data.
74
75    DISCLAIMER:
76       I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
77       USE OF THIS PROGRAM, HOWSOEVER CAUSED.
78
79       Every compression of a file implies an assumption that the
80       compressed file can be decompressed to reproduce the original.
81       Great efforts in design, coding and testing have been made to
82       ensure that this program works correctly.  However, the
83       complexity of the algorithms, and, in particular, the presence
84       of various special cases in the code which occur with very low
85       but non-zero probability make it impossible to rule out the
86       possibility of bugs remaining in the program.  DO NOT COMPRESS
87       ANY DATA WITH THIS PROGRAM AND/OR LIBRARY UNLESS YOU ARE PREPARED 
88       TO ACCEPT THE POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL 
89       NOT BE RECOVERABLE.
90
91       That is not to say this program is inherently unreliable.
92       Indeed, I very much hope the opposite is true.  bzip2/libbzip2
93       has been carefully constructed and extensively tested.
94
95    PATENTS:
96       To the best of my knowledge, bzip2/libbzip2 does not use any 
97       patented algorithms.  However, I do not have the resources 
98       available to carry out a full patent search.  Therefore I cannot 
99       give any guarantee of the above statement.
100 --*/
101
102
103
104 /*----------------------------------------------------*/
105 /*--- and now for something much more pleasant :-) ---*/
106 /*----------------------------------------------------*/
107
108 /*---------------------------------------------*/
109 /*--
110   Place a 1 beside your platform, and 0 elsewhere.
111 --*/
112
113 /*--
114   Generic 32-bit Unix.
115   Also works on 64-bit Unix boxes.
116 --*/
117 #define BZ_UNIX      1
118
119 /*--
120   Win32, as seen by Jacob Navia's excellent
121   port of (Chris Fraser & David Hanson)'s excellent
122   lcc compiler.
123 --*/
124 #define BZ_LCCWIN32  0
125
126 #if defined(_WIN32) && !defined(__CYGWIN__)
127 #undef  BZ_LCCWIN32
128 #define BZ_LCCWIN32 1
129 #undef  BZ_UNIX
130 #define BZ_UNIX 0
131 #endif
132
133
134 /*---------------------------------------------*/
135 /*--
136   Some stuff for all platforms.
137 --*/
138
139 #include <stdio.h>
140 #include <stdlib.h>
141 #include <string.h>
142 #include <signal.h>
143 #include <math.h>
144 #include <errno.h>
145 #include <ctype.h>
146 #include "bzlib.h"
147
148 #define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
149 #define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
150 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
151
152
153 /*---------------------------------------------*/
154 /*--
155    Platform-specific stuff.
156 --*/
157
158 #if BZ_UNIX
159 #   include <sys/types.h>
160 #   include <utime.h>
161 #   include <unistd.h>
162 #   include <sys/stat.h>
163 #   include <sys/times.h>
164
165 #   define PATH_SEP    '/'
166 #   define MY_LSTAT    lstat
167 #   define MY_S_IFREG  S_ISREG
168 #   define MY_STAT     stat
169
170 #   define APPEND_FILESPEC(root, name) \
171       root=snocString((root), (name))
172
173 #   define APPEND_FLAG(root, name) \
174       root=snocString((root), (name))
175
176 #   define SET_BINARY_MODE(fd) /**/
177
178 #   ifdef __GNUC__
179 #      define NORETURN __attribute__ ((noreturn))
180 #   else
181 #      define NORETURN /**/
182 #   endif
183 #   ifdef __DJGPP__
184 #     include <io.h>
185 #     include <fcntl.h>
186 #     undef MY_LSTAT
187 #     define MY_LSTAT stat
188 #     undef SET_BINARY_MODE
189 #     define SET_BINARY_MODE(fd)                        \
190         do {                                            \
191            int retVal = setmode ( fileno ( fd ),        \
192                                  O_BINARY );            \
193            ERROR_IF_MINUS_ONE ( retVal );               \
194         } while ( 0 )
195 #   endif
196 #   ifdef __CYGWIN__
197 #     include <io.h>
198 #     include <fcntl.h>
199 #     undef SET_BINARY_MODE
200 #     define SET_BINARY_MODE(fd)                        \
201         do {                                            \
202            int retVal = setmode ( fileno ( fd ),        \
203                                  O_BINARY );            \
204            ERROR_IF_MINUS_ONE ( retVal );               \
205         } while ( 0 )
206 #   endif
207 #endif
208
209
210
211 #if BZ_LCCWIN32
212 #   include <io.h>
213 #   include <fcntl.h>
214 #   include <sys\stat.h>
215
216 #   define NORETURN       /**/
217 #   define PATH_SEP       '\\'
218 #   define MY_LSTAT       _stat
219 #   define MY_STAT        _stat
220 #   define MY_S_IFREG(x)  ((x) & _S_IFREG)
221
222 #   define APPEND_FLAG(root, name) \
223       root=snocString((root), (name))
224
225 #   if 0
226    /*-- lcc-win32 seems to expand wildcards itself --*/
227 #   define APPEND_FILESPEC(root, spec)                \
228       do {                                            \
229          if ((spec)[0] == '-') {                      \
230             root = snocString((root), (spec));        \
231          } else {                                     \
232             struct _finddata_t c_file;                \
233             long hFile;                               \
234             hFile = _findfirst((spec), &c_file);      \
235             if ( hFile == -1L ) {                     \
236                root = snocString ((root), (spec));    \
237             } else {                                  \
238                int anInt = 0;                         \
239                while ( anInt == 0 ) {                 \
240                   root = snocString((root),           \
241                             &c_file.name[0]);         \
242                   anInt = _findnext(hFile, &c_file);  \
243                }                                      \
244             }                                         \
245          }                                            \
246       } while ( 0 )
247 #   else
248 #   define APPEND_FILESPEC(root, name)                \
249       root = snocString ((root), (name))
250 #   endif
251
252 #   define SET_BINARY_MODE(fd)                        \
253       do {                                            \
254          int retVal = setmode ( fileno ( fd ),        \
255                                O_BINARY );            \
256          ERROR_IF_MINUS_ONE ( retVal );               \
257       } while ( 0 )
258
259 #endif
260
261
262 /*---------------------------------------------*/
263 /*--
264   Some more stuff for all platforms :-)
265 --*/
266
267 typedef char            Char;
268 typedef unsigned char   Bool;
269 typedef unsigned char   UChar;
270 typedef int             Int32;
271 typedef unsigned int    UInt32;
272 typedef short           Int16;
273 typedef unsigned short  UInt16;
274                                        
275 #define True  ((Bool)1)
276 #define False ((Bool)0)
277
278 /*--
279   IntNative is your platform's `native' int size.
280   Only here to avoid probs with 64-bit platforms.
281 --*/
282 typedef int IntNative;
283
284
285 /*---------------------------------------------------*/
286 /*--- Misc (file handling) data decls             ---*/
287 /*---------------------------------------------------*/
288
289 Int32   verbosity;
290 Bool    keepInputFiles, smallMode, deleteOutputOnInterrupt;
291 Bool    forceOverwrite, testFailsExist, unzFailsExist, noisy;
292 Int32   numFileNames, numFilesProcessed, blockSize100k;
293 Int32   exitValue;
294
295 /*-- source modes; F==file, I==stdin, O==stdout --*/
296 #define SM_I2O           1
297 #define SM_F2O           2
298 #define SM_F2F           3
299
300 /*-- operation modes --*/
301 #define OM_Z             1
302 #define OM_UNZ           2
303 #define OM_TEST          3
304
305 Int32   opMode;
306 Int32   srcMode;
307
308 #define FILE_NAME_LEN 1034
309
310 Int32   longestFileName;
311 Char    inName [FILE_NAME_LEN];
312 Char    outName[FILE_NAME_LEN];
313 Char    tmpName[FILE_NAME_LEN];
314 Char    *progName;
315 Char    progNameReally[FILE_NAME_LEN];
316 FILE    *outputHandleJustInCase;
317 Int32   workFactor;
318
319 static void    panic                 ( Char* )   NORETURN;
320 static void    ioError               ( void )    NORETURN;
321 static void    outOfMemory           ( void )    NORETURN;
322 static void    configError           ( void )    NORETURN;
323 static void    crcError              ( void )    NORETURN;
324 static void    cleanUpAndFail        ( Int32 )   NORETURN;
325 static void    compressedStreamEOF   ( void )    NORETURN;
326
327 static void    copyFileName ( Char*, Char* );
328 static void*   myMalloc     ( Int32 );
329
330
331
332 /*---------------------------------------------------*/
333 /*--- An implementation of 64-bit ints.  Sigh.    ---*/
334 /*--- Roll on widespread deployment of ANSI C9X ! ---*/
335 /*---------------------------------------------------*/
336
337 typedef
338    struct { UChar b[8]; } 
339    UInt64;
340
341 static
342 void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
343 {
344    n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
345    n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
346    n->b[5] = (UChar)((hi32 >> 8)  & 0xFF);
347    n->b[4] = (UChar) (hi32        & 0xFF);
348    n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
349    n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
350    n->b[1] = (UChar)((lo32 >> 8)  & 0xFF);
351    n->b[0] = (UChar) (lo32        & 0xFF);
352 }
353
354 static
355 double uInt64_to_double ( UInt64* n )
356 {
357    Int32  i;
358    double base = 1.0;
359    double sum  = 0.0;
360    for (i = 0; i < 8; i++) {
361       sum  += base * (double)(n->b[i]);
362       base *= 256.0;
363    }
364    return sum;
365 }
366
367 static
368 void uInt64_add ( UInt64* src, UInt64* dst )
369 {
370    Int32 i;
371    Int32 carry = 0;
372    for (i = 0; i < 8; i++) {
373       carry += ( ((Int32)src->b[i]) + ((Int32)dst->b[i]) );
374       dst->b[i] = (UChar)(carry & 0xFF);
375       carry >>= 8;
376    }
377 }
378
379 static
380 void uInt64_sub ( UInt64* src, UInt64* dst )
381 {
382    Int32 t, i;
383    Int32 borrow = 0;
384    for (i = 0; i < 8; i++) {
385       t = ((Int32)dst->b[i]) - ((Int32)src->b[i]) - borrow;
386       if (t < 0) {
387          dst->b[i] = (UChar)(t + 256);
388          borrow = 1;
389       } else {
390          dst->b[i] = (UChar)t;
391          borrow = 0;
392       }
393    }
394 }
395
396 static
397 void uInt64_mul ( UInt64* a, UInt64* b, UInt64* r_hi, UInt64* r_lo )
398 {
399    UChar sum[16];
400    Int32 ia, ib, carry;
401    for (ia = 0; ia < 16; ia++) sum[ia] = 0;
402    for (ia = 0; ia < 8; ia++) {
403       carry = 0;
404       for (ib = 0; ib < 8; ib++) {
405          carry += ( ((Int32)sum[ia+ib]) 
406                     + ((Int32)a->b[ia]) * ((Int32)b->b[ib]) );
407          sum[ia+ib] = (UChar)(carry & 0xFF);
408          carry >>= 8;
409       }
410       sum[ia+8] = (UChar)(carry & 0xFF);
411       if ((carry >>= 8) != 0) panic ( "uInt64_mul" );
412    }
413
414    for (ia = 0; ia < 8; ia++) r_hi->b[ia] = sum[ia+8];
415    for (ia = 0; ia < 8; ia++) r_lo->b[ia] = sum[ia];
416 }
417
418
419 static
420 void uInt64_shr1 ( UInt64* n )
421 {
422    Int32 i;
423    for (i = 0; i < 8; i++) {
424       n->b[i] >>= 1;
425       if (i < 7 && (n->b[i+1] & 1)) n->b[i] |= 0x80;
426    }
427 }
428
429 static
430 void uInt64_shl1 ( UInt64* n )
431 {
432    Int32 i;
433    for (i = 7; i >= 0; i--) {
434       n->b[i] <<= 1;
435       if (i > 0 && (n->b[i-1] & 0x80)) n->b[i]++;
436    }
437 }
438
439 static
440 Bool uInt64_isZero ( UInt64* n )
441 {
442    Int32 i;
443    for (i = 0; i < 8; i++)
444       if (n->b[i] != 0) return 0;
445    return 1;
446 }
447
448 static
449 Int32 uInt64_qrm10 ( UInt64* n )
450 {
451    /* Divide *n by 10, and return the remainder.  Long division
452       is difficult, so we cheat and instead multiply by
453       0xCCCC CCCC CCCC CCCD, which is 0.8 (viz, 0.1 << 3).
454    */
455    Int32  i;
456    UInt64 tmp1, tmp2, n_orig, zero_point_eight;
457
458    zero_point_eight.b[1] = zero_point_eight.b[2] = 
459    zero_point_eight.b[3] = zero_point_eight.b[4] = 
460    zero_point_eight.b[5] = zero_point_eight.b[6] = 
461    zero_point_eight.b[7] = 0xCC;
462    zero_point_eight.b[0] = 0xCD;
463
464    n_orig = *n;
465
466    /* divide n by 10, 
467       by multiplying by 0.8 and then shifting right 3 times */
468    uInt64_mul ( n, &zero_point_eight, &tmp1, &tmp2 );
469    uInt64_shr1(&tmp1); uInt64_shr1(&tmp1); uInt64_shr1(&tmp1); 
470    *n = tmp1;
471    
472    /* tmp1 = 8*n, tmp2 = 2*n */
473    uInt64_shl1(&tmp1); uInt64_shl1(&tmp1); uInt64_shl1(&tmp1);
474    tmp2 = *n; uInt64_shl1(&tmp2);
475
476    /* tmp1 = 10*n */
477    uInt64_add ( &tmp2, &tmp1 );
478
479    /* n_orig = n_orig - 10*n */
480    uInt64_sub ( &tmp1, &n_orig );
481
482    /* n_orig should now hold quotient, in range 0 .. 9 */
483    for (i = 7; i >= 1; i--) 
484       if (n_orig.b[i] != 0) panic ( "uInt64_qrm10(1)" );
485    if (n_orig.b[0] > 9)
486       panic ( "uInt64_qrm10(2)" );
487
488    return (int)n_orig.b[0];
489 }
490
491 /* ... and the Whole Entire Point of all this UInt64 stuff is
492    so that we can supply the following function.
493 */
494 static
495 void uInt64_toAscii ( char* outbuf, UInt64* n )
496 {
497    Int32  i, q;
498    UChar  buf[32];
499    Int32  nBuf   = 0;
500    UInt64 n_copy = *n;
501    do {
502       q = uInt64_qrm10 ( &n_copy );
503       buf[nBuf] = q + '0';
504       nBuf++;
505    } while (!uInt64_isZero(&n_copy));
506    outbuf[nBuf] = 0;
507    for (i = 0; i < nBuf; i++) outbuf[i] = buf[nBuf-i-1];
508 }
509
510
511 /*---------------------------------------------------*/
512 /*--- Processing of complete files and streams    ---*/
513 /*---------------------------------------------------*/
514
515 /*---------------------------------------------*/
516 static 
517 Bool myfeof ( FILE* f )
518 {
519    Int32 c = fgetc ( f );
520    if (c == EOF) return True;
521    ungetc ( c, f );
522    return False;
523 }
524
525
526 /*---------------------------------------------*/
527 static 
528 void compressStream ( FILE *stream, FILE *zStream )
529 {
530    BZFILE* bzf = NULL;
531    UChar   ibuf[5000];
532    Int32   nIbuf;
533    UInt32  nbytes_in_lo32, nbytes_in_hi32;
534    UInt32  nbytes_out_lo32, nbytes_out_hi32;
535    Int32   bzerr, bzerr_dummy, ret;
536
537    SET_BINARY_MODE(stream);
538    SET_BINARY_MODE(zStream);
539
540    if (ferror(stream)) goto errhandler_io;
541    if (ferror(zStream)) goto errhandler_io;
542
543    bzf = BZ2_bzWriteOpen ( &bzerr, zStream, 
544                            blockSize100k, verbosity, workFactor );   
545    if (bzerr != BZ_OK) goto errhandler;
546
547    if (verbosity >= 2) fprintf ( stderr, "\n" );
548
549    while (True) {
550
551       if (myfeof(stream)) break;
552       nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
553       if (ferror(stream)) goto errhandler_io;
554       if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
555       if (bzerr != BZ_OK) goto errhandler;
556
557    }
558
559    BZ2_bzWriteClose64 ( &bzerr, bzf, 0, 
560                         &nbytes_in_lo32, &nbytes_in_hi32,
561                         &nbytes_out_lo32, &nbytes_out_hi32 );
562    if (bzerr != BZ_OK) goto errhandler;
563
564    if (ferror(zStream)) goto errhandler_io;
565    ret = fflush ( zStream );
566    if (ret == EOF) goto errhandler_io;
567    if (zStream != stdout) {
568       ret = fclose ( zStream );
569       if (ret == EOF) goto errhandler_io;
570    }
571    if (ferror(stream)) goto errhandler_io;
572    ret = fclose ( stream );
573    if (ret == EOF) goto errhandler_io;
574
575    if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) 
576       nbytes_in_lo32 = 1;
577
578    if (verbosity >= 1) {
579       Char   buf_nin[32], buf_nout[32];
580       UInt64 nbytes_in,   nbytes_out;
581       double nbytes_in_d, nbytes_out_d;
582       uInt64_from_UInt32s ( &nbytes_in, 
583                             nbytes_in_lo32, nbytes_in_hi32 );
584       uInt64_from_UInt32s ( &nbytes_out, 
585                             nbytes_out_lo32, nbytes_out_hi32 );
586       nbytes_in_d  = uInt64_to_double ( &nbytes_in );
587       nbytes_out_d = uInt64_to_double ( &nbytes_out );
588       uInt64_toAscii ( buf_nin, &nbytes_in );
589       uInt64_toAscii ( buf_nout, &nbytes_out );
590       fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
591                         "%5.2f%% saved, %s in, %s out.\n",
592                 nbytes_in_d / nbytes_out_d,
593                 (8.0 * nbytes_out_d) / nbytes_in_d,
594                 100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
595                 buf_nin,
596                 buf_nout
597               );
598    }
599
600    return;
601
602    errhandler:
603    BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1, 
604                         &nbytes_in_lo32, &nbytes_in_hi32,
605                         &nbytes_out_lo32, &nbytes_out_hi32 );
606    switch (bzerr) {
607       case BZ_CONFIG_ERROR:
608          configError(); break;
609       case BZ_MEM_ERROR:
610          outOfMemory (); break;
611       case BZ_IO_ERROR:
612          errhandler_io:
613          ioError(); break;
614       default:
615          panic ( "compress:unexpected error" );
616    }
617
618    panic ( "compress:end" );
619    /*notreached*/
620 }
621
622
623
624 /*---------------------------------------------*/
625 static 
626 Bool uncompressStream ( FILE *zStream, FILE *stream )
627 {
628    BZFILE* bzf = NULL;
629    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
630    UChar   obuf[5000];
631    UChar   unused[BZ_MAX_UNUSED];
632    Int32   nUnused;
633    UChar*  unusedTmp;
634
635    nUnused = 0;
636    streamNo = 0;
637
638    SET_BINARY_MODE(stream);
639    SET_BINARY_MODE(zStream);
640
641    if (ferror(stream)) goto errhandler_io;
642    if (ferror(zStream)) goto errhandler_io;
643
644    while (True) {
645
646       bzf = BZ2_bzReadOpen ( 
647                &bzerr, zStream, verbosity, 
648                (int)smallMode, unused, nUnused
649             );
650       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
651       streamNo++;
652
653       while (bzerr == BZ_OK) {
654          nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
655          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
656          if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
657             fwrite ( obuf, sizeof(UChar), nread, stream );
658          if (ferror(stream)) goto errhandler_io;
659       }
660       if (bzerr != BZ_STREAM_END) goto errhandler;
661
662       BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
663       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
664
665       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
666
667       BZ2_bzReadClose ( &bzerr, bzf );
668       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
669
670       if (nUnused == 0 && myfeof(zStream)) break;
671
672    }
673
674    if (ferror(zStream)) goto errhandler_io;
675    ret = fclose ( zStream );
676    if (ret == EOF) goto errhandler_io;
677
678    if (ferror(stream)) goto errhandler_io;
679    ret = fflush ( stream );
680    if (ret != 0) goto errhandler_io;
681    if (stream != stdout) {
682       ret = fclose ( stream );
683       if (ret == EOF) goto errhandler_io;
684    }
685    if (verbosity >= 2) fprintf ( stderr, "\n    " );
686    return True;
687
688    errhandler:
689    BZ2_bzReadClose ( &bzerr_dummy, bzf );
690    switch (bzerr) {
691       case BZ_CONFIG_ERROR:
692          configError(); break;
693       case BZ_IO_ERROR:
694          errhandler_io:
695          ioError(); break;
696       case BZ_DATA_ERROR:
697          crcError();
698       case BZ_MEM_ERROR:
699          outOfMemory();
700       case BZ_UNEXPECTED_EOF:
701          compressedStreamEOF();
702       case BZ_DATA_ERROR_MAGIC:
703          if (zStream != stdin) fclose(zStream);
704          if (stream != stdout) fclose(stream);
705          if (streamNo == 1) {
706             return False;
707          } else {
708             if (noisy)
709             fprintf ( stderr, 
710                       "\n%s: %s: trailing garbage after EOF ignored\n",
711                       progName, inName );
712             return True;       
713          }
714       default:
715          panic ( "decompress:unexpected error" );
716    }
717
718    panic ( "decompress:end" );
719    return True; /*notreached*/
720 }
721
722
723 /*---------------------------------------------*/
724 static 
725 Bool testStream ( FILE *zStream )
726 {
727    BZFILE* bzf = NULL;
728    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
729    UChar   obuf[5000];
730    UChar   unused[BZ_MAX_UNUSED];
731    Int32   nUnused;
732    UChar*  unusedTmp;
733
734    nUnused = 0;
735    streamNo = 0;
736
737    SET_BINARY_MODE(zStream);
738    if (ferror(zStream)) goto errhandler_io;
739
740    while (True) {
741
742       bzf = BZ2_bzReadOpen ( 
743                &bzerr, zStream, verbosity, 
744                (int)smallMode, unused, nUnused
745             );
746       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
747       streamNo++;
748
749       while (bzerr == BZ_OK) {
750          nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
751          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
752       }
753       if (bzerr != BZ_STREAM_END) goto errhandler;
754
755       BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
756       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
757
758       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
759
760       BZ2_bzReadClose ( &bzerr, bzf );
761       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
762       if (nUnused == 0 && myfeof(zStream)) break;
763
764    }
765
766    if (ferror(zStream)) goto errhandler_io;
767    ret = fclose ( zStream );
768    if (ret == EOF) goto errhandler_io;
769
770    if (verbosity >= 2) fprintf ( stderr, "\n    " );
771    return True;
772
773    errhandler:
774    BZ2_bzReadClose ( &bzerr_dummy, bzf );
775    if (verbosity == 0) 
776       fprintf ( stderr, "%s: %s: ", progName, inName );
777    switch (bzerr) {
778       case BZ_CONFIG_ERROR:
779          configError(); break;
780       case BZ_IO_ERROR:
781          errhandler_io:
782          ioError(); break;
783       case BZ_DATA_ERROR:
784          fprintf ( stderr,
785                    "data integrity (CRC) error in data\n" );
786          return False;
787       case BZ_MEM_ERROR:
788          outOfMemory();
789       case BZ_UNEXPECTED_EOF:
790          fprintf ( stderr,
791                    "file ends unexpectedly\n" );
792          return False;
793       case BZ_DATA_ERROR_MAGIC:
794          if (zStream != stdin) fclose(zStream);
795          if (streamNo == 1) {
796           fprintf ( stderr, 
797                     "bad magic number (file not created by bzip2)\n" );
798             return False;
799          } else {
800             if (noisy)
801             fprintf ( stderr, 
802                       "trailing garbage after EOF ignored\n" );
803             return True;       
804          }
805       default:
806          panic ( "test:unexpected error" );
807    }
808
809    panic ( "test:end" );
810    return True; /*notreached*/
811 }
812
813
814 /*---------------------------------------------------*/
815 /*--- Error [non-] handling grunge                ---*/
816 /*---------------------------------------------------*/
817
818 /*---------------------------------------------*/
819 static
820 void setExit ( Int32 v )
821 {
822    if (v > exitValue) exitValue = v;
823 }
824
825
826 /*---------------------------------------------*/
827 static 
828 void cadvise ( void )
829 {
830    if (noisy)
831    fprintf (
832       stderr,
833       "\nIt is possible that the compressed file(s) have become corrupted.\n"
834         "You can use the -tvv option to test integrity of such files.\n\n"
835         "You can use the `bzip2recover' program to *attempt* to recover\n"
836         "data from undamaged sections of corrupted files.\n\n"
837     );
838 }
839
840
841 /*---------------------------------------------*/
842 static 
843 void showFileNames ( void )
844 {
845    if (noisy)
846    fprintf (
847       stderr,
848       "\tInput file = %s, output file = %s\n",
849       inName, outName 
850    );
851 }
852
853
854 /*---------------------------------------------*/
855 static 
856 void cleanUpAndFail ( Int32 ec )
857 {
858    IntNative retVal;
859
860    if ( srcMode == SM_F2F 
861         && opMode != OM_TEST
862         && deleteOutputOnInterrupt ) {
863       if (noisy)
864       fprintf ( stderr, "%s: Deleting output file %s, if it exists.\n",
865                 progName, outName );
866       if (outputHandleJustInCase != NULL)
867          fclose ( outputHandleJustInCase );
868       retVal = remove ( outName );
869       if (retVal != 0)
870          fprintf ( stderr,
871                    "%s: WARNING: deletion of output file (apparently) failed.\n",
872                    progName );
873    }
874    if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
875       fprintf ( stderr, 
876                 "%s: WARNING: some files have not been processed:\n"
877                 "\t%d specified on command line, %d not processed yet.\n\n",
878                 progName, numFileNames, 
879                           numFileNames - numFilesProcessed );
880    }
881    setExit(ec);
882    exit(exitValue);
883 }
884
885
886 /*---------------------------------------------*/
887 static 
888 void panic ( Char* s )
889 {
890    fprintf ( stderr,
891              "\n%s: PANIC -- internal consistency error:\n"
892              "\t%s\n"
893              "\tThis is a BUG.  Please report it to me at:\n"
894              "\tjseward@acm.org\n",
895              progName, s );
896    showFileNames();
897    cleanUpAndFail( 3 );
898 }
899
900
901 /*---------------------------------------------*/
902 static 
903 void crcError ( void )
904 {
905    fprintf ( stderr,
906              "\n%s: Data integrity error when decompressing.\n",
907              progName );
908    showFileNames();
909    cadvise();
910    cleanUpAndFail( 2 );
911 }
912
913
914 /*---------------------------------------------*/
915 static 
916 void compressedStreamEOF ( void )
917 {
918    fprintf ( stderr,
919              "\n%s: Compressed file ends unexpectedly;\n\t"
920              "perhaps it is corrupted?  *Possible* reason follows.\n",
921              progName );
922    perror ( progName );
923    showFileNames();
924    cadvise();
925    cleanUpAndFail( 2 );
926 }
927
928
929 /*---------------------------------------------*/
930 static 
931 void ioError ( void )
932 {
933    fprintf ( stderr,
934              "\n%s: I/O or other error, bailing out.  "
935              "Possible reason follows.\n",
936              progName );
937    perror ( progName );
938    showFileNames();
939    cleanUpAndFail( 1 );
940 }
941
942
943 /*---------------------------------------------*/
944 static 
945 void mySignalCatcher ( IntNative n )
946 {
947    fprintf ( stderr,
948              "\n%s: Control-C or similar caught, quitting.\n",
949              progName );
950    cleanUpAndFail(1);
951 }
952
953
954 /*---------------------------------------------*/
955 static 
956 void mySIGSEGVorSIGBUScatcher ( IntNative n )
957 {
958    if (opMode == OM_Z)
959       fprintf ( 
960       stderr,
961       "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
962       "\n"
963       "   Possible causes are (most likely first):\n"
964       "   (1) This computer has unreliable memory or cache hardware\n"
965       "       (a surprisingly common problem; try a different machine.)\n"
966       "   (2) A bug in the compiler used to create this executable\n"
967       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
968       "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
969       "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
970       "   \n"
971       "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
972       "   or (2), feel free to report it to me at: jseward@acm.org.\n"
973       "   Section 4.3 of the user's manual describes the info a useful\n"
974       "   bug report should have.  If the manual is available on your\n"
975       "   system, please try and read it before mailing me.  If you don't\n"
976       "   have the manual or can't be bothered to read it, mail me anyway.\n"
977       "\n",
978       progName );
979       else
980       fprintf ( 
981       stderr,
982       "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
983       "\n"
984       "   Possible causes are (most likely first):\n"
985       "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
986       "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
987       "   (2) This computer has unreliable memory or cache hardware\n"
988       "       (a surprisingly common problem; try a different machine.)\n"
989       "   (3) A bug in the compiler used to create this executable\n"
990       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
991       "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
992       "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
993       "   \n"
994       "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
995       "   or (3), feel free to report it to me at: jseward@acm.org.\n"
996       "   Section 4.3 of the user's manual describes the info a useful\n"
997       "   bug report should have.  If the manual is available on your\n"
998       "   system, please try and read it before mailing me.  If you don't\n"
999       "   have the manual or can't be bothered to read it, mail me anyway.\n"
1000       "\n",
1001       progName );
1002
1003    showFileNames();
1004    if (opMode == OM_Z)
1005       cleanUpAndFail( 3 ); else
1006       { cadvise(); cleanUpAndFail( 2 ); }
1007 }
1008
1009
1010 /*---------------------------------------------*/
1011 static 
1012 void outOfMemory ( void )
1013 {
1014    fprintf ( stderr,
1015              "\n%s: couldn't allocate enough memory\n",
1016              progName );
1017    showFileNames();
1018    cleanUpAndFail(1);
1019 }
1020
1021
1022 /*---------------------------------------------*/
1023 static 
1024 void configError ( void )
1025 {
1026    fprintf ( stderr,
1027              "bzip2: I'm not configured correctly for this platform!\n"
1028              "\tI require Int32, Int16 and Char to have sizes\n"
1029              "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
1030              "\tProbably you can fix this by defining them correctly,\n"
1031              "\tand recompiling.  Bye!\n" );
1032    setExit(3);
1033    exit(exitValue);
1034 }
1035
1036
1037 /*---------------------------------------------------*/
1038 /*--- The main driver machinery                   ---*/
1039 /*---------------------------------------------------*/
1040
1041 /*---------------------------------------------*/
1042 static 
1043 void pad ( Char *s )
1044 {
1045    Int32 i;
1046    if ( (Int32)strlen(s) >= longestFileName ) return;
1047    for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
1048       fprintf ( stderr, " " );
1049 }
1050
1051
1052 /*---------------------------------------------*/
1053 static 
1054 void copyFileName ( Char* to, Char* from ) 
1055 {
1056    if ( strlen(from) > FILE_NAME_LEN-10 )  {
1057       fprintf (
1058          stderr,
1059          "bzip2: file name\n`%s'\n"
1060          "is suspiciously (more than %d chars) long.\n"
1061          "Try using a reasonable file name instead.  Sorry! :-)\n",
1062          from, FILE_NAME_LEN-10
1063       );
1064       setExit(1);
1065       exit(exitValue);
1066    }
1067
1068   strncpy(to,from,FILE_NAME_LEN-10);
1069   to[FILE_NAME_LEN-10]='\0';
1070 }
1071
1072
1073 /*---------------------------------------------*/
1074 static 
1075 Bool fileExists ( Char* name )
1076 {
1077    FILE *tmp   = fopen ( name, "rb" );
1078    Bool exists = (tmp != NULL);
1079    if (tmp != NULL) fclose ( tmp );
1080    return exists;
1081 }
1082
1083
1084 /*---------------------------------------------*/
1085 /*--
1086   if in doubt, return True
1087 --*/
1088 static 
1089 Bool notAStandardFile ( Char* name )
1090 {
1091    IntNative      i;
1092    struct MY_STAT statBuf;
1093
1094    i = MY_LSTAT ( name, &statBuf );
1095    if (i != 0) return True;
1096    if (MY_S_IFREG(statBuf.st_mode)) return False;
1097    return True;
1098 }
1099
1100
1101 /*---------------------------------------------*/
1102 /*--
1103   rac 11/21/98 see if file has hard links to it
1104 --*/
1105 static 
1106 Int32 countHardLinks ( Char* name )
1107 {  
1108    IntNative      i;
1109    struct MY_STAT statBuf;
1110
1111    i = MY_LSTAT ( name, &statBuf );
1112    if (i != 0) return 0;
1113    return (statBuf.st_nlink - 1);
1114 }
1115
1116
1117 /*---------------------------------------------*/
1118 static 
1119 void copyDatePermissionsAndOwner ( Char *srcName, Char *dstName )
1120 {
1121 #if BZ_UNIX
1122    IntNative      retVal;
1123    struct MY_STAT statBuf;
1124    struct utimbuf uTimBuf;
1125
1126    retVal = MY_LSTAT ( srcName, &statBuf );
1127    ERROR_IF_NOT_ZERO ( retVal );
1128    uTimBuf.actime = statBuf.st_atime;
1129    uTimBuf.modtime = statBuf.st_mtime;
1130
1131    retVal = chmod ( dstName, statBuf.st_mode );
1132    ERROR_IF_NOT_ZERO ( retVal );
1133
1134    retVal = utime ( dstName, &uTimBuf );
1135    ERROR_IF_NOT_ZERO ( retVal );
1136
1137    retVal = chown ( dstName, statBuf.st_uid, statBuf.st_gid );
1138    /* chown() will in many cases return with EPERM, which can
1139       be safely ignored.
1140    */
1141 #endif
1142 }
1143
1144
1145 /*---------------------------------------------*/
1146 static 
1147 void setInterimPermissions ( Char *dstName )
1148 {
1149 #if BZ_UNIX
1150    IntNative      retVal;
1151    retVal = chmod ( dstName, S_IRUSR | S_IWUSR );
1152    ERROR_IF_NOT_ZERO ( retVal );
1153 #endif
1154 }
1155
1156
1157 /*---------------------------------------------*/
1158 static 
1159 Bool containsDubiousChars ( Char* name )
1160 {
1161    Bool cdc = False;
1162    for (; *name != '\0'; name++)
1163       if (*name == '?' || *name == '*') cdc = True;
1164    return cdc;
1165 }
1166
1167
1168 /*---------------------------------------------*/
1169 #define BZ_N_SUFFIX_PAIRS 4
1170
1171 Char* zSuffix[BZ_N_SUFFIX_PAIRS] 
1172    = { ".bz2", ".bz", ".tbz2", ".tbz" };
1173 Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 
1174    = { "", "", ".tar", ".tar" };
1175
1176 static 
1177 Bool hasSuffix ( Char* s, Char* suffix )
1178 {
1179    Int32 ns = strlen(s);
1180    Int32 nx = strlen(suffix);
1181    if (ns < nx) return False;
1182    if (strcmp(s + ns - nx, suffix) == 0) return True;
1183    return False;
1184 }
1185
1186 static 
1187 Bool mapSuffix ( Char* name, 
1188                  Char* oldSuffix, Char* newSuffix )
1189 {
1190    if (!hasSuffix(name,oldSuffix)) return False;
1191    name[strlen(name)-strlen(oldSuffix)] = 0;
1192    strcat ( name, newSuffix );
1193    return True;
1194 }
1195
1196
1197 /*---------------------------------------------*/
1198 static 
1199 void compress ( Char *name )
1200 {
1201    FILE  *inStr;
1202    FILE  *outStr;
1203    Int32 n, i;
1204
1205    deleteOutputOnInterrupt = False;
1206
1207    if (name == NULL && srcMode != SM_I2O)
1208       panic ( "compress: bad modes\n" );
1209
1210    switch (srcMode) {
1211       case SM_I2O: 
1212          copyFileName ( inName, "(stdin)" );
1213          copyFileName ( outName, "(stdout)" ); 
1214          break;
1215       case SM_F2F: 
1216          copyFileName ( inName, name );
1217          copyFileName ( outName, name );
1218          strcat ( outName, ".bz2" ); 
1219          break;
1220       case SM_F2O: 
1221          copyFileName ( inName, name );
1222          copyFileName ( outName, "(stdout)" ); 
1223          break;
1224    }
1225
1226    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1227       if (noisy)
1228       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1229                 progName, inName );
1230       setExit(1);
1231       return;
1232    }
1233    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1234       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1235                 progName, inName, strerror(errno) );
1236       setExit(1);
1237       return;
1238    }
1239    for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
1240       if (hasSuffix(inName, zSuffix[i])) {
1241          if (noisy)
1242          fprintf ( stderr, 
1243                    "%s: Input file %s already has %s suffix.\n",
1244                    progName, inName, zSuffix[i] );
1245          setExit(1);
1246          return;
1247       }
1248    }
1249    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1250       if (noisy)
1251       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1252                 progName, inName );
1253       setExit(1);
1254       return;
1255    }
1256    if ( srcMode == SM_F2F && !forceOverwrite && fileExists ( outName ) ) {
1257       fprintf ( stderr, "%s: Output file %s already exists.\n",
1258                 progName, outName );
1259       setExit(1);
1260       return;
1261    }
1262    if ( srcMode == SM_F2F && !forceOverwrite &&
1263         (n=countHardLinks ( inName )) > 0) {
1264       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1265                 progName, inName, n, n > 1 ? "s" : "" );
1266       setExit(1);
1267       return;
1268    }
1269
1270    switch ( srcMode ) {
1271
1272       case SM_I2O:
1273          inStr = stdin;
1274          outStr = stdout;
1275          if ( isatty ( fileno ( stdout ) ) ) {
1276             fprintf ( stderr,
1277                       "%s: I won't write compressed data to a terminal.\n",
1278                       progName );
1279             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1280                               progName, progName );
1281             setExit(1);
1282             return;
1283          };
1284          break;
1285
1286       case SM_F2O:
1287          inStr = fopen ( inName, "rb" );
1288          outStr = stdout;
1289          if ( isatty ( fileno ( stdout ) ) ) {
1290             fprintf ( stderr,
1291                       "%s: I won't write compressed data to a terminal.\n",
1292                       progName );
1293             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1294                               progName, progName );
1295             if ( inStr != NULL ) fclose ( inStr );
1296             setExit(1);
1297             return;
1298          };
1299          if ( inStr == NULL ) {
1300             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1301                       progName, inName, strerror(errno) );
1302             setExit(1);
1303             return;
1304          };
1305          break;
1306
1307       case SM_F2F:
1308          inStr = fopen ( inName, "rb" );
1309          outStr = fopen ( outName, "wb" );
1310          if ( outStr == NULL) {
1311             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1312                       progName, outName, strerror(errno) );
1313             if ( inStr != NULL ) fclose ( inStr );
1314             setExit(1);
1315             return;
1316          }
1317          if ( inStr == NULL ) {
1318             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1319                       progName, inName, strerror(errno) );
1320             if ( outStr != NULL ) fclose ( outStr );
1321             setExit(1);
1322             return;
1323          };
1324          setInterimPermissions ( outName );
1325          break;
1326
1327       default:
1328          panic ( "compress: bad srcMode" );
1329          break;
1330    }
1331
1332    if (verbosity >= 1) {
1333       fprintf ( stderr,  "  %s: ", inName );
1334       pad ( inName );
1335       fflush ( stderr );
1336    }
1337
1338    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
1339    outputHandleJustInCase = outStr;
1340    deleteOutputOnInterrupt = True;
1341    compressStream ( inStr, outStr );
1342    outputHandleJustInCase = NULL;
1343
1344    /*--- If there was an I/O error, we won't get here. ---*/
1345    if ( srcMode == SM_F2F ) {
1346       copyDatePermissionsAndOwner ( inName, outName );
1347       deleteOutputOnInterrupt = False;
1348       if ( !keepInputFiles ) {
1349          IntNative retVal = remove ( inName );
1350          ERROR_IF_NOT_ZERO ( retVal );
1351       }
1352    }
1353
1354    deleteOutputOnInterrupt = False;
1355 }
1356
1357
1358 /*---------------------------------------------*/
1359 static 
1360 void uncompress ( Char *name )
1361 {
1362    FILE  *inStr;
1363    FILE  *outStr;
1364    Int32 n, i;
1365    Bool  magicNumberOK;
1366    Bool  cantGuess;
1367
1368    deleteOutputOnInterrupt = False;
1369
1370    if (name == NULL && srcMode != SM_I2O)
1371       panic ( "uncompress: bad modes\n" );
1372
1373    cantGuess = False;
1374    switch (srcMode) {
1375       case SM_I2O: 
1376          copyFileName ( inName, "(stdin)" );
1377          copyFileName ( outName, "(stdout)" ); 
1378          break;
1379       case SM_F2F: 
1380          copyFileName ( inName, name );
1381          copyFileName ( outName, name );
1382          for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
1383             if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
1384                goto zzz; 
1385          cantGuess = True;
1386          strcat ( outName, ".out" );
1387          break;
1388       case SM_F2O: 
1389          copyFileName ( inName, name );
1390          copyFileName ( outName, "(stdout)" ); 
1391          break;
1392    }
1393
1394    zzz:
1395    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1396       if (noisy)
1397       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1398                 progName, inName );
1399       setExit(1);
1400       return;
1401    }
1402    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1403       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1404                 progName, inName, strerror(errno) );
1405       setExit(1);
1406       return;
1407    }
1408    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1409       if (noisy)
1410       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1411                 progName, inName );
1412       setExit(1);
1413       return;
1414    }
1415    if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
1416       if (noisy)
1417       fprintf ( stderr, 
1418                 "%s: Can't guess original name for %s -- using %s\n",
1419                 progName, inName, outName );
1420       /* just a warning, no return */
1421    }   
1422    if ( srcMode == SM_F2F && !forceOverwrite && fileExists ( outName ) ) {
1423       fprintf ( stderr, "%s: Output file %s already exists.\n",
1424                 progName, outName );
1425       setExit(1);
1426       return;
1427    }
1428    if ( srcMode == SM_F2F && !forceOverwrite &&
1429         (n=countHardLinks ( inName ) ) > 0) {
1430       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1431                 progName, inName, n, n > 1 ? "s" : "" );
1432       setExit(1);
1433       return;
1434    }
1435
1436    switch ( srcMode ) {
1437
1438       case SM_I2O:
1439          inStr = stdin;
1440          outStr = stdout;
1441          if ( isatty ( fileno ( stdin ) ) ) {
1442             fprintf ( stderr,
1443                       "%s: I won't read compressed data from a terminal.\n",
1444                       progName );
1445             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1446                               progName, progName );
1447             setExit(1);
1448             return;
1449          };
1450          break;
1451
1452       case SM_F2O:
1453          inStr = fopen ( inName, "rb" );
1454          outStr = stdout;
1455          if ( inStr == NULL ) {
1456             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1457                       progName, inName, strerror(errno) );
1458             if ( inStr != NULL ) fclose ( inStr );
1459             setExit(1);
1460             return;
1461          };
1462          break;
1463
1464       case SM_F2F:
1465          inStr = fopen ( inName, "rb" );
1466          outStr = fopen ( outName, "wb" );
1467          if ( outStr == NULL) {
1468             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1469                       progName, outName, strerror(errno) );
1470             if ( inStr != NULL ) fclose ( inStr );
1471             setExit(1);
1472             return;
1473          }
1474          if ( inStr == NULL ) {
1475             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1476                       progName, inName, strerror(errno) );
1477             if ( outStr != NULL ) fclose ( outStr );
1478             setExit(1);
1479             return;
1480          };
1481          setInterimPermissions ( outName );
1482          break;
1483
1484       default:
1485          panic ( "uncompress: bad srcMode" );
1486          break;
1487    }
1488
1489    if (verbosity >= 1) {
1490       fprintf ( stderr, "  %s: ", inName );
1491       pad ( inName );
1492       fflush ( stderr );
1493    }
1494
1495    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
1496    outputHandleJustInCase = outStr;
1497    deleteOutputOnInterrupt = True;
1498    magicNumberOK = uncompressStream ( inStr, outStr );
1499    outputHandleJustInCase = NULL;
1500
1501    /*--- If there was an I/O error, we won't get here. ---*/
1502    if ( magicNumberOK ) {
1503       if ( srcMode == SM_F2F ) {
1504          copyDatePermissionsAndOwner ( inName, outName );
1505          deleteOutputOnInterrupt = False;
1506          if ( !keepInputFiles ) {
1507             IntNative retVal = remove ( inName );
1508             ERROR_IF_NOT_ZERO ( retVal );
1509          }
1510       }
1511    } else {
1512       unzFailsExist = True;
1513       deleteOutputOnInterrupt = False;
1514       if ( srcMode == SM_F2F ) {
1515          IntNative retVal = remove ( outName );
1516          ERROR_IF_NOT_ZERO ( retVal );
1517       }
1518    }
1519    deleteOutputOnInterrupt = False;
1520
1521    if ( magicNumberOK ) {
1522       if (verbosity >= 1)
1523          fprintf ( stderr, "done\n" );
1524    } else {
1525       setExit(2);
1526       if (verbosity >= 1)
1527          fprintf ( stderr, "not a bzip2 file.\n" ); else
1528          fprintf ( stderr,
1529                    "%s: %s is not a bzip2 file.\n",
1530                    progName, inName );
1531    }
1532
1533 }
1534
1535
1536 /*---------------------------------------------*/
1537 static 
1538 void testf ( Char *name )
1539 {
1540    FILE *inStr;
1541    Bool allOK;
1542
1543    deleteOutputOnInterrupt = False;
1544
1545    if (name == NULL && srcMode != SM_I2O)
1546       panic ( "testf: bad modes\n" );
1547
1548    copyFileName ( outName, "(none)" );
1549    switch (srcMode) {
1550       case SM_I2O: copyFileName ( inName, "(stdin)" ); break;
1551       case SM_F2F: copyFileName ( inName, name ); break;
1552       case SM_F2O: copyFileName ( inName, name ); break;
1553    }
1554
1555    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1556       if (noisy)
1557       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1558                 progName, inName );
1559       setExit(1);
1560       return;
1561    }
1562    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1563       fprintf ( stderr, "%s: Can't open input %s: %s.\n",
1564                 progName, inName, strerror(errno) );
1565       setExit(1);
1566       return;
1567    }
1568
1569    switch ( srcMode ) {
1570
1571       case SM_I2O:
1572          if ( isatty ( fileno ( stdin ) ) ) {
1573             fprintf ( stderr,
1574                       "%s: I won't read compressed data from a terminal.\n",
1575                       progName );
1576             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1577                               progName, progName );
1578             setExit(1);
1579             return;
1580          };
1581          inStr = stdin;
1582          break;
1583
1584       case SM_F2O: case SM_F2F:
1585          inStr = fopen ( inName, "rb" );
1586          if ( inStr == NULL ) {
1587             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1588                       progName, inName, strerror(errno) );
1589             setExit(1);
1590             return;
1591          };
1592          break;
1593
1594       default:
1595          panic ( "testf: bad srcMode" );
1596          break;
1597    }
1598
1599    if (verbosity >= 1) {
1600       fprintf ( stderr, "  %s: ", inName );
1601       pad ( inName );
1602       fflush ( stderr );
1603    }
1604
1605    /*--- Now the input handle is sane.  Do the Biz. ---*/
1606    allOK = testStream ( inStr );
1607
1608    if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
1609    if (!allOK) testFailsExist = True;
1610 }
1611
1612
1613 /*---------------------------------------------*/
1614 static 
1615 void license ( void )
1616 {
1617    fprintf ( stderr,
1618
1619     "bzip2, a block-sorting file compressor.  "
1620     "Version %s.\n"
1621     "   \n"
1622     "   Copyright (C) 1996-2000 by Julian Seward.\n"
1623     "   \n"
1624     "   This program is free software; you can redistribute it and/or modify\n"
1625     "   it under the terms set out in the LICENSE file, which is included\n"
1626     "   in the bzip2-1.0 source distribution.\n"
1627     "   \n"
1628     "   This program is distributed in the hope that it will be useful,\n"
1629     "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1630     "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1631     "   LICENSE file for more details.\n"
1632     "   \n",
1633     BZ2_bzlibVersion()
1634    );
1635 }
1636
1637
1638 /*---------------------------------------------*/
1639 static 
1640 void usage ( Char *fullProgName )
1641 {
1642    fprintf (
1643       stderr,
1644       "bzip2, a block-sorting file compressor.  "
1645       "Version %s.\n"
1646       "\n   usage: %s [flags and input files in any order]\n"
1647       "\n"
1648       "   -h --help           print this message\n"
1649       "   -d --decompress     force decompression\n"
1650       "   -z --compress       force compression\n"
1651       "   -k --keep           keep (don't delete) input files\n"
1652       "   -f --force          overwrite existing output files\n"
1653       "   -t --test           test compressed file integrity\n"
1654       "   -c --stdout         output to standard out\n"
1655       "   -q --quiet          suppress noncritical error messages\n"
1656       "   -v --verbose        be verbose (a 2nd -v gives more)\n"
1657       "   -L --license        display software version & license\n"
1658       "   -V --version        display software version & license\n"
1659       "   -s --small          use less memory (at most 2500k)\n"
1660       "   -1 .. -9            set block size to 100k .. 900k\n"
1661       "\n"
1662       "   If invoked as `bzip2', default action is to compress.\n"
1663       "              as `bunzip2',  default action is to decompress.\n"
1664       "              as `bzcat', default action is to decompress to stdout.\n"
1665       "\n"
1666       "   If no file names are given, bzip2 compresses or decompresses\n"
1667       "   from standard input to standard output.  You can combine\n"
1668       "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
1669 #if BZ_UNIX
1670       "\n"
1671 #endif
1672       ,
1673
1674       BZ2_bzlibVersion(),
1675       fullProgName
1676    );
1677 }
1678
1679
1680 /*---------------------------------------------*/
1681 static 
1682 void redundant ( Char* flag )
1683 {
1684    fprintf ( 
1685       stderr, 
1686       "%s: %s is redundant in versions 0.9.5 and above\n",
1687       progName, flag );
1688 }
1689
1690
1691 /*---------------------------------------------*/
1692 /*--
1693   All the garbage from here to main() is purely to
1694   implement a linked list of command-line arguments,
1695   into which main() copies argv[1 .. argc-1].
1696
1697   The purpose of this exercise is to facilitate 
1698   the expansion of wildcard characters * and ? in 
1699   filenames for OSs which don't know how to do it
1700   themselves, like MSDOS, Windows 95 and NT.
1701
1702   The actual Dirty Work is done by the platform-
1703   specific macro APPEND_FILESPEC.
1704 --*/
1705
1706 typedef
1707    struct zzzz {
1708       Char        *name;
1709       struct zzzz *link;
1710    }
1711    Cell;
1712
1713
1714 /*---------------------------------------------*/
1715 static 
1716 void *myMalloc ( Int32 n )
1717 {
1718    void* p;
1719
1720    p = malloc ( (size_t)n );
1721    if (p == NULL) outOfMemory ();
1722    return p;
1723 }
1724
1725
1726 /*---------------------------------------------*/
1727 static 
1728 Cell *mkCell ( void )
1729 {
1730    Cell *c;
1731
1732    c = (Cell*) myMalloc ( sizeof ( Cell ) );
1733    c->name = NULL;
1734    c->link = NULL;
1735    return c;
1736 }
1737
1738
1739 /*---------------------------------------------*/
1740 static 
1741 Cell *snocString ( Cell *root, Char *name )
1742 {
1743    if (root == NULL) {
1744       Cell *tmp = mkCell();
1745       tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
1746       strcpy ( tmp->name, name );
1747       return tmp;
1748    } else {
1749       Cell *tmp = root;
1750       while (tmp->link != NULL) tmp = tmp->link;
1751       tmp->link = snocString ( tmp->link, name );
1752       return root;
1753    }
1754 }
1755
1756
1757 /*---------------------------------------------*/
1758 static 
1759 void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 
1760 {
1761    Int32 i, j, k;
1762    Char *envbase, *p;
1763
1764    envbase = getenv(varName);
1765    if (envbase != NULL) {
1766       p = envbase;
1767       i = 0;
1768       while (True) {
1769          if (p[i] == 0) break;
1770          p += i;
1771          i = 0;
1772          while (isspace((Int32)(p[0]))) p++;
1773          while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
1774          if (i > 0) {
1775             k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
1776             for (j = 0; j < k; j++) tmpName[j] = p[j];
1777             tmpName[k] = 0;
1778             APPEND_FLAG(*argList, tmpName);
1779          }
1780       }
1781    }
1782 }
1783
1784
1785 /*---------------------------------------------*/
1786 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
1787
1788 IntNative main ( IntNative argc, Char *argv[] )
1789 {
1790    Int32  i, j;
1791    Char   *tmp;
1792    Cell   *argList;
1793    Cell   *aa;
1794    Bool   decode;
1795
1796    /*-- Be really really really paranoid :-) --*/
1797    if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
1798        sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
1799        sizeof(Char)  != 1 || sizeof(UChar)  != 1)
1800       configError();
1801
1802    /*-- Initialise --*/
1803    outputHandleJustInCase  = NULL;
1804    smallMode               = False;
1805    keepInputFiles          = False;
1806    forceOverwrite          = False;
1807    noisy                   = True;
1808    verbosity               = 0;
1809    blockSize100k           = 9;
1810    testFailsExist          = False;
1811    unzFailsExist           = False;
1812    numFileNames            = 0;
1813    numFilesProcessed       = 0;
1814    workFactor              = 30;
1815    deleteOutputOnInterrupt = False;
1816    exitValue               = 0;
1817    i = j = 0; /* avoid bogus warning from egcs-1.1.X */
1818
1819    /*-- Set up signal handlers for mem access errors --*/
1820    signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
1821 #if BZ_UNIX
1822 #ifndef __DJGPP__
1823    signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
1824 #endif
1825 #endif
1826
1827    copyFileName ( inName,  "(none)" );
1828    copyFileName ( outName, "(none)" );
1829
1830    copyFileName ( progNameReally, argv[0] );
1831    progName = &progNameReally[0];
1832    for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
1833       if (*tmp == PATH_SEP) progName = tmp + 1;
1834
1835
1836    /*-- Copy flags from env var BZIP2, and 
1837         expand filename wildcards in arg list.
1838    --*/
1839    argList = NULL;
1840    addFlagsFromEnvVar ( &argList,  "BZIP2" );
1841    addFlagsFromEnvVar ( &argList,  "BZIP" );
1842    for (i = 1; i <= argc-1; i++)
1843       APPEND_FILESPEC(argList, argv[i]);
1844
1845
1846    /*-- Find the length of the longest filename --*/
1847    longestFileName = 7;
1848    numFileNames    = 0;
1849    decode          = True;
1850    for (aa = argList; aa != NULL; aa = aa->link) {
1851       if (ISFLAG("--")) { decode = False; continue; }
1852       if (aa->name[0] == '-' && decode) continue;
1853       numFileNames++;
1854       if (longestFileName < (Int32)strlen(aa->name) )
1855          longestFileName = (Int32)strlen(aa->name);
1856    }
1857
1858
1859    /*-- Determine source modes; flag handling may change this too. --*/
1860    if (numFileNames == 0)
1861       srcMode = SM_I2O; else srcMode = SM_F2F;
1862
1863
1864    /*-- Determine what to do (compress/uncompress/test/cat). --*/
1865    /*-- Note that subsequent flag handling may change this. --*/
1866    opMode = OM_Z;
1867
1868    if ( (strstr ( progName, "unzip" ) != 0) ||
1869         (strstr ( progName, "UNZIP" ) != 0) )
1870       opMode = OM_UNZ;
1871
1872    if ( (strstr ( progName, "z2cat" ) != 0) ||
1873         (strstr ( progName, "Z2CAT" ) != 0) ||
1874         (strstr ( progName, "zcat" ) != 0)  ||
1875         (strstr ( progName, "ZCAT" ) != 0) )  {
1876       opMode = OM_UNZ;
1877       srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
1878    }
1879
1880
1881    /*-- Look at the flags. --*/
1882    for (aa = argList; aa != NULL; aa = aa->link) {
1883       if (ISFLAG("--")) break;
1884       if (aa->name[0] == '-' && aa->name[1] != '-') {
1885          for (j = 1; aa->name[j] != '\0'; j++) {
1886             switch (aa->name[j]) {
1887                case 'c': srcMode          = SM_F2O; break;
1888                case 'd': opMode           = OM_UNZ; break;
1889                case 'z': opMode           = OM_Z; break;
1890                case 'f': forceOverwrite   = True; break;
1891                case 't': opMode           = OM_TEST; break;
1892                case 'k': keepInputFiles   = True; break;
1893                case 's': smallMode        = True; break;
1894                case 'q': noisy            = False; break;
1895                case '1': blockSize100k    = 1; break;
1896                case '2': blockSize100k    = 2; break;
1897                case '3': blockSize100k    = 3; break;
1898                case '4': blockSize100k    = 4; break;
1899                case '5': blockSize100k    = 5; break;
1900                case '6': blockSize100k    = 6; break;
1901                case '7': blockSize100k    = 7; break;
1902                case '8': blockSize100k    = 8; break;
1903                case '9': blockSize100k    = 9; break;
1904                case 'V':
1905                case 'L': license();            break;
1906                case 'v': verbosity++; break;
1907                case 'h': usage ( progName );
1908                          exit ( 0 );
1909                          break;
1910                default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
1911                                    progName, aa->name );
1912                          usage ( progName );
1913                          exit ( 1 );
1914                          break;
1915             }
1916          }
1917       }
1918    }
1919    
1920    /*-- And again ... --*/
1921    for (aa = argList; aa != NULL; aa = aa->link) {
1922       if (ISFLAG("--")) break;
1923       if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
1924       if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
1925       if (ISFLAG("--compress"))          opMode           = OM_Z;    else
1926       if (ISFLAG("--force"))             forceOverwrite   = True;    else
1927       if (ISFLAG("--test"))              opMode           = OM_TEST; else
1928       if (ISFLAG("--keep"))              keepInputFiles   = True;    else
1929       if (ISFLAG("--small"))             smallMode        = True;    else
1930       if (ISFLAG("--quiet"))             noisy            = False;   else
1931       if (ISFLAG("--version"))           license();                  else
1932       if (ISFLAG("--license"))           license();                  else
1933       if (ISFLAG("--exponential"))       workFactor = 1;             else 
1934       if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
1935       if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
1936       if (ISFLAG("--verbose"))           verbosity++;                else
1937       if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
1938          else
1939          if (strncmp ( aa->name, "--", 2) == 0) {
1940             fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
1941             usage ( progName );
1942             exit ( 1 );
1943          }
1944    }
1945
1946    if (verbosity > 4) verbosity = 4;
1947    if (opMode == OM_Z && smallMode && blockSize100k > 2) 
1948       blockSize100k = 2;
1949
1950    if (opMode == OM_TEST && srcMode == SM_F2O) {
1951       fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
1952                 progName );
1953       exit ( 1 );
1954    }
1955
1956    if (srcMode == SM_F2O && numFileNames == 0)
1957       srcMode = SM_I2O;
1958
1959    if (opMode != OM_Z) blockSize100k = 0;
1960
1961    if (srcMode == SM_F2F) {
1962       signal (SIGINT,  mySignalCatcher);
1963       signal (SIGTERM, mySignalCatcher);
1964 #     if BZ_UNIX
1965       signal (SIGHUP,  mySignalCatcher);
1966 #     endif
1967    }
1968
1969    if (opMode == OM_Z) {
1970      if (srcMode == SM_I2O) {
1971         compress ( NULL );
1972      } else {
1973         decode = True;
1974         for (aa = argList; aa != NULL; aa = aa->link) {
1975            if (ISFLAG("--")) { decode = False; continue; }
1976            if (aa->name[0] == '-' && decode) continue;
1977            numFilesProcessed++;
1978            compress ( aa->name );
1979         }
1980      }
1981    } 
1982    else
1983
1984    if (opMode == OM_UNZ) {
1985       unzFailsExist = False;
1986       if (srcMode == SM_I2O) {
1987          uncompress ( NULL );
1988       } else {
1989          decode = True;
1990          for (aa = argList; aa != NULL; aa = aa->link) {
1991             if (ISFLAG("--")) { decode = False; continue; }
1992             if (aa->name[0] == '-' && decode) continue;
1993             numFilesProcessed++;
1994             uncompress ( aa->name );
1995          }      
1996       }
1997       if (unzFailsExist) { 
1998          setExit(2); 
1999          exit(exitValue);
2000       }
2001    } 
2002
2003    else {
2004       testFailsExist = False;
2005       if (srcMode == SM_I2O) {
2006          testf ( NULL );
2007       } else {
2008          decode = True;
2009          for (aa = argList; aa != NULL; aa = aa->link) {
2010             if (ISFLAG("--")) { decode = False; continue; }
2011             if (aa->name[0] == '-' && decode) continue;
2012             numFilesProcessed++;
2013             testf ( aa->name );
2014          }
2015       }
2016       if (testFailsExist && noisy) {
2017          fprintf ( stderr,
2018            "\n"
2019            "You can use the `bzip2recover' program to attempt to recover\n"
2020            "data from undamaged sections of corrupted files.\n\n"
2021          );
2022          setExit(2);
2023          exit(exitValue);
2024       }
2025    }
2026
2027    /* Free the argument list memory to mollify leak detectors 
2028       (eg) Purify, Checker.  Serves no other useful purpose.
2029    */
2030    aa = argList;
2031    while (aa != NULL) {
2032       Cell* aa2 = aa->link;
2033       if (aa->name != NULL) free(aa->name);
2034       free(aa);
2035       aa = aa2;
2036    }
2037
2038    return exitValue;
2039 }
2040
2041
2042 /*-----------------------------------------------------------*/
2043 /*--- end                                         bzip2.c ---*/
2044 /*-----------------------------------------------------------*/