wine/dlls/fusion/asmname.c

526 lines
14 KiB
C

/*
* 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 <stdarg.h>
#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"
WINE_DEFAULT_DEBUG_CHANNEL(fusion);
static inline LPWSTR strdupW(LPCWSTR src)
{
LPWSTR dest;
if (!src)
return NULL;
dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR));
if (dest)
lstrcpyW(dest, src);
return dest;
}
typedef struct {
const IAssemblyNameVtbl *lpIAssemblyNameVtbl;
LPWSTR displayname;
LPWSTR name;
LPWSTR culture;
BYTE 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((LPWSTR)pvProperty, name->name);
*pcbProperty = (lstrlenW(name->name) + 1) * 2;
}
break;
case ASM_NAME_MAJOR_VERSION:
*pcbProperty = 0;
*((LPDWORD)pvProperty) = name->version[0];
if (name->versize >= 1)
*pcbProperty = sizeof(WORD);
break;
case ASM_NAME_MINOR_VERSION:
*pcbProperty = 0;
*((LPDWORD)pvProperty) = name->version[1];
if (name->versize >= 2)
*pcbProperty = sizeof(WORD);
break;
case ASM_NAME_BUILD_NUMBER:
*pcbProperty = 0;
*((LPDWORD)pvProperty) = name->version[2];
if (name->versize >= 3)
*pcbProperty = sizeof(WORD);
break;
case ASM_NAME_REVISION_NUMBER:
*pcbProperty = 0;
*((LPDWORD)pvProperty) = name->version[3];
if (name->versize >= 4)
*pcbProperty = sizeof(WORD);
break;
case ASM_NAME_CULTURE:
*pcbProperty = 0;
if (name->culture)
{
lstrcpyW((LPWSTR)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, %s, %p, %d)\n", iface, debugstr_w(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';
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);
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;
}