⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unrarlib.c

📁 RAR的解压缩算法
💻 C
📖 第 1 页 / 共 4 页
字号:
  BlockHead.DataSize = NewLhd.PackSize;

  if (BlockType != NewLhd.HeadType)
    BlockType = ALL_HEAD;

  if ((FILE_HEAD == BlockType) && (Size > 0))
  {
    ArcFileName = realloc (ArcFileName, NewLhd.NameSize + 1);
    fread (ArcFileName, 1, NewLhd.NameSize, inputfile);
    ArcFileName[NewLhd.NameSize] = 0;
#ifdef _DEBUG_LOG
    if (NewLhd.HeadCRC !=
        (UWORD) ~ CalcCRC32 (HeaderCRC, (UBYTE *) & ArcFileName[0],
                             NewLhd.NameSize))
    {
      debug_log ("file header broken");
    }
#endif
    Size += NewLhd.NameSize;
  }
  else
  {
    memcpy (&NewLhd, &SaveFileHead, sizeof (NewLhd));
    fseek (inputfile, CurBlockPos, SEEK_SET);
  }

  return Size;
}


int
ReadHeader (int BlockType)
{
  int Size = 0;
  unsigned char Header[64];
  switch (BlockType)
  {
  case MAIN_HEAD:
    Size = fread (Header, 1, SIZEOF_NEWMHD, inputfile);
    archiveheader.head_crc = (unsigned short) GetHeaderWord (0);
    archiveheader.head_type = GetHeaderByte (2);
    archiveheader.head_flags = (unsigned short) GetHeaderWord (3);
    archiveheader.head_size = (unsigned short) GetHeaderWord (5);
    archiveheader.reserved1 = (unsigned short) GetHeaderWord (7);
    archiveheader.reserved2 = GetHeaderDword (9);
    HeaderCRC = CalcCRC32 (0xFFFFFFFFL, &Header[2], SIZEOF_NEWMHD - 2);
    break;
  case FILE_HEAD:
    Size = fread (Header, 1, SIZEOF_NEWLHD, inputfile);
    NewLhd.HeadCRC = (unsigned short) GetHeaderWord (0);
    NewLhd.HeadType = GetHeaderByte (2);
    NewLhd.Flags = (unsigned short) GetHeaderWord (3);
    NewLhd.HeadSize = (unsigned short) GetHeaderWord (5);
    NewLhd.PackSize = GetHeaderDword (7);
    NewLhd.UnpSize = GetHeaderDword (11);
    NewLhd.HostOS = GetHeaderByte (15);
    NewLhd.FileCRC = GetHeaderDword (16);
    NewLhd.FileTime = GetHeaderDword (20);
    NewLhd.UnpVer = GetHeaderByte (24);
    NewLhd.Method = GetHeaderByte (25);
    NewLhd.NameSize = (unsigned short) GetHeaderWord (26);
    NewLhd.FileAttr = GetHeaderDword (28);
    HeaderCRC = CalcCRC32 (0xFFFFFFFFL, &Header[2], SIZEOF_NEWLHD - 2);
    break;

#ifdef _DEBUG_LOG
  case COMM_HEAD:              /* log errors in case of debug  */
    debug_log ("Comment headers not supported! "
               "Please create archives without comments.");
    break;
  case PROTECT_HEAD:
    debug_log ("Protected headers not supported!");
    break;
  case ALL_HEAD:
    debug_log ("ShortBlockHeader not supported!");
    break;
  default:
    debug_log ("Unknown//unsupported !");
#else
  default:                     /* else do nothing              */
    break;
#endif
  }
  return Size;
}


/* E X T R A C T   L O O P */

int
IsArchive (void)
{
  if (fread (&markheader, 1, sizeof (markheader), inputfile) !=
      sizeof (markheader))
    return 0;

  /* original RAR v2.0 header */
  /* FIXME: Endian */
  if (!(markheader.head_crc == 0x6152 && markheader.head_type == 0x72
        && markheader.head_flags == 0x1a21 && markheader.head_size == 0x0007))
  {
    fputs ("unknown archive type, only plain RAR 2.0 supported"
           "(normal and solid archives), "
           "SFX and Volumes are NOT supported!\n", stderr);

    return 0;
  }

  if (ReadHeader (MAIN_HEAD) != SIZEOF_NEWMHD)
    return 0;

  return 1;
}


