diff options
author | Julian Seward <jseward@acm.org> | 1997-08-07 22:13:13 +0200 |
---|---|---|
committer | Julian Seward <jseward@acm.org> | 1997-08-07 22:13:13 +0200 |
commit | 33d134030248633ffa7d60c0a35a783c46da034b (patch) | |
tree | b760dc34185dccc7054989c1472478574223cc31 /bzip2recover.c | |
download | bzip2-0.1.tar.gz bzip2-0.1.tar.bz2 bzip2-0.1.zip |
bzip2-0.1bzip2-0.1
Diffstat (limited to 'bzip2recover.c')
-rw-r--r-- | bzip2recover.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/bzip2recover.c b/bzip2recover.c new file mode 100644 index 0000000..efdfb3c --- /dev/null +++ b/bzip2recover.c | |||
@@ -0,0 +1,399 @@ | |||
1 | |||
2 | /*-----------------------------------------------------------*/ | ||
3 | /*--- Block recoverer program for bzip2 ---*/ | ||
4 | /*--- bzip2recover.c ---*/ | ||
5 | /*-----------------------------------------------------------*/ | ||
6 | |||
7 | /*-- | ||
8 | This program is bzip2recover, a program to attempt data | ||
9 | salvage from damaged files created by the accompanying | ||
10 | bzip2 program. | ||
11 | |||
12 | Copyright (C) 1996, 1997 by Julian Seward. | ||
13 | Guildford, Surrey, UK | ||
14 | email: jseward@acm.org | ||
15 | |||
16 | This program is free software; you can redistribute it and/or modify | ||
17 | it under the terms of the GNU General Public License as published by | ||
18 | the Free Software Foundation; either version 2 of the License, or | ||
19 | (at your option) any later version. | ||
20 | |||
21 | This program is distributed in the hope that it will be useful, | ||
22 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | GNU General Public License for more details. | ||
25 | |||
26 | You should have received a copy of the GNU General Public License | ||
27 | along with this program; if not, write to the Free Software | ||
28 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | |||
30 | The GNU General Public License is contained in the file LICENSE. | ||
31 | --*/ | ||
32 | |||
33 | |||
34 | #include <stdio.h> | ||
35 | #include <errno.h> | ||
36 | #include <malloc.h> | ||
37 | #include <stdlib.h> | ||
38 | #include <strings.h> /*-- or try string.h --*/ | ||
39 | |||
40 | #define UInt32 unsigned int | ||
41 | #define Int32 int | ||
42 | #define UChar unsigned char | ||
43 | #define Char char | ||
44 | #define Bool unsigned char | ||
45 | #define True 1 | ||
46 | #define False 0 | ||
47 | |||
48 | |||
49 | Char inFileName[2000]; | ||
50 | Char outFileName[2000]; | ||
51 | Char progName[2000]; | ||
52 | |||
53 | UInt32 bytesOut = 0; | ||
54 | UInt32 bytesIn = 0; | ||
55 | |||
56 | |||
57 | /*---------------------------------------------------*/ | ||
58 | /*--- I/O errors ---*/ | ||
59 | /*---------------------------------------------------*/ | ||
60 | |||
61 | /*---------------------------------------------*/ | ||
62 | void readError ( void ) | ||
63 | { | ||
64 | fprintf ( stderr, | ||
65 | "%s: I/O error reading `%s', possible reason follows.\n", | ||
66 | progName, inFileName ); | ||
67 | perror ( progName ); | ||
68 | fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", | ||
69 | progName ); | ||
70 | exit ( 1 ); | ||
71 | } | ||
72 | |||
73 | |||
74 | /*---------------------------------------------*/ | ||
75 | void writeError ( void ) | ||
76 | { | ||
77 | fprintf ( stderr, | ||
78 | "%s: I/O error reading `%s', possible reason follows.\n", | ||
79 | progName, inFileName ); | ||
80 | perror ( progName ); | ||
81 | fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", | ||
82 | progName ); | ||
83 | exit ( 1 ); | ||
84 | } | ||
85 | |||
86 | |||
87 | /*---------------------------------------------*/ | ||
88 | void mallocFail ( Int32 n ) | ||
89 | { | ||
90 | fprintf ( stderr, | ||
91 | "%s: malloc failed on request for %d bytes.\n", | ||
92 | progName, n ); | ||
93 | fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", | ||
94 | progName ); | ||
95 | exit ( 1 ); | ||
96 | } | ||
97 | |||
98 | |||
99 | /*---------------------------------------------------*/ | ||
100 | /*--- Bit stream I/O ---*/ | ||
101 | /*---------------------------------------------------*/ | ||
102 | |||
103 | typedef | ||
104 | struct { | ||
105 | FILE* handle; | ||
106 | Int32 buffer; | ||
107 | Int32 buffLive; | ||
108 | Char mode; | ||
109 | } | ||
110 | BitStream; | ||
111 | |||
112 | |||
113 | /*---------------------------------------------*/ | ||
114 | BitStream* bsOpenReadStream ( FILE* stream ) | ||
115 | { | ||
116 | BitStream *bs = malloc ( sizeof(BitStream) ); | ||
117 | if (bs == NULL) mallocFail ( sizeof(BitStream) ); | ||
118 | bs->handle = stream; | ||
119 | bs->buffer = 0; | ||
120 | bs->buffLive = 0; | ||
121 | bs->mode = 'r'; | ||
122 | return bs; | ||
123 | } | ||
124 | |||
125 | |||
126 | /*---------------------------------------------*/ | ||
127 | BitStream* bsOpenWriteStream ( FILE* stream ) | ||
128 | { | ||
129 | BitStream *bs = malloc ( sizeof(BitStream) ); | ||
130 | if (bs == NULL) mallocFail ( sizeof(BitStream) ); | ||
131 | bs->handle = stream; | ||
132 | bs->buffer = 0; | ||
133 | bs->buffLive = 0; | ||
134 | bs->mode = 'w'; | ||
135 | return bs; | ||
136 | } | ||
137 | |||
138 | |||
139 | /*---------------------------------------------*/ | ||
140 | void bsPutBit ( BitStream* bs, Int32 bit ) | ||
141 | { | ||
142 | if (bs->buffLive == 8) { | ||
143 | Int32 retVal = putc ( (UChar) bs->buffer, bs->handle ); | ||
144 | if (retVal == EOF) writeError(); | ||
145 | bytesOut++; | ||
146 | bs->buffLive = 1; | ||
147 | bs->buffer = bit & 0x1; | ||
148 | } else { | ||
149 | bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) ); | ||
150 | bs->buffLive++; | ||
151 | }; | ||
152 | } | ||
153 | |||
154 | |||
155 | /*---------------------------------------------*/ | ||
156 | /*-- | ||
157 | Returns 0 or 1, or 2 to indicate EOF. | ||
158 | --*/ | ||
159 | Int32 bsGetBit ( BitStream* bs ) | ||
160 | { | ||
161 | if (bs->buffLive > 0) { | ||
162 | bs->buffLive --; | ||
163 | return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 ); | ||
164 | } else { | ||
165 | Int32 retVal = getc ( bs->handle ); | ||
166 | if ( retVal == EOF ) { | ||
167 | if (errno != 0) readError(); | ||
168 | return 2; | ||
169 | } | ||
170 | bs->buffLive = 7; | ||
171 | bs->buffer = retVal; | ||
172 | return ( ((bs->buffer) >> 7) & 0x1 ); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | |||
177 | /*---------------------------------------------*/ | ||
178 | void bsClose ( BitStream* bs ) | ||
179 | { | ||
180 | Int32 retVal; | ||
181 | |||
182 | if ( bs->mode == 'w' ) { | ||
183 | while ( bs->buffLive < 8 ) { | ||
184 | bs->buffLive++; | ||
185 | bs->buffer <<= 1; | ||
186 | }; | ||
187 | retVal = putc ( (UChar) (bs->buffer), bs->handle ); | ||
188 | if (retVal == EOF) writeError(); | ||
189 | bytesOut++; | ||
190 | retVal = fflush ( bs->handle ); | ||
191 | if (retVal == EOF) writeError(); | ||
192 | } | ||
193 | retVal = fclose ( bs->handle ); | ||
194 | if (retVal == EOF) | ||
195 | if (bs->mode == 'w') writeError(); else readError(); | ||
196 | free ( bs ); | ||
197 | } | ||
198 | |||
199 | |||
200 | /*---------------------------------------------*/ | ||
201 | void bsPutUChar ( BitStream* bs, UChar c ) | ||
202 | { | ||
203 | Int32 i; | ||
204 | for (i = 7; i >= 0; i--) | ||
205 | bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 ); | ||
206 | } | ||
207 | |||
208 | |||
209 | /*---------------------------------------------*/ | ||
210 | void bsPutUInt32 ( BitStream* bs, UInt32 c ) | ||
211 | { | ||
212 | Int32 i; | ||
213 | |||
214 | for (i = 31; i >= 0; i--) | ||
215 | bsPutBit ( bs, (c >> i) & 0x1 ); | ||
216 | } | ||
217 | |||
218 | |||
219 | /*---------------------------------------------*/ | ||
220 | Bool endsInBz2 ( Char* name ) | ||
221 | { | ||
222 | Int32 n = strlen ( name ); | ||
223 | if (n <= 4) return False; | ||
224 | return | ||
225 | (name[n-4] == '.' && | ||
226 | name[n-3] == 'b' && | ||
227 | name[n-2] == 'z' && | ||
228 | name[n-1] == '2'); | ||
229 | } | ||
230 | |||
231 | |||
232 | /*---------------------------------------------------*/ | ||
233 | /*--- ---*/ | ||
234 | /*---------------------------------------------------*/ | ||
235 | |||
236 | #define BLOCK_HEADER_HI 0x00003141UL | ||
237 | #define BLOCK_HEADER_LO 0x59265359UL | ||
238 | |||
239 | #define BLOCK_ENDMARK_HI 0x00001772UL | ||
240 | #define BLOCK_ENDMARK_LO 0x45385090UL | ||
241 | |||
242 | Int32 main ( Int32 argc, Char** argv ) | ||
243 | { | ||
244 | FILE* inFile; | ||
245 | FILE* outFile; | ||
246 | BitStream* bsIn, *bsWr; | ||
247 | Int32 currBlock, b, wrBlock; | ||
248 | UInt32 bitsRead; | ||
249 | UInt32 bStart[20000]; | ||
250 | UInt32 bEnd[20000]; | ||
251 | UInt32 buffHi, buffLo, blockCRC; | ||
252 | Char* p; | ||
253 | |||
254 | strcpy ( progName, argv[0] ); | ||
255 | inFileName[0] = outFileName[0] = 0; | ||
256 | |||
257 | fprintf ( stderr, "bzip2recover: extracts blocks from damaged .bz2 files.\n" ); | ||
258 | |||
259 | if (argc != 2) { | ||
260 | fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n", | ||
261 | progName, progName ); | ||
262 | exit(1); | ||
263 | } | ||
264 | |||
265 | strcpy ( inFileName, argv[1] ); | ||
266 | |||
267 | inFile = fopen ( inFileName, "rb" ); | ||
268 | if (inFile == NULL) { | ||
269 | fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName ); | ||
270 | exit(1); | ||
271 | } | ||
272 | |||
273 | bsIn = bsOpenReadStream ( inFile ); | ||
274 | fprintf ( stderr, "%s: searching for block boundaries ...\n", progName ); | ||
275 | |||
276 | bitsRead = 0; | ||
277 | buffHi = buffLo = 0; | ||
278 | currBlock = 0; | ||
279 | bStart[currBlock] = 0; | ||
280 | |||
281 | while (True) { | ||
282 | b = bsGetBit ( bsIn ); | ||
283 | bitsRead++; | ||
284 | if (b == 2) { | ||
285 | if (bitsRead >= bStart[currBlock] && | ||
286 | (bitsRead - bStart[currBlock]) >= 40) { | ||
287 | bEnd[currBlock] = bitsRead-1; | ||
288 | if (currBlock > 0) | ||
289 | fprintf ( stderr, " block %d runs from %d to %d (incomplete)\n", | ||
290 | currBlock, bStart[currBlock], bEnd[currBlock] ); | ||
291 | } else | ||
292 | currBlock--; | ||
293 | break; | ||
294 | } | ||
295 | buffHi = (buffHi << 1) | (buffLo >> 31); | ||
296 | buffLo = (buffLo << 1) | (b & 1); | ||
297 | if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI | ||
298 | && buffLo == BLOCK_HEADER_LO) | ||
299 | || | ||
300 | ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI | ||
301 | && buffLo == BLOCK_ENDMARK_LO) | ||
302 | ) { | ||
303 | if (bitsRead > 49) | ||
304 | bEnd[currBlock] = bitsRead-49; else | ||
305 | bEnd[currBlock] = 0; | ||
306 | if (currBlock > 0) | ||
307 | fprintf ( stderr, " block %d runs from %d to %d\n", | ||
308 | currBlock, bStart[currBlock], bEnd[currBlock] ); | ||
309 | currBlock++; | ||
310 | bStart[currBlock] = bitsRead; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | bsClose ( bsIn ); | ||
315 | |||
316 | /*-- identified blocks run from 1 to currBlock inclusive. --*/ | ||
317 | |||
318 | if (currBlock < 1) { | ||
319 | fprintf ( stderr, | ||
320 | "%s: sorry, I couldn't find any block boundaries.\n", | ||
321 | progName ); | ||
322 | exit(1); | ||
323 | }; | ||
324 | |||
325 | fprintf ( stderr, "%s: splitting into blocks\n", progName ); | ||
326 | |||
327 | inFile = fopen ( inFileName, "rb" ); | ||
328 | if (inFile == NULL) { | ||
329 | fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName ); | ||
330 | exit(1); | ||
331 | } | ||
332 | bsIn = bsOpenReadStream ( inFile ); | ||
333 | |||
334 | /*-- placate gcc's dataflow analyser --*/ | ||
335 | blockCRC = 0; bsWr = 0; | ||
336 | |||
337 | bitsRead = 0; | ||
338 | outFile = NULL; | ||
339 | wrBlock = 1; | ||
340 | while (True) { | ||
341 | b = bsGetBit(bsIn); | ||
342 | if (b == 2) break; | ||
343 | buffHi = (buffHi << 1) | (buffLo >> 31); | ||
344 | buffLo = (buffLo << 1) | (b & 1); | ||
345 | if (bitsRead == 47+bStart[wrBlock]) | ||
346 | blockCRC = (buffHi << 16) | (buffLo >> 16); | ||
347 | |||
348 | if (outFile != NULL && bitsRead >= bStart[wrBlock] | ||
349 | && bitsRead <= bEnd[wrBlock]) { | ||
350 | bsPutBit ( bsWr, b ); | ||
351 | } | ||
352 | |||
353 | bitsRead++; | ||
354 | |||
355 | if (bitsRead == bEnd[wrBlock]+1) { | ||
356 | if (outFile != NULL) { | ||
357 | bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 ); | ||
358 | bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 ); | ||
359 | bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 ); | ||
360 | bsPutUInt32 ( bsWr, blockCRC ); | ||
361 | bsClose ( bsWr ); | ||
362 | } | ||
363 | if (wrBlock >= currBlock) break; | ||
364 | wrBlock++; | ||
365 | } else | ||
366 | if (bitsRead == bStart[wrBlock]) { | ||
367 | outFileName[0] = 0; | ||
368 | sprintf ( outFileName, "rec%4d", wrBlock ); | ||
369 | for (p = outFileName; *p != 0; p++) if (*p == ' ') *p = '0'; | ||
370 | strcat ( outFileName, inFileName ); | ||
371 | if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" ); | ||
372 | |||
373 | fprintf ( stderr, " writing block %d to `%s' ...\n", | ||
374 | wrBlock, outFileName ); | ||
375 | |||
376 | outFile = fopen ( outFileName, "wb" ); | ||
377 | if (outFile == NULL) { | ||
378 | fprintf ( stderr, "%s: can't write `%s'\n", | ||
379 | progName, outFileName ); | ||
380 | exit(1); | ||
381 | } | ||
382 | bsWr = bsOpenWriteStream ( outFile ); | ||
383 | bsPutUChar ( bsWr, 'B' ); bsPutUChar ( bsWr, 'Z' ); | ||
384 | bsPutUChar ( bsWr, 'h' ); bsPutUChar ( bsWr, '9' ); | ||
385 | bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 ); | ||
386 | bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 ); | ||
387 | bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 ); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | fprintf ( stderr, "%s: finished\n", progName ); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | |||
396 | |||
397 | /*-----------------------------------------------------------*/ | ||
398 | /*--- end bzip2recover.c ---*/ | ||
399 | /*-----------------------------------------------------------*/ | ||