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