text: /*-----------------------------------------------------------*/
  /*--- Block recoverer program for bzip2                   ---*/
  /*---                                      bzip2recover.c ---*/
  /*-----------------------------------------------------------*/
  
  /* ------------------------------------------------------------------
     This file is part of bzip2/libbzip2, a program and library for
     lossless, block-sorting data compression.
  
     bzip2/libbzip2 version 1.0.6 of 6 September 2010
     Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
  
     Please read the WARNING, DISCLAIMER and PATENTS sections in the 
     README file.
  
     This program is released under the terms of the license contained
     in the file LICENSE.
     ------------------------------------------------------------------ */
  
  /* This program is a complete hack and should be rewritten properly.
  	 It isn't very complicated. */
  
  #include <stdio.h>
  #include <errno.h>
  #include <stdlib.h>
  #include <string.h>
  
  
  /* This program records bit locations in the file to be recovered.
     That means that if 64-bit ints are not supported, we will not
     be able to recover .bz2 files over 512MB (2^32 bits) long.
     On GNU supported platforms, we take advantage of the 64-bit
     int support to circumvent this problem.  Ditto MSVC.
  
     This change occurred in version 1.0.2; all prior versions have
     the 512MB limitation.
  */
  #ifdef __GNUC__
  typedef unsigned long long int MaybeUInt64;
  #  define MaybeUInt64_FMT "%Lu"
  #else
  #ifdef _MSC_VER
  typedef  unsigned __int64  MaybeUInt64;
  #  define MaybeUInt64_FMT "%I64u"
  #else
  typedef  unsigned int   MaybeUInt64;
  #  define MaybeUInt64_FMT "%u"
  #endif
  #endif
  
  typedef unsigned int UInt32;
  typedef int Int32;
  typedef unsigned char UChar;
  typedef char Char;
  typedef unsigned char Bool;
  #define True    ((Bool)1)
  #define False   ((Bool)0)
  
  
  #define BZ_MAX_FILENAME 2000
  
  Char inFileName[BZ_MAX_FILENAME];
  Char outFileName[BZ_MAX_FILENAME];
  Char progName[BZ_MAX_FILENAME];
  
  MaybeUInt64 bytesOut = 0;
  MaybeUInt64 bytesIn = 0;
  
  
  /*---------------------------------------------------*/
  /*--- Header bytes                                ---*/
  /*---------------------------------------------------*/
  
  #define BZ_HDR_B 0x42                         /* 'B' */
  #define BZ_HDR_Z 0x5a                         /* 'Z' */
  #define BZ_HDR_h 0x68                         /* 'h' */
  #define BZ_HDR_0 0x30                         /* '0' */
  
  
  /*---------------------------------------------------*/
  /*--- I/O errors                                  ---*/
  /*---------------------------------------------------*/
  
  /*---------------------------------------------*/
  static 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);
  }
  
  
  /*---------------------------------------------*/
  static 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);
  }
  
  
  /*---------------------------------------------*/
  static 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);
  }
  
  
  /*---------------------------------------------*/
  static void tooManyBlocks(Int32 max_handled_blocks) {
      fprintf(stderr,
              "%s: `%s' appears to contain more than %d blocks\n",
              progName, inFileName, max_handled_blocks);
      fprintf(stderr,
              "%s: and cannot be handled.  To fix, increase\n",
              progName);
      fprintf(stderr,
              "%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n",
              progName);
      exit(1);
  }
  
  
  
  /*---------------------------------------------------*/
  /*--- Bit stream I/O                              ---*/
  /*---------------------------------------------------*/
  
  typedef
  struct {
      FILE *handle;
      Int32 buffer;
      Int32 buffLive;
      Char mode;
  }
          BitStream;
  
  
  /*---------------------------------------------*/
  static 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;
  }
  
  
  /*---------------------------------------------*/
  static 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;
  }
  
  
  /*---------------------------------------------*/
  static 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.
  --*/
  static 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);
      }
  }
  
  
  /*---------------------------------------------*/
  static 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);
  }
  
  
  /*---------------------------------------------*/
  static void bsPutUChar(BitStream *bs, UChar c) {
      Int32 i;
      for (i = 7; i >= 0; i--)
          bsPutBit(bs, (((UInt32) c) >> i) & 0x1);
  }
  
  
  /*---------------------------------------------*/
  static void bsPutUInt32(BitStream *bs, UInt32 c) {
      Int32 i;
  
      for (i = 31; i >= 0; i--)
          bsPutBit(bs, (c >> i) & 0x1);
  }
  
  
  /*---------------------------------------------*/
  static 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');
  }
  
  
  /*---------------------------------------------------*/
  /*---                                             ---*/
  /*---------------------------------------------------*/
  
  /* This logic isn't really right when it comes to Cygwin. */
  #ifdef _WIN32
  #  define  BZ_SPLIT_SYM  '\\'  /* path splitter on Windows platform */
  #else
  #  define  BZ_SPLIT_SYM  '/'   /* path splitter on Unix platform */
  #endif
  
  #define BLOCK_HEADER_HI  0x00003141UL
  #define BLOCK_HEADER_LO  0x59265359UL
  
  #define BLOCK_ENDMARK_HI 0x00001772UL
  #define BLOCK_ENDMARK_LO 0x45385090UL
  
  /* Increase if necessary.  However, a .bz2 file with > 50000 blocks
     would have an uncompressed size of at least 40GB, so the chances
     are low you'll need to up this.
  */
  #define BZ_MAX_HANDLED_BLOCKS 50000
  
  MaybeUInt64 bStart[BZ_MAX_HANDLED_BLOCKS];
  MaybeUInt64 bEnd[BZ_MAX_HANDLED_BLOCKS];
  MaybeUInt64 rbStart[BZ_MAX_HANDLED_BLOCKS];
  MaybeUInt64 rbEnd[BZ_MAX_HANDLED_BLOCKS];
  
  //Int32 main ( Int32 argc, Char** argv )
  //{
  //   FILE*       inFile;
  //   FILE*       outFile;
  //   BitStream*  bsIn, *bsWr;
  //   Int32       b, wrBlock, currBlock, rbCtr;
  //   MaybeUInt64 bitsRead;
  //
  //   UInt32      buffHi, buffLo, blockCRC;
  //   Char*       p;
  //
  //   strcpy ( progName, argv[0] );
  //   inFileName[0] = outFileName[0] = 0;
  //
  //   fprintf ( stderr,
  //             "bzip2recover 1.0.6: extracts blocks from damaged .bz2 files.\n" );
  //
  //   if (argc != 2) {
  //      fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
  //                        progName, progName );
  //      switch (sizeof(MaybeUInt64)) {
  //         case 8:
  //            fprintf(stderr,
  //                    "\trestrictions on size of recovered file: None\n");
  //            break;
  //         case 4:
  //            fprintf(stderr,
  //                    "\trestrictions on size of recovered file: 512 MB\n");
  //            fprintf(stderr,
  //                    "\tto circumvent, recompile with MaybeUInt64 as an\n"
  //                    "\tunsigned 64-bit int.\n");
  //            break;
  //         default:
  //            fprintf(stderr,
  //                    "\tsizeof(MaybeUInt64) is not 4 or 8 -- "
  //                    "configuration error.\n");
  //            break;
  //      }
  //      exit(1);
  //   }
  //
  //   if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) {
  //      fprintf ( stderr,
  //                "%s: supplied filename is suspiciously (>= %d chars) long.  Bye!\n",
  //                progName, (int)strlen(argv[1]) );
  //      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;
  //
  //   rbCtr = 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 " MaybeUInt64_FMT
  //                                 " to " MaybeUInt64_FMT " (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 &&
  //	     (bEnd[currBlock] - bStart[currBlock]) >= 130) {
  //            fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT
  //                              " to " MaybeUInt64_FMT "\n",
  //                      rbCtr+1,  bStart[currBlock], bEnd[currBlock] );
  //            rbStart[rbCtr] = bStart[currBlock];
  //            rbEnd[rbCtr] = bEnd[currBlock];
  //            rbCtr++;
  //         }
  //         if (currBlock >= BZ_MAX_HANDLED_BLOCKS)
  //            tooManyBlocks(BZ_MAX_HANDLED_BLOCKS);
  //         currBlock++;
  //
  //         bStart[currBlock] = bitsRead;
  //      }
  //   }
  //
  //   bsClose ( bsIn );
  //
  //   /*-- identified blocks run from 1 to rbCtr inclusive. --*/
  //
  //   if (rbCtr < 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 = 0;
  //   while (True) {
  //      b = bsGetBit(bsIn);
  //      if (b == 2) break;
  //      buffHi = (buffHi << 1) | (buffLo >> 31);
  //      buffLo = (buffLo << 1) | (b & 1);
  //      if (bitsRead == 47+rbStart[wrBlock])
  //         blockCRC = (buffHi << 16) | (buffLo >> 16);
  //
  //      if (outFile != NULL && bitsRead >= rbStart[wrBlock]
  //                          && bitsRead <= rbEnd[wrBlock]) {
  //         bsPutBit ( bsWr, b );
  //      }
  //
  //      bitsRead++;
  //
  //      if (bitsRead == rbEnd[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 >= rbCtr) break;
  //         wrBlock++;
  //      } else
  //      if (bitsRead == rbStart[wrBlock]) {
  //         /* Create the output file name, correctly handling leading paths.
  //            (31.10.2001 by Sergey E. Kusikov) */
  //         Char* split;
  //         Int32 ofs, k;
  //         for (k = 0; k < BZ_MAX_FILENAME; k++)
  //            outFileName[k] = 0;
  //         strcpy (outFileName, inFileName);
  //         split = strrchr (outFileName, BZ_SPLIT_SYM);
  //         if (split == NULL) {
  //            split = outFileName;
  //         } else {
  //            ++split;
  //	 }
  //	 /* Now split points to the start of the basename. */
  //         ofs  = split - outFileName;
  //         sprintf (split, "rec%5d", wrBlock+1);
  //         for (p = split; *p != 0; p++) if (*p == ' ') *p = '0';
  //         strcat (outFileName, inFileName + ofs);
  //
  //         if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
  //
  //         fprintf ( stderr, "   writing block %d to `%s' ...\n",
  //                           wrBlock+1, 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, BZ_HDR_B );
  //         bsPutUChar ( bsWr, BZ_HDR_Z );
  //         bsPutUChar ( bsWr, BZ_HDR_h );
  //         bsPutUChar ( bsWr, BZ_HDR_0 + 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 ---*/
  /*-----------------------------------------------------------*/
  