xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Common/ExtractingFilePath.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // ExtractingFilePath.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/Wildcard.h"
6 
7 #include "../../../Windows/FileName.h"
8 
9 #include "ExtractingFilePath.h"
10 
11 extern
12 bool g_PathTrailReplaceMode;
13 bool g_PathTrailReplaceMode =
14     #ifdef _WIN32
15       true
16     #else
17       false
18     #endif
19     ;
20 
21 
22 #ifdef _WIN32
ReplaceIncorrectChars(UString & s)23 static void ReplaceIncorrectChars(UString &s)
24 {
25   {
26     for (unsigned i = 0; i < s.Len(); i++)
27     {
28       wchar_t c = s[i];
29       if (
30           #ifdef _WIN32
31           c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"'
32           || c == '/'
33           // || c == 0x202E // RLO
34           ||
35           #endif
36           c == WCHAR_PATH_SEPARATOR)
37       {
38        #if WCHAR_PATH_SEPARATOR != L'/'
39         // 22.00 : WSL replacement for backslash
40         if (c == WCHAR_PATH_SEPARATOR)
41           c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT;
42         else
43        #endif
44           c = '_';
45         s.ReplaceOneCharAtPos(i,
46           c
47           // (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters
48           );
49       }
50     }
51   }
52 
53   if (g_PathTrailReplaceMode)
54   {
55     /*
56     // if (g_PathTrailReplaceMode == 1)
57     {
58       if (!s.IsEmpty())
59       {
60         wchar_t c = s.Back();
61         if (c == '.' || c == ' ')
62         {
63           // s += (wchar_t)(0x9c); // STRING TERMINATOR
64           s += (wchar_t)'_';
65         }
66       }
67     }
68     else
69     */
70     {
71       unsigned i;
72       for (i = s.Len(); i != 0;)
73       {
74         wchar_t c = s[i - 1];
75         if (c != '.' && c != ' ')
76           break;
77         i--;
78         s.ReplaceOneCharAtPos(i, '_');
79         // s.ReplaceOneCharAtPos(i, (c == ' ' ? (wchar_t)(0x2423) : (wchar_t)0x00B7));
80       }
81       /*
82       if (g_PathTrailReplaceMode > 1 && i != s.Len())
83       {
84         s.DeleteFrom(i);
85       }
86       */
87     }
88   }
89 }
90 #endif
91 
92 /* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream.
93    But colon in postfix ":$DATA" is allowed.
94    WIN32 functions don't allow empty alt stream name "name:" */
95 
Correct_AltStream_Name(UString & s)96 void Correct_AltStream_Name(UString &s)
97 {
98   unsigned len = s.Len();
99   const unsigned kPostfixSize = 6;
100   if (s.Len() >= kPostfixSize
101       && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA"))
102     len -= kPostfixSize;
103   for (unsigned i = 0; i < len; i++)
104   {
105     wchar_t c = s[i];
106     if (c == ':' || c == '\\' || c == '/'
107         || c == 0x202E // RLO
108         )
109       s.ReplaceOneCharAtPos(i, '_');
110   }
111   if (s.IsEmpty())
112     s = '_';
113 }
114 
115 #ifdef _WIN32
116 
117 static const unsigned g_ReservedWithNum_Index = 4;
118 
119 static const char * const g_ReservedNames[] =
120 {
121   "CON", "PRN", "AUX", "NUL",
122   "COM", "LPT"
123 };
124 
IsSupportedName(const UString & name)125 static bool IsSupportedName(const UString &name)
126 {
127   for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ReservedNames); i++)
128   {
129     const char *reservedName = g_ReservedNames[i];
130     unsigned len = MyStringLen(reservedName);
131     if (name.Len() < len)
132       continue;
133     if (!name.IsPrefixedBy_Ascii_NoCase(reservedName))
134       continue;
135     if (i >= g_ReservedWithNum_Index)
136     {
137       wchar_t c = name[len];
138       if (c < L'0' || c > L'9')
139         continue;
140       len++;
141     }
142     for (;;)
143     {
144       wchar_t c = name[len++];
145       if (c == 0 || c == '.')
146         return false;
147       if (c != ' ')
148         break;
149     }
150   }
151   return true;
152 }
153 
CorrectUnsupportedName(UString & name)154 static void CorrectUnsupportedName(UString &name)
155 {
156   if (!IsSupportedName(name))
157     name.InsertAtFront(L'_');
158 }
159 
160 #endif
161 
Correct_PathPart(UString & s)162 static void Correct_PathPart(UString &s)
163 {
164   // "." and ".."
165   if (s.IsEmpty())
166     return;
167 
168   if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
169     s.Empty();
170   #ifdef _WIN32
171   else
172     ReplaceIncorrectChars(s);
173   #endif
174 }
175 
176 // static const char * const k_EmptyReplaceName = "[]";
177 static const char k_EmptyReplaceName = '_';
178 
Get_Correct_FsFile_Name(const UString & name)179 UString Get_Correct_FsFile_Name(const UString &name)
180 {
181   UString res = name;
182   Correct_PathPart(res);
183 
184   #ifdef _WIN32
185   CorrectUnsupportedName(res);
186   #endif
187 
188   if (res.IsEmpty())
189     res = k_EmptyReplaceName;
190   return res;
191 }
192 
193 
Correct_FsPath(bool absIsAllowed,bool keepAndReplaceEmptyPrefixes,UStringVector & parts,bool isDir)194 void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir)
195 {
196   unsigned i = 0;
197 
198   if (absIsAllowed)
199   {
200     #if defined(_WIN32) && !defined(UNDER_CE)
201     bool isDrive = false;
202     #endif
203 
204     if (parts[0].IsEmpty())
205     {
206       i = 1;
207       #if defined(_WIN32) && !defined(UNDER_CE)
208       if (parts.Size() > 1 && parts[1].IsEmpty())
209       {
210         i = 2;
211         if (parts.Size() > 2 && parts[2] == L"?")
212         {
213           i = 3;
214           if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
215           {
216             isDrive = true;
217             i = 4;
218           }
219         }
220       }
221       #endif
222     }
223     #if defined(_WIN32) && !defined(UNDER_CE)
224     else if (NWindows::NFile::NName::IsDrivePath2(parts[0]))
225     {
226       isDrive = true;
227       i = 1;
228     }
229 
230     if (isDrive)
231     {
232       // we convert "c:name" to "c:\name", if absIsAllowed path.
233       UString &ds = parts[i - 1];
234       if (ds.Len() > 2)
235       {
236         parts.Insert(i, ds.Ptr(2));
237         ds.DeleteFrom(2);
238       }
239     }
240     #endif
241   }
242 
243   if (i != 0)
244     keepAndReplaceEmptyPrefixes = false;
245 
246   for (; i < parts.Size();)
247   {
248     UString &s = parts[i];
249 
250     Correct_PathPart(s);
251 
252     if (s.IsEmpty())
253     {
254       if (!keepAndReplaceEmptyPrefixes)
255         if (isDir || i != parts.Size() - 1)
256         {
257           parts.Delete(i);
258           continue;
259         }
260       s = k_EmptyReplaceName;
261     }
262     else
263     {
264       keepAndReplaceEmptyPrefixes = false;
265       #ifdef _WIN32
266       CorrectUnsupportedName(s);
267       #endif
268     }
269 
270     i++;
271   }
272 
273   if (!isDir)
274   {
275     if (parts.IsEmpty())
276       parts.Add((UString)k_EmptyReplaceName);
277     else
278     {
279       UString &s = parts.Back();
280       if (s.IsEmpty())
281         s = k_EmptyReplaceName;
282     }
283   }
284 }
285 
MakePathFromParts(const UStringVector & parts)286 UString MakePathFromParts(const UStringVector &parts)
287 {
288   UString s;
289   FOR_VECTOR (i, parts)
290   {
291     if (i != 0)
292       s.Add_PathSepar();
293     s += parts[i];
294   }
295   return s;
296 }
297