"Fossies" - the Fresh Open Source Software Archive

Member "UXP-2019.06.08/other-licenses/7zstub/src/CPP/7zip/UI/Common/HashCalc.cpp" (8 Jun 2019, 8180 Bytes) of package /linux/www/UXP-2019.06.08.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.

    1 // HashCalc.cpp
    2 
    3 #include "StdAfx.h"
    4 
    5 #include "../../../../C/Alloc.h"
    6 
    7 #include "../../../Common/StringToInt.h"
    8 
    9 #include "../../Common/FileStreams.h"
   10 #include "../../Common/StreamUtils.h"
   11 
   12 #include "EnumDirItems.h"
   13 #include "HashCalc.h"
   14 
   15 using namespace NWindows;
   16 
   17 class CHashMidBuf
   18 {
   19   void *_data;
   20 public:
   21   CHashMidBuf(): _data(0) {}
   22   operator void *() { return _data; }
   23   bool Alloc(size_t size)
   24   {
   25     if (_data != 0)
   26       return false;
   27     _data = ::MidAlloc(size);
   28     return _data != 0;
   29   }
   30   ~CHashMidBuf() { ::MidFree(_data); }
   31 };
   32 
   33 static const char * const k_DefaultHashMethod = "CRC32";
   34 
   35 HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods)
   36 {
   37   UStringVector names = hashMethods;
   38   if (names.IsEmpty())
   39     names.Add(UString(k_DefaultHashMethod));
   40 
   41   CRecordVector<CMethodId> ids;
   42   CObjectVector<COneMethodInfo> methods;
   43   
   44   unsigned i;
   45   for (i = 0; i < names.Size(); i++)
   46   {
   47     COneMethodInfo m;
   48     RINOK(m.ParseMethodFromString(names[i]));
   49 
   50     if (m.MethodName.IsEmpty())
   51       m.MethodName = k_DefaultHashMethod;
   52     
   53     if (m.MethodName == "*")
   54     {
   55       CRecordVector<CMethodId> tempMethods;
   56       GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
   57       methods.Clear();
   58       ids.Clear();
   59       FOR_VECTOR (t, tempMethods)
   60       {
   61         unsigned index = ids.AddToUniqueSorted(tempMethods[t]);
   62         if (ids.Size() != methods.Size())
   63           methods.Insert(index, m);
   64       }
   65       break;
   66     }
   67     else
   68     {
   69       // m.MethodName.RemoveChar(L'-');
   70       CMethodId id;
   71       if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id))
   72         return E_NOTIMPL;
   73       unsigned index = ids.AddToUniqueSorted(id);
   74       if (ids.Size() != methods.Size())
   75         methods.Insert(index, m);
   76     }
   77   }
   78 
   79   for (i = 0; i < ids.Size(); i++)
   80   {
   81     CMyComPtr<IHasher> hasher;
   82     AString name;
   83     RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher));
   84     if (!hasher)
   85       throw "Can't create hasher";
   86     const COneMethodInfo &m = methods[i];
   87     {
   88       CMyComPtr<ICompressSetCoderProperties> scp;
   89       hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
   90       if (scp)
   91         RINOK(m.SetCoderProps(scp, NULL));
   92     }
   93     UInt32 digestSize = hasher->GetDigestSize();
   94     if (digestSize > k_HashCalc_DigestSize_Max)
   95       return E_NOTIMPL;
   96     CHasherState &h = Hashers.AddNew();
   97     h.Hasher = hasher;
   98     h.Name = name;
   99     h.DigestSize = digestSize;
  100     for (unsigned k = 0; k < k_HashCalc_NumGroups; k++)
  101       memset(h.Digests[k], 0, digestSize);
  102   }
  103 
  104   return S_OK;
  105 }
  106 
  107 void CHashBundle::InitForNewFile()
  108 {
  109   CurSize = 0;
  110   FOR_VECTOR (i, Hashers)
  111   {
  112     CHasherState &h = Hashers[i];
  113     h.Hasher->Init();
  114     memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize);
  115   }
  116 }
  117 
  118 void CHashBundle::Update(const void *data, UInt32 size)
  119 {
  120   CurSize += size;
  121   FOR_VECTOR (i, Hashers)
  122     Hashers[i].Hasher->Update(data, size);
  123 }
  124 
  125 void CHashBundle::SetSize(UInt64 size)
  126 {
  127   CurSize = size;
  128 }
  129 
  130 static void AddDigests(Byte *dest, const Byte *src, UInt32 size)
  131 {
  132   unsigned next = 0;
  133   for (UInt32 i = 0; i < size; i++)
  134   {
  135     next += (unsigned)dest[i] + (unsigned)src[i];
  136     dest[i] = (Byte)next;
  137     next >>= 8;
  138   }
  139 }
  140 
  141 void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path)
  142 {
  143   if (isDir)
  144     NumDirs++;
  145   else if (isAltStream)
  146   {
  147     NumAltStreams++;
  148     AltStreamsSize += CurSize;
  149   }
  150   else
  151   {
  152     NumFiles++;
  153     FilesSize += CurSize;
  154   }
  155 
  156   Byte pre[16];
  157   memset(pre, 0, sizeof(pre));
  158   if (isDir)
  159     pre[0] = 1;
  160   
  161   FOR_VECTOR (i, Hashers)
  162   {
  163     CHasherState &h = Hashers[i];
  164     if (!isDir)
  165     {
  166       h.Hasher->Final(h.Digests[0]);
  167       if (!isAltStream)
  168         AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize);
  169     }
  170 
  171     h.Hasher->Init();
  172     h.Hasher->Update(pre, sizeof(pre));
  173     h.Hasher->Update(h.Digests[0], h.DigestSize);
  174     
  175     for (unsigned k = 0; k < path.Len(); k++)
  176     {
  177       wchar_t c = path[k];
  178       Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) };
  179       h.Hasher->Update(temp, 2);
  180     }
  181   
  182     Byte tempDigest[k_HashCalc_DigestSize_Max];
  183     h.Hasher->Final(tempDigest);
  184     if (!isAltStream)
  185       AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize);
  186     AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize);
  187   }
  188 }
  189 
  190 
  191 HRESULT HashCalc(
  192     DECL_EXTERNAL_CODECS_LOC_VARS
  193     const NWildcard::CCensor &censor,
  194     const CHashOptions &options,
  195     AString &errorInfo,
  196     IHashCallbackUI *callback)
  197 {
  198   CDirItems dirItems;
  199   dirItems.Callback = callback;
  200 
  201   if (options.StdInMode)
  202   {
  203     CDirItem di;
  204     di.Size = (UInt64)(Int64)-1;
  205     di.Attrib = 0;
  206     di.MTime.dwLowDateTime = 0;
  207     di.MTime.dwHighDateTime = 0;
  208     di.CTime = di.ATime = di.MTime;
  209     dirItems.Items.Add(di);
  210   }
  211   else
  212   {
  213     RINOK(callback->StartScanning());
  214     dirItems.ScanAltStreams = options.AltStreamsMode;
  215 
  216     HRESULT res = EnumerateItems(censor,
  217         options.PathMode,
  218         UString(),
  219         dirItems);
  220     
  221     if (res != S_OK)
  222     {
  223       if (res != E_ABORT)
  224         errorInfo = "Scanning error";
  225       return res;
  226     }
  227     RINOK(callback->FinishScanning(dirItems.Stat));
  228   }
  229 
  230   unsigned i;
  231   CHashBundle hb;
  232   RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods));
  233   hb.Init();
  234 
  235   hb.NumErrors = dirItems.Stat.NumErrors;
  236   
  237   if (options.StdInMode)
  238   {
  239     RINOK(callback->SetNumFiles(1));
  240   }
  241   else
  242   {
  243     RINOK(callback->SetTotal(dirItems.Stat.GetTotalBytes()));
  244   }
  245 
  246   const UInt32 kBufSize = 1 << 15;
  247   CHashMidBuf buf;
  248   if (!buf.Alloc(kBufSize))
  249     return E_OUTOFMEMORY;
  250 
  251   UInt64 completeValue = 0;
  252 
  253   RINOK(callback->BeforeFirstFile(hb));
  254 
  255   for (i = 0; i < dirItems.Items.Size(); i++)
  256   {
  257     CMyComPtr<ISequentialInStream> inStream;
  258     UString path;
  259     bool isDir = false;
  260     bool isAltStream = false;
  261     if (options.StdInMode)
  262     {
  263       inStream = new CStdInFileStream;
  264     }
  265     else
  266     {
  267       CInFileStream *inStreamSpec = new CInFileStream;
  268       inStream = inStreamSpec;
  269       const CDirItem &dirItem = dirItems.Items[i];
  270       isDir = dirItem.IsDir();
  271       isAltStream = dirItem.IsAltStream;
  272       path = dirItems.GetLogPath(i);
  273       if (!isDir)
  274       {
  275         FString phyPath = dirItems.GetPhyPath(i);
  276         if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite))
  277         {
  278           HRESULT res = callback->OpenFileError(phyPath, ::GetLastError());
  279           hb.NumErrors++;
  280           if (res != S_FALSE)
  281             return res;
  282           continue;
  283         }
  284       }
  285     }
  286     RINOK(callback->GetStream(path, isDir));
  287     UInt64 fileSize = 0;
  288 
  289     hb.InitForNewFile();
  290     if (!isDir)
  291     {
  292       for (UInt32 step = 0;; step++)
  293       {
  294         if ((step & 0xFF) == 0)
  295           RINOK(callback->SetCompleted(&completeValue));
  296         UInt32 size;
  297         RINOK(inStream->Read(buf, kBufSize, &size));
  298         if (size == 0)
  299           break;
  300         hb.Update(buf, size);
  301         fileSize += size;
  302         completeValue += size;
  303       }
  304     }
  305     hb.Final(isDir, isAltStream, path);
  306     RINOK(callback->SetOperationResult(fileSize, hb, !isDir));
  307     RINOK(callback->SetCompleted(&completeValue));
  308   }
  309   return callback->AfterLastFile(hb);
  310 }
  311 
  312 
  313 static inline char GetHex(unsigned v)
  314 {
  315   return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
  316 }
  317 
  318 void AddHashHexToString(char *dest, const Byte *data, UInt32 size)
  319 {
  320   dest[size * 2] = 0;
  321   
  322   if (!data)
  323   {
  324     for (UInt32 i = 0; i < size; i++)
  325     {
  326       dest[0] = ' ';
  327       dest[1] = ' ';
  328       dest += 2;
  329     }
  330     return;
  331   }
  332   
  333   int step = 2;
  334   if (size <= 8)
  335   {
  336     step = -2;
  337     dest += size * 2 - 2;
  338   }
  339   
  340   for (UInt32 i = 0; i < size; i++)
  341   {
  342     unsigned b = data[i];
  343     dest[0] = GetHex((b >> 4) & 0xF);
  344     dest[1] = GetHex(b & 0xF);
  345     dest += step;
  346   }
  347 }