Add PInvoke/Array tests (#19266)
[platform/upstream/coreclr.git] / tests / src / Common / Platform / platformdefines.cpp
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(LPWSTR 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(LPWSTR 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 }