Commit e68982fc authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

Implement FmtIdToPropStgName & PropStgNameToFmtId, with tests.

parent a3b4e205
......@@ -96,6 +96,7 @@
@ stdcall -private DllUnregisterServer()
@ stdcall DoDragDrop(ptr ptr long ptr)
@ stub EnableHookObject
@ stdcall FmtIdToPropStgName(ptr wstr)
@ stdcall FreePropVariantArray(long ptr)
@ stdcall GetClassFile(wstr ptr)
@ stdcall GetConvertStg(ptr)
......@@ -212,6 +213,7 @@
@ stdcall OleUninitialize()
@ stub OpenOrCreateStream
@ stdcall ProgIDFromCLSID(ptr ptr)
@ stdcall PropStgNameToFmtId(wstr ptr)
@ stdcall PropSysAllocString(wstr)
@ stdcall PropSysFreeString(wstr)
@ stdcall PropVariantClear(ptr)
......
......@@ -1796,70 +1796,6 @@ static HRESULT PropertyStorage_ConstructEmpty(IStream *stm,
* Implementation of IPropertySetStorage
*/
#define BITS_PER_BYTE 8
#define CHARMASK 0x1f
#define BITS_IN_CHARMASK 5
/* Converts rfmtid to a string and returns the resulting string. If rfmtid
* is a well-known FMTID, it just returns a static string. Otherwise it
* creates the appropriate string name in str, which must be 27 characters
* in length, and returns str.
* Based on the algorithm described here:
* http://msdn.microsoft.com/library/en-us/stg/stg/names_in_istorage.asp
*/
static LPCWSTR format_id_to_name(REFFMTID rfmtid, LPWSTR str)
{
static const char fmtMap[] = "abcdefghijklmnopqrstuvwxyz012345";
static const WCHAR szSummaryInfo[] = { 5,'S','u','m','m','a','r','y',
'I','n','f','o','r','m','a','t','i','o','n',0 };
static const WCHAR szDocSummaryInfo[] = { 5,'D','o','c','u','m','e','n','t',
'S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',
0 };
LPCWSTR ret;
if (IsEqualGUID(&FMTID_SummaryInformation, rfmtid))
ret = szSummaryInfo;
else if (IsEqualGUID(&FMTID_DocSummaryInformation, rfmtid))
ret = szDocSummaryInfo;
else
{
BYTE *fmtptr;
WCHAR *pstr = str;
ULONG bitsRemaining = BITS_PER_BYTE;
*pstr++ = 5;
for (fmtptr = (BYTE *)rfmtid; fmtptr < (BYTE *)rfmtid + sizeof(FMTID); )
{
ULONG i = *fmtptr >> (BITS_PER_BYTE - bitsRemaining);
if (bitsRemaining >= BITS_IN_CHARMASK)
{
*pstr = (WCHAR)(fmtMap[i & CHARMASK]);
if (bitsRemaining == BITS_PER_BYTE && *pstr >= 'a' &&
*pstr <= 'z')
*pstr += 'A' - 'a';
pstr++;
bitsRemaining -= BITS_IN_CHARMASK;
if (bitsRemaining == 0)
{
fmtptr++;
bitsRemaining = BITS_PER_BYTE;
}
}
else
{
if (++fmtptr < (BYTE *)rfmtid + sizeof(FMTID))
i |= *fmtptr << bitsRemaining;
*pstr++ = (WCHAR)(fmtMap[i & CHARMASK]);
}
}
*pstr = 0;
ret = str;
}
TRACE("returning %s\n", debugstr_w(ret));
return ret;
}
/************************************************************************
* IPropertySetStorage_fnQueryInterface (IUnknown)
*
......@@ -1910,8 +1846,7 @@ static HRESULT WINAPI IPropertySetStorage_fnCreate(
IPropertyStorage** ppprstg)
{
_ICOM_THIS_From_IPropertySetStorage(StorageImpl, ppstg);
WCHAR nameBuf[27];
LPCWSTR name = NULL;
WCHAR name[CCH_MAX_PROPSTG_NAME];
IStream *stm = NULL;
HRESULT r;
......@@ -1941,7 +1876,9 @@ static HRESULT WINAPI IPropertySetStorage_fnCreate(
goto end;
}
name = format_id_to_name(rfmtid, nameBuf);
r = FmtIdToPropStgName(rfmtid, name);
if (FAILED(r))
goto end;
r = IStorage_CreateStream( (IStorage*)This, name, grfMode, 0, 0, &stm );
if (FAILED(r))
......@@ -1965,8 +1902,7 @@ static HRESULT WINAPI IPropertySetStorage_fnOpen(
{
_ICOM_THIS_From_IPropertySetStorage(StorageImpl, ppstg);
IStream *stm = NULL;
WCHAR nameBuf[27];
LPCWSTR name = NULL;
WCHAR name[CCH_MAX_PROPSTG_NAME];
HRESULT r;
TRACE("%p %s %08lx %p\n", This, debugstr_guid(rfmtid), grfMode, ppprstg);
......@@ -1985,7 +1921,9 @@ static HRESULT WINAPI IPropertySetStorage_fnOpen(
goto end;
}
name = format_id_to_name(rfmtid, nameBuf);
r = FmtIdToPropStgName(rfmtid, name);
if (FAILED(r))
goto end;
r = IStorage_OpenStream((IStorage*) This, name, 0, grfMode, 0, &stm );
if (FAILED(r))
......@@ -2007,17 +1945,17 @@ static HRESULT WINAPI IPropertySetStorage_fnDelete(
{
_ICOM_THIS_From_IPropertySetStorage(StorageImpl, ppstg);
IStorage *stg = NULL;
WCHAR nameBuf[27];
LPCWSTR name = NULL;
WCHAR name[CCH_MAX_PROPSTG_NAME];
HRESULT r;
TRACE("%p %s\n", This, debugstr_guid(rfmtid));
if (!rfmtid)
return E_INVALIDARG;
name = format_id_to_name(rfmtid, nameBuf);
if (!name)
return STG_E_FILENOTFOUND;
r = FmtIdToPropStgName(rfmtid, name);
if (FAILED(r))
return r;
stg = (IStorage*) This;
return IStorage_DestroyElement(stg, name);
......@@ -2068,3 +2006,172 @@ static IPropertyStorageVtbl IPropertyStorage_Vtbl =
IPropertyStorage_fnSetClass,
IPropertyStorage_fnStat,
};
/***********************************************************************
* Format ID <-> name conversion
*/
static const WCHAR szSummaryInfo[] = { 5,'S','u','m','m','a','r','y',
'I','n','f','o','r','m','a','t','i','o','n',0 };
static const WCHAR szDocSummaryInfo[] = { 5,'D','o','c','u','m','e','n','t',
'S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0 };
#define BITS_PER_BYTE 8
#define CHARMASK 0x1f
#define BITS_IN_CHARMASK 5
#define NUM_ALPHA_CHARS 26
/***********************************************************************
* FmtIdToPropStgName [ole32.@]
* Returns the storage name of the format ID rfmtid.
* PARAMS
* rfmtid [I] Format ID for which to return a storage name
* str [O] Storage name associated with rfmtid.
*
* RETURNS
* E_INVALIDARG if rfmtid or str i NULL, S_OK otherwise.
*
* NOTES
* str must be at least CCH_MAX_PROPSTG_NAME characters in length.
* Based on the algorithm described here:
* http://msdn.microsoft.com/library/en-us/stg/stg/names_in_istorage.asp
*/
HRESULT WINAPI FmtIdToPropStgName(const FMTID *rfmtid, LPOLESTR str)
{
static const char fmtMap[] = "abcdefghijklmnopqrstuvwxyz012345";
TRACE("%s, %p\n", debugstr_guid(rfmtid), str);
if (!rfmtid) return E_INVALIDARG;
if (!str) return E_INVALIDARG;
if (IsEqualGUID(&FMTID_SummaryInformation, rfmtid))
lstrcpyW(str, szSummaryInfo);
else if (IsEqualGUID(&FMTID_DocSummaryInformation, rfmtid))
lstrcpyW(str, szDocSummaryInfo);
else if (IsEqualGUID(&FMTID_UserDefinedProperties, rfmtid))
lstrcpyW(str, szDocSummaryInfo);
else
{
BYTE *fmtptr;
WCHAR *pstr = str;
ULONG bitsRemaining = BITS_PER_BYTE;
*pstr++ = 5;
for (fmtptr = (BYTE *)rfmtid; fmtptr < (BYTE *)rfmtid + sizeof(FMTID); )
{
ULONG i = *fmtptr >> (BITS_PER_BYTE - bitsRemaining);
if (bitsRemaining >= BITS_IN_CHARMASK)
{
*pstr = (WCHAR)(fmtMap[i & CHARMASK]);
if (bitsRemaining == BITS_PER_BYTE && *pstr >= 'a' &&
*pstr <= 'z')
*pstr += 'A' - 'a';
pstr++;
bitsRemaining -= BITS_IN_CHARMASK;
if (bitsRemaining == 0)
{
fmtptr++;
bitsRemaining = BITS_PER_BYTE;
}
}
else
{
if (++fmtptr < (BYTE *)rfmtid + sizeof(FMTID))
i |= *fmtptr << bitsRemaining;
*pstr++ = (WCHAR)(fmtMap[i & CHARMASK]);
bitsRemaining += BITS_PER_BYTE - BITS_IN_CHARMASK;
}
}
*pstr = 0;
}
TRACE("returning %s\n", debugstr_w(str));
return S_OK;
}
/***********************************************************************
* PropStgNameToFmtId [ole32.@]
* Returns the format ID corresponding to the given name.
* PARAMS
* str [I] Storage name to convert to a format ID.
* rfmtid [O] Format ID corresponding to str.
*
* RETURNS
* E_INVALIDARG if rfmtid or str is NULL or if str can't be converted to
* a format ID, S_OK otherwise.
*
* NOTES
* Based on the algorithm described here:
* http://msdn.microsoft.com/library/en-us/stg/stg/names_in_istorage.asp
*/
HRESULT WINAPI PropStgNameToFmtId(const LPOLESTR str, FMTID *rfmtid)
{
HRESULT hr = E_INVALIDARG;
TRACE("%s, %p\n", debugstr_w(str), rfmtid);
if (!rfmtid) return E_INVALIDARG;
if (!str) return E_INVALIDARG;
if (!lstrcmpiW(str, szDocSummaryInfo))
{
memcpy(rfmtid, &FMTID_DocSummaryInformation, sizeof(*rfmtid));
hr = S_OK;
}
else if (!lstrcmpiW(str, szSummaryInfo))
{
memcpy(rfmtid, &FMTID_SummaryInformation, sizeof(*rfmtid));
hr = S_OK;
}
else
{
ULONG bits;
BYTE *fmtptr = (BYTE *)rfmtid - 1;
const WCHAR *pstr = str;
memset(rfmtid, 0, sizeof(*rfmtid));
for (bits = 0; bits < sizeof(FMTID) * BITS_PER_BYTE;
bits += BITS_IN_CHARMASK)
{
ULONG bitsUsed = bits % BITS_PER_BYTE, bitsStored;
WCHAR wc;
if (bitsUsed == 0)
fmtptr++;
wc = *++pstr - 'A';
if (wc > NUM_ALPHA_CHARS)
{
wc += 'A' - 'a';
if (wc > NUM_ALPHA_CHARS)
{
wc += 'a' - '0' + NUM_ALPHA_CHARS;
if (wc > CHARMASK)
{
WARN("invalid character (%d)\n", *pstr);
goto end;
}
}
}
*fmtptr |= wc << bitsUsed;
bitsStored = min(BITS_PER_BYTE - bitsUsed, BITS_IN_CHARMASK);
if (bitsStored < BITS_IN_CHARMASK)
{
wc >>= BITS_PER_BYTE - bitsUsed;
if (bits + bitsStored == sizeof(FMTID) * BITS_PER_BYTE)
{
if (wc != 0)
{
WARN("extra bits\n");
goto end;
}
break;
}
fmtptr++;
*fmtptr |= (BYTE)wc;
}
}
hr = S_OK;
}
end:
return hr;
}
......@@ -244,7 +244,77 @@ static void testProps(void)
DeleteFileW(filename);
}
static void testFmtId(void)
{
WCHAR szSummaryInfo[] = { 5,'S','u','m','m','a','r','y',
'I','n','f','o','r','m','a','t','i','o','n',0 };
WCHAR szDocSummaryInfo[] = { 5,'D','o','c','u','m','e','n','t',
'S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',
0 };
WCHAR szIID_IPropSetStg[] = { 5,'0','j','a','a','a','a','a',
'a','A','a','a','a','a','a','d','a','A','a','a','a','a','a','a','a','G',
'c',0 };
WCHAR name[32];
FMTID fmtid;
HRESULT hr;
hr = FmtIdToPropStgName(NULL, name);
ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08lx\n", hr);
hr = FmtIdToPropStgName(&FMTID_SummaryInformation, NULL);
ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08lx\n", hr);
hr = FmtIdToPropStgName(&FMTID_SummaryInformation, name);
ok(SUCCEEDED(hr), "FmtIdToPropStgName failed: 0x%08lx\n", hr);
ok(!memcmp(name, szSummaryInfo, (lstrlenW(szSummaryInfo) + 1) *
sizeof(WCHAR)), "Got wrong name for FMTID_SummaryInformation\n");
hr = FmtIdToPropStgName(&FMTID_DocSummaryInformation, name);
ok(SUCCEEDED(hr), "FmtIdToPropStgName failed: 0x%08lx\n", hr);
ok(!memcmp(name, szDocSummaryInfo, (lstrlenW(szDocSummaryInfo) + 1) *
sizeof(WCHAR)), "Got wrong name for FMTID_DocSummaryInformation\n");
hr = FmtIdToPropStgName(&FMTID_UserDefinedProperties, name);
ok(SUCCEEDED(hr), "FmtIdToPropStgName failed: 0x%08lx\n", hr);
ok(!memcmp(name, szDocSummaryInfo, (lstrlenW(szDocSummaryInfo) + 1) *
sizeof(WCHAR)), "Got wrong name for FMTID_DocSummaryInformation\n");
hr = FmtIdToPropStgName(&IID_IPropertySetStorage, name);
ok(SUCCEEDED(hr), "FmtIdToPropStgName failed: 0x%08lx\n", hr);
ok(!memcmp(name, szIID_IPropSetStg, (lstrlenW(szIID_IPropSetStg) + 1) *
sizeof(WCHAR)), "Got wrong name for IID_IPropertySetStorage\n");
/* test args first */
hr = PropStgNameToFmtId(NULL, NULL);
ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08lx\n", hr);
hr = PropStgNameToFmtId(NULL, &fmtid);
ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08lx\n", hr);
hr = PropStgNameToFmtId(szDocSummaryInfo, NULL);
ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got 0x%08lx\n", hr);
/* test the known format IDs */
hr = PropStgNameToFmtId(szSummaryInfo, &fmtid);
ok(SUCCEEDED(hr), "PropStgNameToFmtId failed: 0x%08lx\n", hr);
ok(!memcmp(&fmtid, &FMTID_SummaryInformation, sizeof(fmtid)),
"Got unexpected FMTID, expected FMTID_SummaryInformation\n");
hr = PropStgNameToFmtId(szDocSummaryInfo, &fmtid);
ok(SUCCEEDED(hr), "PropStgNameToFmtId failed: 0x%08lx\n", hr);
ok(!memcmp(&fmtid, &FMTID_DocSummaryInformation, sizeof(fmtid)),
"Got unexpected FMTID, expected FMTID_DocSummaryInformation\n");
/* test another GUID */
hr = PropStgNameToFmtId(szIID_IPropSetStg, &fmtid);
ok(SUCCEEDED(hr), "PropStgNameToFmtId failed: 0x%08lx\n", hr);
ok(!memcmp(&fmtid, &IID_IPropertySetStorage, sizeof(fmtid)),
"Got unexpected FMTID, expected IID_IPropertySetStorage\n");
/* now check case matching */
CharUpperW(szDocSummaryInfo + 1);
hr = PropStgNameToFmtId(szDocSummaryInfo, &fmtid);
ok(SUCCEEDED(hr), "PropStgNameToFmtId failed: 0x%08lx\n", hr);
ok(!memcmp(&fmtid, &FMTID_DocSummaryInformation, sizeof(fmtid)),
"Got unexpected FMTID, expected FMTID_DocSummaryInformation\n");
CharUpperW(szIID_IPropSetStg + 1);
hr = PropStgNameToFmtId(szIID_IPropSetStg, &fmtid);
ok(SUCCEEDED(hr), "PropStgNameToFmtId failed: 0x%08lx\n", hr);
ok(!memcmp(&fmtid, &IID_IPropertySetStorage, sizeof(fmtid)),
"Got unexpected FMTID, expected IID_IPropertySetStorage\n");
}
START_TEST(stg_prop)
{
testProps();
testFmtId();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment