blob: a2260b6fdda7533bb81fc3f1ca787cfcd9543f0f [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.
Raphael628920b2011-11-22 10:40:13 -0800204 CString& setLastWin32Error() {
205 DWORD err = GetLastError();
206 LPSTR errStr;
207 if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */
208 FORMAT_MESSAGE_FROM_SYSTEM,
209 NULL, /* lpSource */
210 err, /* dwMessageId */
211 0, /* dwLanguageId */
212 (LPSTR)&errStr, /* lpBuffer */
213 0, /* nSize */
214 NULL) != 0) { /* va_list args */
Raphael1bb74402011-11-29 14:33:26 -0800215 setf("[%d] %s", err, errStr);
Raphael628920b2011-11-22 10:40:13 -0800216 LocalFree(errStr);
217 }
218 return *this;
219 }
220
221private:
222 void _free() {
223 if (mStr != NULL) {
224 free((void *)mStr);
225 mStr = NULL;
226 }
227 }
228
229};
230
231// A simple path class wrapper.
232class CPath : public CString {
233public:
234 CPath() : CString() { }
Raphael22fd3c12011-12-02 21:58:23 -0800235 CPath(const CString &str) : CString(str) { }
Raphael628920b2011-11-22 10:40:13 -0800236 CPath(const CPath &str) : CString(str) { }
237 explicit CPath(const char *str) : CString(str) { }
238 CPath(const char *start, int length) : CString(start, length) { }
239
Raphael22fd3c12011-12-02 21:58:23 -0800240 CPath& operator=(const CPath &str) {
241 set(str.cstr());
242 return *this;
243 }
244
Raphael628920b2011-11-22 10:40:13 -0800245 // Appends a path segment, adding a \ as necessary.
246 CPath& addPath(const CString &s) {
247 return addPath(s.cstr());
248 }
249
250 // Appends a path segment, adding a \ as necessary.
251 CPath& addPath(const char *s) {
252 _ASSERT(s != NULL);
253 if (s != NULL && s[0] != 0) {
254 int n = length();
255 if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");
256 add(s);
257 }
258 return *this;
259 }
260
261 // Returns true if file exist and is not a directory.
262 // There's no garantee we have rights to access it.
263 bool fileExists() const {
264 if (mStr == NULL) return false;
265 DWORD attribs = GetFileAttributesA(mStr);
266 return attribs != INVALID_FILE_ATTRIBUTES &&
267 !(attribs & FILE_ATTRIBUTE_DIRECTORY);
268 }
269
270 // Returns true if file exist and is a directory.
271 // There's no garantee we have rights to access it.
272 bool dirExists() const {
273 if (mStr == NULL) return false;
274 DWORD attribs = GetFileAttributesA(mStr);
275 return attribs != INVALID_FILE_ATTRIBUTES &&
276 (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
277 }
278
279 // Returns a copy of the directory portion of the path, if any
280 CPath dirName() const {
281 CPath result;
282 if (mStr != NULL) {
283 char *pos = strrchr(mStr, '\\');
284 if (pos != NULL) {
285 result.set(mStr, pos - mStr);
286 }
287 }
288 return result;
289 }
290
291 // Returns a pointer to the baseName part of the path.
292 // It becomes invalid if the path changes.
293 const char * baseName() const {
294 if (mStr != NULL) {
295 char *pos = strrchr(mStr, '\\');
296 if (pos != NULL) {
297 return pos + 1;
298 }
299 }
300 return NULL;
301 }
302
303 // If the path ends with the given searchName, replace in-place by the new name
304 void replaceName(const char *searchName, const char* newName) {
305 if (mStr == NULL) return;
306 int n = length();
307 int sn = strlen(searchName);
308 if (n < sn) return;
309 // if mStr ends with searchName
310 if (strcmp(mStr + n - sn, searchName) == 0) {
311 int sn2 = strlen(newName);
312 if (sn2 > sn) {
313 mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);
314 }
315 strcpy(mStr + n - sn, newName);
316 mStr[n + sn2 - sn] = 0;
317 }
318 }
Raphaeld2d69992012-01-24 15:06:56 -0800319
320 // Returns a copy of this path as a DOS short path in the destination.
321 // Returns true if the Win32 getShortPathName method worked.
322 // In case of error, returns false and does not change the destination.
323 // It's OK to invoke this->toShortPath(this).
324 bool toShortPath(CPath *dest) {
325 const char *longPath = mStr;
326 if (mStr == NULL) return false;
327
328 DWORD lenShort = strlen(longPath) + 1;
329 char * shortPath = (char *)malloc(lenShort);
330
331 DWORD length = GetShortPathName(longPath, shortPath, lenShort);
332 if (length > lenShort) {
333 // The buffer wasn't big enough, this is the size to use.
334 free(shortPath);
335 lenShort = length;
336 shortPath = (char *)malloc(length);
337 length = GetShortPathName(longPath, shortPath, lenShort);
338 }
339
340 if (length != 0) dest->set(shortPath);
341
342 free(shortPath);
343 return length != 0;
344 }
Raphael628920b2011-11-22 10:40:13 -0800345};
346
347// Displays a message in an ok+info dialog box.
348void msgBox(const char* text, ...);
349
350// Displays GetLastError prefixed with a description in an error dialog box
351void displayLastError(const char *description, ...);
352
353// Executes the command line. Does not wait for the program to finish.
354// The return code is from CreateProcess (0 means failure), not the running app.
355int execNoWait(const char *app, const char *params, const char *workDir);
356
357// Executes command, waits for completion and returns exit code.
358// As indicated in MSDN for CreateProcess, callers should double-quote the program name
359// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
360int execWait(const char *cmd);
361
362bool getModuleDir(CPath *outDir);
363
364// Disables the FS redirection done by WOW64.
365// Because this runs as a 32-bit app, Windows automagically remaps some
366// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").
367// This prevents the app from correctly searching for java.exe in these folders.
368// The registry is also remapped.
369PVOID disableWow64FsRedirection();
370
371// Reverts the redirection disabled in disableWow64FsRedirection.
372void revertWow64FsRedirection(PVOID oldWow64Value);
373
374#endif /* _WIN32 */
375#endif /* _H_UTILS */