bool
ExtrFile (void)
{
  bool ReturnCode = true;

  FileFound = false;            /* no file found by default     */

  /* open and identify archive                                              */
  if ((inputfile = fopen (ArcName, "r")) != NULL)
  {
    if (!IsArchive ())
    {
      debug_log ("Not a RAR file");
      fclose (inputfile);
      inputfile = NULL;
      return false;             /* error => exit!               */
    }
  }
  else
  {
    debug_log ("Error opening file.");
    return false;
  }


  if ((UnpMemory = malloc (UNP_MEMORY)) == NULL)
  {
    debug_log ("Can't allocate memory for decompression!");
    return false;
  }

  fseek (inputfile, archiveheader.head_size - SIZEOF_NEWMHD, SEEK_CUR);

  /* do while file is not extracted and there's no error                    */
  do
  {

    if (ReadBlock (FILE_HEAD | READSUBBLOCK) <= 0)  /* read name of the next  */
    {                           /* file within the RAR archive  */
      /*
       *
       * 21.11.2000  UnQ  There's a problem with some linux distros when a file
       *                  can not be found in an archive.
       *
       *    debug_log("Couldn't read next filename from archive (I/O error).");
       *
       */
      ReturnCode = false;
      break;                    /* error, file not found in     */
    }                           /* archive or I/O error         */
    if (BlockHead.HeadType == SUB_HEAD)
    {
      debug_log ("Sorry, sub-headers not supported.");
      ReturnCode = false;
      break;                    /* error => exit                */
    }

    FileFound = (stricomp (ArgName, ArcFileName) == 0);
    if (FileFound)
      /* file found! */
    {
      /* Allocate memory for the file. The default offset within
         the buffer is 0.  */
      temp_output_buffer = malloc (NewLhd.UnpSize);
      *temp_output_buffer_offset = 0;

      if (temp_output_buffer == NULL)
      {
        debug_log ("can't allocate memory for the file decompression");
        ReturnCode = false;
        break;                  /* error, can't extract file!   */
      }
    }

    /* in case of a solid archive, we need to decompress any single file till
     * we have found the one we are looking for. In case of normal archives
     * (recommended!!), we skip the files until we are sure that it is the
     * one we want.
     */
    if ((archiveheader.head_flags & 0x08) || FileFound)
    {
      if (NewLhd.UnpVer < 13 || NewLhd.UnpVer > UNP_VER)
      {
        char DebugMsg[64];
        snprintf (DebugMsg, sizeof DebugMsg,
                  "unknown compression method: %d", NewLhd.UnpVer);
        debug_log (DebugMsg);
        ReturnCode = false;
        break;                  /* error, can't extract file!   */
      }

      CurUnpRead = CurUnpWrite = 0;
      if ((*Password != 0) && (NewLhd.Flags & LHD_PASSWORD))
        Encryption = NewLhd.UnpVer;
      else
        Encryption = 0;
      if (Encryption)
        SetCryptKeys (Password);

      UnpPackedSize = NewLhd.PackSize;
      DestUnpSize = NewLhd.UnpSize;

      if (NewLhd.Method == 0x30)
      {
        UnstoreFile ();
      }
      else
      {
        Unpack (UnpMemory);
      }



#ifdef _DO_CRC32_CHECK          /* calculate CRC32              */
      if ((UBYTE *) temp_output_buffer != NULL)
      {
        if (NewLhd.FileCRC != ~CalcCRC32 (0xFFFFFFFFL,
                                          (UBYTE *) temp_output_buffer,
                                          NewLhd.UnpSize))
        {
          debug_log
            ("CRC32 error - file couldn't be decompressed correctly!");
          ReturnCode = false;
          break;                /* error, can't extract file! */
        }
      }
#endif

    }

    if (inputfile != NULL)
      fseek (inputfile, NextBlockPos, SEEK_SET);
  }
  while (stricomp (ArgName, ArcFileName) != 0); /* exit if file is extracted */

  /* free memory, clear password and close archive                          */
  free (UnpMemory);
  UnpMemory = NULL;
  if (inputfile != NULL)
  {
    fclose (inputfile);
    inputfile = NULL;
  }

  return ReturnCode;            /* file extracted successful!   */
}


