"Fossies" - the Fresh Open Source Software Archive

Member "p7zip_16.02/CPP/7zip/Archive/Rar/RarHandler.cpp" (11 Jun 2016, 47427 Bytes) of package /linux/misc/p7zip_16.02_src_all.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. See also the last Fossies "Diffs" side-by-side code changes report for "RarHandler.cpp": 15.14.1_src_all_vs_16.02_src_all.

    1 // RarHandler.cpp
    2 
    3 #include "StdAfx.h"
    4 
    5 #include "../../../../C/CpuArch.h"
    6 
    7 #include "../../../Common/ComTry.h"
    8 #include "../../../Common/IntToString.h"
    9 #include "../../../Common/UTFConvert.h"
   10 
   11 #include "../../../Windows/PropVariantUtils.h"
   12 #include "../../../Windows/TimeUtils.h"
   13 
   14 #include "../../IPassword.h"
   15 
   16 #include "../../Common/CreateCoder.h"
   17 #include "../../Common/FilterCoder.h"
   18 #include "../../Common/LimitedStreams.h"
   19 #include "../../Common/MethodId.h"
   20 #include "../../Common/ProgressUtils.h"
   21 #include "../../Common/RegisterArc.h"
   22 #include "../../Common/StreamUtils.h"
   23 
   24 #include "../../Compress/CopyCoder.h"
   25 
   26 #include "../../Crypto/Rar20Crypto.h"
   27 #include "../../Crypto/RarAes.h"
   28 
   29 #include "../Common/FindSignature.h"
   30 #include "../Common/ItemNameUtils.h"
   31 #include "../Common/OutStreamWithCRC.h"
   32 
   33 #include "../HandlerCont.h"
   34 
   35 #include "RarVol.h"
   36 #include "RarHandler.h"
   37 
   38 using namespace NWindows;
   39 
   40 #define Get16(p) GetUi16(p)
   41 #define Get32(p) GetUi32(p)
   42 
   43 namespace NArchive {
   44 namespace NRar {
   45 
   46 #define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }
   47 
   48 static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE;
   49 
   50 const unsigned kPasswordLen_MAX = 127;
   51       
   52 bool CItem::IgnoreItem() const
   53 {
   54   switch (HostOS)
   55   {
   56     case NHeader::NFile::kHostMSDOS:
   57     case NHeader::NFile::kHostOS2:
   58     case NHeader::NFile::kHostWin32:
   59       return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0);
   60   }
   61   return false;
   62 }
   63 
   64 bool CItem::IsDir() const
   65 {
   66   if (GetDictSize() == NHeader::NFile::kDictDirectoryValue)
   67     return true;
   68   switch (HostOS)
   69   {
   70     case NHeader::NFile::kHostMSDOS:
   71     case NHeader::NFile::kHostOS2:
   72     case NHeader::NFile::kHostWin32:
   73       if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
   74         return true;
   75   }
   76   return false;
   77 }
   78 
   79 UInt32 CItem::GetWinAttrib() const
   80 {
   81   UInt32 a;
   82   switch (HostOS)
   83   {
   84     case NHeader::NFile::kHostMSDOS:
   85     case NHeader::NFile::kHostOS2:
   86     case NHeader::NFile::kHostWin32:
   87       a = Attrib;
   88       break;
   89     default:
   90       a = 0; // must be converted from unix value;
   91   }
   92   if (IsDir())
   93     a |= NHeader::NFile::kWinFileDirectoryAttributeMask;
   94   return a;
   95 }
   96   
   97 static const char * const kHostOS[] =
   98 {
   99     "MS DOS"
  100   , "OS/2"
  101   , "Win32"
  102   , "Unix"
  103   , "Mac OS"
  104   , "BeOS"
  105 };
  106 
  107 static const char *kUnknownOS = "Unknown";
  108 
  109 static const CUInt32PCharPair k_Flags[] =
  110 {
  111   { 0, "Volume" },
  112   { 1, "Comment" },
  113   { 2, "Lock" },
  114   { 3, "Solid" },
  115   { 4, "NewVolName" }, // pack_comment in old versuons
  116   { 5, "Authenticity" },
  117   { 6, "Recovery" },
  118   { 7, "BlockEncryption" },
  119   { 8, "FirstVolume" },
  120   { 9, "EncryptVer" }
  121 };
  122 
  123 enum EErrorType
  124 {
  125   k_ErrorType_OK,
  126   k_ErrorType_Corrupted,
  127   k_ErrorType_UnexpectedEnd,
  128   k_ErrorType_DecryptionError
  129 };
  130 
  131 class CInArchive
  132 {
  133   IInStream *m_Stream;
  134   UInt64 m_StreamStartPosition;
  135   CBuffer<wchar_t> _unicodeNameBuffer;
  136   CByteBuffer _comment;
  137   CByteBuffer m_FileHeaderData;
  138   NHeader::NBlock::CBlock m_BlockHeader;
  139   NCrypto::NRar3::CDecoder *m_RarAESSpec;
  140   CMyComPtr<ICompressFilter> m_RarAES;
  141   CBuffer<Byte> m_DecryptedData;
  142   Byte *m_DecryptedDataAligned;
  143   UInt32 m_DecryptedDataSize;
  144   bool m_CryptoMode;
  145   UInt32 m_CryptoPos;
  146 
  147 
  148   HRESULT ReadBytesSpec(void *data, size_t *size);
  149   bool ReadBytesAndTestSize(void *data, UInt32 size);
  150   void ReadName(const Byte *p, unsigned nameSize, CItem &item);
  151   bool ReadHeaderReal(const Byte *p, unsigned size, CItem &item);
  152   
  153   HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
  154 
  155   void AddToSeekValue(UInt64 addValue)
  156   {
  157     m_Position += addValue;
  158   }
  159 
  160   void FinishCryptoBlock()
  161   {
  162     if (m_CryptoMode)
  163       while ((m_CryptoPos & 0xF) != 0)
  164       {
  165         m_CryptoPos++;
  166         m_Position++;
  167       }
  168   }
  169 
  170 public:
  171   UInt64 m_Position;
  172   CInArcInfo ArcInfo;
  173   bool HeaderErrorWarning;
  174 
  175   HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit);
  176   HRESULT GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword,
  177       bool &filled, EErrorType &error);
  178 };
  179   
  180 static bool CheckHeaderCrc(const Byte *header, size_t headerSize)
  181 {
  182   return Get16(header) == (UInt16)(CrcCalc(header + 2, headerSize - 2) & 0xFFFF);
  183 }
  184 
  185 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
  186 {
  187   HeaderErrorWarning = false;
  188   m_CryptoMode = false;
  189   RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition));
  190   RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileSize));
  191   RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL));
  192   m_Position = m_StreamStartPosition;
  193 
  194   UInt64 arcStartPos = m_StreamStartPosition;
  195   {
  196     Byte marker[NHeader::kMarkerSize];
  197     RINOK(ReadStream_FALSE(stream, marker, NHeader::kMarkerSize));
  198     if (memcmp(marker, kMarker, NHeader::kMarkerSize) == 0)
  199       m_Position += NHeader::kMarkerSize;
  200     else
  201     {
  202       if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
  203         return S_FALSE;
  204       RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL));
  205       RINOK(FindSignatureInStream(stream, kMarker, NHeader::kMarkerSize,
  206           searchHeaderSizeLimit, arcStartPos));
  207       m_Position = arcStartPos + NHeader::kMarkerSize;
  208       RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
  209     }
  210   }
  211   Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1];
  212 
  213   RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize));
  214   AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);
  215 
  216 
  217   UInt32 blockSize = Get16(buf + 5);
  218 
  219   ArcInfo.EncryptVersion = 0;
  220   ArcInfo.Flags = Get16(buf + 3);
  221 
  222   UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize;
  223   
  224   /*
  225   if (ArcInfo.IsThereEncryptVer())
  226   {
  227     if (blockSize <= headerSize)
  228       return S_FALSE;
  229     RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1));
  230     AddToSeekValue(1);
  231     ArcInfo.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize];
  232     headerSize += 1;
  233   }
  234   */
  235   
  236   if (blockSize < headerSize
  237       || buf[2] != NHeader::NBlockType::kArchiveHeader
  238       || !CheckHeaderCrc(buf, headerSize))
  239     return S_FALSE;
  240 
  241   size_t commentSize = blockSize - headerSize;
  242   _comment.Alloc(commentSize);
  243   RINOK(ReadStream_FALSE(stream, _comment, commentSize));
  244   AddToSeekValue(commentSize);
  245   m_Stream = stream;
  246   ArcInfo.StartPos = arcStartPos;
  247   return S_OK;
  248 }
  249 
  250 HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize)
  251 {
  252   if (m_CryptoMode)
  253   {
  254     size_t size = *resSize;
  255     *resSize = 0;
  256     const Byte *bufData = m_DecryptedDataAligned;
  257     UInt32 bufSize = m_DecryptedDataSize;
  258     size_t i;
  259     for (i = 0; i < size && m_CryptoPos < bufSize; i++)
  260       ((Byte *)data)[i] = bufData[m_CryptoPos++];
  261     *resSize = i;
  262     return S_OK;
  263   }
  264   return ReadStream(m_Stream, data, resSize);
  265 }
  266 
  267 bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
  268 {
  269   size_t processed = size;
  270   if (ReadBytesSpec(data, &processed) != S_OK)
  271     return false;
  272   return processed == size;
  273 }
  274 
  275 static void DecodeUnicodeFileName(const Byte *name, const Byte *encName,
  276     unsigned encSize, wchar_t *unicodeName, unsigned maxDecSize)
  277 {
  278   unsigned encPos = 0;
  279   unsigned decPos = 0;
  280   unsigned flagBits = 0;
  281   Byte flags = 0;
  282   Byte highByte = encName[encPos++];
  283   while (encPos < encSize && decPos < maxDecSize)
  284   {
  285     if (flagBits == 0)
  286     {
  287       flags = encName[encPos++];
  288       flagBits = 8;
  289     }
  290     switch (flags >> 6)
  291     {
  292       case 0:
  293         unicodeName[decPos++] = encName[encPos++];
  294         break;
  295       case 1:
  296         unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8));
  297         break;
  298       case 2:
  299         unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8));
  300         encPos += 2;
  301         break;
  302       case 3:
  303         {
  304           unsigned len = encName[encPos++];
  305           if (len & 0x80)
  306           {
  307             Byte correction = encName[encPos++];
  308             for (len = (len & 0x7f) + 2;
  309                 len > 0 && decPos < maxDecSize; len--, decPos++)
  310               unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8));
  311           }
  312           else
  313             for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++)
  314               unicodeName[decPos] = name[decPos];
  315         }
  316         break;
  317     }
  318     flags <<= 2;
  319     flagBits -= 2;
  320   }
  321   unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0;
  322 }
  323 
  324 void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item)
  325 {
  326   item.UnicodeName.Empty();
  327   if (nameSize > 0)
  328   {
  329     unsigned i;
  330     for (i = 0; i < nameSize && p[i] != 0; i++);
  331     item.Name.SetFrom((const char *)p, i);
  332 
  333     if (item.HasUnicodeName())
  334     {
  335       if (i < nameSize)
  336       {
  337         i++;
  338         unsigned uNameSizeMax = MyMin(nameSize, (unsigned)0x400);
  339         _unicodeNameBuffer.AllocAtLeast(uNameSizeMax + 1);
  340         DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer, uNameSizeMax);
  341         item.UnicodeName = _unicodeNameBuffer;
  342       }
  343       else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName))
  344         item.UnicodeName.Empty();
  345     }
  346   }
  347   else
  348     item.Name.Empty();
  349 }
  350 
  351 static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime)
  352 {
  353   rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
  354   unsigned numDigits = (mask & 3);
  355   rarTime.SubTime[0] =
  356   rarTime.SubTime[1] =
  357   rarTime.SubTime[2] = 0;
  358   if (numDigits > size)
  359     return -1;
  360   for (unsigned i = 0; i < numDigits; i++)
  361     rarTime.SubTime[3 - numDigits + i] = p[i];
  362   return numDigits;
  363 }
  364 
  365 #define READ_TIME(_mask_, _ttt_) \
  366   { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += (unsigned)size2, size -= (unsigned)size2; }
  367 
  368 #define READ_TIME_2(_mask_, _def_, _ttt_) \
  369     _def_ = ((_mask_ & 8) != 0); if (_def_) \
  370     { if (size < 4) return false; \
  371       _ttt_ .DosTime = Get32(p); p += 4; size -= 4; \
  372       READ_TIME(_mask_, _ttt_); } \
  373 
  374 
  375 bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
  376 {
  377   const Byte *pStart = p;
  378 
  379   item.Clear();
  380   item.Flags = m_BlockHeader.Flags;
  381 
  382   const unsigned kFileHeaderSize = 25;
  383 
  384   if (size < kFileHeaderSize)
  385     return false;
  386 
  387   item.PackSize = Get32(p);
  388   item.Size = Get32(p + 4);
  389   item.HostOS = p[8];
  390   item.FileCRC = Get32(p + 9);
  391   item.MTime.DosTime = Get32(p + 13);
  392   item.UnPackVersion = p[17];
  393   item.Method = p[18];
  394   unsigned nameSize = Get16(p + 19);
  395   item.Attrib = Get32(p + 21);
  396 
  397   item.MTime.LowSecond = 0;
  398   item.MTime.SubTime[0] =
  399       item.MTime.SubTime[1] =
  400       item.MTime.SubTime[2] = 0;
  401 
  402   p += kFileHeaderSize;
  403   size -= kFileHeaderSize;
  404   if ((item.Flags & NHeader::NFile::kSize64Bits) != 0)
  405   {
  406     if (size < 8)
  407       return false;
  408     item.PackSize |= ((UInt64)Get32(p) << 32);
  409     item.Size |= ((UInt64)Get32(p + 4) << 32);
  410     p += 8;
  411     size -= 8;
  412   }
  413   if (nameSize > size)
  414     return false;
  415   ReadName(p, nameSize, item);
  416   p += nameSize;
  417   size -= nameSize;
  418 
  419   /*
  420   // It was commented, since it's difficult to support alt Streams for solid archives.
  421   if (m_BlockHeader.Type == NHeader::NBlockType::kSubBlock)
  422   {
  423     if (item.HasSalt())
  424     {
  425       if (size < sizeof(item.Salt))
  426         return false;
  427       size -= sizeof(item.Salt);
  428       p += sizeof(item.Salt);
  429     }
  430     if (item.Name == "ACL" && size == 0)
  431     {
  432       item.IsAltStream = true;
  433       item.Name.Empty();
  434       item.UnicodeName.SetFromAscii(".ACL");
  435     }
  436     else if (item.Name == "STM" && size != 0 && (size & 1) == 0)
  437     {
  438       item.IsAltStream = true;
  439       item.Name.Empty();
  440       for (UInt32 i = 0; i < size; i += 2)
  441       {
  442         wchar_t c = Get16(p + i);
  443         if (c == 0)
  444           return false;
  445         item.UnicodeName += c;
  446       }
  447     }
  448   }
  449   */
  450 
  451   if (item.HasSalt())
  452   {
  453     if (size < sizeof(item.Salt))
  454       return false;
  455     for (unsigned i = 0; i < sizeof(item.Salt); i++)
  456       item.Salt[i] = p[i];
  457     p += sizeof(item.Salt);
  458     size -= sizeof(item.Salt);
  459   }
  460 
  461   // some rar archives have HasExtTime flag without field.
  462   if (size >= 2 && item.HasExtTime())
  463   {
  464     Byte aMask = (Byte)(p[0] >> 4);
  465     Byte b = p[1];
  466     p += 2;
  467     size -= 2;
  468     Byte mMask = (Byte)(b >> 4);
  469     Byte cMask = (Byte)(b & 0xF);
  470     if ((mMask & 8) != 0)
  471     {
  472       READ_TIME(mMask, item.MTime);
  473     }
  474     READ_TIME_2(cMask, item.CTimeDefined, item.CTime);
  475     READ_TIME_2(aMask, item.ATimeDefined, item.ATime);
  476   }
  477 
  478   unsigned fileHeaderWithNameSize = 7 + (unsigned)(p - pStart);
  479   
  480   item.Position = m_Position;
  481   item.MainPartSize = fileHeaderWithNameSize;
  482   item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize);
  483 
  484   if (m_CryptoMode)
  485     item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF);
  486   else
  487     item.AlignSize = 0;
  488   AddToSeekValue(m_BlockHeader.HeadSize);
  489   
  490   // return (m_BlockHeader.Type != NHeader::NBlockType::kSubBlock || item.IsAltStream);
  491   return true;
  492 }
  493 
  494 HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, bool &filled, EErrorType &error)
  495 {
  496   filled = false;
  497   error = k_ErrorType_OK;
  498   for (;;)
  499   {
  500     m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL);
  501     ArcInfo.EndPos = m_Position;
  502     if (!m_CryptoMode && (ArcInfo.Flags &
  503         NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
  504     {
  505       m_CryptoMode = false;
  506       if (getTextPassword == 0)
  507       {
  508         error = k_ErrorType_DecryptionError;
  509         return S_OK; // return S_FALSE;
  510       }
  511       if (!m_RarAES)
  512       {
  513         m_RarAESSpec = new NCrypto::NRar3::CDecoder;
  514         m_RarAES = m_RarAESSpec;
  515       }
  516       // m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld());
  517 
  518       // Salt
  519       const UInt32 kSaltSize = 8;
  520       Byte salt[kSaltSize];
  521       if (!ReadBytesAndTestSize(salt, kSaltSize))
  522         return S_FALSE;
  523       m_Position += kSaltSize;
  524       RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize))
  525       // Password
  526       CMyComBSTR password;
  527       RINOK(getTextPassword->CryptoGetTextPassword(&password))
  528       unsigned len = 0;
  529       if (password)
  530         len = MyStringLen(password);
  531       if (len > kPasswordLen_MAX)
  532         len = kPasswordLen_MAX;
  533 
  534       CByteArr buffer(len * 2);
  535       for (unsigned i = 0; i < len; i++)
  536       {
  537         wchar_t c = password[i];
  538         ((Byte *)buffer)[i * 2] = (Byte)c;
  539         ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
  540       }
  541 
  542       m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2);
  543 
  544       const UInt32 kDecryptedBufferSize = (1 << 12);
  545       if (m_DecryptedData.Size() == 0)
  546       {
  547         const UInt32 kAlign = 16;
  548         m_DecryptedData.Alloc(kDecryptedBufferSize + kAlign);
  549         m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
  550       }
  551       RINOK(m_RarAES->Init());
  552       size_t decryptedDataSizeT = kDecryptedBufferSize;
  553       RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT));
  554       m_DecryptedDataSize = (UInt32)decryptedDataSizeT;
  555       m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize);
  556 
  557       m_CryptoMode = true;
  558       m_CryptoPos = 0;
  559     }
  560 
  561     m_FileHeaderData.AllocAtLeast(7);
  562     size_t processed = 7;
  563     RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed));
  564     if (processed != 7)
  565     {
  566       if (processed != 0)
  567         error = k_ErrorType_UnexpectedEnd;
  568       ArcInfo.EndPos = m_Position + processed; // test it
  569       return S_OK;
  570     }
  571 
  572     const Byte *p = m_FileHeaderData;
  573     m_BlockHeader.CRC = Get16(p + 0);
  574     m_BlockHeader.Type = p[2];
  575     m_BlockHeader.Flags = Get16(p + 3);
  576     m_BlockHeader.HeadSize = Get16(p + 5);
  577 
  578     if (m_BlockHeader.HeadSize < 7)
  579     {
  580       error = k_ErrorType_Corrupted;
  581       return S_OK;
  582       // ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive);
  583     }
  584 
  585     if (m_BlockHeader.Type < NHeader::NBlockType::kFileHeader ||
  586         m_BlockHeader.Type > NHeader::NBlockType::kEndOfArchive)
  587     {
  588       error = m_CryptoMode ?
  589           k_ErrorType_DecryptionError :
  590           k_ErrorType_Corrupted;
  591       return S_OK;
  592     }
  593 
  594     if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive)
  595     {
  596       bool footerError = false;
  597 
  598       unsigned expectHeadLen = 7;
  599       if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC)
  600         expectHeadLen += 4;
  601       if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber)
  602         expectHeadLen += 2;
  603       if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_RevSpace)
  604         expectHeadLen += 7;
  605 
  606       // rar 5.0 beta 1 writes incorrect RevSpace and headSize
  607 
  608       if (m_BlockHeader.HeadSize < expectHeadLen)
  609         HeaderErrorWarning = true;
  610         
  611       if (m_BlockHeader.HeadSize > 7)
  612       {
  613         /* We suppose that EndOfArchive header is always small.
  614            It's only 20 bytes for multivolume
  615            Fix the limit, if larger footers are possible */
  616         if (m_BlockHeader.HeadSize > (1 << 8))
  617           footerError = true;
  618         else
  619         {
  620           if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize)
  621             m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7);
  622           UInt32 afterSize = m_BlockHeader.HeadSize - 7;
  623           if (ReadBytesAndTestSize(m_FileHeaderData + 7, afterSize))
  624             processed += afterSize;
  625           else
  626           {
  627             if (!m_CryptoMode)
  628             {
  629               error = k_ErrorType_UnexpectedEnd;
  630               return S_OK;
  631             }
  632             footerError = true;
  633           }
  634         }
  635       }
  636       
  637       if (footerError || !CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize))
  638       {
  639         error = m_CryptoMode ?
  640           k_ErrorType_DecryptionError :
  641           k_ErrorType_Corrupted;
  642       }
  643       else
  644       {
  645         ArcInfo.EndFlags = m_BlockHeader.Flags;
  646         UInt32 offset = 7;
  647         
  648         if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC)
  649         {
  650           if (processed < offset + 4)
  651             error = k_ErrorType_Corrupted;
  652           else
  653             ArcInfo.DataCRC = Get32(m_FileHeaderData + offset);
  654           offset += 4;
  655         }
  656         
  657         if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber)
  658         {
  659           if (processed < offset + 2)
  660             error = k_ErrorType_Corrupted;
  661           ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset);
  662         }
  663 
  664         ArcInfo.EndOfArchive_was_Read = true;
  665       }
  666 
  667       m_Position += processed;
  668       FinishCryptoBlock();
  669       ArcInfo.EndPos = m_Position;
  670       return S_OK;
  671     }
  672 
  673     if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader
  674         /* || m_BlockHeader.Type == NHeader::NBlockType::kSubBlock */)
  675     {
  676       if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize)
  677         m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7);
  678       // m_CurData = (Byte *)m_FileHeaderData;
  679       // m_PosLimit = m_BlockHeader.HeadSize;
  680       if (!ReadBytesAndTestSize(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7))
  681       {
  682         error = k_ErrorType_UnexpectedEnd;
  683         return S_OK;
  684       }
  685 
  686       bool okItem = ReadHeaderReal(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7, item);
  687       if (okItem)
  688       {
  689         if (!CheckHeaderCrc(m_FileHeaderData, (unsigned)m_BlockHeader.HeadSize - item.CommentSize))
  690         {
  691           error = k_ErrorType_Corrupted; // ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError);
  692           return S_OK;
  693         }
  694         filled = true;
  695       }
  696 
  697       FinishCryptoBlock();
  698       m_CryptoMode = false;
  699       // Move Position to compressed Data;
  700       m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL);
  701       AddToSeekValue(item.PackSize);  // m_Position points to next header;
  702       // if (okItem)
  703         return S_OK;
  704       /*
  705       else
  706         continue;
  707       */
  708     }
  709     
  710     if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10))
  711     {
  712       error = k_ErrorType_DecryptionError;
  713       return S_OK;
  714     }
  715     
  716     if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
  717     {
  718       if (m_FileHeaderData.Size() < 7 + 4)
  719         m_FileHeaderData.ChangeSize_KeepData(7 + 4, 7);
  720       if (!ReadBytesAndTestSize(m_FileHeaderData + 7, 4))
  721       {
  722         error = k_ErrorType_UnexpectedEnd;
  723         return S_OK;
  724       }
  725       UInt32 dataSize = Get32(m_FileHeaderData + 7);
  726       AddToSeekValue(dataSize);
  727       if (m_CryptoMode && dataSize > (1 << 27))
  728       {
  729         error = k_ErrorType_DecryptionError;
  730         return S_OK;
  731       }
  732       m_CryptoPos = m_BlockHeader.HeadSize;
  733     }
  734     else
  735       m_CryptoPos = 0;
  736     
  737     {
  738       UInt64 newPos = m_Position + m_BlockHeader.HeadSize;
  739       if (newPos > ArcInfo.FileSize)
  740       {
  741         error = k_ErrorType_UnexpectedEnd;
  742         return S_OK;
  743       }
  744     }
  745     AddToSeekValue(m_BlockHeader.HeadSize);
  746     FinishCryptoBlock();
  747     m_CryptoMode = false;
  748   }
  749 }
  750 
  751 
  752 static const Byte kProps[] =
  753 {
  754   kpidPath,
  755   kpidIsDir,
  756   kpidSize,
  757   kpidPackSize,
  758   kpidMTime,
  759   kpidCTime,
  760   kpidATime,
  761   kpidAttrib,
  762 
  763   kpidEncrypted,
  764   kpidSolid,
  765   kpidCommented,
  766   kpidSplitBefore,
  767   kpidSplitAfter,
  768   kpidCRC,
  769   kpidHostOS,
  770   kpidMethod,
  771   kpidUnpackVer
  772 };
  773 
  774 static const Byte kArcProps[] =
  775 {
  776   kpidTotalPhySize,
  777   kpidCharacts,
  778   kpidSolid,
  779   kpidNumBlocks,
  780   // kpidEncrypted,
  781   kpidIsVolume,
  782   kpidVolumeIndex,
  783   kpidNumVolumes
  784   // kpidCommented
  785 };
  786 
  787 IMP_IInArchive_Props
  788 IMP_IInArchive_ArcProps
  789 
  790 UInt64 CHandler::GetPackSize(unsigned refIndex) const
  791 {
  792   const CRefItem &refItem = _refItems[refIndex];
  793   UInt64 totalPackSize = 0;
  794   for (unsigned i = 0; i < refItem.NumItems; i++)
  795     totalPackSize += _items[refItem.ItemIndex + i].PackSize;
  796   return totalPackSize;
  797 }
  798 
  799 bool CHandler::IsSolid(unsigned refIndex) const
  800 {
  801   const CItem &item = _items[_refItems[refIndex].ItemIndex];
  802   if (item.UnPackVersion < 20)
  803   {
  804     if (_arcInfo.IsSolid())
  805       return (refIndex > 0);
  806     return false;
  807   }
  808   return item.IsSolid();
  809 }
  810 
  811 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
  812 {
  813   COM_TRY_BEGIN
  814   NCOM::CPropVariant prop;
  815   switch (propID)
  816   {
  817     case kpidVolumeIndex: if (_arcInfo.Is_VolNumber_Defined()) prop = (UInt32)_arcInfo.VolNumber; break;
  818     case kpidSolid: prop = _arcInfo.IsSolid(); break;
  819     case kpidCharacts:
  820     {
  821       AString s = FlagsToString(k_Flags, ARRAY_SIZE(k_Flags), _arcInfo.Flags);
  822       // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop);
  823       if (_arcInfo.Is_DataCRC_Defined())
  824       {
  825         s.Add_Space_if_NotEmpty();
  826         s += "VolCRC";
  827       }
  828       prop = s;
  829       break;
  830     }
  831     // case kpidEncrypted: prop = _arcInfo.IsEncrypted(); break; // it's for encrypted names.
  832     case kpidIsVolume: prop = _arcInfo.IsVolume(); break;
  833     case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break;
  834     case kpidOffset: if (_arcs.Size() == 1 && _arcInfo.StartPos != 0) prop = _arcInfo.StartPos; break;
  835 
  836     case kpidTotalPhySize:
  837     {
  838       if (_arcs.Size() > 1)
  839       {
  840         UInt64 sum = 0;
  841         FOR_VECTOR (v, _arcs)
  842           sum += _arcs[v].PhySize;
  843         prop = sum;
  844       }
  845       break;
  846     }
  847 
  848     case kpidPhySize:
  849     {
  850       if (_arcs.Size() != 0)
  851         prop = _arcInfo.GetPhySize();
  852       break;
  853     }
  854 
  855     // case kpidCommented: prop = _arcInfo.IsCommented(); break;
  856 
  857     case kpidNumBlocks:
  858     {
  859       UInt32 numBlocks = 0;
  860       FOR_VECTOR (i, _refItems)
  861         if (!IsSolid(i))
  862           numBlocks++;
  863       prop = (UInt32)numBlocks;
  864       break;
  865     }
  866     
  867     
  868     case kpidError:
  869     {
  870       // if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
  871 
  872       if (/* &_missingVol || */ !_missingVolName.IsEmpty())
  873       {
  874         UString s;
  875         s.SetFromAscii("Missing volume : ");
  876         s += _missingVolName;
  877         prop = s;
  878       }
  879       break;
  880     }
  881 
  882     case kpidErrorFlags:
  883     {
  884       UInt32 v = _errorFlags;
  885       if (!_isArc)
  886         v |= kpv_ErrorFlags_IsNotArc;
  887       prop = v;
  888       break;
  889     }
  890 
  891     case kpidWarningFlags:
  892     {
  893       if (_warningFlags != 0)
  894         prop = _warningFlags;
  895       break;
  896     }
  897 
  898     case kpidExtension:
  899       if (_arcs.Size() == 1)
  900       {
  901         if (_arcInfo.Is_VolNumber_Defined())
  902         {
  903           char sz[16];
  904           ConvertUInt32ToString((UInt32)_arcInfo.VolNumber + 1, sz);
  905           unsigned len = MyStringLen(sz);
  906           AString s = "part";
  907           for (; len < 2; len++)
  908             s += '0';
  909           s += sz;
  910           s += ".rar";
  911           prop = s;
  912         }
  913       }
  914       break;
  915   }
  916   prop.Detach(value);
  917   return S_OK;
  918   COM_TRY_END
  919 }
  920 
  921 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
  922 {
  923   *numItems = _refItems.Size();
  924   return S_OK;
  925 }
  926 
  927 static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
  928 {
  929   if (!NTime::DosTimeToFileTime(rarTime.DosTime, result))
  930     return false;
  931   UInt64 value =  (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;
  932   value += (UInt64)rarTime.LowSecond * 10000000;
  933   value += ((UInt64)rarTime.SubTime[2] << 16) +
  934     ((UInt64)rarTime.SubTime[1] << 8) +
  935     ((UInt64)rarTime.SubTime[0]);
  936   result.dwLowDateTime = (DWORD)value;
  937   result.dwHighDateTime = DWORD(value >> 32);
  938   return true;
  939 }
  940 
  941 static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop)
  942 {
  943   FILETIME localFileTime, utcFileTime;
  944   if (RarTimeToFileTime(rarTime, localFileTime))
  945   {
  946     if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
  947       utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
  948   }
  949   else
  950     utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
  951   prop = utcFileTime;
  952 }
  953 
  954 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
  955 {
  956   COM_TRY_BEGIN
  957   NCOM::CPropVariant prop;
  958   const CRefItem &refItem = _refItems[index];
  959   const CItem &item = _items[refItem.ItemIndex];
  960   const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
  961 
  962   /*
  963   const CItem *mainItem = &item;
  964   if (item.BaseFileIndex >= 0)
  965     mainItem = &_items[_refItems[item.BaseFileIndex].ItemIndex];
  966   */
  967   switch (propID)
  968   {
  969     case kpidPath:
  970     {
  971       /*
  972       UString u;
  973       if (item.BaseFileIndex >= 0)
  974         u = mainItem->GetName();
  975       u += item.GetName();
  976       */
  977       prop = (const wchar_t *)NItemName::WinNameToOSName(item.GetName());
  978       break;
  979     }
  980     case kpidIsDir: prop = item.IsDir(); break;
  981     case kpidSize: if (lastItem.Is_Size_Defined()) prop = lastItem.Size; break;
  982     case kpidPackSize: prop = GetPackSize(index); break;
  983     case kpidMTime: RarTimeToProp(item.MTime, prop); break;
  984     case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break;
  985     case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break;
  986     case kpidAttrib: prop = item.GetWinAttrib(); break;
  987     case kpidEncrypted: prop = item.IsEncrypted(); break;
  988     case kpidSolid: prop = IsSolid(index); break;
  989     case kpidCommented: prop = item.IsCommented(); break;
  990     case kpidSplitBefore: prop = item.IsSplitBefore(); break;
  991     case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break;
  992     case kpidCRC:
  993     {
  994       prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC);
  995       break;
  996     }
  997     case kpidUnpackVer: prop = item.UnPackVersion; break;
  998     case kpidMethod:
  999     {
 1000       char s[16];
 1001       Byte m = item.Method;
 1002       if (m < (Byte)'0' || m > (Byte)'5')
 1003         ConvertUInt32ToString(m, s);
 1004       else
 1005       {
 1006         s[0] = 'm';
 1007         s[1] = (char)m;
 1008         s[2] = 0;
 1009         if (!item.IsDir())
 1010         {
 1011           s[2] = ':';
 1012           ConvertUInt32ToString(16 + item.GetDictSize(), &s[3]);
 1013         }
 1014       }
 1015       prop = s;
 1016       break;
 1017     }
 1018     case kpidHostOS: prop = (item.HostOS < ARRAY_SIZE(kHostOS)) ? kHostOS[item.HostOS] : kUnknownOS; break;
 1019   }
 1020   prop.Detach(value);
 1021   return S_OK;
 1022   COM_TRY_END
 1023 }
 1024 
 1025 
 1026 HRESULT CHandler::Open2(IInStream *stream,
 1027     const UInt64 *maxCheckStartPosition,
 1028     IArchiveOpenCallback *openCallback)
 1029 {
 1030   {
 1031     CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
 1032     CMyComPtr<ICryptoGetTextPassword> getTextPassword;
 1033     
 1034     CVolumeName seqName;
 1035 
 1036     UInt64 totalBytes = 0;
 1037     UInt64 curBytes = 0;
 1038 
 1039     if (openCallback)
 1040     {
 1041       openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
 1042       openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
 1043     }
 1044 
 1045     bool nextVol_is_Required = false;
 1046 
 1047     CInArchive archive;
 1048 
 1049     for (;;)
 1050     {
 1051       CMyComPtr<IInStream> inStream;
 1052       if (!_arcs.IsEmpty())
 1053       {
 1054         if (!openVolumeCallback)
 1055           break;
 1056         
 1057         if (_arcs.Size() == 1)
 1058         {
 1059           if (!_arcInfo.IsVolume())
 1060             break;
 1061           UString baseName;
 1062           {
 1063             NCOM::CPropVariant prop;
 1064             RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
 1065             if (prop.vt != VT_BSTR)
 1066               break;
 1067             baseName = prop.bstrVal;
 1068           }
 1069           if (!seqName.InitName(baseName, _arcInfo.HaveNewVolumeName()))
 1070             break;
 1071           /*
 1072           if (_arcInfo.HaveNewVolumeName() && !_arcInfo.IsFirstVolume())
 1073           {
 1074             seqName.MakeBeforeFirstName();
 1075           }
 1076           */
 1077         }
 1078 
 1079         const UString volName = seqName.GetNextName();
 1080         
 1081         HRESULT result = openVolumeCallback->GetStream(volName, &inStream);
 1082 
 1083         if (result != S_OK && result != S_FALSE)
 1084           return result;
 1085 
 1086         if (!inStream || result != S_OK)
 1087         {
 1088           if (nextVol_is_Required)
 1089             _missingVolName = volName;
 1090           break;
 1091         }
 1092       }
 1093       else
 1094         inStream = stream;
 1095 
 1096       UInt64 endPos = 0;
 1097       RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
 1098       RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
 1099       if (openCallback)
 1100       {
 1101         totalBytes += endPos;
 1102         RINOK(openCallback->SetTotal(NULL, &totalBytes));
 1103       }
 1104       
 1105       RINOK(archive.Open(inStream, maxCheckStartPosition));
 1106       _isArc = true;
 1107       CItem item;
 1108       
 1109       for (;;)
 1110       {
 1111         if (archive.m_Position > endPos)
 1112         {
 1113           _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
 1114           break;
 1115         }
 1116         
 1117         EErrorType error;
 1118         // bool decryptionError;
 1119         // AString errorMessageLoc;
 1120         bool filled;
 1121         HRESULT result = archive.GetNextItem(item, getTextPassword, filled, error);
 1122         
 1123         if (error != k_ErrorType_OK)
 1124         {
 1125           if (error == k_ErrorType_UnexpectedEnd)
 1126             _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
 1127           else if (error == k_ErrorType_Corrupted)
 1128             _errorFlags |= kpv_ErrorFlags_HeadersError;
 1129           else if (error == k_ErrorType_DecryptionError)
 1130             _errorFlags |= kpv_ErrorFlags_EncryptedHeadersError;
 1131 
 1132           // AddErrorMessage(errorMessageLoc);
 1133         }
 1134         RINOK(result);
 1135         
 1136         if (!filled)
 1137         {
 1138           if (error == k_ErrorType_DecryptionError && _items.IsEmpty())
 1139             return S_FALSE;
 1140 
 1141           if (archive.ArcInfo.ExtraZeroTail_is_Possible())
 1142           {
 1143             /* if there is recovery record for multivolume archive,
 1144                RAR adds 18 bytes (ZERO bytes) at the end for alignment.
 1145                We must skip these bytes to prevent phySize warning. */
 1146             RINOK(inStream->Seek(archive.ArcInfo.EndPos, STREAM_SEEK_SET, NULL));
 1147             bool areThereNonZeros;
 1148             UInt64 numZeros;
 1149             const UInt64 maxSize = 1 << 12;
 1150             RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize));
 1151             if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize)
 1152               archive.ArcInfo.EndPos += numZeros;
 1153           }
 1154           break;
 1155         }
 1156         
 1157         if (item.IgnoreItem())
 1158           continue;
 1159 
 1160         bool needAdd = true;
 1161         
 1162         if (item.IsSplitBefore())
 1163         {
 1164           if (!_refItems.IsEmpty())
 1165           {
 1166             CRefItem &refItem = _refItems.Back();
 1167             refItem.NumItems++;
 1168             needAdd = false;
 1169           }
 1170         }
 1171         
 1172         if (needAdd)
 1173         {
 1174           CRefItem refItem;
 1175           refItem.ItemIndex = _items.Size();
 1176           refItem.NumItems = 1;
 1177           refItem.VolumeIndex = _arcs.Size();
 1178           _refItems.Add(refItem);
 1179         }
 1180 
 1181         _items.Add(item);
 1182         
 1183         if (openCallback && _items.Size() % 100 == 0)
 1184         {
 1185           UInt64 numFiles = _items.Size();
 1186           UInt64 numBytes = curBytes + item.Position;
 1187           RINOK(openCallback->SetCompleted(&numFiles, &numBytes));
 1188         }
 1189       }
 1190 
 1191       if (archive.HeaderErrorWarning)
 1192         _warningFlags |= kpv_ErrorFlags_HeadersError;
 1193 
 1194       /*
 1195       if (archive.m_Position < endPos)
 1196         _warningFlags |= kpv_ErrorFlags_DataAfterEnd;
 1197       */
 1198       if (_arcs.IsEmpty())
 1199         _arcInfo = archive.ArcInfo;
 1200       // _arcInfo.EndPos = archive.EndPos;
 1201 
 1202       curBytes += endPos;
 1203       {
 1204         CArc &arc = _arcs.AddNew();
 1205         arc.PhySize = archive.ArcInfo.GetPhySize();
 1206         arc.Stream = inStream;
 1207       }
 1208 
 1209       nextVol_is_Required = false;
 1210 
 1211       if (!archive.ArcInfo.IsVolume())
 1212         break;
 1213 
 1214       if (archive.ArcInfo.EndOfArchive_was_Read)
 1215       {
 1216         if (!archive.ArcInfo.AreMoreVolumes())
 1217           break;
 1218         nextVol_is_Required = true;
 1219       }
 1220     }
 1221   }
 1222 
 1223   /*
 1224   int baseFileIndex = -1;
 1225   for (unsigned i = 0; i < _refItems.Size(); i++)
 1226   {
 1227     CItem &item = _items[_refItems[i].ItemIndex];
 1228     if (item.IsAltStream)
 1229       item.BaseFileIndex = baseFileIndex;
 1230     else
 1231       baseFileIndex = i;
 1232   }
 1233   */
 1234   return S_OK;
 1235 }
 1236 
 1237 STDMETHODIMP CHandler::Open(IInStream *stream,
 1238     const UInt64 *maxCheckStartPosition,
 1239     IArchiveOpenCallback *openCallback)
 1240 {
 1241   COM_TRY_BEGIN
 1242   Close();
 1243   // try
 1244   {
 1245     HRESULT res = Open2(stream, maxCheckStartPosition, openCallback);
 1246     /*
 1247     if (res != S_OK)
 1248       Close();
 1249     */
 1250 
 1251     return res;
 1252   }
 1253   // catch(const CInArchiveException &) { Close(); return S_FALSE; }
 1254   // catch(...) { Close(); throw; }
 1255   COM_TRY_END
 1256 }
 1257 
 1258 STDMETHODIMP CHandler::Close()
 1259 {
 1260   COM_TRY_BEGIN
 1261   // _errorMessage.Empty();
 1262   _missingVolName.Empty();
 1263   _errorFlags = 0;
 1264   _warningFlags = 0;
 1265   _isArc = false;
 1266   _refItems.Clear();
 1267   _items.Clear();
 1268   _arcs.Clear();
 1269   return S_OK;
 1270   COM_TRY_END
 1271 }
 1272 
 1273 struct CMethodItem
 1274 {
 1275   Byte RarUnPackVersion;
 1276   CMyComPtr<ICompressCoder> Coder;
 1277 };
 1278 
 1279 
 1280 class CVolsInStream:
 1281   public ISequentialInStream,
 1282   public CMyUnknownImp
 1283 {
 1284   UInt64 _rem;
 1285   ISequentialInStream *_stream;
 1286   const CObjectVector<CArc> *_arcs;
 1287   const CObjectVector<CItem> *_items;
 1288   CRefItem _refItem;
 1289   unsigned _curIndex;
 1290   UInt32 _crc;
 1291   bool _calcCrc;
 1292 
 1293 public:
 1294   MY_UNKNOWN_IMP
 1295 
 1296   STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
 1297   
 1298   void Init(const CObjectVector<CArc> *arcs,
 1299       const CObjectVector<CItem> *items,
 1300       const CRefItem &refItem)
 1301   {
 1302     _arcs = arcs;
 1303     _items = items;
 1304     _refItem = refItem;
 1305     _curIndex = 0;
 1306     _stream = NULL;
 1307     CrcIsOK = true;
 1308   }
 1309 
 1310   bool CrcIsOK;
 1311 };
 1312 
 1313 
 1314 STDMETHODIMP CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
 1315 {
 1316   if (processedSize)
 1317     *processedSize = 0;
 1318   UInt32 realProcessedSize = 0;
 1319 
 1320   while (size != 0)
 1321   {
 1322     if (!_stream)
 1323     {
 1324       if (_curIndex >= _refItem.NumItems)
 1325         break;
 1326       const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
 1327       IInStream *s = (*_arcs)[_refItem.VolumeIndex + _curIndex].Stream;
 1328       RINOK(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
 1329       _stream = s;
 1330       _calcCrc = (CrcIsOK && item.IsSplitAfter());
 1331       _crc = CRC_INIT_VAL;
 1332       _rem = item.PackSize;
 1333     }
 1334     {
 1335       UInt32 cur = size;
 1336       if (cur > _rem)
 1337         cur = (UInt32)_rem;
 1338       UInt32 num = cur;
 1339       HRESULT res = _stream->Read(data, cur, &cur);
 1340       if (_calcCrc)
 1341         _crc = CrcUpdate(_crc, data, cur);
 1342       realProcessedSize += cur;
 1343       if (processedSize)
 1344         *processedSize = realProcessedSize;
 1345       data = (Byte *)data + cur;
 1346       size -= cur;
 1347       _rem -= cur;
 1348       if (_rem == 0)
 1349       {
 1350         const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
 1351         _curIndex++;
 1352         if (_calcCrc && CRC_GET_DIGEST(_crc) != item.FileCRC)
 1353           CrcIsOK = false;
 1354         _stream = NULL;
 1355       }
 1356       if (res != S_OK)
 1357         return res;
 1358       if (realProcessedSize != 0)
 1359         return S_OK;
 1360       if (cur == 0 && num != 0)
 1361         return S_OK;
 1362     }
 1363   }
 1364 
 1365   return S_OK;
 1366 }
 1367 
 1368 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
 1369     Int32 testMode, IArchiveExtractCallback *extractCallback)
 1370 {
 1371   COM_TRY_BEGIN
 1372   CMyComPtr<ICryptoGetTextPassword> getTextPassword;
 1373   UInt64 censoredTotalUnPacked = 0,
 1374         // censoredTotalPacked = 0,
 1375         importantTotalUnPacked = 0;
 1376         // importantTotalPacked = 0;
 1377   bool allFilesMode = (numItems == (UInt32)(Int32)-1);
 1378   if (allFilesMode)
 1379     numItems = _refItems.Size();
 1380   if (numItems == 0)
 1381     return S_OK;
 1382   unsigned lastIndex = 0;
 1383   CRecordVector<unsigned> importantIndexes;
 1384   CRecordVector<bool> extractStatuses;
 1385 
 1386   bool isThereUndefinedSize = false;
 1387 
 1388   for (UInt32 t = 0; t < numItems; t++)
 1389   {
 1390     unsigned index = allFilesMode ? t : indices[t];
 1391     
 1392     {
 1393       const CRefItem &refItem = _refItems[index];
 1394       const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1];
 1395       
 1396       if (item.Is_Size_Defined())
 1397         censoredTotalUnPacked += item.Size;
 1398       else
 1399         isThereUndefinedSize = true;
 1400       
 1401       // censoredTotalPacked += item.PackSize;
 1402     }
 1403     
 1404     unsigned j;
 1405     for (j = lastIndex; j <= index; j++)
 1406       // if (!_items[_refItems[j].ItemIndex].IsSolid())
 1407       if (!IsSolid(j))
 1408         lastIndex = j;
 1409   
 1410     for (j = lastIndex; j <= index; j++)
 1411     {
 1412       const CRefItem &refItem = _refItems[j];
 1413       const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1];
 1414 
 1415       if (item.Is_Size_Defined())
 1416         importantTotalUnPacked += item.Size;
 1417       else
 1418         isThereUndefinedSize = true;
 1419       // importantTotalPacked += item.PackSize;
 1420       importantIndexes.Add(j);
 1421       extractStatuses.Add(j == index);
 1422     }
 1423 
 1424     lastIndex = index + 1;
 1425   }
 1426 
 1427   if (importantTotalUnPacked != 0 || !isThereUndefinedSize)
 1428   {
 1429     RINOK(extractCallback->SetTotal(importantTotalUnPacked));
 1430   }
 1431 
 1432   UInt64 currentImportantTotalUnPacked = 0;
 1433   UInt64 currentImportantTotalPacked = 0;
 1434   UInt64 currentUnPackSize, currentPackSize;
 1435 
 1436   CObjectVector<CMethodItem> methodItems;
 1437 
 1438   NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
 1439   CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
 1440 
 1441   CFilterCoder *filterStreamSpec = new CFilterCoder(false);
 1442   CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
 1443 
 1444   NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL;
 1445   CMyComPtr<ICompressFilter> rar20CryptoDecoder;
 1446   NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL;
 1447   CMyComPtr<ICompressFilter> rar3CryptoDecoder;
 1448 
 1449   CVolsInStream *volsInStreamSpec = NULL;
 1450   CMyComPtr<ISequentialInStream> volsInStream;
 1451 
 1452   CLocalProgress *lps = new CLocalProgress;
 1453   CMyComPtr<ICompressProgressInfo> progress = lps;
 1454   lps->Init(extractCallback, false);
 1455 
 1456   bool solidStart = true;
 1457   
 1458   for (unsigned i = 0;;
 1459       i++,
 1460       currentImportantTotalUnPacked += currentUnPackSize,
 1461       currentImportantTotalPacked += currentPackSize)
 1462   {
 1463     lps->InSize = currentImportantTotalPacked;
 1464     lps->OutSize = currentImportantTotalUnPacked;
 1465     RINOK(lps->SetCur());
 1466 
 1467     if (i >= importantIndexes.Size())
 1468       break;
 1469 
 1470     CMyComPtr<ISequentialOutStream> realOutStream;
 1471 
 1472     Int32 askMode;
 1473     if (extractStatuses[i])
 1474       askMode = testMode ?
 1475           NExtract::NAskMode::kTest :
 1476           NExtract::NAskMode::kExtract;
 1477     else
 1478       askMode = NExtract::NAskMode::kSkip;
 1479 
 1480     UInt32 index = importantIndexes[i];
 1481 
 1482     const CRefItem &refItem = _refItems[index];
 1483     const CItem &item = _items[refItem.ItemIndex];
 1484     const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
 1485     
 1486     UInt64 outSize = (UInt64)(Int64)-1;
 1487     currentUnPackSize = 0;
 1488     if (lastItem.Is_Size_Defined())
 1489     {
 1490       outSize = lastItem.Size;
 1491       currentUnPackSize = outSize;
 1492     }
 1493 
 1494     currentPackSize = GetPackSize(index);
 1495 
 1496     if (item.IgnoreItem())
 1497       continue;
 1498 
 1499     RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
 1500 
 1501     if (!IsSolid(index))
 1502       solidStart = true;
 1503     if (item.IsDir())
 1504     {
 1505       RINOK(extractCallback->PrepareOperation(askMode));
 1506       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
 1507       continue;
 1508     }
 1509 
 1510     bool mustBeProcessedAnywhere = false;
 1511     if (i < importantIndexes.Size() - 1)
 1512     {
 1513       // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
 1514       // const CItem &nextItemInfo = _items[nextRefItem.ItemIndex];
 1515       // mustBeProcessedAnywhere = nextItemInfo.IsSolid();
 1516       mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
 1517     }
 1518     
 1519     if (!mustBeProcessedAnywhere && !testMode && !realOutStream)
 1520       continue;
 1521     
 1522     if (!realOutStream && !testMode)
 1523       askMode = NExtract::NAskMode::kSkip;
 1524 
 1525     RINOK(extractCallback->PrepareOperation(askMode));
 1526 
 1527     COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
 1528     CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
 1529     outStreamSpec->SetStream(realOutStream);
 1530     outStreamSpec->Init();
 1531     realOutStream.Release();
 1532     
 1533     if (!volsInStream)
 1534     {
 1535       volsInStreamSpec = new CVolsInStream;
 1536       volsInStream = volsInStreamSpec;
 1537     }
 1538 
 1539     volsInStreamSpec->Init(&_arcs, &_items, refItem);
 1540 
 1541     UInt64 packSize = currentPackSize;
 1542 
 1543     // packedPos += item.PackSize;
 1544     // unpackedPos += 0;
 1545     
 1546     CMyComPtr<ISequentialInStream> inStream;
 1547     
 1548     if (item.IsEncrypted())
 1549     {
 1550       // CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
 1551       
 1552       if (item.UnPackVersion >= 29)
 1553       {
 1554         if (!rar3CryptoDecoder)
 1555         {
 1556           rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder;
 1557           rar3CryptoDecoder = rar3CryptoDecoderSpec;
 1558         }
 1559         // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
 1560         /*
 1561         CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
 1562         RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
 1563             &cryptoProperties));
 1564         */
 1565         RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
 1566         filterStreamSpec->Filter = rar3CryptoDecoder;
 1567       }
 1568       else if (item.UnPackVersion >= 20)
 1569       {
 1570         if (!rar20CryptoDecoder)
 1571         {
 1572           rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder;
 1573           rar20CryptoDecoder = rar20CryptoDecoderSpec;
 1574         }
 1575         filterStreamSpec->Filter = rar20CryptoDecoder;
 1576       }
 1577       else
 1578       {
 1579         outStream.Release();
 1580         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
 1581         continue;
 1582       }
 1583       
 1584       // RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
 1585 
 1586       if (!getTextPassword)
 1587         extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
 1588 
 1589       if (!getTextPassword)
 1590       {
 1591         outStream.Release();
 1592         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
 1593         continue;
 1594       }
 1595 
 1596       // if (getTextPassword)
 1597       {
 1598         CMyComBSTR password;
 1599         RINOK(getTextPassword->CryptoGetTextPassword(&password));
 1600         
 1601         if (item.UnPackVersion >= 29)
 1602         {
 1603           unsigned len = 0;
 1604           if (password)
 1605             len = MyStringLen(password);
 1606           if (len > kPasswordLen_MAX)
 1607             len = kPasswordLen_MAX;
 1608           CByteArr buffer(len * 2);
 1609           for (unsigned k = 0; k < len; k++)
 1610           {
 1611             wchar_t c = password[k];
 1612             ((Byte *)buffer)[k * 2] = (Byte)c;
 1613             ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8);
 1614           }
 1615           rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2);
 1616         }
 1617         else
 1618         {
 1619           AString oemPassword;
 1620           if (password)
 1621           {
 1622             UString unicode = (LPCOLESTR)password;
 1623             if (unicode.Len() > kPasswordLen_MAX)
 1624               unicode.DeleteFrom(kPasswordLen_MAX);
 1625             oemPassword = UnicodeStringToMultiByte(unicode, CP_OEMCP);
 1626           }
 1627           rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len());
 1628         }
 1629       }
 1630       /*
 1631       else
 1632       {
 1633         RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0));
 1634       }
 1635       */
 1636       
 1637       filterStreamSpec->SetInStream(volsInStream);
 1638       filterStreamSpec->SetOutStreamSize(NULL);
 1639       inStream = filterStream;
 1640     }
 1641     else
 1642     {
 1643       inStream = volsInStream;
 1644     }
 1645     
 1646     CMyComPtr<ICompressCoder> commonCoder;
 1647     
 1648     switch (item.Method)
 1649     {
 1650       case '0':
 1651       {
 1652         commonCoder = copyCoder;
 1653         break;
 1654       }
 1655       case '1':
 1656       case '2':
 1657       case '3':
 1658       case '4':
 1659       case '5':
 1660       {
 1661         unsigned m;
 1662         for (m = 0; m < methodItems.Size(); m++)
 1663           if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
 1664             break;
 1665         if (m == methodItems.Size())
 1666         {
 1667           CMethodItem mi;
 1668           mi.RarUnPackVersion = item.UnPackVersion;
 1669 
 1670           mi.Coder.Release();
 1671           if (item.UnPackVersion <= 40)
 1672           {
 1673             UInt32 methodID = 0x40300;
 1674             if (item.UnPackVersion < 20)
 1675               methodID += 1;
 1676             else if (item.UnPackVersion < 29)
 1677               methodID += 2;
 1678             else
 1679               methodID += 3;
 1680             RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, false, mi.Coder));
 1681           }
 1682          
 1683           if (mi.Coder == 0)
 1684           {
 1685             outStream.Release();
 1686             RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
 1687             continue;
 1688           }
 1689 
 1690           m = methodItems.Add(mi);
 1691         }
 1692         CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;
 1693 
 1694         CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
 1695         RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
 1696             &compressSetDecoderProperties));
 1697         
 1698         Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
 1699         if (solidStart)
 1700         {
 1701           isSolid = 0;
 1702           solidStart = false;
 1703         }
 1704 
 1705 
 1706         RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));
 1707           
 1708         commonCoder = decoder;
 1709         break;
 1710       }
 1711       default:
 1712         outStream.Release();
 1713         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
 1714         continue;
 1715     }
 1716     
 1717     HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, progress);
 1718     
 1719     if (item.IsEncrypted())
 1720       filterStreamSpec->ReleaseInStream();
 1721     
 1722     if (outSize == (UInt64)(Int64)-1)
 1723       currentUnPackSize = outStreamSpec->GetSize();
 1724 
 1725     int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ?
 1726         NExtract::NOperationResult::kOK:
 1727         NExtract::NOperationResult::kCRCError;
 1728     outStream.Release();
 1729 
 1730     if (result != S_OK)
 1731     {
 1732       if (result == S_FALSE)
 1733         opRes = NExtract::NOperationResult::kDataError;
 1734       else if (result == E_NOTIMPL)
 1735         opRes = NExtract::NOperationResult::kUnsupportedMethod;
 1736       else
 1737         return result;
 1738     }
 1739     RINOK(extractCallback->SetOperationResult(opRes));
 1740   }
 1741   
 1742   return S_OK;
 1743   COM_TRY_END
 1744 }
 1745 
 1746 IMPL_ISetCompressCodecsInfo
 1747 
 1748 REGISTER_ARC_I(
 1749   "Rar", "rar r00", 0, 3,
 1750   kMarker,
 1751   0,
 1752   NArcInfoFlags::kFindSignature,
 1753   NULL)
 1754 
 1755 }}