/* * IAssemblyName implementation * * Copyright 2008 James Hawkins * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #define COBJMACROS #define INITGUID #include "windef.h" #include "winbase.h" #include "winuser.h" #include "ole2.h" #include "guiddef.h" #include "fusion.h" #include "corerror.h" #include "wine/debug.h" #include "wine/unicode.h" #include "fusionpriv.h" WINE_DEFAULT_DEBUG_CHANNEL(fusion); typedef struct { const IAssemblyNameVtbl *lpIAssemblyNameVtbl; LPWSTR displayname; LPWSTR name; LPWSTR culture; WORD version[4]; DWORD versize; BYTE pubkey[8]; BOOL haspubkey; LONG ref; } IAssemblyNameImpl; static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface, REFIID riid, LPVOID *ppobj) { IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface; TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj); *ppobj = NULL; if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAssemblyName)) { IUnknown_AddRef(iface); *ppobj = This; return S_OK; } WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj); return E_NOINTERFACE; } static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface) { IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface; ULONG refCount = InterlockedIncrement(&This->ref); TRACE("(%p)->(ref before = %u)\n", This, refCount - 1); return refCount; } static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface) { IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface; ULONG refCount = InterlockedDecrement(&This->ref); TRACE("(%p)->(ref before = %u)\n", This, refCount + 1); if (!refCount) { HeapFree(GetProcessHeap(), 0, This->displayname); HeapFree(GetProcessHeap(), 0, This->name); HeapFree(GetProcessHeap(), 0, This->culture); HeapFree(GetProcessHeap(), 0, This); } return refCount; } static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface, DWORD PropertyId, LPVOID pvProperty, DWORD cbProperty) { FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty); return E_NOTIMPL; } static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface, DWORD PropertyId, LPVOID pvProperty, LPDWORD pcbProperty) { IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface; TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty); *((LPWSTR)pvProperty) = '\0'; switch (PropertyId) { case ASM_NAME_NULL_PUBLIC_KEY: case ASM_NAME_NULL_PUBLIC_KEY_TOKEN: if (name->haspubkey) return S_OK; return S_FALSE; case ASM_NAME_NULL_CUSTOM: return S_OK; case ASM_NAME_NAME: *pcbProperty = 0; if (name->name) { lstrcpyW(pvProperty, name->name); *pcbProperty = (lstrlenW(name->name) + 1) * 2; } break; case ASM_NAME_MAJOR_VERSION: *pcbProperty = 0; *((WORD *)pvProperty) = name->version[0]; if (name->versize >= 1) *pcbProperty = sizeof(WORD); break; case ASM_NAME_MINOR_VERSION: *pcbProperty = 0; *((WORD *)pvProperty) = name->version[1]; if (name->versize >= 2) *pcbProperty = sizeof(WORD); break; case ASM_NAME_BUILD_NUMBER: *pcbProperty = 0; *((WORD *)pvProperty) = name->version[2]; if (name->versize >= 3) *pcbProperty = sizeof(WORD); break; case ASM_NAME_REVISION_NUMBER: *pcbProperty = 0; *((WORD *)pvProperty) = name->version[3]; if (name->versize >= 4) *pcbProperty = sizeof(WORD); break; case ASM_NAME_CULTURE: *pcbProperty = 0; if (name->culture) { lstrcpyW(pvProperty, name->culture); *pcbProperty = (lstrlenW(name->culture) + 1) * 2; } break; case ASM_NAME_PUBLIC_KEY_TOKEN: *pcbProperty = 0; if (name->haspubkey) { memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2); *pcbProperty = sizeof(DWORD) * 2; } break; default: *pcbProperty = 0; break; } return S_OK; } static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface) { FIXME("(%p) stub!\n", iface); return E_NOTIMPL; } static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface, LPOLESTR szDisplayName, LPDWORD pccDisplayName, DWORD dwDisplayFlags) { IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface; TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName, pccDisplayName, dwDisplayFlags); if (!name->displayname || !*name->displayname) return FUSION_E_INVALID_NAME; lstrcpyW(szDisplayName, name->displayname); *pccDisplayName = lstrlenW(szDisplayName) + 1; return S_OK; } static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface, REFIID refIID, IUnknown *pUnkReserved1, IUnknown *pUnkReserved2, LPCOLESTR szReserved, LONGLONG llReserved, LPVOID pvReserved, DWORD cbReserved, LPVOID *ppReserved) { TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface, debugstr_guid(refIID), pUnkReserved1, pUnkReserved2, debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved, pvReserved, cbReserved, ppReserved); return E_NOTIMPL; } static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface, LPDWORD lpcwBuffer, WCHAR *pwzName) { IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface; TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName); if (!name->name) { *pwzName = '\0'; *lpcwBuffer = 0; return S_OK; } lstrcpyW(pwzName, name->name); *lpcwBuffer = lstrlenW(pwzName) + 1; return S_OK; } static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface, LPDWORD pdwVersionHi, LPDWORD pdwVersionLow) { IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface; TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow); *pdwVersionHi = 0; *pdwVersionLow = 0; if (name->versize != 4) return FUSION_E_INVALID_NAME; *pdwVersionHi = (name->version[0] << 16) + name->version[1]; *pdwVersionLow = (name->version[2] << 16) + name->version[3]; return S_OK; } static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface, IAssemblyName *pName, DWORD dwCmpFlags) { FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags); return E_NOTIMPL; } static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface, IAssemblyName **pName) { FIXME("(%p, %p) stub!\n", iface, pName); return E_NOTIMPL; } static const IAssemblyNameVtbl AssemblyNameVtbl = { IAssemblyNameImpl_QueryInterface, IAssemblyNameImpl_AddRef, IAssemblyNameImpl_Release, IAssemblyNameImpl_SetProperty, IAssemblyNameImpl_GetProperty, IAssemblyNameImpl_Finalize, IAssemblyNameImpl_GetDisplayName, IAssemblyNameImpl_Reserved, IAssemblyNameImpl_GetName, IAssemblyNameImpl_GetVersion, IAssemblyNameImpl_IsEqual, IAssemblyNameImpl_Clone }; static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version) { LPWSTR beg, end; int i; for (i = 0, beg = version; i < 4; i++) { if (!*beg) return S_OK; end = strchrW(beg, '.'); if (end) *end = '\0'; name->version[i] = atolW(beg); name->versize++; if (!end && i < 3) return S_OK; beg = end + 1; } return S_OK; } static HRESULT parse_culture(IAssemblyNameImpl *name, LPWSTR culture) { static const WCHAR empty[] = {0}; if (lstrlenW(culture) == 2) name->culture = strdupW(culture); else name->culture = strdupW(empty); return S_OK; } #define CHARS_PER_PUBKEY 16 static BOOL is_hex(WCHAR c) { return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9')); } static BYTE hextobyte(WCHAR c) { if(c >= '0' && c <= '9') return c - '0'; if(c >= 'A' && c <= 'F') return c - 'A' + 10; if(c >= 'a' && c <= 'f') return c - 'a' + 10; return 0; } static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPWSTR pubkey) { int i; BYTE val; if (lstrlenW(pubkey) < CHARS_PER_PUBKEY) return FUSION_E_INVALID_NAME; for (i = 0; i < CHARS_PER_PUBKEY; i++) if (!is_hex(pubkey[i])) return FUSION_E_INVALID_NAME; name->haspubkey = TRUE; for (i = 0; i < CHARS_PER_PUBKEY; i += 2) { val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]); name->pubkey[i / 2] = val; } return S_OK; } static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName) { LPWSTR str, save; LPWSTR ptr, ptr2; HRESULT hr = S_OK; BOOL done = FALSE; static const WCHAR separator[] = {',',' ',0}; static const WCHAR version[] = {'V','e','r','s','i','o','n',0}; static const WCHAR culture[] = {'C','u','l','t','u','r','e',0}; static const WCHAR pubkey[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0}; if (!szAssemblyName) return S_OK; name->displayname = strdupW(szAssemblyName); if (!name->displayname) return E_OUTOFMEMORY; str = strdupW(szAssemblyName); save = str; if (!str) return E_OUTOFMEMORY; ptr = strstrW(str, separator); if (ptr) *ptr = '\0'; name->name = strdupW(str); if (!name->name) return E_OUTOFMEMORY; if (!ptr) goto done; str = ptr + 2; while (!done) { ptr = strchrW(str, '='); if (!ptr) { hr = FUSION_E_INVALID_NAME; goto done; } *(ptr++) = '\0'; if (!*ptr) { hr = FUSION_E_INVALID_NAME; goto done; } if (!(ptr2 = strstrW(ptr, separator))) { if (!(ptr2 = strchrW(ptr, '\0'))) { hr = FUSION_E_INVALID_NAME; goto done; } done = TRUE; } *ptr2 = '\0'; while (*str == ' ') str++; if (!lstrcmpW(str, version)) hr = parse_version(name, ptr); else if (!lstrcmpW(str, culture)) hr = parse_culture(name, ptr); else if (!lstrcmpW(str, pubkey)) hr = parse_pubkey(name, ptr); if (FAILED(hr)) goto done; str = ptr2 + 1; } done: HeapFree(GetProcessHeap(), 0, save); if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, name->displayname); HeapFree(GetProcessHeap(), 0, name->name); } return hr; } /****************************************************************** * CreateAssemblyNameObject (FUSION.@) */ HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj, LPCWSTR szAssemblyName, DWORD dwFlags, LPVOID pvReserved) { IAssemblyNameImpl *name; HRESULT hr; TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj, debugstr_w(szAssemblyName), dwFlags, pvReserved); if (!ppAssemblyNameObj) return E_INVALIDARG; if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) && (!szAssemblyName || !*szAssemblyName)) return E_INVALIDARG; name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl)); if (!name) return E_OUTOFMEMORY; name->lpIAssemblyNameVtbl = &AssemblyNameVtbl; name->ref = 1; hr = parse_display_name(name, szAssemblyName); if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, name); return hr; } *ppAssemblyNameObj = (IAssemblyName *)name; return S_OK; }