Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
c1fe67bc
Commit
c1fe67bc
authored
Apr 11, 2005
by
Juan Lang
Committed by
Alexandre Julliard
Apr 11, 2005
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
- add write support to IPropertyStorage, with tests
- misc. cleanups the tests turned up
parent
ad5ec783
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
779 additions
and
133 deletions
+779
-133
stg_prop.c
dlls/ole32/stg_prop.c
+686
-130
stg_prop.c
dlls/ole32/tests/stg_prop.c
+93
-3
No files found.
dlls/ole32/stg_prop.c
View file @
c1fe67bc
...
...
@@ -34,7 +34,6 @@
* - There are all sorts of restricions I don't honor, like maximum property
* set byte size, maximum property name length
* - Certain bogus files could result in reading past the end of a buffer.
* - Write support is missing.
* - This will probably fail on big-endian machines, especially reading and
* writing strings.
* - Mac-generated files won't be read correctly, even if they're little
...
...
@@ -111,13 +110,25 @@ typedef struct tagPROPERTYIDOFFSET
DWORD
dwOffset
;
/* from beginning of section */
}
PROPERTYIDOFFSET
;
struct
tagPropertyStorage_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
(
IPropertyStorage
*
iface
);
static
HRESULT
PropertyStorage_ReadFromStream
(
struct
tagPropertyStorage_impl
*
);
static
HRESULT
PropertyStorage_WriteToStream
(
struct
tagPropertyStorage_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
(
struct
tagPropertyStorage_impl
*
);
static
HRESULT
PropertyStorage_WriteToStream
(
IPropertyStorage
*
iface
);
static
void
PropertyStorage_DestroyDictionaries
(
struct
tagPropertyStorage_impl
*
);
static
IPropertyStorageVtbl
IPropertyStorage_Vtbl
;
...
...
@@ -193,11 +204,11 @@ static ULONG WINAPI IPropertyStorage_fnRelease(
if
(
ref
==
0
)
{
TRACE
(
"Destroying %p
\n
"
,
This
);
if
(
This
->
dirty
)
IPropertyStorage_Commit
(
iface
,
STGC_DEFAULT
);
IStream_Release
(
This
->
stm
);
DeleteCriticalSection
(
&
This
->
cs
);
dictionary_destroy
(
This
->
name_to_propid
);
dictionary_destroy
(
This
->
propid_to_name
);
dictionary_destroy
(
This
->
propid_to_prop
);
PropertyStorage_DestroyDictionaries
(
This
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
return
ref
;
...
...
@@ -208,20 +219,21 @@ static PROPVARIANT *PropertyStorage_FindProperty(PropertyStorage_impl *This,
{
PROPVARIANT
*
ret
=
NULL
;
if
(
!
This
)
return
NULL
;
assert
(
This
);
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
(
!
This
||
!
name
)
assert
(
This
);
if
(
!
name
)
return
NULL
;
if
(
dictionary_find
(
This
->
name_to_propid
,
name
,
(
void
**
)
&
propid
))
ret
=
PropertyStorage_FindProperty
(
This
,
(
PROPID
)
propid
);
...
...
@@ -234,8 +246,7 @@ static LPWSTR PropertyStorage_FindPropertyNameById(PropertyStorage_impl *This,
{
LPWSTR
ret
=
NULL
;
if
(
!
This
)
return
NULL
;
assert
(
This
);
dictionary_find
(
This
->
propid_to_name
,
(
void
*
)
propid
,
(
void
**
)
&
ret
);
TRACE
(
"returning %p
\n
"
,
ret
);
return
ret
;
...
...
@@ -290,6 +301,9 @@ static HRESULT PropertyStorage_StorePropWithId(PropertyStorage_impl *This,
HRESULT
hr
=
S_OK
;
PROPVARIANT
*
prop
=
PropertyStorage_FindProperty
(
This
,
propid
);
assert
(
This
);
assert
(
propvar
);
TRACE
(
"Setting 0x%08lx to type %d
\n
"
,
propid
,
propvar
->
vt
);
if
(
prop
)
{
PropVariantClear
(
prop
);
...
...
@@ -409,6 +423,8 @@ static HRESULT WINAPI IPropertyStorage_fnWriteMultiple(
}
}
}
if
(
This
->
grfFlags
&
PROPSETFLAG_UNBUFFERED
)
IPropertyStorage_Commit
(
iface
,
STGC_DEFAULT
);
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
...
...
@@ -434,6 +450,7 @@ static HRESULT WINAPI IPropertyStorage_fnDeleteMultiple(
return
STG_E_ACCESSDENIED
;
hr
=
S_OK
;
EnterCriticalSection
(
&
This
->
cs
);
This
->
dirty
=
TRUE
;
for
(
i
=
0
;
i
<
cpspec
;
i
++
)
{
if
(
rgpspec
[
i
].
ulKind
==
PRSPEC_LPWSTR
)
...
...
@@ -454,6 +471,8 @@ static HRESULT WINAPI IPropertyStorage_fnDeleteMultiple(
hr
=
STG_E_INVALIDPARAMETER
;
}
}
if
(
This
->
grfFlags
&
PROPSETFLAG_UNBUFFERED
)
IPropertyStorage_Commit
(
iface
,
STGC_DEFAULT
);
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
...
...
@@ -521,6 +540,7 @@ static HRESULT WINAPI IPropertyStorage_fnWritePropertyNames(
return
STG_E_ACCESSDENIED
;
hr
=
S_OK
;
EnterCriticalSection
(
&
This
->
cs
);
This
->
dirty
=
TRUE
;
for
(
i
=
0
;
i
<
cpropid
;
i
++
)
{
if
(
rgpropid
[
i
]
!=
PID_ILLEGAL
)
...
...
@@ -533,6 +553,8 @@ static HRESULT WINAPI IPropertyStorage_fnWritePropertyNames(
dictionary_insert
(
This
->
propid_to_name
,
(
void
*
)
rgpropid
[
i
],
name
);
}
}
if
(
This
->
grfFlags
&
PROPSETFLAG_UNBUFFERED
)
IPropertyStorage_Commit
(
iface
,
STGC_DEFAULT
);
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
...
...
@@ -558,6 +580,7 @@ static HRESULT WINAPI IPropertyStorage_fnDeletePropertyNames(
return
STG_E_ACCESSDENIED
;
hr
=
S_OK
;
EnterCriticalSection
(
&
This
->
cs
);
This
->
dirty
=
TRUE
;
for
(
i
=
0
;
i
<
cpropid
;
i
++
)
{
LPWSTR
name
=
NULL
;
...
...
@@ -569,6 +592,8 @@ static HRESULT WINAPI IPropertyStorage_fnDeletePropertyNames(
dictionary_remove
(
This
->
name_to_propid
,
name
);
}
}
if
(
This
->
grfFlags
&
PROPSETFLAG_UNBUFFERED
)
IPropertyStorage_Commit
(
iface
,
STGC_DEFAULT
);
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
...
...
@@ -590,7 +615,7 @@ static HRESULT WINAPI IPropertyStorage_fnCommit(
return
STG_E_ACCESSDENIED
;
EnterCriticalSection
(
&
This
->
cs
);
if
(
This
->
dirty
)
hr
=
PropertyStorage_WriteToStream
(
iface
);
hr
=
PropertyStorage_WriteToStream
(
This
);
else
hr
=
S_OK
;
LeaveCriticalSection
(
&
This
->
cs
);
...
...
@@ -612,7 +637,12 @@ static HRESULT WINAPI IPropertyStorage_fnRevert(
EnterCriticalSection
(
&
This
->
cs
);
if
(
This
->
dirty
)
hr
=
PropertyStorage_ReadFromStream
(
iface
);
{
PropertyStorage_DestroyDictionaries
(
This
);
hr
=
PropertyStorage_CreateDictionaries
(
This
);
if
(
SUCCEEDED
(
hr
))
hr
=
PropertyStorage_ReadFromStream
(
This
);
}
else
hr
=
S_OK
;
LeaveCriticalSection
(
&
This
->
cs
);
...
...
@@ -659,6 +689,8 @@ static HRESULT WINAPI IPropertyStorage_fnSetClass(
return
STG_E_ACCESSDENIED
;
memcpy
(
&
This
->
clsid
,
clsid
,
sizeof
(
This
->
clsid
));
This
->
dirty
=
TRUE
;
if
(
This
->
grfFlags
&
PROPSETFLAG_UNBUFFERED
)
IPropertyStorage_Commit
(
iface
,
STGC_DEFAULT
);
return
S_OK
;
}
...
...
@@ -735,67 +767,64 @@ static void PropertyStorage_PropertyDestroy(void *k, void *d, void *extra)
static
HRESULT
PropertyStorage_ReadDictionary
(
PropertyStorage_impl
*
This
,
BYTE
*
ptr
)
{
DWORD
numEntries
=
*
(
DWORD
*
)
ptr
;
DWORD
numEntries
,
i
;
HRESULT
hr
=
S_OK
;
assert
(
This
);
assert
(
This
->
name_to_propid
);
assert
(
This
->
propid_to_name
);
StorageUtl_ReadDWord
(
ptr
,
0
,
&
numEntries
);
TRACE
(
"Reading %ld entries:
\n
"
,
numEntries
);
ptr
+=
sizeof
(
DWORD
);
if
(
This
->
name_to_propid
&&
This
->
propid_to_name
)
for
(
i
=
0
;
SUCCEEDED
(
hr
)
&&
i
<
numEntries
;
i
++
)
{
DWORD
i
;
PROPID
propid
;
DWORD
cbEntry
;
LPWSTR
name
=
NULL
;
for
(
i
=
0
;
SUCCEEDED
(
hr
)
&&
i
<
numEntries
;
i
++
)
StorageUtl_ReadDWord
(
ptr
,
0
,
&
propid
);
ptr
+=
sizeof
(
PROPID
);
StorageUtl_ReadDWord
(
ptr
,
0
,
&
cbEntry
);
ptr
+=
sizeof
(
DWORD
);
/* FIXME: if host is big-endian, this'll suck to convert */
TRACE
(
"Reading entry with ID 0x%08lx, %ld bytes
\n
"
,
propid
,
cbEntry
);
if
(
This
->
codePage
!=
CP_UNICODE
)
{
PROPID
propid
;
DWORD
cbEntry
;
int
len
;
StorageUtl_ReadDWord
(
ptr
,
0
,
&
propid
);
ptr
+=
sizeof
(
PROPID
);
StorageUtl_ReadDWord
(
ptr
,
0
,
&
cbEntry
);
ptr
+=
sizeof
(
DWORD
);
/* FIXME: if host is big-endian, this'll suck to convert */
len
=
MultiByteToWideChar
(
This
->
codePage
,
0
,
ptr
,
cbEntry
,
NULL
,
0
);
int
len
=
MultiByteToWideChar
(
This
->
codePage
,
0
,
ptr
,
cbEntry
,
NULL
,
0
);
if
(
!
len
)
hr
=
HRESULT_FROM_WIN32
(
GetLastError
());
else
{
LPWSTR
name
=
HeapAlloc
(
GetProcessHeap
(),
0
,
name
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
));
if
(
name
)
{
MultiByteToWideChar
(
This
->
codePage
,
0
,
ptr
+
sizeof
(
DWORD
),
cbEntry
,
name
,
len
);
dictionary_insert
(
This
->
name_to_propid
,
name
,
(
void
*
)
propid
);
dictionary_insert
(
This
->
propid_to_name
,
(
void
*
)
propid
,
name
);
TRACE
(
"Property %s maps to id %ld
\n
"
,
debugstr_w
(
name
),
propid
);
}
MultiByteToWideChar
(
This
->
codePage
,
0
,
ptr
,
cbEntry
,
name
,
len
);
else
hr
=
STG_E_INSUFFICIENTMEMORY
;
}
ptr
+=
sizeof
(
DWORD
)
+
cbEntry
;
/* Unicode entries are padded to DWORD boundaries */
if
(
This
->
codePage
==
CP_UNICODE
&&
cbEntry
%
sizeof
(
DWORD
))
ptr
+=
sizeof
(
DWORD
)
-
(
cbEntry
%
sizeof
(
DWORD
));
}
}
else
{
/* one or the other failed, free the other */
if
(
This
->
name_to_propid
)
else
{
dictionary_destroy
(
This
->
name_to_propid
);
This
->
name_to_propid
=
NULL
;
name
=
HeapAlloc
(
GetProcessHeap
(),
0
,
cbEntry
);
if
(
name
)
lstrcpyW
(
name
,
(
LPWSTR
)
ptr
);
else
hr
=
STG_E_INSUFFICIENTMEMORY
;
/* Unicode entries are padded to DWORD boundaries */
if
(
cbEntry
%
sizeof
(
DWORD
))
ptr
+=
sizeof
(
DWORD
)
-
(
cbEntry
%
sizeof
(
DWORD
));
}
if
(
This
->
propid_to_
name
)
if
(
name
)
{
dictionary_destroy
(
This
->
propid_to_name
);
This
->
propid_to_name
=
NULL
;
dictionary_insert
(
This
->
name_to_propid
,
name
,
(
void
*
)
propid
);
dictionary_insert
(
This
->
propid_to_name
,
(
void
*
)
propid
,
name
);
TRACE
(
"Property %s maps to id %ld
\n
"
,
debugstr_w
(
name
),
propid
);
}
hr
=
STG_E_INSUFFICIENTMEMORY
;
ptr
+=
sizeof
(
DWORD
)
+
cbEntry
;
}
return
hr
;
}
...
...
@@ -803,57 +832,53 @@ static HRESULT PropertyStorage_ReadDictionary(PropertyStorage_impl *This,
/* FIXME: there isn't any checking whether the read property extends past the
* end of the buffer.
*/
static
HRESULT
PropertyStorage_ReadProperty
(
PROPVARIANT
*
prop
,
DWORD
type
,
const
BYTE
*
data
)
static
HRESULT
PropertyStorage_ReadProperty
(
PROPVARIANT
*
prop
,
const
BYTE
*
data
)
{
HRESULT
hr
=
S_OK
;
prop
->
vt
=
VT_EMPTY
;
switch
(
type
)
assert
(
prop
);
assert
(
data
);
StorageUtl_ReadDWord
(
data
,
0
,
(
DWORD
*
)
&
prop
->
vt
);
data
+=
sizeof
(
DWORD
);
switch
(
prop
->
vt
)
{
case
VT_EMPTY
:
case
VT_NULL
:
prop
->
vt
=
VT_NULL
;
break
;
case
VT_I1
:
prop
->
vt
=
VT_I1
;
prop
->
u
.
cVal
=
*
(
const
char
*
)
data
;
TRACE
(
"Read char 0x%x ('%c')
\n
"
,
prop
->
u
.
cVal
,
prop
->
u
.
cVal
);
break
;
case
VT_UI1
:
prop
->
vt
=
VT_UI1
;
prop
->
u
.
bVal
=
*
(
const
UCHAR
*
)
data
;
TRACE
(
"Read byte 0x%x
\n
"
,
prop
->
u
.
bVal
);
break
;
case
VT_I2
:
prop
->
vt
=
VT_I2
;
StorageUtl_ReadWord
(
data
,
0
,
&
prop
->
u
.
iVal
);
TRACE
(
"Read short %d
\n
"
,
prop
->
u
.
iVal
);
break
;
case
VT_UI2
:
prop
->
vt
=
VT_UI2
;
StorageUtl_ReadWord
(
data
,
0
,
&
prop
->
u
.
uiVal
);
TRACE
(
"Read ushort %d
\n
"
,
prop
->
u
.
uiVal
);
break
;
case
VT_I4
:
prop
->
vt
=
VT_I4
;
StorageUtl_ReadDWord
(
data
,
0
,
&
prop
->
u
.
lVal
);
TRACE
(
"Read long %ld
\n
"
,
prop
->
u
.
lVal
);
break
;
case
VT_UI4
:
prop
->
vt
=
VT_UI4
;
StorageUtl_ReadDWord
(
data
,
0
,
&
prop
->
u
.
ulVal
);
TRACE
(
"Read ulong %ld
\n
"
,
prop
->
u
.
ulVal
);
break
;
case
VT_LPSTR
:
{
DWORD
count
=
*
(
const
DWORD
*
)
data
;
DWORD
count
;
StorageUtl_ReadDWord
(
data
,
0
,
&
count
);
prop
->
u
.
pszVal
=
CoTaskMemAlloc
(
count
);
if
(
prop
->
u
.
pszVal
)
{
/* FIXME: if the host is big-endian, this'll suck */
memcpy
(
prop
->
u
.
pszVal
,
data
+
sizeof
(
DWORD
),
count
);
prop
->
vt
=
VT_LPSTR
;
/* FIXME: so far so good, but this may be Unicode or DBCS depending
* on This->codePage.
*/
...
...
@@ -865,15 +890,15 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, DWORD type,
}
case
VT_LPWSTR
:
{
DWORD
count
=
*
(
DWORD
*
)
data
;
DWORD
count
;
StorageUtl_ReadDWord
(
data
,
0
,
&
count
);
prop
->
u
.
pwszVal
=
CoTaskMemAlloc
(
count
*
sizeof
(
WCHAR
));
if
(
prop
->
u
.
pwszVal
)
{
/* FIXME: if the host is big-endian, gotta swap every char */
memcpy
(
prop
->
u
.
pwszVal
,
data
+
sizeof
(
DWORD
),
count
*
sizeof
(
WCHAR
));
prop
->
vt
=
VT_LPWSTR
;
TRACE
(
"Read string value %s
\n
"
,
debugstr_w
(
prop
->
u
.
pwszVal
));
}
else
...
...
@@ -882,11 +907,10 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, DWORD type,
}
case
VT_FILETIME
:
/* FIXME: endianness */
prop
->
vt
=
VT_FILETIME
;
memcpy
(
&
prop
->
u
.
filetime
,
data
,
sizeof
(
FILETIME
));
break
;
default:
FIXME
(
"unsupported type %
ld
\n
"
,
type
);
FIXME
(
"unsupported type %
d
\n
"
,
prop
->
vt
);
hr
=
STG_E_INVALIDPARAMETER
;
}
return
hr
;
...
...
@@ -985,12 +1009,12 @@ static HRESULT PropertyStorage_ReadSectionHeaderFromStream(IStream *stm,
return
hr
;
}
static
HRESULT
PropertyStorage_ReadFromStream
(
IPropertyStorage
*
iface
)
static
HRESULT
PropertyStorage_ReadFromStream
(
PropertyStorage_impl
*
This
)
{
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
PROPERTYSETHEADER
hdr
;
FORMATIDOFFSET
fmtOffset
;
PROPERTYSECTIONHEADER
sectionHdr
;
LARGE_INTEGER
seek
;
ULONG
i
;
STATSTG
stat
;
HRESULT
hr
;
...
...
@@ -998,35 +1022,9 @@ static HRESULT PropertyStorage_ReadFromStream(IPropertyStorage *iface)
ULONG
count
=
0
;
DWORD
dictOffset
=
0
;
if
(
!
This
)
return
E_INVALIDARG
;
assert
(
This
);
This
->
dirty
=
FALSE
;
This
->
highestProp
=
0
;
dictionary_destroy
(
This
->
name_to_propid
);
dictionary_destroy
(
This
->
propid_to_name
);
dictionary_destroy
(
This
->
propid_to_prop
);
This
->
name_to_propid
=
dictionary_create
(
PropertyStorage_PropNameCompare
,
PropertyStorage_PropNameDestroy
,
This
);
if
(
!
This
->
name_to_propid
)
{
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
This
->
propid_to_name
=
dictionary_create
(
PropertyStorage_PropCompare
,
NULL
,
This
);
if
(
!
This
->
propid_to_name
)
{
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
This
->
propid_to_prop
=
dictionary_create
(
PropertyStorage_PropCompare
,
PropertyStorage_PropertyDestroy
,
This
);
if
(
!
This
->
propid_to_prop
)
{
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
hr
=
IStream_Stat
(
This
->
stm
,
&
stat
,
STATFLAG_NONAME
);
if
(
FAILED
(
hr
))
goto
end
;
...
...
@@ -1039,7 +1037,7 @@ static HRESULT PropertyStorage_ReadFromStream(IPropertyStorage *iface)
}
if
(
stat
.
cbSize
.
u
.
LowPart
==
0
)
{
/* empty stream is okay
, we might be being called from Create
*/
/* empty stream is okay */
hr
=
S_OK
;
goto
end
;
}
...
...
@@ -1050,6 +1048,10 @@ static HRESULT PropertyStorage_ReadFromStream(IPropertyStorage *iface)
hr
=
STG_E_INVALIDHEADER
;
goto
end
;
}
seek
.
QuadPart
=
0
;
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
PropertyStorage_ReadHeaderFromStream
(
This
->
stm
,
&
hdr
);
/* I've only seen reserved == 1, but the article says I shouldn't disallow
* higher values.
...
...
@@ -1109,6 +1111,7 @@ static HRESULT PropertyStorage_ReadFromStream(IPropertyStorage *iface)
sizeof
(
PROPERTYSECTIONHEADER
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
TRACE
(
"Reading %ld properties:
\n
"
,
sectionHdr
.
cProperties
);
for
(
i
=
0
;
SUCCEEDED
(
hr
)
&&
i
<
sectionHdr
.
cProperties
;
i
++
)
{
PROPERTYIDOFFSET
*
idOffset
=
(
PROPERTYIDOFFSET
*
)(
buf
+
...
...
@@ -1130,18 +1133,17 @@ static HRESULT PropertyStorage_ReadFromStream(IPropertyStorage *iface)
* later.
*/
dictOffset
=
idOffset
->
dwOffset
;
TRACE
(
"Dictionary offset is %ld
\n
"
,
dictOffset
);
}
else
{
DWORD
type
;
PROPVARIANT
prop
;
StorageUtl_ReadDWord
(
buf
,
idOffset
->
dwOffset
-
sizeof
(
PROPERTYSECTIONHEADER
),
&
type
);
if
(
SUCCEEDED
(
PropertyStorage_ReadProperty
(
&
prop
,
type
,
buf
+
idOffset
->
dwOffset
-
sizeof
(
PROPERTYSECTIONHEADER
)
+
sizeof
(
DWORD
))))
if
(
SUCCEEDED
(
PropertyStorage_ReadProperty
(
&
prop
,
buf
+
idOffset
->
dwOffset
-
sizeof
(
PROPERTYSECTIONHEADER
))))
{
TRACE
(
"Read property with ID 0x%08lx, type %d
\n
"
,
idOffset
->
propid
,
prop
.
vt
);
switch
(
idOffset
->
propid
)
{
case
PID_CODEPAGE
:
...
...
@@ -1178,7 +1180,7 @@ static HRESULT PropertyStorage_ReadFromStream(IPropertyStorage *iface)
This
->
locale
=
LOCALE_SYSTEM_DEFAULT
;
TRACE
(
"Code page is %d, locale is %ld
\n
"
,
This
->
codePage
,
This
->
locale
);
if
(
dictOffset
)
PropertyStorage_ReadDictionary
(
This
,
hr
=
PropertyStorage_ReadDictionary
(
This
,
buf
+
dictOffset
-
sizeof
(
PROPERTYSECTIONHEADER
));
end:
...
...
@@ -1195,42 +1197,597 @@ end:
return
hr
;
}
static
HRESULT
PropertyStorage_WriteToStream
(
IPropertyStorage
*
iface
)
static
void
PropertyStorage_MakeHeader
(
PropertyStorage_impl
*
This
,
PROPERTYSETHEADER
*
hdr
)
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
assert
(
This
);
assert
(
hdr
);
StorageUtl_WriteWord
((
BYTE
*
)
&
hdr
->
wByteOrder
,
0
,
PROPSETHDR_BYTEORDER_MAGIC
);
/* FIXME: should be able to write format 0 property sets too, depending
* on whether I have too long string names or if case-sensitivity is set.
* For now always write format 1.
*/
StorageUtl_WriteWord
((
BYTE
*
)
&
hdr
->
wFormat
,
0
,
1
);
StorageUtl_WriteDWord
((
BYTE
*
)
&
hdr
->
dwOSVer
,
0
,
This
->
originatorOS
);
StorageUtl_WriteGUID
((
BYTE
*
)
&
hdr
->
clsid
,
0
,
&
This
->
clsid
);
StorageUtl_WriteDWord
((
BYTE
*
)
&
hdr
->
reserved
,
0
,
1
);
}
static
void
PropertyStorage_MakeFmtIdOffset
(
PropertyStorage_impl
*
This
,
FORMATIDOFFSET
*
fmtOffset
)
{
assert
(
This
);
assert
(
fmtOffset
);
StorageUtl_WriteGUID
((
BYTE
*
)
fmtOffset
,
0
,
&
This
->
fmtid
);
StorageUtl_WriteDWord
((
BYTE
*
)
fmtOffset
,
offsetof
(
FORMATIDOFFSET
,
dwOffset
),
sizeof
(
PROPERTYSETHEADER
)
+
sizeof
(
FORMATIDOFFSET
));
}
static
void
PropertyStorage_MakeSectionHdr
(
DWORD
cbSection
,
DWORD
numProps
,
PROPERTYSECTIONHEADER
*
hdr
)
{
assert
(
hdr
);
StorageUtl_WriteDWord
((
BYTE
*
)
hdr
,
0
,
cbSection
);
StorageUtl_WriteDWord
((
BYTE
*
)
hdr
,
offsetof
(
PROPERTYSECTIONHEADER
,
cProperties
),
numProps
);
}
static
void
PropertyStorage_MakePropertyIdOffset
(
DWORD
propid
,
DWORD
dwOffset
,
PROPERTYIDOFFSET
*
propIdOffset
)
{
assert
(
propIdOffset
);
StorageUtl_WriteDWord
((
BYTE
*
)
propIdOffset
,
0
,
propid
);
StorageUtl_WriteDWord
((
BYTE
*
)
propIdOffset
,
offsetof
(
PROPERTYIDOFFSET
,
dwOffset
),
dwOffset
);
}
struct
DictionaryClosure
{
HRESULT
hr
;
DWORD
bytesWritten
;
};
static
BOOL
PropertyStorage_DictionaryWriter
(
const
void
*
key
,
const
void
*
value
,
void
*
extra
,
void
*
closure
)
{
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
extra
;
struct
DictionaryClosure
*
c
=
(
struct
DictionaryClosure
*
)
closure
;
DWORD
propid
;
ULONG
count
;
assert
(
key
);
assert
(
This
);
assert
(
closure
);
StorageUtl_WriteDWord
((
LPBYTE
)
&
propid
,
0
,
(
DWORD
)
value
);
c
->
hr
=
IStream_Write
(
This
->
stm
,
&
propid
,
sizeof
(
propid
),
&
count
);
if
(
FAILED
(
c
->
hr
))
goto
end
;
c
->
bytesWritten
+=
sizeof
(
DWORD
);
if
(
This
->
codePage
==
CP_UNICODE
)
{
DWORD
keyLen
,
pad
=
0
;
StorageUtl_WriteDWord
((
LPBYTE
)
&
keyLen
,
0
,
(
lstrlenW
((
LPWSTR
)
key
)
+
1
)
*
sizeof
(
WCHAR
));
c
->
hr
=
IStream_Write
(
This
->
stm
,
&
keyLen
,
sizeof
(
keyLen
),
&
count
);
if
(
FAILED
(
c
->
hr
))
goto
end
;
c
->
bytesWritten
+=
sizeof
(
DWORD
);
/* FIXME: endian-convert every char (yuck) */
c
->
hr
=
IStream_Write
(
This
->
stm
,
key
,
keyLen
,
&
count
);
if
(
FAILED
(
c
->
hr
))
goto
end
;
c
->
bytesWritten
+=
keyLen
;
if
(
keyLen
%
sizeof
(
DWORD
))
{
c
->
hr
=
IStream_Write
(
This
->
stm
,
&
pad
,
sizeof
(
DWORD
)
-
keyLen
%
sizeof
(
DWORD
),
&
count
);
if
(
FAILED
(
c
->
hr
))
goto
end
;
c
->
bytesWritten
+=
sizeof
(
DWORD
)
-
keyLen
%
sizeof
(
DWORD
);
}
}
else
{
int
len
=
WideCharToMultiByte
(
This
->
codePage
,
0
,
(
LPWSTR
)
key
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
LPBYTE
buf
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
);
DWORD
dwLen
;
if
(
!
buf
)
{
c
->
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
/* FIXME: endian-convert multibyte chars? Ick! */
WideCharToMultiByte
(
This
->
codePage
,
0
,
(
LPWSTR
)
key
,
-
1
,
buf
,
len
,
NULL
,
NULL
);
StorageUtl_WriteDWord
((
LPBYTE
)
&
dwLen
,
0
,
len
);
c
->
hr
=
IStream_Write
(
This
->
stm
,
&
dwLen
,
sizeof
(
dwLen
),
&
count
);
if
(
FAILED
(
c
->
hr
))
{
HeapFree
(
GetProcessHeap
(),
0
,
buf
);
goto
end
;
}
c
->
bytesWritten
+=
sizeof
(
DWORD
);
c
->
hr
=
IStream_Write
(
This
->
stm
,
buf
,
len
,
&
count
);
if
(
FAILED
(
c
->
hr
))
{
HeapFree
(
GetProcessHeap
(),
0
,
buf
);
goto
end
;
}
c
->
bytesWritten
+=
len
;
HeapFree
(
GetProcessHeap
(),
0
,
buf
);
}
end:
return
SUCCEEDED
(
c
->
hr
);
}
#define SECTIONHEADER_OFFSET sizeof(PROPERTYSETHEADER) + sizeof(FORMATIDOFFSET)
/* Writes the dictionary to the stream. Assumes without checking that the
* dictionary isn't empty.
*/
static
HRESULT
PropertyStorage_WriteDictionaryToStream
(
PropertyStorage_impl
*
This
,
DWORD
*
sectionOffset
)
{
HRESULT
hr
;
LARGE_INTEGER
seek
;
PROPERTYIDOFFSET
propIdOffset
;
ULONG
count
;
DWORD
dwTemp
;
struct
DictionaryClosure
closure
;
assert
(
This
);
assert
(
sectionOffset
);
/* The dictionary's always the first property written, so seek to its
* spot.
*/
seek
.
QuadPart
=
SECTIONHEADER_OFFSET
+
sizeof
(
PROPERTYSECTIONHEADER
);
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
PropertyStorage_MakePropertyIdOffset
(
PID_DICTIONARY
,
*
sectionOffset
,
&
propIdOffset
);
hr
=
IStream_Write
(
This
->
stm
,
&
propIdOffset
,
sizeof
(
propIdOffset
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
seek
.
QuadPart
=
SECTIONHEADER_OFFSET
+
*
sectionOffset
;
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
StorageUtl_WriteDWord
((
LPBYTE
)
&
dwTemp
,
0
,
dictionary_num_entries
(
This
->
name_to_propid
));
hr
=
IStream_Write
(
This
->
stm
,
&
dwTemp
,
sizeof
(
dwTemp
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
*
sectionOffset
+=
sizeof
(
dwTemp
);
closure
.
hr
=
S_OK
;
closure
.
bytesWritten
=
0
;
dictionary_enumerate
(
This
->
name_to_propid
,
PropertyStorage_DictionaryWriter
,
&
closure
);
hr
=
closure
.
hr
;
if
(
FAILED
(
hr
))
goto
end
;
*
sectionOffset
+=
closure
.
bytesWritten
;
if
(
closure
.
bytesWritten
%
sizeof
(
DWORD
))
{
TRACE
(
"adding %ld bytes of padding
\n
"
,
sizeof
(
DWORD
)
-
closure
.
bytesWritten
%
sizeof
(
DWORD
));
*
sectionOffset
+=
sizeof
(
DWORD
)
-
closure
.
bytesWritten
%
sizeof
(
DWORD
);
}
end:
return
hr
;
}
static
HRESULT
PropertyStorage_WritePropertyToStream
(
PropertyStorage_impl
*
This
,
DWORD
propNum
,
DWORD
propid
,
PROPVARIANT
*
var
,
DWORD
*
sectionOffset
)
{
HRESULT
hr
;
LARGE_INTEGER
seek
;
PROPERTYIDOFFSET
propIdOffset
;
ULONG
count
;
DWORD
dwType
,
bytesWritten
;
assert
(
This
);
assert
(
var
);
assert
(
sectionOffset
);
TRACE
(
"%p, %ld, 0x%08lx, (%d), (%ld)
\n
"
,
This
,
propNum
,
propid
,
var
->
vt
,
*
sectionOffset
);
seek
.
QuadPart
=
SECTIONHEADER_OFFSET
+
sizeof
(
PROPERTYSECTIONHEADER
)
+
propNum
*
sizeof
(
PROPERTYIDOFFSET
);
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
PropertyStorage_MakePropertyIdOffset
(
propid
,
*
sectionOffset
,
&
propIdOffset
);
hr
=
IStream_Write
(
This
->
stm
,
&
propIdOffset
,
sizeof
(
propIdOffset
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
seek
.
QuadPart
=
SECTIONHEADER_OFFSET
+
*
sectionOffset
;
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
StorageUtl_WriteDWord
((
LPBYTE
)
&
dwType
,
0
,
var
->
vt
);
hr
=
IStream_Write
(
This
->
stm
,
&
dwType
,
sizeof
(
dwType
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
*
sectionOffset
+=
sizeof
(
dwType
);
switch
(
var
->
vt
)
{
case
VT_EMPTY
:
case
VT_NULL
:
bytesWritten
=
0
;
break
;
case
VT_I1
:
case
VT_UI1
:
hr
=
IStream_Write
(
This
->
stm
,
&
var
->
u
.
cVal
,
sizeof
(
var
->
u
.
cVal
),
&
count
);
bytesWritten
=
count
;
break
;
case
VT_I2
:
case
VT_UI2
:
{
WORD
wTemp
;
StorageUtl_WriteWord
((
LPBYTE
)
&
wTemp
,
0
,
var
->
u
.
iVal
);
hr
=
IStream_Write
(
This
->
stm
,
&
wTemp
,
sizeof
(
wTemp
),
&
count
);
bytesWritten
=
count
;
break
;
}
case
VT_I4
:
case
VT_UI4
:
{
DWORD
dwTemp
;
StorageUtl_WriteDWord
((
LPBYTE
)
&
dwTemp
,
0
,
var
->
u
.
lVal
);
hr
=
IStream_Write
(
This
->
stm
,
&
dwTemp
,
sizeof
(
dwTemp
),
&
count
);
bytesWritten
=
count
;
break
;
}
case
VT_LPSTR
:
{
DWORD
len
,
dwTemp
;
if
(
This
->
codePage
==
CP_UNICODE
)
len
=
(
lstrlenW
(
var
->
u
.
pwszVal
)
+
1
)
*
sizeof
(
WCHAR
);
else
len
=
lstrlenA
(
var
->
u
.
pszVal
)
+
1
;
StorageUtl_WriteDWord
((
LPBYTE
)
&
dwTemp
,
0
,
len
);
hr
=
IStream_Write
(
This
->
stm
,
&
dwTemp
,
sizeof
(
dwTemp
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
IStream_Write
(
This
->
stm
,
var
->
u
.
pszVal
,
len
,
&
count
);
bytesWritten
=
count
+
sizeof
(
DWORD
);
break
;
}
case
VT_LPWSTR
:
{
DWORD
len
=
lstrlenW
(
var
->
u
.
pwszVal
)
+
1
,
dwTemp
;
StorageUtl_WriteDWord
((
LPBYTE
)
&
dwTemp
,
0
,
len
);
hr
=
IStream_Write
(
This
->
stm
,
&
dwTemp
,
sizeof
(
dwTemp
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
IStream_Write
(
This
->
stm
,
var
->
u
.
pwszVal
,
len
*
sizeof
(
WCHAR
),
&
count
);
bytesWritten
=
count
+
sizeof
(
DWORD
);
break
;
}
default:
FIXME
(
"unsupported type: %d
\n
"
,
var
->
vt
);
return
STG_E_INVALIDPARAMETER
;
}
if
(
SUCCEEDED
(
hr
))
{
*
sectionOffset
+=
bytesWritten
;
if
(
bytesWritten
%
sizeof
(
DWORD
))
{
TRACE
(
"adding %ld bytes of padding
\n
"
,
sizeof
(
DWORD
)
-
bytesWritten
%
sizeof
(
DWORD
));
*
sectionOffset
+=
sizeof
(
DWORD
)
-
bytesWritten
%
sizeof
(
DWORD
);
}
}
end:
return
hr
;
}
struct
PropertyClosure
{
HRESULT
hr
;
DWORD
propNum
;
DWORD
*
sectionOffset
;
};
static
BOOL
PropertyStorage_PropertiesWriter
(
const
void
*
key
,
const
void
*
value
,
void
*
extra
,
void
*
closure
)
{
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
extra
;
struct
PropertyClosure
*
c
=
(
struct
PropertyClosure
*
)
closure
;
assert
(
key
);
assert
(
value
);
assert
(
extra
);
assert
(
closure
);
c
->
hr
=
PropertyStorage_WritePropertyToStream
(
This
,
c
->
propNum
++
,
(
DWORD
)
key
,
(
PROPVARIANT
*
)
value
,
c
->
sectionOffset
);
return
SUCCEEDED
(
c
->
hr
);
}
static
HRESULT
PropertyStorage_WritePropertiesToStream
(
PropertyStorage_impl
*
This
,
DWORD
startingPropNum
,
DWORD
*
sectionOffset
)
{
struct
PropertyClosure
closure
;
assert
(
This
);
assert
(
sectionOffset
);
closure
.
hr
=
S_OK
;
closure
.
propNum
=
startingPropNum
;
closure
.
sectionOffset
=
sectionOffset
;
dictionary_enumerate
(
This
->
propid_to_prop
,
PropertyStorage_PropertiesWriter
,
&
closure
);
return
closure
.
hr
;
}
static
HRESULT
PropertyStorage_WriteHeadersToStream
(
PropertyStorage_impl
*
This
)
{
HRESULT
hr
;
ULONG
count
=
0
;
LARGE_INTEGER
seek
=
{
{
0
}
};
PROPERTYSETHEADER
hdr
;
FORMATIDOFFSET
fmtOffset
;
assert
(
This
);
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
PropertyStorage_MakeHeader
(
This
,
&
hdr
);
hr
=
IStream_Write
(
This
->
stm
,
&
hdr
,
sizeof
(
hdr
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
if
(
count
!=
sizeof
(
hdr
))
{
hr
=
STG_E_WRITEFAULT
;
goto
end
;
}
PropertyStorage_MakeFmtIdOffset
(
This
,
&
fmtOffset
);
hr
=
IStream_Write
(
This
->
stm
,
&
fmtOffset
,
sizeof
(
fmtOffset
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
if
(
count
!=
sizeof
(
fmtOffset
))
{
hr
=
STG_E_WRITEFAULT
;
goto
end
;
}
hr
=
S_OK
;
end:
return
hr
;
}
static
HRESULT
PropertyStorage_WriteToStream
(
PropertyStorage_impl
*
This
)
{
PROPERTYSECTIONHEADER
sectionHdr
;
HRESULT
hr
;
ULONG
count
;
LARGE_INTEGER
seek
;
DWORD
numProps
,
prop
,
sectionOffset
,
dwTemp
;
PROPVARIANT
var
;
assert
(
This
);
PropertyStorage_WriteHeadersToStream
(
This
);
/* Count properties. Always at least one property, the code page */
numProps
=
1
;
if
(
dictionary_num_entries
(
This
->
name_to_propid
))
numProps
++
;
if
(
This
->
locale
!=
LOCALE_SYSTEM_DEFAULT
)
numProps
++
;
if
(
This
->
grfFlags
&
PROPSETFLAG_CASE_SENSITIVE
)
numProps
++
;
numProps
+=
dictionary_num_entries
(
This
->
propid_to_prop
);
/* Write section header with 0 bytes right now, I'll adjust it after
* writing properties.
*/
PropertyStorage_MakeSectionHdr
(
0
,
numProps
,
&
sectionHdr
);
seek
.
QuadPart
=
SECTIONHEADER_OFFSET
;
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
IStream_Write
(
This
->
stm
,
&
sectionHdr
,
sizeof
(
sectionHdr
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
prop
=
0
;
sectionOffset
=
sizeof
(
PROPERTYSECTIONHEADER
)
+
numProps
*
sizeof
(
PROPERTYIDOFFSET
);
if
(
dictionary_num_entries
(
This
->
name_to_propid
))
{
prop
++
;
hr
=
PropertyStorage_WriteDictionaryToStream
(
This
,
&
sectionOffset
);
if
(
FAILED
(
hr
))
goto
end
;
}
PropVariantInit
(
&
var
);
var
.
vt
=
VT_I2
;
var
.
u
.
iVal
=
This
->
codePage
;
hr
=
PropertyStorage_WritePropertyToStream
(
This
,
prop
++
,
PID_CODEPAGE
,
&
var
,
&
sectionOffset
);
if
(
FAILED
(
hr
))
goto
end
;
if
(
This
->
locale
!=
LOCALE_SYSTEM_DEFAULT
)
{
var
.
vt
=
VT_I4
;
var
.
u
.
lVal
=
This
->
locale
;
hr
=
PropertyStorage_WritePropertyToStream
(
This
,
prop
++
,
PID_LOCALE
,
&
var
,
&
sectionOffset
);
if
(
FAILED
(
hr
))
goto
end
;
}
if
(
This
->
grfFlags
&
PROPSETFLAG_CASE_SENSITIVE
)
{
var
.
vt
=
VT_I4
;
var
.
u
.
lVal
=
1
;
hr
=
PropertyStorage_WritePropertyToStream
(
This
,
prop
++
,
PID_BEHAVIOR
,
&
var
,
&
sectionOffset
);
if
(
FAILED
(
hr
))
goto
end
;
}
hr
=
PropertyStorage_WritePropertiesToStream
(
This
,
prop
,
&
sectionOffset
);
if
(
FAILED
(
hr
))
goto
end
;
/* Now write the byte count of the section */
seek
.
QuadPart
=
SECTIONHEADER_OFFSET
;
hr
=
IStream_Seek
(
This
->
stm
,
seek
,
STREAM_SEEK_SET
,
NULL
);
if
(
FAILED
(
hr
))
goto
end
;
StorageUtl_WriteDWord
((
LPBYTE
)
&
dwTemp
,
0
,
sectionOffset
);
hr
=
IStream_Write
(
This
->
stm
,
&
dwTemp
,
sizeof
(
dwTemp
),
&
count
);
end:
return
hr
;
}
/***********************************************************************
* PropertyStorage_Construct
*/
static
HRESULT
PropertyStorage_Construct
(
IStream
*
stm
,
REFFMTID
rfmtid
,
DWORD
grfFlags
,
DWORD
grfMode
,
IPropertyStorage
**
pps
)
static
void
PropertyStorage_DestroyDictionaries
(
PropertyStorage_impl
*
This
)
{
assert
(
This
);
dictionary_destroy
(
This
->
name_to_propid
);
This
->
name_to_propid
=
NULL
;
dictionary_destroy
(
This
->
propid_to_name
);
This
->
propid_to_name
=
NULL
;
dictionary_destroy
(
This
->
propid_to_prop
);
This
->
propid_to_prop
=
NULL
;
}
static
HRESULT
PropertyStorage_CreateDictionaries
(
PropertyStorage_impl
*
This
)
{
HRESULT
hr
=
S_OK
;
assert
(
This
);
This
->
name_to_propid
=
dictionary_create
(
PropertyStorage_PropNameCompare
,
PropertyStorage_PropNameDestroy
,
This
);
if
(
!
This
->
name_to_propid
)
{
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
This
->
propid_to_name
=
dictionary_create
(
PropertyStorage_PropCompare
,
NULL
,
This
);
if
(
!
This
->
propid_to_name
)
{
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
This
->
propid_to_prop
=
dictionary_create
(
PropertyStorage_PropCompare
,
PropertyStorage_PropertyDestroy
,
This
);
if
(
!
This
->
propid_to_prop
)
{
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
end:
if
(
FAILED
(
hr
))
PropertyStorage_DestroyDictionaries
(
This
);
return
hr
;
}
static
HRESULT
PropertyStorage_BaseConstruct
(
IStream
*
stm
,
REFFMTID
rfmtid
,
DWORD
grfMode
,
PropertyStorage_impl
**
pps
)
{
HRESULT
hr
=
S_OK
;
assert
(
pps
);
assert
(
rfmtid
);
*
pps
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
**
pps
);
if
(
!
pps
)
return
E_OUTOFMEMORY
;
(
*
pps
)
->
vtbl
=
&
IPropertyStorage_Vtbl
;
(
*
pps
)
->
ref
=
1
;
InitializeCriticalSection
(
&
(
*
pps
)
->
cs
);
(
*
pps
)
->
stm
=
stm
;
memcpy
(
&
(
*
pps
)
->
fmtid
,
rfmtid
,
sizeof
((
*
pps
)
->
fmtid
));
(
*
pps
)
->
grfMode
=
grfMode
;
hr
=
PropertyStorage_CreateDictionaries
(
*
pps
);
return
hr
;
}
static
HRESULT
PropertyStorage_ConstructFromStream
(
IStream
*
stm
,
REFFMTID
rfmtid
,
DWORD
grfMode
,
IPropertyStorage
**
pps
)
{
PropertyStorage_impl
*
ps
;
HRESULT
hr
;
ps
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
*
ps
);
if
(
!
ps
)
return
E_OUTOFMEMORY
;
assert
(
pps
);
hr
=
PropertyStorage_BaseConstruct
(
stm
,
rfmtid
,
grfMode
,
&
ps
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
PropertyStorage_ReadFromStream
(
ps
);
if
(
SUCCEEDED
(
hr
))
{
*
pps
=
(
IPropertyStorage
*
)
ps
;
TRACE
(
"PropertyStorage %p constructed
\n
"
,
ps
);
hr
=
S_OK
;
}
else
{
PropertyStorage_DestroyDictionaries
(
ps
);
HeapFree
(
GetProcessHeap
(),
0
,
ps
);
}
}
return
hr
;
}
ps
->
vtbl
=
&
IPropertyStorage_Vtbl
;
ps
->
ref
=
1
;
InitializeCriticalSection
(
&
ps
->
cs
);
ps
->
stm
=
stm
;
memcpy
(
&
ps
->
fmtid
,
rfmtid
,
sizeof
(
ps
->
fmtid
));
ps
->
grfFlags
=
grfFlags
;
ps
->
grfMode
=
grfMode
;
static
HRESULT
PropertyStorage_ConstructEmpty
(
IStream
*
stm
,
REFFMTID
rfmtid
,
DWORD
grfFlags
,
DWORD
grfMode
,
IPropertyStorage
**
pps
)
{
PropertyStorage_impl
*
ps
;
HRESULT
hr
;
hr
=
PropertyStorage_ReadFromStream
((
IPropertyStorage
*
)
ps
);
assert
(
pps
);
hr
=
PropertyStorage_BaseConstruct
(
stm
,
rfmtid
,
grfMode
,
&
ps
);
if
(
SUCCEEDED
(
hr
))
{
ps
->
grfFlags
=
grfFlags
;
/* default to Unicode unless told not to, as specified here:
* http://msdn.microsoft.com/library/en-us/stg/stg/names_in_istorage.asp
*/
if
(
ps
->
grfFlags
&
PROPSETFLAG_ANSI
)
ps
->
codePage
=
GetACP
();
else
ps
->
codePage
=
CP_UNICODE
;
ps
->
locale
=
LOCALE_SYSTEM_DEFAULT
;
TRACE
(
"Code page is %d, locale is %ld
\n
"
,
ps
->
codePage
,
ps
->
locale
);
*
pps
=
(
IPropertyStorage
*
)
ps
;
TRACE
(
"PropertyStorage %p constructed
\n
"
,
ps
);
hr
=
S_OK
;
}
else
HeapFree
(
GetProcessHeap
(),
0
,
ps
);
return
hr
;
}
...
...
@@ -1390,7 +1947,7 @@ static HRESULT WINAPI IPropertySetStorage_fnCreate(
if
(
FAILED
(
r
))
goto
end
;
r
=
PropertyStorage_Construct
(
stm
,
rfmtid
,
grfFlags
,
grfMode
,
ppprstg
);
r
=
PropertyStorage_Construct
Empty
(
stm
,
rfmtid
,
grfFlags
,
grfMode
,
ppprstg
);
end:
TRACE
(
"returning 0x%08lx
\n
"
,
r
);
...
...
@@ -1434,8 +1991,7 @@ static HRESULT WINAPI IPropertySetStorage_fnOpen(
if
(
FAILED
(
r
))
goto
end
;
r
=
PropertyStorage_Construct
(
stm
,
rfmtid
,
PROPSETFLAG_DEFAULT
,
grfMode
,
ppprstg
);
r
=
PropertyStorage_ConstructFromStream
(
stm
,
rfmtid
,
grfMode
,
ppprstg
);
end:
TRACE
(
"returning 0x%08lx
\n
"
,
r
);
...
...
dlls/ole32/tests/stg_prop.c
View file @
c1fe67bc
...
...
@@ -26,7 +26,7 @@
# define U(x) (x)
#endif
/* FIXME: this creates an ANSI storage,
need
try to find conditions under which
/* FIXME: this creates an ANSI storage, try to find conditions under which
* Unicode translation fails
*/
static
void
testProps
(
void
)
...
...
@@ -34,6 +34,7 @@ static void testProps(void)
static
const
WCHAR
szDot
[]
=
{
'.'
,
0
};
static
const
WCHAR
szPrefix
[]
=
{
's'
,
't'
,
'g'
,
0
};
static
const
WCHAR
propName
[]
=
{
'p'
,
'r'
,
'o'
,
'p'
,
0
};
static
const
char
val
[]
=
"l33t auth0r"
;
WCHAR
filename
[
MAX_PATH
];
HRESULT
hr
;
IStorage
*
storage
=
NULL
;
...
...
@@ -58,7 +59,7 @@ static void testProps(void)
&
FMTID_SummaryInformation
,
NULL
,
PROPSETFLAG_ANSI
,
STGM_READWRITE
|
STGM_CREATE
|
STGM_SHARE_EXCLUSIVE
,
&
propertyStorage
);
ok
(
SUCCEEDED
(
hr
),
"
QI -> IPropertyStorag
e failed: 0x%08lx
\n
"
,
hr
);
ok
(
SUCCEEDED
(
hr
),
"
IPropertySetStorage_Creat
e failed: 0x%08lx
\n
"
,
hr
);
hr
=
IPropertyStorage_WriteMultiple
(
propertyStorage
,
0
,
NULL
,
NULL
,
0
);
ok
(
SUCCEEDED
(
hr
),
"WriteMultiple with 0 args failed: 0x%08lx
\n
"
,
hr
);
...
...
@@ -98,7 +99,7 @@ static void testProps(void)
hr
=
IPropertyStorage_WriteMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
,
0
);
ok
(
SUCCEEDED
(
hr
),
"WriteMultiple failed: 0x%08lx
\n
"
,
hr
);
/*
finally,
set one by name */
/* set one by name */
spec
.
ulKind
=
PRSPEC_LPWSTR
;
U
(
spec
).
lpwstr
=
(
LPOLESTR
)
propName
;
U
(
var
).
lVal
=
2
;
...
...
@@ -106,6 +107,14 @@ static void testProps(void)
PID_FIRST_USABLE
);
ok
(
SUCCEEDED
(
hr
),
"WriteMultiple failed: 0x%08lx
\n
"
,
hr
);
/* set a string value */
spec
.
ulKind
=
PRSPEC_PROPID
;
U
(
spec
).
propid
=
PIDSI_AUTHOR
;
var
.
vt
=
VT_LPSTR
;
U
(
var
).
pszVal
=
(
LPSTR
)
val
;
hr
=
IPropertyStorage_WriteMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
,
0
);
ok
(
SUCCEEDED
(
hr
),
"WriteMultiple failed: 0x%08lx
\n
"
,
hr
);
/* check reading */
hr
=
IPropertyStorage_ReadMultiple
(
propertyStorage
,
0
,
NULL
,
NULL
);
ok
(
SUCCEEDED
(
hr
),
"ReadMultiple with 0 args failed: 0x%08lx
\n
"
,
hr
);
...
...
@@ -127,6 +136,14 @@ static void testProps(void)
ok
(
var
.
vt
==
VT_I4
&&
U
(
var
).
lVal
==
2
,
"Didn't get expected type or value for property (got type %d, value %ld)
\n
"
,
var
.
vt
,
U
(
var
).
lVal
);
/* read string value */
spec
.
ulKind
=
PRSPEC_PROPID
;
U
(
spec
).
propid
=
PIDSI_AUTHOR
;
hr
=
IPropertyStorage_ReadMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
);
ok
(
SUCCEEDED
(
hr
),
"ReadMultiple failed: 0x%08lx
\n
"
,
hr
);
ok
(
var
.
vt
==
VT_LPSTR
&&
!
lstrcmpA
(
U
(
var
).
pszVal
,
val
),
"Didn't get expected type or value for property (got type %d, value %s)
\n
"
,
var
.
vt
,
U
(
var
).
pszVal
);
/* check deleting */
hr
=
IPropertyStorage_DeleteMultiple
(
propertyStorage
,
0
,
NULL
);
...
...
@@ -147,6 +164,79 @@ static void testProps(void)
hr
=
IPropertyStorage_ReadMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
);
ok
(
hr
==
S_FALSE
,
"Expected S_FALSE, got 0x%08lx
\n
"
,
hr
);
hr
=
IPropertyStorage_Commit
(
propertyStorage
,
STGC_DEFAULT
);
ok
(
SUCCEEDED
(
hr
),
"Commit failed: 0x%08lx
\n
"
,
hr
);
/* check reverting */
spec
.
ulKind
=
PRSPEC_PROPID
;
U
(
spec
).
propid
=
PID_FIRST_USABLE
;
hr
=
IPropertyStorage_WriteMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
,
0
);
ok
(
SUCCEEDED
(
hr
),
"WriteMultiple failed: 0x%08lx
\n
"
,
hr
);
hr
=
IPropertyStorage_Revert
(
propertyStorage
);
ok
(
SUCCEEDED
(
hr
),
"Revert failed: 0x%08lx
\n
"
,
hr
);
/* now check that it's still not there */
hr
=
IPropertyStorage_ReadMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
);
ok
(
hr
==
S_FALSE
,
"Expected S_FALSE, got 0x%08lx
\n
"
,
hr
);
/* set an integer value again */
spec
.
ulKind
=
PRSPEC_PROPID
;
U
(
spec
).
propid
=
PID_FIRST_USABLE
;
var
.
vt
=
VT_I4
;
U
(
var
).
lVal
=
1
;
hr
=
IPropertyStorage_WriteMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
,
0
);
ok
(
SUCCEEDED
(
hr
),
"WriteMultiple failed: 0x%08lx
\n
"
,
hr
);
/* commit it */
hr
=
IPropertyStorage_Commit
(
propertyStorage
,
STGC_DEFAULT
);
ok
(
SUCCEEDED
(
hr
),
"Commit failed: 0x%08lx
\n
"
,
hr
);
/* set it to a string value */
var
.
vt
=
VT_LPSTR
;
U
(
var
).
pszVal
=
(
LPSTR
)
val
;
hr
=
IPropertyStorage_WriteMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
,
0
);
ok
(
SUCCEEDED
(
hr
),
"WriteMultiple failed: 0x%08lx
\n
"
,
hr
);
/* revert it */
hr
=
IPropertyStorage_Revert
(
propertyStorage
);
ok
(
SUCCEEDED
(
hr
),
"Revert failed: 0x%08lx
\n
"
,
hr
);
/* and make sure it's still an integer */
hr
=
IPropertyStorage_ReadMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
);
ok
(
SUCCEEDED
(
hr
),
"ReadMultiple failed: 0x%08lx
\n
"
,
hr
);
ok
(
var
.
vt
==
VT_I4
&&
U
(
var
).
lVal
==
1
,
"Didn't get expected type or value for property (got type %d, value %ld)
\n
"
,
var
.
vt
,
U
(
var
).
lVal
);
IPropertyStorage_Release
(
propertyStorage
);
propertyStorage
=
NULL
;
IPropertySetStorage_Release
(
propSetStorage
);
propSetStorage
=
NULL
;
IStorage_Release
(
storage
);
storage
=
NULL
;
/* now open it again */
hr
=
StgOpenStorage
(
filename
,
NULL
,
STGM_READWRITE
|
STGM_SHARE_EXCLUSIVE
,
NULL
,
0
,
&
storage
);
ok
(
SUCCEEDED
(
hr
),
"StgOpenStorage failed: 0x%08lx
\n
"
,
hr
);
hr
=
StgCreatePropSetStg
(
storage
,
0
,
&
propSetStorage
);
ok
(
SUCCEEDED
(
hr
),
"StgCreatePropSetStg failed: 0x%08lx
\n
"
,
hr
);
hr
=
IPropertySetStorage_Open
(
propSetStorage
,
&
FMTID_SummaryInformation
,
STGM_READWRITE
|
STGM_SHARE_EXCLUSIVE
,
&
propertyStorage
);
ok
(
SUCCEEDED
(
hr
),
"IPropertySetStorage_Open failed: 0x%08lx
\n
"
,
hr
);
/* check properties again */
spec
.
ulKind
=
PRSPEC_LPWSTR
;
U
(
spec
).
lpwstr
=
(
LPOLESTR
)
propName
;
hr
=
IPropertyStorage_ReadMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
);
ok
(
SUCCEEDED
(
hr
),
"ReadMultiple failed: 0x%08lx
\n
"
,
hr
);
ok
(
var
.
vt
==
VT_I4
&&
U
(
var
).
lVal
==
2
,
"Didn't get expected type or value for property (got type %d, value %ld)
\n
"
,
var
.
vt
,
U
(
var
).
lVal
);
spec
.
ulKind
=
PRSPEC_PROPID
;
U
(
spec
).
propid
=
PIDSI_AUTHOR
;
hr
=
IPropertyStorage_ReadMultiple
(
propertyStorage
,
1
,
&
spec
,
&
var
);
ok
(
SUCCEEDED
(
hr
),
"ReadMultiple failed: 0x%08lx
\n
"
,
hr
);
ok
(
var
.
vt
==
VT_LPSTR
&&
!
lstrcmpA
(
U
(
var
).
pszVal
,
val
),
"Didn't get expected type or value for property (got type %d, value %s)
\n
"
,
var
.
vt
,
U
(
var
).
pszVal
);
IPropertyStorage_Release
(
propertyStorage
);
IPropertySetStorage_Release
(
propSetStorage
);
IStorage_Release
(
storage
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment