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