| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 1 | /*
|
| 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 |
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame] | 22 | #define _CRT_SECURE_NO_WARNINGS 1
|
| 23 |
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 24 | #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 |
|
| Raphael | d2d6999 | 2012-01-24 15:06:56 -0800 | [diff] [blame^] | 37 | extern bool gIsDebug;
|
| 38 | extern bool gIsConsole;
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 39 |
|
| 40 | // An array that knows its own size. Not dynamically resizable.
|
| 41 | template <class T> class CArray {
|
| 42 | T* mPtr;
|
| 43 | int mSize;
|
| 44 | public:
|
| 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.
|
| 69 | class CString {
|
| 70 | protected:
|
| 71 | char *mStr;
|
| 72 | public:
|
| 73 | CString() { mStr = NULL; }
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame] | 74 | CString(const CString &str) { mStr = NULL; set(str.mStr); }
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 75 | explicit CString(const char *str) { mStr = NULL; set(str); }
|
| 76 | CString(const char *start, int length) { mStr = NULL; set(start, length); }
|
| 77 |
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame] | 78 | CString& operator=(const CString &str) {
|
| 79 | return set(str.cstr());
|
| 80 | }
|
| 81 |
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 82 | CString& set(const char *str) {
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame] | 83 | if (str != mStr) {
|
| 84 | _free();
|
| 85 | if (str != NULL) {
|
| 86 | mStr = _strdup(str);
|
| 87 | }
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 88 | }
|
| 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 |
|
| Raphael | d2d6999 | 2012-01-24 15:06:56 -0800 | [diff] [blame^] | 152 | CString& add(const char *str) {
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 153 | if (mStr == NULL) {
|
| Raphael | d2d6999 | 2012-01-24 15:06:56 -0800 | [diff] [blame^] | 154 | set(str);
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 155 | } else {
|
| Raphael | d2d6999 | 2012-01-24 15:06:56 -0800 | [diff] [blame^] | 156 | 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;
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 170 | }
|
| 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 |
|
| Raphael | 1bb7440 | 2011-11-29 14:33:26 -0800 | [diff] [blame] | 203 | // Sets the string to the message matching Win32 GetLastError.
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 204 | 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 */
|
| Raphael | 1bb7440 | 2011-11-29 14:33:26 -0800 | [diff] [blame] | 215 | setf("[%d] %s", err, errStr);
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 216 | LocalFree(errStr);
|
| 217 | }
|
| 218 | return *this;
|
| 219 | }
|
| 220 |
|
| 221 | private:
|
| 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.
|
| 232 | class CPath : public CString {
|
| 233 | public:
|
| 234 | CPath() : CString() { }
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame] | 235 | CPath(const CString &str) : CString(str) { }
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 236 | 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 |
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame] | 240 | CPath& operator=(const CPath &str) {
|
| 241 | set(str.cstr());
|
| 242 | return *this;
|
| 243 | }
|
| 244 |
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 245 | // 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 | }
|
| Raphael | d2d6999 | 2012-01-24 15:06:56 -0800 | [diff] [blame^] | 319 |
|
| 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 | }
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 345 | };
|
| 346 |
|
| 347 | // Displays a message in an ok+info dialog box.
|
| 348 | void msgBox(const char* text, ...);
|
| 349 |
|
| 350 | // Displays GetLastError prefixed with a description in an error dialog box
|
| 351 | void 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.
|
| 355 | int 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";
|
| 360 | int execWait(const char *cmd);
|
| 361 |
|
| 362 | bool 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.
|
| 369 | PVOID disableWow64FsRedirection();
|
| 370 |
|
| 371 | // Reverts the redirection disabled in disableWow64FsRedirection.
|
| 372 | void revertWow64FsRedirection(PVOID oldWow64Value);
|
| 373 |
|
| 374 | #endif /* _WIN32 */
|
| 375 | #endif /* _H_UTILS */
|