Visual C++ backend for rbuild (for now just a hacked mingw backend) and related compi...
[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
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((LPWSTR)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((LPWSTR)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 }