1370b324cSopenharmony_ci// HashCalc.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../../../C/Alloc.h"
6370b324cSopenharmony_ci#include "../../../../C/CpuArch.h"
7370b324cSopenharmony_ci
8370b324cSopenharmony_ci#include "../../../Common/DynLimBuf.h"
9370b324cSopenharmony_ci#include "../../../Common/IntToString.h"
10370b324cSopenharmony_ci#include "../../../Common/StringToInt.h"
11370b324cSopenharmony_ci
12370b324cSopenharmony_ci#include "../../Common/FileStreams.h"
13370b324cSopenharmony_ci#include "../../Common/ProgressUtils.h"
14370b324cSopenharmony_ci#include "../../Common/StreamObjects.h"
15370b324cSopenharmony_ci#include "../../Common/StreamUtils.h"
16370b324cSopenharmony_ci
17370b324cSopenharmony_ci#include "../../Archive/Common/ItemNameUtils.h"
18370b324cSopenharmony_ci#include "../../Archive/IArchive.h"
19370b324cSopenharmony_ci
20370b324cSopenharmony_ci#include "EnumDirItems.h"
21370b324cSopenharmony_ci#include "HashCalc.h"
22370b324cSopenharmony_ci
23370b324cSopenharmony_ciusing namespace NWindows;
24370b324cSopenharmony_ci
25370b324cSopenharmony_ci#ifdef Z7_EXTERNAL_CODECS
26370b324cSopenharmony_ciextern const CExternalCodecs *g_ExternalCodecs_Ptr;
27370b324cSopenharmony_ci#endif
28370b324cSopenharmony_ci
29370b324cSopenharmony_ciclass CHashMidBuf
30370b324cSopenharmony_ci{
31370b324cSopenharmony_ci  void *_data;
32370b324cSopenharmony_cipublic:
33370b324cSopenharmony_ci  CHashMidBuf(): _data(NULL) {}
34370b324cSopenharmony_ci  operator void *() { return _data; }
35370b324cSopenharmony_ci  bool Alloc(size_t size)
36370b324cSopenharmony_ci  {
37370b324cSopenharmony_ci    if (_data)
38370b324cSopenharmony_ci      return false;
39370b324cSopenharmony_ci    _data = ::MidAlloc(size);
40370b324cSopenharmony_ci    return _data != NULL;
41370b324cSopenharmony_ci  }
42370b324cSopenharmony_ci  ~CHashMidBuf() { ::MidFree(_data); }
43370b324cSopenharmony_ci};
44370b324cSopenharmony_ci
45370b324cSopenharmony_cistatic const char * const k_DefaultHashMethod = "CRC32";
46370b324cSopenharmony_ci
47370b324cSopenharmony_ciHRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods)
48370b324cSopenharmony_ci{
49370b324cSopenharmony_ci  UStringVector names = hashMethods;
50370b324cSopenharmony_ci  if (names.IsEmpty())
51370b324cSopenharmony_ci    names.Add(UString(k_DefaultHashMethod));
52370b324cSopenharmony_ci
53370b324cSopenharmony_ci  CRecordVector<CMethodId> ids;
54370b324cSopenharmony_ci  CObjectVector<COneMethodInfo> methods;
55370b324cSopenharmony_ci
56370b324cSopenharmony_ci  unsigned i;
57370b324cSopenharmony_ci  for (i = 0; i < names.Size(); i++)
58370b324cSopenharmony_ci  {
59370b324cSopenharmony_ci    COneMethodInfo m;
60370b324cSopenharmony_ci    RINOK(m.ParseMethodFromString(names[i]))
61370b324cSopenharmony_ci
62370b324cSopenharmony_ci    if (m.MethodName.IsEmpty())
63370b324cSopenharmony_ci      m.MethodName = k_DefaultHashMethod;
64370b324cSopenharmony_ci
65370b324cSopenharmony_ci    if (m.MethodName == "*")
66370b324cSopenharmony_ci    {
67370b324cSopenharmony_ci      CRecordVector<CMethodId> tempMethods;
68370b324cSopenharmony_ci      GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
69370b324cSopenharmony_ci      methods.Clear();
70370b324cSopenharmony_ci      ids.Clear();
71370b324cSopenharmony_ci      FOR_VECTOR (t, tempMethods)
72370b324cSopenharmony_ci      {
73370b324cSopenharmony_ci        unsigned index = ids.AddToUniqueSorted(tempMethods[t]);
74370b324cSopenharmony_ci        if (ids.Size() != methods.Size())
75370b324cSopenharmony_ci          methods.Insert(index, m);
76370b324cSopenharmony_ci      }
77370b324cSopenharmony_ci      break;
78370b324cSopenharmony_ci    }
79370b324cSopenharmony_ci    else
80370b324cSopenharmony_ci    {
81370b324cSopenharmony_ci      // m.MethodName.RemoveChar(L'-');
82370b324cSopenharmony_ci      CMethodId id;
83370b324cSopenharmony_ci      if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id))
84370b324cSopenharmony_ci        return E_NOTIMPL;
85370b324cSopenharmony_ci      unsigned index = ids.AddToUniqueSorted(id);
86370b324cSopenharmony_ci      if (ids.Size() != methods.Size())
87370b324cSopenharmony_ci        methods.Insert(index, m);
88370b324cSopenharmony_ci    }
89370b324cSopenharmony_ci  }
90370b324cSopenharmony_ci
91370b324cSopenharmony_ci  for (i = 0; i < ids.Size(); i++)
92370b324cSopenharmony_ci  {
93370b324cSopenharmony_ci    CMyComPtr<IHasher> hasher;
94370b324cSopenharmony_ci    AString name;
95370b324cSopenharmony_ci    RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher))
96370b324cSopenharmony_ci    if (!hasher)
97370b324cSopenharmony_ci      throw "Can't create hasher";
98370b324cSopenharmony_ci    const COneMethodInfo &m = methods[i];
99370b324cSopenharmony_ci    {
100370b324cSopenharmony_ci      CMyComPtr<ICompressSetCoderProperties> scp;
101370b324cSopenharmony_ci      hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
102370b324cSopenharmony_ci      if (scp)
103370b324cSopenharmony_ci        RINOK(m.SetCoderProps(scp, NULL))
104370b324cSopenharmony_ci    }
105370b324cSopenharmony_ci    const UInt32 digestSize = hasher->GetDigestSize();
106370b324cSopenharmony_ci    if (digestSize > k_HashCalc_DigestSize_Max)
107370b324cSopenharmony_ci      return E_NOTIMPL;
108370b324cSopenharmony_ci    CHasherState &h = Hashers.AddNew();
109370b324cSopenharmony_ci    h.DigestSize = digestSize;
110370b324cSopenharmony_ci    h.Hasher = hasher;
111370b324cSopenharmony_ci    h.Name = name;
112370b324cSopenharmony_ci    for (unsigned k = 0; k < k_HashCalc_NumGroups; k++)
113370b324cSopenharmony_ci      h.InitDigestGroup(k);
114370b324cSopenharmony_ci  }
115370b324cSopenharmony_ci
116370b324cSopenharmony_ci  return S_OK;
117370b324cSopenharmony_ci}
118370b324cSopenharmony_ci
119370b324cSopenharmony_civoid CHashBundle::InitForNewFile()
120370b324cSopenharmony_ci{
121370b324cSopenharmony_ci  CurSize = 0;
122370b324cSopenharmony_ci  FOR_VECTOR (i, Hashers)
123370b324cSopenharmony_ci  {
124370b324cSopenharmony_ci    CHasherState &h = Hashers[i];
125370b324cSopenharmony_ci    h.Hasher->Init();
126370b324cSopenharmony_ci    h.InitDigestGroup(k_HashCalc_Index_Current);
127370b324cSopenharmony_ci  }
128370b324cSopenharmony_ci}
129370b324cSopenharmony_ci
130370b324cSopenharmony_civoid CHashBundle::Update(const void *data, UInt32 size)
131370b324cSopenharmony_ci{
132370b324cSopenharmony_ci  CurSize += size;
133370b324cSopenharmony_ci  FOR_VECTOR (i, Hashers)
134370b324cSopenharmony_ci    Hashers[i].Hasher->Update(data, size);
135370b324cSopenharmony_ci}
136370b324cSopenharmony_ci
137370b324cSopenharmony_civoid CHashBundle::SetSize(UInt64 size)
138370b324cSopenharmony_ci{
139370b324cSopenharmony_ci  CurSize = size;
140370b324cSopenharmony_ci}
141370b324cSopenharmony_ci
142370b324cSopenharmony_cistatic void AddDigests(Byte *dest, const Byte *src, UInt32 size)
143370b324cSopenharmony_ci{
144370b324cSopenharmony_ci  unsigned next = 0;
145370b324cSopenharmony_ci  /*
146370b324cSopenharmony_ci  // we could use big-endian addition for sha-1 and sha-256
147370b324cSopenharmony_ci  // but another hashers are little-endian
148370b324cSopenharmony_ci  if (size > 8)
149370b324cSopenharmony_ci  {
150370b324cSopenharmony_ci    for (unsigned i = size; i != 0;)
151370b324cSopenharmony_ci    {
152370b324cSopenharmony_ci      i--;
153370b324cSopenharmony_ci      next += (unsigned)dest[i] + (unsigned)src[i];
154370b324cSopenharmony_ci      dest[i] = (Byte)next;
155370b324cSopenharmony_ci      next >>= 8;
156370b324cSopenharmony_ci    }
157370b324cSopenharmony_ci  }
158370b324cSopenharmony_ci  else
159370b324cSopenharmony_ci  */
160370b324cSopenharmony_ci  {
161370b324cSopenharmony_ci    for (unsigned i = 0; i < size; i++)
162370b324cSopenharmony_ci    {
163370b324cSopenharmony_ci      next += (unsigned)dest[i] + (unsigned)src[i];
164370b324cSopenharmony_ci      dest[i] = (Byte)next;
165370b324cSopenharmony_ci      next >>= 8;
166370b324cSopenharmony_ci    }
167370b324cSopenharmony_ci  }
168370b324cSopenharmony_ci
169370b324cSopenharmony_ci  // we use little-endian to store extra bytes
170370b324cSopenharmony_ci  dest += k_HashCalc_DigestSize_Max;
171370b324cSopenharmony_ci  for (unsigned i = 0; i < k_HashCalc_ExtraSize; i++)
172370b324cSopenharmony_ci  {
173370b324cSopenharmony_ci    next += (unsigned)dest[i];
174370b324cSopenharmony_ci    dest[i] = (Byte)next;
175370b324cSopenharmony_ci    next >>= 8;
176370b324cSopenharmony_ci  }
177370b324cSopenharmony_ci}
178370b324cSopenharmony_ci
179370b324cSopenharmony_civoid CHasherState::AddDigest(unsigned groupIndex, const Byte *data)
180370b324cSopenharmony_ci{
181370b324cSopenharmony_ci  NumSums[groupIndex]++;
182370b324cSopenharmony_ci  AddDigests(Digests[groupIndex], data, DigestSize);
183370b324cSopenharmony_ci}
184370b324cSopenharmony_ci
185370b324cSopenharmony_civoid CHashBundle::Final(bool isDir, bool isAltStream, const UString &path)
186370b324cSopenharmony_ci{
187370b324cSopenharmony_ci  if (isDir)
188370b324cSopenharmony_ci    NumDirs++;
189370b324cSopenharmony_ci  else if (isAltStream)
190370b324cSopenharmony_ci  {
191370b324cSopenharmony_ci    NumAltStreams++;
192370b324cSopenharmony_ci    AltStreamsSize += CurSize;
193370b324cSopenharmony_ci  }
194370b324cSopenharmony_ci  else
195370b324cSopenharmony_ci  {
196370b324cSopenharmony_ci    NumFiles++;
197370b324cSopenharmony_ci    FilesSize += CurSize;
198370b324cSopenharmony_ci  }
199370b324cSopenharmony_ci
200370b324cSopenharmony_ci  Byte pre[16];
201370b324cSopenharmony_ci  memset(pre, 0, sizeof(pre));
202370b324cSopenharmony_ci  if (isDir)
203370b324cSopenharmony_ci    pre[0] = 1;
204370b324cSopenharmony_ci
205370b324cSopenharmony_ci  FOR_VECTOR (i, Hashers)
206370b324cSopenharmony_ci  {
207370b324cSopenharmony_ci    CHasherState &h = Hashers[i];
208370b324cSopenharmony_ci    if (!isDir)
209370b324cSopenharmony_ci    {
210370b324cSopenharmony_ci      h.Hasher->Final(h.Digests[0]); // k_HashCalc_Index_Current
211370b324cSopenharmony_ci      if (!isAltStream)
212370b324cSopenharmony_ci        h.AddDigest(k_HashCalc_Index_DataSum, h.Digests[0]);
213370b324cSopenharmony_ci    }
214370b324cSopenharmony_ci
215370b324cSopenharmony_ci    h.Hasher->Init();
216370b324cSopenharmony_ci    h.Hasher->Update(pre, sizeof(pre));
217370b324cSopenharmony_ci    h.Hasher->Update(h.Digests[0], h.DigestSize);
218370b324cSopenharmony_ci
219370b324cSopenharmony_ci    for (unsigned k = 0; k < path.Len(); k++)
220370b324cSopenharmony_ci    {
221370b324cSopenharmony_ci      wchar_t c = path[k];
222370b324cSopenharmony_ci
223370b324cSopenharmony_ci      // 21.04: we want same hash for linux and windows paths
224370b324cSopenharmony_ci      #if CHAR_PATH_SEPARATOR != '/'
225370b324cSopenharmony_ci      if (c == CHAR_PATH_SEPARATOR)
226370b324cSopenharmony_ci        c = '/';
227370b324cSopenharmony_ci      // if (c == (wchar_t)('\\' + 0xf000)) c = '\\'; // to debug WSL
228370b324cSopenharmony_ci      // if (c > 0xf000 && c < 0xf080) c -= 0xf000; // to debug WSL
229370b324cSopenharmony_ci      #endif
230370b324cSopenharmony_ci
231370b324cSopenharmony_ci      Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) };
232370b324cSopenharmony_ci      h.Hasher->Update(temp, 2);
233370b324cSopenharmony_ci    }
234370b324cSopenharmony_ci
235370b324cSopenharmony_ci    Byte tempDigest[k_HashCalc_DigestSize_Max];
236370b324cSopenharmony_ci    h.Hasher->Final(tempDigest);
237370b324cSopenharmony_ci    if (!isAltStream)
238370b324cSopenharmony_ci      h.AddDigest(k_HashCalc_Index_NamesSum, tempDigest);
239370b324cSopenharmony_ci    h.AddDigest(k_HashCalc_Index_StreamsSum, tempDigest);
240370b324cSopenharmony_ci  }
241370b324cSopenharmony_ci}
242370b324cSopenharmony_ci
243370b324cSopenharmony_ci
244370b324cSopenharmony_cistatic void CSum_Name_OriginalToEscape(const AString &src, AString &dest)
245370b324cSopenharmony_ci{
246370b324cSopenharmony_ci  dest.Empty();
247370b324cSopenharmony_ci  for (unsigned i = 0; i < src.Len();)
248370b324cSopenharmony_ci  {
249370b324cSopenharmony_ci    char c = src[i++];
250370b324cSopenharmony_ci    if (c == '\n')
251370b324cSopenharmony_ci    {
252370b324cSopenharmony_ci      dest += '\\';
253370b324cSopenharmony_ci      c = 'n';
254370b324cSopenharmony_ci    }
255370b324cSopenharmony_ci    else if (c == '\\')
256370b324cSopenharmony_ci      dest += '\\';
257370b324cSopenharmony_ci    dest += c;
258370b324cSopenharmony_ci  }
259370b324cSopenharmony_ci}
260370b324cSopenharmony_ci
261370b324cSopenharmony_ci
262370b324cSopenharmony_cistatic bool CSum_Name_EscapeToOriginal(const char *s, AString &dest)
263370b324cSopenharmony_ci{
264370b324cSopenharmony_ci  bool isOK = true;
265370b324cSopenharmony_ci  dest.Empty();
266370b324cSopenharmony_ci  for (;;)
267370b324cSopenharmony_ci  {
268370b324cSopenharmony_ci    char c = *s++;
269370b324cSopenharmony_ci    if (c == 0)
270370b324cSopenharmony_ci      break;
271370b324cSopenharmony_ci    if (c == '\\')
272370b324cSopenharmony_ci    {
273370b324cSopenharmony_ci      const char c1 = *s;
274370b324cSopenharmony_ci      if (c1 == 'n')
275370b324cSopenharmony_ci      {
276370b324cSopenharmony_ci        c = '\n';
277370b324cSopenharmony_ci        s++;
278370b324cSopenharmony_ci      }
279370b324cSopenharmony_ci      else if (c1 == '\\')
280370b324cSopenharmony_ci      {
281370b324cSopenharmony_ci        c = c1;
282370b324cSopenharmony_ci        s++;
283370b324cSopenharmony_ci      }
284370b324cSopenharmony_ci      else
285370b324cSopenharmony_ci      {
286370b324cSopenharmony_ci        // original md5sum returns NULL for such bad strings
287370b324cSopenharmony_ci        isOK = false;
288370b324cSopenharmony_ci      }
289370b324cSopenharmony_ci    }
290370b324cSopenharmony_ci    dest += c;
291370b324cSopenharmony_ci  }
292370b324cSopenharmony_ci  return isOK;
293370b324cSopenharmony_ci}
294370b324cSopenharmony_ci
295370b324cSopenharmony_ci
296370b324cSopenharmony_ci
297370b324cSopenharmony_cistatic void SetSpacesAndNul(char *s, unsigned num)
298370b324cSopenharmony_ci{
299370b324cSopenharmony_ci  for (unsigned i = 0; i < num; i++)
300370b324cSopenharmony_ci    s[i] = ' ';
301370b324cSopenharmony_ci  s[num] = 0;
302370b324cSopenharmony_ci}
303370b324cSopenharmony_ci
304370b324cSopenharmony_cistatic const unsigned kHashColumnWidth_Min = 4 * 2;
305370b324cSopenharmony_ci
306370b324cSopenharmony_cistatic unsigned GetColumnWidth(unsigned digestSize)
307370b324cSopenharmony_ci{
308370b324cSopenharmony_ci  const unsigned width = digestSize * 2;
309370b324cSopenharmony_ci  return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
310370b324cSopenharmony_ci}
311370b324cSopenharmony_ci
312370b324cSopenharmony_ci
313370b324cSopenharmony_cistatic void AddHashResultLine(
314370b324cSopenharmony_ci    AString &_s,
315370b324cSopenharmony_ci    // bool showHash,
316370b324cSopenharmony_ci    // UInt64 fileSize, bool showSize,
317370b324cSopenharmony_ci    const CObjectVector<CHasherState> &hashers
318370b324cSopenharmony_ci    // unsigned digestIndex, = k_HashCalc_Index_Current
319370b324cSopenharmony_ci    )
320370b324cSopenharmony_ci{
321370b324cSopenharmony_ci  FOR_VECTOR (i, hashers)
322370b324cSopenharmony_ci  {
323370b324cSopenharmony_ci    const CHasherState &h = hashers[i];
324370b324cSopenharmony_ci    char s[k_HashCalc_DigestSize_Max * 2 + 64];
325370b324cSopenharmony_ci    s[0] = 0;
326370b324cSopenharmony_ci    // if (showHash)
327370b324cSopenharmony_ci      HashHexToString(s, h.Digests[k_HashCalc_Index_Current], h.DigestSize);
328370b324cSopenharmony_ci    const unsigned pos = (unsigned)strlen(s);
329370b324cSopenharmony_ci    const int numSpaces = (int)GetColumnWidth(h.DigestSize) - (int)pos;
330370b324cSopenharmony_ci    if (numSpaces > 0)
331370b324cSopenharmony_ci      SetSpacesAndNul(s + pos, (unsigned)numSpaces);
332370b324cSopenharmony_ci    if (i != 0)
333370b324cSopenharmony_ci      _s.Add_Space();
334370b324cSopenharmony_ci    _s += s;
335370b324cSopenharmony_ci  }
336370b324cSopenharmony_ci
337370b324cSopenharmony_ci  /*
338370b324cSopenharmony_ci  if (showSize)
339370b324cSopenharmony_ci  {
340370b324cSopenharmony_ci    _s.Add_Space();
341370b324cSopenharmony_ci    static const unsigned kSizeField_Len = 13; // same as in HashCon.cpp
342370b324cSopenharmony_ci    char s[kSizeField_Len + 32];
343370b324cSopenharmony_ci    char *p = s;
344370b324cSopenharmony_ci    SetSpacesAndNul(s, kSizeField_Len);
345370b324cSopenharmony_ci    p = s + kSizeField_Len;
346370b324cSopenharmony_ci    ConvertUInt64ToString(fileSize, p);
347370b324cSopenharmony_ci    int numSpaces = (int)kSizeField_Len - (int)strlen(p);
348370b324cSopenharmony_ci    if (numSpaces > 0)
349370b324cSopenharmony_ci      p -= (unsigned)numSpaces;
350370b324cSopenharmony_ci    _s += p;
351370b324cSopenharmony_ci  }
352370b324cSopenharmony_ci  */
353370b324cSopenharmony_ci}
354370b324cSopenharmony_ci
355370b324cSopenharmony_ci
356370b324cSopenharmony_cistatic void Add_LF(CDynLimBuf &hashFileString, const CHashOptionsLocal &options)
357370b324cSopenharmony_ci{
358370b324cSopenharmony_ci  hashFileString += (char)(options.HashMode_Zero.Val ? 0 : '\n');
359370b324cSopenharmony_ci}
360370b324cSopenharmony_ci
361370b324cSopenharmony_ci
362370b324cSopenharmony_ci
363370b324cSopenharmony_ci
364370b324cSopenharmony_cistatic void WriteLine(CDynLimBuf &hashFileString,
365370b324cSopenharmony_ci    const CHashOptionsLocal &options,
366370b324cSopenharmony_ci    const UString &path2,
367370b324cSopenharmony_ci    bool isDir,
368370b324cSopenharmony_ci    const AString &methodName,
369370b324cSopenharmony_ci    const AString &hashesString)
370370b324cSopenharmony_ci{
371370b324cSopenharmony_ci  if (options.HashMode_OnlyHash.Val)
372370b324cSopenharmony_ci  {
373370b324cSopenharmony_ci    hashFileString += hashesString;
374370b324cSopenharmony_ci    Add_LF(hashFileString, options);
375370b324cSopenharmony_ci    return;
376370b324cSopenharmony_ci  }
377370b324cSopenharmony_ci
378370b324cSopenharmony_ci  UString path = path2;
379370b324cSopenharmony_ci
380370b324cSopenharmony_ci  bool isBin = false;
381370b324cSopenharmony_ci  const bool zeroMode = options.HashMode_Zero.Val;
382370b324cSopenharmony_ci  const bool tagMode = options.HashMode_Tag.Val;
383370b324cSopenharmony_ci
384370b324cSopenharmony_ci#if CHAR_PATH_SEPARATOR != '/'
385370b324cSopenharmony_ci  path.Replace(WCHAR_PATH_SEPARATOR, L'/');
386370b324cSopenharmony_ci  // path.Replace((wchar_t)('\\' + 0xf000), L'\\'); // to debug WSL
387370b324cSopenharmony_ci#endif
388370b324cSopenharmony_ci
389370b324cSopenharmony_ci  AString utf8;
390370b324cSopenharmony_ci  ConvertUnicodeToUTF8(path, utf8);
391370b324cSopenharmony_ci
392370b324cSopenharmony_ci  AString esc;
393370b324cSopenharmony_ci  CSum_Name_OriginalToEscape(utf8, esc);
394370b324cSopenharmony_ci
395370b324cSopenharmony_ci  if (!zeroMode)
396370b324cSopenharmony_ci  {
397370b324cSopenharmony_ci    if (esc != utf8)
398370b324cSopenharmony_ci    {
399370b324cSopenharmony_ci      /* Original md5sum writes escape in that case.
400370b324cSopenharmony_ci      We do same for compatibility with original md5sum. */
401370b324cSopenharmony_ci      hashFileString += '\\';
402370b324cSopenharmony_ci    }
403370b324cSopenharmony_ci  }
404370b324cSopenharmony_ci
405370b324cSopenharmony_ci  if (isDir && !esc.IsEmpty() && esc.Back() != '/')
406370b324cSopenharmony_ci    esc += '/';
407370b324cSopenharmony_ci
408370b324cSopenharmony_ci  if (tagMode)
409370b324cSopenharmony_ci  {
410370b324cSopenharmony_ci    if (!methodName.IsEmpty())
411370b324cSopenharmony_ci    {
412370b324cSopenharmony_ci      hashFileString += methodName;
413370b324cSopenharmony_ci      hashFileString += ' ';
414370b324cSopenharmony_ci    }
415370b324cSopenharmony_ci    hashFileString += '(';
416370b324cSopenharmony_ci    hashFileString += esc;
417370b324cSopenharmony_ci    hashFileString += ')';
418370b324cSopenharmony_ci    hashFileString += " = ";
419370b324cSopenharmony_ci  }
420370b324cSopenharmony_ci
421370b324cSopenharmony_ci  hashFileString += hashesString;
422370b324cSopenharmony_ci
423370b324cSopenharmony_ci  if (!tagMode)
424370b324cSopenharmony_ci  {
425370b324cSopenharmony_ci    hashFileString += ' ';
426370b324cSopenharmony_ci    hashFileString += (char)(isBin ? '*' : ' ');
427370b324cSopenharmony_ci    hashFileString += esc;
428370b324cSopenharmony_ci  }
429370b324cSopenharmony_ci
430370b324cSopenharmony_ci  Add_LF(hashFileString, options);
431370b324cSopenharmony_ci}
432370b324cSopenharmony_ci
433370b324cSopenharmony_ci
434370b324cSopenharmony_ci
435370b324cSopenharmony_cistatic void WriteLine(CDynLimBuf &hashFileString,
436370b324cSopenharmony_ci    const CHashOptionsLocal &options,
437370b324cSopenharmony_ci    const UString &path,
438370b324cSopenharmony_ci    bool isDir,
439370b324cSopenharmony_ci    const CHashBundle &hb)
440370b324cSopenharmony_ci{
441370b324cSopenharmony_ci  AString methodName;
442370b324cSopenharmony_ci  if (!hb.Hashers.IsEmpty())
443370b324cSopenharmony_ci    methodName = hb.Hashers[0].Name;
444370b324cSopenharmony_ci
445370b324cSopenharmony_ci  AString hashesString;
446370b324cSopenharmony_ci  AddHashResultLine(hashesString, hb.Hashers);
447370b324cSopenharmony_ci  WriteLine(hashFileString, options, path, isDir, methodName, hashesString);
448370b324cSopenharmony_ci}
449370b324cSopenharmony_ci
450370b324cSopenharmony_ci
451370b324cSopenharmony_ciHRESULT HashCalc(
452370b324cSopenharmony_ci    DECL_EXTERNAL_CODECS_LOC_VARS
453370b324cSopenharmony_ci    const NWildcard::CCensor &censor,
454370b324cSopenharmony_ci    const CHashOptions &options,
455370b324cSopenharmony_ci    AString &errorInfo,
456370b324cSopenharmony_ci    IHashCallbackUI *callback)
457370b324cSopenharmony_ci{
458370b324cSopenharmony_ci  CDirItems dirItems;
459370b324cSopenharmony_ci  dirItems.Callback = callback;
460370b324cSopenharmony_ci
461370b324cSopenharmony_ci  if (options.StdInMode)
462370b324cSopenharmony_ci  {
463370b324cSopenharmony_ci    CDirItem di;
464370b324cSopenharmony_ci    di.Size = (UInt64)(Int64)-1;
465370b324cSopenharmony_ci    di.SetAsFile();
466370b324cSopenharmony_ci    dirItems.Items.Add(di);
467370b324cSopenharmony_ci  }
468370b324cSopenharmony_ci  else
469370b324cSopenharmony_ci  {
470370b324cSopenharmony_ci    RINOK(callback->StartScanning())
471370b324cSopenharmony_ci
472370b324cSopenharmony_ci    dirItems.SymLinks = options.SymLinks.Val;
473370b324cSopenharmony_ci    dirItems.ScanAltStreams = options.AltStreamsMode;
474370b324cSopenharmony_ci    dirItems.ExcludeDirItems = censor.ExcludeDirItems;
475370b324cSopenharmony_ci    dirItems.ExcludeFileItems = censor.ExcludeFileItems;
476370b324cSopenharmony_ci
477370b324cSopenharmony_ci    dirItems.ShareForWrite = options.OpenShareForWrite;
478370b324cSopenharmony_ci
479370b324cSopenharmony_ci    HRESULT res = EnumerateItems(censor,
480370b324cSopenharmony_ci        options.PathMode,
481370b324cSopenharmony_ci        UString(),
482370b324cSopenharmony_ci        dirItems);
483370b324cSopenharmony_ci
484370b324cSopenharmony_ci    if (res != S_OK)
485370b324cSopenharmony_ci    {
486370b324cSopenharmony_ci      if (res != E_ABORT)
487370b324cSopenharmony_ci        errorInfo = "Scanning error";
488370b324cSopenharmony_ci      return res;
489370b324cSopenharmony_ci    }
490370b324cSopenharmony_ci    RINOK(callback->FinishScanning(dirItems.Stat))
491370b324cSopenharmony_ci  }
492370b324cSopenharmony_ci
493370b324cSopenharmony_ci  unsigned i;
494370b324cSopenharmony_ci  CHashBundle hb;
495370b324cSopenharmony_ci  RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods))
496370b324cSopenharmony_ci  // hb.Init();
497370b324cSopenharmony_ci
498370b324cSopenharmony_ci  hb.NumErrors = dirItems.Stat.NumErrors;
499370b324cSopenharmony_ci
500370b324cSopenharmony_ci  UInt64 totalSize = 0;
501370b324cSopenharmony_ci  if (options.StdInMode)
502370b324cSopenharmony_ci  {
503370b324cSopenharmony_ci    RINOK(callback->SetNumFiles(1))
504370b324cSopenharmony_ci  }
505370b324cSopenharmony_ci  else
506370b324cSopenharmony_ci  {
507370b324cSopenharmony_ci    totalSize = dirItems.Stat.GetTotalBytes();
508370b324cSopenharmony_ci    RINOK(callback->SetTotal(totalSize))
509370b324cSopenharmony_ci  }
510370b324cSopenharmony_ci
511370b324cSopenharmony_ci  const UInt32 kBufSize = 1 << 15;
512370b324cSopenharmony_ci  CHashMidBuf buf;
513370b324cSopenharmony_ci  if (!buf.Alloc(kBufSize))
514370b324cSopenharmony_ci    return E_OUTOFMEMORY;
515370b324cSopenharmony_ci
516370b324cSopenharmony_ci  UInt64 completeValue = 0;
517370b324cSopenharmony_ci
518370b324cSopenharmony_ci  RINOK(callback->BeforeFirstFile(hb))
519370b324cSopenharmony_ci
520370b324cSopenharmony_ci  /*
521370b324cSopenharmony_ci  CDynLimBuf hashFileString((size_t)1 << 31);
522370b324cSopenharmony_ci  const bool needGenerate = !options.HashFilePath.IsEmpty();
523370b324cSopenharmony_ci  */
524370b324cSopenharmony_ci
525370b324cSopenharmony_ci  for (i = 0; i < dirItems.Items.Size(); i++)
526370b324cSopenharmony_ci  {
527370b324cSopenharmony_ci    CMyComPtr<ISequentialInStream> inStream;
528370b324cSopenharmony_ci    UString path;
529370b324cSopenharmony_ci    bool isDir = false;
530370b324cSopenharmony_ci    bool isAltStream = false;
531370b324cSopenharmony_ci
532370b324cSopenharmony_ci    if (options.StdInMode)
533370b324cSopenharmony_ci    {
534370b324cSopenharmony_ci      inStream = new CStdInFileStream;
535370b324cSopenharmony_ci    }
536370b324cSopenharmony_ci    else
537370b324cSopenharmony_ci    {
538370b324cSopenharmony_ci      path = dirItems.GetLogPath(i);
539370b324cSopenharmony_ci      const CDirItem &di = dirItems.Items[i];
540370b324cSopenharmony_ci     #ifdef _WIN32
541370b324cSopenharmony_ci      isAltStream = di.IsAltStream;
542370b324cSopenharmony_ci     #endif
543370b324cSopenharmony_ci
544370b324cSopenharmony_ci      #ifndef UNDER_CE
545370b324cSopenharmony_ci      // if (di.AreReparseData())
546370b324cSopenharmony_ci      if (di.ReparseData.Size() != 0)
547370b324cSopenharmony_ci      {
548370b324cSopenharmony_ci        CBufInStream *inStreamSpec = new CBufInStream();
549370b324cSopenharmony_ci        inStream = inStreamSpec;
550370b324cSopenharmony_ci        inStreamSpec->Init(di.ReparseData, di.ReparseData.Size());
551370b324cSopenharmony_ci      }
552370b324cSopenharmony_ci      else
553370b324cSopenharmony_ci      #endif
554370b324cSopenharmony_ci      {
555370b324cSopenharmony_ci        CInFileStream *inStreamSpec = new CInFileStream;
556370b324cSopenharmony_ci        inStreamSpec->Set_PreserveATime(options.PreserveATime);
557370b324cSopenharmony_ci        inStream = inStreamSpec;
558370b324cSopenharmony_ci        isDir = di.IsDir();
559370b324cSopenharmony_ci        if (!isDir)
560370b324cSopenharmony_ci        {
561370b324cSopenharmony_ci          const FString phyPath = dirItems.GetPhyPath(i);
562370b324cSopenharmony_ci          if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite))
563370b324cSopenharmony_ci          {
564370b324cSopenharmony_ci            HRESULT res = callback->OpenFileError(phyPath, ::GetLastError());
565370b324cSopenharmony_ci            hb.NumErrors++;
566370b324cSopenharmony_ci            if (res != S_FALSE)
567370b324cSopenharmony_ci              return res;
568370b324cSopenharmony_ci            continue;
569370b324cSopenharmony_ci          }
570370b324cSopenharmony_ci          if (!options.StdInMode)
571370b324cSopenharmony_ci          {
572370b324cSopenharmony_ci            UInt64 curSize = 0;
573370b324cSopenharmony_ci            if (inStreamSpec->GetSize(&curSize) == S_OK)
574370b324cSopenharmony_ci            {
575370b324cSopenharmony_ci              if (curSize > di.Size)
576370b324cSopenharmony_ci              {
577370b324cSopenharmony_ci                totalSize += curSize - di.Size;
578370b324cSopenharmony_ci                RINOK(callback->SetTotal(totalSize))
579370b324cSopenharmony_ci                // printf("\ntotal = %d MiB\n", (unsigned)(totalSize >> 20));
580370b324cSopenharmony_ci              }
581370b324cSopenharmony_ci            }
582370b324cSopenharmony_ci          }
583370b324cSopenharmony_ci          // inStreamSpec->ReloadProps();
584370b324cSopenharmony_ci        }
585370b324cSopenharmony_ci      }
586370b324cSopenharmony_ci    }
587370b324cSopenharmony_ci
588370b324cSopenharmony_ci    RINOK(callback->GetStream(path, isDir))
589370b324cSopenharmony_ci    UInt64 fileSize = 0;
590370b324cSopenharmony_ci
591370b324cSopenharmony_ci    hb.InitForNewFile();
592370b324cSopenharmony_ci
593370b324cSopenharmony_ci    if (!isDir)
594370b324cSopenharmony_ci    {
595370b324cSopenharmony_ci      for (UInt32 step = 0;; step++)
596370b324cSopenharmony_ci      {
597370b324cSopenharmony_ci        if ((step & 0xFF) == 0)
598370b324cSopenharmony_ci        {
599370b324cSopenharmony_ci          // printf("\ncompl = %d\n", (unsigned)(completeValue >> 20));
600370b324cSopenharmony_ci          RINOK(callback->SetCompleted(&completeValue))
601370b324cSopenharmony_ci        }
602370b324cSopenharmony_ci        UInt32 size;
603370b324cSopenharmony_ci        RINOK(inStream->Read(buf, kBufSize, &size))
604370b324cSopenharmony_ci        if (size == 0)
605370b324cSopenharmony_ci          break;
606370b324cSopenharmony_ci        hb.Update(buf, size);
607370b324cSopenharmony_ci        fileSize += size;
608370b324cSopenharmony_ci        completeValue += size;
609370b324cSopenharmony_ci      }
610370b324cSopenharmony_ci    }
611370b324cSopenharmony_ci
612370b324cSopenharmony_ci    hb.Final(isDir, isAltStream, path);
613370b324cSopenharmony_ci
614370b324cSopenharmony_ci    /*
615370b324cSopenharmony_ci    if (needGenerate
616370b324cSopenharmony_ci        && (options.HashMode_Dirs.Val || !isDir))
617370b324cSopenharmony_ci    {
618370b324cSopenharmony_ci      WriteLine(hashFileString,
619370b324cSopenharmony_ci          options,
620370b324cSopenharmony_ci          path, // change it
621370b324cSopenharmony_ci          isDir,
622370b324cSopenharmony_ci          hb);
623370b324cSopenharmony_ci
624370b324cSopenharmony_ci      if (hashFileString.IsError())
625370b324cSopenharmony_ci        return E_OUTOFMEMORY;
626370b324cSopenharmony_ci    }
627370b324cSopenharmony_ci    */
628370b324cSopenharmony_ci
629370b324cSopenharmony_ci    RINOK(callback->SetOperationResult(fileSize, hb, !isDir))
630370b324cSopenharmony_ci    RINOK(callback->SetCompleted(&completeValue))
631370b324cSopenharmony_ci  }
632370b324cSopenharmony_ci
633370b324cSopenharmony_ci  /*
634370b324cSopenharmony_ci  if (needGenerate)
635370b324cSopenharmony_ci  {
636370b324cSopenharmony_ci    NFile::NIO::COutFile file;
637370b324cSopenharmony_ci    if (!file.Create(us2fs(options.HashFilePath), true)) // createAlways
638370b324cSopenharmony_ci      return GetLastError_noZero_HRESULT();
639370b324cSopenharmony_ci    if (!file.WriteFull(hashFileString, hashFileString.Len()))
640370b324cSopenharmony_ci      return GetLastError_noZero_HRESULT();
641370b324cSopenharmony_ci  }
642370b324cSopenharmony_ci  */
643370b324cSopenharmony_ci
644370b324cSopenharmony_ci  return callback->AfterLastFile(hb);
645370b324cSopenharmony_ci}
646370b324cSopenharmony_ci
647370b324cSopenharmony_ci
648370b324cSopenharmony_cistatic inline char GetHex_Upper(unsigned v)
649370b324cSopenharmony_ci{
650370b324cSopenharmony_ci  return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
651370b324cSopenharmony_ci}
652370b324cSopenharmony_ci
653370b324cSopenharmony_cistatic inline char GetHex_Lower(unsigned v)
654370b324cSopenharmony_ci{
655370b324cSopenharmony_ci  return (char)((v < 10) ? ('0' + v) : ('a' + (v - 10)));
656370b324cSopenharmony_ci}
657370b324cSopenharmony_ci
658370b324cSopenharmony_civoid HashHexToString(char *dest, const Byte *data, UInt32 size)
659370b324cSopenharmony_ci{
660370b324cSopenharmony_ci  dest[size * 2] = 0;
661370b324cSopenharmony_ci
662370b324cSopenharmony_ci  if (!data)
663370b324cSopenharmony_ci  {
664370b324cSopenharmony_ci    for (UInt32 i = 0; i < size; i++)
665370b324cSopenharmony_ci    {
666370b324cSopenharmony_ci      dest[0] = ' ';
667370b324cSopenharmony_ci      dest[1] = ' ';
668370b324cSopenharmony_ci      dest += 2;
669370b324cSopenharmony_ci    }
670370b324cSopenharmony_ci    return;
671370b324cSopenharmony_ci  }
672370b324cSopenharmony_ci
673370b324cSopenharmony_ci  if (size <= 8)
674370b324cSopenharmony_ci  {
675370b324cSopenharmony_ci    dest += size * 2;
676370b324cSopenharmony_ci    for (UInt32 i = 0; i < size; i++)
677370b324cSopenharmony_ci    {
678370b324cSopenharmony_ci      const unsigned b = data[i];
679370b324cSopenharmony_ci      dest -= 2;
680370b324cSopenharmony_ci      dest[0] = GetHex_Upper((b >> 4) & 0xF);
681370b324cSopenharmony_ci      dest[1] = GetHex_Upper(b & 0xF);
682370b324cSopenharmony_ci    }
683370b324cSopenharmony_ci  }
684370b324cSopenharmony_ci  else
685370b324cSopenharmony_ci  {
686370b324cSopenharmony_ci    for (UInt32 i = 0; i < size; i++)
687370b324cSopenharmony_ci    {
688370b324cSopenharmony_ci      const unsigned b = data[i];
689370b324cSopenharmony_ci      dest[0] = GetHex_Lower((b >> 4) & 0xF);
690370b324cSopenharmony_ci      dest[1] = GetHex_Lower(b & 0xF);
691370b324cSopenharmony_ci      dest += 2;
692370b324cSopenharmony_ci    }
693370b324cSopenharmony_ci  }
694370b324cSopenharmony_ci}
695370b324cSopenharmony_ci
696370b324cSopenharmony_civoid CHasherState::WriteToString(unsigned digestIndex, char *s) const
697370b324cSopenharmony_ci{
698370b324cSopenharmony_ci  HashHexToString(s, Digests[digestIndex], DigestSize);
699370b324cSopenharmony_ci
700370b324cSopenharmony_ci  if (digestIndex != 0 && NumSums[digestIndex] != 1)
701370b324cSopenharmony_ci  {
702370b324cSopenharmony_ci    unsigned numExtraBytes = GetNumExtraBytes_for_Group(digestIndex);
703370b324cSopenharmony_ci    if (numExtraBytes > 4)
704370b324cSopenharmony_ci      numExtraBytes = 8;
705370b324cSopenharmony_ci    else // if (numExtraBytes >= 0)
706370b324cSopenharmony_ci      numExtraBytes = 4;
707370b324cSopenharmony_ci    // if (numExtraBytes != 0)
708370b324cSopenharmony_ci    {
709370b324cSopenharmony_ci      s += strlen(s);
710370b324cSopenharmony_ci      *s++ = '-';
711370b324cSopenharmony_ci      // *s = 0;
712370b324cSopenharmony_ci      HashHexToString(s, GetExtraData_for_Group(digestIndex), numExtraBytes);
713370b324cSopenharmony_ci    }
714370b324cSopenharmony_ci  }
715370b324cSopenharmony_ci}
716370b324cSopenharmony_ci
717370b324cSopenharmony_ci
718370b324cSopenharmony_ci
719370b324cSopenharmony_ci// ---------- Hash Handler ----------
720370b324cSopenharmony_ci
721370b324cSopenharmony_cinamespace NHash {
722370b324cSopenharmony_ci
723370b324cSopenharmony_cistatic size_t ParseHexString(const char *s, Byte *dest) throw()
724370b324cSopenharmony_ci{
725370b324cSopenharmony_ci  size_t num;
726370b324cSopenharmony_ci  for (num = 0;; num++, s += 2)
727370b324cSopenharmony_ci  {
728370b324cSopenharmony_ci    unsigned c = (Byte)s[0];
729370b324cSopenharmony_ci    unsigned v0;
730370b324cSopenharmony_ci         if (c >= '0' && c <= '9') v0 =      (c - '0');
731370b324cSopenharmony_ci    else if (c >= 'A' && c <= 'F') v0 = 10 + (c - 'A');
732370b324cSopenharmony_ci    else if (c >= 'a' && c <= 'f') v0 = 10 + (c - 'a');
733370b324cSopenharmony_ci    else
734370b324cSopenharmony_ci      return num;
735370b324cSopenharmony_ci    c = (Byte)s[1];
736370b324cSopenharmony_ci    unsigned v1;
737370b324cSopenharmony_ci         if (c >= '0' && c <= '9') v1 =      (c - '0');
738370b324cSopenharmony_ci    else if (c >= 'A' && c <= 'F') v1 = 10 + (c - 'A');
739370b324cSopenharmony_ci    else if (c >= 'a' && c <= 'f') v1 = 10 + (c - 'a');
740370b324cSopenharmony_ci    else
741370b324cSopenharmony_ci      return num;
742370b324cSopenharmony_ci    if (dest)
743370b324cSopenharmony_ci      dest[num] = (Byte)(v1 | (v0 << 4));
744370b324cSopenharmony_ci  }
745370b324cSopenharmony_ci}
746370b324cSopenharmony_ci
747370b324cSopenharmony_ci
748370b324cSopenharmony_ci#define IsWhite(c) ((c) == ' ' || (c) == '\t')
749370b324cSopenharmony_ci
750370b324cSopenharmony_cibool CHashPair::IsDir() const
751370b324cSopenharmony_ci{
752370b324cSopenharmony_ci  if (Name.IsEmpty() || Name.Back() != '/')
753370b324cSopenharmony_ci    return false;
754370b324cSopenharmony_ci  // here we expect that Dir items contain only zeros or no Hash
755370b324cSopenharmony_ci  for (size_t i = 0; i < Hash.Size(); i++)
756370b324cSopenharmony_ci    if (Hash[i] != 0)
757370b324cSopenharmony_ci      return false;
758370b324cSopenharmony_ci  return true;
759370b324cSopenharmony_ci}
760370b324cSopenharmony_ci
761370b324cSopenharmony_ci
762370b324cSopenharmony_cibool CHashPair::ParseCksum(const char *s)
763370b324cSopenharmony_ci{
764370b324cSopenharmony_ci  const char *end;
765370b324cSopenharmony_ci
766370b324cSopenharmony_ci  const UInt32 crc = ConvertStringToUInt32(s, &end);
767370b324cSopenharmony_ci  if (*end != ' ')
768370b324cSopenharmony_ci    return false;
769370b324cSopenharmony_ci  end++;
770370b324cSopenharmony_ci
771370b324cSopenharmony_ci  const UInt64 size = ConvertStringToUInt64(end, &end);
772370b324cSopenharmony_ci  if (*end != ' ')
773370b324cSopenharmony_ci    return false;
774370b324cSopenharmony_ci  end++;
775370b324cSopenharmony_ci
776370b324cSopenharmony_ci  Name = end;
777370b324cSopenharmony_ci
778370b324cSopenharmony_ci  Hash.Alloc(4);
779370b324cSopenharmony_ci  SetBe32(Hash, crc)
780370b324cSopenharmony_ci
781370b324cSopenharmony_ci  Size_from_Arc = size;
782370b324cSopenharmony_ci  Size_from_Arc_Defined = true;
783370b324cSopenharmony_ci
784370b324cSopenharmony_ci  return true;
785370b324cSopenharmony_ci}
786370b324cSopenharmony_ci
787370b324cSopenharmony_ci
788370b324cSopenharmony_ci
789370b324cSopenharmony_cistatic const char *SkipWhite(const char *s)
790370b324cSopenharmony_ci{
791370b324cSopenharmony_ci  while (IsWhite(*s))
792370b324cSopenharmony_ci    s++;
793370b324cSopenharmony_ci  return s;
794370b324cSopenharmony_ci}
795370b324cSopenharmony_ci
796370b324cSopenharmony_cistatic const char * const k_CsumMethodNames[] =
797370b324cSopenharmony_ci{
798370b324cSopenharmony_ci    "sha256"
799370b324cSopenharmony_ci  , "sha224"
800370b324cSopenharmony_ci//  , "sha512/224"
801370b324cSopenharmony_ci//  , "sha512/256"
802370b324cSopenharmony_ci  , "sha512"
803370b324cSopenharmony_ci  , "sha384"
804370b324cSopenharmony_ci  , "sha1"
805370b324cSopenharmony_ci  , "md5"
806370b324cSopenharmony_ci  , "blake2b"
807370b324cSopenharmony_ci  , "crc64"
808370b324cSopenharmony_ci  , "crc32"
809370b324cSopenharmony_ci  , "cksum"
810370b324cSopenharmony_ci};
811370b324cSopenharmony_ci
812370b324cSopenharmony_cistatic UString GetMethod_from_FileName(const UString &name)
813370b324cSopenharmony_ci{
814370b324cSopenharmony_ci  AString s;
815370b324cSopenharmony_ci  ConvertUnicodeToUTF8(name, s);
816370b324cSopenharmony_ci  const int dotPos = s.ReverseFind_Dot();
817370b324cSopenharmony_ci  const char *src = s.Ptr();
818370b324cSopenharmony_ci  bool isExtension = false;
819370b324cSopenharmony_ci  if (dotPos >= 0)
820370b324cSopenharmony_ci  {
821370b324cSopenharmony_ci    isExtension = true;
822370b324cSopenharmony_ci    src = s.Ptr(dotPos + 1);
823370b324cSopenharmony_ci  }
824370b324cSopenharmony_ci  const char *m = "";
825370b324cSopenharmony_ci  unsigned i;
826370b324cSopenharmony_ci  for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
827370b324cSopenharmony_ci  {
828370b324cSopenharmony_ci    m = k_CsumMethodNames[i];
829370b324cSopenharmony_ci    if (isExtension)
830370b324cSopenharmony_ci    {
831370b324cSopenharmony_ci      if (StringsAreEqual_Ascii(src, m))
832370b324cSopenharmony_ci        break;
833370b324cSopenharmony_ci    }
834370b324cSopenharmony_ci    else if (IsString1PrefixedByString2_NoCase_Ascii(src, m))
835370b324cSopenharmony_ci      if (StringsAreEqual_Ascii(src + strlen(m), "sums"))
836370b324cSopenharmony_ci        break;
837370b324cSopenharmony_ci  }
838370b324cSopenharmony_ci  UString res;
839370b324cSopenharmony_ci  if (i != Z7_ARRAY_SIZE(k_CsumMethodNames))
840370b324cSopenharmony_ci    res = m;
841370b324cSopenharmony_ci  return res;
842370b324cSopenharmony_ci}
843370b324cSopenharmony_ci
844370b324cSopenharmony_ci
845370b324cSopenharmony_cibool CHashPair::Parse(const char *s)
846370b324cSopenharmony_ci{
847370b324cSopenharmony_ci  // here we keep compatibility with original md5sum / shasum
848370b324cSopenharmony_ci  bool escape = false;
849370b324cSopenharmony_ci
850370b324cSopenharmony_ci  s = SkipWhite(s);
851370b324cSopenharmony_ci
852370b324cSopenharmony_ci  if (*s == '\\')
853370b324cSopenharmony_ci  {
854370b324cSopenharmony_ci    s++;
855370b324cSopenharmony_ci    escape = true;
856370b324cSopenharmony_ci  }
857370b324cSopenharmony_ci
858370b324cSopenharmony_ci  // const char *kMethod = GetMethod_from_FileName(s);
859370b324cSopenharmony_ci  // if (kMethod)
860370b324cSopenharmony_ci  if (ParseHexString(s, NULL) < 4)
861370b324cSopenharmony_ci  {
862370b324cSopenharmony_ci    // BSD-style checksum line
863370b324cSopenharmony_ci    {
864370b324cSopenharmony_ci      const char *s2 = s;
865370b324cSopenharmony_ci      for (; *s2 != 0; s2++)
866370b324cSopenharmony_ci      {
867370b324cSopenharmony_ci        const char c = *s2;
868370b324cSopenharmony_ci        if (c == 0)
869370b324cSopenharmony_ci          return false;
870370b324cSopenharmony_ci        if (c == ' ' || c == '(')
871370b324cSopenharmony_ci          break;
872370b324cSopenharmony_ci      }
873370b324cSopenharmony_ci      Method.SetFrom(s, (unsigned)(s2 - s));
874370b324cSopenharmony_ci      s = s2;
875370b324cSopenharmony_ci    }
876370b324cSopenharmony_ci    IsBSD = true;
877370b324cSopenharmony_ci    if (*s == ' ')
878370b324cSopenharmony_ci      s++;
879370b324cSopenharmony_ci    if (*s != '(')
880370b324cSopenharmony_ci      return false;
881370b324cSopenharmony_ci    s++;
882370b324cSopenharmony_ci    {
883370b324cSopenharmony_ci      const char *s2 = s;
884370b324cSopenharmony_ci      for (; *s2 != 0; s2++)
885370b324cSopenharmony_ci      {}
886370b324cSopenharmony_ci      for (;;)
887370b324cSopenharmony_ci      {
888370b324cSopenharmony_ci        s2--;
889370b324cSopenharmony_ci        if (s2 < s)
890370b324cSopenharmony_ci          return false;
891370b324cSopenharmony_ci        if (*s2 == ')')
892370b324cSopenharmony_ci          break;
893370b324cSopenharmony_ci      }
894370b324cSopenharmony_ci      Name.SetFrom(s, (unsigned)(s2 - s));
895370b324cSopenharmony_ci      s = s2 + 1;
896370b324cSopenharmony_ci    }
897370b324cSopenharmony_ci
898370b324cSopenharmony_ci    s = SkipWhite(s);
899370b324cSopenharmony_ci    if (*s != '=')
900370b324cSopenharmony_ci      return false;
901370b324cSopenharmony_ci    s++;
902370b324cSopenharmony_ci    s = SkipWhite(s);
903370b324cSopenharmony_ci  }
904370b324cSopenharmony_ci
905370b324cSopenharmony_ci  {
906370b324cSopenharmony_ci    const size_t num = ParseHexString(s, NULL);
907370b324cSopenharmony_ci    Hash.Alloc(num);
908370b324cSopenharmony_ci    ParseHexString(s, Hash);
909370b324cSopenharmony_ci    const size_t numChars = num * 2;
910370b324cSopenharmony_ci    HashString.SetFrom(s, (unsigned)numChars);
911370b324cSopenharmony_ci    s += numChars;
912370b324cSopenharmony_ci  }
913370b324cSopenharmony_ci
914370b324cSopenharmony_ci  if (IsBSD)
915370b324cSopenharmony_ci  {
916370b324cSopenharmony_ci    if (*s != 0)
917370b324cSopenharmony_ci      return false;
918370b324cSopenharmony_ci    if (escape)
919370b324cSopenharmony_ci    {
920370b324cSopenharmony_ci      const AString temp (Name);
921370b324cSopenharmony_ci      return CSum_Name_EscapeToOriginal(temp, Name);
922370b324cSopenharmony_ci    }
923370b324cSopenharmony_ci    return true;
924370b324cSopenharmony_ci  }
925370b324cSopenharmony_ci
926370b324cSopenharmony_ci  if (*s == 0)
927370b324cSopenharmony_ci    return true;
928370b324cSopenharmony_ci
929370b324cSopenharmony_ci  if (*s != ' ')
930370b324cSopenharmony_ci    return false;
931370b324cSopenharmony_ci  s++;
932370b324cSopenharmony_ci  const char c = *s;
933370b324cSopenharmony_ci  if (c != ' '
934370b324cSopenharmony_ci      && c != '*'
935370b324cSopenharmony_ci      && c != 'U' // shasum Universal
936370b324cSopenharmony_ci      && c != '^' // shasum 0/1
937370b324cSopenharmony_ci     )
938370b324cSopenharmony_ci    return false;
939370b324cSopenharmony_ci  Mode = c;
940370b324cSopenharmony_ci  s++;
941370b324cSopenharmony_ci  if (escape)
942370b324cSopenharmony_ci    return CSum_Name_EscapeToOriginal(s, Name);
943370b324cSopenharmony_ci  Name = s;
944370b324cSopenharmony_ci  return true;
945370b324cSopenharmony_ci}
946370b324cSopenharmony_ci
947370b324cSopenharmony_ci
948370b324cSopenharmony_cistatic bool GetLine(CByteBuffer &buf, bool zeroMode, bool cr_lf_Mode, size_t &posCur, AString &s)
949370b324cSopenharmony_ci{
950370b324cSopenharmony_ci  s.Empty();
951370b324cSopenharmony_ci  size_t pos = posCur;
952370b324cSopenharmony_ci  const Byte *p = buf;
953370b324cSopenharmony_ci  unsigned numDigits = 0;
954370b324cSopenharmony_ci  for (; pos < buf.Size(); pos++)
955370b324cSopenharmony_ci  {
956370b324cSopenharmony_ci    const Byte b = p[pos];
957370b324cSopenharmony_ci    if (b == 0)
958370b324cSopenharmony_ci    {
959370b324cSopenharmony_ci      numDigits = 1;
960370b324cSopenharmony_ci      break;
961370b324cSopenharmony_ci    }
962370b324cSopenharmony_ci    if (zeroMode)
963370b324cSopenharmony_ci      continue;
964370b324cSopenharmony_ci    if (b == 0x0a)
965370b324cSopenharmony_ci    {
966370b324cSopenharmony_ci      numDigits = 1;
967370b324cSopenharmony_ci      break;
968370b324cSopenharmony_ci    }
969370b324cSopenharmony_ci    if (!cr_lf_Mode)
970370b324cSopenharmony_ci      continue;
971370b324cSopenharmony_ci    if (b == 0x0d)
972370b324cSopenharmony_ci    {
973370b324cSopenharmony_ci      if (pos + 1 >= buf.Size())
974370b324cSopenharmony_ci      {
975370b324cSopenharmony_ci        numDigits = 1;
976370b324cSopenharmony_ci        break;
977370b324cSopenharmony_ci        // return false;
978370b324cSopenharmony_ci      }
979370b324cSopenharmony_ci      if (p[pos + 1] == 0x0a)
980370b324cSopenharmony_ci      {
981370b324cSopenharmony_ci        numDigits = 2;
982370b324cSopenharmony_ci        break;
983370b324cSopenharmony_ci      }
984370b324cSopenharmony_ci    }
985370b324cSopenharmony_ci  }
986370b324cSopenharmony_ci  s.SetFrom((const char *)(p + posCur), (unsigned)(pos - posCur));
987370b324cSopenharmony_ci  posCur = pos + numDigits;
988370b324cSopenharmony_ci  return true;
989370b324cSopenharmony_ci}
990370b324cSopenharmony_ci
991370b324cSopenharmony_ci
992370b324cSopenharmony_cistatic bool Is_CR_LF_Data(const Byte *buf, size_t size)
993370b324cSopenharmony_ci{
994370b324cSopenharmony_ci  bool isCrLf = false;
995370b324cSopenharmony_ci  for (size_t i = 0; i < size;)
996370b324cSopenharmony_ci  {
997370b324cSopenharmony_ci    const Byte b = buf[i];
998370b324cSopenharmony_ci    if (b == 0x0a)
999370b324cSopenharmony_ci      return false;
1000370b324cSopenharmony_ci    if (b == 0x0d)
1001370b324cSopenharmony_ci    {
1002370b324cSopenharmony_ci      if (i == size - 1)
1003370b324cSopenharmony_ci        return false;
1004370b324cSopenharmony_ci      if (buf[i + 1] != 0x0a)
1005370b324cSopenharmony_ci        return false;
1006370b324cSopenharmony_ci      isCrLf = true;
1007370b324cSopenharmony_ci      i += 2;
1008370b324cSopenharmony_ci    }
1009370b324cSopenharmony_ci    else
1010370b324cSopenharmony_ci      i++;
1011370b324cSopenharmony_ci  }
1012370b324cSopenharmony_ci  return isCrLf;
1013370b324cSopenharmony_ci}
1014370b324cSopenharmony_ci
1015370b324cSopenharmony_ci
1016370b324cSopenharmony_cistatic const Byte kArcProps[] =
1017370b324cSopenharmony_ci{
1018370b324cSopenharmony_ci  // kpidComment,
1019370b324cSopenharmony_ci  kpidCharacts
1020370b324cSopenharmony_ci};
1021370b324cSopenharmony_ci
1022370b324cSopenharmony_cistatic const Byte kProps[] =
1023370b324cSopenharmony_ci{
1024370b324cSopenharmony_ci  kpidPath,
1025370b324cSopenharmony_ci  kpidSize,
1026370b324cSopenharmony_ci  kpidPackSize,
1027370b324cSopenharmony_ci  kpidMethod
1028370b324cSopenharmony_ci};
1029370b324cSopenharmony_ci
1030370b324cSopenharmony_cistatic const Byte kRawProps[] =
1031370b324cSopenharmony_ci{
1032370b324cSopenharmony_ci  kpidChecksum
1033370b324cSopenharmony_ci};
1034370b324cSopenharmony_ci
1035370b324cSopenharmony_ci
1036370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */ , UInt32 *parent, UInt32 *parentType))
1037370b324cSopenharmony_ci{
1038370b324cSopenharmony_ci  *parentType = NParentType::kDir;
1039370b324cSopenharmony_ci  *parent = (UInt32)(Int32)-1;
1040370b324cSopenharmony_ci  return S_OK;
1041370b324cSopenharmony_ci}
1042370b324cSopenharmony_ci
1043370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
1044370b324cSopenharmony_ci{
1045370b324cSopenharmony_ci  *numProps = Z7_ARRAY_SIZE(kRawProps);
1046370b324cSopenharmony_ci  return S_OK;
1047370b324cSopenharmony_ci}
1048370b324cSopenharmony_ci
1049370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
1050370b324cSopenharmony_ci{
1051370b324cSopenharmony_ci  *propID = kRawProps[index];
1052370b324cSopenharmony_ci  *name = NULL;
1053370b324cSopenharmony_ci  return S_OK;
1054370b324cSopenharmony_ci}
1055370b324cSopenharmony_ci
1056370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
1057370b324cSopenharmony_ci{
1058370b324cSopenharmony_ci  *data = NULL;
1059370b324cSopenharmony_ci  *dataSize = 0;
1060370b324cSopenharmony_ci  *propType = 0;
1061370b324cSopenharmony_ci
1062370b324cSopenharmony_ci  if (propID == kpidChecksum)
1063370b324cSopenharmony_ci  {
1064370b324cSopenharmony_ci    const CHashPair &hp = HashPairs[index];
1065370b324cSopenharmony_ci    if (hp.Hash.Size() > 0)
1066370b324cSopenharmony_ci    {
1067370b324cSopenharmony_ci      *data = hp.Hash;
1068370b324cSopenharmony_ci      *dataSize = (UInt32)hp.Hash.Size();
1069370b324cSopenharmony_ci      *propType = NPropDataType::kRaw;
1070370b324cSopenharmony_ci    }
1071370b324cSopenharmony_ci    return S_OK;
1072370b324cSopenharmony_ci  }
1073370b324cSopenharmony_ci
1074370b324cSopenharmony_ci  return S_OK;
1075370b324cSopenharmony_ci}
1076370b324cSopenharmony_ci
1077370b324cSopenharmony_ciIMP_IInArchive_Props
1078370b324cSopenharmony_ciIMP_IInArchive_ArcProps
1079370b324cSopenharmony_ci
1080370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
1081370b324cSopenharmony_ci{
1082370b324cSopenharmony_ci  *numItems = HashPairs.Size();
1083370b324cSopenharmony_ci  return S_OK;
1084370b324cSopenharmony_ci}
1085370b324cSopenharmony_ci
1086370b324cSopenharmony_cistatic void Add_OptSpace_String(UString &dest, const char *src)
1087370b324cSopenharmony_ci{
1088370b324cSopenharmony_ci  dest.Add_Space_if_NotEmpty();
1089370b324cSopenharmony_ci  dest += src;
1090370b324cSopenharmony_ci}
1091370b324cSopenharmony_ci
1092370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1093370b324cSopenharmony_ci{
1094370b324cSopenharmony_ci  NWindows::NCOM::CPropVariant prop;
1095370b324cSopenharmony_ci  switch (propID)
1096370b324cSopenharmony_ci  {
1097370b324cSopenharmony_ci    case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
1098370b324cSopenharmony_ci    /*
1099370b324cSopenharmony_ci    case kpidErrorFlags:
1100370b324cSopenharmony_ci    {
1101370b324cSopenharmony_ci      UInt32 v = 0;
1102370b324cSopenharmony_ci      if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
1103370b324cSopenharmony_ci      // if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
1104370b324cSopenharmony_ci      if (v != 0)
1105370b324cSopenharmony_ci        prop = v;
1106370b324cSopenharmony_ci      break;
1107370b324cSopenharmony_ci    }
1108370b324cSopenharmony_ci    */
1109370b324cSopenharmony_ci    case kpidCharacts:
1110370b324cSopenharmony_ci    {
1111370b324cSopenharmony_ci      UString s;
1112370b324cSopenharmony_ci      if (_hashSize_Defined)
1113370b324cSopenharmony_ci      {
1114370b324cSopenharmony_ci        s.Add_Space_if_NotEmpty();
1115370b324cSopenharmony_ci        s.Add_UInt32(_hashSize * 8);
1116370b324cSopenharmony_ci        s += "-bit";
1117370b324cSopenharmony_ci      }
1118370b324cSopenharmony_ci      if (!_nameExtenstion.IsEmpty())
1119370b324cSopenharmony_ci      {
1120370b324cSopenharmony_ci        s.Add_Space_if_NotEmpty();
1121370b324cSopenharmony_ci        s += _nameExtenstion;
1122370b324cSopenharmony_ci      }
1123370b324cSopenharmony_ci      if (_is_PgpMethod)
1124370b324cSopenharmony_ci      {
1125370b324cSopenharmony_ci        Add_OptSpace_String(s, "PGP");
1126370b324cSopenharmony_ci        if (!_pgpMethod.IsEmpty())
1127370b324cSopenharmony_ci        {
1128370b324cSopenharmony_ci          s += ":";
1129370b324cSopenharmony_ci          s += _pgpMethod;
1130370b324cSopenharmony_ci        }
1131370b324cSopenharmony_ci      }
1132370b324cSopenharmony_ci      if (_is_ZeroMode)
1133370b324cSopenharmony_ci        Add_OptSpace_String(s, "ZERO");
1134370b324cSopenharmony_ci      if (_are_there_Tags)
1135370b324cSopenharmony_ci        Add_OptSpace_String(s, "TAG");
1136370b324cSopenharmony_ci      if (_are_there_Dirs)
1137370b324cSopenharmony_ci        Add_OptSpace_String(s, "DIRS");
1138370b324cSopenharmony_ci      prop = s;
1139370b324cSopenharmony_ci      break;
1140370b324cSopenharmony_ci    }
1141370b324cSopenharmony_ci
1142370b324cSopenharmony_ci    case kpidReadOnly:
1143370b324cSopenharmony_ci    {
1144370b324cSopenharmony_ci      if (_isArc)
1145370b324cSopenharmony_ci        if (!CanUpdate())
1146370b324cSopenharmony_ci          prop = true;
1147370b324cSopenharmony_ci      break;
1148370b324cSopenharmony_ci    }
1149370b324cSopenharmony_ci  }
1150370b324cSopenharmony_ci  prop.Detach(value);
1151370b324cSopenharmony_ci  return S_OK;
1152370b324cSopenharmony_ci}
1153370b324cSopenharmony_ci
1154370b324cSopenharmony_ci
1155370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
1156370b324cSopenharmony_ci{
1157370b324cSopenharmony_ci  // COM_TRY_BEGIN
1158370b324cSopenharmony_ci  NWindows::NCOM::CPropVariant prop;
1159370b324cSopenharmony_ci  CHashPair &hp = HashPairs[index];
1160370b324cSopenharmony_ci  switch (propID)
1161370b324cSopenharmony_ci  {
1162370b324cSopenharmony_ci    case kpidIsDir:
1163370b324cSopenharmony_ci    {
1164370b324cSopenharmony_ci      prop = hp.IsDir();
1165370b324cSopenharmony_ci      break;
1166370b324cSopenharmony_ci    }
1167370b324cSopenharmony_ci    case kpidPath:
1168370b324cSopenharmony_ci    {
1169370b324cSopenharmony_ci      UString path;
1170370b324cSopenharmony_ci      hp.Get_UString_Path(path);
1171370b324cSopenharmony_ci
1172370b324cSopenharmony_ci      NArchive::NItemName::ReplaceToOsSlashes_Remove_TailSlash(path,
1173370b324cSopenharmony_ci          true); // useBackslashReplacement
1174370b324cSopenharmony_ci
1175370b324cSopenharmony_ci      prop = path;
1176370b324cSopenharmony_ci      break;
1177370b324cSopenharmony_ci    }
1178370b324cSopenharmony_ci    case kpidSize:
1179370b324cSopenharmony_ci    {
1180370b324cSopenharmony_ci      // client needs processed size of last file
1181370b324cSopenharmony_ci      if (hp.Size_from_Disk_Defined)
1182370b324cSopenharmony_ci        prop = (UInt64)hp.Size_from_Disk;
1183370b324cSopenharmony_ci      else if (hp.Size_from_Arc_Defined)
1184370b324cSopenharmony_ci        prop = (UInt64)hp.Size_from_Arc;
1185370b324cSopenharmony_ci      break;
1186370b324cSopenharmony_ci    }
1187370b324cSopenharmony_ci    case kpidPackSize:
1188370b324cSopenharmony_ci    {
1189370b324cSopenharmony_ci      prop = (UInt64)hp.Hash.Size();
1190370b324cSopenharmony_ci      break;
1191370b324cSopenharmony_ci    }
1192370b324cSopenharmony_ci    case kpidMethod:
1193370b324cSopenharmony_ci    {
1194370b324cSopenharmony_ci      if (!hp.Method.IsEmpty())
1195370b324cSopenharmony_ci        prop = hp.Method;
1196370b324cSopenharmony_ci      break;
1197370b324cSopenharmony_ci    }
1198370b324cSopenharmony_ci  }
1199370b324cSopenharmony_ci  prop.Detach(value);
1200370b324cSopenharmony_ci  return S_OK;
1201370b324cSopenharmony_ci  // COM_TRY_END
1202370b324cSopenharmony_ci}
1203370b324cSopenharmony_ci
1204370b324cSopenharmony_ci
1205370b324cSopenharmony_cistatic HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOpenCallback *openCallback)
1206370b324cSopenharmony_ci{
1207370b324cSopenharmony_ci  buf.Free();
1208370b324cSopenharmony_ci  UInt64 len;
1209370b324cSopenharmony_ci  RINOK(InStream_AtBegin_GetSize(stream, len))
1210370b324cSopenharmony_ci  if (len == 0 || len >= ((UInt64)1 << 31))
1211370b324cSopenharmony_ci    return S_FALSE;
1212370b324cSopenharmony_ci  buf.Alloc((size_t)len);
1213370b324cSopenharmony_ci  UInt64 pos = 0;
1214370b324cSopenharmony_ci  // return ReadStream_FALSE(stream, buf, (size_t)len);
1215370b324cSopenharmony_ci  for (;;)
1216370b324cSopenharmony_ci  {
1217370b324cSopenharmony_ci    const UInt32 kBlockSize = ((UInt32)1 << 24);
1218370b324cSopenharmony_ci    const UInt32 curSize = (len < kBlockSize) ? (UInt32)len : kBlockSize;
1219370b324cSopenharmony_ci    UInt32 processedSizeLoc;
1220370b324cSopenharmony_ci    RINOK(stream->Read((Byte *)buf + pos, curSize, &processedSizeLoc))
1221370b324cSopenharmony_ci    if (processedSizeLoc == 0)
1222370b324cSopenharmony_ci      return E_FAIL;
1223370b324cSopenharmony_ci    len -= processedSizeLoc;
1224370b324cSopenharmony_ci    pos += processedSizeLoc;
1225370b324cSopenharmony_ci    if (len == 0)
1226370b324cSopenharmony_ci      return S_OK;
1227370b324cSopenharmony_ci    if (openCallback)
1228370b324cSopenharmony_ci    {
1229370b324cSopenharmony_ci      const UInt64 files = 0;
1230370b324cSopenharmony_ci      RINOK(openCallback->SetCompleted(&files, &pos))
1231370b324cSopenharmony_ci    }
1232370b324cSopenharmony_ci  }
1233370b324cSopenharmony_ci}
1234370b324cSopenharmony_ci
1235370b324cSopenharmony_ci
1236370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
1237370b324cSopenharmony_ci{
1238370b324cSopenharmony_ci  COM_TRY_BEGIN
1239370b324cSopenharmony_ci  {
1240370b324cSopenharmony_ci    Close();
1241370b324cSopenharmony_ci
1242370b324cSopenharmony_ci    CByteBuffer buf;
1243370b324cSopenharmony_ci    RINOK(ReadStream_to_Buf(stream, buf, openCallback))
1244370b324cSopenharmony_ci
1245370b324cSopenharmony_ci    CObjectVector<CHashPair> &pairs = HashPairs;
1246370b324cSopenharmony_ci
1247370b324cSopenharmony_ci    bool zeroMode = false;
1248370b324cSopenharmony_ci    bool cr_lf_Mode = false;
1249370b324cSopenharmony_ci    {
1250370b324cSopenharmony_ci      for (size_t i = 0; i < buf.Size(); i++)
1251370b324cSopenharmony_ci        if (buf[i] == 0)
1252370b324cSopenharmony_ci        {
1253370b324cSopenharmony_ci          zeroMode = true;
1254370b324cSopenharmony_ci          break;
1255370b324cSopenharmony_ci        }
1256370b324cSopenharmony_ci    }
1257370b324cSopenharmony_ci    _is_ZeroMode = zeroMode;
1258370b324cSopenharmony_ci    if (!zeroMode)
1259370b324cSopenharmony_ci      cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size());
1260370b324cSopenharmony_ci
1261370b324cSopenharmony_ci    if (openCallback)
1262370b324cSopenharmony_ci    {
1263370b324cSopenharmony_ci      Z7_DECL_CMyComPtr_QI_FROM(
1264370b324cSopenharmony_ci          IArchiveOpenVolumeCallback,
1265370b324cSopenharmony_ci          openVolumeCallback, openCallback)
1266370b324cSopenharmony_ci      if (openVolumeCallback)
1267370b324cSopenharmony_ci      {
1268370b324cSopenharmony_ci        NCOM::CPropVariant prop;
1269370b324cSopenharmony_ci        RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
1270370b324cSopenharmony_ci        if (prop.vt == VT_BSTR)
1271370b324cSopenharmony_ci          _nameExtenstion = GetMethod_from_FileName(prop.bstrVal);
1272370b324cSopenharmony_ci      }
1273370b324cSopenharmony_ci    }
1274370b324cSopenharmony_ci
1275370b324cSopenharmony_ci    bool cksumMode = false;
1276370b324cSopenharmony_ci    if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum"))
1277370b324cSopenharmony_ci      cksumMode = true;
1278370b324cSopenharmony_ci    _is_CksumMode = cksumMode;
1279370b324cSopenharmony_ci
1280370b324cSopenharmony_ci    size_t pos = 0;
1281370b324cSopenharmony_ci    AString s;
1282370b324cSopenharmony_ci    bool minusMode = false;
1283370b324cSopenharmony_ci    unsigned numLines = 0;
1284370b324cSopenharmony_ci
1285370b324cSopenharmony_ci    while (pos < buf.Size())
1286370b324cSopenharmony_ci    {
1287370b324cSopenharmony_ci      if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s))
1288370b324cSopenharmony_ci        return S_FALSE;
1289370b324cSopenharmony_ci      numLines++;
1290370b324cSopenharmony_ci      if (s.IsEmpty())
1291370b324cSopenharmony_ci        continue;
1292370b324cSopenharmony_ci
1293370b324cSopenharmony_ci      if (s.IsPrefixedBy_Ascii_NoCase("; "))
1294370b324cSopenharmony_ci      {
1295370b324cSopenharmony_ci        if (numLines != 1)
1296370b324cSopenharmony_ci          return S_FALSE;
1297370b324cSopenharmony_ci        // comment line of FileVerifier++
1298370b324cSopenharmony_ci        continue;
1299370b324cSopenharmony_ci      }
1300370b324cSopenharmony_ci
1301370b324cSopenharmony_ci      if (s.IsPrefixedBy_Ascii_NoCase("-----"))
1302370b324cSopenharmony_ci      {
1303370b324cSopenharmony_ci        if (minusMode)
1304370b324cSopenharmony_ci          break; // end of pgp mode
1305370b324cSopenharmony_ci        minusMode = true;
1306370b324cSopenharmony_ci        if (s.IsPrefixedBy_Ascii_NoCase("-----BEGIN PGP SIGNED MESSAGE"))
1307370b324cSopenharmony_ci        {
1308370b324cSopenharmony_ci          if (_is_PgpMethod)
1309370b324cSopenharmony_ci            return S_FALSE;
1310370b324cSopenharmony_ci          if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s))
1311370b324cSopenharmony_ci            return S_FALSE;
1312370b324cSopenharmony_ci          const char *kStart = "Hash: ";
1313370b324cSopenharmony_ci          if (!s.IsPrefixedBy_Ascii_NoCase(kStart))
1314370b324cSopenharmony_ci            return S_FALSE;
1315370b324cSopenharmony_ci          _pgpMethod = s.Ptr((unsigned)strlen(kStart));
1316370b324cSopenharmony_ci          _is_PgpMethod = true;
1317370b324cSopenharmony_ci        }
1318370b324cSopenharmony_ci        continue;
1319370b324cSopenharmony_ci      }
1320370b324cSopenharmony_ci
1321370b324cSopenharmony_ci      CHashPair pair;
1322370b324cSopenharmony_ci      pair.FullLine = s;
1323370b324cSopenharmony_ci      if (cksumMode)
1324370b324cSopenharmony_ci      {
1325370b324cSopenharmony_ci        if (!pair.ParseCksum(s))
1326370b324cSopenharmony_ci          return S_FALSE;
1327370b324cSopenharmony_ci      }
1328370b324cSopenharmony_ci      else if (!pair.Parse(s))
1329370b324cSopenharmony_ci        return S_FALSE;
1330370b324cSopenharmony_ci      pairs.Add(pair);
1331370b324cSopenharmony_ci    }
1332370b324cSopenharmony_ci
1333370b324cSopenharmony_ci    {
1334370b324cSopenharmony_ci      unsigned hashSize = 0;
1335370b324cSopenharmony_ci      bool hashSize_Dismatch = false;
1336370b324cSopenharmony_ci      for (unsigned i = 0; i < HashPairs.Size(); i++)
1337370b324cSopenharmony_ci      {
1338370b324cSopenharmony_ci        const CHashPair &hp = HashPairs[i];
1339370b324cSopenharmony_ci        if (i == 0)
1340370b324cSopenharmony_ci          hashSize = (unsigned)hp.Hash.Size();
1341370b324cSopenharmony_ci        else
1342370b324cSopenharmony_ci          if (hashSize != hp.Hash.Size())
1343370b324cSopenharmony_ci            hashSize_Dismatch = true;
1344370b324cSopenharmony_ci
1345370b324cSopenharmony_ci        if (hp.IsBSD)
1346370b324cSopenharmony_ci          _are_there_Tags = true;
1347370b324cSopenharmony_ci        if (!_are_there_Dirs && hp.IsDir())
1348370b324cSopenharmony_ci          _are_there_Dirs = true;
1349370b324cSopenharmony_ci      }
1350370b324cSopenharmony_ci      if (!hashSize_Dismatch && hashSize != 0)
1351370b324cSopenharmony_ci      {
1352370b324cSopenharmony_ci        _hashSize = hashSize;
1353370b324cSopenharmony_ci        _hashSize_Defined = true;
1354370b324cSopenharmony_ci      }
1355370b324cSopenharmony_ci    }
1356370b324cSopenharmony_ci
1357370b324cSopenharmony_ci    _phySize = buf.Size();
1358370b324cSopenharmony_ci    _isArc = true;
1359370b324cSopenharmony_ci    return S_OK;
1360370b324cSopenharmony_ci  }
1361370b324cSopenharmony_ci  COM_TRY_END
1362370b324cSopenharmony_ci}
1363370b324cSopenharmony_ci
1364370b324cSopenharmony_ci
1365370b324cSopenharmony_civoid CHandler::ClearVars()
1366370b324cSopenharmony_ci{
1367370b324cSopenharmony_ci  _phySize = 0;
1368370b324cSopenharmony_ci  _isArc = false;
1369370b324cSopenharmony_ci  _is_CksumMode = false;
1370370b324cSopenharmony_ci  _is_PgpMethod = false;
1371370b324cSopenharmony_ci  _is_ZeroMode = false;
1372370b324cSopenharmony_ci  _are_there_Tags = false;
1373370b324cSopenharmony_ci  _are_there_Dirs = false;
1374370b324cSopenharmony_ci  _hashSize_Defined = false;
1375370b324cSopenharmony_ci  _hashSize = 0;
1376370b324cSopenharmony_ci}
1377370b324cSopenharmony_ci
1378370b324cSopenharmony_ci
1379370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Close())
1380370b324cSopenharmony_ci{
1381370b324cSopenharmony_ci  ClearVars();
1382370b324cSopenharmony_ci  _nameExtenstion.Empty();
1383370b324cSopenharmony_ci  _pgpMethod.Empty();
1384370b324cSopenharmony_ci  HashPairs.Clear();
1385370b324cSopenharmony_ci  return S_OK;
1386370b324cSopenharmony_ci}
1387370b324cSopenharmony_ci
1388370b324cSopenharmony_ci
1389370b324cSopenharmony_cistatic bool CheckDigests(const Byte *a, const Byte *b, size_t size)
1390370b324cSopenharmony_ci{
1391370b324cSopenharmony_ci  if (size <= 8)
1392370b324cSopenharmony_ci  {
1393370b324cSopenharmony_ci    /* we use reversed order for one digest, when text representation
1394370b324cSopenharmony_ci       uses big-order for crc-32 and crc-64 */
1395370b324cSopenharmony_ci    for (size_t i = 0; i < size; i++)
1396370b324cSopenharmony_ci      if (a[i] != b[size - 1 - i])
1397370b324cSopenharmony_ci        return false;
1398370b324cSopenharmony_ci    return true;
1399370b324cSopenharmony_ci  }
1400370b324cSopenharmony_ci  {
1401370b324cSopenharmony_ci    for (size_t i = 0; i < size; i++)
1402370b324cSopenharmony_ci      if (a[i] != b[i])
1403370b324cSopenharmony_ci        return false;
1404370b324cSopenharmony_ci    return true;
1405370b324cSopenharmony_ci  }
1406370b324cSopenharmony_ci}
1407370b324cSopenharmony_ci
1408370b324cSopenharmony_ci
1409370b324cSopenharmony_cistatic void AddDefaultMethod(UStringVector &methods, unsigned size)
1410370b324cSopenharmony_ci{
1411370b324cSopenharmony_ci  const char *m = NULL;
1412370b324cSopenharmony_ci       if (size == 32) m = "sha256";
1413370b324cSopenharmony_ci  else if (size == 20) m = "sha1";
1414370b324cSopenharmony_ci  else if (size == 16) m = "md5";
1415370b324cSopenharmony_ci  else if (size ==  8) m = "crc64";
1416370b324cSopenharmony_ci  else if (size ==  4) m = "crc32";
1417370b324cSopenharmony_ci  else
1418370b324cSopenharmony_ci    return;
1419370b324cSopenharmony_ci  #ifdef Z7_EXTERNAL_CODECS
1420370b324cSopenharmony_ci  const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
1421370b324cSopenharmony_ci  #endif
1422370b324cSopenharmony_ci  CMethodId id;
1423370b324cSopenharmony_ci  if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS
1424370b324cSopenharmony_ci      AString(m), id))
1425370b324cSopenharmony_ci    methods.Add(UString(m));
1426370b324cSopenharmony_ci}
1427370b324cSopenharmony_ci
1428370b324cSopenharmony_ci
1429370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1430370b324cSopenharmony_ci    Int32 testMode, IArchiveExtractCallback *extractCallback))
1431370b324cSopenharmony_ci{
1432370b324cSopenharmony_ci  COM_TRY_BEGIN
1433370b324cSopenharmony_ci
1434370b324cSopenharmony_ci  /*
1435370b324cSopenharmony_ci  if (testMode == 0)
1436370b324cSopenharmony_ci    return E_NOTIMPL;
1437370b324cSopenharmony_ci  */
1438370b324cSopenharmony_ci
1439370b324cSopenharmony_ci  const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1440370b324cSopenharmony_ci  if (allFilesMode)
1441370b324cSopenharmony_ci    numItems = HashPairs.Size();
1442370b324cSopenharmony_ci  if (numItems == 0)
1443370b324cSopenharmony_ci    return S_OK;
1444370b324cSopenharmony_ci
1445370b324cSopenharmony_ci  #ifdef Z7_EXTERNAL_CODECS
1446370b324cSopenharmony_ci  const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
1447370b324cSopenharmony_ci  #endif
1448370b324cSopenharmony_ci
1449370b324cSopenharmony_ci  CHashBundle hb_Glob;
1450370b324cSopenharmony_ci  // UStringVector methods = options.Methods;
1451370b324cSopenharmony_ci  UStringVector methods;
1452370b324cSopenharmony_ci
1453370b324cSopenharmony_ci  if (methods.IsEmpty() && !_nameExtenstion.IsEmpty())
1454370b324cSopenharmony_ci  {
1455370b324cSopenharmony_ci    AString utf;
1456370b324cSopenharmony_ci    ConvertUnicodeToUTF8(_nameExtenstion, utf);
1457370b324cSopenharmony_ci    CMethodId id;
1458370b324cSopenharmony_ci    if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id))
1459370b324cSopenharmony_ci      methods.Add(_nameExtenstion);
1460370b324cSopenharmony_ci  }
1461370b324cSopenharmony_ci
1462370b324cSopenharmony_ci  if (methods.IsEmpty() && !_pgpMethod.IsEmpty())
1463370b324cSopenharmony_ci  {
1464370b324cSopenharmony_ci    CMethodId id;
1465370b324cSopenharmony_ci    if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS _pgpMethod, id))
1466370b324cSopenharmony_ci      methods.Add(UString(_pgpMethod));
1467370b324cSopenharmony_ci  }
1468370b324cSopenharmony_ci
1469370b324cSopenharmony_ci  if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined)
1470370b324cSopenharmony_ci    AddDefaultMethod(methods, _hashSize);
1471370b324cSopenharmony_ci
1472370b324cSopenharmony_ci  RINOK(hb_Glob.SetMethods(
1473370b324cSopenharmony_ci      EXTERNAL_CODECS_LOC_VARS
1474370b324cSopenharmony_ci      methods))
1475370b324cSopenharmony_ci
1476370b324cSopenharmony_ci  Z7_DECL_CMyComPtr_QI_FROM(
1477370b324cSopenharmony_ci      IArchiveUpdateCallbackFile,
1478370b324cSopenharmony_ci      updateCallbackFile, extractCallback)
1479370b324cSopenharmony_ci  if (!updateCallbackFile)
1480370b324cSopenharmony_ci    return E_NOTIMPL;
1481370b324cSopenharmony_ci  {
1482370b324cSopenharmony_ci    Z7_DECL_CMyComPtr_QI_FROM(
1483370b324cSopenharmony_ci        IArchiveGetDiskProperty,
1484370b324cSopenharmony_ci        GetDiskProperty, extractCallback)
1485370b324cSopenharmony_ci    if (GetDiskProperty)
1486370b324cSopenharmony_ci    {
1487370b324cSopenharmony_ci      UInt64 totalSize = 0;
1488370b324cSopenharmony_ci      UInt32 i;
1489370b324cSopenharmony_ci      for (i = 0; i < numItems; i++)
1490370b324cSopenharmony_ci      {
1491370b324cSopenharmony_ci        const UInt32 index = allFilesMode ? i : indices[i];
1492370b324cSopenharmony_ci        const CHashPair &hp = HashPairs[index];
1493370b324cSopenharmony_ci        if (hp.IsDir())
1494370b324cSopenharmony_ci          continue;
1495370b324cSopenharmony_ci        {
1496370b324cSopenharmony_ci          NCOM::CPropVariant prop;
1497370b324cSopenharmony_ci          RINOK(GetDiskProperty->GetDiskProperty(index, kpidSize, &prop))
1498370b324cSopenharmony_ci          if (prop.vt != VT_UI8)
1499370b324cSopenharmony_ci            continue;
1500370b324cSopenharmony_ci          totalSize += prop.uhVal.QuadPart;
1501370b324cSopenharmony_ci        }
1502370b324cSopenharmony_ci      }
1503370b324cSopenharmony_ci      RINOK(extractCallback->SetTotal(totalSize))
1504370b324cSopenharmony_ci      // RINOK(Hash_SetTotalUnpacked->Hash_SetTotalUnpacked(indices, numItems));
1505370b324cSopenharmony_ci    }
1506370b324cSopenharmony_ci  }
1507370b324cSopenharmony_ci
1508370b324cSopenharmony_ci  const UInt32 kBufSize = 1 << 15;
1509370b324cSopenharmony_ci  CHashMidBuf buf;
1510370b324cSopenharmony_ci  if (!buf.Alloc(kBufSize))
1511370b324cSopenharmony_ci    return E_OUTOFMEMORY;
1512370b324cSopenharmony_ci
1513370b324cSopenharmony_ci  CLocalProgress *lps = new CLocalProgress;
1514370b324cSopenharmony_ci  CMyComPtr<ICompressProgressInfo> progress = lps;
1515370b324cSopenharmony_ci  lps->Init(extractCallback, false);
1516370b324cSopenharmony_ci  lps->InSize = lps->OutSize = 0;
1517370b324cSopenharmony_ci
1518370b324cSopenharmony_ci  UInt32 i;
1519370b324cSopenharmony_ci  for (i = 0; i < numItems; i++)
1520370b324cSopenharmony_ci  {
1521370b324cSopenharmony_ci    RINOK(lps->SetCur())
1522370b324cSopenharmony_ci    const UInt32 index = allFilesMode ? i : indices[i];
1523370b324cSopenharmony_ci
1524370b324cSopenharmony_ci    CHashPair &hp = HashPairs[index];
1525370b324cSopenharmony_ci
1526370b324cSopenharmony_ci    UString path;
1527370b324cSopenharmony_ci    hp.Get_UString_Path(path);
1528370b324cSopenharmony_ci
1529370b324cSopenharmony_ci    CMyComPtr<ISequentialInStream> inStream;
1530370b324cSopenharmony_ci    const bool isDir = hp.IsDir();
1531370b324cSopenharmony_ci    if (!isDir)
1532370b324cSopenharmony_ci    {
1533370b324cSopenharmony_ci      RINOK(updateCallbackFile->GetStream2(index, &inStream, NUpdateNotifyOp::kHashRead))
1534370b324cSopenharmony_ci      if (!inStream)
1535370b324cSopenharmony_ci      {
1536370b324cSopenharmony_ci        continue; // we have shown error in GetStream2()
1537370b324cSopenharmony_ci      }
1538370b324cSopenharmony_ci      // askMode = NArchive::NExtract::NAskMode::kSkip;
1539370b324cSopenharmony_ci    }
1540370b324cSopenharmony_ci
1541370b324cSopenharmony_ci    Int32 askMode = testMode ?
1542370b324cSopenharmony_ci        NArchive::NExtract::NAskMode::kTest :
1543370b324cSopenharmony_ci        NArchive::NExtract::NAskMode::kExtract;
1544370b324cSopenharmony_ci
1545370b324cSopenharmony_ci    CMyComPtr<ISequentialOutStream> realOutStream;
1546370b324cSopenharmony_ci    RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
1547370b324cSopenharmony_ci
1548370b324cSopenharmony_ci    /* PrepareOperation() can expect kExtract to set
1549370b324cSopenharmony_ci       Attrib and security of output file */
1550370b324cSopenharmony_ci    askMode = NArchive::NExtract::NAskMode::kReadExternal;
1551370b324cSopenharmony_ci
1552370b324cSopenharmony_ci    extractCallback->PrepareOperation(askMode);
1553370b324cSopenharmony_ci
1554370b324cSopenharmony_ci    const bool isAltStream = false;
1555370b324cSopenharmony_ci
1556370b324cSopenharmony_ci    UInt64 fileSize = 0;
1557370b324cSopenharmony_ci
1558370b324cSopenharmony_ci    CHashBundle hb_Loc;
1559370b324cSopenharmony_ci
1560370b324cSopenharmony_ci    CHashBundle *hb_Use = &hb_Glob;
1561370b324cSopenharmony_ci
1562370b324cSopenharmony_ci    HRESULT res_SetMethods = S_OK;
1563370b324cSopenharmony_ci
1564370b324cSopenharmony_ci    UStringVector methods_loc;
1565370b324cSopenharmony_ci
1566370b324cSopenharmony_ci    if (!hp.Method.IsEmpty())
1567370b324cSopenharmony_ci    {
1568370b324cSopenharmony_ci      hb_Use = &hb_Loc;
1569370b324cSopenharmony_ci      CMethodId id;
1570370b324cSopenharmony_ci      if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id))
1571370b324cSopenharmony_ci      {
1572370b324cSopenharmony_ci        methods_loc.Add(UString(hp.Method));
1573370b324cSopenharmony_ci        RINOK(hb_Loc.SetMethods(
1574370b324cSopenharmony_ci            EXTERNAL_CODECS_LOC_VARS
1575370b324cSopenharmony_ci            methods_loc))
1576370b324cSopenharmony_ci      }
1577370b324cSopenharmony_ci      else
1578370b324cSopenharmony_ci        res_SetMethods = E_NOTIMPL;
1579370b324cSopenharmony_ci    }
1580370b324cSopenharmony_ci    else if (methods.IsEmpty())
1581370b324cSopenharmony_ci    {
1582370b324cSopenharmony_ci      AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size());
1583370b324cSopenharmony_ci      if (!methods_loc.IsEmpty())
1584370b324cSopenharmony_ci      {
1585370b324cSopenharmony_ci        hb_Use = &hb_Loc;
1586370b324cSopenharmony_ci        RINOK(hb_Loc.SetMethods(
1587370b324cSopenharmony_ci            EXTERNAL_CODECS_LOC_VARS
1588370b324cSopenharmony_ci            methods_loc))
1589370b324cSopenharmony_ci      }
1590370b324cSopenharmony_ci    }
1591370b324cSopenharmony_ci
1592370b324cSopenharmony_ci    const bool isSupportedMode = hp.IsSupportedMode();
1593370b324cSopenharmony_ci    hb_Use->InitForNewFile();
1594370b324cSopenharmony_ci
1595370b324cSopenharmony_ci    if (inStream)
1596370b324cSopenharmony_ci    {
1597370b324cSopenharmony_ci      for (UInt32 step = 0;; step++)
1598370b324cSopenharmony_ci      {
1599370b324cSopenharmony_ci        if ((step & 0xFF) == 0)
1600370b324cSopenharmony_ci        {
1601370b324cSopenharmony_ci          RINOK(progress->SetRatioInfo(NULL, &fileSize))
1602370b324cSopenharmony_ci        }
1603370b324cSopenharmony_ci        UInt32 size;
1604370b324cSopenharmony_ci        RINOK(inStream->Read(buf, kBufSize, &size))
1605370b324cSopenharmony_ci        if (size == 0)
1606370b324cSopenharmony_ci          break;
1607370b324cSopenharmony_ci        hb_Use->Update(buf, size);
1608370b324cSopenharmony_ci        if (realOutStream)
1609370b324cSopenharmony_ci        {
1610370b324cSopenharmony_ci          RINOK(WriteStream(realOutStream, buf, size))
1611370b324cSopenharmony_ci        }
1612370b324cSopenharmony_ci        fileSize += size;
1613370b324cSopenharmony_ci      }
1614370b324cSopenharmony_ci
1615370b324cSopenharmony_ci      hp.Size_from_Disk = fileSize;
1616370b324cSopenharmony_ci      hp.Size_from_Disk_Defined = true;
1617370b324cSopenharmony_ci    }
1618370b324cSopenharmony_ci
1619370b324cSopenharmony_ci    realOutStream.Release();
1620370b324cSopenharmony_ci    inStream.Release();
1621370b324cSopenharmony_ci
1622370b324cSopenharmony_ci    lps->InSize += hp.Hash.Size();
1623370b324cSopenharmony_ci    lps->OutSize += fileSize;
1624370b324cSopenharmony_ci
1625370b324cSopenharmony_ci    hb_Use->Final(isDir, isAltStream, path);
1626370b324cSopenharmony_ci
1627370b324cSopenharmony_ci    Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod;
1628370b324cSopenharmony_ci    if (isSupportedMode
1629370b324cSopenharmony_ci        && res_SetMethods != E_NOTIMPL
1630370b324cSopenharmony_ci        && hb_Use->Hashers.Size() > 0
1631370b324cSopenharmony_ci        )
1632370b324cSopenharmony_ci    {
1633370b324cSopenharmony_ci      const CHasherState &hs = hb_Use->Hashers[0];
1634370b324cSopenharmony_ci      if (hs.DigestSize == hp.Hash.Size())
1635370b324cSopenharmony_ci      {
1636370b324cSopenharmony_ci        opRes = NArchive::NExtract::NOperationResult::kCRCError;
1637370b324cSopenharmony_ci        if (CheckDigests(hp.Hash, hs.Digests[0], hs.DigestSize))
1638370b324cSopenharmony_ci          if (!hp.Size_from_Arc_Defined || hp.Size_from_Arc == fileSize)
1639370b324cSopenharmony_ci            opRes = NArchive::NExtract::NOperationResult::kOK;
1640370b324cSopenharmony_ci      }
1641370b324cSopenharmony_ci    }
1642370b324cSopenharmony_ci
1643370b324cSopenharmony_ci    RINOK(extractCallback->SetOperationResult(opRes))
1644370b324cSopenharmony_ci  }
1645370b324cSopenharmony_ci
1646370b324cSopenharmony_ci  return lps->SetCur();
1647370b324cSopenharmony_ci
1648370b324cSopenharmony_ci  COM_TRY_END
1649370b324cSopenharmony_ci}
1650370b324cSopenharmony_ci
1651370b324cSopenharmony_ci
1652370b324cSopenharmony_ci// ---------- UPDATE ----------
1653370b324cSopenharmony_ci
1654370b324cSopenharmony_cistruct CUpdateItem
1655370b324cSopenharmony_ci{
1656370b324cSopenharmony_ci  int IndexInArc;
1657370b324cSopenharmony_ci  unsigned IndexInClient;
1658370b324cSopenharmony_ci  UInt64 Size;
1659370b324cSopenharmony_ci  bool NewData;
1660370b324cSopenharmony_ci  bool NewProps;
1661370b324cSopenharmony_ci  bool IsDir;
1662370b324cSopenharmony_ci  UString Path;
1663370b324cSopenharmony_ci
1664370b324cSopenharmony_ci  CUpdateItem(): Size(0), IsDir(false) {}
1665370b324cSopenharmony_ci};
1666370b324cSopenharmony_ci
1667370b324cSopenharmony_ci
1668370b324cSopenharmony_cistatic HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId,
1669370b324cSopenharmony_ci    UString &res,
1670370b324cSopenharmony_ci    bool convertSlash)
1671370b324cSopenharmony_ci{
1672370b324cSopenharmony_ci  NCOM::CPropVariant prop;
1673370b324cSopenharmony_ci  RINOK(callback->GetProperty(index, propId, &prop))
1674370b324cSopenharmony_ci  if (prop.vt == VT_BSTR)
1675370b324cSopenharmony_ci  {
1676370b324cSopenharmony_ci    res = prop.bstrVal;
1677370b324cSopenharmony_ci    if (convertSlash)
1678370b324cSopenharmony_ci      NArchive::NItemName::ReplaceSlashes_OsToUnix(res);
1679370b324cSopenharmony_ci  }
1680370b324cSopenharmony_ci  else if (prop.vt != VT_EMPTY)
1681370b324cSopenharmony_ci    return E_INVALIDARG;
1682370b324cSopenharmony_ci  return S_OK;
1683370b324cSopenharmony_ci}
1684370b324cSopenharmony_ci
1685370b324cSopenharmony_ci
1686370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
1687370b324cSopenharmony_ci{
1688370b324cSopenharmony_ci  *type = NFileTimeType::kUnix;
1689370b324cSopenharmony_ci  return S_OK;
1690370b324cSopenharmony_ci}
1691370b324cSopenharmony_ci
1692370b324cSopenharmony_ci
1693370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
1694370b324cSopenharmony_ci    IArchiveUpdateCallback *callback))
1695370b324cSopenharmony_ci{
1696370b324cSopenharmony_ci  COM_TRY_BEGIN
1697370b324cSopenharmony_ci
1698370b324cSopenharmony_ci  if (_isArc && !CanUpdate())
1699370b324cSopenharmony_ci    return E_NOTIMPL;
1700370b324cSopenharmony_ci
1701370b324cSopenharmony_ci  /*
1702370b324cSopenharmony_ci  Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp,
1703370b324cSopenharmony_ci      reportArcProp, callback)
1704370b324cSopenharmony_ci  */
1705370b324cSopenharmony_ci
1706370b324cSopenharmony_ci  CObjectVector<CUpdateItem> updateItems;
1707370b324cSopenharmony_ci
1708370b324cSopenharmony_ci  UInt64 complexity = 0;
1709370b324cSopenharmony_ci
1710370b324cSopenharmony_ci  UInt32 i;
1711370b324cSopenharmony_ci  for (i = 0; i < numItems; i++)
1712370b324cSopenharmony_ci  {
1713370b324cSopenharmony_ci    CUpdateItem ui;
1714370b324cSopenharmony_ci    Int32 newData;
1715370b324cSopenharmony_ci    Int32 newProps;
1716370b324cSopenharmony_ci    UInt32 indexInArc;
1717370b324cSopenharmony_ci
1718370b324cSopenharmony_ci    if (!callback)
1719370b324cSopenharmony_ci      return E_FAIL;
1720370b324cSopenharmony_ci
1721370b324cSopenharmony_ci    RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc))
1722370b324cSopenharmony_ci
1723370b324cSopenharmony_ci    ui.NewProps = IntToBool(newProps);
1724370b324cSopenharmony_ci    ui.NewData = IntToBool(newData);
1725370b324cSopenharmony_ci    ui.IndexInArc = (int)indexInArc;
1726370b324cSopenharmony_ci    ui.IndexInClient = i;
1727370b324cSopenharmony_ci    if (IntToBool(newProps))
1728370b324cSopenharmony_ci    {
1729370b324cSopenharmony_ci      {
1730370b324cSopenharmony_ci        NCOM::CPropVariant prop;
1731370b324cSopenharmony_ci        RINOK(callback->GetProperty(i, kpidIsDir, &prop))
1732370b324cSopenharmony_ci        if (prop.vt == VT_EMPTY)
1733370b324cSopenharmony_ci          ui.IsDir = false;
1734370b324cSopenharmony_ci        else if (prop.vt != VT_BOOL)
1735370b324cSopenharmony_ci          return E_INVALIDARG;
1736370b324cSopenharmony_ci        else
1737370b324cSopenharmony_ci          ui.IsDir = (prop.boolVal != VARIANT_FALSE);
1738370b324cSopenharmony_ci      }
1739370b324cSopenharmony_ci
1740370b324cSopenharmony_ci      RINOK(GetPropString(callback, i, kpidPath, ui.Path,
1741370b324cSopenharmony_ci          true)) // convertSlash
1742370b324cSopenharmony_ci      /*
1743370b324cSopenharmony_ci      if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
1744370b324cSopenharmony_ci        ui.Name += '/';
1745370b324cSopenharmony_ci      */
1746370b324cSopenharmony_ci    }
1747370b324cSopenharmony_ci
1748370b324cSopenharmony_ci    if (IntToBool(newData))
1749370b324cSopenharmony_ci    {
1750370b324cSopenharmony_ci      NCOM::CPropVariant prop;
1751370b324cSopenharmony_ci      RINOK(callback->GetProperty(i, kpidSize, &prop))
1752370b324cSopenharmony_ci      if (prop.vt == VT_UI8)
1753370b324cSopenharmony_ci      {
1754370b324cSopenharmony_ci        ui.Size = prop.uhVal.QuadPart;
1755370b324cSopenharmony_ci        complexity += ui.Size;
1756370b324cSopenharmony_ci      }
1757370b324cSopenharmony_ci      else if (prop.vt == VT_EMPTY)
1758370b324cSopenharmony_ci        ui.Size = (UInt64)(Int64)-1;
1759370b324cSopenharmony_ci      else
1760370b324cSopenharmony_ci        return E_INVALIDARG;
1761370b324cSopenharmony_ci    }
1762370b324cSopenharmony_ci
1763370b324cSopenharmony_ci    updateItems.Add(ui);
1764370b324cSopenharmony_ci  }
1765370b324cSopenharmony_ci
1766370b324cSopenharmony_ci  if (complexity != 0)
1767370b324cSopenharmony_ci  {
1768370b324cSopenharmony_ci    RINOK(callback->SetTotal(complexity))
1769370b324cSopenharmony_ci  }
1770370b324cSopenharmony_ci
1771370b324cSopenharmony_ci  #ifdef Z7_EXTERNAL_CODECS
1772370b324cSopenharmony_ci  const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
1773370b324cSopenharmony_ci  #endif
1774370b324cSopenharmony_ci
1775370b324cSopenharmony_ci  CHashBundle hb;
1776370b324cSopenharmony_ci  UStringVector methods;
1777370b324cSopenharmony_ci  if (!_methods.IsEmpty())
1778370b324cSopenharmony_ci  {
1779370b324cSopenharmony_ci    FOR_VECTOR(k, _methods)
1780370b324cSopenharmony_ci    {
1781370b324cSopenharmony_ci      methods.Add(_methods[k]);
1782370b324cSopenharmony_ci    }
1783370b324cSopenharmony_ci  }
1784370b324cSopenharmony_ci  else if (_crcSize_WasSet)
1785370b324cSopenharmony_ci  {
1786370b324cSopenharmony_ci    AddDefaultMethod(methods, _crcSize);
1787370b324cSopenharmony_ci  }
1788370b324cSopenharmony_ci  else
1789370b324cSopenharmony_ci  {
1790370b324cSopenharmony_ci    Z7_DECL_CMyComPtr_QI_FROM(
1791370b324cSopenharmony_ci        IArchiveGetRootProps,
1792370b324cSopenharmony_ci        getRootProps, callback)
1793370b324cSopenharmony_ci    if (getRootProps)
1794370b324cSopenharmony_ci    {
1795370b324cSopenharmony_ci      NCOM::CPropVariant prop;
1796370b324cSopenharmony_ci      RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop))
1797370b324cSopenharmony_ci      if (prop.vt == VT_BSTR)
1798370b324cSopenharmony_ci      {
1799370b324cSopenharmony_ci        const UString method = GetMethod_from_FileName(prop.bstrVal);
1800370b324cSopenharmony_ci        if (!method.IsEmpty())
1801370b324cSopenharmony_ci          methods.Add(method);
1802370b324cSopenharmony_ci      }
1803370b324cSopenharmony_ci    }
1804370b324cSopenharmony_ci  }
1805370b324cSopenharmony_ci
1806370b324cSopenharmony_ci  RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods))
1807370b324cSopenharmony_ci
1808370b324cSopenharmony_ci  CLocalProgress *lps = new CLocalProgress;
1809370b324cSopenharmony_ci  CMyComPtr<ICompressProgressInfo> progress = lps;
1810370b324cSopenharmony_ci  lps->Init(callback, true);
1811370b324cSopenharmony_ci
1812370b324cSopenharmony_ci  const UInt32 kBufSize = 1 << 15;
1813370b324cSopenharmony_ci  CHashMidBuf buf;
1814370b324cSopenharmony_ci  if (!buf.Alloc(kBufSize))
1815370b324cSopenharmony_ci    return E_OUTOFMEMORY;
1816370b324cSopenharmony_ci
1817370b324cSopenharmony_ci  CDynLimBuf hashFileString((size_t)1 << 31);
1818370b324cSopenharmony_ci
1819370b324cSopenharmony_ci  CHashOptionsLocal options = _options;
1820370b324cSopenharmony_ci
1821370b324cSopenharmony_ci  if (_isArc)
1822370b324cSopenharmony_ci  {
1823370b324cSopenharmony_ci    if (!options.HashMode_Zero.Def && _is_ZeroMode)
1824370b324cSopenharmony_ci      options.HashMode_Zero.Val = true;
1825370b324cSopenharmony_ci    if (!options.HashMode_Tag.Def && _are_there_Tags)
1826370b324cSopenharmony_ci      options.HashMode_Tag.Val = true;
1827370b324cSopenharmony_ci    if (!options.HashMode_Dirs.Def && _are_there_Dirs)
1828370b324cSopenharmony_ci      options.HashMode_Dirs.Val = true;
1829370b324cSopenharmony_ci  }
1830370b324cSopenharmony_ci  if (options.HashMode_OnlyHash.Val && updateItems.Size() != 1)
1831370b324cSopenharmony_ci    options.HashMode_OnlyHash.Val = false;
1832370b324cSopenharmony_ci
1833370b324cSopenharmony_ci  lps->OutSize = 0;
1834370b324cSopenharmony_ci  complexity = 0;
1835370b324cSopenharmony_ci
1836370b324cSopenharmony_ci  for (i = 0; i < updateItems.Size(); i++)
1837370b324cSopenharmony_ci  {
1838370b324cSopenharmony_ci    lps->InSize = complexity;
1839370b324cSopenharmony_ci    RINOK(lps->SetCur())
1840370b324cSopenharmony_ci
1841370b324cSopenharmony_ci    const CUpdateItem &ui = updateItems[i];
1842370b324cSopenharmony_ci
1843370b324cSopenharmony_ci    /*
1844370b324cSopenharmony_ci    CHashPair item;
1845370b324cSopenharmony_ci    if (!ui.NewProps)
1846370b324cSopenharmony_ci      item = HashPairs[(unsigned)ui.IndexInArc];
1847370b324cSopenharmony_ci    */
1848370b324cSopenharmony_ci
1849370b324cSopenharmony_ci    if (ui.NewData)
1850370b324cSopenharmony_ci    {
1851370b324cSopenharmony_ci      UInt64 currentComplexity = ui.Size;
1852370b324cSopenharmony_ci      UInt64 fileSize = 0;
1853370b324cSopenharmony_ci
1854370b324cSopenharmony_ci      CMyComPtr<ISequentialInStream> fileInStream;
1855370b324cSopenharmony_ci      bool needWrite = true;
1856370b324cSopenharmony_ci      {
1857370b324cSopenharmony_ci        HRESULT res = callback->GetStream(ui.IndexInClient, &fileInStream);
1858370b324cSopenharmony_ci
1859370b324cSopenharmony_ci        if (res == S_FALSE)
1860370b324cSopenharmony_ci          needWrite = false;
1861370b324cSopenharmony_ci        else
1862370b324cSopenharmony_ci        {
1863370b324cSopenharmony_ci          RINOK(res)
1864370b324cSopenharmony_ci
1865370b324cSopenharmony_ci          if (fileInStream)
1866370b324cSopenharmony_ci          {
1867370b324cSopenharmony_ci            Z7_DECL_CMyComPtr_QI_FROM(
1868370b324cSopenharmony_ci                IStreamGetSize,
1869370b324cSopenharmony_ci                streamGetSize, fileInStream)
1870370b324cSopenharmony_ci            if (streamGetSize)
1871370b324cSopenharmony_ci            {
1872370b324cSopenharmony_ci              UInt64 size;
1873370b324cSopenharmony_ci              if (streamGetSize->GetSize(&size) == S_OK)
1874370b324cSopenharmony_ci                currentComplexity = size;
1875370b324cSopenharmony_ci            }
1876370b324cSopenharmony_ci            /*
1877370b324cSopenharmony_ci            Z7_DECL_CMyComPtr_QI_FROM(
1878370b324cSopenharmony_ci                IStreamGetProps,
1879370b324cSopenharmony_ci                getProps, fileInStream)
1880370b324cSopenharmony_ci            if (getProps)
1881370b324cSopenharmony_ci            {
1882370b324cSopenharmony_ci              FILETIME mTime;
1883370b324cSopenharmony_ci              UInt64 size2;
1884370b324cSopenharmony_ci              if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
1885370b324cSopenharmony_ci              {
1886370b324cSopenharmony_ci                currentComplexity = size2;
1887370b324cSopenharmony_ci                // item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
1888370b324cSopenharmony_ci              }
1889370b324cSopenharmony_ci            }
1890370b324cSopenharmony_ci            */
1891370b324cSopenharmony_ci          }
1892370b324cSopenharmony_ci          else
1893370b324cSopenharmony_ci          {
1894370b324cSopenharmony_ci            currentComplexity = 0;
1895370b324cSopenharmony_ci          }
1896370b324cSopenharmony_ci        }
1897370b324cSopenharmony_ci      }
1898370b324cSopenharmony_ci
1899370b324cSopenharmony_ci      hb.InitForNewFile();
1900370b324cSopenharmony_ci      const bool isDir = ui.IsDir;
1901370b324cSopenharmony_ci
1902370b324cSopenharmony_ci      if (needWrite && fileInStream && !isDir)
1903370b324cSopenharmony_ci      {
1904370b324cSopenharmony_ci        for (UInt32 step = 0;; step++)
1905370b324cSopenharmony_ci        {
1906370b324cSopenharmony_ci          if ((step & 0xFF) == 0)
1907370b324cSopenharmony_ci          {
1908370b324cSopenharmony_ci            RINOK(progress->SetRatioInfo(&fileSize, NULL))
1909370b324cSopenharmony_ci            // RINOK(callback->SetCompleted(&completeValue));
1910370b324cSopenharmony_ci          }
1911370b324cSopenharmony_ci          UInt32 size;
1912370b324cSopenharmony_ci          RINOK(fileInStream->Read(buf, kBufSize, &size))
1913370b324cSopenharmony_ci          if (size == 0)
1914370b324cSopenharmony_ci            break;
1915370b324cSopenharmony_ci          hb.Update(buf, size);
1916370b324cSopenharmony_ci          fileSize += size;
1917370b324cSopenharmony_ci        }
1918370b324cSopenharmony_ci        currentComplexity = fileSize;
1919370b324cSopenharmony_ci      }
1920370b324cSopenharmony_ci
1921370b324cSopenharmony_ci      fileInStream.Release();
1922370b324cSopenharmony_ci      const bool isAltStream = false;
1923370b324cSopenharmony_ci      hb.Final(isDir, isAltStream, ui.Path);
1924370b324cSopenharmony_ci
1925370b324cSopenharmony_ci      if (options.HashMode_Dirs.Val || !isDir)
1926370b324cSopenharmony_ci      {
1927370b324cSopenharmony_ci        if (!hb.Hashers.IsEmpty())
1928370b324cSopenharmony_ci          lps->OutSize += hb.Hashers[0].DigestSize;
1929370b324cSopenharmony_ci        WriteLine(hashFileString,
1930370b324cSopenharmony_ci            options,
1931370b324cSopenharmony_ci            ui.Path,
1932370b324cSopenharmony_ci            isDir,
1933370b324cSopenharmony_ci            hb);
1934370b324cSopenharmony_ci        if (hashFileString.IsError())
1935370b324cSopenharmony_ci          return E_OUTOFMEMORY;
1936370b324cSopenharmony_ci      }
1937370b324cSopenharmony_ci
1938370b324cSopenharmony_ci      complexity += currentComplexity;
1939370b324cSopenharmony_ci
1940370b324cSopenharmony_ci      /*
1941370b324cSopenharmony_ci      if (reportArcProp)
1942370b324cSopenharmony_ci      {
1943370b324cSopenharmony_ci        PROPVARIANT prop;
1944370b324cSopenharmony_ci        prop.vt = VT_EMPTY;
1945370b324cSopenharmony_ci        prop.wReserved1 = 0;
1946370b324cSopenharmony_ci
1947370b324cSopenharmony_ci        NCOM::PropVarEm_Set_UInt64(&prop, fileSize);
1948370b324cSopenharmony_ci        RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidSize, &prop));
1949370b324cSopenharmony_ci
1950370b324cSopenharmony_ci        for (unsigned k = 0; k < hb.Hashers.Size(); k++)
1951370b324cSopenharmony_ci        {
1952370b324cSopenharmony_ci          const CHasherState &hs = hb.Hashers[k];
1953370b324cSopenharmony_ci
1954370b324cSopenharmony_ci          if (hs.DigestSize == 4 && hs.Name.IsEqualTo_Ascii_NoCase("crc32"))
1955370b324cSopenharmony_ci          {
1956370b324cSopenharmony_ci            NCOM::PropVarEm_Set_UInt32(&prop, GetUi32(hs.Digests[k_HashCalc_Index_Current]));
1957370b324cSopenharmony_ci            RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidCRC, &prop));
1958370b324cSopenharmony_ci          }
1959370b324cSopenharmony_ci          else
1960370b324cSopenharmony_ci          {
1961370b324cSopenharmony_ci            RINOK(reportArcProp->ReportRawProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient,
1962370b324cSopenharmony_ci              kpidChecksum, hs.Digests[k_HashCalc_Index_Current],
1963370b324cSopenharmony_ci              hs.DigestSize, NPropDataType::kRaw));
1964370b324cSopenharmony_ci          }
1965370b324cSopenharmony_ci          RINOK(reportArcProp->ReportFinished(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, NArchive::NUpdate::NOperationResult::kOK));
1966370b324cSopenharmony_ci        }
1967370b324cSopenharmony_ci      }
1968370b324cSopenharmony_ci      */
1969370b324cSopenharmony_ci      RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
1970370b324cSopenharmony_ci    }
1971370b324cSopenharmony_ci    else
1972370b324cSopenharmony_ci    {
1973370b324cSopenharmony_ci      // old data
1974370b324cSopenharmony_ci      const CHashPair &existItem = HashPairs[(unsigned)ui.IndexInArc];
1975370b324cSopenharmony_ci      if (ui.NewProps)
1976370b324cSopenharmony_ci      {
1977370b324cSopenharmony_ci        WriteLine(hashFileString,
1978370b324cSopenharmony_ci            options,
1979370b324cSopenharmony_ci            ui.Path,
1980370b324cSopenharmony_ci            ui.IsDir,
1981370b324cSopenharmony_ci            existItem.Method, existItem.HashString
1982370b324cSopenharmony_ci            );
1983370b324cSopenharmony_ci      }
1984370b324cSopenharmony_ci      else
1985370b324cSopenharmony_ci      {
1986370b324cSopenharmony_ci        hashFileString += existItem.FullLine;
1987370b324cSopenharmony_ci        Add_LF(hashFileString, options);
1988370b324cSopenharmony_ci      }
1989370b324cSopenharmony_ci    }
1990370b324cSopenharmony_ci    if (hashFileString.IsError())
1991370b324cSopenharmony_ci      return E_OUTOFMEMORY;
1992370b324cSopenharmony_ci  }
1993370b324cSopenharmony_ci
1994370b324cSopenharmony_ci  RINOK(WriteStream(outStream, hashFileString, hashFileString.Len()))
1995370b324cSopenharmony_ci
1996370b324cSopenharmony_ci  return S_OK;
1997370b324cSopenharmony_ci  COM_TRY_END
1998370b324cSopenharmony_ci}
1999370b324cSopenharmony_ci
2000370b324cSopenharmony_ci
2001370b324cSopenharmony_ci
2002370b324cSopenharmony_ciHRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
2003370b324cSopenharmony_ci{
2004370b324cSopenharmony_ci  UString name = nameSpec;
2005370b324cSopenharmony_ci  name.MakeLower_Ascii();
2006370b324cSopenharmony_ci  if (name.IsEmpty())
2007370b324cSopenharmony_ci    return E_INVALIDARG;
2008370b324cSopenharmony_ci
2009370b324cSopenharmony_ci  if (name.IsEqualTo("m")) // "hm" hash method
2010370b324cSopenharmony_ci  {
2011370b324cSopenharmony_ci    // COneMethodInfo omi;
2012370b324cSopenharmony_ci    // RINOK(omi.ParseMethodFromPROPVARIANT(L"", value));
2013370b324cSopenharmony_ci    // _methods.Add(omi.MethodName); // change it. use omi.PropsString
2014370b324cSopenharmony_ci    if (value.vt != VT_BSTR)
2015370b324cSopenharmony_ci      return E_INVALIDARG;
2016370b324cSopenharmony_ci    UString s (value.bstrVal);
2017370b324cSopenharmony_ci    _methods.Add(s);
2018370b324cSopenharmony_ci    return S_OK;
2019370b324cSopenharmony_ci  }
2020370b324cSopenharmony_ci
2021370b324cSopenharmony_ci  if (name.IsEqualTo("flags"))
2022370b324cSopenharmony_ci  {
2023370b324cSopenharmony_ci    if (value.vt != VT_BSTR)
2024370b324cSopenharmony_ci      return E_INVALIDARG;
2025370b324cSopenharmony_ci    if (!_options.ParseString(value.bstrVal))
2026370b324cSopenharmony_ci      return E_INVALIDARG;
2027370b324cSopenharmony_ci    return S_OK;
2028370b324cSopenharmony_ci  }
2029370b324cSopenharmony_ci
2030370b324cSopenharmony_ci  if (name.IsPrefixedBy_Ascii_NoCase("crc"))
2031370b324cSopenharmony_ci  {
2032370b324cSopenharmony_ci    name.Delete(0, 3);
2033370b324cSopenharmony_ci    _crcSize = 4;
2034370b324cSopenharmony_ci    _crcSize_WasSet = true;
2035370b324cSopenharmony_ci    return ParsePropToUInt32(name, value, _crcSize);
2036370b324cSopenharmony_ci  }
2037370b324cSopenharmony_ci
2038370b324cSopenharmony_ci  // common properties
2039370b324cSopenharmony_ci  if (name.IsPrefixedBy_Ascii_NoCase("mt")
2040370b324cSopenharmony_ci      || name.IsPrefixedBy_Ascii_NoCase("memuse"))
2041370b324cSopenharmony_ci    return S_OK;
2042370b324cSopenharmony_ci
2043370b324cSopenharmony_ci  return E_INVALIDARG;
2044370b324cSopenharmony_ci}
2045370b324cSopenharmony_ci
2046370b324cSopenharmony_ci
2047370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
2048370b324cSopenharmony_ci{
2049370b324cSopenharmony_ci  COM_TRY_BEGIN
2050370b324cSopenharmony_ci
2051370b324cSopenharmony_ci  InitProps();
2052370b324cSopenharmony_ci
2053370b324cSopenharmony_ci  for (UInt32 i = 0; i < numProps; i++)
2054370b324cSopenharmony_ci  {
2055370b324cSopenharmony_ci    RINOK(SetProperty(names[i], values[i]))
2056370b324cSopenharmony_ci  }
2057370b324cSopenharmony_ci  return S_OK;
2058370b324cSopenharmony_ci  COM_TRY_END
2059370b324cSopenharmony_ci}
2060370b324cSopenharmony_ci
2061370b324cSopenharmony_ciCHandler::CHandler()
2062370b324cSopenharmony_ci{
2063370b324cSopenharmony_ci  ClearVars();
2064370b324cSopenharmony_ci  InitProps();
2065370b324cSopenharmony_ci}
2066370b324cSopenharmony_ci
2067370b324cSopenharmony_ci}
2068370b324cSopenharmony_ci
2069370b324cSopenharmony_ci
2070370b324cSopenharmony_ci
2071370b324cSopenharmony_cistatic IInArchive  *CreateHashHandler_In()  { return new NHash::CHandler; }
2072370b324cSopenharmony_cistatic IOutArchive *CreateHashHandler_Out() { return new NHash::CHandler; }
2073370b324cSopenharmony_ci
2074370b324cSopenharmony_civoid Codecs_AddHashArcHandler(CCodecs *codecs)
2075370b324cSopenharmony_ci{
2076370b324cSopenharmony_ci  {
2077370b324cSopenharmony_ci    CArcInfoEx item;
2078370b324cSopenharmony_ci
2079370b324cSopenharmony_ci    item.Name = "Hash";
2080370b324cSopenharmony_ci    item.CreateInArchive = CreateHashHandler_In;
2081370b324cSopenharmony_ci    item.CreateOutArchive = CreateHashHandler_Out;
2082370b324cSopenharmony_ci    item.IsArcFunc = NULL;
2083370b324cSopenharmony_ci    item.Flags =
2084370b324cSopenharmony_ci        NArcInfoFlags::kKeepName
2085370b324cSopenharmony_ci      | NArcInfoFlags::kStartOpen
2086370b324cSopenharmony_ci      | NArcInfoFlags::kByExtOnlyOpen
2087370b324cSopenharmony_ci      // | NArcInfoFlags::kPureStartOpen
2088370b324cSopenharmony_ci      | NArcInfoFlags::kHashHandler
2089370b324cSopenharmony_ci      ;
2090370b324cSopenharmony_ci
2091370b324cSopenharmony_ci    // ubuntu uses "SHA256SUMS" file
2092370b324cSopenharmony_ci    item.AddExts(UString (
2093370b324cSopenharmony_ci        "sha256 sha512 sha224 sha384 sha1 sha md5"
2094370b324cSopenharmony_ci        // "b2sum"
2095370b324cSopenharmony_ci        " crc32 crc64"
2096370b324cSopenharmony_ci        " asc"
2097370b324cSopenharmony_ci        " cksum"
2098370b324cSopenharmony_ci        ),
2099370b324cSopenharmony_ci        UString());
2100370b324cSopenharmony_ci
2101370b324cSopenharmony_ci    item.UpdateEnabled = (item.CreateOutArchive != NULL);
2102370b324cSopenharmony_ci    item.SignatureOffset = 0;
2103370b324cSopenharmony_ci    // item.Version = MY_VER_MIX;
2104370b324cSopenharmony_ci    item.NewInterface = true;
2105370b324cSopenharmony_ci
2106370b324cSopenharmony_ci    item.Signatures.AddNew().CopyFrom(NULL, 0);
2107370b324cSopenharmony_ci
2108370b324cSopenharmony_ci    codecs->Formats.Add(item);
2109370b324cSopenharmony_ci  }
2110370b324cSopenharmony_ci}
2111