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 #define _CRT_SECURE_NO_WARNINGS 1
23 
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 gIsDebug;
38 extern bool gIsConsole;
39 
40 // An array that knows its own size. Not dynamically resizable.
41 template <class T> class CArray {
42     T* mPtr;
43     int mSize;
44 public:
CArray(int size)45     explicit CArray(int size) {
46         mSize = size;
47         mPtr = new T[size];
48     }
49 
~CArray()50     ~CArray() {
51         if (mPtr != NULL) {
52             delete[] mPtr;
53             mPtr = NULL;
54         }
55         mSize = 0;
56     }
57 
58     T& operator[](int i) {
59         _ASSERT(i >= 0 && i < mSize);
60         return mPtr[i];
61     }
62 
size()63     int size() const {
64         return mSize;
65     }
66 };
67 
68 // A simple string class wrapper.
69 class CString {
70 protected:
71     char *mStr;
72 public:
CString()73     CString()                              { mStr = NULL; }
CString(const CString & str)74     CString(const CString &str)            { mStr = NULL; set(str.mStr); }
CString(const char * str)75     explicit CString(const char *str)      { mStr = NULL; set(str); }
CString(const char * start,size_t length)76     CString(const char *start, size_t length) { mStr = NULL; set(start, length); }
77 
78     CString& operator=(const CString &str) {
79         return set(str.cstr());
80     }
81 
set(const char * str)82     CString& set(const char *str) {
83         if (str != mStr) {
84             _free();
85             if (str != NULL) {
86                 mStr = _strdup(str);
87             }
88         }
89         return *this;
90     }
91 
set(const char * start,size_t length)92     CString& set(const char *start, size_t length) {
93         _free();
94         if (start != NULL) {
95             mStr = (char *)malloc(length + 1);
96             strncpy(mStr, start, length);
97             mStr[length] = 0;
98         }
99         return *this;
100     }
101 
setv(const char * str,va_list ap)102     CString& setv(const char *str, va_list ap) {
103         _free();
104         // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.
105         // Instead we'll iterate till we have enough space to generate the string.
106         size_t len = strlen(str) + 1024;
107         mStr = (char *)malloc(len);
108         strcpy(mStr, str); // provide a default in case vsnprintf totally fails
109         for (int guard = 0; guard < 10; guard++) {
110             int ret = vsnprintf(mStr, len, str, ap);
111             if (ret == -1) {
112                 // Some implementations don't give the proper size needed
113                 // so double the space and try again.
114                 len *= 2;
115             } else if (ret >= len) {
116                 len = ret + 1;
117             } else {
118                 // There was enough space to write.
119                 break;
120             }
121             mStr = (char *)realloc((void *)mStr, len);
122             strcpy(mStr, str); // provide a default in case vsnprintf totally fails
123         }
124         return *this;
125     }
126 
setf(const char * str,...)127     CString& setf(const char *str, ...) {
128         _free();
129         va_list ap;
130         va_start(ap, str);
131         setv(str, ap);
132         va_end(ap);
133         return *this;
134     }
135 
~CString()136     virtual ~CString() { _free(); }
137 
138     // Returns the C string owned by this CString. It will be
139     // invalid as soon as this CString is deleted or out of scope.
cstr()140     const char * cstr() const {
141         return mStr;
142     }
143 
isEmpty()144     bool isEmpty() const {
145         return mStr == NULL || *mStr == 0;
146     }
147 
length()148     size_t length() const {
149         return mStr == NULL ? 0 : strlen(mStr);
150     }
151 
add(const char * str)152     CString& add(const char *str) {
153         if (mStr == NULL) {
154             set(str);
155         } else {
156             mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(str) + 1);
157             strcat(mStr, str);
158         }
159         return *this;
160     }
161 
add(const char * str,int length)162     CString& add(const char *str, int length) {
163         if (mStr == NULL) {
164             set(str, length);
165         } else {
166             size_t l1 = strlen(mStr);
167             mStr = (char *)realloc((void *)mStr, l1 + length + 1);
168             strncpy(mStr + l1, str, length);
169             mStr[l1 + length] = 0;
170         }
171         return *this;
172     }
173 
split(char sep)174     CArray<CString> * split(char sep) const {
175         if (mStr == NULL) {
176             return new CArray<CString>(0);
177         }
178         const char *last = NULL;
179         int n = 0;
180         for (const char *s = mStr; *s; s++) {
181             if (*s == sep && s != mStr && (last == NULL || s > last+1)) {
182                 n++;
183                 last = s;
184             }
185         }
186 
187         CArray<CString> *result = new CArray<CString>(n);
188         last = NULL;
189         n = 0;
190         for (const char *s = mStr; *s; s++) {
191             if (*s == sep) {
192                 if (s != mStr && (last == NULL || s > last+1)) {
193                     const char *start = last ? last : mStr;
194                     (*result)[n++].set(start, s-start);
195                 }
196                 last = s+1;
197             }
198         }
199 
200         return result;
201     }
202 
203     // Sets the string to the message matching Win32 GetLastError.
204     // If message is non-null, it is prepended to the last error string.
setLastWin32Error(const char * message)205     CString& setLastWin32Error(const char *message) {
206         DWORD err = GetLastError();
207         LPSTR errStr;
208         if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */
209                           FORMAT_MESSAGE_FROM_SYSTEM,
210                           NULL,                             /* lpSource */
211                           err,                              /* dwMessageId */
212                           0,                                /* dwLanguageId */
213                           (LPSTR)&errStr,                   /* lpBuffer */
214                           0,                                /* nSize */
215                           NULL) != 0) {                     /* va_list args */
216             if (message == NULL) {
217                 setf("[%d] %s", err, errStr);
218             } else {
219                 setf("%s[%d] %s", message, err, errStr);
220             }
221             LocalFree(errStr);
222         }
223         return *this;
224     }
225 
226 private:
_free()227     void _free() {
228         if (mStr != NULL) {
229             free((void *)mStr);
230             mStr = NULL;
231         }
232     }
233 
234 };
235 
236 // A simple path class wrapper.
237 class CPath : public CString {
238 public:
CPath()239     CPath()                              : CString()    { }
CPath(const CString & str)240     CPath(const CString &str)            : CString(str) { }
CPath(const CPath & str)241     CPath(const CPath &str)              : CString(str) { }
CPath(const char * str)242     explicit CPath(const char *str)      : CString(str) { }
CPath(const char * start,int length)243     CPath(const char *start, int length) : CString(start, length) { }
244 
245     CPath& operator=(const CPath &str) {
246         set(str.cstr());
247         return *this;
248     }
249 
250     // Appends a path segment, adding a \ as necessary.
addPath(const CString & s)251     CPath& addPath(const CString &s) {
252         return addPath(s.cstr());
253     }
254 
255     // Appends a path segment, adding a \ as necessary.
addPath(const char * s)256     CPath& addPath(const char *s) {
257         _ASSERT(s != NULL);
258         if (s != NULL && s[0] != 0) {
259             size_t n = length();
260             if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");
261             add(s);
262         }
263         return *this;
264     }
265 
266     // Returns true if file exist and is not a directory.
267     // There's no garantee we have rights to access it.
fileExists()268     bool fileExists() const {
269         if (mStr == NULL) return false;
270         DWORD attribs = GetFileAttributesA(mStr);
271         return attribs != INVALID_FILE_ATTRIBUTES &&
272              !(attribs & FILE_ATTRIBUTE_DIRECTORY);
273     }
274 
275     // Returns true if file exist and is a directory.
276     // There's no garantee we have rights to access it.
dirExists()277     bool dirExists() const {
278         if (mStr == NULL) return false;
279         DWORD attribs = GetFileAttributesA(mStr);
280         return attribs != INVALID_FILE_ATTRIBUTES &&
281               (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
282     }
283 
284     // Returns a copy of the directory portion of the path, if any
dirName()285     CPath dirName() const {
286         CPath result;
287         if (mStr != NULL) {
288             char *pos = strrchr(mStr, '\\');
289             if (pos != NULL) {
290                 result.set(mStr, pos - mStr);
291             }
292         }
293         return result;
294     }
295 
296     // Returns a pointer to the baseName part of the path.
297     // It becomes invalid if the path changes.
baseName()298     const char * baseName() const {
299         if (mStr != NULL) {
300             char *pos = strrchr(mStr, '\\');
301             if (pos != NULL) {
302                 return pos + 1;
303             }
304         }
305         return NULL;
306     }
307 
308     // If the path ends with the given searchName, replace in-place by the new name
replaceName(const char * searchName,const char * newName)309     void replaceName(const char *searchName, const char* newName) {
310         if (mStr == NULL) return;
311         size_t n = length();
312         size_t sn = strlen(searchName);
313         if (n < sn) return;
314         // if mStr ends with searchName
315         if (strcmp(mStr + n - sn, searchName) == 0) {
316             size_t sn2 = strlen(newName);
317             if (sn2 > sn) {
318                 mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);
319             }
320             strcpy(mStr + n - sn, newName);
321             mStr[n + sn2 - sn] = 0;
322         }
323     }
324 
325     // Returns a copy of this path as a DOS short path in the destination.
326     // Returns true if the Win32 getShortPathName method worked.
327     // In case of error, returns false and does not change the destination.
328     // It's OK to invoke this->toShortPath(this).
toShortPath(CPath * dest)329     bool toShortPath(CPath *dest) {
330         const char *longPath = mStr;
331         if (mStr == NULL) return false;
332 
333         DWORD lenShort = (DWORD)strlen(longPath) + 1; // GetShortPathName deals with DWORDs
334         char * shortPath = (char *)malloc(lenShort);
335 
336         DWORD length = GetShortPathName(longPath, shortPath, lenShort);
337         if (length > lenShort) {
338             // The buffer wasn't big enough, this is the size to use.
339             free(shortPath);
340             lenShort = length;
341             shortPath = (char *)malloc(length);
342             length = GetShortPathName(longPath, shortPath, lenShort);
343         }
344 
345         if (length != 0) dest->set(shortPath);
346 
347         free(shortPath);
348         return length != 0;
349     }
350 };
351 
352 // Displays a message in an ok+info dialog box.
353 void msgBox(const char* text, ...);
354 
355 // Displays GetLastError prefixed with a description in an error dialog box
356 void displayLastError(const char *description, ...);
357 
358 // Executes the command line. Does not wait for the program to finish.
359 // The return code is from CreateProcess (0 means failure), not the running app.
360 int execNoWait(const char *app, const char *params, const char *workDir);
361 
362 // Executes command, waits for completion and returns exit code.
363 // As indicated in MSDN for CreateProcess, callers should double-quote the program name
364 // e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
365 int execWait(const char *cmd);
366 
367 bool getModuleDir(CPath *outDir);
368 
369 #endif /* _WIN32 */
370 #endif /* _H_UTILS */
371