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