📄 stg_prop.c
字号:
/*
* Compound Storage (32 bit version)
* Storage implementation
*
* This file contains the compound file implementation
* of the storage interface.
*
* Copyright 1999 Francis Beaudet
* Copyright 1999 Sylvain St-Germain
* Copyright 1999 Thuy Nguyen
* Copyright 2005 Mike McCormack
* Copyright 2005 Juan Lang
*
* 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
*
* There's a decent overview of property set storage here:
* http://msdn.microsoft.com/archive/en-us/dnarolegen/html/msdn_propset.asp
* It's a little bit out of date, and more definitive references are given
* below, but it gives the best "big picture" that I've found.
*
* TODO:
* - I don't honor the maximum property set size.
* - Certain bogus files could result in reading past the end of a buffer.
* - Mac-generated files won't be read correctly, even if they're little
* endian, because I disregard whether the generator was a Mac. This means
* strings will probably be munged (as I don't understand Mac scripts.)
* - Not all PROPVARIANT types are supported.
* - User defined properties are not supported, see comment in
* PropertyStorage_ReadFromStream
*/
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winuser.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "dictionary.h"
#include "storage32.h"
#include "enumx.h"
WINE_DEFAULT_DEBUG_CHANNEL(storage);
static inline StorageImpl *impl_from_IPropertySetStorage( IPropertySetStorage *iface )
{
return (StorageImpl *)((char*)iface - FIELD_OFFSET(StorageImpl, base.pssVtbl));
}
/* These are documented in MSDN, e.g.
* http://msdn.microsoft.com/library/en-us/stg/stg/property_set_header.asp
* http://msdn.microsoft.com/library/library/en-us/stg/stg/section.asp
* but they don't seem to be in any header file.
*/
#define PROPSETHDR_BYTEORDER_MAGIC 0xfffe
#define PROPSETHDR_OSVER_KIND_WIN16 0
#define PROPSETHDR_OSVER_KIND_MAC 1
#define PROPSETHDR_OSVER_KIND_WIN32 2
#define CP_UNICODE 1200
#define MAX_VERSION_0_PROP_NAME_LENGTH 256
#define CFTAG_WINDOWS (-1L)
#define CFTAG_MACINTOSH (-2L)
#define CFTAG_FMTID (-3L)
#define CFTAG_NODATA 0L
/* The format version (and what it implies) is described here:
* http://msdn.microsoft.com/library/en-us/stg/stg/format_version.asp
*/
typedef struct tagPROPERTYSETHEADER
{
WORD wByteOrder; /* always 0xfffe */
WORD wFormat; /* can be zero or one */
DWORD dwOSVer; /* OS version of originating system */
CLSID clsid; /* application CLSID */
DWORD reserved; /* always 1 */
} PROPERTYSETHEADER;
typedef struct tagFORMATIDOFFSET
{
FMTID fmtid;
DWORD dwOffset; /* from beginning of stream */
} FORMATIDOFFSET;
typedef struct tagPROPERTYSECTIONHEADER
{
DWORD cbSection;
DWORD cProperties;
} PROPERTYSECTIONHEADER;
typedef struct tagPROPERTYIDOFFSET
{
DWORD propid;
DWORD dwOffset; /* from beginning of section */
} PROPERTYIDOFFSET;
typedef struct tagPropertyStorage_impl PropertyStorage_impl;
/* Initializes the property storage from the stream (and undoes any uncommitted
* changes in the process.) Returns an error if there is an error reading or
* if the stream format doesn't match what's expected.
*/
static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *);
static HRESULT PropertyStorage_WriteToStream(PropertyStorage_impl *);
/* Creates the dictionaries used by the property storage. If successful, all
* the dictionaries have been created. If failed, none has been. (This makes
* it a bit easier to deal with destroying them.)
*/
static HRESULT PropertyStorage_CreateDictionaries(PropertyStorage_impl *);
static void PropertyStorage_DestroyDictionaries(PropertyStorage_impl *);
/* Copies from propvar to prop. If propvar's type is VT_LPSTR, copies the
* string using PropertyStorage_StringCopy.
*/
static HRESULT PropertyStorage_PropVariantCopy(PROPVARIANT *prop,
const PROPVARIANT *propvar, LCID targetCP, LCID srcCP);
/* Copies the string src, which is encoded using code page srcCP, and returns
* it in *dst, in the code page specified by targetCP. The returned string is
* allocated using CoTaskMemAlloc.
* If srcCP is CP_UNICODE, src is in fact an LPCWSTR. Similarly, if targetCP
* is CP_UNICODE, the returned string is in fact an LPWSTR.
* Returns S_OK on success, something else on failure.
*/
static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst,
LCID targetCP);
static const IPropertyStorageVtbl IPropertyStorage_Vtbl;
static const IEnumSTATPROPSETSTGVtbl IEnumSTATPROPSETSTG_Vtbl;
static const IEnumSTATPROPSTGVtbl IEnumSTATPROPSTG_Vtbl;
static HRESULT create_EnumSTATPROPSETSTG(StorageImpl *, IEnumSTATPROPSETSTG**);
static HRESULT create_EnumSTATPROPSTG(PropertyStorage_impl *, IEnumSTATPROPSTG**);
/***********************************************************************
* Implementation of IPropertyStorage
*/
struct tagPropertyStorage_impl
{
const IPropertyStorageVtbl *vtbl;
LONG ref;
CRITICAL_SECTION cs;
IStream *stm;
BOOL dirty;
FMTID fmtid;
CLSID clsid;
WORD format;
DWORD originatorOS;
DWORD grfFlags;
DWORD grfMode;
UINT codePage;
LCID locale;
PROPID highestProp;
struct dictionary *name_to_propid;
struct dictionary *propid_to_name;
struct dictionary *propid_to_prop;
};
/************************************************************************
* IPropertyStorage_fnQueryInterface (IPropertyStorage)
*/
static HRESULT WINAPI IPropertyStorage_fnQueryInterface(
IPropertyStorage *iface,
REFIID riid,
void** ppvObject)
{
PropertyStorage_impl *This = (PropertyStorage_impl *)iface;
if ( (This==0) || (ppvObject==0) )
return E_INVALIDARG;
*ppvObject = 0;
if (IsEqualGUID(&IID_IUnknown, riid) ||
IsEqualGUID(&IID_IPropertyStorage, riid))
{
IPropertyStorage_AddRef(iface);
*ppvObject = (IPropertyStorage*)iface;
return S_OK;
}
return E_NOINTERFACE;
}
/************************************************************************
* IPropertyStorage_fnAddRef (IPropertyStorage)
*/
static ULONG WINAPI IPropertyStorage_fnAddRef(
IPropertyStorage *iface)
{
PropertyStorage_impl *This = (PropertyStorage_impl *)iface;
return InterlockedIncrement(&This->ref);
}
/************************************************************************
* IPropertyStorage_fnRelease (IPropertyStorage)
*/
static ULONG WINAPI IPropertyStorage_fnRelease(
IPropertyStorage *iface)
{
PropertyStorage_impl *This = (PropertyStorage_impl *)iface;
ULONG ref;
ref = InterlockedDecrement(&This->ref);
if (ref == 0)
{
TRACE("Destroying %p\n", This);
if (This->dirty)
IPropertyStorage_Commit(iface, STGC_DEFAULT);
IStream_Release(This->stm);
This->cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->cs);
PropertyStorage_DestroyDictionaries(This);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
static PROPVARIANT *PropertyStorage_FindProperty(PropertyStorage_impl *This,
DWORD propid)
{
PROPVARIANT *ret = NULL;
dictionary_find(This->propid_to_prop, (void *)propid, (void **)&ret);
TRACE("returning %p\n", ret);
return ret;
}
/* Returns NULL if name is NULL. */
static PROPVARIANT *PropertyStorage_FindPropertyByName(
PropertyStorage_impl *This, LPCWSTR name)
{
PROPVARIANT *ret = NULL;
PROPID propid;
if (!name)
return NULL;
if (This->codePage == CP_UNICODE)
{
if (dictionary_find(This->name_to_propid, name, (void **)&propid))
ret = PropertyStorage_FindProperty(This, (PROPID)propid);
}
else
{
LPSTR ansiName;
HRESULT hr = PropertyStorage_StringCopy((LPCSTR)name, CP_UNICODE,
&ansiName, This->codePage);
if (SUCCEEDED(hr))
{
if (dictionary_find(This->name_to_propid, ansiName,
(void **)&propid))
ret = PropertyStorage_FindProperty(This, (PROPID)propid);
CoTaskMemFree(ansiName);
}
}
TRACE("returning %p\n", ret);
return ret;
}
static LPWSTR PropertyStorage_FindPropertyNameById(PropertyStorage_impl *This,
DWORD propid)
{
LPWSTR ret = NULL;
dictionary_find(This->propid_to_name, (void *)propid, (void **)&ret);
TRACE("returning %p\n", ret);
return ret;
}
/************************************************************************
* IPropertyStorage_fnReadMultiple (IPropertyStorage)
*/
static HRESULT WINAPI IPropertyStorage_fnReadMultiple(
IPropertyStorage* iface,
ULONG cpspec,
const PROPSPEC rgpspec[],
PROPVARIANT rgpropvar[])
{
PropertyStorage_impl *This = (PropertyStorage_impl *)iface;
HRESULT hr = S_OK;
ULONG i;
TRACE("(%p, %d, %p, %p)\n", iface, cpspec, rgpspec, rgpropvar);
if (!cpspec)
return S_FALSE;
if (!rgpspec || !rgpropvar)
return E_INVALIDARG;
EnterCriticalSection(&This->cs);
for (i = 0; i < cpspec; i++)
{
PropVariantInit(&rgpropvar[i]);
if (rgpspec[i].ulKind == PRSPEC_LPWSTR)
{
PROPVARIANT *prop = PropertyStorage_FindPropertyByName(This,
rgpspec[i].u.lpwstr);
if (prop)
PropertyStorage_PropVariantCopy(&rgpropvar[i], prop, GetACP(),
This->codePage);
}
else
{
switch (rgpspec[i].u.propid)
{
case PID_CODEPAGE:
rgpropvar[i].vt = VT_I2;
rgpropvar[i].u.iVal = This->codePage;
break;
case PID_LOCALE:
rgpropvar[i].vt = VT_I4;
rgpropvar[i].u.lVal = This->locale;
break;
default:
{
PROPVARIANT *prop = PropertyStorage_FindProperty(This,
rgpspec[i].u.propid);
if (prop)
PropertyStorage_PropVariantCopy(&rgpropvar[i], prop,
GetACP(), This->codePage);
else
hr = S_FALSE;
}
}
}
}
LeaveCriticalSection(&This->cs);
return hr;
}
static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst,
LCID dstCP)
{
HRESULT hr = S_OK;
int len;
TRACE("%s, %p, %d, %d\n",
srcCP == CP_UNICODE ? debugstr_w((LPCWSTR)src) : debugstr_a(src), dst,
dstCP, srcCP);
assert(src);
assert(dst);
*dst = NULL;
if (dstCP == srcCP)
{
size_t len;
if (dstCP == CP_UNICODE)
len = (strlenW((LPCWSTR)src) + 1) * sizeof(WCHAR);
else
len = strlen(src) + 1;
*dst = CoTaskMemAlloc(len * sizeof(WCHAR));
if (!*dst)
hr = STG_E_INSUFFICIENTMEMORY;
else
memcpy(*dst, src, len);
}
else
{
if (dstCP == CP_UNICODE)
{
len = MultiByteToWideChar(srcCP, 0, src, -1, NULL, 0);
*dst = CoTaskMemAlloc(len * sizeof(WCHAR));
if (!*dst)
hr = STG_E_INSUFFICIENTMEMORY;
else
MultiByteToWideChar(srcCP, 0, src, -1, (LPWSTR)*dst, len);
}
else
{
LPCWSTR wideStr = NULL;
LPWSTR wideStr_tmp = NULL;
if (srcCP == CP_UNICODE)
wideStr = (LPCWSTR)src;
else
{
len = MultiByteToWideChar(srcCP, 0, src, -1, NULL, 0);
wideStr_tmp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (wideStr_tmp)
{
MultiByteToWideChar(srcCP, 0, src, -1, wideStr_tmp, len);
wideStr = wideStr_tmp;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -