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
42void 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).
161HRESULT 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//
200HRESULT 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