1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | /*** |
5 | *makepath.c - create path name from components |
6 | * |
7 | |
8 | * |
9 | *Purpose: |
10 | * To provide support for creation of full path names from components |
11 | * |
12 | *******************************************************************************/ |
13 | #include "stdafx.h" |
14 | #include "winwrap.h" |
15 | #include "utilcode.h" |
16 | #include "ex.h" |
17 | |
18 | |
19 | /*** |
20 | *void Makepath() - build path name from components |
21 | * |
22 | *Purpose: |
23 | * create a path name from its individual components |
24 | * |
25 | *Entry: |
26 | * CQuickWSTR &szPath - Buffer for constructed path |
27 | * WCHAR *drive - pointer to drive component, may or may not contain |
28 | * trailing ':' |
29 | * WCHAR *dir - pointer to subdirectory component, may or may not include |
30 | * leading and/or trailing '/' or '\' characters |
31 | * WCHAR *fname - pointer to file base name component |
32 | * WCHAR *ext - pointer to extension component, may or may not contain |
33 | * a leading '.'. |
34 | * |
35 | *Exit: |
36 | * path - pointer to constructed path name |
37 | * |
38 | *Exceptions: |
39 | * |
40 | *******************************************************************************/ |
41 | |
42 | void MakePath ( |
43 | __out CQuickWSTR &szPath, |
44 | __in LPCWSTR drive, |
45 | __in LPCWSTR dir, |
46 | __in LPCWSTR fname, |
47 | __in LPCWSTR ext |
48 | ) |
49 | { |
50 | CONTRACTL |
51 | { |
52 | NOTHROW; |
53 | GC_NOTRIGGER; |
54 | } |
55 | CONTRACTL_END |
56 | |
57 | SIZE_T maxCount = 4 // Possible separators between components, plus null terminator |
58 | + (drive != nullptr ? 2 : 0) |
59 | + (dir != nullptr ? wcslen(dir) : 0) |
60 | + (fname != nullptr ? wcslen(fname) : 0) |
61 | + (ext != nullptr ? wcslen(ext) : 0); |
62 | LPWSTR path = szPath.AllocNoThrow(maxCount); |
63 | |
64 | const WCHAR *p; |
65 | DWORD count = 0; |
66 | |
67 | /* we assume that the arguments are in the following form (although we |
68 | * do not diagnose invalid arguments or illegal filenames (such as |
69 | * names longer than 8.3 or with illegal characters in them) |
70 | * |
71 | * drive: |
72 | * A ; or |
73 | * A: |
74 | * dir: |
75 | * \top\next\last\ ; or |
76 | * /top/next/last/ ; or |
77 | * either of the above forms with either/both the leading |
78 | * and trailing / or \ removed. Mixed use of '/' and '\' is |
79 | * also tolerated |
80 | * fname: |
81 | * any valid file name |
82 | * ext: |
83 | * any valid extension (none if empty or null ) |
84 | */ |
85 | |
86 | /* copy drive */ |
87 | |
88 | if (drive && *drive) { |
89 | *path++ = *drive; |
90 | *path++ = _T(':'); |
91 | count += 2; |
92 | } |
93 | |
94 | /* copy dir */ |
95 | |
96 | if ((p = dir)) { |
97 | while (*p) { |
98 | *path++ = *p++; |
99 | count++; |
100 | |
101 | _ASSERTE(count < maxCount); |
102 | } |
103 | |
104 | #ifdef _MBCS |
105 | if (*(p=_mbsdec(dir,p)) != _T('/') && *p != _T('\\')) { |
106 | #else /* _MBCS */ |
107 | // suppress warning for the following line; this is safe but would require significant code |
108 | // delta for prefast to understand. |
109 | #ifdef _PREFAST_ |
110 | #pragma warning( suppress: 26001 ) |
111 | #endif |
112 | if (*(p-1) != _T('/') && *(p-1) != _T('\\')) { |
113 | #endif /* _MBCS */ |
114 | *path++ = _T('\\'); |
115 | count++; |
116 | |
117 | _ASSERTE(count < maxCount); |
118 | } |
119 | } |
120 | |
121 | /* copy fname */ |
122 | |
123 | if ((p = fname)) { |
124 | while (*p) { |
125 | *path++ = *p++; |
126 | count++; |
127 | |
128 | _ASSERTE(count < maxCount); |
129 | } |
130 | } |
131 | |
132 | /* copy ext, including 0-terminator - check to see if a '.' needs |
133 | * to be inserted. |
134 | */ |
135 | |
136 | if ((p = ext)) { |
137 | if (*p && *p != _T('.')) { |
138 | *path++ = _T('.'); |
139 | count++; |
140 | |
141 | _ASSERTE(count < maxCount); |
142 | } |
143 | |
144 | while ((*path++ = *p++)) { |
145 | count++; |
146 | |
147 | _ASSERTE(count < maxCount); |
148 | } |
149 | } |
150 | else { |
151 | /* better add the 0-terminator */ |
152 | *path = _T('\0'); |
153 | } |
154 | |
155 | szPath.Shrink(count + 1); |
156 | } |
157 | |
158 | |
159 | // Returns the directory for HMODULE. So, if HMODULE was for "C:\Dir1\Dir2\Filename.DLL", |
160 | // then this would return "C:\Dir1\Dir2\" (note the trailing backslash). |
161 | HRESULT GetHModuleDirectory( |
162 | __in HMODULE hMod, |
163 | SString& wszPath) |
164 | { |
165 | CONTRACTL |
166 | { |
167 | NOTHROW; |
168 | GC_NOTRIGGER; |
169 | CANNOT_TAKE_LOCK; |
170 | } |
171 | CONTRACTL_END; |
172 | |
173 | DWORD dwRet = WszGetModuleFileName(hMod, wszPath); |
174 | |
175 | if (dwRet == 0) |
176 | { // Some other error. |
177 | return HRESULT_FROM_GetLastError(); |
178 | } |
179 | |
180 | CopySystemDirectory(wszPath, wszPath); |
181 | |
182 | |
183 | return S_OK; |
184 | } |
185 | |
186 | // |
187 | // Returns path name from a file name. |
188 | // Example: For input "C:\Windows\System.dll" returns "C:\Windows\". |
189 | // Warning: The input file name string might be destroyed. |
190 | // |
191 | // Arguments: |
192 | // pPathString - [in] SString with file name |
193 | // |
194 | // pBuffer - [out] SString . |
195 | // |
196 | // Return Value: |
197 | // S_OK - Output buffer contains path name. |
198 | // other errors - If Sstring throws. |
199 | // |
200 | HRESULT CopySystemDirectory(const SString& pPathString, |
201 | SString& pbuffer) |
202 | { |
203 | HRESULT hr = S_OK; |
204 | EX_TRY |
205 | { |
206 | pbuffer.Set(pPathString); |
207 | SString::Iterator iter = pbuffer.End(); |
208 | if (pbuffer.FindBack(iter,DIRECTORY_SEPARATOR_CHAR_W)) |
209 | { |
210 | iter++; |
211 | pbuffer.Truncate(iter); |
212 | } |
213 | else |
214 | { |
215 | hr = E_UNEXPECTED; |
216 | } |
217 | } |
218 | EX_CATCH_HRESULT(hr); |
219 | |
220 | return hr; |
221 | } |
222 | |