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