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