blob: dc9031dbea3fef6ec0c97a8cb7242e8108b14823 [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
Raphael22fd3c12011-12-02 21:58:23 -080022#define _CRT_SECURE_NO_WARNINGS 1
23
Raphael628920b2011-11-22 10:40:13 -080024#include <direct.h>
25#include <stdio.h>
26#include <stdarg.h>
27#include <string.h>
28#include <windows.h>
29
30// VS vs MINGW specific includes
31#ifdef USE_VS_CRT
32 #include <crtdbg.h> // for _ASSERT
33#else
34 #define _ASSERT(x) // undef
35#endif
36
Raphaeld2d69992012-01-24 15:06:56 -080037extern bool gIsDebug;
38extern bool gIsConsole;
Raphael628920b2011-11-22 10:40:13 -080039
40// An array that knows its own size. Not dynamically resizable.
41template <class T> class CArray {
42 T* mPtr;
43 int mSize;
44public:
45 explicit CArray(int size) {
46 mSize = size;
47 mPtr = new T[size];
48 }
49
50 ~CArray() {
51 if (mPtr != NULL) {
52 delete[] mPtr;
53 mPtr = NULL;
54 }
55 mSize = 0;
56 }
57
58 T& operator[](int i) {
59 _ASSERT(i >= 0 && i < mSize);
60 return mPtr[i];
61 }
62
63 int size() const {
64 return mSize;
65 }
66};
67
68// A simple string class wrapper.
69class CString {
70protected:
71 char *mStr;
72public:
73 CString() { mStr = NULL; }
Raphael22fd3c12011-12-02 21:58:23 -080074 CString(const CString &str) { mStr = NULL; set(str.mStr); }
Raphael628920b2011-11-22 10:40:13 -080075 explicit CString(const char *str) { mStr = NULL; set(str); }
76 CString(const char *start, int length) { mStr = NULL; set(start, length); }
77
Raphael22fd3c12011-12-02 21:58:23 -080078 CString& operator=(const CString &str) {
79 return set(str.cstr());
80 }
81
Raphael628920b2011-11-22 10:40:13 -080082 CString& set(const char *str) {
Raphael22fd3c12011-12-02 21:58:23 -080083 if (str != mStr) {
84 _free();
85 if (str != NULL) {
86 mStr = _strdup(str);
87 }
Raphael628920b2011-11-22 10:40:13 -080088 }
89 return *this;
90 }
91
92 CString& set(const char *start, int length) {
93 _free();
94 if (start != NULL) {
95 mStr = (char *)malloc(length + 1);
96 strncpy(mStr, start, length);
97 mStr[length] = 0;
98 }
99 return *this;
100 }
101
102 CString& setv(const char *str, va_list ap) {
103 _free();
104 // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.
105 // Instead we'll iterate till we have enough space to generate the string.
106 int len = strlen(str) + 1024;
107 mStr = (char *)malloc(len);
108 strcpy(mStr, str); // provide a default in case vsnprintf totally fails
109 for (int guard = 0; guard < 10; guard++) {
110 int ret = vsnprintf(mStr, len, str, ap);
111 if (ret == -1) {
112 // Some implementations don't give the proper size needed
113 // so double the space and try again.
114 len *= 2;
115 } else if (ret >= len) {
116 len = ret + 1;
117 } else {
118 // There was enough space to write.
119 break;
120 }
121 mStr = (char *)realloc((void *)mStr, len);
122 strcpy(mStr, str); // provide a default in case vsnprintf totally fails
123 }
124 return *this;
125 }
126
127 CString& setf(const char *str, ...) {
128 _free();
129 va_list ap;
130 va_start(ap, str);
131 setv(str, ap);
132 va_end(ap);
133 return *this;
134 }
135
136 virtual ~CString() { _free(); }
137
138 // Returns the C string owned by this CString. It will be
139 // invalid as soon as this CString is deleted or out of scope.
140 const char * cstr() const {
141 return mStr;
142 }
143
144 bool isEmpty() const {
145 return mStr == NULL || *mStr == 0;
146 }
147
148 int length() const {
149 return mStr == NULL ? 0 : strlen(mStr);
150 }
151
Raphaeld2d69992012-01-24 15:06:56 -0800152 CString& add(const char *str) {
Raphael628920b2011-11-22 10:40:13 -0800153 if (mStr == NULL) {
Raphaeld2d69992012-01-24 15:06:56 -0800154 set(str);
Raphael628920b2011-11-22 10:40:13 -0800155 } else {
Raphaeld2d69992012-01-24 15:06:56 -0800156 mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(str) + 1);
157 strcat(mStr, str);
158 }
159 return *this;
160 }
161
162 CString& add(const char *str, int length) {
163 if (mStr == NULL) {
164 set(str, length);
165 } else {
166 int l1 = strlen(mStr);
167 mStr = (char *)realloc((void *)mStr, l1 + length + 1);
168 strncpy(mStr + l1, str, length);
169 mStr[l1 + length] = 0;
Raphael628920b2011-11-22 10:40:13 -0800170 }
171 return *this;
172 }
173
174 CArray<CString> * split(char sep) const {
175 if (mStr == NULL) {
176 return new CArray<CString>(0);
177 }
178 const char *last = NULL;
179 int n = 0;
180 for (const char *s = mStr; *s; s++) {
181 if (*s == sep && s != mStr && (last == NULL || s > last+1)) {
182 n++;
183 last = s;
184 }
185 }
186
187 CArray<CString> *result = new CArray<CString>(n);
188 last = NULL;
189 n = 0;
190 for (const char *s = mStr; *s; s++) {
191 if (*s == sep) {
192 if (s != mStr && (last == NULL || s > last+1)) {
193 const char *start = last ? last : mStr;
194 (*result)[n++].set(start, s-start);
195 }
196 last = s+1;
197 }
198 }
199
200 return result;
201 }
202
Raphael1bb74402011-11-29 14:33:26 -0800203 // Sets the string to the message matching Win32 GetLastError.
Raphael42a9ced2012-01-26 19:15:43 -0800204 // If message is non-null, it is prepended to the last error string.
205 CString& setLastWin32Error(const char *message) {
Raphael628920b2011-11-22 10:40:13 -0800206 DWORD err = GetLastError();
207 LPSTR errStr;
208 if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */
209 FORMAT_MESSAGE_FROM_SYSTEM,
210 NULL, /* lpSource */
211 err, /* dwMessageId */
212 0, /* dwLanguageId */
213 (LPSTR)&errStr, /* lpBuffer */
214 0, /* nSize */
215 NULL) != 0) { /* va_list args */
Raphael42a9ced2012-01-26 19:15:43 -0800216 if (message == NULL) {
217 setf("[%d] %s", err, errStr);
218 } else {
219 setf("%s[%d] %s", message, err, errStr);
220 }
Raphael628920b2011-11-22 10:40:13 -0800221 LocalFree(errStr);
222 }
223 return *this;
224 }
225
226private:
227 void _free() {
228 if (mStr != NULL) {
229 free((void *)mStr);
230 mStr = NULL;
231 }
232 }
233
234};
235
236// A simple path class wrapper.
237class CPath : public CString {
238public:
239 CPath() : CString() { }
Raphael22fd3c12011-12-02 21:58:23 -0800240 CPath(const CString &str) : CString(str) { }
Raphael628920b2011-11-22 10:40:13 -0800241 CPath(const CPath &str) : CString(str) { }
242 explicit CPath(const char *str) : CString(str) { }
243 CPath(const char *start, int length) : CString(start, length) { }
244
Raphael22fd3c12011-12-02 21:58:23 -0800245 CPath& operator=(const CPath &str) {
246 set(str.cstr());
247 return *this;
248 }
249
Raphael628920b2011-11-22 10:40:13 -0800250 // Appends a path segment, adding a \ as necessary.
251 CPath& addPath(const CString &s) {
252 return addPath(s.cstr());
253 }
254
255 // Appends a path segment, adding a \ as necessary.
256 CPath& addPath(const char *s) {
257 _ASSERT(s != NULL);
258 if (s != NULL && s[0] != 0) {
259 int n = length();
260 if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");
261 add(s);
262 }
263 return *this;
264 }
265
266 // Returns true if file exist and is not a directory.
267 // There's no garantee we have rights to access it.
268 bool fileExists() const {
269 if (mStr == NULL) return false;
270 DWORD attribs = GetFileAttributesA(mStr);
271 return attribs != INVALID_FILE_ATTRIBUTES &&
272 !(attribs & FILE_ATTRIBUTE_DIRECTORY);
273 }
274
275 // Returns true if file exist and is a directory.
276 // There's no garantee we have rights to access it.
277 bool dirExists() const {
278 if (mStr == NULL) return false;
279 DWORD attribs = GetFileAttributesA(mStr);
280 return attribs != INVALID_FILE_ATTRIBUTES &&
281 (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
282 }
283
284 // Returns a copy of the directory portion of the path, if any
285 CPath dirName() const {
286 CPath result;
287 if (mStr != NULL) {
288 char *pos = strrchr(mStr, '\\');
289 if (pos != NULL) {
290 result.set(mStr, pos - mStr);
291 }
292 }
293 return result;
294 }
295
296 // Returns a pointer to the baseName part of the path.
297 // It becomes invalid if the path changes.
298 const char * baseName() const {
299 if (mStr != NULL) {
300 char *pos = strrchr(mStr, '\\');
301 if (pos != NULL) {
302 return pos + 1;
303 }
304 }
305 return NULL;
306 }
307
308 // If the path ends with the given searchName, replace in-place by the new name
309 void replaceName(const char *searchName, const char* newName) {
310 if (mStr == NULL) return;
311 int n = length();
312 int sn = strlen(searchName);
313 if (n < sn) return;
314 // if mStr ends with searchName
315 if (strcmp(mStr + n - sn, searchName) == 0) {
316 int sn2 = strlen(newName);
317 if (sn2 > sn) {
318 mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);
319 }
320 strcpy(mStr + n - sn, newName);
321 mStr[n + sn2 - sn] = 0;
322 }
323 }
Raphaeld2d69992012-01-24 15:06:56 -0800324
325 // Returns a copy of this path as a DOS short path in the destination.
326 // Returns true if the Win32 getShortPathName method worked.
327 // In case of error, returns false and does not change the destination.
328 // It's OK to invoke this->toShortPath(this).
329 bool toShortPath(CPath *dest) {
330 const char *longPath = mStr;
331 if (mStr == NULL) return false;
332
333 DWORD lenShort = strlen(longPath) + 1;
334 char * shortPath = (char *)malloc(lenShort);
335
336 DWORD length = GetShortPathName(longPath, shortPath, lenShort);
337 if (length > lenShort) {
338 // The buffer wasn't big enough, this is the size to use.
339 free(shortPath);
340 lenShort = length;
341 shortPath = (char *)malloc(length);
342 length = GetShortPathName(longPath, shortPath, lenShort);
343 }
344
345 if (length != 0) dest->set(shortPath);
346
347 free(shortPath);
348 return length != 0;
349 }
Raphael628920b2011-11-22 10:40:13 -0800350};
351
352// Displays a message in an ok+info dialog box.
353void msgBox(const char* text, ...);
354
355// Displays GetLastError prefixed with a description in an error dialog box
356void displayLastError(const char *description, ...);
357
358// Executes the command line. Does not wait for the program to finish.
359// The return code is from CreateProcess (0 means failure), not the running app.
360int execNoWait(const char *app, const char *params, const char *workDir);
361
362// Executes command, waits for completion and returns exit code.
363// As indicated in MSDN for CreateProcess, callers should double-quote the program name
364// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
365int execWait(const char *cmd);
366
367bool getModuleDir(CPath *outDir);
368
369// Disables the FS redirection done by WOW64.
370// Because this runs as a 32-bit app, Windows automagically remaps some
371// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").
372// This prevents the app from correctly searching for java.exe in these folders.
373// The registry is also remapped.
374PVOID disableWow64FsRedirection();
375
376// Reverts the redirection disabled in disableWow64FsRedirection.
377void revertWow64FsRedirection(PVOID oldWow64Value);
378
379#endif /* _WIN32 */
380#endif /* _H_UTILS */