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