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