xref: /reactos/dll/win32/propsys/propvar.c (revision a93b822d)
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 
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #define NONAMELESSUNION
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #include "shlobj.h"
34 #include "propvarutil.h"
35 #include "strsafe.h"
36 
37 #include "wine/debug.h"
38 
39 WINE_DEFAULT_DEBUG_CHANNEL(propsys);
40 
PROPVAR_ConvertFILETIME(const FILETIME * ft,PROPVARIANT * ppropvarDest,VARTYPE vt)41 static HRESULT PROPVAR_ConvertFILETIME(const FILETIME *ft, PROPVARIANT *ppropvarDest, VARTYPE vt)
42 {
43     SYSTEMTIME time;
44 
45     FileTimeToSystemTime(ft, &time);
46 
47     switch (vt)
48     {
49         case VT_LPSTR:
50             ppropvarDest->u.pszVal = HeapAlloc(GetProcessHeap(), 0, 64);
51             if (!ppropvarDest->u.pszVal)
52                 return E_OUTOFMEMORY;
53 
54             sprintf( ppropvarDest->u.pszVal, "%04d/%02d/%02d:%02d:%02d:%02d.%03d",
55                       time.wYear, time.wMonth, time.wDay,
56                       time.wHour, time.wMinute, time.wSecond,
57                       time.wMilliseconds );
58 
59             return S_OK;
60 
61         default:
62             FIXME("Unhandled target type: %d\n", vt);
63     }
64 
65     return E_FAIL;
66 }
67 
PROPVAR_ConvertNumber(REFPROPVARIANT pv,int dest_bits,BOOL dest_signed,LONGLONG * res)68 static HRESULT PROPVAR_ConvertNumber(REFPROPVARIANT pv, int dest_bits,
69                                      BOOL dest_signed, LONGLONG *res)
70 {
71     BOOL src_signed;
72 
73     switch (pv->vt)
74     {
75     case VT_I1:
76         src_signed = TRUE;
77         *res = pv->u.cVal;
78         break;
79     case VT_UI1:
80         src_signed = FALSE;
81         *res = pv->u.bVal;
82         break;
83     case VT_I2:
84         src_signed = TRUE;
85         *res = pv->u.iVal;
86         break;
87     case VT_UI2:
88         src_signed = FALSE;
89         *res = pv->u.uiVal;
90         break;
91     case VT_I4:
92         src_signed = TRUE;
93         *res = pv->u.lVal;
94         break;
95     case VT_UI4:
96         src_signed = FALSE;
97         *res = pv->u.ulVal;
98         break;
99     case VT_I8:
100         src_signed = TRUE;
101         *res = pv->u.hVal.QuadPart;
102         break;
103     case VT_UI8:
104         src_signed = FALSE;
105         *res = pv->u.uhVal.QuadPart;
106         break;
107     case VT_EMPTY:
108         src_signed = FALSE;
109         *res = 0;
110         break;
111     case VT_LPSTR:
112     {
113         char *end;
114         *res = _strtoi64(pv->u.pszVal, &end, 0);
115         if (pv->u.pszVal == end)
116             return DISP_E_TYPEMISMATCH;
117         src_signed = *res < 0;
118         break;
119     }
120     case VT_LPWSTR:
121     case VT_BSTR:
122     {
123         WCHAR *end;
124         *res = wcstol(pv->u.pwszVal, &end, 0);
125         if (pv->u.pwszVal == end)
126             return DISP_E_TYPEMISMATCH;
127         src_signed = *res < 0;
128         break;
129     }
130     case VT_R8:
131     {
132         src_signed = TRUE;
133         *res = pv->u.dblVal;
134         break;
135     }
136     default:
137         FIXME("unhandled vt %d\n", pv->vt);
138         return E_NOTIMPL;
139     }
140 
141     if (*res < 0 && src_signed != dest_signed)
142         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
143 
144     if (dest_bits < 64)
145     {
146         if (dest_signed)
147         {
148             if (*res >= ((LONGLONG)1 << (dest_bits-1)) ||
149                 *res < ((LONGLONG)-1 << (dest_bits-1)))
150                 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
151         }
152         else
153         {
154             if ((ULONGLONG)(*res) >= ((ULONGLONG)1 << dest_bits))
155                 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
156         }
157     }
158 
159     return S_OK;
160 }
161 
PropVariantToDouble(REFPROPVARIANT propvarIn,double * ret)162 HRESULT WINAPI PropVariantToDouble(REFPROPVARIANT propvarIn, double *ret)
163 {
164     LONGLONG res;
165     HRESULT hr;
166 
167     TRACE("(%p, %p)\n", propvarIn, ret);
168 
169     hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
170     if (SUCCEEDED(hr)) *ret = (double)res;
171     return hr;
172 }
173 
PropVariantToInt16(REFPROPVARIANT propvarIn,SHORT * ret)174 HRESULT WINAPI PropVariantToInt16(REFPROPVARIANT propvarIn, SHORT *ret)
175 {
176     LONGLONG res;
177     HRESULT hr;
178 
179     TRACE("%p,%p\n", propvarIn, ret);
180 
181     hr = PROPVAR_ConvertNumber(propvarIn, 16, TRUE, &res);
182     if (SUCCEEDED(hr)) *ret = (SHORT)res;
183     return hr;
184 }
185 
PropVariantToInt32(REFPROPVARIANT propvarIn,LONG * ret)186 HRESULT WINAPI PropVariantToInt32(REFPROPVARIANT propvarIn, LONG *ret)
187 {
188     LONGLONG res;
189     HRESULT hr;
190 
191     TRACE("%p,%p\n", propvarIn, ret);
192 
193     hr = PROPVAR_ConvertNumber(propvarIn, 32, TRUE, &res);
194     if (SUCCEEDED(hr)) *ret = (LONG)res;
195     return hr;
196 }
197 
PropVariantToInt64(REFPROPVARIANT propvarIn,LONGLONG * ret)198 HRESULT WINAPI PropVariantToInt64(REFPROPVARIANT propvarIn, LONGLONG *ret)
199 {
200     LONGLONG res;
201     HRESULT hr;
202 
203     TRACE("%p,%p\n", propvarIn, ret);
204 
205     hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
206     if (SUCCEEDED(hr)) *ret = res;
207     return hr;
208 }
209 
PropVariantToUInt16(REFPROPVARIANT propvarIn,USHORT * ret)210 HRESULT WINAPI PropVariantToUInt16(REFPROPVARIANT propvarIn, USHORT *ret)
211 {
212     LONGLONG res;
213     HRESULT hr;
214 
215     TRACE("%p,%p\n", propvarIn, ret);
216 
217     hr = PROPVAR_ConvertNumber(propvarIn, 16, FALSE, &res);
218     if (SUCCEEDED(hr)) *ret = (USHORT)res;
219     return hr;
220 }
221 
PropVariantToUInt32(REFPROPVARIANT propvarIn,ULONG * ret)222 HRESULT WINAPI PropVariantToUInt32(REFPROPVARIANT propvarIn, ULONG *ret)
223 {
224     LONGLONG res;
225     HRESULT hr;
226 
227     TRACE("%p,%p\n", propvarIn, ret);
228 
229     hr = PROPVAR_ConvertNumber(propvarIn, 32, FALSE, &res);
230     if (SUCCEEDED(hr)) *ret = (ULONG)res;
231     return hr;
232 }
233 
PropVariantToUInt64(REFPROPVARIANT propvarIn,ULONGLONG * ret)234 HRESULT WINAPI PropVariantToUInt64(REFPROPVARIANT propvarIn, ULONGLONG *ret)
235 {
236     LONGLONG res;
237     HRESULT hr;
238 
239     TRACE("%p,%p\n", propvarIn, ret);
240 
241     hr = PROPVAR_ConvertNumber(propvarIn, 64, FALSE, &res);
242     if (SUCCEEDED(hr)) *ret = (ULONGLONG)res;
243     return hr;
244 }
245 
PropVariantToBoolean(REFPROPVARIANT propvarIn,BOOL * ret)246 HRESULT WINAPI PropVariantToBoolean(REFPROPVARIANT propvarIn, BOOL *ret)
247 {
248     static const WCHAR trueW[] = {'t','r','u','e',0};
249     static const WCHAR falseW[] = {'f','a','l','s','e',0};
250     static const WCHAR true2W[] = {'#','T','R','U','E','#',0};
251     static const WCHAR false2W[] = {'#','F','A','L','S','E','#',0};
252     LONGLONG res;
253     HRESULT hr;
254 
255     TRACE("%p,%p\n", propvarIn, ret);
256 
257     *ret = FALSE;
258 
259     switch (propvarIn->vt)
260     {
261         case VT_BOOL:
262             *ret = propvarIn->u.boolVal == VARIANT_TRUE;
263             return S_OK;
264 
265         case VT_LPWSTR:
266         case VT_BSTR:
267             if (!propvarIn->u.pwszVal)
268                 return DISP_E_TYPEMISMATCH;
269 
270             if (!lstrcmpiW(propvarIn->u.pwszVal, trueW) || !lstrcmpW(propvarIn->u.pwszVal, true2W))
271             {
272                 *ret = TRUE;
273                 return S_OK;
274             }
275 
276             if (!lstrcmpiW(propvarIn->u.pwszVal, falseW) || !lstrcmpW(propvarIn->u.pwszVal, false2W))
277             {
278                 *ret = FALSE;
279                 return S_OK;
280             }
281             break;
282 
283          case VT_LPSTR:
284             if (!propvarIn->u.pszVal)
285                 return DISP_E_TYPEMISMATCH;
286 
287             if (!lstrcmpiA(propvarIn->u.pszVal, "true") || !lstrcmpA(propvarIn->u.pszVal, "#TRUE#"))
288             {
289                 *ret = TRUE;
290                 return S_OK;
291             }
292 
293             if (!lstrcmpiA(propvarIn->u.pszVal, "false") || !lstrcmpA(propvarIn->u.pszVal, "#FALSE#"))
294             {
295                 *ret = FALSE;
296                 return S_OK;
297             }
298             break;
299     }
300 
301     hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
302     *ret = !!res;
303     return hr;
304 }
305 
PropVariantToBuffer(REFPROPVARIANT propvarIn,void * ret,UINT cb)306 HRESULT WINAPI PropVariantToBuffer(REFPROPVARIANT propvarIn, void *ret, UINT cb)
307 {
308     HRESULT hr = S_OK;
309 
310     TRACE("(%p, %p, %d)\n", propvarIn, ret, cb);
311 
312     switch(propvarIn->vt)
313     {
314         case VT_VECTOR|VT_UI1:
315             if(cb > propvarIn->u.caub.cElems)
316                 return E_FAIL;
317             memcpy(ret, propvarIn->u.caub.pElems, cb);
318             break;
319         case VT_ARRAY|VT_UI1:
320             FIXME("Unsupported type: VT_ARRAY|VT_UI1\n");
321             hr = E_NOTIMPL;
322             break;
323         default:
324             WARN("Unexpected type: %x\n", propvarIn->vt);
325             hr = E_INVALIDARG;
326     }
327 
328     return hr;
329 }
330 
331 
PropVariantToString(REFPROPVARIANT propvarIn,PWSTR ret,UINT cch)332 HRESULT WINAPI PropVariantToString(REFPROPVARIANT propvarIn, PWSTR ret, UINT cch)
333 {
334     HRESULT hr;
335     WCHAR *stringW = NULL;
336 
337     TRACE("(%p, %p, %d)\n", propvarIn, ret, cch);
338 
339     ret[0] = '\0';
340 
341     if(!cch)
342         return E_INVALIDARG;
343 
344     hr = PropVariantToStringAlloc(propvarIn, &stringW);
345     if(SUCCEEDED(hr))
346     {
347         if(lstrlenW(stringW) >= cch)
348             hr = STRSAFE_E_INSUFFICIENT_BUFFER;
349         lstrcpynW(ret, stringW, cch);
350         CoTaskMemFree(stringW);
351     }
352 
353     return hr;
354 }
355 
PropVariantToStringAlloc(REFPROPVARIANT propvarIn,WCHAR ** ret)356 HRESULT WINAPI PropVariantToStringAlloc(REFPROPVARIANT propvarIn, WCHAR **ret)
357 {
358     WCHAR *res = NULL;
359     HRESULT hr = S_OK;
360 
361     TRACE("%p,%p semi-stub\n", propvarIn, ret);
362 
363     switch(propvarIn->vt)
364     {
365         case VT_EMPTY:
366         case VT_NULL:
367             res = CoTaskMemAlloc(1*sizeof(WCHAR));
368             res[0] = '\0';
369             break;
370 
371         case VT_LPSTR:
372             if(propvarIn->u.pszVal)
373             {
374                 DWORD len;
375 
376                 len = MultiByteToWideChar(CP_ACP, 0, propvarIn->u.pszVal, -1, NULL, 0);
377                 res = CoTaskMemAlloc(len*sizeof(WCHAR));
378                 if(!res)
379                     return E_OUTOFMEMORY;
380 
381                 MultiByteToWideChar(CP_ACP, 0, propvarIn->u.pszVal, -1, res, len);
382             }
383             break;
384 
385         case VT_LPWSTR:
386         case VT_BSTR:
387             if (propvarIn->u.pwszVal)
388             {
389                 DWORD size = (lstrlenW(propvarIn->u.pwszVal) + 1) * sizeof(WCHAR);
390                 res = CoTaskMemAlloc(size);
391                 if(!res) return E_OUTOFMEMORY;
392                 memcpy(res, propvarIn->u.pwszVal, size);
393             }
394             break;
395 
396         default:
397             FIXME("Unsupported conversion (%d)\n", propvarIn->vt);
398             hr = E_FAIL;
399             break;
400     }
401 
402     *ret = res;
403 
404     return hr;
405 }
406 
PropVariantToStringWithDefault(REFPROPVARIANT propvarIn,LPCWSTR pszDefault)407 PCWSTR WINAPI PropVariantToStringWithDefault(REFPROPVARIANT propvarIn, LPCWSTR pszDefault)
408 {
409     static const WCHAR str_empty[] = {0};
410     if (propvarIn->vt == VT_BSTR)
411     {
412         if (propvarIn->u.bstrVal == NULL)
413             return str_empty;
414 
415         return propvarIn->u.bstrVal;
416     }
417 
418     if (propvarIn->vt == VT_LPWSTR && propvarIn->u.pwszVal != NULL)
419         return propvarIn->u.pwszVal;
420 
421     return pszDefault;
422 }
423 
424 
425 /******************************************************************
426  *  PropVariantChangeType   (PROPSYS.@)
427  */
PropVariantChangeType(PROPVARIANT * ppropvarDest,REFPROPVARIANT propvarSrc,PROPVAR_CHANGE_FLAGS flags,VARTYPE vt)428 HRESULT WINAPI PropVariantChangeType(PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
429                                      PROPVAR_CHANGE_FLAGS flags, VARTYPE vt)
430 {
431     HRESULT hr;
432 
433     FIXME("(%p, %p, %d, %d, %d): semi-stub!\n", ppropvarDest, propvarSrc,
434           propvarSrc->vt, flags, vt);
435 
436     if (vt == propvarSrc->vt)
437         return PropVariantCopy(ppropvarDest, propvarSrc);
438 
439     if (propvarSrc->vt == VT_FILETIME)
440         return PROPVAR_ConvertFILETIME(&propvarSrc->u.filetime, ppropvarDest, vt);
441 
442     switch (vt)
443     {
444     case VT_I1:
445     {
446         LONGLONG res;
447 
448         hr = PROPVAR_ConvertNumber(propvarSrc, 8, TRUE, &res);
449         if (SUCCEEDED(hr))
450         {
451             ppropvarDest->vt = VT_I1;
452             ppropvarDest->u.cVal = (char)res;
453         }
454         return hr;
455     }
456 
457     case VT_UI1:
458     {
459         LONGLONG res;
460 
461         hr = PROPVAR_ConvertNumber(propvarSrc, 8, FALSE, &res);
462         if (SUCCEEDED(hr))
463         {
464             ppropvarDest->vt = VT_UI1;
465             ppropvarDest->u.bVal = (UCHAR)res;
466         }
467         return hr;
468     }
469 
470     case VT_I2:
471     {
472         SHORT res;
473         hr = PropVariantToInt16(propvarSrc, &res);
474         if (SUCCEEDED(hr))
475         {
476             ppropvarDest->vt = VT_I2;
477             ppropvarDest->u.iVal = res;
478         }
479         return hr;
480     }
481     case VT_UI2:
482     {
483         USHORT res;
484         hr = PropVariantToUInt16(propvarSrc, &res);
485         if (SUCCEEDED(hr))
486         {
487             ppropvarDest->vt = VT_UI2;
488             ppropvarDest->u.uiVal = res;
489         }
490         return hr;
491     }
492     case VT_I4:
493     {
494         LONG res;
495         hr = PropVariantToInt32(propvarSrc, &res);
496         if (SUCCEEDED(hr))
497         {
498             ppropvarDest->vt = VT_I4;
499             ppropvarDest->u.lVal = res;
500         }
501         return hr;
502     }
503     case VT_UI4:
504     {
505         ULONG res;
506         hr = PropVariantToUInt32(propvarSrc, &res);
507         if (SUCCEEDED(hr))
508         {
509             ppropvarDest->vt = VT_UI4;
510             ppropvarDest->u.ulVal = res;
511         }
512         return hr;
513     }
514     case VT_I8:
515     {
516         LONGLONG res;
517         hr = PropVariantToInt64(propvarSrc, &res);
518         if (SUCCEEDED(hr))
519         {
520             ppropvarDest->vt = VT_I8;
521             ppropvarDest->u.hVal.QuadPart = res;
522         }
523         return hr;
524     }
525     case VT_UI8:
526     {
527         ULONGLONG res;
528         hr = PropVariantToUInt64(propvarSrc, &res);
529         if (SUCCEEDED(hr))
530         {
531             ppropvarDest->vt = VT_UI8;
532             ppropvarDest->u.uhVal.QuadPart = res;
533         }
534         return hr;
535     }
536 
537     case VT_LPWSTR:
538     case VT_BSTR:
539     {
540         WCHAR *res;
541         hr = PropVariantToStringAlloc(propvarSrc, &res);
542         if (SUCCEEDED(hr))
543         {
544             ppropvarDest->vt = VT_LPWSTR;
545             ppropvarDest->u.pwszVal = res;
546         }
547         return hr;
548     }
549 
550     case VT_LPSTR:
551     {
552         WCHAR *resW;
553         hr = PropVariantToStringAlloc(propvarSrc, &resW);
554         if (SUCCEEDED(hr))
555         {
556             char *res;
557             DWORD len;
558 
559             len = WideCharToMultiByte(CP_ACP, 0, resW, -1, NULL, 0, NULL, NULL);
560             res = CoTaskMemAlloc(len);
561             if (res)
562             {
563                 WideCharToMultiByte(CP_ACP, 0, resW, -1, res, len, NULL, NULL);
564                 ppropvarDest->vt = VT_LPSTR;
565                 ppropvarDest->u.pszVal = res;
566             }
567             else
568                 hr = E_OUTOFMEMORY;
569 
570             CoTaskMemFree(resW);
571         }
572         return hr;
573     }
574 
575     default:
576         FIXME("Unhandled dest type: %d\n", vt);
577         return E_FAIL;
578     }
579 }
580 
PROPVAR_GUIDToWSTR(REFGUID guid,WCHAR * str)581 static void PROPVAR_GUIDToWSTR(REFGUID guid, WCHAR *str)
582 {
583     static const WCHAR format[] = {'{','%','0','8','X','-','%','0','4','X','-','%','0','4','X',
584         '-','%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X',
585         '%','0','2','X','%','0','2','X','%','0','2','X','}',0};
586 
587     swprintf(str, format, guid->Data1, guid->Data2, guid->Data3,
588             guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
589             guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
590 }
591 
InitPropVariantFromGUIDAsString(REFGUID guid,PROPVARIANT * ppropvar)592 HRESULT WINAPI InitPropVariantFromGUIDAsString(REFGUID guid, PROPVARIANT *ppropvar)
593 {
594     TRACE("(%p %p)\n", guid, ppropvar);
595 
596     if(!guid)
597         return E_FAIL;
598 
599     ppropvar->vt = VT_LPWSTR;
600     ppropvar->u.pwszVal = CoTaskMemAlloc(39*sizeof(WCHAR));
601     if(!ppropvar->u.pwszVal)
602         return E_OUTOFMEMORY;
603 
604     PROPVAR_GUIDToWSTR(guid, ppropvar->u.pwszVal);
605     return S_OK;
606 }
607 
InitVariantFromGUIDAsString(REFGUID guid,VARIANT * pvar)608 HRESULT WINAPI InitVariantFromGUIDAsString(REFGUID guid, VARIANT *pvar)
609 {
610     TRACE("(%p %p)\n", guid, pvar);
611 
612     if(!guid) {
613         FIXME("guid == NULL\n");
614         return E_FAIL;
615     }
616 
617     V_VT(pvar) = VT_BSTR;
618     V_BSTR(pvar) = SysAllocStringLen(NULL, 38);
619     if(!V_BSTR(pvar))
620         return E_OUTOFMEMORY;
621 
622     PROPVAR_GUIDToWSTR(guid, V_BSTR(pvar));
623     return S_OK;
624 }
625 
InitPropVariantFromBuffer(const VOID * pv,UINT cb,PROPVARIANT * ppropvar)626 HRESULT WINAPI InitPropVariantFromBuffer(const VOID *pv, UINT cb, PROPVARIANT *ppropvar)
627 {
628     TRACE("(%p %u %p)\n", pv, cb, ppropvar);
629 
630     ppropvar->u.caub.pElems = CoTaskMemAlloc(cb);
631     if(!ppropvar->u.caub.pElems)
632         return E_OUTOFMEMORY;
633 
634     ppropvar->vt = VT_VECTOR|VT_UI1;
635     ppropvar->u.caub.cElems = cb;
636     memcpy(ppropvar->u.caub.pElems, pv, cb);
637     return S_OK;
638 }
639 
InitPropVariantFromCLSID(REFCLSID clsid,PROPVARIANT * ppropvar)640 HRESULT WINAPI InitPropVariantFromCLSID(REFCLSID clsid, PROPVARIANT *ppropvar)
641 {
642     TRACE("(%s %p)\n", debugstr_guid(clsid), ppropvar);
643 
644     ppropvar->u.puuid = CoTaskMemAlloc(sizeof(*ppropvar->u.puuid));
645     if(!ppropvar->u.puuid)
646         return E_OUTOFMEMORY;
647 
648     ppropvar->vt = VT_CLSID;
649     memcpy(ppropvar->u.puuid, clsid, sizeof(*ppropvar->u.puuid));
650     return S_OK;
651 }
652 
InitVariantFromBuffer(const VOID * pv,UINT cb,VARIANT * pvar)653 HRESULT WINAPI InitVariantFromBuffer(const VOID *pv, UINT cb, VARIANT *pvar)
654 {
655     SAFEARRAY *arr;
656     void *data;
657     HRESULT hres;
658 
659     TRACE("(%p %u %p)\n", pv, cb, pvar);
660 
661     arr = SafeArrayCreateVector(VT_UI1, 0, cb);
662     if(!arr)
663         return E_OUTOFMEMORY;
664 
665     hres = SafeArrayAccessData(arr, &data);
666     if(FAILED(hres)) {
667         SafeArrayDestroy(arr);
668         return hres;
669     }
670 
671     memcpy(data, pv, cb);
672 
673     hres = SafeArrayUnaccessData(arr);
674     if(FAILED(hres)) {
675         SafeArrayDestroy(arr);
676         return hres;
677     }
678 
679     V_VT(pvar) = VT_ARRAY|VT_UI1;
680     V_ARRAY(pvar) = arr;
681     return S_OK;
682 }
683 
PROPVAR_HexToNum(const WCHAR * hex)684 static inline DWORD PROPVAR_HexToNum(const WCHAR *hex)
685 {
686     DWORD ret;
687 
688     if(hex[0]>='0' && hex[0]<='9')
689         ret = hex[0]-'0';
690     else if(hex[0]>='a' && hex[0]<='f')
691         ret = hex[0]-'a'+10;
692     else if(hex[0]>='A' && hex[0]<='F')
693         ret = hex[0]-'A'+10;
694     else
695         return -1;
696 
697     ret <<= 4;
698     if(hex[1]>='0' && hex[1]<='9')
699         return ret + hex[1]-'0';
700     else if(hex[1]>='a' && hex[1]<='f')
701         return ret + hex[1]-'a'+10;
702     else if(hex[1]>='A' && hex[1]<='F')
703         return ret + hex[1]-'A'+10;
704     else
705         return -1;
706 }
707 
PROPVAR_WCHARToGUID(const WCHAR * str,int len,GUID * guid)708 static inline HRESULT PROPVAR_WCHARToGUID(const WCHAR *str, int len, GUID *guid)
709 {
710     DWORD i, val=0;
711     const WCHAR *p;
712 
713     memset(guid, 0, sizeof(GUID));
714 
715     if(len!=38 || str[0]!='{' || str[9]!='-' || str[14]!='-'
716             || str[19]!='-' || str[24]!='-' || str[37]!='}') {
717         WARN("Error parsing %s\n", debugstr_w(str));
718         return E_INVALIDARG;
719     }
720 
721     p = str+1;
722     for(i=0; i<4 && val!=-1; i++) {
723         val = PROPVAR_HexToNum(p);
724         guid->Data1 = (guid->Data1<<8) + val;
725         p += 2;
726     }
727     p++;
728     for(i=0; i<2 && val!=-1; i++) {
729         val = PROPVAR_HexToNum(p);
730         guid->Data2 = (guid->Data2<<8) + val;
731         p += 2;
732     }
733     p++;
734     for(i=0; i<2 && val!=-1; i++) {
735         val = PROPVAR_HexToNum(p);
736         guid->Data3 = (guid->Data3<<8) + val;
737         p += 2;
738     }
739     p++;
740     for(i=0; i<8 && val!=-1; i++) {
741         if(i == 2)
742             p++;
743 
744         val = guid->Data4[i] = PROPVAR_HexToNum(p);
745         p += 2;
746     }
747 
748     if(val == -1) {
749         WARN("Error parsing %s\n", debugstr_w(str));
750         memset(guid, 0, sizeof(GUID));
751         return E_INVALIDARG;
752     }
753     return S_OK;
754 }
755 
PropVariantToGUID(const PROPVARIANT * ppropvar,GUID * guid)756 HRESULT WINAPI PropVariantToGUID(const PROPVARIANT *ppropvar, GUID *guid)
757 {
758     TRACE("%p %p)\n", ppropvar, guid);
759 
760     switch(ppropvar->vt) {
761     case VT_BSTR:
762         return PROPVAR_WCHARToGUID(ppropvar->u.bstrVal, SysStringLen(ppropvar->u.bstrVal), guid);
763     case VT_LPWSTR:
764         return PROPVAR_WCHARToGUID(ppropvar->u.pwszVal, lstrlenW(ppropvar->u.pwszVal), guid);
765     case VT_CLSID:
766         memcpy(guid, ppropvar->u.puuid, sizeof(*ppropvar->u.puuid));
767         return S_OK;
768 
769     default:
770         FIXME("unsupported vt: %d\n", ppropvar->vt);
771         return E_NOTIMPL;
772     }
773 }
774 
VariantToGUID(const VARIANT * pvar,GUID * guid)775 HRESULT WINAPI VariantToGUID(const VARIANT *pvar, GUID *guid)
776 {
777     TRACE("(%p %p)\n", pvar, guid);
778 
779     switch(V_VT(pvar)) {
780     case VT_BSTR: {
781         HRESULT hres = PROPVAR_WCHARToGUID(V_BSTR(pvar), SysStringLen(V_BSTR(pvar)), guid);
782         if(hres == E_INVALIDARG)
783             return E_FAIL;
784         return hres;
785     }
786 
787     default:
788         FIXME("unsupported vt: %d\n", V_VT(pvar));
789         return E_NOTIMPL;
790     }
791 }
792 
isemptyornull(const PROPVARIANT * propvar)793 static BOOL isemptyornull(const PROPVARIANT *propvar)
794 {
795     if (propvar->vt == VT_EMPTY || propvar->vt == VT_NULL)
796         return TRUE;
797     if ((propvar->vt & VT_ARRAY) == VT_ARRAY)
798     {
799         int i;
800         for (i=0; i<propvar->u.parray->cDims; i++)
801         {
802             if (propvar->u.parray->rgsabound[i].cElements != 0)
803                 break;
804         }
805         return i == propvar->u.parray->cDims;
806     }
807     if (propvar->vt == VT_CLSID)
808         return !propvar->u.puuid;
809 
810     /* FIXME: vectors, byrefs, errors? */
811     return FALSE;
812 }
813 
PropVariantCompareEx(REFPROPVARIANT propvar1,REFPROPVARIANT propvar2,PROPVAR_COMPARE_UNIT unit,PROPVAR_COMPARE_FLAGS flags)814 INT WINAPI PropVariantCompareEx(REFPROPVARIANT propvar1, REFPROPVARIANT propvar2,
815     PROPVAR_COMPARE_UNIT unit, PROPVAR_COMPARE_FLAGS flags)
816 {
817     const PROPVARIANT *propvar2_converted;
818     PROPVARIANT propvar2_static;
819     HRESULT hr;
820     INT res=-1;
821 
822     TRACE("%p,%p,%x,%x\n", propvar1, propvar2, unit, flags);
823 
824     if (isemptyornull(propvar1))
825     {
826         if (isemptyornull(propvar2))
827             return 0;
828         return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? 1 : -1;
829     }
830 
831     if (isemptyornull(propvar2))
832         return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? -1 : 1;
833 
834     if (propvar1->vt != propvar2->vt)
835     {
836         hr = PropVariantChangeType(&propvar2_static, propvar2, 0, propvar1->vt);
837 
838         if (FAILED(hr))
839             return -1;
840 
841         propvar2_converted = &propvar2_static;
842     }
843     else
844         propvar2_converted = propvar2;
845 
846 #define CMP_NUM_VALUE(var) do { \
847     if (propvar1->u.var > propvar2_converted->u.var) \
848         res = 1; \
849     else if (propvar1->u.var < propvar2_converted->u.var) \
850         res = -1; \
851     else \
852         res = 0; \
853     } while (0)
854 
855     switch (propvar1->vt)
856     {
857     case VT_I1:
858         CMP_NUM_VALUE(cVal);
859         break;
860     case VT_UI1:
861         CMP_NUM_VALUE(bVal);
862         break;
863     case VT_I2:
864         CMP_NUM_VALUE(iVal);
865         break;
866     case VT_UI2:
867         CMP_NUM_VALUE(uiVal);
868         break;
869     case VT_I4:
870         CMP_NUM_VALUE(lVal);
871         break;
872     case VT_UI4:
873         CMP_NUM_VALUE(uiVal);
874         break;
875     case VT_I8:
876         CMP_NUM_VALUE(hVal.QuadPart);
877         break;
878     case VT_UI8:
879         CMP_NUM_VALUE(uhVal.QuadPart);
880         break;
881     case VT_R4:
882         CMP_NUM_VALUE(fltVal);
883         break;
884     case VT_R8:
885         CMP_NUM_VALUE(dblVal);
886         break;
887     case VT_BSTR:
888     case VT_LPWSTR:
889         /* FIXME: Use other string flags. */
890         if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC))
891             res = lstrcmpiW(propvar1->u.bstrVal, propvar2_converted->u.bstrVal);
892         else
893             res = lstrcmpW(propvar1->u.bstrVal, propvar2_converted->u.bstrVal);
894         break;
895     case VT_LPSTR:
896         /* FIXME: Use other string flags. */
897         if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC))
898             res = lstrcmpiA(propvar1->u.pszVal, propvar2_converted->u.pszVal);
899         else
900             res = lstrcmpA(propvar1->u.pszVal, propvar2_converted->u.pszVal);
901         break;
902     case VT_CLSID:
903         res = memcmp(propvar1->u.puuid, propvar2->u.puuid, sizeof(*propvar1->u.puuid));
904         if (res) res = res > 0 ? 1 : -1;
905         break;
906     default:
907         FIXME("vartype %#x not handled\n", propvar1->vt);
908         res = -1;
909         break;
910     }
911 
912     if (propvar2_converted == &propvar2_static)
913         PropVariantClear(&propvar2_static);
914 
915     return res;
916 }
917