| 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 |
|
| 37 | extern bool gDebug;
|
| 38 |
|
| 39 | // An array that knows its own size. Not dynamically resizable.
|
| 40 | template <class T> class CArray {
|
| 41 | T* mPtr;
|
| 42 | int mSize;
|
| 43 | public:
|
| 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.
|
| 68 | class CString {
|
| 69 | protected:
|
| 70 | char *mStr;
|
| 71 | public:
|
| 72 | CString() { mStr = NULL; }
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame^] | 73 | CString(const CString &str) { mStr = NULL; set(str.mStr); }
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 74 | explicit CString(const char *str) { mStr = NULL; set(str); }
|
| 75 | CString(const char *start, int length) { mStr = NULL; set(start, length); }
|
| 76 |
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame^] | 77 | CString& operator=(const CString &str) {
|
| 78 | return set(str.cstr());
|
| 79 | }
|
| 80 |
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 81 | CString& set(const char *str) {
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame^] | 82 | if (str != mStr) {
|
| 83 | _free();
|
| 84 | if (str != NULL) {
|
| 85 | mStr = _strdup(str);
|
| 86 | }
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 87 | }
|
| 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 |
|
| Raphael | 1bb7440 | 2011-11-29 14:33:26 -0800 | [diff] [blame] | 190 | // Sets the string to the message matching Win32 GetLastError.
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 191 | 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 */
|
| Raphael | 1bb7440 | 2011-11-29 14:33:26 -0800 | [diff] [blame] | 202 | setf("[%d] %s", err, errStr);
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 203 | LocalFree(errStr);
|
| 204 | }
|
| 205 | return *this;
|
| 206 | }
|
| 207 |
|
| 208 | private:
|
| 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.
|
| 219 | class CPath : public CString {
|
| 220 | public:
|
| 221 | CPath() : CString() { }
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame^] | 222 | CPath(const CString &str) : CString(str) { }
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 223 | 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 |
|
| Raphael | 22fd3c1 | 2011-12-02 21:58:23 -0800 | [diff] [blame^] | 227 | CPath& operator=(const CPath &str) {
|
| 228 | set(str.cstr());
|
| 229 | return *this;
|
| 230 | }
|
| 231 |
|
| Raphael | 628920b | 2011-11-22 10:40:13 -0800 | [diff] [blame] | 232 | // 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.
|
| 309 | void msgBox(const char* text, ...);
|
| 310 |
|
| 311 | // Displays GetLastError prefixed with a description in an error dialog box
|
| 312 | void 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.
|
| 316 | int 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";
|
| 321 | int execWait(const char *cmd);
|
| 322 |
|
| 323 | bool 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.
|
| 330 | PVOID disableWow64FsRedirection();
|
| 331 |
|
| 332 | // Reverts the redirection disabled in disableWow64FsRedirection.
|
| 333 | void revertWow64FsRedirection(PVOID oldWow64Value);
|
| 334 |
|
| 335 | #endif /* _WIN32 */
|
| 336 | #endif /* _H_UTILS */
|