This is bzip2recover.c in view mode; [Download] [Up]
/*-----------------------------------------------------------*/ /*--- Block recoverer program for bzip2 ---*/ /*--- bzip2recover.c ---*/ /*-----------------------------------------------------------*/ /*-- This program is bzip2recover, a program to attempt data salvage from damaged files created by the accompanying bzip2-0.1 program. Copyright (C) 1996, 1997 by Julian Seward. Guildford, Surrey, UK email: jseward@acm.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The GNU General Public License is contained in the file LICENSE. --*/ #include <stdio.h> #include <errno.h> #ifndef NEXT #include <malloc.h> #endif #include <stdlib.h> #include <strings.h> /*-- or try string.h --*/ #define UInt32 unsigned int #define Int32 int #define UChar unsigned char #define Char char #define Bool unsigned char #define True 1 #define False 0 Char inFileName[2000]; Char outFileName[2000]; Char progName[2000]; UInt32 bytesOut = 0; UInt32 bytesIn = 0; /*---------------------------------------------------*/ /*--- I/O errors ---*/ /*---------------------------------------------------*/ /*---------------------------------------------*/ void readError ( void ) { fprintf ( stderr, "%s: I/O error reading `%s', possible reason follows.\n", progName, inFileName ); perror ( progName ); fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", progName ); exit ( 1 ); } /*---------------------------------------------*/ void writeError ( void ) { fprintf ( stderr, "%s: I/O error reading `%s', possible reason follows.\n", progName, inFileName ); perror ( progName ); fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", progName ); exit ( 1 ); } /*---------------------------------------------*/ void mallocFail ( Int32 n ) { fprintf ( stderr, "%s: malloc failed on request for %d bytes.\n", progName, n ); fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", progName ); exit ( 1 ); } /*---------------------------------------------------*/ /*--- Bit stream I/O ---*/ /*---------------------------------------------------*/ typedef struct { FILE* handle; Int32 buffer; Int32 buffLive; Char mode; } BitStream; /*---------------------------------------------*/ BitStream* bsOpenReadStream ( FILE* stream ) { BitStream *bs = malloc ( sizeof(BitStream) ); if (bs == NULL) mallocFail ( sizeof(BitStream) ); bs->handle = stream; bs->buffer = 0; bs->buffLive = 0; bs->mode = 'r'; return bs; } /*---------------------------------------------*/ BitStream* bsOpenWriteStream ( FILE* stream ) { BitStream *bs = malloc ( sizeof(BitStream) ); if (bs == NULL) mallocFail ( sizeof(BitStream) ); bs->handle = stream; bs->buffer = 0; bs->buffLive = 0; bs->mode = 'w'; return bs; } /*---------------------------------------------*/ void bsPutBit ( BitStream* bs, Int32 bit ) { if (bs->buffLive == 8) { Int32 retVal = putc ( (UChar) bs->buffer, bs->handle ); if (retVal == EOF) writeError(); bytesOut++; bs->buffLive = 1; bs->buffer = bit & 0x1; } else { bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) ); bs->buffLive++; }; } /*---------------------------------------------*/ /*-- Returns 0 or 1, or 2 to indicate EOF. --*/ Int32 bsGetBit ( BitStream* bs ) { if (bs->buffLive > 0) { bs->buffLive --; return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 ); } else { Int32 retVal = getc ( bs->handle ); if ( retVal == EOF ) { if (errno != 0) readError(); return 2; } bs->buffLive = 7; bs->buffer = retVal; return ( ((bs->buffer) >> 7) & 0x1 ); } } /*---------------------------------------------*/ void bsClose ( BitStream* bs ) { Int32 retVal; if ( bs->mode == 'w' ) { while ( bs->buffLive < 8 ) { bs->buffLive++; bs->buffer <<= 1; }; retVal = putc ( (UChar) (bs->buffer), bs->handle ); if (retVal == EOF) writeError(); bytesOut++; retVal = fflush ( bs->handle ); if (retVal == EOF) writeError(); } retVal = fclose ( bs->handle ); if (retVal == EOF) if (bs->mode == 'w') writeError(); else readError(); free ( bs ); } /*---------------------------------------------*/ void bsPutUChar ( BitStream* bs, UChar c ) { Int32 i; for (i = 7; i >= 0; i--) bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 ); } /*---------------------------------------------*/ void bsPutUInt32 ( BitStream* bs, UInt32 c ) { Int32 i; for (i = 31; i >= 0; i--) bsPutBit ( bs, (c >> i) & 0x1 ); } /*---------------------------------------------*/ Bool endsInBz2 ( Char* name ) { Int32 n = strlen ( name ); if (n <= 4) return False; return (name[n-4] == '.' && name[n-3] == 'b' && name[n-2] == 'z' && name[n-1] == '2'); } /*---------------------------------------------------*/ /*--- ---*/ /*---------------------------------------------------*/ #define BLOCK_HEADER_HI 0x00003141UL #define BLOCK_HEADER_LO 0x59265359UL #define BLOCK_ENDMARK_HI 0x00001772UL #define BLOCK_ENDMARK_LO 0x45385090UL Int32 main ( Int32 argc, Char** argv ) { FILE* inFile; FILE* outFile; BitStream* bsIn, *bsWr; Int32 currBlock, b, wrBlock; UInt32 bitsRead; UInt32 bStart[20000]; UInt32 bEnd[20000]; UInt32 buffHi, buffLo, blockCRC; Char* p; strcpy ( progName, argv[0] ); inFileName[0] = outFileName[0] = 0; fprintf ( stderr, "bzip2recover: extracts blocks from damaged .bz2 files.\n" ); if (argc != 2) { fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n", progName, progName ); exit(1); } strcpy ( inFileName, argv[1] ); inFile = fopen ( inFileName, "rb" ); if (inFile == NULL) { fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName ); exit(1); } bsIn = bsOpenReadStream ( inFile ); fprintf ( stderr, "%s: searching for block boundaries ...\n", progName ); bitsRead = 0; buffHi = buffLo = 0; currBlock = 0; bStart[currBlock] = 0; while (True) { b = bsGetBit ( bsIn ); bitsRead++; if (b == 2) { if (bitsRead >= bStart[currBlock] && (bitsRead - bStart[currBlock]) >= 40) { bEnd[currBlock] = bitsRead-1; if (currBlock > 0) fprintf ( stderr, " block %d runs from %d to %d (incomplete)\n", currBlock, bStart[currBlock], bEnd[currBlock] ); } else currBlock--; break; } buffHi = (buffHi << 1) | (buffLo >> 31); buffLo = (buffLo << 1) | (b & 1); if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI && buffLo == BLOCK_HEADER_LO) || ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI && buffLo == BLOCK_ENDMARK_LO) ) { if (bitsRead > 49) bEnd[currBlock] = bitsRead-49; else bEnd[currBlock] = 0; if (currBlock > 0) fprintf ( stderr, " block %d runs from %d to %d\n", currBlock, bStart[currBlock], bEnd[currBlock] ); currBlock++; bStart[currBlock] = bitsRead; } } bsClose ( bsIn ); /*-- identified blocks run from 1 to currBlock inclusive. --*/ if (currBlock < 1) { fprintf ( stderr, "%s: sorry, I couldn't find any block boundaries.\n", progName ); exit(1); }; fprintf ( stderr, "%s: splitting into blocks\n", progName ); inFile = fopen ( inFileName, "rb" ); if (inFile == NULL) { fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName ); exit(1); } bsIn = bsOpenReadStream ( inFile ); /*-- placate gcc's dataflow analyser --*/ blockCRC = 0; bsWr = 0; bitsRead = 0; outFile = NULL; wrBlock = 1; while (True) { b = bsGetBit(bsIn); if (b == 2) break; buffHi = (buffHi << 1) | (buffLo >> 31); buffLo = (buffLo << 1) | (b & 1); if (bitsRead == 47+bStart[wrBlock]) blockCRC = (buffHi << 16) | (buffLo >> 16); if (outFile != NULL && bitsRead >= bStart[wrBlock] && bitsRead <= bEnd[wrBlock]) { bsPutBit ( bsWr, b ); } bitsRead++; if (bitsRead == bEnd[wrBlock]+1) { if (outFile != NULL) { bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 ); bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 ); bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 ); bsPutUInt32 ( bsWr, blockCRC ); bsClose ( bsWr ); } if (wrBlock >= currBlock) break; wrBlock++; } else if (bitsRead == bStart[wrBlock]) { outFileName[0] = 0; sprintf ( outFileName, "rec%4d", wrBlock ); for (p = outFileName; *p != 0; p++) if (*p == ' ') *p = '0'; strcat ( outFileName, inFileName ); if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" ); fprintf ( stderr, " writing block %d to `%s' ...\n", wrBlock, outFileName ); outFile = fopen ( outFileName, "wb" ); if (outFile == NULL) { fprintf ( stderr, "%s: can't write `%s'\n", progName, outFileName ); exit(1); } bsWr = bsOpenWriteStream ( outFile ); bsPutUChar ( bsWr, 'B' ); bsPutUChar ( bsWr, 'Z' ); bsPutUChar ( bsWr, 'h' ); bsPutUChar ( bsWr, '9' ); bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 ); bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 ); bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 ); } } fprintf ( stderr, "%s: finished\n", progName ); return 0; } /*-----------------------------------------------------------*/ /*--- end bzip2recover.c ---*/ /*-----------------------------------------------------------*/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.