* Sync to recent trunk (r52563).
[reactos.git] / dll / win32 / 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 }