示例#1
0
文件: extract.cpp 项目: KastB/OpenCPN
EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
{
  Archive Arc(Cmd);
  if (!Arc.WOpen(ArcName))
    return EXTRACT_ARC_NEXT;

  if (!Arc.IsArchive(true))
  {
#ifndef GUI
    mprintf(St(MNotRAR),ArcName);
#endif
    if (CmpExt(ArcName,L"rar"))
      ErrHandler.SetErrorCode(RARX_WARNING);
    return EXTRACT_ARC_NEXT;
  }

  if (Arc.FailedHeaderDecryption) // Bad archive password.
    return EXTRACT_ARC_NEXT;

#ifndef SFX_MODULE
  if (Arc.Volume && !Arc.FirstVolume)
  {
    wchar FirstVolName[NM];
    VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),Arc.NewNumbering);

    // If several volume names from same volume set are specified
    // and current volume is not first in set and first volume is present
    // and specified too, let's skip the current volume.
    if (wcsicomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
        Cmd->ArcNames.Search(FirstVolName,false))
      return EXTRACT_ARC_NEXT;
  }
#endif

  int64 VolumeSetSize=0; // Total size of volumes after the current volume.

  if (Arc.Volume)
  {
    // Calculate the total size of all accessible volumes.
    // This size is necessary to display the correct total progress indicator.

    wchar NextName[NM];
    wcscpy(NextName,Arc.FileName);

    while (true)
    {
      // First volume is already added to DataIO.TotalArcSize 
      // in initial TotalArcSize calculation in DoExtract.
      // So we skip it and start from second volume.
      NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
      FindData FD;
      if (FindFile::FastFind(NextName,&FD))
        VolumeSetSize+=FD.Size;
      else
        break;
    }
    DataIO.TotalArcSize+=VolumeSetSize;
  }

  ExtractArchiveInit(Arc);

  if (*Cmd->Command=='T' || *Cmd->Command=='I')
    Cmd->Test=true;


  if (*Cmd->Command=='I')
  {
#ifndef GUI   
    Cmd->DisablePercentage=true;
#endif
  }
  else
    uiStartArchiveExtract(!Cmd->Test,ArcName);

  Arc.ViewComment();


  while (1)
  {
    size_t Size=Arc.ReadHeader();


    bool Repeat=false;
    if (!ExtractCurrentFile(Arc,Size,Repeat))
    {
      if (Repeat)
      {
        // If we started extraction from not first volume and need to
        // restart it from first, we must correct DataIO.TotalArcSize
        // for correct total progress display. We subtract the size
        // of current volume and all volumes after it and add the size
        // of new (first) volume.
        FindData OldArc,NewArc;
        if (FindFile::FastFind(Arc.FileName,&OldArc) &&
            FindFile::FastFind(ArcName,&NewArc))
          DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
        return EXTRACT_ARC_REPEAT;
      }
      else
        break;
    }
  }


  return EXTRACT_ARC_NEXT;
}
示例#2
0
EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
{
  Archive Arc(Cmd);
  if (!Arc.WOpen(ArcName,ArcNameW))
  {
    ErrHandler.SetErrorCode(OPEN_ERROR);
    return(EXTRACT_ARC_NEXT);
  }

  if (!Arc.IsArchive(true))
  {
#ifndef GUI
    mprintf(St(MNotRAR),ArcName);
#endif
    if (CmpExt(ArcName,"rar"))
      ErrHandler.SetErrorCode(WARNING);
    return(EXTRACT_ARC_NEXT);
  }

  // archive with corrupt encrypted header can be closed in IsArchive() call
  if (!Arc.IsOpened())
    return(EXTRACT_ARC_NEXT);

#ifndef SFX_MODULE
  if (Arc.Volume && Arc.NotFirstVolume)
  {
    char FirstVolName[NM];
    VolNameToFirstName(ArcName,FirstVolName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0);

    // If several volume names from same volume set are specified
    // and current volume is not first in set and first volume is present
    // and specified too, let's skip the current volume.
    if (stricomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
        Cmd->ArcNames->Search(FirstVolName,NULL,false))
      return(EXTRACT_ARC_NEXT);
  }
#endif

  int64 VolumeSetSize=0; // Total size of volumes after the current volume.

  if (Arc.Volume)
  {
    // Calculate the total size of all accessible volumes.
    // This size is necessary to display the correct total progress indicator.

    char NextName[NM];
    wchar NextNameW[NM];

    strcpy(NextName,Arc.FileName);
    strcpyw(NextNameW,Arc.FileNameW);

    while (true)
    {
      // First volume is already added to DataIO.TotalArcSize 
      // in initial TotalArcSize calculation in DoExtract.
      // So we skip it and start from second volume.
      NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat);
      struct FindData FD;
      if (FindFile::FastFind(NextName,NextNameW,&FD))
        VolumeSetSize+=FD.Size;
      else
        break;
    }
    DataIO.TotalArcSize+=VolumeSetSize;
  }

  ExtractArchiveInit(Cmd,Arc);

  if (*Cmd->Command=='T' || *Cmd->Command=='I')
    Cmd->Test=true;

