ddrawex: Rename impl_from_dds3() to impl_from_IDirectDrawSurface3().
[wine] / dlls / fusion / asmname.c
1 /*
2  * IAssemblyName implementation
3  *
4  * Copyright 2008 James Hawkins
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 <stdarg.h>
22 #include <assert.h>
23
24 #define COBJMACROS
25 #define INITGUID
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "ole2.h"
31 #include "guiddef.h"
32 #include "fusion.h"
33 #include "corerror.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "fusionpriv.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
40
41 typedef struct {
42     const IAssemblyNameVtbl *lpIAssemblyNameVtbl;
43
44     LPWSTR path;
45
46     LPWSTR displayname;
47     LPWSTR name;
48     LPWSTR culture;
49     LPWSTR procarch;
50
51     WORD version[4];
52     DWORD versize;
53
54     BYTE pubkey[8];
55     BOOL haspubkey;
56
57     LONG ref;
58 } IAssemblyNameImpl;
59
60 static const WCHAR separator[] = {',',' ',0};
61 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
62 static const WCHAR culture[] = {'C','u','l','t','u','r','e',0};
63 static const WCHAR pubkey[] =
64     {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
65 static const WCHAR procarch[] = {'p','r','o','c','e','s','s','o','r',
66     'A','r','c','h','i','t','e','c','t','u','r','e',0};
67
68 #define CHARS_PER_PUBKEY 16
69
70 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
71                                                        REFIID riid, LPVOID *ppobj)
72 {
73     IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
74
75     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
76
77     *ppobj = NULL;
78
79     if (IsEqualIID(riid, &IID_IUnknown) ||
80         IsEqualIID(riid, &IID_IAssemblyName))
81     {
82         IUnknown_AddRef(iface);
83         *ppobj = This;
84         return S_OK;
85     }
86
87     WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
88     return E_NOINTERFACE;
89 }
90
91 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
92 {
93     IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
94     ULONG refCount = InterlockedIncrement(&This->ref);
95
96     TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
97
98     return refCount;
99 }
100
101 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
102 {
103     IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
104     ULONG refCount = InterlockedDecrement(&This->ref);
105
106     TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
107
108     if (!refCount)
109     {
110         HeapFree(GetProcessHeap(), 0, This->path);
111         HeapFree(GetProcessHeap(), 0, This->displayname);
112         HeapFree(GetProcessHeap(), 0, This->name);
113         HeapFree(GetProcessHeap(), 0, This->culture);
114         HeapFree(GetProcessHeap(), 0, This->procarch);
115         HeapFree(GetProcessHeap(), 0, This);
116     }
117
118     return refCount;
119 }
120
121 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
122                                                     DWORD PropertyId,
123                                                     LPVOID pvProperty,
124                                                     DWORD cbProperty)
125 {
126     FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
127     return E_NOTIMPL;
128 }
129
130 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
131                                                     DWORD PropertyId,
132                                                     LPVOID pvProperty,
133                                                     LPDWORD pcbProperty)
134 {
135     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
136
137     TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
138
139     *((LPWSTR)pvProperty) = '\0';
140
141     switch (PropertyId)
142     {
143         case ASM_NAME_NULL_PUBLIC_KEY:
144         case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
145             if (name->haspubkey)
146                 return S_OK;
147             return S_FALSE;
148
149         case ASM_NAME_NULL_CUSTOM:
150             return S_OK;
151
152         case ASM_NAME_NAME:
153             *pcbProperty = 0;
154             if (name->name)
155             {
156                 lstrcpyW(pvProperty, name->name);
157                 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
158             }
159             break;
160
161         case ASM_NAME_MAJOR_VERSION:
162             *pcbProperty = 0;
163             *((WORD *)pvProperty) = name->version[0];
164             if (name->versize >= 1)
165                 *pcbProperty = sizeof(WORD);
166             break;
167
168         case ASM_NAME_MINOR_VERSION:
169             *pcbProperty = 0;
170             *((WORD *)pvProperty) = name->version[1];
171             if (name->versize >= 2)
172                 *pcbProperty = sizeof(WORD);
173             break;
174
175         case ASM_NAME_BUILD_NUMBER:
176             *pcbProperty = 0;
177             *((WORD *)pvProperty) = name->version[2];
178             if (name->versize >= 3)
179                 *pcbProperty = sizeof(WORD);
180             break;
181
182         case ASM_NAME_REVISION_NUMBER:
183             *pcbProperty = 0;
184             *((WORD *)pvProperty) = name->version[3];
185             if (name->versize >= 4)
186                 *pcbProperty = sizeof(WORD);
187             break;
188
189         case ASM_NAME_CULTURE:
190             *pcbProperty = 0;
191             if (name->culture)
192             {
193                 lstrcpyW(pvProperty, name->culture);
194                 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
195             }
196             break;
197
198         case ASM_NAME_PUBLIC_KEY_TOKEN:
199             *pcbProperty = 0;
200             if (name->haspubkey)
201             {
202                 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
203                 *pcbProperty = sizeof(DWORD) * 2;
204             }
205             break;
206
207         default:
208             *pcbProperty = 0;
209             break;
210     }
211
212     return S_OK;
213 }
214
215 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
216 {
217     FIXME("(%p) stub!\n", iface);
218     return E_NOTIMPL;
219 }
220
221 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
222                                                        LPOLESTR szDisplayName,
223                                                        LPDWORD pccDisplayName,
224                                                        DWORD dwDisplayFlags)
225 {
226     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
227     WCHAR verstr[30];
228     DWORD size;
229     LPWSTR cultureval = 0;
230
231     static const WCHAR equals[] = {'=',0};
232
233     TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
234           pccDisplayName, dwDisplayFlags);
235
236     if (dwDisplayFlags == 0)
237     {
238         if (!name->displayname || !*name->displayname)
239             return FUSION_E_INVALID_NAME;
240
241         size = min(*pccDisplayName, lstrlenW(name->displayname) + 1);
242
243         lstrcpynW(szDisplayName, name->displayname, size);
244         *pccDisplayName = size;
245
246         return S_OK;
247     }
248
249     if (!name->name || !*name->name)
250         return FUSION_E_INVALID_NAME;
251
252     /* Verify buffer size is sufficient */
253     size = lstrlenW(name->name) + 1;
254
255     if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
256     {
257         static const WCHAR spec[] = {'%','d',0};
258         static const WCHAR period[] = {'.',0};
259         int i;
260
261         wsprintfW(verstr, spec, name->version[0]);
262
263         for (i = 1; i < name->versize; i++)
264         {
265             WCHAR value[6];
266             wsprintfW(value, spec, name->version[i]);
267
268             lstrcatW(verstr, period);
269             lstrcatW(verstr, value);
270         }
271
272         size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
273     }
274
275     if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
276     {
277         static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
278
279         cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
280         size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
281     }
282
283     if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
284         size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
285
286     if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
287         size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
288
289     if (size > *pccDisplayName)
290         return S_FALSE;
291
292     /* Construct the string */
293     lstrcpyW(szDisplayName, name->name);
294
295     if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
296     {
297         lstrcatW(szDisplayName, separator);
298
299         lstrcatW(szDisplayName, version);
300         lstrcatW(szDisplayName, equals);
301         lstrcatW(szDisplayName, verstr);
302     }
303
304     if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
305     {
306         lstrcatW(szDisplayName, separator);
307
308         lstrcatW(szDisplayName, culture);
309         lstrcatW(szDisplayName, equals);
310         lstrcatW(szDisplayName, cultureval);
311     }
312
313     if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
314     {
315         WCHAR pkt[CHARS_PER_PUBKEY + 1];
316         static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x',
317             '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
318
319         lstrcatW(szDisplayName, separator);
320
321         lstrcatW(szDisplayName, pubkey);
322         lstrcatW(szDisplayName, equals);
323
324         wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
325             name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
326             name->pubkey[7]);
327
328         lstrcatW(szDisplayName, pkt);
329     }
330
331     if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
332     {
333         lstrcatW(szDisplayName, separator);
334
335         lstrcatW(szDisplayName, procarch);
336         lstrcatW(szDisplayName, equals);
337         lstrcatW(szDisplayName, name->procarch);
338     }
339
340     *pccDisplayName = size;
341     return S_OK;
342 }
343
344 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
345                                                  REFIID refIID,
346                                                  IUnknown *pUnkReserved1,
347                                                  IUnknown *pUnkReserved2,
348                                                  LPCOLESTR szReserved,
349                                                  LONGLONG llReserved,
350                                                  LPVOID pvReserved,
351                                                  DWORD cbReserved,
352                                                  LPVOID *ppReserved)
353 {
354     TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
355           debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
356           debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
357           pvReserved, cbReserved, ppReserved);
358
359     return E_NOTIMPL;
360 }
361
362 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
363                                                 LPDWORD lpcwBuffer,
364                                                 WCHAR *pwzName)
365 {
366     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
367
368     TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
369
370     if (!name->name)
371     {
372         *pwzName = '\0';
373         *lpcwBuffer = 0;
374         return S_OK;
375     }
376
377     lstrcpyW(pwzName, name->name);
378     *lpcwBuffer = lstrlenW(pwzName) + 1;
379
380     return S_OK;
381 }
382
383 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
384                                                    LPDWORD pdwVersionHi,
385                                                    LPDWORD pdwVersionLow)
386 {
387     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
388
389     TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
390
391     *pdwVersionHi = 0;
392     *pdwVersionLow = 0;
393
394     if (name->versize != 4)
395         return FUSION_E_INVALID_NAME;
396
397     *pdwVersionHi = (name->version[0] << 16) + name->version[1];
398     *pdwVersionLow = (name->version[2] << 16) + name->version[3];
399
400     return S_OK;
401 }
402
403 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
404                                                 IAssemblyName *pName,
405                                                 DWORD dwCmpFlags)
406 {
407     FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags);
408     return E_NOTIMPL;
409 }
410
411 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
412                                               IAssemblyName **pName)
413 {
414     FIXME("(%p, %p) stub!\n", iface, pName);
415     return E_NOTIMPL;
416 }
417
418 static const IAssemblyNameVtbl AssemblyNameVtbl = {
419     IAssemblyNameImpl_QueryInterface,
420     IAssemblyNameImpl_AddRef,
421     IAssemblyNameImpl_Release,
422     IAssemblyNameImpl_SetProperty,
423     IAssemblyNameImpl_GetProperty,
424     IAssemblyNameImpl_Finalize,
425     IAssemblyNameImpl_GetDisplayName,
426     IAssemblyNameImpl_Reserved,
427     IAssemblyNameImpl_GetName,
428     IAssemblyNameImpl_GetVersion,
429     IAssemblyNameImpl_IsEqual,
430     IAssemblyNameImpl_Clone
431 };
432
433 /* Internal methods */
434 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
435 {
436     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
437
438     assert(name->lpIAssemblyNameVtbl == &AssemblyNameVtbl);
439
440     name->path = strdupW(path);
441     if (!name->path)
442         return E_OUTOFMEMORY;
443
444     return S_OK;
445 }
446
447 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
448 {
449     ULONG buffer_size = *len;
450     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
451
452     assert(name->lpIAssemblyNameVtbl == &AssemblyNameVtbl);
453
454     if (!name->path)
455         return S_OK;
456
457     if (!buf)
458         buffer_size = 0;
459
460     *len = lstrlenW(name->path) + 1;
461
462     if (*len <= buffer_size)
463         lstrcpyW(buf, name->path);
464     else
465         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
466
467     return S_OK;
468 }
469
470 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
471 {
472     LPWSTR beg, end;
473     int i;
474
475     for (i = 0, beg = version; i < 4; i++)
476     {
477         if (!*beg)
478             return S_OK;
479
480         end = strchrW(beg, '.');
481
482         if (end) *end = '\0';
483         name->version[i] = atolW(beg);
484         name->versize++;
485
486         if (!end && i < 3)
487             return S_OK;
488
489         beg = end + 1;
490     }
491
492     return S_OK;
493 }
494
495 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
496 {
497     static const WCHAR empty[] = {0};
498
499     if (lstrlenW(culture) == 2)
500         name->culture = strdupW(culture);
501     else
502         name->culture = strdupW(empty);
503
504     return S_OK;
505 }
506
507 static BOOL is_hex(WCHAR c)
508 {
509     return ((c >= 'a' && c <= 'f') ||
510             (c >= 'A' && c <= 'F') ||
511             (c >= '0' && c <= '9'));
512 }
513
514 static BYTE hextobyte(WCHAR c)
515 {
516     if(c >= '0' && c <= '9')
517         return c - '0';
518     if(c >= 'A' && c <= 'F')
519         return c - 'A' + 10;
520     if(c >= 'a' && c <= 'f')
521         return c - 'a' + 10;
522     return 0;
523 }
524
525 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
526 {
527     int i;
528     BYTE val;
529
530     if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
531         return FUSION_E_INVALID_NAME;
532
533     for (i = 0; i < CHARS_PER_PUBKEY; i++)
534         if (!is_hex(pubkey[i]))
535             return FUSION_E_INVALID_NAME;
536
537     name->haspubkey = TRUE;
538
539     for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
540     {
541         val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
542         name->pubkey[i / 2] = val;
543     }
544
545     return S_OK;
546 }
547
548 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
549 {
550     LPWSTR str, save;
551     LPWSTR ptr, ptr2;
552     HRESULT hr = S_OK;
553     BOOL done = FALSE;
554
555     if (!szAssemblyName)
556         return S_OK;
557
558     name->displayname = strdupW(szAssemblyName);
559     if (!name->displayname)
560         return E_OUTOFMEMORY;
561
562     str = strdupW(szAssemblyName);
563     save = str;
564     if (!str)
565     {
566         hr = E_OUTOFMEMORY;
567         goto done;
568     }
569
570     ptr = strchrW(str, ',');
571     if (ptr) *ptr = '\0';
572
573     /* no ',' but ' ' only */
574     if( !ptr && strchrW(str, ' ') )
575     {
576         hr = FUSION_E_INVALID_NAME;
577         goto done;
578     }
579
580     name->name = strdupW(str);
581     if (!name->name)
582     {
583         hr = E_OUTOFMEMORY;
584         goto done;
585     }
586
587     if (!ptr)
588         goto done;
589
590     str = ptr + 2;
591     while (!done)
592     {
593         ptr = strchrW(str, '=');
594         if (!ptr)
595         {
596             hr = FUSION_E_INVALID_NAME;
597             goto done;
598         }
599
600         *(ptr++) = '\0';
601         if (!*ptr)
602         {
603             hr = FUSION_E_INVALID_NAME;
604             goto done;
605         }
606
607         if (!(ptr2 = strstrW(ptr, separator)))
608         {
609             if (!(ptr2 = strchrW(ptr, '\0')))
610             {
611                 hr = FUSION_E_INVALID_NAME;
612                 goto done;
613             }
614
615             done = TRUE;
616         }
617
618         *ptr2 = '\0';
619
620         while (*str == ' ') str++;
621
622         if (!lstrcmpW(str, version))
623             hr = parse_version(name, ptr);
624         else if (!lstrcmpW(str, culture))
625             hr = parse_culture(name, ptr);
626         else if (!lstrcmpW(str, pubkey))
627             hr = parse_pubkey(name, ptr);
628         else if (!lstrcmpW(str, procarch))
629         {
630             name->procarch = strdupW(ptr);
631             if (!name->procarch)
632                 hr = E_OUTOFMEMORY;
633         }
634
635         if (FAILED(hr))
636             goto done;
637
638         str = ptr2 + 1;
639     }
640
641 done:
642     HeapFree(GetProcessHeap(), 0, save);
643     if (FAILED(hr))
644     {
645         HeapFree(GetProcessHeap(), 0, name->displayname);
646         HeapFree(GetProcessHeap(), 0, name->name);
647     }
648     return hr;
649 }
650
651 /******************************************************************
652  *  CreateAssemblyNameObject   (FUSION.@)
653  */
654 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
655                                         LPCWSTR szAssemblyName, DWORD dwFlags,
656                                         LPVOID pvReserved)
657 {
658     IAssemblyNameImpl *name;
659     HRESULT hr;
660
661     TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
662           debugstr_w(szAssemblyName), dwFlags, pvReserved);
663
664     if (!ppAssemblyNameObj)
665         return E_INVALIDARG;
666
667     if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
668         (!szAssemblyName || !*szAssemblyName))
669         return E_INVALIDARG;
670
671     name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
672     if (!name)
673         return E_OUTOFMEMORY;
674
675     name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
676     name->ref = 1;
677
678     hr = parse_display_name(name, szAssemblyName);
679     if (FAILED(hr))
680     {
681         HeapFree(GetProcessHeap(), 0, name);
682         return hr;
683     }
684
685     *ppAssemblyNameObj = (IAssemblyName *)name;
686
687     return S_OK;
688 }