ae22b15a10f54b405adc67b52fe1448ea4fc6262
[platform/upstream/coreclr.git] / src / palrt / bstr.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5
6 //
7 // ===========================================================================
8 // File: bstr.cpp
9 // 
10 // ===========================================================================
11
12
13 /*++
14
15 Abstract:
16
17     PALRT BSTR support
18
19 Revision History:
20
21 --*/
22
23 #include "common.h"
24 #include "intsafe.h"
25
26 #define CCH_BSTRMAX 0x7FFFFFFF  // 4 + (0x7ffffffb + 1 ) * 2 ==> 0xFFFFFFFC
27 #define CB_BSTRMAX 0xFFFFFFFa   // 4 + (0xfffffff6 + 2) ==> 0xFFFFFFFC
28
29 #define WIN32_ALLOC_ALIGN (16 - 1)      
30
31 inline HRESULT CbSysStringSize(ULONG cchSize, BOOL isByteLen, ULONG *result)
32 {
33     if (result == NULL)
34         return E_INVALIDARG;
35
36     // +2 for the null terminator
37     // + DWORD_PTR to store the byte length of the string
38     int constant = sizeof(WCHAR) + sizeof(DWORD_PTR) + WIN32_ALLOC_ALIGN;
39
40     if (isByteLen)
41     {
42         if (SUCCEEDED(ULongAdd(constant, cchSize, result)))
43         {
44             *result = *result & ~WIN32_ALLOC_ALIGN;
45             return NOERROR;
46         }
47     }
48     else
49     {
50         ULONG temp = 0; // should not use in-place addition in ULongAdd
51         if (SUCCEEDED(ULongMult(cchSize, sizeof(WCHAR), &temp)) &
52             SUCCEEDED(ULongAdd(temp, constant, result)))
53         {
54             *result = *result & ~WIN32_ALLOC_ALIGN;
55             return NOERROR;
56         }
57     }
58     return INTSAFE_E_ARITHMETIC_OVERFLOW;
59 }
60
61 /***
62 *BSTR SysAllocStringLen(char*, unsigned int)
63 *Purpose:
64 *  Allocation a bstr of the given length and initialize with
65 *  the pasted in string
66 *
67 *Entry:
68 *  [optional]
69 *
70 *Exit:
71 *  return value = BSTR, NULL if the allocation failed.
72 *
73 ***********************************************************************/
74 STDAPI_(BSTR) SysAllocStringLen(const OLECHAR *psz, UINT len)
75 {
76     
77     BSTR bstr;
78     DWORD cbTotal = 0;
79
80     if (FAILED(CbSysStringSize(len, FALSE, &cbTotal)))
81         return NULL;
82
83     bstr = (OLECHAR *)HeapAlloc(GetProcessHeap(), 0, cbTotal);
84
85     if(bstr != NULL){
86
87 #if defined(_WIN64)
88       // 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,
89       // we need to ensure that the BSTR length can be found by looking one DWORD before the BSTR pointer. 
90       *(DWORD_PTR *)bstr = (DWORD_PTR) 0;
91       bstr = (BSTR) ((char *) bstr + sizeof (DWORD));
92 #endif
93       *(DWORD FAR*)bstr = (DWORD)len * sizeof(OLECHAR);
94
95       bstr = (BSTR) ((char*) bstr + sizeof(DWORD));
96
97       if(psz != NULL){
98             memcpy(bstr, psz, len * sizeof(OLECHAR));
99       }
100
101       bstr[len] = '\0'; // always 0 terminate
102     }
103
104     return bstr;
105 }
106
107 /***
108 *BSTR SysAllocString(char*)
109 *Purpose:
110 *  Allocation a bstr using the passed in string
111 *
112 *Entry:
113 *  String to create a bstr for
114 *
115 *Exit:
116 *  return value = BSTR, NULL if allocation failed
117 *
118 ***********************************************************************/
119 STDAPI_(BSTR) SysAllocString(const OLECHAR* psz)
120 {
121     if(psz == NULL)
122       return NULL;
123
124     return SysAllocStringLen(psz, (DWORD)wcslen(psz));
125 }
126
127 STDAPI_(BSTR)
128 SysAllocStringByteLen(const char FAR* psz, unsigned int len)
129 {
130     BSTR bstr;
131     DWORD cbTotal = 0;
132
133     if (FAILED(CbSysStringSize(len, TRUE, &cbTotal)))
134         return FALSE;
135
136     bstr = (OLECHAR *)HeapAlloc(GetProcessHeap(), 0, cbTotal);
137
138     if (bstr != NULL) {
139 #if defined(_WIN64)
140       *(DWORD FAR*)((char *)bstr + sizeof (DWORD)) = (DWORD)len;
141 #else
142       *(DWORD FAR*)bstr = (DWORD)len;
143 #endif
144
145       bstr = (WCHAR*) ((char*) bstr + sizeof(DWORD_PTR));
146
147       if (psz != NULL) {
148             memcpy(bstr, psz, len);
149       }
150
151       // NULL-terminate with both a narrow and wide zero.
152       *((char *)bstr + len) = '\0';
153       *(WCHAR *)((char *)bstr + ((len + 1) & ~1)) = 0;
154     }
155
156     return bstr;
157 }
158
159 /***
160 *void SysFreeString(BSTR)
161 *Purpose:
162 *  Free the given BSTR.
163 *
164 *Entry:
165 *  bstr = the BSTR to free
166 *
167 *Exit:
168 *  None
169 *
170 ***********************************************************************/
171 STDAPI_(void) SysFreeString(BSTR bstr)
172 {
173     if(bstr == NULL)
174       return;
175     HeapFree(GetProcessHeap(), 0, (BYTE *)bstr-sizeof(DWORD_PTR));    
176 }
177
178 /***
179 *unsigned int SysStringLen(BSTR)
180 *Purpose:
181 *  return the length in characters of the given BSTR.
182 *
183 *Entry:
184 *  bstr = the BSTR to return the length of
185 *
186 *Exit:
187 *  return value = unsigned int, length in characters.
188 *
189 ***********************************************************************/
190 STDAPI_(unsigned int)
191 SysStringLen(BSTR bstr)
192 {
193     if(bstr == NULL)
194       return 0;
195     return (unsigned int)((((DWORD FAR*)bstr)[-1]) / sizeof(OLECHAR));
196 }
197
198 /***
199 *unsigned int SysStringByteLen(BSTR)
200 *Purpose:
201 *  return the size in bytes of the given BSTR.
202 *
203 *Entry:
204 *  bstr = the BSTR to return the size of
205 *
206 *Exit:
207 *  return value = unsigned int, size in bytes.
208 *
209 ***********************************************************************/
210 STDAPI_(unsigned int)
211 SysStringByteLen(BSTR bstr)
212 {
213     if(bstr == NULL)
214       return 0;
215     return (unsigned int)(((DWORD FAR*)bstr)[-1]);
216 }
217
218 extern "C" HRESULT
219 ErrStringCopy(BSTR bstrSource, BSTR FAR *pbstrOut)
220 {
221     if (bstrSource == NULL) {
222         *pbstrOut = NULL;
223         return NOERROR;
224     }
225     if ((*pbstrOut = SysAllocStringLen(bstrSource,
226                                        SysStringLen(bstrSource))) == NULL)
227         return E_OUTOFMEMORY;
228
229     return NOERROR;
230 }
231
232 /***
233 *PRIVATE HRESULT ErrSysAllocString(char*, BSTR*)
234 *Purpose:
235 *  This is an implementation of SysAllocString that check for the
236 *  NULL return value and return the corresponding error - E_OUTOFMEMORY.
237 *
238 *  This is simply a convenience, and this routine is only used
239 *  internally by the oledisp component.
240 *
241 *Entry:
242 *  psz = the source string
243 *
244 *Exit:
245 *  return value = HRESULT
246 *    S_OK
247 *    E_OUTOFMEMORY
248 *
249 *  *pbstrOut = the newly allocated BSTR
250 *
251 ***********************************************************************/
252 extern "C" HRESULT
253 ErrSysAllocString(const OLECHAR FAR* psz, BSTR FAR* pbstrOut)
254 {
255     if(psz == NULL){
256       *pbstrOut = NULL;
257       return NOERROR;
258     }
259
260     if((*pbstrOut = SysAllocString(psz)) == NULL)
261       return E_OUTOFMEMORY;
262
263     return NOERROR;
264 }