ole32: Handle optional WCHAR data when loading item moniker.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2019-12-13 13:06:56 +03:00 committed by Alexandre Julliard
parent 7a98b0527a
commit b676616700
2 changed files with 161 additions and 62 deletions

View file

@ -157,72 +157,106 @@ static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface)
return S_FALSE;
}
static HRESULT item_moniker_load_string_record(IStream *stream, WCHAR **ret)
{
DWORD str_len, read_len, lenW, i;
HRESULT hr = S_OK;
char *buffer;
WCHAR *str;
IStream_Read(stream, &str_len, sizeof(str_len), &read_len);
if (read_len != sizeof(str_len))
return E_FAIL;
if (!str_len)
{
heap_free(*ret);
*ret = NULL;
return S_OK;
}
if (!(buffer = heap_alloc(str_len)))
return E_OUTOFMEMORY;
IStream_Read(stream, buffer, str_len, &read_len);
if (read_len != str_len)
{
heap_free(buffer);
return E_FAIL;
}
/* Skip ansi buffer, it must be null terminated. */
i = 0;
while (i < str_len && buffer[i])
i++;
if (buffer[i])
{
WARN("Expected null terminated ansi name.\n");
hr = E_FAIL;
goto end;
}
if (i < str_len - 1)
{
str_len -= i + 1;
if (str_len % sizeof(WCHAR))
{
WARN("Unexpected Unicode name length %d.\n", str_len);
hr = E_FAIL;
goto end;
}
str = heap_alloc(str_len + sizeof(WCHAR));
if (str)
{
memcpy(str, &buffer[i + 1], str_len);
str[str_len / sizeof(WCHAR)] = 0;
}
}
else
{
lenW = MultiByteToWideChar(CP_ACP, 0, buffer, -1, NULL, 0);
str = heap_alloc(lenW * sizeof(WCHAR));
if (str)
MultiByteToWideChar(CP_ACP, 0, buffer, -1, str, lenW);
}
if (str)
{
heap_free(*ret);
*ret = str;
}
else
hr = E_OUTOFMEMORY;
end:
heap_free(buffer);
return hr;
}
/******************************************************************************
* ItemMoniker_Load
******************************************************************************/
static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm)
static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker *iface, IStream *stream)
{
ItemMonikerImpl *This = impl_from_IMoniker(iface);
HRESULT res;
DWORD delimiterLength,nameLength,lenW;
CHAR *itemNameA,*itemDelimiterA;
ULONG bread;
HRESULT hr;
TRACE("\n");
TRACE("(%p, %p)\n", iface, stream);
/* for more details about data read by this function see comments of ItemMonikerImpl_Save function */
/* Delimiter and name use the same record structure: 4 bytes byte-length field, followed by
string data. Data starts with single byte null-terminated string, WCHAR non-terminated
string optionally follows. Length of WCHAR string is determined as a difference between total
byte-length and single byte string length. */
/* read item delimiter string length + 1 */
res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread);
if (bread != sizeof(DWORD))
return E_FAIL;
hr = item_moniker_load_string_record(stream, &This->itemDelimiter);
if (SUCCEEDED(hr))
hr = item_moniker_load_string_record(stream, &This->itemName);
/* read item delimiter string */
if (!(itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength)))
return E_OUTOFMEMORY;
res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread);
if (bread != delimiterLength)
{
HeapFree( GetProcessHeap(), 0, itemDelimiterA );
return E_FAIL;
}
lenW = MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, NULL, 0 );
This->itemDelimiter=HeapReAlloc(GetProcessHeap(),0,This->itemDelimiter,lenW*sizeof(WCHAR));
if (!This->itemDelimiter)
{
HeapFree( GetProcessHeap(), 0, itemDelimiterA );
return E_OUTOFMEMORY;
}
MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, This->itemDelimiter, lenW );
HeapFree( GetProcessHeap(), 0, itemDelimiterA );
/* read item name string length + 1*/
res=IStream_Read(pStm,&nameLength,sizeof(DWORD),&bread);
if (bread != sizeof(DWORD))
return E_FAIL;
/* read item name string */
if (!(itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength)))
return E_OUTOFMEMORY;
res=IStream_Read(pStm,itemNameA,nameLength,&bread);
if (bread != nameLength)
{
HeapFree( GetProcessHeap(), 0, itemNameA );
return E_FAIL;
}
lenW = MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, NULL, 0 );
This->itemName=HeapReAlloc(GetProcessHeap(),0,This->itemName,lenW*sizeof(WCHAR));
if (!This->itemName)
{
HeapFree( GetProcessHeap(), 0, itemNameA );
return E_OUTOFMEMORY;
}
MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, This->itemName, lenW );
HeapFree( GetProcessHeap(), 0, itemNameA );
return res;
return hr;
}
/******************************************************************************

View file

@ -1674,9 +1674,37 @@ static void test_file_monikers(void)
static void test_item_moniker(void)
{
static const char item_moniker_unicode_delim_stream[] =
{
0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, '!',
0x00, 0x02, 0x00, 0x00, 0x00, 'A', 0x00,
};
static const char item_moniker_unicode_item_stream[] =
{
0x02, 0x00, 0x00, 0x00, '!', 0x00, 0x05, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 'B', 0x00,
};
static const char item_moniker_unicode_delim_item_stream[] =
{
0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, '!',
0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0x00, 'C', 0x00,
};
static struct
{
const char *data;
int data_len;
const WCHAR *display_name;
}
item_moniker_data[] =
{
{ item_moniker_unicode_delim_stream, sizeof(item_moniker_unicode_delim_stream), L"!A" },
{ item_moniker_unicode_item_stream, sizeof(item_moniker_unicode_item_stream), L"!B" },
{ item_moniker_unicode_delim_item_stream, sizeof(item_moniker_unicode_delim_item_stream), L"!C" },
};
IMoniker *moniker, *moniker2;
HRESULT hr;
IMoniker *moniker;
DWORD moniker_type;
DWORD moniker_type, i;
DWORD hash;
IBindCtx *bindctx;
IMoniker *inverse;
@ -1684,6 +1712,9 @@ static void test_item_moniker(void)
static const WCHAR wszDelimiter[] = {'!',0};
static const WCHAR wszObjectName[] = {'T','e','s','t',0};
static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
WCHAR *display_name;
LARGE_INTEGER pos;
IStream *stream;
hr = CreateItemMoniker(NULL, wszObjectName, &moniker);
ok(hr == S_OK, "Failed to create item moniker, hr %#x.\n", hr);
@ -1727,6 +1758,43 @@ static void test_item_moniker(void)
expected_item_moniker_comparison_data5, sizeof(expected_item_moniker_comparison_data5),
58, L"abTest");
/* Serialize and load back. */
hr = CreateItemMoniker(NULL, L"object", &moniker2);
ok(hr == S_OK, "Failed to create item moniker, hr %#x.\n", hr);
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
hr = CreateBindCtx(0, &bindctx);
ok(hr == S_OK, "Failed to create bind context, hr %#x.\n", hr);
for (i = 0; i < ARRAY_SIZE(item_moniker_data); ++i)
{
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "Failed to seek stream, hr %#x.\n", hr);
hr = IStream_Write(stream, item_moniker_data[i].data, item_moniker_data[i].data_len, NULL);
ok(hr == S_OK, "Failed to write stream contents, hr %#x.\n", hr);
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "Failed to seek stream, hr %#x.\n", hr);
hr = IMoniker_Load(moniker2, stream);
ok(hr == S_OK, "Failed to load moniker, hr %#x.\n", hr);
hr = IMoniker_GetDisplayName(moniker2, bindctx, NULL, &display_name);
ok(hr == S_OK, "Failed to get display name, hr %#x.\n", hr);
ok(!lstrcmpW(display_name, item_moniker_data[i].display_name), "%d: unexpected display name %s.\n",
i, wine_dbgstr_w(display_name));
CoTaskMemFree(display_name);
}
IStream_Release(stream);
IMoniker_Release(moniker2);
IMoniker_Release(moniker);
hr = CreateItemMoniker(wszDelimiter, wszObjectName, &moniker);
@ -1756,9 +1824,6 @@ static void test_item_moniker(void)
"dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
moniker_type);
hr = CreateBindCtx(0, &bindctx);
ok_ole_success(hr, CreateBindCtx);
/* IsRunning test */
hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr);