xref: /freebsd-src/contrib/bzip2/bzip2recover.c (revision 51f61fc0c7ece7a30c737341e65455841bc3f04e)
1df9de0ebSDavid E. O'Brien /*-----------------------------------------------------------*/
2df9de0ebSDavid E. O'Brien /*--- Block recoverer program for bzip2                   ---*/
3df9de0ebSDavid E. O'Brien /*---                                      bzip2recover.c ---*/
4df9de0ebSDavid E. O'Brien /*-----------------------------------------------------------*/
5df9de0ebSDavid E. O'Brien 
61b79bae0SXin LI /* ------------------------------------------------------------------
71b79bae0SXin LI    This file is part of bzip2/libbzip2, a program and library for
81b79bae0SXin LI    lossless, block-sorting data compression.
9df9de0ebSDavid E. O'Brien 
10*51f61fc0SXin LI    bzip2/libbzip2 version 1.0.8 of 13 July 2019
11*51f61fc0SXin LI    Copyright (C) 1996-2019 Julian Seward <jseward@acm.org>
12df9de0ebSDavid E. O'Brien 
131b79bae0SXin LI    Please read the WARNING, DISCLAIMER and PATENTS sections in the
141b79bae0SXin LI    README file.
15df9de0ebSDavid E. O'Brien 
161b79bae0SXin LI    This program is released under the terms of the license contained
171b79bae0SXin LI    in the file LICENSE.
181b79bae0SXin LI    ------------------------------------------------------------------ */
19df9de0ebSDavid E. O'Brien 
201b79bae0SXin LI /* This program is a complete hack and should be rewritten properly.
211b79bae0SXin LI 	 It isn't very complicated. */
22df9de0ebSDavid E. O'Brien 
23df9de0ebSDavid E. O'Brien #include <stdio.h>
24df9de0ebSDavid E. O'Brien #include <errno.h>
25df9de0ebSDavid E. O'Brien #include <stdlib.h>
26df9de0ebSDavid E. O'Brien #include <string.h>
27df9de0ebSDavid E. O'Brien 
28ed14b6e0SMaxim Sobolev 
29ed14b6e0SMaxim Sobolev /* This program records bit locations in the file to be recovered.
30ed14b6e0SMaxim Sobolev    That means that if 64-bit ints are not supported, we will not
31ed14b6e0SMaxim Sobolev    be able to recover .bz2 files over 512MB (2^32 bits) long.
32ed14b6e0SMaxim Sobolev    On GNU supported platforms, we take advantage of the 64-bit
33ed14b6e0SMaxim Sobolev    int support to circumvent this problem.  Ditto MSVC.
34ed14b6e0SMaxim Sobolev 
35ed14b6e0SMaxim Sobolev    This change occurred in version 1.0.2; all prior versions have
36ed14b6e0SMaxim Sobolev    the 512MB limitation.
37ed14b6e0SMaxim Sobolev */
38ed14b6e0SMaxim Sobolev #ifdef __GNUC__
39ed14b6e0SMaxim Sobolev    typedef  unsigned long long int  MaybeUInt64;
40586f6303SDimitry Andric #  define MaybeUInt64_FMT "%llu"
41ed14b6e0SMaxim Sobolev #else
42ed14b6e0SMaxim Sobolev #ifdef _MSC_VER
43ed14b6e0SMaxim Sobolev    typedef  unsigned __int64  MaybeUInt64;
44ed14b6e0SMaxim Sobolev #  define MaybeUInt64_FMT "%I64u"
45ed14b6e0SMaxim Sobolev #else
46ed14b6e0SMaxim Sobolev    typedef  unsigned int   MaybeUInt64;
47ed14b6e0SMaxim Sobolev #  define MaybeUInt64_FMT "%u"
48ed14b6e0SMaxim Sobolev #endif
49ed14b6e0SMaxim Sobolev #endif
50ed14b6e0SMaxim Sobolev 
51df9de0ebSDavid E. O'Brien typedef  unsigned int   UInt32;
52df9de0ebSDavid E. O'Brien typedef  int            Int32;
53df9de0ebSDavid E. O'Brien typedef  unsigned char  UChar;
54df9de0ebSDavid E. O'Brien typedef  char           Char;
55df9de0ebSDavid E. O'Brien typedef  unsigned char  Bool;
56df9de0ebSDavid E. O'Brien #define True    ((Bool)1)
57df9de0ebSDavid E. O'Brien #define False   ((Bool)0)
58df9de0ebSDavid E. O'Brien 
59df9de0ebSDavid E. O'Brien 
60ed14b6e0SMaxim Sobolev #define BZ_MAX_FILENAME 2000
61df9de0ebSDavid E. O'Brien 
62ed14b6e0SMaxim Sobolev Char inFileName[BZ_MAX_FILENAME];
63ed14b6e0SMaxim Sobolev Char outFileName[BZ_MAX_FILENAME];
64ed14b6e0SMaxim Sobolev Char progName[BZ_MAX_FILENAME];
65ed14b6e0SMaxim Sobolev 
66ed14b6e0SMaxim Sobolev MaybeUInt64 bytesOut = 0;
67ed14b6e0SMaxim Sobolev MaybeUInt64 bytesIn  = 0;
68ed14b6e0SMaxim Sobolev 
69ed14b6e0SMaxim Sobolev 
70ed14b6e0SMaxim Sobolev /*---------------------------------------------------*/
71ed14b6e0SMaxim Sobolev /*--- Header bytes                                ---*/
72ed14b6e0SMaxim Sobolev /*---------------------------------------------------*/
73ed14b6e0SMaxim Sobolev 
74ed14b6e0SMaxim Sobolev #define BZ_HDR_B 0x42                         /* 'B' */
75ed14b6e0SMaxim Sobolev #define BZ_HDR_Z 0x5a                         /* 'Z' */
76ed14b6e0SMaxim Sobolev #define BZ_HDR_h 0x68                         /* 'h' */
77ed14b6e0SMaxim Sobolev #define BZ_HDR_0 0x30                         /* '0' */
78df9de0ebSDavid E. O'Brien 
79df9de0ebSDavid E. O'Brien 
80df9de0ebSDavid E. O'Brien /*---------------------------------------------------*/
81df9de0ebSDavid E. O'Brien /*--- I/O errors                                  ---*/
82df9de0ebSDavid E. O'Brien /*---------------------------------------------------*/
83df9de0ebSDavid E. O'Brien 
84df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
readError(void)851b79bae0SXin LI static void readError ( void )
86df9de0ebSDavid E. O'Brien {
87df9de0ebSDavid E. O'Brien    fprintf ( stderr,
88df9de0ebSDavid E. O'Brien              "%s: I/O error reading `%s', possible reason follows.\n",
89df9de0ebSDavid E. O'Brien             progName, inFileName );
90df9de0ebSDavid E. O'Brien    perror ( progName );
91df9de0ebSDavid E. O'Brien    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
92df9de0ebSDavid E. O'Brien              progName );
93df9de0ebSDavid E. O'Brien    exit ( 1 );
94df9de0ebSDavid E. O'Brien }
95df9de0ebSDavid E. O'Brien 
96df9de0ebSDavid E. O'Brien 
97df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
writeError(void)981b79bae0SXin LI static void writeError ( void )
99df9de0ebSDavid E. O'Brien {
100df9de0ebSDavid E. O'Brien    fprintf ( stderr,
101df9de0ebSDavid E. O'Brien              "%s: I/O error reading `%s', possible reason follows.\n",
102df9de0ebSDavid E. O'Brien             progName, inFileName );
103df9de0ebSDavid E. O'Brien    perror ( progName );
104df9de0ebSDavid E. O'Brien    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
105df9de0ebSDavid E. O'Brien              progName );
106df9de0ebSDavid E. O'Brien    exit ( 1 );
107df9de0ebSDavid E. O'Brien }
108df9de0ebSDavid E. O'Brien 
109df9de0ebSDavid E. O'Brien 
110df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
mallocFail(Int32 n)1111b79bae0SXin LI static void mallocFail ( Int32 n )
112df9de0ebSDavid E. O'Brien {
113df9de0ebSDavid E. O'Brien    fprintf ( stderr,
114df9de0ebSDavid E. O'Brien              "%s: malloc failed on request for %d bytes.\n",
115df9de0ebSDavid E. O'Brien             progName, n );
116df9de0ebSDavid E. O'Brien    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
117df9de0ebSDavid E. O'Brien              progName );
118df9de0ebSDavid E. O'Brien    exit ( 1 );
119df9de0ebSDavid E. O'Brien }
120df9de0ebSDavid E. O'Brien 
121df9de0ebSDavid E. O'Brien 
122ed14b6e0SMaxim Sobolev /*---------------------------------------------*/
tooManyBlocks(Int32 max_handled_blocks)1231b79bae0SXin LI static void tooManyBlocks ( Int32 max_handled_blocks )
124ed14b6e0SMaxim Sobolev {
125ed14b6e0SMaxim Sobolev    fprintf ( stderr,
126ed14b6e0SMaxim Sobolev              "%s: `%s' appears to contain more than %d blocks\n",
127ed14b6e0SMaxim Sobolev             progName, inFileName, max_handled_blocks );
128ed14b6e0SMaxim Sobolev    fprintf ( stderr,
129ed14b6e0SMaxim Sobolev              "%s: and cannot be handled.  To fix, increase\n",
130ed14b6e0SMaxim Sobolev              progName );
131ed14b6e0SMaxim Sobolev    fprintf ( stderr,
132ed14b6e0SMaxim Sobolev              "%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n",
133ed14b6e0SMaxim Sobolev              progName );
134ed14b6e0SMaxim Sobolev    exit ( 1 );
135ed14b6e0SMaxim Sobolev }
136ed14b6e0SMaxim Sobolev 
137ed14b6e0SMaxim Sobolev 
138ed14b6e0SMaxim Sobolev 
139df9de0ebSDavid E. O'Brien /*---------------------------------------------------*/
140df9de0ebSDavid E. O'Brien /*--- Bit stream I/O                              ---*/
141df9de0ebSDavid E. O'Brien /*---------------------------------------------------*/
142df9de0ebSDavid E. O'Brien 
143df9de0ebSDavid E. O'Brien typedef
144df9de0ebSDavid E. O'Brien    struct {
145df9de0ebSDavid E. O'Brien       FILE*  handle;
146df9de0ebSDavid E. O'Brien       Int32  buffer;
147df9de0ebSDavid E. O'Brien       Int32  buffLive;
148df9de0ebSDavid E. O'Brien       Char   mode;
149df9de0ebSDavid E. O'Brien    }
150df9de0ebSDavid E. O'Brien    BitStream;
151df9de0ebSDavid E. O'Brien 
152df9de0ebSDavid E. O'Brien 
153df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
bsOpenReadStream(FILE * stream)1541b79bae0SXin LI static BitStream* bsOpenReadStream ( FILE* stream )
155df9de0ebSDavid E. O'Brien {
156df9de0ebSDavid E. O'Brien    BitStream *bs = malloc ( sizeof(BitStream) );
157df9de0ebSDavid E. O'Brien    if (bs == NULL) mallocFail ( sizeof(BitStream) );
158df9de0ebSDavid E. O'Brien    bs->handle = stream;
159df9de0ebSDavid E. O'Brien    bs->buffer = 0;
160df9de0ebSDavid E. O'Brien    bs->buffLive = 0;
161df9de0ebSDavid E. O'Brien    bs->mode = 'r';
162df9de0ebSDavid E. O'Brien    return bs;
163df9de0ebSDavid E. O'Brien }
164df9de0ebSDavid E. O'Brien 
165df9de0ebSDavid E. O'Brien 
166df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
bsOpenWriteStream(FILE * stream)1671b79bae0SXin LI static BitStream* bsOpenWriteStream ( FILE* stream )
168df9de0ebSDavid E. O'Brien {
169df9de0ebSDavid E. O'Brien    BitStream *bs = malloc ( sizeof(BitStream) );
170df9de0ebSDavid E. O'Brien    if (bs == NULL) mallocFail ( sizeof(BitStream) );
171df9de0ebSDavid E. O'Brien    bs->handle = stream;
172df9de0ebSDavid E. O'Brien    bs->buffer = 0;
173df9de0ebSDavid E. O'Brien    bs->buffLive = 0;
174df9de0ebSDavid E. O'Brien    bs->mode = 'w';
175df9de0ebSDavid E. O'Brien    return bs;
176df9de0ebSDavid E. O'Brien }
177df9de0ebSDavid E. O'Brien 
178df9de0ebSDavid E. O'Brien 
179df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
bsPutBit(BitStream * bs,Int32 bit)1801b79bae0SXin LI static void bsPutBit ( BitStream* bs, Int32 bit )
181df9de0ebSDavid E. O'Brien {
182df9de0ebSDavid E. O'Brien    if (bs->buffLive == 8) {
183df9de0ebSDavid E. O'Brien       Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
184df9de0ebSDavid E. O'Brien       if (retVal == EOF) writeError();
185df9de0ebSDavid E. O'Brien       bytesOut++;
186df9de0ebSDavid E. O'Brien       bs->buffLive = 1;
187df9de0ebSDavid E. O'Brien       bs->buffer = bit & 0x1;
188df9de0ebSDavid E. O'Brien    } else {
189df9de0ebSDavid E. O'Brien       bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
190df9de0ebSDavid E. O'Brien       bs->buffLive++;
191df9de0ebSDavid E. O'Brien    };
192df9de0ebSDavid E. O'Brien }
193df9de0ebSDavid E. O'Brien 
194df9de0ebSDavid E. O'Brien 
195df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
196df9de0ebSDavid E. O'Brien /*--
197df9de0ebSDavid E. O'Brien    Returns 0 or 1, or 2 to indicate EOF.
198df9de0ebSDavid E. O'Brien --*/
bsGetBit(BitStream * bs)1991b79bae0SXin LI static Int32 bsGetBit ( BitStream* bs )
200df9de0ebSDavid E. O'Brien {
201df9de0ebSDavid E. O'Brien    if (bs->buffLive > 0) {
202df9de0ebSDavid E. O'Brien       bs->buffLive --;
203df9de0ebSDavid E. O'Brien       return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
204df9de0ebSDavid E. O'Brien    } else {
205df9de0ebSDavid E. O'Brien       Int32 retVal = getc ( bs->handle );
206df9de0ebSDavid E. O'Brien       if ( retVal == EOF ) {
207df9de0ebSDavid E. O'Brien          if (errno != 0) readError();
208df9de0ebSDavid E. O'Brien          return 2;
209df9de0ebSDavid E. O'Brien       }
210df9de0ebSDavid E. O'Brien       bs->buffLive = 7;
211df9de0ebSDavid E. O'Brien       bs->buffer = retVal;
212df9de0ebSDavid E. O'Brien       return ( ((bs->buffer) >> 7) & 0x1 );
213df9de0ebSDavid E. O'Brien    }
214df9de0ebSDavid E. O'Brien }
215df9de0ebSDavid E. O'Brien 
216df9de0ebSDavid E. O'Brien 
217df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
bsClose(BitStream * bs)2181b79bae0SXin LI static void bsClose ( BitStream* bs )
219df9de0ebSDavid E. O'Brien {
220df9de0ebSDavid E. O'Brien    Int32 retVal;
221df9de0ebSDavid E. O'Brien 
222df9de0ebSDavid E. O'Brien    if ( bs->mode == 'w' ) {
223df9de0ebSDavid E. O'Brien       while ( bs->buffLive < 8 ) {
224df9de0ebSDavid E. O'Brien          bs->buffLive++;
225df9de0ebSDavid E. O'Brien          bs->buffer <<= 1;
226df9de0ebSDavid E. O'Brien       };
227df9de0ebSDavid E. O'Brien       retVal = putc ( (UChar) (bs->buffer), bs->handle );
228df9de0ebSDavid E. O'Brien       if (retVal == EOF) writeError();
229df9de0ebSDavid E. O'Brien       bytesOut++;
230df9de0ebSDavid E. O'Brien       retVal = fflush ( bs->handle );
231df9de0ebSDavid E. O'Brien       if (retVal == EOF) writeError();
232df9de0ebSDavid E. O'Brien    }
233df9de0ebSDavid E. O'Brien    retVal = fclose ( bs->handle );
234df9de0ebSDavid E. O'Brien    if (retVal == EOF) {
235df9de0ebSDavid E. O'Brien       if (bs->mode == 'w') writeError(); else readError();
236df9de0ebSDavid E. O'Brien    }
237df9de0ebSDavid E. O'Brien    free ( bs );
238df9de0ebSDavid E. O'Brien }
239df9de0ebSDavid E. O'Brien 
240df9de0ebSDavid E. O'Brien 
241df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
bsPutUChar(BitStream * bs,UChar c)2421b79bae0SXin LI static void bsPutUChar ( BitStream* bs, UChar c )
243df9de0ebSDavid E. O'Brien {
244df9de0ebSDavid E. O'Brien    Int32 i;
245df9de0ebSDavid E. O'Brien    for (i = 7; i >= 0; i--)
246df9de0ebSDavid E. O'Brien       bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
247df9de0ebSDavid E. O'Brien }
248df9de0ebSDavid E. O'Brien 
249df9de0ebSDavid E. O'Brien 
250df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
bsPutUInt32(BitStream * bs,UInt32 c)2511b79bae0SXin LI static void bsPutUInt32 ( BitStream* bs, UInt32 c )
252df9de0ebSDavid E. O'Brien {
253df9de0ebSDavid E. O'Brien    Int32 i;
254df9de0ebSDavid E. O'Brien 
255df9de0ebSDavid E. O'Brien    for (i = 31; i >= 0; i--)
256df9de0ebSDavid E. O'Brien       bsPutBit ( bs, (c >> i) & 0x1 );
257df9de0ebSDavid E. O'Brien }
258df9de0ebSDavid E. O'Brien 
259df9de0ebSDavid E. O'Brien 
260df9de0ebSDavid E. O'Brien /*---------------------------------------------*/
endsInBz2(Char * name)2611b79bae0SXin LI static Bool endsInBz2 ( Char* name )
262df9de0ebSDavid E. O'Brien {
263df9de0ebSDavid E. O'Brien    Int32 n = strlen ( name );
264df9de0ebSDavid E. O'Brien    if (n <= 4) return False;
265df9de0ebSDavid E. O'Brien    return
266df9de0ebSDavid E. O'Brien       (name[n-4] == '.' &&
267df9de0ebSDavid E. O'Brien        name[n-3] == 'b' &&
268df9de0ebSDavid E. O'Brien        name[n-2] == 'z' &&
269df9de0ebSDavid E. O'Brien        name[n-1] == '2');
270df9de0ebSDavid E. O'Brien }
271df9de0ebSDavid E. O'Brien 
272df9de0ebSDavid E. O'Brien 
273df9de0ebSDavid E. O'Brien /*---------------------------------------------------*/
274df9de0ebSDavid E. O'Brien /*---                                             ---*/
275df9de0ebSDavid E. O'Brien /*---------------------------------------------------*/
276df9de0ebSDavid E. O'Brien 
277ed14b6e0SMaxim Sobolev /* This logic isn't really right when it comes to Cygwin. */
278ed14b6e0SMaxim Sobolev #ifdef _WIN32
279ed14b6e0SMaxim Sobolev #  define  BZ_SPLIT_SYM  '\\'  /* path splitter on Windows platform */
280ed14b6e0SMaxim Sobolev #else
281ed14b6e0SMaxim Sobolev #  define  BZ_SPLIT_SYM  '/'   /* path splitter on Unix platform */
282ed14b6e0SMaxim Sobolev #endif
283ed14b6e0SMaxim Sobolev 
284df9de0ebSDavid E. O'Brien #define BLOCK_HEADER_HI  0x00003141UL
285df9de0ebSDavid E. O'Brien #define BLOCK_HEADER_LO  0x59265359UL
286df9de0ebSDavid E. O'Brien 
287df9de0ebSDavid E. O'Brien #define BLOCK_ENDMARK_HI 0x00001772UL
288df9de0ebSDavid E. O'Brien #define BLOCK_ENDMARK_LO 0x45385090UL
289df9de0ebSDavid E. O'Brien 
290ed14b6e0SMaxim Sobolev /* Increase if necessary.  However, a .bz2 file with > 50000 blocks
291ed14b6e0SMaxim Sobolev    would have an uncompressed size of at least 40GB, so the chances
292ed14b6e0SMaxim Sobolev    are low you'll need to up this.
293ed14b6e0SMaxim Sobolev */
294ed14b6e0SMaxim Sobolev #define BZ_MAX_HANDLED_BLOCKS 50000
295df9de0ebSDavid E. O'Brien 
296ed14b6e0SMaxim Sobolev MaybeUInt64 bStart [BZ_MAX_HANDLED_BLOCKS];
297ed14b6e0SMaxim Sobolev MaybeUInt64 bEnd   [BZ_MAX_HANDLED_BLOCKS];
298ed14b6e0SMaxim Sobolev MaybeUInt64 rbStart[BZ_MAX_HANDLED_BLOCKS];
299ed14b6e0SMaxim Sobolev MaybeUInt64 rbEnd  [BZ_MAX_HANDLED_BLOCKS];
300df9de0ebSDavid E. O'Brien 
main(Int32 argc,Char ** argv)301df9de0ebSDavid E. O'Brien Int32 main ( Int32 argc, Char** argv )
302df9de0ebSDavid E. O'Brien {
303df9de0ebSDavid E. O'Brien    FILE*       inFile;
304df9de0ebSDavid E. O'Brien    FILE*       outFile;
305df9de0ebSDavid E. O'Brien    BitStream*  bsIn, *bsWr;
306ed14b6e0SMaxim Sobolev    Int32       b, wrBlock, currBlock, rbCtr;
307ed14b6e0SMaxim Sobolev    MaybeUInt64 bitsRead;
308df9de0ebSDavid E. O'Brien 
309df9de0ebSDavid E. O'Brien    UInt32      buffHi, buffLo, blockCRC;
310df9de0ebSDavid E. O'Brien    Char*       p;
311df9de0ebSDavid E. O'Brien 
312b88cc53dSXin LI    strncpy ( progName, argv[0], BZ_MAX_FILENAME-1);
313b88cc53dSXin LI    progName[BZ_MAX_FILENAME-1]='\0';
314df9de0ebSDavid E. O'Brien    inFileName[0] = outFileName[0] = 0;
315df9de0ebSDavid E. O'Brien 
316ed14b6e0SMaxim Sobolev    fprintf ( stderr,
317*51f61fc0SXin LI              "bzip2recover 1.0.8: extracts blocks from damaged .bz2 files.\n" );
318df9de0ebSDavid E. O'Brien 
319df9de0ebSDavid E. O'Brien    if (argc != 2) {
320df9de0ebSDavid E. O'Brien       fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
321df9de0ebSDavid E. O'Brien                         progName, progName );
322ed14b6e0SMaxim Sobolev       switch (sizeof(MaybeUInt64)) {
323ed14b6e0SMaxim Sobolev          case 8:
324ed14b6e0SMaxim Sobolev             fprintf(stderr,
325ed14b6e0SMaxim Sobolev                     "\trestrictions on size of recovered file: None\n");
326ed14b6e0SMaxim Sobolev             break;
327ed14b6e0SMaxim Sobolev          case 4:
328ed14b6e0SMaxim Sobolev             fprintf(stderr,
329ed14b6e0SMaxim Sobolev                     "\trestrictions on size of recovered file: 512 MB\n");
330ed14b6e0SMaxim Sobolev             fprintf(stderr,
331ed14b6e0SMaxim Sobolev                     "\tto circumvent, recompile with MaybeUInt64 as an\n"
332ed14b6e0SMaxim Sobolev                     "\tunsigned 64-bit int.\n");
333ed14b6e0SMaxim Sobolev             break;
334ed14b6e0SMaxim Sobolev          default:
335ed14b6e0SMaxim Sobolev             fprintf(stderr,
336ed14b6e0SMaxim Sobolev                     "\tsizeof(MaybeUInt64) is not 4 or 8 -- "
337ed14b6e0SMaxim Sobolev                     "configuration error.\n");
338ed14b6e0SMaxim Sobolev             break;
339ed14b6e0SMaxim Sobolev       }
340ed14b6e0SMaxim Sobolev       exit(1);
341ed14b6e0SMaxim Sobolev    }
342ed14b6e0SMaxim Sobolev 
343ed14b6e0SMaxim Sobolev    if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) {
344ed14b6e0SMaxim Sobolev       fprintf ( stderr,
345ed14b6e0SMaxim Sobolev                 "%s: supplied filename is suspiciously (>= %d chars) long.  Bye!\n",
346f7a4f99fSDavid E. O'Brien                 progName, (int)strlen(argv[1]) );
347df9de0ebSDavid E. O'Brien       exit(1);
348df9de0ebSDavid E. O'Brien    }
349df9de0ebSDavid E. O'Brien 
350df9de0ebSDavid E. O'Brien    strcpy ( inFileName, argv[1] );
351df9de0ebSDavid E. O'Brien 
352df9de0ebSDavid E. O'Brien    inFile = fopen ( inFileName, "rb" );
353df9de0ebSDavid E. O'Brien    if (inFile == NULL) {
354df9de0ebSDavid E. O'Brien       fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
355df9de0ebSDavid E. O'Brien       exit(1);
356df9de0ebSDavid E. O'Brien    }
357df9de0ebSDavid E. O'Brien 
358df9de0ebSDavid E. O'Brien    bsIn = bsOpenReadStream ( inFile );
359df9de0ebSDavid E. O'Brien    fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
360df9de0ebSDavid E. O'Brien 
361df9de0ebSDavid E. O'Brien    bitsRead = 0;
362df9de0ebSDavid E. O'Brien    buffHi = buffLo = 0;
363df9de0ebSDavid E. O'Brien    currBlock = 0;
364df9de0ebSDavid E. O'Brien    bStart[currBlock] = 0;
365df9de0ebSDavid E. O'Brien 
366df9de0ebSDavid E. O'Brien    rbCtr = 0;
367df9de0ebSDavid E. O'Brien 
368df9de0ebSDavid E. O'Brien    while (True) {
369df9de0ebSDavid E. O'Brien       b = bsGetBit ( bsIn );
370df9de0ebSDavid E. O'Brien       bitsRead++;
371df9de0ebSDavid E. O'Brien       if (b == 2) {
372df9de0ebSDavid E. O'Brien          if (bitsRead >= bStart[currBlock] &&
373df9de0ebSDavid E. O'Brien             (bitsRead - bStart[currBlock]) >= 40) {
374df9de0ebSDavid E. O'Brien             bEnd[currBlock] = bitsRead-1;
375df9de0ebSDavid E. O'Brien             if (currBlock > 0)
376ed14b6e0SMaxim Sobolev                fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT
377ed14b6e0SMaxim Sobolev                                  " to " MaybeUInt64_FMT " (incomplete)\n",
378df9de0ebSDavid E. O'Brien                          currBlock,  bStart[currBlock], bEnd[currBlock] );
379df9de0ebSDavid E. O'Brien          } else
380df9de0ebSDavid E. O'Brien             currBlock--;
381df9de0ebSDavid E. O'Brien          break;
382df9de0ebSDavid E. O'Brien       }
383df9de0ebSDavid E. O'Brien       buffHi = (buffHi << 1) | (buffLo >> 31);
384df9de0ebSDavid E. O'Brien       buffLo = (buffLo << 1) | (b & 1);
385df9de0ebSDavid E. O'Brien       if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI
386df9de0ebSDavid E. O'Brien              && buffLo == BLOCK_HEADER_LO)
387df9de0ebSDavid E. O'Brien            ||
388df9de0ebSDavid E. O'Brien            ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI
389df9de0ebSDavid E. O'Brien              && buffLo == BLOCK_ENDMARK_LO)
390df9de0ebSDavid E. O'Brien          ) {
391ed14b6e0SMaxim Sobolev          if (bitsRead > 49) {
392ed14b6e0SMaxim Sobolev             bEnd[currBlock] = bitsRead-49;
393ed14b6e0SMaxim Sobolev          } else {
394df9de0ebSDavid E. O'Brien             bEnd[currBlock] = 0;
395ed14b6e0SMaxim Sobolev          }
396df9de0ebSDavid E. O'Brien          if (currBlock > 0 &&
397df9de0ebSDavid E. O'Brien 	     (bEnd[currBlock] - bStart[currBlock]) >= 130) {
398ed14b6e0SMaxim Sobolev             fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT
399ed14b6e0SMaxim Sobolev                               " to " MaybeUInt64_FMT "\n",
400df9de0ebSDavid E. O'Brien                       rbCtr+1,  bStart[currBlock], bEnd[currBlock] );
401df9de0ebSDavid E. O'Brien             rbStart[rbCtr] = bStart[currBlock];
402df9de0ebSDavid E. O'Brien             rbEnd[rbCtr] = bEnd[currBlock];
403df9de0ebSDavid E. O'Brien             rbCtr++;
404df9de0ebSDavid E. O'Brien          }
405ed14b6e0SMaxim Sobolev          if (currBlock >= BZ_MAX_HANDLED_BLOCKS)
406ed14b6e0SMaxim Sobolev             tooManyBlocks(BZ_MAX_HANDLED_BLOCKS);
407df9de0ebSDavid E. O'Brien          currBlock++;
408df9de0ebSDavid E. O'Brien 
409df9de0ebSDavid E. O'Brien          bStart[currBlock] = bitsRead;
410df9de0ebSDavid E. O'Brien       }
411df9de0ebSDavid E. O'Brien    }
412df9de0ebSDavid E. O'Brien 
413df9de0ebSDavid E. O'Brien    bsClose ( bsIn );
414df9de0ebSDavid E. O'Brien 
415df9de0ebSDavid E. O'Brien    /*-- identified blocks run from 1 to rbCtr inclusive. --*/
416df9de0ebSDavid E. O'Brien 
417df9de0ebSDavid E. O'Brien    if (rbCtr < 1) {
418df9de0ebSDavid E. O'Brien       fprintf ( stderr,
419df9de0ebSDavid E. O'Brien                 "%s: sorry, I couldn't find any block boundaries.\n",
420df9de0ebSDavid E. O'Brien                 progName );
421df9de0ebSDavid E. O'Brien       exit(1);
422df9de0ebSDavid E. O'Brien    };
423df9de0ebSDavid E. O'Brien 
424df9de0ebSDavid E. O'Brien    fprintf ( stderr, "%s: splitting into blocks\n", progName );
425df9de0ebSDavid E. O'Brien 
426df9de0ebSDavid E. O'Brien    inFile = fopen ( inFileName, "rb" );
427df9de0ebSDavid E. O'Brien    if (inFile == NULL) {
428df9de0ebSDavid E. O'Brien       fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
429df9de0ebSDavid E. O'Brien       exit(1);
430df9de0ebSDavid E. O'Brien    }
431df9de0ebSDavid E. O'Brien    bsIn = bsOpenReadStream ( inFile );
432df9de0ebSDavid E. O'Brien 
433df9de0ebSDavid E. O'Brien    /*-- placate gcc's dataflow analyser --*/
434df9de0ebSDavid E. O'Brien    blockCRC = 0; bsWr = 0;
435df9de0ebSDavid E. O'Brien 
436df9de0ebSDavid E. O'Brien    bitsRead = 0;
437df9de0ebSDavid E. O'Brien    outFile = NULL;
438df9de0ebSDavid E. O'Brien    wrBlock = 0;
439df9de0ebSDavid E. O'Brien    while (True) {
440df9de0ebSDavid E. O'Brien       b = bsGetBit(bsIn);
441df9de0ebSDavid E. O'Brien       if (b == 2) break;
442df9de0ebSDavid E. O'Brien       buffHi = (buffHi << 1) | (buffLo >> 31);
443df9de0ebSDavid E. O'Brien       buffLo = (buffLo << 1) | (b & 1);
444df9de0ebSDavid E. O'Brien       if (bitsRead == 47+rbStart[wrBlock])
445df9de0ebSDavid E. O'Brien          blockCRC = (buffHi << 16) | (buffLo >> 16);
446df9de0ebSDavid E. O'Brien 
447df9de0ebSDavid E. O'Brien       if (outFile != NULL && bitsRead >= rbStart[wrBlock]
448df9de0ebSDavid E. O'Brien                           && bitsRead <= rbEnd[wrBlock]) {
449df9de0ebSDavid E. O'Brien          bsPutBit ( bsWr, b );
450df9de0ebSDavid E. O'Brien       }
451df9de0ebSDavid E. O'Brien 
452df9de0ebSDavid E. O'Brien       bitsRead++;
453df9de0ebSDavid E. O'Brien 
454df9de0ebSDavid E. O'Brien       if (bitsRead == rbEnd[wrBlock]+1) {
455df9de0ebSDavid E. O'Brien          if (outFile != NULL) {
456df9de0ebSDavid E. O'Brien             bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
457df9de0ebSDavid E. O'Brien             bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
458df9de0ebSDavid E. O'Brien             bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
459df9de0ebSDavid E. O'Brien             bsPutUInt32 ( bsWr, blockCRC );
460df9de0ebSDavid E. O'Brien             bsClose ( bsWr );
461b88cc53dSXin LI             outFile = NULL;
462df9de0ebSDavid E. O'Brien          }
463df9de0ebSDavid E. O'Brien          if (wrBlock >= rbCtr) break;
464df9de0ebSDavid E. O'Brien          wrBlock++;
465df9de0ebSDavid E. O'Brien       } else
466df9de0ebSDavid E. O'Brien       if (bitsRead == rbStart[wrBlock]) {
467ed14b6e0SMaxim Sobolev          /* Create the output file name, correctly handling leading paths.
468ed14b6e0SMaxim Sobolev             (31.10.2001 by Sergey E. Kusikov) */
469ed14b6e0SMaxim Sobolev          Char* split;
470ed14b6e0SMaxim Sobolev          Int32 ofs, k;
471ed14b6e0SMaxim Sobolev          for (k = 0; k < BZ_MAX_FILENAME; k++)
472ed14b6e0SMaxim Sobolev             outFileName[k] = 0;
473ed14b6e0SMaxim Sobolev          strcpy (outFileName, inFileName);
474ed14b6e0SMaxim Sobolev          split = strrchr (outFileName, BZ_SPLIT_SYM);
475ed14b6e0SMaxim Sobolev          if (split == NULL) {
476ed14b6e0SMaxim Sobolev             split = outFileName;
477ed14b6e0SMaxim Sobolev          } else {
478ed14b6e0SMaxim Sobolev             ++split;
479ed14b6e0SMaxim Sobolev 	 }
480ed14b6e0SMaxim Sobolev 	 /* Now split points to the start of the basename. */
481ed14b6e0SMaxim Sobolev          ofs  = split - outFileName;
482ed14b6e0SMaxim Sobolev          sprintf (split, "rec%5d", wrBlock+1);
483ed14b6e0SMaxim Sobolev          for (p = split; *p != 0; p++) if (*p == ' ') *p = '0';
484ed14b6e0SMaxim Sobolev          strcat (outFileName, inFileName + ofs);
485ed14b6e0SMaxim Sobolev 
486df9de0ebSDavid E. O'Brien          if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
487df9de0ebSDavid E. O'Brien 
488df9de0ebSDavid E. O'Brien          fprintf ( stderr, "   writing block %d to `%s' ...\n",
489df9de0ebSDavid E. O'Brien                            wrBlock+1, outFileName );
490df9de0ebSDavid E. O'Brien 
491df9de0ebSDavid E. O'Brien          outFile = fopen ( outFileName, "wb" );
492df9de0ebSDavid E. O'Brien          if (outFile == NULL) {
493df9de0ebSDavid E. O'Brien             fprintf ( stderr, "%s: can't write `%s'\n",
494df9de0ebSDavid E. O'Brien                       progName, outFileName );
495df9de0ebSDavid E. O'Brien             exit(1);
496df9de0ebSDavid E. O'Brien          }
497df9de0ebSDavid E. O'Brien          bsWr = bsOpenWriteStream ( outFile );
498ed14b6e0SMaxim Sobolev          bsPutUChar ( bsWr, BZ_HDR_B );
499ed14b6e0SMaxim Sobolev          bsPutUChar ( bsWr, BZ_HDR_Z );
500ed14b6e0SMaxim Sobolev          bsPutUChar ( bsWr, BZ_HDR_h );
501ed14b6e0SMaxim Sobolev          bsPutUChar ( bsWr, BZ_HDR_0 + 9 );
502df9de0ebSDavid E. O'Brien          bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
503df9de0ebSDavid E. O'Brien          bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
504df9de0ebSDavid E. O'Brien          bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
505df9de0ebSDavid E. O'Brien       }
506df9de0ebSDavid E. O'Brien    }
507df9de0ebSDavid E. O'Brien 
508df9de0ebSDavid E. O'Brien    fprintf ( stderr, "%s: finished\n", progName );
509df9de0ebSDavid E. O'Brien    return 0;
510df9de0ebSDavid E. O'Brien }
511df9de0ebSDavid E. O'Brien 
512df9de0ebSDavid E. O'Brien 
513df9de0ebSDavid E. O'Brien 
514df9de0ebSDavid E. O'Brien /*-----------------------------------------------------------*/
515df9de0ebSDavid E. O'Brien /*--- end                                  bzip2recover.c ---*/
516df9de0ebSDavid E. O'Brien /*-----------------------------------------------------------*/
517