comctl32/monthcal: Copy SYSTEMTIME with a simple assignment.
[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
23 #define COBJMACROS
24 #define INITGUID
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "guiddef.h"
31 #include "fusion.h"
32 #include "corerror.h"
33
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "fusionpriv.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
39
40 typedef struct {
41     const IAssemblyNameVtbl *lpIAssemblyNameVtbl;
42
43     LPWSTR displayname;
44     LPWSTR name;
45     LPWSTR culture;
46
47     WORD version[4];
48     DWORD versize;
49
50     BYTE pubkey[8];
51     BOOL haspubkey;
52
53     LONG ref;
54 } IAssemblyNameImpl;
55
56 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
57                                                        REFIID riid, LPVOID *ppobj)
58 {
59     IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
60
61     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
62
63     *ppobj = NULL;
64
65     if (IsEqualIID(riid, &IID_IUnknown) ||
66         IsEqualIID(riid, &IID_IAssemblyName))
67     {
68         IUnknown_AddRef(iface);
69         *ppobj = This;
70         return S_OK;
71     }
72
73     WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
74     return E_NOINTERFACE;
75 }
76
77 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
78 {
79     IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
80     ULONG refCount = InterlockedIncrement(&This->ref);
81
82     TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
83
84     return refCount;
85 }
86
87 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
88 {
89     IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
90     ULONG refCount = InterlockedDecrement(&This->ref);
91
92     TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
93
94     if (!refCount)
95     {
96         HeapFree(GetProcessHeap(), 0, This->displayname);
97         HeapFree(GetProcessHeap(), 0, This->name);
98         HeapFree(GetProcessHeap(), 0, This->culture);
99         HeapFree(GetProcessHeap(), 0, This);
100     }
101
102     return refCount;
103 }
104
105 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
106                                                     DWORD PropertyId,
107                                                     LPVOID pvProperty,
108                                                     DWORD cbProperty)
109 {
110     FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
111     return E_NOTIMPL;
112 }
113
114 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
115                                                     DWORD PropertyId,
116                                                     LPVOID pvProperty,
117                                                     LPDWORD pcbProperty)
118 {
119     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
120
121     TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
122
123     *((LPWSTR)pvProperty) = '\0';
124
125     switch (PropertyId)
126     {
127         case ASM_NAME_NULL_PUBLIC_KEY:
128         case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
129             if (name->haspubkey)
130                 return S_OK;
131             return S_FALSE;
132
133         case ASM_NAME_NULL_CUSTOM:
134             return S_OK;
135
136         case ASM_NAME_NAME:
137             *pcbProperty = 0;
138             if (name->name)
139             {
140                 lstrcpyW(pvProperty, name->name);
141                 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
142             }
143             break;
144
145         case ASM_NAME_MAJOR_VERSION:
146             *pcbProperty = 0;
147             *((WORD *)pvProperty) = name->version[0];
148             if (name->versize >= 1)
149                 *pcbProperty = sizeof(WORD);
150             break;
151
152         case ASM_NAME_MINOR_VERSION:
153             *pcbProperty = 0;
154             *((WORD *)pvProperty) = name->version[1];
155             if (name->versize >= 2)
156                 *pcbProperty = sizeof(WORD);
157             break;
158
159         case ASM_NAME_BUILD_NUMBER:
160             *pcbProperty = 0;
161             *((WORD *)pvProperty) = name->version[2];
162             if (name->versize >= 3)
163                 *pcbProperty = sizeof(WORD);
164             break;
165
166         case ASM_NAME_REVISION_NUMBER:
167             *pcbProperty = 0;
168             *((WORD *)pvProperty) = name->version[3];
169             if (name->versize >= 4)
170                 *pcbProperty = sizeof(WORD);
171             break;
172
173         case ASM_NAME_CULTURE:
174             *pcbProperty = 0;
175             if (name->culture)
176             {
177                 lstrcpyW(pvProperty, name->culture);
178                 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
179             }
180             break;
181
182         case ASM_NAME_PUBLIC_KEY_TOKEN:
183             *pcbProperty = 0;
184             if (name->haspubkey)
185             {
186                 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
187                 *pcbProperty = sizeof(DWORD) * 2;
188             }
189             break;
190
191         default:
192             *pcbProperty = 0;
193             break;
194     }
195
196     return S_OK;
197 }
198
199 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
200 {
201     FIXME("(%p) stub!\n", iface);
202     return E_NOTIMPL;
203 }
204
205 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
206                                                        LPOLESTR szDisplayName,
207                                                        LPDWORD pccDisplayName,
208                                                        DWORD dwDisplayFlags)
209 {
210     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
211
212     TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
213           pccDisplayName, dwDisplayFlags);
214
215     if (!name->displayname || !*name->displayname)
216         return FUSION_E_INVALID_NAME;
217
218     lstrcpyW(szDisplayName, name->displayname);
219     *pccDisplayName = lstrlenW(szDisplayName) + 1;
220
221     return S_OK;
222 }
223
224 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
225                                                  REFIID refIID,
226                                                  IUnknown *pUnkReserved1,
227                                                  IUnknown *pUnkReserved2,
228                                                  LPCOLESTR szReserved,
229                                                  LONGLONG llReserved,
230                                                  LPVOID pvReserved,
231                                                  DWORD cbReserved,
232                                                  LPVOID *ppReserved)
233 {
234     TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
235           debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
236           debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
237           pvReserved, cbReserved, ppReserved);
238
239     return E_NOTIMPL;
240 }
241
242 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
243                                                 LPDWORD lpcwBuffer,
244                                                 WCHAR *pwzName)
245 {
246     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
247
248     TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
249
250     if (!name->name)
251     {
252         *pwzName = '\0';
253         *lpcwBuffer = 0;
254         return S_OK;
255     }
256
257     lstrcpyW(pwzName, name->name);
258     *lpcwBuffer = lstrlenW(pwzName) + 1;
259
260     return S_OK;
261 }
262
263 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
264                                                    LPDWORD pdwVersionHi,
265                                                    LPDWORD pdwVersionLow)
266 {
267     IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
268
269     TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
270
271     *pdwVersionHi = 0;
272     *pdwVersionLow = 0;
273
274     if (name->versize != 4)
275         return FUSION_E_INVALID_NAME;
276
277     *pdwVersionHi = (name->version[0] << 16) + name->version[1];
278     *pdwVersionLow = (name->version[2] << 16) + name->version[3];
279
280     return S_OK;
281 }
282
283 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
284                                                 IAssemblyName *pName,
285                                                 DWORD dwCmpFlags)
286 {
287     FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags);
288     return E_NOTIMPL;
289 }
290
291 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
292                                               IAssemblyName **pName)
293 {
294     FIXME("(%p, %p) stub!\n", iface, pName);
295     return E_NOTIMPL;
296 }
297
298 static const IAssemblyNameVtbl AssemblyNameVtbl = {
299     IAssemblyNameImpl_QueryInterface,
300     IAssemblyNameImpl_AddRef,
301     IAssemblyNameImpl_Release,
302     IAssemblyNameImpl_SetProperty,
303     IAssemblyNameImpl_GetProperty,
304     IAssemblyNameImpl_Finalize,
305     IAssemblyNameImpl_GetDisplayName,
306     IAssemblyNameImpl_Reserved,
307     IAssemblyNameImpl_GetName,
308     IAssemblyNameImpl_GetVersion,
309     IAssemblyNameImpl_IsEqual,
310     IAssemblyNameImpl_Clone
311 };
312
313 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
314 {
315     LPWSTR beg, end;
316     int i;
317
318     for (i = 0, beg = version; i < 4; i++)
319     {
320         if (!*beg)
321             return S_OK;
322
323         end = strchrW(beg, '.');
324
325         if (end) *end = '\0';
326         name->version[i] = atolW(beg);
327         name->versize++;
328
329         if (!end && i < 3)
330             return S_OK;
331
332         beg = end + 1;
333     }
334
335     return S_OK;
336 }
337
338 static HRESULT parse_culture(IAssemblyNameImpl *name, LPWSTR culture)
339 {
340     static const WCHAR empty[] = {0};
341
342     if (lstrlenW(culture) == 2)
343         name->culture = strdupW(culture);
344     else
345         name->culture = strdupW(empty);
346
347     return S_OK;
348 }
349
350 #define CHARS_PER_PUBKEY 16
351
352 static BOOL is_hex(WCHAR c)
353 {
354     return ((c >= 'a' && c <= 'f') ||
355             (c >= 'A' && c <= 'F') ||
356             (c >= '0' && c <= '9'));
357 }
358
359 static BYTE hextobyte(WCHAR c)
360 {
361     if(c >= '0' && c <= '9')
362         return c - '0';
363     if(c >= 'A' && c <= 'F')
364         return c - 'A' + 10;
365     if(c >= 'a' && c <= 'f')
366         return c - 'a' + 10;
367     return 0;
368 }
369
370 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPWSTR pubkey)
371 {
372     int i;
373     BYTE val;
374
375     if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
376         return FUSION_E_INVALID_NAME;
377
378     for (i = 0; i < CHARS_PER_PUBKEY; i++)
379         if (!is_hex(pubkey[i]))
380             return FUSION_E_INVALID_NAME;
381
382     name->haspubkey = TRUE;
383
384     for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
385     {
386         val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
387         name->pubkey[i / 2] = val;
388     }
389
390     return S_OK;
391 }
392
393 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
394 {
395     LPWSTR str, save;
396     LPWSTR ptr, ptr2;
397     HRESULT hr = S_OK;
398     BOOL done = FALSE;
399
400     static const WCHAR separator[] = {',',' ',0};
401     static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
402     static const WCHAR culture[] = {'C','u','l','t','u','r','e',0};
403     static const WCHAR pubkey[] =
404         {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
405
406     if (!szAssemblyName)
407         return S_OK;
408
409     name->displayname = strdupW(szAssemblyName);
410     if (!name->displayname)
411         return E_OUTOFMEMORY;
412
413     str = strdupW(szAssemblyName);
414     save = str;
415     if (!str)
416         return E_OUTOFMEMORY;
417
418     ptr = strstrW(str, separator);
419     if (ptr) *ptr = '\0';
420     name->name = strdupW(str);
421     if (!name->name)
422         return E_OUTOFMEMORY;
423
424     if (!ptr)
425         goto done;
426
427     str = ptr + 2;
428     while (!done)
429     {
430         ptr = strchrW(str, '=');
431         if (!ptr)
432         {
433             hr = FUSION_E_INVALID_NAME;
434             goto done;
435         }
436
437         *(ptr++) = '\0';
438         if (!*ptr)
439         {
440             hr = FUSION_E_INVALID_NAME;
441             goto done;
442         }
443
444         if (!(ptr2 = strstrW(ptr, separator)))
445         {
446             if (!(ptr2 = strchrW(ptr, '\0')))
447             {
448                 hr = FUSION_E_INVALID_NAME;
449                 goto done;
450             }
451
452             done = TRUE;
453         }
454
455         *ptr2 = '\0';
456
457         while (*str == ' ') str++;
458
459         if (!lstrcmpW(str, version))
460             hr = parse_version(name, ptr);
461         else if (!lstrcmpW(str, culture))
462             hr = parse_culture(name, ptr);
463         else if (!lstrcmpW(str, pubkey))
464             hr = parse_pubkey(name, ptr);
465
466         if (FAILED(hr))
467             goto done;
468
469         str = ptr2 + 1;
470     }
471
472 done:
473     HeapFree(GetProcessHeap(), 0, save);
474     return hr;
475 }
476
477 /******************************************************************
478  *  CreateAssemblyNameObject   (FUSION.@)
479  */
480 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
481                                         LPCWSTR szAssemblyName, DWORD dwFlags,
482                                         LPVOID pvReserved)
483 {
484     IAssemblyNameImpl *name;
485     HRESULT hr;
486
487     TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
488           debugstr_w(szAssemblyName), dwFlags, pvReserved);
489
490     if (!ppAssemblyNameObj)
491         return E_INVALIDARG;
492
493     if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
494         (!szAssemblyName || !*szAssemblyName))
495         return E_INVALIDARG;
496
497     name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
498     if (!name)
499         return E_OUTOFMEMORY;
500
501     name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
502     name->ref = 1;
503
504     hr = parse_display_name(name, szAssemblyName);
505     if (FAILED(hr))
506     {
507         HeapFree(GetProcessHeap(), 0, name);
508         return hr;
509     }
510
511     *ppAssemblyNameObj = (IAssemblyName *)name;
512
513     return S_OK;
514 }