Sync with trunk 48067
[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
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 if (FAILED(hr))
475 {
476 HeapFree(GetProcessHeap(), 0, name->displayname);
477 HeapFree(GetProcessHeap(), 0, name->name);
478 }
479 return hr;
480 }
481
482 /******************************************************************
483 * CreateAssemblyNameObject (FUSION.@)
484 */
485 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
486 LPCWSTR szAssemblyName, DWORD dwFlags,
487 LPVOID pvReserved)
488 {
489 IAssemblyNameImpl *name;
490 HRESULT hr;
491
492 TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
493 debugstr_w(szAssemblyName), dwFlags, pvReserved);
494
495 if (!ppAssemblyNameObj)
496 return E_INVALIDARG;
497
498 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
499 (!szAssemblyName || !*szAssemblyName))
500 return E_INVALIDARG;
501
502 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
503 if (!name)
504 return E_OUTOFMEMORY;
505
506 name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
507 name->ref = 1;
508
509 hr = parse_display_name(name, szAssemblyName);
510 if (FAILED(hr))
511 {
512 HeapFree(GetProcessHeap(), 0, name);
513 return hr;
514 }
515
516 *ppAssemblyNameObj = (IAssemblyName *)name;
517
518 return S_OK;
519 }