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
8LPWSTR 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
30LPSTR 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
49error_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
67error_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
80size_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
92int 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
116int 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
140error_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
162error_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
183void 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
197error_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
239error_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
281LPWSTR 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
317DWORD 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}
329DWORD 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
361void 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//
376HRESULT 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
390HRESULT 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
404HRESULT ULongMult(ULONG ulMultiplicand, ULONG ulMultiplier, ULONG* pulResult)
405{
406 ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier);
407
408 return ULongLongToULong(ull64Result, pulResult);
409}
410
411HRESULT 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
441BSTR 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
452BSTR 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
483BSTR 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
518void 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
529size_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
546DWORD 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