#ifndef GUI
  if (*Cmd->Command=='I')
    Cmd->DisablePercentage=true;
  else
    if (Cmd->Test)
      mprintf(St(MExtrTest),ArcName);
    else
      mprintf(St(MExtracting),ArcName);
#endif

  Arc.ViewComment();

  // RAR can close a corrupt encrypted archive
  if (!Arc.IsOpened())
    return(EXTRACT_ARC_NEXT);


  while (1)
  {
    size_t Size=Arc.ReadHeader();
    bool Repeat=false;
    if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
      if (Repeat)
      {
        // If we started extraction from not first volume and need to
        // restart it from first, we must correct DataIO.TotalArcSize
        // for correct total progress display. We subtract the size
        // of current volume and all volumes after it and add the size
        // of new (first) volume.
        struct FindData OldArc,NewArc;
        if (FindFile::FastFind(Arc.FileName,Arc.FileNameW,&OldArc) &&
            FindFile::FastFind(ArcName,ArcNameW,&NewArc))
          DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
        return(EXTRACT_ARC_REPEAT);
      }
      else
        break;
  }

  return(EXTRACT_ARC_NEXT);
}
示例#3
0
文件: recvol5.cpp 项目: 1ldk/mpc-hc
bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
{
  wchar ArcName[NM];
  wcscpy(ArcName,Name);

  wchar *Num=GetVolNumPart(ArcName);
  while (Num>ArcName && IsDigit(*(Num-1)))
    Num--;
  wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName));
  
  wchar FirstVolName[NM];
  *FirstVolName=0;

  int64 RecFileSize=0;

  FindFile VolFind;
  VolFind.SetMask(ArcName);
  FindData fd;
  uint FoundRecVolumes=0;
  while (VolFind.Next(&fd))
  {
    Wait();

    Archive *Vol=new Archive(Cmd);
    int ItemPos=-1;
    if (Vol->WOpen(fd.Name))
    {
      if (CmpExt(fd.Name,L"rev"))
      {
        uint RecNum=ReadHeader(Vol,FoundRecVolumes==0);
        if (RecNum!=0)
        {
          if (FoundRecVolumes==0)
            RecFileSize=Vol->FileLength();

          ItemPos=RecNum;
          FoundRecVolumes++;
        }
      }
      else
        if (Vol->IsArchive(true) && (Vol->SFXSize>0 || CmpExt(fd.Name,L"rar")))
        {
          if (!Vol->Volume && !Vol->BrokenHeader)
          {
            uiMsg(UIERROR_NOTVOLUME,ArcName);
            return false;
          }
          // We work with archive as with raw data file, so we do not want
          // to spend time to QOpen I/O redirection.
          Vol->QOpenUnload();
      
          Vol->Seek(0,SEEK_SET);

          // RAR volume found. Get its number, store the handle in appropriate
          // array slot, clean slots in between if we had to grow the array.
          wchar *Num=GetVolNumPart(fd.Name);
          uint VolNum=0;
          for (uint K=1;Num>=fd.Name && IsDigit(*Num);K*=10,Num--)
            VolNum+=(*Num-'0')*K;
          if (VolNum==0 || VolNum>MaxVolumes)
            continue;
          size_t CurSize=RecItems.Size();
          if (VolNum>CurSize)
          {
            RecItems.Alloc(VolNum);
            for (size_t I=CurSize;I<VolNum;I++)
              RecItems[I].f=NULL;
          }
          ItemPos=VolNum-1;

          if (*FirstVolName==0)
            VolNameToFirstName(fd.Name,FirstVolName,ASIZE(FirstVolName),true);
        }
    }
    if (ItemPos==-1)
      delete Vol; // Skip found file, it is not RAR or REV volume.
    else
      if ((uint)ItemPos<RecItems.Size()) // Check if found more REV than needed.
      {
        // Store found RAR or REV volume.
        RecVolItem *Item=RecItems+ItemPos;
        Item->f=Vol;
        Item->New=false;
        wcsncpyz(Item->Name,fd.Name,ASIZE(Item->Name));
      }
  }

  if (!Silent || FoundRecVolumes!=0)
    uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes);
  if (FoundRecVolumes==0)
    return false;

  uiMsg(UIMSG_RECVOLCALCCHECKSUM);

  MissingVolumes=0;
  for (uint I=0;I<TotalCount;I++)
  {
    RecVolItem *Item=&RecItems[I];
    if (Item->f!=NULL)
    {
      uiMsg(UIMSG_STRING,Item->Name);

      uint RevCRC;
      CalcFileSum(Item->f,&RevCRC,NULL,Cmd->Threads,INT64NDF,CALCFSUM_CURPOS);
      Item->Valid=RevCRC==Item->CRC;
      if (!Item->Valid)
      {
        uiMsg(UIMSG_CHECKSUM,Item->Name);

        // Close only corrupt REV volumes here. We'll close and rename corrupt
        // RAR volumes later, if we'll know that recovery is possible.
        if (I>=DataCount)
        {
          Item->f->Close();
          Item->f=NULL;
          FoundRecVolumes--;
        }
      }
    }
    if (I<DataCount && (Item->f==NULL || !Item->Valid))
      MissingVolumes++;
  }

  uiMsg(UIMSG_RECVOLMISSING,MissingVolumes);

  if (MissingVolumes==0)
  {
    uiMsg(UIERROR_RECVOLALLEXIST);
    return false;
  }

  if (MissingVolumes>FoundRecVolumes)
  {
    uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not displayed in console mode.
    uiMsg(UIERROR_RECVOLCANNOTFIX);
    return false;
  }

  uiMsg(UIMSG_RECONSTRUCTING);

  // Create missing and rename bad volumes.
  uint64 MaxVolSize=0;
  for (uint I=0;I<DataCount;I++)
  {
    RecVolItem *Item=&RecItems[I];
    if (Item->FileSize>MaxVolSize)
      MaxVolSize=Item->FileSize;
    if (Item->f!=NULL && !Item->Valid)
    {
      Item->f->Close();

      wchar NewName[NM];
      wcscpy(NewName,Item->Name);
      wcscat(NewName,L".bad");

      uiMsg(UIMSG_BADARCHIVE,Item->Name);
      uiMsg(UIMSG_RENAMING,Item->Name,NewName);
      RenameFile(Item->Name,NewName);
      delete Item->f;
      Item->f=NULL;
    }

    if (Item->New=(Item->f==NULL))
    {
      wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name));
      uiMsg(UIMSG_CREATING,Item->Name);
      uiMsg(UIEVENT_NEWARCHIVE,Item->Name);
      File *NewVol=new File;
      bool UserReject;
      if (!FileCreate(Cmd,NewVol,Item->Name,ASIZE(Item->Name),&UserReject))
      {
        if (!UserReject)
          ErrHandler.CreateErrorMsg(Item->Name);
        ErrHandler.Exit(UserReject ? RARX_USERBREAK:RARX_CREATE);
      }
      NewVol->Prealloc(Item->FileSize);
      Item->f=NewVol;
      Item->New=true;
    }
    NextVolumeName(FirstVolName,ASIZE(FirstVolName),false);
  }


  int64 ProcessedSize=0;
