/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _H_UTILS #define _H_UTILS #ifdef _WIN32 #define _CRT_SECURE_NO_WARNINGS 1 #include <direct.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <windows.h> // VS vs MINGW specific includes #ifdef USE_VS_CRT #include <crtdbg.h> // for _ASSERT #else #define _ASSERT(x) // undef #endif extern bool gIsDebug; extern bool gIsConsole; // An array that knows its own size. Not dynamically resizable. template <class T> class CArray { T* mPtr; int mSize; public: explicit CArray(int size) { mSize = size; mPtr = new T[size]; } ~CArray() { if (mPtr != NULL) { delete[] mPtr; mPtr = NULL; } mSize = 0; } T& operator[](int i) { _ASSERT(i >= 0 && i < mSize); return mPtr[i]; } int size() const { return mSize; } }; // A simple string class wrapper. class CString { protected: char *mStr; public: CString() { mStr = NULL; } CString(const CString &str) { mStr = NULL; set(str.mStr); } explicit CString(const char *str) { mStr = NULL; set(str); } CString(const char *start, int length) { mStr = NULL; set(start, length); } CString& operator=(const CString &str) { return set(str.cstr()); } CString& set(const char *str) { if (str != mStr) { _free(); if (str != NULL) { mStr = _strdup(str); } } return *this; } CString& set(const char *start, int length) { _free(); if (start != NULL) { mStr = (char *)malloc(length + 1); strncpy(mStr, start, length); mStr[length] = 0; } return *this; } CString& setv(const char *str, va_list ap) { _free(); // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW. // Instead we'll iterate till we have enough space to generate the string. int len = strlen(str) + 1024; mStr = (char *)malloc(len); strcpy(mStr, str); // provide a default in case vsnprintf totally fails for (int guard = 0; guard < 10; guard++) { int ret = vsnprintf(mStr, len, str, ap); if (ret == -1) { // Some implementations don't give the proper size needed // so double the space and try again. len *= 2; } else if (ret >= len) { len = ret + 1; } else { // There was enough space to write. break; } mStr = (char *)realloc((void *)mStr, len); strcpy(mStr, str); // provide a default in case vsnprintf totally fails } return *this; } CString& setf(const char *str, ...) { _free(); va_list ap; va_start(ap, str); setv(str, ap); va_end(ap); return *this; } virtual ~CString() { _free(); } // Returns the C string owned by this CString. It will be // invalid as soon as this CString is deleted or out of scope. const char * cstr() const { return mStr; } bool isEmpty() const { return mStr == NULL || *mStr == 0; } int length() const { return mStr == NULL ? 0 : strlen(mStr); } CString& add(const char *str) { if (mStr == NULL) { set(str); } else { mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(str) + 1); strcat(mStr, str); } return *this; } CString& add(const char *str, int length) { if (mStr == NULL) { set(str, length); } else { int l1 = strlen(mStr); mStr = (char *)realloc((void *)mStr, l1 + length + 1); strncpy(mStr + l1, str, length); mStr[l1 + length] = 0; } return *this; } CArray<CString> * split(char sep) const { if (mStr == NULL) { return new CArray<CString>(0); } const char *last = NULL; int n = 0; for (const char *s = mStr; *s; s++) { if (*s == sep && s != mStr && (last == NULL || s > last+1)) { n++; last = s; } } CArray<CString> *result = new CArray<CString>(n); last = NULL; n = 0; for (const char *s = mStr; *s; s++) { if (*s == sep) { if (s != mStr && (last == NULL || s > last+1)) { const char *start = last ? last : mStr; (*result)[n++].set(start, s-start); } last = s+1; } } return result; } // Sets the string to the message matching Win32 GetLastError. // If message is non-null, it is prepended to the last error string. CString& setLastWin32Error(const char *message) { DWORD err = GetLastError(); LPSTR errStr; if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */ FORMAT_MESSAGE_FROM_SYSTEM, NULL, /* lpSource */ err, /* dwMessageId */ 0, /* dwLanguageId */ (LPSTR)&errStr, /* lpBuffer */ 0, /* nSize */ NULL) != 0) { /* va_list args */ if (message == NULL) { setf("[%d] %s", err, errStr); } else { setf("%s[%d] %s", message, err, errStr); } LocalFree(errStr); } return *this; } private: void _free() { if (mStr != NULL) { free((void *)mStr); mStr = NULL; } } }; // A simple path class wrapper. class CPath : public CString { public: CPath() : CString() { } CPath(const CString &str) : CString(str) { } CPath(const CPath &str) : CString(str) { } explicit CPath(const char *str) : CString(str) { } CPath(const char *start, int length) : CString(start, length) { } CPath& operator=(const CPath &str) { set(str.cstr()); return *this; } // Appends a path segment, adding a \ as necessary. CPath& addPath(const CString &s) { return addPath(s.cstr()); } // Appends a path segment, adding a \ as necessary. CPath& addPath(const char *s) { _ASSERT(s != NULL); if (s != NULL && s[0] != 0) { int n = length(); if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\"); add(s); } return *this; } // Returns true if file exist and is not a directory. // There's no garantee we have rights to access it. bool fileExists() const { if (mStr == NULL) return false; DWORD attribs = GetFileAttributesA(mStr); return attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY); } // Returns true if file exist and is a directory. // There's no garantee we have rights to access it. bool dirExists() const { if (mStr == NULL) return false; DWORD attribs = GetFileAttributesA(mStr); return attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; } // Returns a copy of the directory portion of the path, if any CPath dirName() const { CPath result; if (mStr != NULL) { char *pos = strrchr(mStr, '\\'); if (pos != NULL) { result.set(mStr, pos - mStr); } } return result; } // Returns a pointer to the baseName part of the path. // It becomes invalid if the path changes. const char * baseName() const { if (mStr != NULL) { char *pos = strrchr(mStr, '\\'); if (pos != NULL) { return pos + 1; } } return NULL; } // If the path ends with the given searchName, replace in-place by the new name void replaceName(const char *searchName, const char* newName) { if (mStr == NULL) return; int n = length(); int sn = strlen(searchName); if (n < sn) return; // if mStr ends with searchName if (strcmp(mStr + n - sn, searchName) == 0) { int sn2 = strlen(newName); if (sn2 > sn) { mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1); } strcpy(mStr + n - sn, newName); mStr[n + sn2 - sn] = 0; } } // Returns a copy of this path as a DOS short path in the destination. // Returns true if the Win32 getShortPathName method worked. // In case of error, returns false and does not change the destination. // It's OK to invoke this->toShortPath(this). bool toShortPath(CPath *dest) { const char *longPath = mStr; if (mStr == NULL) return false; DWORD lenShort = strlen(longPath) + 1; char * shortPath = (char *)malloc(lenShort); DWORD length = GetShortPathName(longPath, shortPath, lenShort); if (length > lenShort) { // The buffer wasn't big enough, this is the size to use. free(shortPath); lenShort = length; shortPath = (char *)malloc(length); length = GetShortPathName(longPath, shortPath, lenShort); } if (length != 0) dest->set(shortPath); free(shortPath); return length != 0; } }; // Displays a message in an ok+info dialog box. void msgBox(const char* text, ...); // Displays GetLastError prefixed with a description in an error dialog box void displayLastError(const char *description, ...); // Executes the command line. Does not wait for the program to finish. // The return code is from CreateProcess (0 means failure), not the running app. int execNoWait(const char *app, const char *params, const char *workDir); // Executes command, waits for completion and returns exit code. // As indicated in MSDN for CreateProcess, callers should double-quote the program name // e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2"; int execWait(const char *cmd); bool getModuleDir(CPath *outDir); // Disables the FS redirection done by WOW64. // Because this runs as a 32-bit app, Windows automagically remaps some // folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files"). // This prevents the app from correctly searching for java.exe in these folders. // The registry is also remapped. PVOID disableWow64FsRedirection(); // Reverts the redirection disabled in disableWow64FsRedirection. void revertWow64FsRedirection(PVOID oldWow64Value); #endif /* _WIN32 */ #endif /* _H_UTILS */