"Fossies" - the Fresh Open Source Software Archive

Member "unrar/arcread.cpp" (4 May 2022, 47207 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "arcread.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "rar.hpp"
    2 
    3 size_t Archive::ReadHeader()
    4 {
    5   // Once we failed to decrypt an encrypted block, there is no reason to
    6   // attempt to do it further. We'll never be successful and only generate
    7   // endless errors.
    8   if (FailedHeaderDecryption)
    9     return 0;
   10 
   11   CurBlockPos=Tell();
   12 
   13   // Other developers asked us to initialize it to suppress "may be used
   14   // uninitialized" warning in code below in some compilers.
   15   size_t ReadSize=0;
   16 
   17   switch(Format)
   18   {
   19 #ifndef SFX_MODULE
   20     case RARFMT14:
   21       ReadSize=ReadHeader14();
   22       break;
   23 #endif
   24     case RARFMT15:
   25       ReadSize=ReadHeader15();
   26       break;
   27     case RARFMT50:
   28       ReadSize=ReadHeader50();
   29       break;
   30   }
   31 
   32   // It is important to check ReadSize>0 here, because it is normal
   33   // for RAR2 and RAR3 archives without end of archive block to have
   34   // NextBlockPos==CurBlockPos after the end of archive has reached.
   35   if (ReadSize>0 && NextBlockPos<=CurBlockPos)
   36   {
   37     BrokenHeaderMsg();
   38     ReadSize=0;
   39   }
   40 
   41   if (ReadSize==0)
   42     CurHeaderType=HEAD_UNKNOWN;
   43 
   44   return ReadSize;
   45 }
   46 
   47 
   48 size_t Archive::SearchBlock(HEADER_TYPE HeaderType)
   49 {
   50   size_t Size,Count=0;
   51   while ((Size=ReadHeader())!=0 &&
   52          (HeaderType==HEAD_ENDARC || GetHeaderType()!=HEAD_ENDARC))
   53   {
   54     if ((++Count & 127)==0)
   55       Wait();
   56     if (GetHeaderType()==HeaderType)
   57       return Size;
   58     SeekToNext();
   59   }
   60   return 0;
   61 }
   62 
   63 
   64 size_t Archive::SearchSubBlock(const wchar *Type)
   65 {
   66   size_t Size,Count=0;
   67   while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC)
   68   {
   69     if ((++Count & 127)==0)
   70       Wait();
   71     if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type))
   72       return Size;
   73     SeekToNext();
   74   }
   75   return 0;
   76 }
   77 
   78 
   79 size_t Archive::SearchRR()
   80 {
   81   // If locator extra field is available for recovery record, let's utilize it.
   82   if (MainHead.Locator && MainHead.RROffset!=0)
   83   {
   84     uint64 CurPos=Tell();
   85     Seek(MainHead.RROffset,SEEK_SET);
   86     size_t Size=ReadHeader();
   87     if (Size!=0 && !BrokenHeader && GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(SUBHEAD_TYPE_RR))
   88       return Size;
   89     Seek(CurPos,SEEK_SET);
   90   }
   91   // Otherwise scan the entire archive to find the recovery record.
   92   return SearchSubBlock(SUBHEAD_TYPE_RR);
   93 }
   94 
   95 
   96 void Archive::UnexpEndArcMsg()
   97 {
   98   int64 ArcSize=FileLength();
   99 
  100   // If block positions are equal to file size, this is not an error.
  101   // It can happen when we reached the end of older RAR 1.5 archive,
  102   // which did not have the end of archive block.
  103   if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize)
  104   {
  105     uiMsg(UIERROR_UNEXPEOF,FileName);
  106     ErrHandler.SetErrorCode(RARX_WARNING);
  107   }
  108 }
  109 
  110 
  111 void Archive::BrokenHeaderMsg()
  112 {
  113   uiMsg(UIERROR_HEADERBROKEN,FileName);
  114   BrokenHeader=true;
  115   ErrHandler.SetErrorCode(RARX_CRC);
  116 }
  117 
  118 
  119 void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
  120 {
  121   uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
  122   ErrHandler.SetErrorCode(RARX_WARNING);
  123 }
  124 
  125 
  126 // Return f in case of signed integer overflow or negative parameters
  127 // or v1+v2 otherwise. We use it for file offsets, which are signed
  128 // for compatibility with off_t in POSIX file functions and third party code.
  129 // Signed integer overflow is the undefined behavior according to
  130 // C++ standard and it causes fuzzers to complain.
  131 inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
  132 {
  133   return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f;
  134 }
  135 
  136 
  137 size_t Archive::ReadHeader15()
  138 {
  139   RawRead Raw(this);
  140 
  141   bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3;
  142 
  143   if (Decrypt)
  144   {
  145 #ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
  146     return 0;
  147 #else
  148     RequestArcPassword();
  149 
  150     byte Salt[SIZE_SALT30];
  151     if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
  152     {
  153       UnexpEndArcMsg();
  154       return 0;
  155     }
  156     HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL);
  157     Raw.SetCrypt(&HeadersCrypt);
  158 #endif
  159   }
  160 
  161   Raw.Read(SIZEOF_SHORTBLOCKHEAD);
  162   if (Raw.Size()==0)
  163   {
  164     UnexpEndArcMsg();
  165     return 0;
  166   }
  167 
  168   ShortBlock.HeadCRC=Raw.Get2();
  169 
  170   ShortBlock.Reset();
  171 
  172   uint HeaderType=Raw.Get1();
  173   ShortBlock.Flags=Raw.Get2();
  174   ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
  175   ShortBlock.HeadSize=Raw.Get2();
  176 
  177   ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
  178   if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
  179   {
  180     BrokenHeaderMsg();
  181     return 0;
  182   }
  183 
  184   // For simpler further processing we map header types common
  185   // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
  186   // header types specific for RAR 1.5 - 4.x only.
  187   switch(ShortBlock.HeaderType)
  188   {
  189     case HEAD3_MAIN:    ShortBlock.HeaderType=HEAD_MAIN;     break;
  190     case HEAD3_FILE:    ShortBlock.HeaderType=HEAD_FILE;     break;
  191     case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE;  break;
  192     case HEAD3_ENDARC:  ShortBlock.HeaderType=HEAD_ENDARC;   break;
  193   }
  194   CurHeaderType=ShortBlock.HeaderType;
  195 
  196   if (ShortBlock.HeaderType==HEAD3_CMT)
  197   {
  198     // Old style (up to RAR 2.9) comment header embedded into main
  199     // or file header. We must not read the entire ShortBlock.HeadSize here
  200     // to not break the comment processing logic later.
  201     Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
  202   }
  203   else
  204     if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
  205     {
  206       // Old style (up to RAR 2.9) main archive comment embedded into
  207       // the main archive header found. While we can read the entire
  208       // ShortBlock.HeadSize here and remove this part of "if", it would be
  209       // waste of memory, because we'll read and process this comment data
  210       // in other function anyway and we do not need them here now.
  211       Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
  212     }
  213     else
  214       Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
  215 
  216   NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
  217 
  218   switch(ShortBlock.HeaderType)
  219   {
  220     case HEAD_MAIN:
  221       MainHead.Reset();
  222       *(BaseBlock *)&MainHead=ShortBlock;
  223       MainHead.HighPosAV=Raw.Get2();
  224       MainHead.PosAV=Raw.Get4();
  225 
  226       Volume=(MainHead.Flags & MHD_VOLUME)!=0;
  227       Solid=(MainHead.Flags & MHD_SOLID)!=0;
  228       Locked=(MainHead.Flags & MHD_LOCK)!=0;
  229       Protected=(MainHead.Flags & MHD_PROTECT)!=0;
  230       Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
  231       Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
  232       MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
  233 
  234       // Only for encrypted 3.0+ archives. 2.x archives did not have this
  235       // flag, so for non-encrypted archives, we'll set it later based on
  236       // file attributes.
  237       FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0;
  238 
  239       NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0;
  240       break;
  241     case HEAD_FILE:
  242     case HEAD_SERVICE:
  243       {
  244         bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
  245         FileHeader *hd=FileBlock ? &FileHead:&SubHead;
  246         hd->Reset();
  247 
  248         *(BaseBlock *)hd=ShortBlock;
  249 
  250         hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
  251         hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
  252         hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
  253         hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
  254         hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
  255         hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
  256         hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
  257         hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
  258         hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
  259         hd->Version=(hd->Flags & LHD_VERSION)!=0;
  260 
  261         hd->DataSize=Raw.Get4();
  262         uint LowUnpSize=Raw.Get4();
  263         hd->HostOS=Raw.Get1();
  264 
  265         hd->FileHash.Type=HASH_CRC32;
  266         hd->FileHash.CRC32=Raw.Get4();
  267 
  268         uint FileTime=Raw.Get4();
  269         hd->UnpVer=Raw.Get1();
  270 
  271         hd->Method=Raw.Get1()-0x30;
  272         size_t NameSize=Raw.Get2();
  273         hd->FileAttr=Raw.Get4();
  274 
  275         // RAR15 did not use the special dictionary size to mark dirs.
  276         if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
  277           hd->Dir=true;
  278 
  279         hd->CryptMethod=CRYPT_NONE;
  280         if (hd->Encrypted)
  281           switch(hd->UnpVer)
  282           {
  283             case 13: hd->CryptMethod=CRYPT_RAR13; break;
  284             case 15: hd->CryptMethod=CRYPT_RAR15; break;
  285             case 20:
  286             case 26: hd->CryptMethod=CRYPT_RAR20; break;
  287             default: hd->CryptMethod=CRYPT_RAR30; break;
  288           }
  289 
  290         hd->HSType=HSYS_UNKNOWN;
  291         if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
  292           hd->HSType=HSYS_UNIX;
  293         else
  294           if (hd->HostOS<HOST_MAX)
  295             hd->HSType=HSYS_WINDOWS;
  296 
  297         hd->RedirType=FSREDIR_NONE;
  298 
  299         // RAR 4.x Unix symlink.
  300         if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
  301         {
  302           hd->RedirType=FSREDIR_UNIXSYMLINK;
  303           *hd->RedirName=0;
  304         }
  305 
  306         hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
  307 
  308         hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
  309 
  310         uint HighPackSize,HighUnpSize;
  311         if (hd->LargeFile)
  312         {
  313           HighPackSize=Raw.Get4();
  314           HighUnpSize=Raw.Get4();
  315           hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
  316         }
  317         else
  318         {
  319           HighPackSize=HighUnpSize=0;
  320           // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
  321           // that we do not know the unpacked file size and must unpack it
  322           // until we find the end of file marker in compressed data.
  323           hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
  324         }
  325         hd->PackSize=INT32TO64(HighPackSize,hd->DataSize);
  326         hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize);
  327         if (hd->UnknownUnpSize)
  328           hd->UnpSize=INT64NDF;
  329 
  330         char FileName[NM*4];
  331         size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
  332         Raw.GetB((byte *)FileName,ReadNameSize);
  333         FileName[ReadNameSize]=0;
  334 
  335         if (FileBlock)
  336         {
  337           *hd->FileName=0;
  338           if ((hd->Flags & LHD_UNICODE)!=0)
  339           {
  340             EncodeFileName NameCoder;
  341             size_t Length=strlen(FileName);
  342             Length++;
  343             if (ReadNameSize>Length)
  344               NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length,
  345                                ReadNameSize-Length,hd->FileName,
  346                                ASIZE(hd->FileName));
  347           }
  348 
  349           if (*hd->FileName==0)
  350             ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM);
  351 
  352 #ifndef SFX_MODULE
  353           ConvertNameCase(hd->FileName);
  354 #endif
  355           ConvertFileHeader(hd);
  356         }
  357         else
  358         {
  359           CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
  360 
  361           // Calculate the size of optional data.
  362           int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
  363           if ((hd->Flags & LHD_SALT)!=0)
  364             DataSize-=SIZE_SALT30;
  365 
  366           if (DataSize>0)
  367           {
  368             // Here we read optional additional fields for subheaders.
  369             // They are stored after the file name and before salt.
  370             hd->SubData.Alloc(DataSize);
  371             Raw.GetB(&hd->SubData[0],DataSize);
  372 
  373           }
  374 
  375           if (hd->CmpName(SUBHEAD_TYPE_CMT))
  376             MainComment=true;
  377         }
  378         if ((hd->Flags & LHD_SALT)!=0)
  379           Raw.GetB(hd->Salt,SIZE_SALT30);
  380         hd->mtime.SetDos(FileTime);
  381         if ((hd->Flags & LHD_EXTTIME)!=0)
  382         {
  383           ushort Flags=Raw.Get2();
  384           RarTime *tbl[4];
  385           tbl[0]=&FileHead.mtime;
  386           tbl[1]=&FileHead.ctime;
  387           tbl[2]=&FileHead.atime;
  388           tbl[3]=NULL; // Archive time is not used now.
  389           for (int I=0;I<4;I++)
  390           {
  391             RarTime *CurTime=tbl[I];
  392             uint rmode=Flags>>(3-I)*4;
  393             if ((rmode & 8)==0 || CurTime==NULL)
  394               continue;
  395             if (I!=0)
  396             {
  397               uint DosTime=Raw.Get4();
  398               CurTime->SetDos(DosTime);
  399             }
  400             RarLocalTime rlt;
  401             CurTime->GetLocal(&rlt);
  402             if (rmode & 4)
  403               rlt.Second++;
  404             rlt.Reminder=0;
  405             uint count=rmode&3;
  406             for (uint J=0;J<count;J++)
  407             {
  408               byte CurByte=Raw.Get1();
  409               rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
  410             }
  411             // Convert from 100ns RAR precision to REMINDER_PRECISION.
  412             rlt.Reminder*=RarTime::REMINDER_PRECISION/10000000;
  413             CurTime->SetLocal(&rlt);
  414           }
  415         }
  416         // Set to 0 in case of overflow, so end of ReadHeader cares about it.
  417         NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
  418 
  419         bool CRCProcessedOnly=hd->CommentInHeader;
  420         ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
  421         if (hd->HeadCRC!=HeaderCRC)
  422         {
  423           BrokenHeader=true;
  424           ErrHandler.SetErrorCode(RARX_WARNING);
  425 
  426           // If we have a broken encrypted header, we do not need to display
  427           // the error message here, because it will be displayed for such
  428           // headers later in this function. Also such headers are unlikely
  429           // to have anything sensible in file name field, so it is useless
  430           // to display the file name.
  431           if (!Decrypt)
  432             uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
  433         }
  434       }
  435       break;
  436     case HEAD_ENDARC:
  437       *(BaseBlock *)&EndArcHead=ShortBlock;
  438       EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
  439       EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
  440       EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
  441       EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
  442       if (EndArcHead.DataCRC)
  443         EndArcHead.ArcDataCRC=Raw.Get4();
  444       if (EndArcHead.StoreVolNumber)
  445         VolNumber=EndArcHead.VolNumber=Raw.Get2();
  446       break;
  447 #ifndef SFX_MODULE
  448     case HEAD3_CMT:
  449       *(BaseBlock *)&CommHead=ShortBlock;
  450       CommHead.UnpSize=Raw.Get2();
  451       CommHead.UnpVer=Raw.Get1();
  452       CommHead.Method=Raw.Get1();
  453       CommHead.CommCRC=Raw.Get2();
  454       break;
  455     case HEAD3_PROTECT:
  456       *(BaseBlock *)&ProtectHead=ShortBlock;
  457       ProtectHead.DataSize=Raw.Get4();
  458       ProtectHead.Version=Raw.Get1();
  459       ProtectHead.RecSectors=Raw.Get2();
  460       ProtectHead.TotalBlocks=Raw.Get4();
  461       Raw.GetB(ProtectHead.Mark,8);
  462       NextBlockPos+=ProtectHead.DataSize;
  463       break;
  464     case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
  465       *(BaseBlock *)&SubBlockHead=ShortBlock;
  466       SubBlockHead.DataSize=Raw.Get4();
  467       NextBlockPos+=SubBlockHead.DataSize;
  468       SubBlockHead.SubType=Raw.Get2();
  469       SubBlockHead.Level=Raw.Get1();
  470       switch(SubBlockHead.SubType)
  471       {
  472         case UO_HEAD:
  473           *(SubBlockHeader *)&UOHead=SubBlockHead;
  474           UOHead.OwnerNameSize=Raw.Get2();
  475           UOHead.GroupNameSize=Raw.Get2();
  476           if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName))
  477             UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1;
  478           if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName))
  479             UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1;
  480           Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize);
  481           Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize);
  482           UOHead.OwnerName[UOHead.OwnerNameSize]=0;
  483           UOHead.GroupName[UOHead.GroupNameSize]=0;
  484           break;
  485         case NTACL_HEAD:
  486           *(SubBlockHeader *)&EAHead=SubBlockHead;
  487           EAHead.UnpSize=Raw.Get4();
  488           EAHead.UnpVer=Raw.Get1();
  489           EAHead.Method=Raw.Get1();
  490           EAHead.EACRC=Raw.Get4();
  491           break;
  492         case STREAM_HEAD:
  493           *(SubBlockHeader *)&StreamHead=SubBlockHead;
  494           StreamHead.UnpSize=Raw.Get4();
  495           StreamHead.UnpVer=Raw.Get1();
  496           StreamHead.Method=Raw.Get1();
  497           StreamHead.StreamCRC=Raw.Get4();
  498           StreamHead.StreamNameSize=Raw.Get2();
  499           if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName))
  500             StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1;
  501           Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize);
  502           StreamHead.StreamName[StreamHead.StreamNameSize]=0;
  503           break;
  504       }
  505       break;
  506 #endif
  507     default:
  508       if (ShortBlock.Flags & LONG_BLOCK)
  509         NextBlockPos+=Raw.Get4();
  510       break;
  511   }
  512 
  513   ushort HeaderCRC=Raw.GetCRC15(false);
  514 
  515   // Old AV header does not have header CRC properly set.
  516   if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
  517       ShortBlock.HeaderType!=HEAD3_AV)
  518   {
  519     bool Recovered=false;
  520     if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace)
  521     {
  522       // Last 7 bytes of recovered volume can contain zeroes, because
  523       // REV files store its own information (volume number, etc.) here.
  524       int64 Length=Tell();
  525       Seek(Length-7,SEEK_SET);
  526       Recovered=true;
  527       for (int J=0;J<7;J++)
  528         if (GetByte()!=0)
  529           Recovered=false;
  530     }
  531     if (!Recovered)
  532     {
  533       BrokenHeader=true;
  534       ErrHandler.SetErrorCode(RARX_CRC);
  535 
  536       if (Decrypt)
  537       {
  538         uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
  539         FailedHeaderDecryption=true;
  540         return 0;
  541       }
  542     }
  543   }
  544 
  545   return Raw.Size();
  546 }
  547 
  548 
  549 size_t Archive::ReadHeader50()
  550 {
  551   RawRead Raw(this);
  552 
  553   bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5;
  554 
  555   if (Decrypt)
  556   {
  557 #if defined(RAR_NOCRYPT)
  558     return 0;
  559 #else
  560 
  561     if (Cmd->SkipEncrypted)
  562     {
  563       uiMsg(UIMSG_SKIPENCARC,FileName);
  564       FailedHeaderDecryption=true; // Suppress error messages and quit quietly.
  565       return 0;
  566     }
  567 
  568     byte HeadersInitV[SIZE_INITV];
  569     if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
  570     {
  571       UnexpEndArcMsg();
  572       return 0;
  573     }
  574 
  575     // We repeat the password request only for manually entered passwords
  576     // and not for -p<pwd>. Wrong password can be intentionally provided
  577     // in -p<pwd> to not stop batch processing for encrypted archives.
  578     bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
  579 
  580     while (true) // Repeat the password prompt for wrong passwords.
  581     {
  582       RequestArcPassword();
  583 
  584       byte PswCheck[SIZE_PSWCHECK];
  585       HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
  586       // Verify password validity.
  587       if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
  588       {
  589         if (GlobalPassword) // For -p<pwd> or Ctrl+P.
  590         {
  591           // This message is used by Android GUI to reset cached passwords.
  592           // Update appropriate code if changed.
  593           uiMsg(UIERROR_BADPSW,FileName,FileName);
  594           FailedHeaderDecryption=true;
  595           ErrHandler.SetErrorCode(RARX_BADPWD);
  596           return 0;
  597         }
  598         else // For passwords entered manually.
  599         {
  600           // This message is used by Android GUI and Windows GUI and SFX to
  601           // reset cached passwords. Update appropriate code if changed.
  602           uiMsg(UIWAIT_BADPSW,FileName,FileName);
  603           Cmd->Password.Clean();
  604         }
  605 
  606 #ifdef RARDLL
  607         // Avoid new requests for unrar.dll to prevent the infinite loop
  608         // if app always returns the same password.
  609         ErrHandler.SetErrorCode(RARX_BADPWD);
  610         Cmd->DllError=ERAR_BAD_PASSWORD;
  611         ErrHandler.Exit(RARX_BADPWD);
  612 #else
  613         continue; // Request a password again.
  614 #endif
  615       }
  616       break;
  617     }
  618 
  619     Raw.SetCrypt(&HeadersCrypt);
  620 #endif
  621   }
  622 
  623   // Header size must not occupy more than 3 variable length integer bytes
  624   // resulting in 2 MB maximum header size (MAX_HEADER_SIZE_RAR5),
  625   // so here we read 4 byte CRC32 followed by 3 bytes or less of header size.
  626   const size_t FirstReadSize=7; // Smallest possible block size.
  627   if (Raw.Read(FirstReadSize)<FirstReadSize)
  628   {
  629     UnexpEndArcMsg();
  630     return 0;
  631   }
  632 
  633   ShortBlock.Reset();
  634   ShortBlock.HeadCRC=Raw.Get4();
  635   uint SizeBytes=Raw.GetVSize(4);
  636   uint64 BlockSize=Raw.GetV();
  637 
  638   if (BlockSize==0 || SizeBytes==0)
  639   {
  640     BrokenHeaderMsg();
  641     return 0;
  642   }
  643 
  644   int SizeToRead=int(BlockSize);
  645   SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
  646   uint HeaderSize=4+SizeBytes+(uint)BlockSize;
  647 
  648   if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
  649   {
  650     BrokenHeaderMsg();
  651     return 0;
  652   }
  653 
  654   Raw.Read(SizeToRead);
  655 
  656   if (Raw.Size()<HeaderSize)
  657   {
  658     UnexpEndArcMsg();
  659     return 0;
  660   }
  661 
  662   uint HeaderCRC=Raw.GetCRC50();
  663 
  664   ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
  665   ShortBlock.Flags=(uint)Raw.GetV();
  666   ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
  667   ShortBlock.HeadSize=HeaderSize;
  668 
  669   CurHeaderType=ShortBlock.HeaderType;
  670 
  671   bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
  672   if (BadCRC)
  673   {
  674     BrokenHeaderMsg(); // Report, but attempt to process.
  675 
  676     BrokenHeader=true;
  677     ErrHandler.SetErrorCode(RARX_CRC);
  678 
  679     if (Decrypt)
  680     {
  681       uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
  682       FailedHeaderDecryption=true;
  683       return 0;
  684     }
  685   }
  686 
  687   uint64 ExtraSize=0;
  688   if ((ShortBlock.Flags & HFL_EXTRA)!=0)
  689   {
  690     ExtraSize=Raw.GetV();
  691     if (ExtraSize>=ShortBlock.HeadSize)
  692     {
  693       BrokenHeaderMsg();
  694       return 0;
  695     }
  696   }
  697 
  698   uint64 DataSize=0;
  699   if ((ShortBlock.Flags & HFL_DATA)!=0)
  700     DataSize=Raw.GetV();
  701 
  702   NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
  703   // Set to 0 in case of overflow, so end of ReadHeader cares about it.
  704   NextBlockPos=SafeAdd(NextBlockPos,DataSize,0);
  705 
  706   switch(ShortBlock.HeaderType)
  707   {
  708     case HEAD_CRYPT:
  709       {
  710         *(BaseBlock *)&CryptHead=ShortBlock;
  711         uint CryptVersion=(uint)Raw.GetV();
  712         if (CryptVersion>CRYPT_VERSION)
  713         {
  714           wchar Info[20];
  715           swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
  716           UnkEncVerMsg(FileName,Info);
  717           return 0;
  718         }
  719         uint EncFlags=(uint)Raw.GetV();
  720         CryptHead.UsePswCheck=(EncFlags & CHFL_CRYPT_PSWCHECK)!=0;
  721         CryptHead.Lg2Count=Raw.Get1();
  722         if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
  723         {
  724           wchar Info[20];
  725           swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
  726           UnkEncVerMsg(FileName,Info);
  727           return 0;
  728         }
  729 
  730         Raw.GetB(CryptHead.Salt,SIZE_SALT50);
  731         if (CryptHead.UsePswCheck)
  732         {
  733           Raw.GetB(CryptHead.PswCheck,SIZE_PSWCHECK);
  734 
  735           byte csum[SIZE_PSWCHECK_CSUM];
  736           Raw.GetB(csum,SIZE_PSWCHECK_CSUM);
  737 
  738           sha256_context ctx;
  739           sha256_init(&ctx);
  740           sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK);
  741 
  742           byte Digest[SHA256_DIGEST_SIZE];
  743           sha256_done(&ctx, Digest);
  744 
  745           CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
  746         }
  747         Encrypted=true;
  748       }
  749       break;
  750     case HEAD_MAIN:
  751       {
  752         MainHead.Reset();
  753         *(BaseBlock *)&MainHead=ShortBlock;
  754         uint ArcFlags=(uint)Raw.GetV();
  755 
  756         Volume=(ArcFlags & MHFL_VOLUME)!=0;
  757         Solid=(ArcFlags & MHFL_SOLID)!=0;
  758         Locked=(ArcFlags & MHFL_LOCK)!=0;
  759         Protected=(ArcFlags & MHFL_PROTECT)!=0;
  760         Signed=false;
  761         NewNumbering=true;
  762 
  763         if ((ArcFlags & MHFL_VOLNUMBER)!=0)
  764           VolNumber=(uint)Raw.GetV();
  765         else
  766           VolNumber=0;
  767         FirstVolume=Volume && VolNumber==0;
  768 
  769         if (ExtraSize!=0)
  770           ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
  771 
  772 #ifdef USE_QOPEN
  773         if (!ProhibitQOpen && MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
  774         {
  775           // We seek to QO block in the end of archive when processing
  776           // QOpen.Load, so we need to preserve current block positions
  777           // to not break normal archive processing by calling function.
  778           int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
  779           HEADER_TYPE SaveCurHeaderType=CurHeaderType;
  780 
  781           QOpen.Init(this,false);
  782           QOpen.Load(MainHead.QOpenOffset);
  783 
  784           CurBlockPos=SaveCurBlockPos;
  785           NextBlockPos=SaveNextBlockPos;
  786           CurHeaderType=SaveCurHeaderType;
  787         }
  788 #endif
  789       }
  790       break;
  791     case HEAD_FILE:
  792     case HEAD_SERVICE:
  793       {
  794         FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
  795         hd->Reset(); // Clear hash, time fields and other stuff like flags.
  796         *(BaseBlock *)hd=ShortBlock;
  797 
  798         bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
  799 
  800         hd->LargeFile=true;
  801 
  802         hd->PackSize=DataSize;
  803         hd->FileFlags=(uint)Raw.GetV();
  804         hd->UnpSize=Raw.GetV();
  805 
  806         hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
  807         if (hd->UnknownUnpSize)
  808           hd->UnpSize=INT64NDF;
  809 
  810         hd->MaxSize=Max(hd->PackSize,hd->UnpSize);
  811         hd->FileAttr=(uint)Raw.GetV();
  812         if ((hd->FileFlags & FHFL_UTIME)!=0)
  813           hd->mtime.SetUnix((time_t)Raw.Get4());
  814 
  815         hd->FileHash.Type=HASH_NONE;
  816         if ((hd->FileFlags & FHFL_CRC32)!=0)
  817         {
  818           hd->FileHash.Type=HASH_CRC32;
  819           hd->FileHash.CRC32=Raw.Get4();
  820         }
  821 
  822         hd->RedirType=FSREDIR_NONE;
  823 
  824         uint CompInfo=(uint)Raw.GetV();
  825         hd->Method=(CompInfo>>7) & 7;
  826 
  827         // "+ 50" to not mix with old RAR format algorithms. For example,
  828         // we may need to use the compression algorithm 15 in the future,
  829         // but it was already used in RAR 1.5 and Unpack needs to distinguish
  830         // them.
  831         hd->UnpVer=(CompInfo & 0x3f) + 50;
  832         if (hd->UnpVer!=50) // Only 5.0 compression is known now.
  833           hd->UnpVer=VER_UNKNOWN;
  834 
  835         hd->HostOS=(byte)Raw.GetV();
  836         size_t NameSize=(size_t)Raw.GetV();
  837         hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0;
  838 
  839         hd->HSType=HSYS_UNKNOWN;
  840         if (hd->HostOS==HOST5_UNIX)
  841           hd->HSType=HSYS_UNIX;
  842         else
  843           if (hd->HostOS==HOST5_WINDOWS)
  844             hd->HSType=HSYS_WINDOWS;
  845 
  846         hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0;
  847         hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0;
  848         hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
  849         hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
  850         hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
  851         hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
  852 
  853         hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
  854 
  855         char FileName[NM*4];
  856         size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
  857         Raw.GetB((byte *)FileName,ReadNameSize);
  858         FileName[ReadNameSize]=0;
  859 
  860         UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName));
  861 
  862         // Should do it before converting names, because extra fields can
  863         // affect name processing, like in case of NTFS streams.
  864         if (ExtraSize!=0)
  865           ProcessExtra50(&Raw,(size_t)ExtraSize,hd);
  866 
  867         if (FileBlock)
  868         {
  869 #ifndef SFX_MODULE
  870           ConvertNameCase(hd->FileName);
  871 #endif
  872           ConvertFileHeader(hd);
  873         }
  874 
  875         if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
  876           MainComment=true;
  877 
  878 #if 0
  879         // For RAR5 format we read the user specified recovery percent here.
  880         // It would be useful to do it for shell extension too, so we display
  881         // the correct recovery record size in archive properties. But then
  882         // we would need to include the entire recovery record processing
  883         // code to shell extension, which is not done now.
  884         if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0)
  885         {
  886           // It is stored as a single byte up to RAR 6.02 and as vint since
  887           // 6.10, where we extended the maximum RR size from 99% to 1000%.
  888           RawRead RawPercent;
  889           RawPercent.Read(&hd->SubData[0],hd->SubData.Size());
  890           RecoveryPercent=(int)RawPercent.GetV();
  891 
  892           RSBlockHeader Header;
  893           GetRRInfo(this,&Header);
  894           RecoverySize=Header.RecSectionSize*Header.RecCount;
  895         }
  896 #endif
  897 
  898         if (BadCRC) // Add the file name to broken header message displayed above.
  899           uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
  900       }
  901       break;
  902     case HEAD_ENDARC:
  903       {
  904         *(BaseBlock *)&EndArcHead=ShortBlock;
  905         uint ArcFlags=(uint)Raw.GetV();
  906         EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
  907         EndArcHead.StoreVolNumber=false;
  908         EndArcHead.DataCRC=false;
  909         EndArcHead.RevSpace=false;
  910       }
  911       break;
  912   }
  913 
  914   return Raw.Size();
  915 }
  916 
  917 
  918 #if !defined(RAR_NOCRYPT)
  919 void Archive::RequestArcPassword()
  920 {
  921   if (!Cmd->Password.IsSet())
  922   {
  923 #ifdef RARDLL
  924     if (Cmd->Callback!=NULL)
  925     {
  926       wchar PasswordW[MAXPASSWORD];
  927       *PasswordW=0;
  928       if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
  929         *PasswordW=0;
  930       if (*PasswordW==0)
  931       {
  932         char PasswordA[MAXPASSWORD];
  933         *PasswordA=0;
  934         if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
  935           *PasswordA=0;
  936         GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
  937         cleandata(PasswordA,sizeof(PasswordA));
  938       }
  939       Cmd->Password.Set(PasswordW);
  940       cleandata(PasswordW,sizeof(PasswordW));
  941     }
  942     if (!Cmd->Password.IsSet())
  943     {
  944       Close();
  945       Cmd->DllError=ERAR_MISSING_PASSWORD;
  946       ErrHandler.Exit(RARX_USERBREAK);
  947     }
  948 #else
  949     if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password))
  950     {
  951       Close();
  952       uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
  953       ErrHandler.Exit(RARX_USERBREAK);
  954     }
  955 #endif
  956     Cmd->ManualPassword=true;
  957   }
  958 }
  959 #endif
  960 
  961 
  962 void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
  963 {
  964   // Read extra data from the end of block skipping any fields before it.
  965   size_t ExtraStart=Raw->Size()-ExtraSize;
  966   if (ExtraStart<Raw->GetPos())
  967     return;
  968   Raw->SetPos(ExtraStart);
  969   while (Raw->DataLeft()>=2)
  970   {
  971     int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative.
  972     if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
  973       break;
  974     size_t NextPos=size_t(Raw->GetPos()+FieldSize);
  975     uint64 FieldType=Raw->GetV();
  976 
  977     FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields.
  978 
  979     if (FieldSize<0) // FieldType is longer than expected extra field size.
  980       break;
  981 
  982     if (bb->HeaderType==HEAD_MAIN)
  983     {
  984       MainHeader *hd=(MainHeader *)bb;
  985       if (FieldType==MHEXTRA_LOCATOR)
  986       {
  987         hd->Locator=true;
  988         uint Flags=(uint)Raw->GetV();
  989         if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
  990         {
  991           uint64 Offset=Raw->GetV();
  992           if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
  993             hd->QOpenOffset=Offset+CurBlockPos;
  994         }
  995         if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
  996         {
  997           uint64 Offset=Raw->GetV();
  998           if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
  999             hd->RROffset=Offset+CurBlockPos;
 1000         }
 1001       }
 1002     }
 1003 
 1004     if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
 1005     {
 1006       FileHeader *hd=(FileHeader *)bb;
 1007       switch(FieldType)
 1008       {
 1009         case FHEXTRA_CRYPT:
 1010           {
 1011             FileHeader *hd=(FileHeader *)bb;
 1012             uint EncVersion=(uint)Raw->GetV();
 1013             if (EncVersion>CRYPT_VERSION)
 1014             {
 1015               wchar Info[20];
 1016               swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
 1017               UnkEncVerMsg(hd->FileName,Info);
 1018             }
 1019             else
 1020             {
 1021               uint Flags=(uint)Raw->GetV();
 1022               hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
 1023               hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
 1024               hd->Lg2Count=Raw->Get1();
 1025               if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
 1026               {
 1027                 wchar Info[20];
 1028                 swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
 1029                 UnkEncVerMsg(hd->FileName,Info);
 1030               }
 1031               Raw->GetB(hd->Salt,SIZE_SALT50);
 1032               Raw->GetB(hd->InitV,SIZE_INITV);
 1033               if (hd->UsePswCheck)
 1034               {
 1035                 Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
 1036 
 1037                 // It is important to know if password check data is valid.
 1038                 // If it is damaged and header CRC32 fails to detect it,
 1039                 // archiver would refuse to decompress a possibly valid file.
 1040                 // Since we want to be sure distinguishing a wrong password
 1041                 // or corrupt file data, we use 64-bit password check data
 1042                 // and to control its validity we use 32 bits of password
 1043                 // check data SHA-256 additionally to 32-bit header CRC32.
 1044                 byte csum[SIZE_PSWCHECK_CSUM];
 1045                 Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
 1046 
 1047                 sha256_context ctx;
 1048                 sha256_init(&ctx);
 1049                 sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK);
 1050 
 1051                 byte Digest[SHA256_DIGEST_SIZE];
 1052                 sha256_done(&ctx, Digest);
 1053 
 1054                 hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
 1055 
 1056                 // RAR 5.21 and earlier set PswCheck field in service records to 0
 1057                 // even if UsePswCheck was present.
 1058                 if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
 1059                   hd->UsePswCheck=0;
 1060               }
 1061               hd->SaltSet=true;
 1062               hd->CryptMethod=CRYPT_RAR50;
 1063               hd->Encrypted=true;
 1064             }
 1065           }
 1066           break;
 1067         case FHEXTRA_HASH:
 1068           {
 1069             FileHeader *hd=(FileHeader *)bb;
 1070             uint Type=(uint)Raw->GetV();
 1071             if (Type==FHEXTRA_HASH_BLAKE2)
 1072             {
 1073               hd->FileHash.Type=HASH_BLAKE2;
 1074               Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
 1075             }
 1076           }
 1077           break;
 1078         case FHEXTRA_HTIME:
 1079           if (FieldSize>=5)
 1080           {
 1081             byte Flags=(byte)Raw->GetV();
 1082             bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0;
 1083             if ((Flags & FHEXTRA_HTIME_MTIME)!=0)
 1084               if (UnixTime)
 1085                 hd->mtime.SetUnix(Raw->Get4());
 1086               else
 1087                 hd->mtime.SetWin(Raw->Get8());
 1088             if ((Flags & FHEXTRA_HTIME_CTIME)!=0)
 1089               if (UnixTime)
 1090                 hd->ctime.SetUnix(Raw->Get4());
 1091               else
 1092                 hd->ctime.SetWin(Raw->Get8());
 1093             if ((Flags & FHEXTRA_HTIME_ATIME)!=0)
 1094               if (UnixTime)
 1095                 hd->atime.SetUnix((time_t)Raw->Get4());
 1096               else
 1097                 hd->atime.SetWin(Raw->Get8());
 1098             if (UnixTime && (Flags & FHEXTRA_HTIME_UNIX_NS)!=0) // Add nanoseconds.
 1099             {
 1100               uint ns;
 1101               if ((Flags & FHEXTRA_HTIME_MTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
 1102                 hd->mtime.Adjust(ns);
 1103               if ((Flags & FHEXTRA_HTIME_CTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
 1104                 hd->ctime.Adjust(ns);
 1105               if ((Flags & FHEXTRA_HTIME_ATIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
 1106                 hd->atime.Adjust(ns);
 1107             }
 1108           }
 1109           break;
 1110         case FHEXTRA_VERSION:
 1111           if (FieldSize>=1)
 1112           {
 1113             Raw->GetV(); // Skip flags field.
 1114             uint Version=(uint)Raw->GetV();
 1115             if (Version!=0)
 1116             {
 1117               hd->Version=true;
 1118 
 1119               wchar VerText[20];
 1120               swprintf(VerText,ASIZE(VerText),L";%u",Version);
 1121               wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName));
 1122             }
 1123           }
 1124           break;
 1125         case FHEXTRA_REDIR:
 1126           {
 1127             hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
 1128             uint Flags=(uint)Raw->GetV();
 1129             hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
 1130             size_t NameSize=(size_t)Raw->GetV();
 1131 
 1132             char UtfName[NM*4];
 1133             *UtfName=0;
 1134             if (NameSize<ASIZE(UtfName)-1)
 1135             {
 1136               Raw->GetB(UtfName,NameSize);
 1137               UtfName[NameSize]=0;
 1138             }
 1139 #ifdef _WIN_ALL
 1140             UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName));
 1141 #endif
 1142             UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName));
 1143           }
 1144           break;
 1145         case FHEXTRA_UOWNER:
 1146           {
 1147             uint Flags=(uint)Raw->GetV();
 1148             hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0;
 1149             hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0;
 1150             *hd->UnixOwnerName=*hd->UnixGroupName=0;
 1151             if ((Flags & FHEXTRA_UOWNER_UNAME)!=0)
 1152             {
 1153               size_t Length=(size_t)Raw->GetV();
 1154               Length=Min(Length,ASIZE(hd->UnixOwnerName)-1);
 1155               Raw->GetB(hd->UnixOwnerName,Length);
 1156               hd->UnixOwnerName[Length]=0;
 1157             }
 1158             if ((Flags & FHEXTRA_UOWNER_GNAME)!=0)
 1159             {
 1160               size_t Length=(size_t)Raw->GetV();
 1161               Length=Min(Length,ASIZE(hd->UnixGroupName)-1);
 1162               Raw->GetB(hd->UnixGroupName,Length);
 1163               hd->UnixGroupName[Length]=0;
 1164             }
 1165 #ifdef _UNIX
 1166             if (hd->UnixOwnerNumeric)
 1167               hd->UnixOwnerID=(uid_t)Raw->GetV();
 1168             if (hd->UnixGroupNumeric)
 1169               hd->UnixGroupID=(gid_t)Raw->GetV();
 1170 #else
 1171             // Need these fields in Windows too for 'list' command,
 1172             // but uid_t and gid_t are not defined.
 1173             if (hd->UnixOwnerNumeric)
 1174               hd->UnixOwnerID=(uint)Raw->GetV();
 1175             if (hd->UnixGroupNumeric)
 1176               hd->UnixGroupID=(uint)Raw->GetV();
 1177 #endif
 1178             hd->UnixOwnerSet=true;
 1179           }
 1180           break;
 1181         case FHEXTRA_SUBDATA:
 1182           {
 1183             // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than
 1184             // required. It did not hurt extraction, because UnRAR 5.21
 1185             // and earlier ignored this field and set FieldSize as data left
 1186             // in entire extra area. But now we set the correct field size
 1187             // and set FieldSize based on the actual extra record size,
 1188             // so we need to adjust it for those older archives here.
 1189             // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE
 1190             // and always is last in extra area. So since its size is by 1
 1191             // less than needed, we always have 1 byte left in extra area,
 1192             // which fact we use here to detect such archives.
 1193             if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1)
 1194               FieldSize++;
 1195 
 1196             // We cannot allocate too much memory here, because above
 1197             // we check FieldSize againt Raw size and we control that Raw size
 1198             // is sensible when reading headers.
 1199             hd->SubData.Alloc((size_t)FieldSize);
 1200             Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
 1201           }
 1202           break;
 1203       }
 1204     }
 1205 
 1206     Raw->SetPos(NextPos);
 1207   }
 1208 }
 1209 
 1210 
 1211 #ifndef SFX_MODULE
 1212 size_t Archive::ReadHeader14()
 1213 {
 1214   RawRead Raw(this);
 1215   if (CurBlockPos<=(int64)SFXSize)
 1216   {
 1217     Raw.Read(SIZEOF_MAINHEAD14);
 1218     MainHead.Reset();
 1219     byte Mark[4];
 1220     Raw.GetB(Mark,4);
 1221     uint HeadSize=Raw.Get2();
 1222     if (HeadSize<7)
 1223       return false;
 1224     byte Flags=Raw.Get1();
 1225     NextBlockPos=CurBlockPos+HeadSize;
 1226     CurHeaderType=HEAD_MAIN;
 1227 
 1228     Volume=(Flags & MHD_VOLUME)!=0;
 1229     Solid=(Flags & MHD_SOLID)!=0;
 1230     Locked=(Flags & MHD_LOCK)!=0;
 1231     MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
 1232     MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
 1233   }
 1234   else
 1235   {
 1236     Raw.Read(SIZEOF_FILEHEAD14);
 1237     FileHead.Reset();
 1238 
 1239     FileHead.HeaderType=HEAD_FILE;
 1240     FileHead.DataSize=Raw.Get4();
 1241     FileHead.UnpSize=Raw.Get4();
 1242     FileHead.FileHash.Type=HASH_RAR14;
 1243     FileHead.FileHash.CRC32=Raw.Get2();
 1244     FileHead.HeadSize=Raw.Get2();
 1245     if (FileHead.HeadSize<21)
 1246       return false;
 1247     uint FileTime=Raw.Get4();
 1248     FileHead.FileAttr=Raw.Get1();
 1249     FileHead.Flags=Raw.Get1()|LONG_BLOCK;
 1250     FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
 1251     size_t NameSize=Raw.Get1();
 1252     FileHead.Method=Raw.Get1();
 1253 
 1254     FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
 1255     FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
 1256     FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
 1257     FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE;
 1258 
 1259     FileHead.PackSize=FileHead.DataSize;
 1260     FileHead.WinSize=0x10000;
 1261     FileHead.Dir=(FileHead.FileAttr & 0x10)!=0;
 1262 
 1263     FileHead.HostOS=HOST_MSDOS;
 1264     FileHead.HSType=HSYS_WINDOWS;
 1265 
 1266     FileHead.mtime.SetDos(FileTime);
 1267 
 1268     Raw.Read(NameSize);
 1269 
 1270     char FileName[NM];
 1271     size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
 1272     Raw.GetB((byte *)FileName,ReadNameSize);
 1273     FileName[ReadNameSize]=0;
 1274     IntToExt(FileName,FileName,ASIZE(FileName));
 1275     CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
 1276     ConvertNameCase(FileHead.FileName);
 1277     ConvertFileHeader(&FileHead);
 1278 
 1279     if (Raw.Size()!=0)
 1280       NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
 1281     CurHeaderType=HEAD_FILE;
 1282   }
 1283   return NextBlockPos>CurBlockPos ? Raw.Size() : 0;
 1284 }
 1285 #endif
 1286 
 1287 
 1288 #ifndef SFX_MODULE
 1289 void Archive::ConvertNameCase(wchar *Name)
 1290 {
 1291   if (Cmd->ConvertNames==NAMES_UPPERCASE)
 1292     wcsupper(Name);
 1293   if (Cmd->ConvertNames==NAMES_LOWERCASE)
 1294     wcslower(Name);
 1295 }
 1296 #endif
 1297 
 1298 
 1299 bool Archive::IsArcDir()
 1300 {
 1301   return FileHead.Dir;
 1302 }
 1303 
 1304 
 1305 void Archive::ConvertAttributes()
 1306 {
 1307 #if defined(_WIN_ALL) || defined(_EMX)
 1308   if (FileHead.HSType!=HSYS_WINDOWS)
 1309     FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
 1310 #endif
 1311 #ifdef _UNIX
 1312   // umask defines which permission bits must not be set by default
 1313   // when creating a file or directory. The typical default value
 1314   // for the process umask is S_IWGRP | S_IWOTH (octal 022),
 1315   // resulting in 0644 mode for new files.
 1316   // Normally umask is applied automatically when creating a file,
 1317   // but we set attributes with chmod later, so we need to calculate
 1318   // resulting attributes here. We do it only for non-Unix archives.
 1319   // We restore native Unix attributes as is, because it can be backup.
 1320   static mode_t mask = (mode_t) -1;
 1321 
 1322   if (mask == (mode_t) -1)
 1323   {
 1324     // umask call returns the current umask value. Argument (022) is not
 1325     // really important here.
 1326     mask = umask(022);
 1327 
 1328     // Restore the original umask value, which was changed to 022 above.
 1329     umask(mask);
 1330   }
 1331 
 1332   switch(FileHead.HSType)
 1333   {
 1334     case HSYS_WINDOWS:
 1335       {
 1336         // Mapping MSDOS, OS/2 and Windows file attributes to Unix.
 1337 
 1338         if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
 1339         {
 1340           // For directories we use 0777 mask.
 1341           FileHead.FileAttr=0777 & ~mask;
 1342         }
 1343         else
 1344           if (FileHead.FileAttr & 1)  // FILE_ATTRIBUTE_READONLY
 1345           {
 1346             // For read only files we use 0444 mask with 'w' bits turned off.
 1347             FileHead.FileAttr=0444 & ~mask;
 1348           }
 1349           else
 1350           {
 1351             // umask does not set +x for regular files, so we use 0666
 1352             // instead of 0777 as for directories.
 1353             FileHead.FileAttr=0666 & ~mask;
 1354           }
 1355       }
 1356       break;
 1357     case HSYS_UNIX:
 1358       break;
 1359     default:
 1360       if (FileHead.Dir)
 1361         FileHead.FileAttr=0x41ff & ~mask;
 1362       else
 1363         FileHead.FileAttr=0x81b6 & ~mask;
 1364       break;
 1365   }
 1366 #endif
 1367 }
 1368 
 1369 
 1370 void Archive::ConvertFileHeader(FileHeader *hd)
 1371 {
 1372   if (hd->HSType==HSYS_UNKNOWN)
 1373     if (hd->Dir)
 1374       hd->FileAttr=0x10;
 1375     else
 1376       hd->FileAttr=0x20;
 1377 
 1378 #ifdef _WIN_ALL
 1379   if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
 1380     ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName));
 1381 #endif
 1382 
 1383   for (wchar *s=hd->FileName;*s!=0;s++)
 1384   {
 1385 #ifdef _UNIX
 1386     // Backslash is the invalid character for Windows file headers,
 1387     // but it can present in Unix file names extracted in Unix.
 1388     if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS)
 1389       *s='_';
 1390 #endif
 1391 
 1392 #if defined(_WIN_ALL) || defined(_EMX)
 1393     // RAR 5.0 archives do not use '\' as path separator, so if we see it,
 1394     // it means that it is a part of Unix file name, which we cannot
 1395     // extract in Windows.
 1396     if (*s=='\\' && Format==RARFMT50)
 1397       *s='_';
 1398 
 1399     // ':' in file names is allowed in Unix, but not in Windows.
 1400     // Even worse, file data will be written to NTFS stream on NTFS,
 1401     // so automatic name correction on file create error in extraction
 1402     // routine does not work. In Windows and DOS versions we better
 1403     // replace ':' now.
 1404     if (*s==':')
 1405       *s='_';
 1406 #endif
 1407 
 1408     // This code must be performed only after other path separator checks,
 1409     // because it produces backslashes illegal for some of checks above.
 1410     // Backslash is allowed in file names in Unix, but not in Windows.
 1411     // Still, RAR 4.x uses backslashes as path separator even in Unix.
 1412     // Forward slash is not allowed in both systems. In RAR 5.0 we use
 1413     // the forward slash as universal path separator.
 1414     if (*s=='/' || *s=='\\' && Format!=RARFMT50)
 1415       *s=CPATHDIVIDER;
 1416   }
 1417 }
 1418 
 1419 
 1420 int64 Archive::GetStartPos()
 1421 {
 1422   int64 StartPos=SFXSize+MarkHead.HeadSize;
 1423   if (Format==RARFMT15)
 1424     StartPos+=MainHead.HeadSize;
 1425   else // RAR 5.0.
 1426     StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize);
 1427   return StartPos;
 1428 }
 1429 
 1430 
 1431 bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
 1432 {
 1433   if (BrokenHeader)
 1434   {
 1435     uiMsg(UIERROR_SUBHEADERBROKEN,FileName);
 1436     ErrHandler.SetErrorCode(RARX_CRC);
 1437     return false;
 1438   }
 1439   if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK))
 1440   {
 1441     uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
 1442     return false;
 1443   }
 1444 
 1445   if (SubHead.PackSize==0 && !SubHead.SplitAfter)
 1446     return true;
 1447 
 1448   SubDataIO.Init();
 1449   Unpack Unpack(&SubDataIO);
 1450   Unpack.Init(SubHead.WinSize,false);
 1451 
 1452   if (DestFile==NULL)
 1453   {
 1454     if (SubHead.UnpSize>0x1000000)
 1455     {
 1456       // So huge allocation must never happen in valid archives.
 1457       uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
 1458       return false;
 1459     }
 1460     if (UnpData==NULL)
 1461       SubDataIO.SetTestMode(true);
 1462     else
 1463     {
 1464       UnpData->Alloc((size_t)SubHead.UnpSize);
 1465       SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
 1466     }
 1467   }
 1468   if (SubHead.Encrypted)
 1469     if (Cmd->Password.IsSet())
 1470       SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password,
 1471                 SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV,
 1472                 SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck);
 1473     else
 1474       return false;
 1475   SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1);
 1476   SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
 1477   SubDataIO.EnableShowProgress(false);
 1478   SubDataIO.SetFiles(this,DestFile);
 1479   SubDataIO.SetTestMode(TestMode);
 1480   SubDataIO.UnpVolume=SubHead.SplitAfter;
 1481   SubDataIO.SetSubHeader(&SubHead,NULL);
 1482   Unpack.SetDestSize(SubHead.UnpSize);
 1483   if (SubHead.Method==0)
 1484     CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
 1485   else
 1486     Unpack.DoUnpack(SubHead.UnpVer,false);
 1487 
 1488   if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL))
 1489   {
 1490     uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName);
 1491     ErrHandler.SetErrorCode(RARX_CRC);
 1492     if (UnpData!=NULL)
 1493       UnpData->Reset();
 1494     return false;
 1495   }
 1496   return true;
 1497 }