Nikolay Sivov : ole32: Handle optional WCHAR data when loading item moniker.
Alexandre Julliard
julliard at winehq.org
Fri Dec 13 15:27:22 CST 2019
Module: wine
Branch: master
Commit: b6766167002a9be0ab40b8daedecd82a0f76dba6
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b6766167002a9be0ab40b8daedecd82a0f76dba6
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Fri Dec 13 13:06:56 2019 +0300
ole32: Handle optional WCHAR data when loading item moniker.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ole32/itemmoniker.c | 128 ++++++++++++++++++++++++++++-----------------
dlls/ole32/tests/moniker.c | 75 ++++++++++++++++++++++++--
2 files changed, 151 insertions(+), 52 deletions(-)
diff --git a/dlls/ole32/itemmoniker.c b/dlls/ole32/itemmoniker.c
index 2d325ff50c..bd6fd6fd87 100644
--- a/dlls/ole32/itemmoniker.c
+++ b/dlls/ole32/itemmoniker.c
@@ -157,72 +157,106 @@ static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface)
return S_FALSE;
}
-/******************************************************************************
- * ItemMoniker_Load
- ******************************************************************************/
-static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm)
+static HRESULT item_moniker_load_string_record(IStream *stream, WCHAR **ret)
{
- ItemMonikerImpl *This = impl_from_IMoniker(iface);
- HRESULT res;
- DWORD delimiterLength,nameLength,lenW;
- CHAR *itemNameA,*itemDelimiterA;
- ULONG bread;
-
- TRACE("\n");
+ DWORD str_len, read_len, lenW, i;
+ HRESULT hr = S_OK;
+ char *buffer;
+ WCHAR *str;
- /* for more details about data read by this function see comments of ItemMonikerImpl_Save function */
-
- /* read item delimiter string length + 1 */
- res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread);
- if (bread != sizeof(DWORD))
+ IStream_Read(stream, &str_len, sizeof(str_len), &read_len);
+ if (read_len != sizeof(str_len))
return E_FAIL;
- /* read item delimiter string */
- if (!(itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength)))
+ if (!str_len)
+ {
+ heap_free(*ret);
+ *ret = NULL;
+ return S_OK;
+ }
+
+ if (!(buffer = heap_alloc(str_len)))
return E_OUTOFMEMORY;
- res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread);
- if (bread != delimiterLength)
+
+ IStream_Read(stream, buffer, str_len, &read_len);
+ if (read_len != str_len)
{
- HeapFree( GetProcessHeap(), 0, itemDelimiterA );
+ heap_free(buffer);
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)
+ /* Skip ansi buffer, it must be null terminated. */
+ i = 0;
+ while (i < str_len && buffer[i])
+ i++;
+
+ if (buffer[i])
{
- HeapFree( GetProcessHeap(), 0, itemDelimiterA );
- return E_OUTOFMEMORY;
+ WARN("Expected null terminated ansi name.\n");
+ hr = E_FAIL;
+ goto end;
}
- 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;
+ if (i < str_len - 1)
+ {
+ str_len -= i + 1;
- /* read item name string */
- if (!(itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength)))
- return E_OUTOFMEMORY;
- res=IStream_Read(pStm,itemNameA,nameLength,&bread);
- if (bread != nameLength)
+ 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
{
- HeapFree( GetProcessHeap(), 0, itemNameA );
- return E_FAIL;
+ 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);
}
- lenW = MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, NULL, 0 );
- This->itemName=HeapReAlloc(GetProcessHeap(),0,This->itemName,lenW*sizeof(WCHAR));
- if (!This->itemName)
+ if (str)
{
- HeapFree( GetProcessHeap(), 0, itemNameA );
- return E_OUTOFMEMORY;
+ heap_free(*ret);
+ *ret = str;
}
- MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, This->itemName, lenW );
- HeapFree( GetProcessHeap(), 0, itemNameA );
+ else
+ hr = E_OUTOFMEMORY;
- return res;
+end:
+ heap_free(buffer);
+
+ return hr;
+}
+
+/******************************************************************************
+ * ItemMoniker_Load
+ ******************************************************************************/
+static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker *iface, IStream *stream)
+{
+ ItemMonikerImpl *This = impl_from_IMoniker(iface);
+ HRESULT hr;
+
+ TRACE("(%p, %p)\n", iface, stream);
+
+ /* 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. */
+
+ hr = item_moniker_load_string_record(stream, &This->itemDelimiter);
+ if (SUCCEEDED(hr))
+ hr = item_moniker_load_string_record(stream, &This->itemName);
+
+ return hr;
}
/******************************************************************************
diff --git a/dlls/ole32/tests/moniker.c b/dlls/ole32/tests/moniker.c
index 8b88ae4a0d..d911ce57e9 100644
--- a/dlls/ole32/tests/moniker.c
+++ b/dlls/ole32/tests/moniker.c
@@ -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);
More information about the wine-cvs
mailing list