blob: 8c5cdb76dd3cea534b871deb8fe93a57de2206b5 [file] [log] [blame]
Raphael628920b2011-11-22 10:40:13 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _H_UTILS
18#define _H_UTILS
19
20#ifdef _WIN32
21
22#include <direct.h>
23#include <stdio.h>
24#include <stdarg.h>
25#include <string.h>
26#include <windows.h>
27
28// VS vs MINGW specific includes
29#ifdef USE_VS_CRT
30 #include <crtdbg.h> // for _ASSERT
31#else
32 #define _ASSERT(x) // undef
33#endif
34
35extern bool gDebug;
36
37// An array that knows its own size. Not dynamically resizable.
38template <class T> class CArray {
39 T* mPtr;
40 int mSize;
41public:
42 explicit CArray(int size) {
43 mSize = size;
44 mPtr = new T[size];
45 }
46
47 ~CArray() {
48 if (mPtr != NULL) {
49 delete[] mPtr;
50 mPtr = NULL;
51 }
52 mSize = 0;
53 }
54
55 T& operator[](int i) {
56 _ASSERT(i >= 0 && i < mSize);
57 return mPtr[i];
58 }
59
60 int size() const {
61 return mSize;
62 }
63};
64
65// A simple string class wrapper.
66class CString {
67protected:
68 char *mStr;
69public:
70 CString() { mStr = NULL; }
71 CString(const CString &str) { mStr = str.mStr == NULL ? NULL : _strdup(str.mStr); }
72 explicit CString(const char *str) { mStr = NULL; set(str); }
73 CString(const char *start, int length) { mStr = NULL; set(start, length); }
74
75 CString& set(const char *str) {
76 _free();
77 if (str != NULL) {
78 mStr = _strdup(str);
79 }
80 return *this;
81 }
82
83 CString& set(const char *start, int length) {
84 _free();
85 if (start != NULL) {
86 mStr = (char *)malloc(length + 1);
87 strncpy(mStr, start, length);
88 mStr[length] = 0;
89 }
90 return *this;
91 }
92
93 CString& setv(const char *str, va_list ap) {
94 _free();
95 // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.
96 // Instead we'll iterate till we have enough space to generate the string.
97 int len = strlen(str) + 1024;
98 mStr = (char *)malloc(len);
99 strcpy(mStr, str); // provide a default in case vsnprintf totally fails
100 for (int guard = 0; guard < 10; guard++) {
101 int ret = vsnprintf(mStr, len, str, ap);
102 if (ret == -1) {
103 // Some implementations don't give the proper size needed
104 // so double the space and try again.
105 len *= 2;
106 } else if (ret >= len) {
107 len = ret + 1;
108 } else {
109 // There was enough space to write.
110 break;
111 }
112 mStr = (char *)realloc((void *)mStr, len);
113 strcpy(mStr, str); // provide a default in case vsnprintf totally fails
114 }
115 return *this;
116 }
117
118 CString& setf(const char *str, ...) {
119 _free();
120 va_list ap;
121 va_start(ap, str);
122 setv(str, ap);
123 va_end(ap);
124 return *this;
125 }
126
127 virtual ~CString() { _free(); }
128
129 // Returns the C string owned by this CString. It will be
130 // invalid as soon as this CString is deleted or out of scope.
131 const char * cstr() const {
132 return mStr;
133 }
134
135 bool isEmpty() const {
136 return mStr == NULL || *mStr == 0;
137 }
138
139 int length() const {
140 return mStr == NULL ? 0 : strlen(mStr);
141 }
142
143 CString& add(const char *s) {
144 if (mStr == NULL) {
145 set(s);
146 } else {
147 mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(s) + 1);
148 strcat(mStr, s);
149 }
150 return *this;
151 }
152
153 CArray<CString> * split(char sep) const {
154 if (mStr == NULL) {
155 return new CArray<CString>(0);
156 }
157 const char *last = NULL;
158 int n = 0;
159 for (const char *s = mStr; *s; s++) {
160 if (*s == sep && s != mStr && (last == NULL || s > last+1)) {
161 n++;
162 last = s;
163 }
164 }
165
166 CArray<CString> *result = new CArray<CString>(n);
167 last = NULL;
168 n = 0;
169 for (const char *s = mStr; *s; s++) {
170 if (*s == sep) {
171 if (s != mStr && (last == NULL || s > last+1)) {
172 const char *start = last ? last : mStr;
173 (*result)[n++].set(start, s-start);
174 }
175 last = s+1;
176 }
177 }
178
179 return result;
180 }
181
Raphael1bb74402011-11-29 14:33:26 -0800182 // Sets the string to the message matching Win32 GetLastError.
Raphael628920b2011-11-22 10:40:13 -0800183 CString& setLastWin32Error() {
184 DWORD err = GetLastError();
185 LPSTR errStr;
186 if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */
187 FORMAT_MESSAGE_FROM_SYSTEM,
188 NULL, /* lpSource */
189 err, /* dwMessageId */
190 0, /* dwLanguageId */
191 (LPSTR)&errStr, /* lpBuffer */
192 0, /* nSize */
193 NULL) != 0) { /* va_list args */
Raphael1bb74402011-11-29 14:33:26 -0800194 setf("[%d] %s", err, errStr);
Raphael628920b2011-11-22 10:40:13 -0800195 LocalFree(errStr);
196 }
197 return *this;
198 }
199
200private:
201 void _free() {
202 if (mStr != NULL) {
203 free((void *)mStr);
204 mStr = NULL;
205 }
206 }
207
208};
209
210// A simple path class wrapper.
211class CPath : public CString {
212public:
213 CPath() : CString() { }
214 CPath(const CPath &str) : CString(str) { }
215 explicit CPath(const char *str) : CString(str) { }
216 CPath(const char *start, int length) : CString(start, length) { }
217
218 // Appends a path segment, adding a \ as necessary.
219 CPath& addPath(const CString &s) {
220 return addPath(s.cstr());
221 }
222
223 // Appends a path segment, adding a \ as necessary.
224 CPath& addPath(const char *s) {
225 _ASSERT(s != NULL);
226 if (s != NULL && s[0] != 0) {
227 int n = length();
228 if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");
229 add(s);
230 }
231 return *this;
232 }
233
234 // Returns true if file exist and is not a directory.
235 // There's no garantee we have rights to access it.
236 bool fileExists() const {
237 if (mStr == NULL) return false;
238 DWORD attribs = GetFileAttributesA(mStr);
239 return attribs != INVALID_FILE_ATTRIBUTES &&
240 !(attribs & FILE_ATTRIBUTE_DIRECTORY);
241 }
242
243 // Returns true if file exist and is a directory.
244 // There's no garantee we have rights to access it.
245 bool dirExists() const {
246 if (mStr == NULL) return false;
247 DWORD attribs = GetFileAttributesA(mStr);
248 return attribs != INVALID_FILE_ATTRIBUTES &&
249 (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
250 }
251
252 // Returns a copy of the directory portion of the path, if any
253 CPath dirName() const {
254 CPath result;
255 if (mStr != NULL) {
256 char *pos = strrchr(mStr, '\\');
257 if (pos != NULL) {
258 result.set(mStr, pos - mStr);
259 }
260 }
261 return result;
262 }
263
264 // Returns a pointer to the baseName part of the path.
265 // It becomes invalid if the path changes.
266 const char * baseName() const {
267 if (mStr != NULL) {
268 char *pos = strrchr(mStr, '\\');
269 if (pos != NULL) {
270 return pos + 1;
271 }
272 }
273 return NULL;
274 }
275
276 // If the path ends with the given searchName, replace in-place by the new name
277 void replaceName(const char *searchName, const char* newName) {
278 if (mStr == NULL) return;
279 int n = length();
280 int sn = strlen(searchName);
281 if (n < sn) return;
282 // if mStr ends with searchName
283 if (strcmp(mStr + n - sn, searchName) == 0) {
284 int sn2 = strlen(newName);
285 if (sn2 > sn) {
286 mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);
287 }
288 strcpy(mStr + n - sn, newName);
289 mStr[n + sn2 - sn] = 0;
290 }
291 }
292};
293
294// Displays a message in an ok+info dialog box.
295void msgBox(const char* text, ...);
296
297// Displays GetLastError prefixed with a description in an error dialog box
298void displayLastError(const char *description, ...);
299
300// Executes the command line. Does not wait for the program to finish.
301// The return code is from CreateProcess (0 means failure), not the running app.
302int execNoWait(const char *app, const char *params, const char *workDir);
303
304// Executes command, waits for completion and returns exit code.
305// As indicated in MSDN for CreateProcess, callers should double-quote the program name
306// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
307int execWait(const char *cmd);
308
309bool getModuleDir(CPath *outDir);
310
311// Disables the FS redirection done by WOW64.
312// Because this runs as a 32-bit app, Windows automagically remaps some
313// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").
314// This prevents the app from correctly searching for java.exe in these folders.
315// The registry is also remapped.
316PVOID disableWow64FsRedirection();
317
318// Reverts the redirection disabled in disableWow64FsRedirection.
319void revertWow64FsRedirection(PVOID oldWow64Value);
320
321#endif /* _WIN32 */
322#endif /* _H_UTILS */