[PROPSYS]
[reactos.git] / reactos / dll / win32 / propsys / propvar.c
1 /*
2 * PropVariant implementation
3 *
4 * Copyright 2008 James Hawkins for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "propsys_private.h"
22
23 #include <stdio.h>
24 #include <winreg.h>
25 #include <oleauto.h>
26 #include <propvarutil.h>
27
28 static HRESULT PROPVAR_ConvertFILETIME(PROPVARIANT *ppropvarDest,
29 REFPROPVARIANT propvarSrc, VARTYPE vt)
30 {
31 SYSTEMTIME time;
32
33 FileTimeToSystemTime(&propvarSrc->u.filetime, &time);
34
35 switch (vt)
36 {
37 case VT_LPSTR:
38 {
39 static const char format[] = "%04d/%02d/%02d:%02d:%02d:%02d.%03d";
40
41 ppropvarDest->u.pszVal = HeapAlloc(GetProcessHeap(), 0,
42 lstrlenA(format) + 1);
43 if (!ppropvarDest->u.pszVal)
44 return E_OUTOFMEMORY;
45
46 sprintf(ppropvarDest->u.pszVal, format, time.wYear, time.wMonth,
47 time.wDay, time.wHour, time.wMinute,
48 time.wSecond, time.wMilliseconds);
49
50 return S_OK;
51 }
52
53 default:
54 FIXME("Unhandled target type: %d\n", vt);
55 }
56
57 return E_FAIL;
58 }
59
60 static HRESULT PROPVAR_ConvertNumber(REFPROPVARIANT pv, int dest_bits,
61 BOOL dest_signed, LONGLONG *res)
62 {
63 BOOL src_signed;
64
65 switch (pv->vt)
66 {
67 case VT_I1:
68 src_signed = TRUE;
69 *res = pv->u.cVal;
70 break;
71 case VT_UI1:
72 src_signed = FALSE;
73 *res = pv->u.bVal;
74 break;
75 case VT_I2:
76 src_signed = TRUE;
77 *res = pv->u.iVal;
78 break;
79 case VT_UI2:
80 src_signed = FALSE;
81 *res = pv->u.uiVal;
82 break;
83 case VT_I4:
84 src_signed = TRUE;
85 *res = pv->u.lVal;
86 break;
87 case VT_UI4:
88 src_signed = FALSE;
89 *res = pv->u.ulVal;
90 break;
91 case VT_I8:
92 src_signed = TRUE;
93 *res = pv->u.hVal.QuadPart;
94 break;
95 case VT_UI8:
96 src_signed = FALSE;
97 *res = pv->u.uhVal.QuadPart;
98 break;
99 case VT_EMPTY:
100 src_signed = FALSE;
101 *res = 0;
102 break;
103 default:
104 FIXME("unhandled vt %d\n", pv->vt);
105 return E_NOTIMPL;
106 }
107
108 if (*res < 0 && src_signed != dest_signed)
109 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
110
111 if (dest_bits < 64)
112 {
113 if (dest_signed)
114 {
115 if (*res >= ((LONGLONG)1 << (dest_bits-1)) ||
116 *res < ((LONGLONG)-1 << (dest_bits-1)))
117 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
118 }
119 else
120 {
121 if ((ULONGLONG)(*res) >= ((ULONGLONG)1 << dest_bits))
122 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
123 }
124 }
125
126 return S_OK;
127 }
128
129 HRESULT WINAPI PropVariantToInt16(REFPROPVARIANT propvarIn, SHORT *ret)
130 {
131 LONGLONG res;
132 HRESULT hr;
133
134 TRACE("%p,%p\n", propvarIn, ret);
135
136 hr = PROPVAR_ConvertNumber(propvarIn, 16, TRUE, &res);
137 if (SUCCEEDED(hr)) *ret = (SHORT)res;
138 return hr;
139 }
140
141 HRESULT WINAPI PropVariantToInt32(REFPROPVARIANT propvarIn, LONG *ret)
142 {
143 LONGLONG res;
144 HRESULT hr;
145
146 TRACE("%p,%p\n", propvarIn, ret);
147
148 hr = PROPVAR_ConvertNumber(propvarIn, 32, TRUE, &res);
149 if (SUCCEEDED(hr)) *ret = (LONG)res;
150 return hr;
151 }
152
153 HRESULT WINAPI PropVariantToInt64(REFPROPVARIANT propvarIn, LONGLONG *ret)
154 {
155 LONGLONG res;
156 HRESULT hr;
157
158 TRACE("%p,%p\n", propvarIn, ret);
159
160 hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
161 if (SUCCEEDED(hr)) *ret = (LONGLONG)res;
162 return hr;
163 }
164
165 HRESULT WINAPI PropVariantToUInt16(REFPROPVARIANT propvarIn, USHORT *ret)
166 {
167 LONGLONG res;
168 HRESULT hr;
169
170 TRACE("%p,%p\n", propvarIn, ret);
171
172 hr = PROPVAR_ConvertNumber(propvarIn, 16, FALSE, &res);
173 if (SUCCEEDED(hr)) *ret = (USHORT)res;
174 return hr;
175 }
176
177 HRESULT WINAPI PropVariantToUInt32(REFPROPVARIANT propvarIn, ULONG *ret)
178 {
179 LONGLONG res;
180 HRESULT hr;
181
182 TRACE("%p,%p\n", propvarIn, ret);
183
184 hr = PROPVAR_ConvertNumber(propvarIn, 32, FALSE, &res);
185 if (SUCCEEDED(hr)) *ret = (ULONG)res;
186 return hr;
187 }
188
189 HRESULT WINAPI PropVariantToUInt64(REFPROPVARIANT propvarIn, ULONGLONG *ret)
190 {
191 LONGLONG res;
192 HRESULT hr;
193
194 TRACE("%p,%p\n", propvarIn, ret);
195
196 hr = PROPVAR_ConvertNumber(propvarIn, 64, FALSE, &res);
197 if (SUCCEEDED(hr)) *ret = (ULONGLONG)res;
198 return hr;
199 }
200
201 /******************************************************************
202 * PropVariantChangeType (PROPSYS.@)
203 */
204 HRESULT WINAPI PropVariantChangeType(PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
205 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt)
206 {
207 HRESULT hr;
208
209 FIXME("(%p, %p, %d, %d, %d): semi-stub!\n", ppropvarDest, propvarSrc,
210 propvarSrc->vt, flags, vt);
211
212 switch (vt)
213 {
214 case VT_I2:
215 {
216 SHORT res;
217 hr = PropVariantToInt16(propvarSrc, &res);
218 if (SUCCEEDED(hr))
219 {
220 ppropvarDest->vt = VT_I2;
221 ppropvarDest->u.iVal = res;
222 }
223 return hr;
224 }
225 case VT_UI2:
226 {
227 USHORT res;
228 hr = PropVariantToUInt16(propvarSrc, &res);
229 if (SUCCEEDED(hr))
230 {
231 ppropvarDest->vt = VT_UI2;
232 ppropvarDest->u.uiVal = res;
233 }
234 return hr;
235 }
236 case VT_I4:
237 {
238 LONG res;
239 hr = PropVariantToInt32(propvarSrc, &res);
240 if (SUCCEEDED(hr))
241 {
242 ppropvarDest->vt = VT_I4;
243 ppropvarDest->u.lVal = res;
244 }
245 return hr;
246 }
247 case VT_UI4:
248 {
249 ULONG res;
250 hr = PropVariantToUInt32(propvarSrc, &res);
251 if (SUCCEEDED(hr))
252 {
253 ppropvarDest->vt = VT_UI4;
254 ppropvarDest->u.ulVal = res;
255 }
256 return hr;
257 }
258 case VT_I8:
259 {
260 LONGLONG res;
261 hr = PropVariantToInt64(propvarSrc, &res);
262 if (SUCCEEDED(hr))
263 {
264 ppropvarDest->vt = VT_I8;
265 ppropvarDest->u.hVal.QuadPart = res;
266 }
267 return hr;
268 }
269 case VT_UI8:
270 {
271 ULONGLONG res;
272 hr = PropVariantToUInt64(propvarSrc, &res);
273 if (SUCCEEDED(hr))
274 {
275 ppropvarDest->vt = VT_UI8;
276 ppropvarDest->u.uhVal.QuadPart = res;
277 }
278 return hr;
279 }
280 }
281
282 switch (propvarSrc->vt)
283 {
284 case VT_FILETIME:
285 return PROPVAR_ConvertFILETIME(ppropvarDest, propvarSrc, vt);
286 default:
287 FIXME("Unhandled source type: %d\n", propvarSrc->vt);
288 }
289
290 return E_FAIL;
291 }
292
293 static void PROPVAR_GUIDToWSTR(REFGUID guid, WCHAR *str)
294 {
295 static const WCHAR format[] = {'{','%','0','8','X','-','%','0','4','X','-','%','0','4','X',
296 '-','%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X',
297 '%','0','2','X','%','0','2','X','%','0','2','X','}',0};
298
299 sprintfW(str, format, guid->Data1, guid->Data2, guid->Data3,
300 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
301 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
302 }
303
304 HRESULT WINAPI InitPropVariantFromGUIDAsString(REFGUID guid, PROPVARIANT *ppropvar)
305 {
306 TRACE("(%p %p)\n", guid, ppropvar);
307
308 if(!guid)
309 return E_FAIL;
310
311 ppropvar->vt = VT_LPWSTR;
312 ppropvar->u.pwszVal = CoTaskMemAlloc(39*sizeof(WCHAR));
313 if(!ppropvar->u.pwszVal)
314 return E_OUTOFMEMORY;
315
316 PROPVAR_GUIDToWSTR(guid, ppropvar->u.pwszVal);
317 return S_OK;
318 }
319
320 HRESULT WINAPI InitVariantFromGUIDAsString(REFGUID guid, VARIANT *pvar)
321 {
322 TRACE("(%p %p)\n", guid, pvar);
323
324 if(!guid) {
325 FIXME("guid == NULL\n");
326 return E_FAIL;
327 }
328
329 V_VT(pvar) = VT_BSTR;
330 V_BSTR(pvar) = SysAllocStringLen(NULL, 38);
331 if(!V_BSTR(pvar))
332 return E_OUTOFMEMORY;
333
334 PROPVAR_GUIDToWSTR(guid, V_BSTR(pvar));
335 return S_OK;
336 }
337
338 HRESULT WINAPI InitPropVariantFromBuffer(const VOID *pv, UINT cb, PROPVARIANT *ppropvar)
339 {
340 TRACE("(%p %u %p)\n", pv, cb, ppropvar);
341
342 ppropvar->u.caub.pElems = CoTaskMemAlloc(cb);
343 if(!ppropvar->u.caub.pElems)
344 return E_OUTOFMEMORY;
345
346 ppropvar->vt = VT_VECTOR|VT_UI1;
347 ppropvar->u.caub.cElems = cb;
348 memcpy(ppropvar->u.caub.pElems, pv, cb);
349 return S_OK;
350 }
351
352 HRESULT WINAPI InitVariantFromBuffer(const VOID *pv, UINT cb, VARIANT *pvar)
353 {
354 SAFEARRAY *arr;
355 void *data;
356 HRESULT hres;
357
358 TRACE("(%p %u %p)\n", pv, cb, pvar);
359
360 arr = SafeArrayCreateVector(VT_UI1, 0, cb);
361 if(!arr)
362 return E_OUTOFMEMORY;
363
364 hres = SafeArrayAccessData(arr, &data);
365 if(FAILED(hres)) {
366 SafeArrayDestroy(arr);
367 return hres;
368 }
369
370 memcpy(data, pv, cb);
371
372 hres = SafeArrayUnaccessData(arr);
373 if(FAILED(hres)) {
374 SafeArrayDestroy(arr);
375 return hres;
376 }
377
378 V_VT(pvar) = VT_ARRAY|VT_UI1;
379 V_ARRAY(pvar) = arr;
380 return S_OK;
381 }
382
383 static inline DWORD PROPVAR_HexToNum(const WCHAR *hex)
384 {
385 DWORD ret;
386
387 if(hex[0]>='0' && hex[0]<='9')
388 ret = hex[0]-'0';
389 else if(hex[0]>='a' && hex[0]<='f')
390 ret = hex[0]-'a'+10;
391 else if(hex[0]>='A' && hex[0]<='F')
392 ret = hex[0]-'A'+10;
393 else
394 return -1;
395
396 ret <<= 4;
397 if(hex[1]>='0' && hex[1]<='9')
398 return ret + hex[1]-'0';
399 else if(hex[1]>='a' && hex[1]<='f')
400 return ret + hex[1]-'a'+10;
401 else if(hex[1]>='A' && hex[1]<='F')
402 return ret + hex[1]-'A'+10;
403 else
404 return -1;
405 }
406
407 static inline HRESULT PROPVAR_WCHARToGUID(const WCHAR *str, int len, GUID *guid)
408 {
409 DWORD i, val=0;
410 const WCHAR *p;
411
412 memset(guid, 0, sizeof(GUID));
413
414 if(len!=38 || str[0]!='{' || str[9]!='-' || str[14]!='-'
415 || str[19]!='-' || str[24]!='-' || str[37]!='}') {
416 WARN("Error parsing %s\n", debugstr_w(str));
417 return E_INVALIDARG;
418 }
419
420 p = str+1;
421 for(i=0; i<4 && val!=-1; i++) {
422 val = PROPVAR_HexToNum(p);
423 guid->Data1 = (guid->Data1<<8) + val;
424 p += 2;
425 }
426 p++;
427 for(i=0; i<2 && val!=-1; i++) {
428 val = PROPVAR_HexToNum(p);
429 guid->Data2 = (guid->Data2<<8) + val;
430 p += 2;
431 }
432 p++;
433 for(i=0; i<2 && val!=-1; i++) {
434 val = PROPVAR_HexToNum(p);
435 guid->Data3 = (guid->Data3<<8) + val;
436 p += 2;
437 }
438 p++;
439 for(i=0; i<8 && val!=-1; i++) {
440 if(i == 2)
441 p++;
442
443 val = guid->Data4[i] = PROPVAR_HexToNum(p);
444 p += 2;
445 }
446
447 if(val == -1) {
448 WARN("Error parsing %s\n", debugstr_w(str));
449 memset(guid, 0, sizeof(GUID));
450 return E_INVALIDARG;
451 }
452 return S_OK;
453 }
454
455 HRESULT WINAPI PropVariantToGUID(const PROPVARIANT *ppropvar, GUID *guid)
456 {
457 TRACE("%p %p)\n", ppropvar, guid);
458
459 switch(ppropvar->vt) {
460 case VT_BSTR:
461 return PROPVAR_WCHARToGUID(ppropvar->u.bstrVal, SysStringLen(ppropvar->u.bstrVal), guid);
462 case VT_LPWSTR:
463 return PROPVAR_WCHARToGUID(ppropvar->u.pwszVal, strlenW(ppropvar->u.pwszVal), guid);
464
465 default:
466 FIXME("unsupported vt: %d\n", ppropvar->vt);
467 return E_NOTIMPL;
468 }
469 }
470
471 HRESULT WINAPI VariantToGUID(const VARIANT *pvar, GUID *guid)
472 {
473 TRACE("(%p %p)\n", pvar, guid);
474
475 switch(V_VT(pvar)) {
476 case VT_BSTR: {
477 HRESULT hres = PROPVAR_WCHARToGUID(V_BSTR(pvar), SysStringLen(V_BSTR(pvar)), guid);
478 if(hres == E_INVALIDARG)
479 return E_FAIL;
480 return hres;
481 }
482
483 default:
484 FIXME("unsupported vt: %d\n", V_VT(pvar));
485 return E_NOTIMPL;
486 }
487 }
488
489 static BOOL isemptyornull(const PROPVARIANT *propvar)
490 {
491 if (propvar->vt == VT_EMPTY || propvar->vt == VT_NULL)
492 return TRUE;
493 if ((propvar->vt & VT_ARRAY) == VT_ARRAY)
494 {
495 int i;
496 for (i=0; i<propvar->u.parray->cDims; i++)
497 {
498 if (propvar->u.parray->rgsabound[i].cElements != 0)
499 break;
500 }
501 return i == propvar->u.parray->cDims;
502 }
503 /* FIXME: vectors, byrefs, errors? */
504 return FALSE;
505 }
506
507 INT WINAPI PropVariantCompareEx(REFPROPVARIANT propvar1, REFPROPVARIANT propvar2,
508 PROPVAR_COMPARE_UNIT unit, PROPVAR_COMPARE_FLAGS flags)
509 {
510 const PROPVARIANT *propvar2_converted;
511 PROPVARIANT propvar2_static;
512 HRESULT hr;
513 INT res=-1;
514
515 TRACE("%p,%p,%x,%x\n", propvar1, propvar2, unit, flags);
516
517 if (isemptyornull(propvar1))
518 {
519 if (isemptyornull(propvar2))
520 return 0;
521 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? 1 : -1;
522 }
523
524 if (isemptyornull(propvar2))
525 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? -1 : 1;
526
527 if (propvar1->vt != propvar2->vt)
528 {
529 hr = PropVariantChangeType(&propvar2_static, propvar2, 0, propvar1->vt);
530
531 if (FAILED(hr))
532 return -1;
533
534 propvar2_converted = &propvar2_static;
535 }
536 else
537 propvar2_converted = propvar2;
538
539 #define CMP_INT_VALUE(var) do { \
540 if (propvar1->u.var > propvar2_converted->u.var) \
541 res = 1; \
542 else if (propvar1->u.var < propvar2_converted->u.var) \
543 res = -1; \
544 else \
545 res = 0; \
546 } while (0)
547
548 switch (propvar1->vt)
549 {
550 case VT_I1:
551 CMP_INT_VALUE(cVal);
552 break;
553 case VT_UI1:
554 CMP_INT_VALUE(bVal);
555 break;
556 case VT_I2:
557 CMP_INT_VALUE(iVal);
558 break;
559 case VT_UI2:
560 CMP_INT_VALUE(uiVal);
561 break;
562 case VT_I4:
563 CMP_INT_VALUE(lVal);
564 break;
565 case VT_UI4:
566 CMP_INT_VALUE(uiVal);
567 break;
568 case VT_I8:
569 CMP_INT_VALUE(hVal.QuadPart);
570 break;
571 case VT_UI8:
572 CMP_INT_VALUE(uhVal.QuadPart);
573 break;
574 case VT_BSTR:
575 /* FIXME: Use string flags. */
576 res = lstrcmpW(propvar1->u.bstrVal, propvar2->u.bstrVal);
577 break;
578 default:
579 FIXME("vartype %d not handled\n", propvar1->vt);
580 res = -1;
581 break;
582 }
583
584 if (propvar2_converted == &propvar2_static)
585 PropVariantClear(&propvar2_static);
586
587 return res;
588 }