1 | // Copyright (c) Microsoft. All rights reserved. |
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
3 | // |
4 | |
5 | |
6 | #include "platformdefines.h" |
7 | |
8 | LPWSTR HackyConvertToWSTR(const char* pszInput) |
9 | { |
10 | size_t cchInput; |
11 | LPWSTR pwszOutput; |
12 | char* pStr; |
13 | |
14 | if (NULL == pszInput) return NULL; |
15 | |
16 | // poor mans strlen |
17 | pStr = (char*)pszInput; |
18 | cchInput = 0; |
19 | while('\0' != *pStr) {cchInput++; pStr++;} |
20 | pwszOutput = new WCHAR[ cchInput + 1]; |
21 | |
22 | for(size_t i=0; i<=cchInput; i++) |
23 | { |
24 | pwszOutput[i] = (WCHAR)pszInput[i]; |
25 | } |
26 | |
27 | return pwszOutput; |
28 | } |
29 | |
30 | LPSTR HackyConvertToSTR(LPWSTR pwszInput) |
31 | { |
32 | size_t cchInput; |
33 | LPSTR pszOutput; |
34 | |
35 | if (NULL == pwszInput) return NULL; |
36 | |
37 | cchInput = wcslen(pwszInput); |
38 | pszOutput = new char[ cchInput + 1]; |
39 | |
40 | for(size_t i=0; i<=cchInput; i++) |
41 | { |
42 | // ugly down cast |
43 | pszOutput[i] = (char)pwszInput[i]; |
44 | } |
45 | |
46 | return pszOutput; |
47 | } |
48 | |
49 | error_t TP_scpy_s(LPWSTR strDestination, size_t sizeInWords, LPCWSTR strSource) |
50 | { |
51 | size_t cnt; |
52 | // copy sizeInBytes bytes of strSource into strDestination |
53 | |
54 | if (NULL == strDestination || NULL == strSource) return 1; |
55 | |
56 | cnt = 0; |
57 | while(cnt < sizeInWords && '\0' != strSource[cnt]) |
58 | { |
59 | strDestination[cnt] = strSource[cnt]; |
60 | cnt++; |
61 | } |
62 | strDestination[cnt] = '\0'; |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | error_t TP_scat_s(LPWSTR strDestination, size_t sizeInWords, LPCWSTR strSource) |
68 | { |
69 | LPWSTR strEnd; |
70 | // locate the end (ie. '\0') and TP_scpy_s the string |
71 | |
72 | if (NULL == strDestination || NULL == strSource) return 1; |
73 | |
74 | strEnd = strDestination; |
75 | while('\0' != *strEnd) strEnd++; |
76 | |
77 | return TP_scpy_s(strEnd, sizeInWords - ((strEnd - strDestination) / sizeof(WCHAR)), strSource); |
78 | } |
79 | |
80 | size_t TP_slen(LPCWSTR str) |
81 | { |
82 | size_t len; |
83 | |
84 | if (NULL == str) return 0; |
85 | |
86 | len = 0; |
87 | while('\0' != *(str+len)) len++; |
88 | |
89 | return len; |
90 | } |
91 | |
92 | int TP_scmp_s(LPCSTR str1, LPCSTR str2) |
93 | { |
94 | // < 0 str1 less than str2 |
95 | // 0 str1 identical to str2 |
96 | // > 0 str1 greater than str2 |
97 | |
98 | if (NULL == str1 && NULL != str2) return -1; |
99 | if (NULL != str1 && NULL == str2) return 1; |
100 | if (NULL == str1 && NULL == str2) return 0; |
101 | |
102 | while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2) |
103 | { |
104 | str1++; |
105 | str2++; |
106 | } |
107 | |
108 | if ('\0' == *str1 && '\0' == *str2) return 0; |
109 | |
110 | if ('\0' != *str1) return -1; |
111 | if ('\0' != *str2) return 1; |
112 | |
113 | return (*str1 > *str2) ? 1 : -1; |
114 | } |
115 | |
116 | int TP_wcmp_s(LPCWSTR str1, LPCWSTR str2) |
117 | { |
118 | // < 0 str1 less than str2 |
119 | // 0 str1 identical to str2 |
120 | // > 0 str1 greater than str2 |
121 | |
122 | if (NULL == str1 && NULL != str2) return -1; |
123 | if (NULL != str1 && NULL == str2) return 1; |
124 | if (NULL == str1 && NULL == str2) return 0; |
125 | |
126 | while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2) |
127 | { |
128 | str1++; |
129 | str2++; |
130 | } |
131 | |
132 | if ('\0' == *str1 && '\0' == *str2) return 0; |
133 | |
134 | if ('\0' != *str1) return -1; |
135 | if ('\0' != *str2) return 1; |
136 | |
137 | return (*str1 > *str2) ? 1 : -1; |
138 | } |
139 | |
140 | error_t TP_getenv_s(size_t* pReturnValue, LPWSTR buffer, size_t sizeInWords, LPCWSTR varname) |
141 | { |
142 | if (NULL == pReturnValue || NULL == varname) return 1; |
143 | |
144 | #ifdef WINDOWS |
145 | |
146 | size_t returnValue; |
147 | WCHAR buf[100]; |
148 | if( 0 != _wgetenv_s(&returnValue, buf, 100, varname) || returnValue<=0 ) |
149 | return 2; |
150 | |
151 | |
152 | TP_scpy_s(buffer, sizeInWords, (LPWSTR)buf); |
153 | #else |
154 | LPSTR pRet; |
155 | pRet = getenv( HackyConvertToSTR((LPWSTR)varname) ); |
156 | if (NULL == pRet) return 2; |
157 | TP_scpy_s(buffer, sizeInWords, HackyConvertToWSTR(pRet)); |
158 | #endif |
159 | return 0; |
160 | } |
161 | |
162 | error_t TP_putenv_s(LPTSTR name, LPTSTR value) |
163 | { |
164 | if (NULL == name || NULL == value) return 1; |
165 | |
166 | #ifdef WINDOWS |
167 | if( 0 != _putenv_s(name, value)) |
168 | return 2; |
169 | else |
170 | return 0; |
171 | #else |
172 | int retVal = 0; |
173 | char *assignment = (char*) malloc(sizeof(char) * (strlen(name) + strlen(value) + 1)); |
174 | sprintf(assignment, "%s=%s" , name, value); |
175 | |
176 | if (0 != putenv(assignment)) |
177 | retVal = 2; |
178 | free(assignment); |
179 | return retVal; |
180 | #endif |
181 | } |
182 | |
183 | void TP_ZeroMemory(LPVOID buffer, size_t sizeInBytes) |
184 | { |
185 | BYTE* bBuf; |
186 | |
187 | // clear out the memory with 0's |
188 | if (NULL == buffer) return; |
189 | |
190 | bBuf = (BYTE*)buffer; |
191 | for(size_t i=0; i<sizeInBytes; i++) |
192 | { |
193 | bBuf[i] = 0; |
194 | } |
195 | } |
196 | |
197 | error_t TP_itow_s(int num, LPWSTR buffer, size_t sizeInCharacters, int radix) |
198 | { |
199 | size_t len; |
200 | int tmpNum; |
201 | |
202 | // only support radix == 10 and only positive numbers |
203 | if (10 != radix) return 1; |
204 | if (0 > num) return 2; |
205 | if (NULL == buffer) return 3; |
206 | if (2 > sizeInCharacters) return 4; |
207 | |
208 | // take care of the trivial case |
209 | if (0 == num) |
210 | { |
211 | buffer[0] = '0'; |
212 | buffer[1] = '\0'; |
213 | return 0; |
214 | } |
215 | |
216 | // get length of final string (dumb implementation) |
217 | len = 0; |
218 | tmpNum = num; |
219 | while (0 < tmpNum) |
220 | { |
221 | tmpNum /= 10; |
222 | len++; |
223 | } |
224 | |
225 | if (len >= sizeInCharacters) return 5; |
226 | |
227 | // convert num into a string (backwards) |
228 | buffer[len] = '\0'; |
229 | while(0 < num && 0 < len) |
230 | { |
231 | len--; |
232 | buffer[len] = (WCHAR)((num % 10) + '0'); |
233 | num /= 10; |
234 | } |
235 | |
236 | return 0; |
237 | } |
238 | |
239 | error_t TP_itoa_s(int num, LPSTR buffer, size_t sizeInCharacters, int radix) |
240 | { |
241 | size_t len; |
242 | int tmpNum; |
243 | |
244 | // only support radix == 10 and only positive numbers |
245 | if (10 != radix) return 1; |
246 | if (0 > num) return 2; |
247 | if (NULL == buffer) return 3; |
248 | if (2 > sizeInCharacters) return 4; |
249 | |
250 | // take care of the trivial case |
251 | if (0 == num) |
252 | { |
253 | buffer[0] = '0'; |
254 | buffer[1] = '\0'; |
255 | return 0; |
256 | } |
257 | |
258 | // get length of final string (dumb implementation) |
259 | len = 0; |
260 | tmpNum = num; |
261 | while (0 < tmpNum) |
262 | { |
263 | tmpNum /= 10; |
264 | len++; |
265 | } |
266 | |
267 | if (len >= sizeInCharacters) return 5; |
268 | |
269 | // convert num into a string (backwards) |
270 | buffer[len] = '\0'; |
271 | while(0 < num && 0 < len) |
272 | { |
273 | len--; |
274 | buffer[len] = (char)((num % 10) + '0'); |
275 | num /= 10; |
276 | } |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | LPWSTR TP_sstr(LPWSTR str, LPWSTR searchStr) |
282 | { |
283 | LPWSTR start; |
284 | LPWSTR current; |
285 | LPWSTR searchCurrent; |
286 | |
287 | if (NULL == str || NULL == searchStr) return NULL; |
288 | |
289 | // return a pointer to where searchStr |
290 | // exists in str |
291 | current = str; |
292 | start = NULL; |
293 | searchCurrent = searchStr; |
294 | while('\0' != *current) |
295 | { |
296 | if (NULL != start && '\0' == *searchCurrent) |
297 | { |
298 | break; |
299 | } |
300 | |
301 | if (*current == *searchCurrent) |
302 | { |
303 | searchCurrent++; |
304 | if (NULL == start) start = current; |
305 | } |
306 | else |
307 | { |
308 | searchCurrent = searchStr; |
309 | start = NULL; |
310 | } |
311 | current++; |
312 | } |
313 | |
314 | return start; |
315 | } |
316 | |
317 | DWORD TP_GetFullPathName(LPWSTR fileName, DWORD nBufferLength, LPWSTR lpBuffer) |
318 | { |
319 | #ifdef WINDOWS |
320 | return GetFullPathNameW(fileName, nBufferLength, lpBuffer, NULL); |
321 | #else |
322 | char nativeFullPath[MAX_PATH]; |
323 | (void)realpath(HackyConvertToSTR(fileName), nativeFullPath); |
324 | LPWSTR fullPathForCLR = HackyConvertToWSTR(nativeFullPath); |
325 | wcscpy_s(lpBuffer, MAX_PATH, fullPathForCLR); |
326 | return wcslen(lpBuffer); |
327 | #endif |
328 | } |
329 | DWORD TP_CreateThread(THREAD_ID* tThread, LPTHREAD_START_ROUTINE worker, LPVOID lpParameter) |
330 | { |
331 | #ifdef WINDOWS |
332 | DWORD ret; |
333 | *tThread = CreateThread( |
334 | NULL, |
335 | 0, |
336 | worker, |
337 | lpParameter, |
338 | 0, |
339 | &ret); |
340 | return ret; |
341 | #else |
342 | pthread_create( |
343 | tThread, |
344 | NULL, |
345 | (MacWorker)worker, |
346 | lpParameter); |
347 | #ifdef MAC64 |
348 | // This is a major kludge...64 bit posix threads just can't be cast into a DWORD and there just isn't |
349 | // a great way to get what we're using for the ID. The fact that we're casting this at all is kind of |
350 | // silly since we're returing the actual thread handle and everything being done to manipulate the thread |
351 | // is done with that. Anyhow, the only thing done with the dword returned from this method is a printf |
352 | // which is good since this DWORD really shouldn't be reliably used. Just in case it is though, return |
353 | // a value that can be traced back to here. |
354 | return 42; |
355 | #else |
356 | return (DWORD)*tThread; |
357 | #endif |
358 | #endif |
359 | } |
360 | |
361 | void TP_JoinThread(THREAD_ID tThread) |
362 | { |
363 | #ifdef WINDOWS |
364 | WaitForSingleObject(tThread, INFINITE); |
365 | #else |
366 | pthread_join(tThread, NULL); |
367 | #endif |
368 | } |
369 | |
370 | #define INTSAFE_E_ARITHMETIC_OVERFLOW ((HRESULT)0x80070216L) // 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW |
371 | #define ULONG_ERROR (0xffffffffUL) |
372 | #define WIN32_ALLOC_ALIGN (16 - 1) |
373 | // |
374 | // ULONGLONG -> ULONG conversion |
375 | // |
376 | HRESULT ULongLongToULong(ULONGLONG ullOperand, ULONG* pulResult) |
377 | { |
378 | HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; |
379 | *pulResult = ULONG_ERROR; |
380 | |
381 | if (ullOperand <= ULONG_MAX) |
382 | { |
383 | *pulResult = (ULONG)ullOperand; |
384 | hr = S_OK; |
385 | } |
386 | |
387 | return hr; |
388 | } |
389 | |
390 | HRESULT ULongAdd(ULONG ulAugend, ULONG ulAddend,ULONG* pulResult) |
391 | { |
392 | HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; |
393 | *pulResult = ULONG_ERROR; |
394 | |
395 | if ((ulAugend + ulAddend) >= ulAugend) |
396 | { |
397 | *pulResult = (ulAugend + ulAddend); |
398 | hr = S_OK; |
399 | } |
400 | |
401 | return hr; |
402 | } |
403 | |
404 | HRESULT ULongMult(ULONG ulMultiplicand, ULONG ulMultiplier, ULONG* pulResult) |
405 | { |
406 | ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier); |
407 | |
408 | return ULongLongToULong(ull64Result, pulResult); |
409 | } |
410 | |
411 | HRESULT CbSysStringSize(ULONG cchSize, BOOL isByteLen, ULONG *result) |
412 | { |
413 | if (result == NULL) |
414 | return E_INVALIDARG; |
415 | |
416 | // +2 for the null terminator |
417 | // + DWORD_PTR to store the byte length of the string |
418 | int constant = sizeof(WCHAR) + sizeof(DWORD_PTR) + WIN32_ALLOC_ALIGN; |
419 | |
420 | if (isByteLen) |
421 | { |
422 | if (SUCCEEDED(ULongAdd(constant, cchSize, result))) |
423 | { |
424 | *result = *result & ~WIN32_ALLOC_ALIGN; |
425 | return S_OK; |
426 | } |
427 | } |
428 | else |
429 | { |
430 | ULONG temp = 0; // should not use in-place addition in ULongAdd |
431 | if (SUCCEEDED(ULongMult(cchSize, sizeof(WCHAR), &temp)) & |
432 | SUCCEEDED(ULongAdd(temp, constant, result))) |
433 | { |
434 | *result = *result & ~WIN32_ALLOC_ALIGN; |
435 | return S_OK; |
436 | } |
437 | } |
438 | return INTSAFE_E_ARITHMETIC_OVERFLOW; |
439 | } |
440 | |
441 | BSTR TP_SysAllocString(LPCWSTR psz) |
442 | { |
443 | #ifdef WINDOWS |
444 | return SysAllocString(psz); |
445 | #else |
446 | if(psz == NULL) |
447 | return NULL; |
448 | return TP_SysAllocStringLen(psz, (DWORD)wcslen(psz)); |
449 | #endif |
450 | } |
451 | |
452 | BSTR TP_SysAllocStringLen(LPCWSTR psz, size_t len) |
453 | { |
454 | ULONG cbTotal = 0; |
455 | |
456 | if (FAILED(CbSysStringSize((ULONG)len, FALSE, &cbTotal))) |
457 | return NULL; |
458 | |
459 | BSTR bstr = (BSTR)TP_CoTaskMemAlloc(cbTotal); |
460 | |
461 | if(bstr != NULL){ |
462 | |
463 | #if defined(_WIN64) |
464 | // NOTE: There are some apps which peek back 4 bytes to look at the size of the BSTR. So, in case of 64-bit code, |
465 | // we need to ensure that the BSTR length can be found by looking one DWORD before the BSTR pointer. |
466 | *(DWORD_PTR *)bstr = (DWORD_PTR) 0; |
467 | bstr = (BSTR) ((char *) bstr + sizeof (DWORD)); |
468 | #endif |
469 | *(DWORD *)bstr = (DWORD)len * sizeof(OLECHAR); |
470 | |
471 | bstr = (BSTR) ((char*) bstr + sizeof(DWORD)); |
472 | |
473 | if(psz != NULL){ |
474 | memcpy(bstr, psz, len * sizeof(OLECHAR)); |
475 | } |
476 | |
477 | bstr[len] = '\0'; // always 0 terminate |
478 | } |
479 | |
480 | return bstr; |
481 | } |
482 | |
483 | BSTR TP_SysAllocStringByteLen(LPCSTR psz, size_t len) |
484 | { |
485 | #ifdef WINDOWS |
486 | return SysAllocStringByteLen(psz, (UINT)len); |
487 | #else |
488 | BSTR bstr; |
489 | ULONG cbTotal = 0; |
490 | |
491 | if (FAILED(CbSysStringSize(len, TRUE, &cbTotal))) |
492 | return NULL; |
493 | |
494 | bstr = (BSTR)TP_CoTaskMemAlloc(cbTotal); |
495 | |
496 | if (bstr != NULL) { |
497 | #if defined(_WIN64) |
498 | *(DWORD *)((char *)bstr + sizeof (DWORD)) = (DWORD)len; |
499 | #else |
500 | *(DWORD *)bstr = (DWORD)len; |
501 | #endif |
502 | |
503 | bstr = (WCHAR*) ((char*) bstr + sizeof(DWORD_PTR)); |
504 | |
505 | if (psz != NULL) { |
506 | memcpy(bstr, psz, len); |
507 | } |
508 | |
509 | // NULL-terminate with both a narrow and wide zero. |
510 | *((char *)bstr + len) = '\0'; |
511 | *(WCHAR *)((char *)bstr + ((len + 1) & ~1)) = 0; |
512 | } |
513 | |
514 | return bstr; |
515 | #endif |
516 | } |
517 | |
518 | void TP_SysFreeString(BSTR bstr) |
519 | { |
520 | #ifdef WINDOWS |
521 | return SysFreeString(bstr); |
522 | #else |
523 | if (bstr == NULL) |
524 | return; |
525 | TP_CoTaskMemFree((BYTE *)bstr - sizeof(DWORD_PTR)); |
526 | #endif |
527 | } |
528 | |
529 | size_t TP_SysStringByteLen(BSTR bstr) |
530 | { |
531 | #ifdef WINDOWS |
532 | return SysStringByteLen(bstr); |
533 | #else |
534 | if(bstr == NULL) |
535 | return 0; |
536 | int32_t * p32 = (int32_t *) bstr; |
537 | int32_t * p32_1 = p32 -1; |
538 | DWORD * d32 = (DWORD *) bstr; |
539 | DWORD * d32_1 = d32 - 1; |
540 | //std::cout << p32 << p32_1 << endl; |
541 | //std::cout << d32 << d32_1 << endl; |
542 | return (unsigned int)(((DWORD *)bstr)[-1]); |
543 | #endif |
544 | } |
545 | |
546 | DWORD TP_SysStringLen(BSTR bstr) |
547 | { |
548 | #ifdef WINDOWS |
549 | return SysStringLen(bstr); |
550 | #else |
551 | if(bstr == NULL) |
552 | return 0; |
553 | return (unsigned int)((((DWORD *)bstr)[-1]) / sizeof(OLECHAR)); |
554 | #endif |
555 | } |
556 | |