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