/* G L O B A L   F U N C T I O N S  */
int
stricomp (char *Str1, char *Str2)
/* compare strings without regard of '\' and '/'                            */
{
  char S1[512], S2[512];
  char *chptr;

  strncpy (S1, Str1, sizeof (S1));
  strncpy (S2, Str2, sizeof (S2));

  while ((chptr = strchr (S1, '\\')) != NULL) /* ignore backslash             */
  {
    *chptr = '_';
  }

  while ((chptr = strchr (S2, '\\')) != NULL) /* ignore backslash             */
  {
    *chptr = '_';
  }

  while ((chptr = strchr (S1, '/')) != NULL)  /* ignore slash                 */
  {
    *chptr = '_';
  }

  while ((chptr = strchr (S2, '/')) != NULL)  /* ignore slash                 */
  {
    *chptr = '_';
  }

  return strcasecmp (S1, S2);
}

/*  U N P A C K   C O D E  */

/* *****************************
 * ** unpack stored RAR files **
 * *****************************/

bool
UnstoreFile (void)
{
  if ((long) (*temp_output_buffer_offset = UnpRead (temp_output_buffer,
                                                    NewLhd.UnpSize)) == -1)
  {
    debug_log ("Read error of stored file!");
    return false;
  }
  return true;
}



/* ****************************************
 * ** RAR decompression code starts here **
 * ****************************************/

#define NC 298                  /* alphabet = {0,1,2, .,NC - 1} */
#define DC 48
#define RC 28
#define BC 19
#define MC 257

enum
{
  CODE_HUFFMAN = 0,
  CODE_LZ = 1,
  CODE_LZ2 = 2,
  CODE_REPEATLZ = 3,
  CODE_CACHELZ = 4,
  CODE_STARTFILE = 5,
  CODE_ENDFILE = 6,
  CODE_ENDMM = 7,
  CODE_STARTMM = 8,
  CODE_MMDELTA = 9
};

struct AudioVariables
{
  int K1, K2, K3, K4, K5;
  int D1, D2, D3, D4;
  int LastDelta;
  unsigned int Dif[11];
  unsigned int ByteCount;
  int LastChar;
};


struct AudioVariables AudV[4];

#define GetBits()                                                 \
        BitField = ( ( ( (UDWORD)InBuf[InAddr]   << 16 ) |        \
                       ( (UWORD) InBuf[InAddr+1] <<  8 ) |        \
                       (         InBuf[InAddr+2]       ) )        \
                       >> (8-InBit) ) & 0xffff;


#define AddBits(Bits)                          \
        InAddr += ( InBit + (Bits) ) >> 3;     \
        InBit  =  ( InBit + (Bits) ) &  7;

static unsigned char *UnpBuf;
static unsigned int BitField;
static unsigned int Number;

unsigned char InBuf[8192];      /* input read buffer            */

unsigned char UnpOldTable[MC * 4];

unsigned int InAddr, InBit, ReadTop;

unsigned int LastDist, LastLength;
static unsigned int Length, Distance;

unsigned int OldDist[4], OldDistPtr;


struct LitDecode
{
  unsigned int MaxNum;
  unsigned int DecodeLen[16];
  unsigned int DecodePos[16];
  unsigned int DecodeNum[NC];
} LD;

struct DistDecode
{
  unsigned int MaxNum;
  unsigned int DecodeLen[16];
  unsigned int DecodePos[16];
  unsigned int DecodeNum[DC];
} DD;

struct RepDecode
{
  unsigned int MaxNum;
  unsigned int DecodeLen[16];
  unsigned int DecodePos[16];
  unsigned int DecodeNum[RC];
} RD;

struct MultDecode
{
  unsigned int MaxNum;
  unsigned int DecodeLen[16];
  unsigned int DecodePos[16];
  unsigned int DecodeNum[MC];
} MD[4];

