Edit

kc3-lang/bzip2/bzip2recover.c

Branch :

  • Show log

    Commit

  • Author : Julian Seward
    Date : 1997-08-07 22:13:13
    Hash : 33d13403
    Message : bzip2-0.1

  • bzip2recover.c
  • /*-----------------------------------------------------------*/
    /*--- 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 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>
    #include <malloc.h>
    #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 ---*/
    /*-----------------------------------------------------------*/