Home | History | Annotate | Download | only in 7z
      1 // 7zHandler.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../../C/CpuArch.h"
      6 
      7 #include "../../../Common/ComTry.h"
      8 #include "../../../Common/IntToString.h"
      9 
     10 #ifndef __7Z_SET_PROPERTIES
     11 #include "../../../Windows/System.h"
     12 #endif
     13 
     14 #include "../Common/ItemNameUtils.h"
     15 
     16 #include "7zHandler.h"
     17 #include "7zProperties.h"
     18 
     19 #ifdef __7Z_SET_PROPERTIES
     20 #ifdef EXTRACT_ONLY
     21 #include "../Common/ParseProperties.h"
     22 #endif
     23 #endif
     24 
     25 using namespace NWindows;
     26 
     27 extern UString ConvertMethodIdToString(UInt64 id);
     28 
     29 namespace NArchive {
     30 namespace N7z {
     31 
     32 CHandler::CHandler()
     33 {
     34   _crcSize = 4;
     35 
     36   #ifndef _NO_CRYPTO
     37   _passwordIsDefined = false;
     38   #endif
     39 
     40   #ifdef EXTRACT_ONLY
     41   #ifdef __7Z_SET_PROPERTIES
     42   _numThreads = NSystem::GetNumberOfProcessors();
     43   #endif
     44   #else
     45   Init();
     46   #endif
     47 }
     48 
     49 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
     50 {
     51   *numItems = _db.Files.Size();
     52   return S_OK;
     53 }
     54 
     55 #ifdef _SFX
     56 
     57 IMP_IInArchive_ArcProps_NO
     58 
     59 STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
     60 {
     61   return E_NOTIMPL;
     62 }
     63 
     64 STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
     65       BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
     66 {
     67   return E_NOTIMPL;
     68 }
     69 
     70 
     71 #else
     72 
     73 STATPROPSTG kArcProps[] =
     74 {
     75   { NULL, kpidMethod, VT_BSTR},
     76   { NULL, kpidSolid, VT_BOOL},
     77   { NULL, kpidNumBlocks, VT_UI4},
     78   { NULL, kpidPhySize, VT_UI8},
     79   { NULL, kpidHeadersSize, VT_UI8},
     80   { NULL, kpidOffset, VT_UI8}
     81 };
     82 
     83 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
     84 {
     85   COM_TRY_BEGIN
     86   NCOM::CPropVariant prop;
     87   switch(propID)
     88   {
     89     case kpidMethod:
     90     {
     91       UString resString;
     92       CRecordVector<UInt64> ids;
     93       int i;
     94       for (i = 0; i < _db.Folders.Size(); i++)
     95       {
     96         const CFolder &f = _db.Folders[i];
     97         for (int j = f.Coders.Size() - 1; j >= 0; j--)
     98           ids.AddToUniqueSorted(f.Coders[j].MethodID);
     99       }
    100 
    101       for (i = 0; i < ids.Size(); i++)
    102       {
    103         UInt64 id = ids[i];
    104         UString methodName;
    105         /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
    106         if (methodName.IsEmpty())
    107           methodName = ConvertMethodIdToString(id);
    108         if (!resString.IsEmpty())
    109           resString += L' ';
    110         resString += methodName;
    111       }
    112       prop = resString;
    113       break;
    114     }
    115     case kpidSolid: prop = _db.IsSolid(); break;
    116     case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break;
    117     case kpidHeadersSize:  prop = _db.HeadersSize; break;
    118     case kpidPhySize:  prop = _db.PhySize; break;
    119     case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break;
    120   }
    121   prop.Detach(value);
    122   return S_OK;
    123   COM_TRY_END
    124 }
    125 
    126 IMP_IInArchive_ArcProps
    127 
    128 #endif
    129 
    130 static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop)
    131 {
    132   UInt64 value;
    133   if (v.GetItem(index, value))
    134   {
    135     FILETIME ft;
    136     ft.dwLowDateTime = (DWORD)value;
    137     ft.dwHighDateTime = (DWORD)(value >> 32);
    138     prop = ft;
    139   }
    140 }
    141 
    142 #ifndef _SFX
    143 
    144 static UString ConvertUInt32ToString(UInt32 value)
    145 {
    146   wchar_t buffer[32];
    147   ConvertUInt64ToString(value, buffer);
    148   return buffer;
    149 }
    150 
    151 static UString GetStringForSizeValue(UInt32 value)
    152 {
    153   for (int i = 31; i >= 0; i--)
    154     if ((UInt32(1) << i) == value)
    155       return ConvertUInt32ToString(i);
    156   UString result;
    157   if (value % (1 << 20) == 0)
    158   {
    159     result += ConvertUInt32ToString(value >> 20);
    160     result += L"m";
    161   }
    162   else if (value % (1 << 10) == 0)
    163   {
    164     result += ConvertUInt32ToString(value >> 10);
    165     result += L"k";
    166   }
    167   else
    168   {
    169     result += ConvertUInt32ToString(value);
    170     result += L"b";
    171   }
    172   return result;
    173 }
    174 
    175 static const UInt64 k_Copy = 0x0;
    176 static const UInt64 k_Delta = 3;
    177 static const UInt64 k_LZMA2 = 0x21;
    178 static const UInt64 k_LZMA  = 0x030101;
    179 static const UInt64 k_PPMD  = 0x030401;
    180 
    181 static wchar_t GetHex(Byte value)
    182 {
    183   return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
    184 }
    185 static inline void AddHexToString(UString &res, Byte value)
    186 {
    187   res += GetHex((Byte)(value >> 4));
    188   res += GetHex((Byte)(value & 0xF));
    189 }
    190 
    191 #endif
    192 
    193 bool CHandler::IsEncrypted(UInt32 index2) const
    194 {
    195   CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
    196   if (folderIndex != kNumNoIndex)
    197     return _db.Folders[folderIndex].IsEncrypted();
    198   return false;
    199 }
    200 
    201 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value)
    202 {
    203   COM_TRY_BEGIN
    204   NCOM::CPropVariant prop;
    205 
    206   /*
    207   const CRef2 &ref2 = _refs[index];
    208   if (ref2.Refs.IsEmpty())
    209     return E_FAIL;
    210   const CRef &ref = ref2.Refs.Front();
    211   */
    212 
    213   const CFileItem &item = _db.Files[index];
    214   UInt32 index2 = index;
    215 
    216   switch(propID)
    217   {
    218     case kpidPath:
    219       if (!item.Name.IsEmpty())
    220         prop = NItemName::GetOSName(item.Name);
    221       break;
    222     case kpidIsDir:  prop = item.IsDir; break;
    223     case kpidSize:
    224     {
    225       prop = item.Size;
    226       // prop = ref2.Size;
    227       break;
    228     }
    229     case kpidPackSize:
    230     {
    231       // prop = ref2.PackSize;
    232       {
    233         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
    234         if (folderIndex != kNumNoIndex)
    235         {
    236           if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
    237             prop = _db.GetFolderFullPackSize(folderIndex);
    238           /*
    239           else
    240             prop = (UInt64)0;
    241           */
    242         }
    243         else
    244           prop = (UInt64)0;
    245       }
    246       break;
    247     }
    248     case kpidPosition:  { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; }
    249     case kpidCTime:  SetPropFromUInt64Def(_db.CTime, index2, prop); break;
    250     case kpidATime:  SetPropFromUInt64Def(_db.ATime, index2, prop); break;
    251     case kpidMTime:  SetPropFromUInt64Def(_db.MTime, index2, prop); break;
    252     case kpidAttrib:  if (item.AttribDefined) prop = item.Attrib; break;
    253     case kpidCRC:  if (item.CrcDefined) prop = item.Crc; break;
    254     case kpidEncrypted:  prop = IsEncrypted(index2); break;
    255     case kpidIsAnti:  prop = _db.IsItemAnti(index2); break;
    256     #ifndef _SFX
    257     case kpidMethod:
    258       {
    259         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
    260         if (folderIndex != kNumNoIndex)
    261         {
    262           const CFolder &folderInfo = _db.Folders[folderIndex];
    263           UString methodsString;
    264           for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
    265           {
    266             const CCoderInfo &coder = folderInfo.Coders[i];
    267             if (!methodsString.IsEmpty())
    268               methodsString += L' ';
    269 
    270             UString methodName, propsString;
    271             bool methodIsKnown = FindMethod(
    272               EXTERNAL_CODECS_VARS
    273               coder.MethodID, methodName);
    274 
    275             if (!methodIsKnown)
    276               methodsString += ConvertMethodIdToString(coder.MethodID);
    277             else
    278             {
    279               methodsString += methodName;
    280               if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1)
    281                 propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1);
    282               else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5)
    283               {
    284                 UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
    285                 propsString = GetStringForSizeValue(dicSize);
    286               }
    287               else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1)
    288               {
    289                 Byte p = coder.Props[0];
    290                 UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));
    291                 propsString = GetStringForSizeValue(dicSize);
    292               }
    293               else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5)
    294               {
    295                 Byte order = *(const Byte *)coder.Props;
    296                 propsString = L'o';
    297                 propsString += ConvertUInt32ToString(order);
    298                 propsString += L":mem";
    299                 UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
    300                 propsString += GetStringForSizeValue(dicSize);
    301               }
    302               else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1)
    303               {
    304                 const Byte *data = (const Byte *)coder.Props;
    305                 Byte firstByte = *data++;
    306                 UInt32 numCyclesPower = firstByte & 0x3F;
    307                 propsString = ConvertUInt32ToString(numCyclesPower);
    308                 /*
    309                 if ((firstByte & 0xC0) != 0)
    310                 {
    311                   UInt32 saltSize = (firstByte >> 7) & 1;
    312                   UInt32 ivSize = (firstByte >> 6) & 1;
    313                   if (coder.Props.GetCapacity() >= 2)
    314                   {
    315                     Byte secondByte = *data++;
    316                     saltSize += (secondByte >> 4);
    317                     ivSize += (secondByte & 0x0F);
    318                   }
    319                 }
    320                 */
    321               }
    322             }
    323             if (!propsString.IsEmpty())
    324             {
    325               methodsString += L':';
    326               methodsString += propsString;
    327             }
    328             else if (coder.Props.GetCapacity() > 0)
    329             {
    330               methodsString += L":[";
    331               for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++)
    332               {
    333                 if (bi > 5 && bi + 1 < coder.Props.GetCapacity())
    334                 {
    335                   methodsString += L"..";
    336                   break;
    337                 }
    338                 else
    339                   AddHexToString(methodsString, coder.Props[bi]);
    340               }
    341               methodsString += L']';
    342             }
    343           }
    344           prop = methodsString;
    345         }
    346       }
    347       break;
    348     case kpidBlock:
    349       {
    350         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
    351         if (folderIndex != kNumNoIndex)
    352           prop = (UInt32)folderIndex;
    353       }
    354       break;
    355     case kpidPackedSize0:
    356     case kpidPackedSize1:
    357     case kpidPackedSize2:
    358     case kpidPackedSize3:
    359     case kpidPackedSize4:
    360       {
    361         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
    362         if (folderIndex != kNumNoIndex)
    363         {
    364           const CFolder &folderInfo = _db.Folders[folderIndex];
    365           if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
    366               folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
    367           {
    368             prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
    369           }
    370           else
    371             prop = (UInt64)0;
    372         }
    373         else
    374           prop = (UInt64)0;
    375       }
    376       break;
    377     #endif
    378   }
    379   prop.Detach(value);
    380   return S_OK;
    381   COM_TRY_END
    382 }
    383 
    384 STDMETHODIMP CHandler::Open(IInStream *stream,
    385     const UInt64 *maxCheckStartPosition,
    386     IArchiveOpenCallback *openArchiveCallback)
    387 {
    388   COM_TRY_BEGIN
    389   Close();
    390   #ifndef _SFX
    391   _fileInfoPopIDs.Clear();
    392   #endif
    393   try
    394   {
    395     CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
    396 
    397     #ifndef _NO_CRYPTO
    398     CMyComPtr<ICryptoGetTextPassword> getTextPassword;
    399     if (openArchiveCallback)
    400     {
    401       openArchiveCallbackTemp.QueryInterface(
    402           IID_ICryptoGetTextPassword, &getTextPassword);
    403     }
    404     #endif
    405     CInArchive archive;
    406     RINOK(archive.Open(stream, maxCheckStartPosition));
    407     #ifndef _NO_CRYPTO
    408     _passwordIsDefined = false;
    409     UString password;
    410     #endif
    411     HRESULT result = archive.ReadDatabase(
    412       EXTERNAL_CODECS_VARS
    413       _db
    414       #ifndef _NO_CRYPTO
    415       , getTextPassword, _passwordIsDefined
    416       #endif
    417       );
    418     RINOK(result);
    419     _db.Fill();
    420     _inStream = stream;
    421   }
    422   catch(...)
    423   {
    424     Close();
    425     return S_FALSE;
    426   }
    427   // _inStream = stream;
    428   #ifndef _SFX
    429   FillPopIDs();
    430   #endif
    431   return S_OK;
    432   COM_TRY_END
    433 }
    434 
    435 STDMETHODIMP CHandler::Close()
    436 {
    437   COM_TRY_BEGIN
    438   _inStream.Release();
    439   _db.Clear();
    440   return S_OK;
    441   COM_TRY_END
    442 }
    443 
    444 #ifdef __7Z_SET_PROPERTIES
    445 #ifdef EXTRACT_ONLY
    446 
    447 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
    448 {
    449   COM_TRY_BEGIN
    450   const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
    451   _numThreads = numProcessors;
    452 
    453   for (int i = 0; i < numProperties; i++)
    454   {
    455     UString name = names[i];
    456     name.MakeUpper();
    457     if (name.IsEmpty())
    458       return E_INVALIDARG;
    459     const PROPVARIANT &value = values[i];
    460     UInt32 number;
    461     int index = ParseStringToUInt32(name, number);
    462     if (index == 0)
    463     {
    464       if(name.Left(2).CompareNoCase(L"MT") == 0)
    465       {
    466         RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
    467         continue;
    468       }
    469       else
    470         return E_INVALIDARG;
    471     }
    472   }
    473   return S_OK;
    474   COM_TRY_END
    475 }
    476 
    477 #endif
    478 #endif
    479 
    480 IMPL_ISetCompressCodecsInfo
    481 
    482 }}
    483