/* | |
* 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 */ |