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