1// ArchiveName.cpp
2
3#include "StdAfx.h"
4
5#include "../../../../C/Sort.h"
6
7#include "../../../Common/Wildcard.h"
8#include "../../../Common/StringToInt.h"
9
10#include "../../../Windows/FileDir.h"
11#include "../../../Windows/FileName.h"
12
13#include "ArchiveName.h"
14#include "ExtractingFilePath.h"
15
16using namespace NWindows;
17using namespace NFile;
18
19
20static const char *g_ArcExts =
21        "7z"
22  "\0"  "zip"
23  "\0"  "tar"
24  "\0"  "wim"
25  "\0";
26
27static const char *g_HashExts =
28  "sha256"
29  "\0";
30
31
32UString CreateArchiveName(
33    const UStringVector &paths,
34    bool isHash,
35    const NFind::CFileInfo *fi,
36    UString &baseName)
37{
38  bool keepName = isHash;
39  /*
40  if (paths.Size() == 1)
41  {
42    const UString &name = paths[0];
43    if (name.Len() > 4)
44      if (CompareFileNames(name.RightPtr(4), L".tar") == 0)
45        keepName = true;
46  }
47  */
48
49  UString name ("Archive");
50  NFind::CFileInfo fi3;
51  if (paths.Size() > 1)
52    fi = NULL;
53  if (!fi && paths.Size() != 0)
54  {
55    const UString &path = paths.Front();
56    if (paths.Size() == 1)
57    {
58      if (fi3.Find(us2fs(path)))
59        fi = &fi3;
60    }
61    else
62    {
63      // we try to use name of parent folder
64      FString dirPrefix;
65      if (NDir::GetOnlyDirPrefix(us2fs(path), dirPrefix))
66      {
67        if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back()))
68        {
69         #if defined(_WIN32) && !defined(UNDER_CE)
70          if (NName::IsDriveRootPath_SuperAllowed(dirPrefix))
71          {
72            if (path != fs2us(dirPrefix))
73              name = dirPrefix[dirPrefix.Len() - 3]; // only letter
74          }
75          else
76         #endif
77          {
78            dirPrefix.DeleteBack();
79            if (!dirPrefix.IsEmpty())
80            {
81              const int slash = dirPrefix.ReverseFind_PathSepar();
82              if (slash >= 0 && slash != (int)dirPrefix.Len() - 1)
83                name = dirPrefix.Ptr(slash + 1);
84              else if (fi3.Find(dirPrefix))
85                name = fs2us(fi3.Name);
86            }
87          }
88        }
89      }
90    }
91  }
92
93  if (fi)
94  {
95    name = fs2us(fi->Name);
96    if (!fi->IsDir() && !keepName)
97    {
98      const int dotPos = name.Find(L'.');
99      if (dotPos > 0 && name.Find(L'.', (unsigned)dotPos + 1) < 0)
100        name.DeleteFrom((unsigned)dotPos);
101    }
102  }
103  name = Get_Correct_FsFile_Name(name);
104
105  CRecordVector<UInt32> ids;
106  bool simple_IsAllowed = true;
107  // for (int y = 0; y < 10000; y++) // for debug
108  {
109    // ids.Clear();
110    UString n;
111
112    FOR_VECTOR (i, paths)
113    {
114      const UString &a = paths[i];
115      const int slash = a.ReverseFind_PathSepar();
116      // if (name.Len() >= a.Len() - slash + 1) continue;
117      const wchar_t *s = a.Ptr(slash + 1);
118      if (!IsPath1PrefixedByPath2(s, name))
119        continue;
120      s += name.Len();
121      const char *exts = isHash ? g_HashExts : g_ArcExts;
122
123      for (;;)
124      {
125        const char *ext = exts;
126        const unsigned len = MyStringLen(ext);
127        if (len == 0)
128          break;
129        exts += len + 1;
130        n = s;
131        if (n.Len() <= len)
132          continue;
133        if (!StringsAreEqualNoCase_Ascii(n.RightPtr(len), ext))
134          continue;
135        n.DeleteFrom(n.Len() - len);
136        if (n.Back() != '.')
137          continue;
138        n.DeleteBack();
139        if (n.IsEmpty())
140        {
141          simple_IsAllowed = false;
142          break;
143        }
144        if (n.Len() < 2)
145          continue;
146        if (n[0] != '_')
147          continue;
148        const wchar_t *end;
149        const UInt32 v = ConvertStringToUInt32(n.Ptr(1), &end);
150        if (*end != 0)
151          continue;
152        ids.Add(v);
153        break;
154      }
155    }
156  }
157
158  baseName = name;
159  if (!simple_IsAllowed)
160  {
161    HeapSort(&ids.Front(), ids.Size());
162    UInt32 v = 2;
163    const unsigned num = ids.Size();
164    for (unsigned i = 0; i < num; i++)
165    {
166      const UInt32 id = ids[i];
167      if (id > v)
168        break;
169      if (id == v)
170        v = id + 1;
171    }
172    name += '_';
173    name.Add_UInt32(v);
174  }
175  return name;
176}
177