1 /** @file
2   Helper functions for mangling file names in UDF/ECMA-167 file systems.
3 
4   Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8 
9 #include "Udf.h"
10 
11 /**
12   Trim the leading and trailing spaces for a give Unicode string.
13 
14   @param[in]  String              The Unicode string to trim.
15 
16   @return  A pointer to the trimmed string.
17 
18 **/
19 CHAR16 *
TrimString(IN CHAR16 * String)20 TrimString (
21   IN CHAR16    *String
22   )
23 {
24   CHAR16       *TempString;
25 
26   for ( ; *String != L'\0' && *String == L' '; String++) {
27     ;
28   }
29 
30   TempString = String + StrLen (String) - 1;
31   while ((TempString >= String) && (*TempString == L' ')) {
32     TempString--;
33   }
34 
35   *(TempString + 1) = L'\0';
36 
37   return String;
38 }
39 
40 /**
41   Replace the content of a Unicode string with the content of another Unicode
42   string.
43 
44   @param[in]  Destination         A pointer to a Unicode string.
45   @param[in]  Source              A pointer to a Unicode string.
46 
47 **/
48 VOID
ReplaceLeft(IN CHAR16 * Destination,IN CONST CHAR16 * Source)49 ReplaceLeft (
50   IN CHAR16         *Destination,
51   IN CONST CHAR16   *Source
52   )
53 {
54   CONST CHAR16      *EndString;
55 
56   EndString = Source + StrLen (Source);
57   while (Source <= EndString) {
58     *Destination++ = *Source++;
59   }
60 }
61 
62 /**
63   Remove one or more consecutive backslashes starting from the second character
64   of a given Unicode string.
65 
66   @param[in]  String              A pointer to a Unicode string.
67 
68   @return  A pointer to the modified string.
69 
70 **/
71 CHAR16 *
ExcludeTrailingBackslashes(IN CHAR16 * String)72 ExcludeTrailingBackslashes (
73   IN CHAR16                    *String
74   )
75 {
76   CHAR16                       *TempString;
77 
78   switch (*(String + 1)) {
79   case L'\\':
80     break;
81   case L'\0':
82   default:
83     String++;
84     goto Exit;
85   }
86 
87   TempString = String;
88   while (*TempString != L'\0' && *TempString == L'\\') {
89     TempString++;
90   }
91 
92   if (TempString - 1 > String) {
93     ReplaceLeft (String + 1, TempString);
94   }
95 
96   String++;
97 
98 Exit:
99   return String;
100 }
101 
102 /**
103   Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".
104 
105   @param[in] FileName Filename.
106 
107   @retval The mangled Filename.
108 
109 **/
110 CHAR16 *
MangleFileName(IN CHAR16 * FileName)111 MangleFileName (
112   IN CHAR16        *FileName
113   )
114 {
115   CHAR16           *FileNameSavedPointer;
116   CHAR16           *TempFileName;
117   UINTN            BackslashesNo;
118 
119   if (FileName == NULL || *FileName == L'\0') {
120     FileName = NULL;
121     goto Exit;
122   }
123 
124   FileName = TrimString (FileName);
125   if (*FileName == L'\0') {
126     goto Exit;
127   }
128 
129   if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] == L'\\')) {
130     FileName[StrLen (FileName) - 1] = L'\0';
131   }
132 
133   FileNameSavedPointer = FileName;
134 
135   if (FileName[0] == L'.') {
136     if (FileName[1] == L'.') {
137       if (FileName[2] == L'\0') {
138         goto Exit;
139       } else {
140         FileName += 2;
141       }
142     } else if (FileName[1] == L'\0') {
143       goto Exit;
144     }
145   }
146 
147   while (*FileName != L'\0') {
148     if (*FileName == L'\\') {
149       FileName = ExcludeTrailingBackslashes (FileName);
150     } else if (*FileName == L'.') {
151       switch (*(FileName + 1)) {
152       case L'\0':
153         *FileName = L'\0';
154         break;
155       case L'\\':
156         TempFileName = FileName + 1;
157         TempFileName = ExcludeTrailingBackslashes (TempFileName);
158         ReplaceLeft (FileName, TempFileName);
159         break;
160       case '.':
161         if ((*(FileName - 1) != L'\\') && ((*(FileName + 2) != L'\\') ||
162                                            (*(FileName + 2) != L'\0'))) {
163           FileName++;
164           continue;
165         }
166 
167         BackslashesNo = 0;
168         TempFileName = FileName - 1;
169         while (TempFileName >= FileNameSavedPointer) {
170           if (*TempFileName == L'\\') {
171             if (++BackslashesNo == 2) {
172               break;
173             }
174           }
175 
176           TempFileName--;
177         }
178 
179         TempFileName++;
180 
181         if ((*TempFileName == L'.') && (*(TempFileName + 1) == L'.')) {
182           FileName += 2;
183         } else {
184           if (*(FileName + 2) != L'\0') {
185             ReplaceLeft (TempFileName, FileName + 3);
186             if (*(TempFileName - 1) == L'\\') {
187               FileName = TempFileName;
188               ExcludeTrailingBackslashes (TempFileName - 1);
189               TempFileName = FileName;
190             }
191           } else {
192             *TempFileName = L'\0';
193           }
194 
195           FileName = TempFileName;
196         }
197 
198         break;
199       default:
200         FileName++;
201       }
202     } else {
203       FileName++;
204     }
205   }
206 
207   FileName = FileNameSavedPointer;
208   if ((StrLen (FileName) > 1) && (FileName [StrLen (FileName) - 1] == L'\\')) {
209     FileName [StrLen (FileName) - 1] = L'\0';
210   }
211 
212 Exit:
213   return FileName;
214 }
215