#ifndef GUI
  int LastPercent=-1;
  mprintf(L"     ");
#endif

  // Even though we already preliminary calculated missing volume number,
  // let's do it again now, when we have the final and exact information.
  MissingVolumes=0;

  ValidFlags=new bool[TotalCount];
  for (uint I=0;I<TotalCount;I++)
  {
    ValidFlags[I]=RecItems[I].f!=NULL && !RecItems[I].New;
    if (I<DataCount && !ValidFlags[I])
      MissingVolumes++;
  }

  // Size of per file buffer.
  RecBufferSize=TotalBufferSize/MissingVolumes;
  if ((RecBufferSize&1)==1) // Must be even for our RS16 codec.
    RecBufferSize--;
#ifdef USE_SSE
  RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE.
#endif

  uint *Data=new uint[TotalCount];

  RSCoder16 RS;
  if (!RS.Init(DataCount,RecCount,ValidFlags))
    return false; // Should not happen, we check parameter validity above.

  RealReadBuffer=new byte[RecBufferSize+SSE_ALIGNMENT];
  byte *ReadBuf=(byte *)ALIGN_VALUE(RealReadBuffer,SSE_ALIGNMENT);

  while (true)
  {
    Wait();

    int MaxRead=0;
    for (uint I=0,J=DataCount;I<DataCount;I++)
    {
      uint VolNum=I;
      if (!ValidFlags[I]) // If next RAR volume is missing or invalid.
      {
        while (!ValidFlags[J]) // Find next valid REV volume.
          J++;
        VolNum=J++; // Use next valid REV volume data instead of RAR.
      }
      RecVolItem *Item=RecItems+VolNum;

      byte *B=&ReadBuf[0];
      int ReadSize=0;
      if (Item->f!=NULL && !Item->New)
        ReadSize=Item->f->Read(B,RecBufferSize);
      if (ReadSize!=RecBufferSize)
        memset(B+ReadSize,0,RecBufferSize-ReadSize);
      if (ReadSize>MaxRead)
        MaxRead=ReadSize;

      // We can have volumes of different size. Let's use data chunk
      // for largest volume size.
      uint DataToProcess=(uint)Min(RecBufferSize,MaxVolSize-ProcessedSize);
      ProcessRS(Cmd,I,B,DataToProcess,false);
    }
    if (MaxRead==0)
      break;

    for (uint I=0,J=0;I<DataCount;I++)
      if (!ValidFlags[I])
      {
        RecVolItem *Item=RecItems+I;
        size_t WriteSize=(size_t)Min(MaxRead,Item->FileSize);
        Item->f->Write(Buf+(J++)*RecBufferSize,WriteSize);
        Item->FileSize-=WriteSize;
      }

    int CurPercent=ToPercent(ProcessedSize,RecFileSize);
    if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
    {
      uiProcessProgress("RV",ProcessedSize,RecFileSize);
      LastPercent=CurPercent;
    }
    ProcessedSize+=MaxRead;
  }

  for (uint I=0;I<TotalCount;I++)
    if (RecItems[I].f!=NULL)
      RecItems[I].f->Close();

  delete[] ValidFlags;
  delete[] Data;
