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