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
15Abstract:
16
17 PALRT BSTR support
18
19Revision 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
31inline 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***********************************************************************/
74STDAPI_(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***********************************************************************/
119STDAPI_(BSTR) SysAllocString(const OLECHAR* psz)
120{
121 if(psz == NULL)
122 return NULL;
123
124 return SysAllocStringLen(psz, (DWORD)wcslen(psz));
125}
126
127STDAPI_(BSTR)
128SysAllocStringByteLen(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***********************************************************************/
171STDAPI_(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***********************************************************************/
190STDAPI_(unsigned int)
191SysStringLen(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***********************************************************************/
210STDAPI_(unsigned int)
211SysStringByteLen(BSTR bstr)
212{
213 if(bstr == NULL)
214 return 0;
215 return (unsigned int)(((DWORD FAR*)bstr)[-1]);
216}
217
218extern "C" HRESULT
219ErrStringCopy(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***********************************************************************/
252extern "C" HRESULT
253ErrSysAllocString(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}
265