#if !defined(GUI) && !defined(SILENT)
  if (!Cmd->DisablePercentage)
    mprintf(L"\b\b\b\b100%%");
  if (!Silent && !Cmd->DisableDone)
    mprintf(St(MDone));
#endif
  return true;
}
示例#4
0
EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
{
  Archive Arc(Cmd);
  if (!Arc.WOpen(ArcName,ArcNameW))
  {
    ErrHandler.SetErrorCode(OPEN_ERROR);
    return(EXTRACT_ARC_NEXT);
  }

  if (!Arc.IsArchive(true))
  {
#ifndef GUI
    mprintf(St(MNotRAR),ArcName);
#endif
    if (CmpExt(ArcName,"rar"))
      ErrHandler.SetErrorCode(WARNING);
    return(EXTRACT_ARC_NEXT);
  }

  if (!Arc.IsOpened())
    return(EXTRACT_ARC_NEXT);

#ifndef SFX_MODULE
  if (Arc.Volume && Arc.NotFirstVolume)
  {
    char FirstVolName[NM];

    VolNameToFirstName(ArcName,FirstVolName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING));
    if (stricomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
        Cmd->ArcNames->Search(FirstVolName,NULL,false))
      return(EXTRACT_ARC_NEXT);
  }
#endif
  ExtractArchiveInit(Cmd,Arc);

  if (*Cmd->Command=='T' || *Cmd->Command=='I')
    Cmd->Test=true;

#ifndef GUI
  if (*Cmd->Command=='I')
    Cmd->DisablePercentage=true;
  else
    if (Cmd->Test)
      mprintf(St(MExtrTest),ArcName);
    else
      mprintf(St(MExtracting),ArcName);
#endif

  Arc.ViewComment();

  while (1)
  {
    int Size=Arc.ReadHeader();
    bool Repeat=false;
    if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
      if (Repeat)
      {
        return(EXTRACT_ARC_REPEAT);
      }
      else
        break;
  }
  return(EXTRACT_ARC_NEXT);
}