home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #7 / amigamamagazinepolishissue1998.iso / archiwizery / bzip / bzip2-0.1pl2_src / bzip2recover.c < prev    next >
C/C++ Source or Header  |  1998-02-27  |  11KB  |  400 lines

  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-0.1 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. /*-----------------------------------------------------------*/
  400.