| /* | |
| * 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, size_t 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, size_t 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. | |
| size_t 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; | |
| } | |
| size_t 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 { | |
| size_t 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) { | |
| size_t 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; | |
| size_t n = length(); | |
| size_t sn = strlen(searchName); | |
| if (n < sn) return; | |
| // if mStr ends with searchName | |
| if (strcmp(mStr + n - sn, searchName) == 0) { | |
| size_t 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 = (DWORD)strlen(longPath) + 1; // GetShortPathName deals with DWORDs | |
| 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); | |
| #endif /* _WIN32 */ | |
| #endif /* _H_UTILS */ |