struct BitDecode
{
  unsigned int MaxNum;
  unsigned int DecodeLen[16];
  unsigned int DecodePos[16];
  unsigned int DecodeNum[BC];
} BD;

static struct MultDecode *MDPtr[4] = { &MD[0], &MD[1], &MD[2], &MD[3] };

int UnpAudioBlock, UnpChannels, CurChannel, ChannelDelta;

struct Decode Decode_tmp;
struct Decode *
LitDecode2Decode (struct LitDecode *ld)
{
  Decode_tmp.MaxNum = ld->MaxNum;
  Decode_tmp.DecodeLen = ld->DecodeLen;
  Decode_tmp.DecodePos = ld->DecodePos;
  Decode_tmp.DecodeNum = ld->DecodeNum;
  return &Decode_tmp;
}
struct Decode *
DistDecode2Decode (struct DistDecode *ld)
{
  Decode_tmp.MaxNum = ld->MaxNum;
  Decode_tmp.DecodeLen = ld->DecodeLen;
  Decode_tmp.DecodePos = ld->DecodePos;
  Decode_tmp.DecodeNum = ld->DecodeNum;
  return &Decode_tmp;
}
struct Decode *
RepDecode2Decode (struct RepDecode *ld)
{
  Decode_tmp.MaxNum = ld->MaxNum;
  Decode_tmp.DecodeLen = ld->DecodeLen;
  Decode_tmp.DecodePos = ld->DecodePos;
  Decode_tmp.DecodeNum = ld->DecodeNum;
  return &Decode_tmp;
}
struct Decode *
MultDecode2Decode (struct MultDecode *ld)
{
  Decode_tmp.MaxNum = ld->MaxNum;
  Decode_tmp.DecodeLen = ld->DecodeLen;
  Decode_tmp.DecodePos = ld->DecodePos;
  Decode_tmp.DecodeNum = ld->DecodeNum;
  return &Decode_tmp;
}
struct Decode *
BitDecode2Decode (struct BitDecode *ld)
{
  Decode_tmp.MaxNum = ld->MaxNum;
  Decode_tmp.DecodeLen = ld->DecodeLen;
  Decode_tmp.DecodePos = ld->DecodePos;
  Decode_tmp.DecodeNum = ld->DecodeNum;
  return &Decode_tmp;
}

void
Decode2LitDecode (struct LitDecode *ld)
{
  ld->MaxNum = Decode_tmp.MaxNum;
}

void
Decode2DistDecode (struct DistDecode *ld)
{
  ld->MaxNum = Decode_tmp.MaxNum;
}

void
Decode2RepDecode (struct RepDecode *ld)
{
  ld->MaxNum = Decode_tmp.MaxNum;
}

void
Decode2MultDecode (struct MultDecode *ld)
{
  ld->MaxNum = Decode_tmp.MaxNum;
}

void
Decode2BitDecode (struct BitDecode *ld)
{
  ld->MaxNum = Decode_tmp.MaxNum;
}

void
Unpack (unsigned char *UnpAddr)
/* *** 38.3% of all CPU time is spent within this function!!!               */
{
  static unsigned char LDecode[] =
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32,
    40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224
  };
  static unsigned char LBits[] =
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3,
    3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
  };
  static int DDecode[] =
    { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384,
    512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288,
    16384, 24576, 32768U, 49152U, 65536, 98304, 131072, 196608,
    262144, 327680, 393216, 458752, 524288, 589824, 655360,
    720896, 786432, 851968, 917504, 983040
  };
  static unsigned char DBits[] =
    { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9,
    9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
  };
  static unsigned char SDDecode[] = { 0, 4, 8, 16, 32, 64, 128, 192 };
  static unsigned char SDBits[] = { 2, 2, 3, 4, 5, 6, 6, 6 };
  unsigned int Bits;

  /* UnpAddr is a pointer to the unpack buffer */
  UnpBuf = UnpAddr;
  UnpInitData ();
  UnpReadBuf (1);
  if (!(NewLhd.Flags & LHD_SOLID))
    ReadTables ();
  DestUnpSize--;

  while (DestUnpSize >= 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -