Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
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-cw
Commits
be84f8d9
Commit
be84f8d9
authored
Mar 17, 2005
by
Juan Lang
Committed by
Alexandre Julliard
Mar 17, 2005
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Begin implementing IPropertyStorage.
parent
f7560908
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1278 additions
and
48 deletions
+1278
-48
Makefile.in
dlls/ole32/Makefile.in
+2
-1
dictionary.c
dlls/ole32/dictionary.c
+170
-0
dictionary.h
dlls/ole32/dictionary.h
+87
-0
stg_prop.c
dlls/ole32/stg_prop.c
+1019
-47
No files found.
dlls/ole32/Makefile.in
View file @
be84f8d9
...
...
@@ -5,7 +5,7 @@ SRCDIR = @srcdir@
VPATH
=
@srcdir@
MODULE
=
ole32.dll
IMPORTS
=
advapi32 user32 gdi32 rpcrt4 kernel32 ntdll
EXTRALIBS
=
-luuid
EXTRALIBS
=
-luuid
$(LIBUNICODE)
C_SRCS
=
\
antimoniker.c
\
...
...
@@ -15,6 +15,7 @@ C_SRCS = \
compositemoniker.c
\
datacache.c
\
defaulthandler.c
\
dictionary.c
\
errorinfo.c
\
filemoniker.c
\
ftmarshal.c
\
...
...
dlls/ole32/dictionary.c
0 → 100644
View file @
be84f8d9
/* Simple dictionary implementation using a linked list.
* FIXME: a skip list would be faster.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <assert.h>
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "dictionary.h"
struct
dictionary_entry
{
void
*
key
;
void
*
value
;
struct
dictionary_entry
*
next
;
};
struct
dictionary
{
comparefunc
comp
;
destroyfunc
destroy
;
void
*
extra
;
struct
dictionary_entry
*
head
;
};
struct
dictionary
*
dictionary_create
(
comparefunc
c
,
destroyfunc
d
,
void
*
extra
)
{
struct
dictionary
*
ret
;
if
(
!
c
)
return
NULL
;
ret
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
struct
dictionary
));
if
(
ret
)
{
ret
->
comp
=
c
;
ret
->
destroy
=
d
;
ret
->
extra
=
extra
;
ret
->
head
=
NULL
;
}
return
ret
;
}
void
dictionary_destroy
(
struct
dictionary
*
d
)
{
if
(
d
)
{
struct
dictionary_entry
*
p
;
for
(
p
=
d
->
head
;
p
;
)
{
struct
dictionary_entry
*
next
=
p
->
next
;
if
(
d
->
destroy
)
d
->
destroy
(
p
->
key
,
p
->
value
,
d
->
extra
);
HeapFree
(
GetProcessHeap
(),
0
,
p
);
p
=
next
;
}
HeapFree
(
GetProcessHeap
(),
0
,
d
);
}
}
/* Returns the address of the pointer to the node containing k. (It returns
* the address of either h->head or the address of the next member of the
* prior node. It's useful when you want to delete.)
* Assumes h and prev are not NULL.
*/
static
struct
dictionary_entry
**
dictionary_find_internal
(
struct
dictionary
*
d
,
const
void
*
k
)
{
struct
dictionary_entry
**
ret
=
NULL
;
struct
dictionary_entry
*
p
;
assert
(
d
);
/* special case for head containing the desired element */
if
(
d
->
head
&&
d
->
comp
(
k
,
d
->
head
->
key
,
d
->
extra
)
==
0
)
ret
=
&
d
->
head
;
for
(
p
=
d
->
head
;
!
ret
&&
p
&&
p
->
next
;
p
=
p
->
next
)
{
if
(
d
->
comp
(
k
,
p
->
next
->
key
,
d
->
extra
)
==
0
)
ret
=
&
p
->
next
;
}
return
ret
;
}
void
dictionary_insert
(
struct
dictionary
*
d
,
const
void
*
k
,
const
void
*
v
)
{
struct
dictionary_entry
**
prior
;
if
(
!
d
)
return
;
if
((
prior
=
dictionary_find_internal
(
d
,
k
)))
{
if
(
d
->
destroy
)
d
->
destroy
((
*
prior
)
->
key
,
(
*
prior
)
->
value
,
d
->
extra
);
(
*
prior
)
->
key
=
(
void
*
)
k
;
(
*
prior
)
->
value
=
(
void
*
)
v
;
}
else
{
struct
dictionary_entry
*
elem
=
(
struct
dictionary_entry
*
)
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
struct
dictionary_entry
));
if
(
!
elem
)
return
;
elem
->
key
=
(
void
*
)
k
;
elem
->
value
=
(
void
*
)
v
;
elem
->
next
=
d
->
head
;
d
->
head
=
elem
;
}
}
BOOL
dictionary_find
(
struct
dictionary
*
d
,
const
void
*
k
,
void
**
value
)
{
struct
dictionary_entry
**
prior
;
BOOL
ret
=
FALSE
;
if
(
!
d
)
return
FALSE
;
if
(
!
value
)
return
FALSE
;
if
((
prior
=
dictionary_find_internal
(
d
,
k
)))
{
*
value
=
(
*
prior
)
->
value
;
ret
=
TRUE
;
}
return
ret
;
}
void
dictionary_remove
(
struct
dictionary
*
d
,
const
void
*
k
)
{
struct
dictionary_entry
**
prior
,
*
temp
;
if
(
!
d
)
return
;
if
((
prior
=
dictionary_find_internal
(
d
,
k
)))
{
temp
=
*
prior
;
if
(
d
->
destroy
)
d
->
destroy
((
*
prior
)
->
key
,
(
*
prior
)
->
value
,
d
->
extra
);
*
prior
=
(
*
prior
)
->
next
;
HeapFree
(
GetProcessHeap
(),
0
,
temp
);
}
}
void
dictionary_enumerate
(
struct
dictionary
*
d
,
enumeratefunc
e
)
{
struct
dictionary_entry
*
p
;
if
(
!
d
)
return
;
if
(
!
e
)
return
;
for
(
p
=
d
->
head
;
p
;
p
=
p
->
next
)
e
(
p
->
key
,
p
->
value
,
d
->
extra
);
}
dlls/ole32/dictionary.h
0 → 100644
View file @
be84f8d9
/* Simple dictionary
*
* Copyright 2005 Juan Lang
*
* This is a pretty basic dictionary, or map if you prefer. It's not
* thread-safe.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __DICTIONARY_H__
#define __DICTIONARY_H__
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
struct
dictionary
;
/* Returns whether key a is less than, equal to, or greater than key b, in
* the same way (a - b) would for integers or strcmp(a, b) would for ANSI
* strings.
*/
typedef
int
(
*
comparefunc
)(
const
void
*
a
,
const
void
*
b
,
void
*
extra
);
/* Called for every element removed from the dictionary. See
* dictionary_destroy, dictionary_insert, and dictionary_remove.
*/
typedef
void
(
*
destroyfunc
)(
void
*
k
,
void
*
v
,
void
*
extra
);
/* Called for each element in the dictionary. Return FALSE if you don't want
* to enumerate any more.
*/
typedef
BOOL
(
*
enumeratefunc
)(
const
void
*
k
,
const
void
*
d
,
void
*
extra
);
/* Constructs a dictionary, using c as a comparison function for keys.
* If d is not NULL, it will be called whenever an item is about to be removed
* from the table, for example when dictionary_remove is called for a key, or
* when dictionary_destroy is called.
* extra is passed to c (and d, if it's provided).
* Assumes c is not NULL.
*/
struct
dictionary
*
dictionary_create
(
comparefunc
c
,
destroyfunc
d
,
void
*
extra
);
/* Assumes d is not NULL. */
void
dictionary_destroy
(
struct
dictionary
*
d
);
/* Sets an element with key k and value v to the dictionary. If a value
* already exists with key k, its value is replaced, and the destroyfunc (if
* set) is called for the previous item.
* Assumes k and v can be bitwise-copied.
* Both k and v are allowed to be NULL, in case you want to use integer
* values for either the key or the value.
* Assumes d is not NULL.
*/
void
dictionary_insert
(
struct
dictionary
*
d
,
const
void
*
k
,
const
void
*
v
);
/* If a value with key k has been inserted into the dictionary, *v is set
* to its associated value. Returns FALSE if the key is not found, and TRUE
* if it is. *v is undefined if it returns FALSE. (It is not set to NULL,
* because this dictionary doesn't prevent you from using NULL as a value
* value; see dictionary_insert.)
* Assumes d and v are not NULL.
*/
BOOL
dictionary_find
(
struct
dictionary
*
d
,
const
void
*
k
,
void
**
v
);
/* Removes the element with key k from the dictionary. Calls the destroyfunc
* for the dictionary with the element if found (so you may destroy it if it's
* dynamically allocated.)
* Assumes d is not NULL.
*/
void
dictionary_remove
(
struct
dictionary
*
d
,
const
void
*
k
);
void
dictionary_enumerate
(
struct
dictionary
*
d
,
enumeratefunc
e
);
#endif
/* ndef __DICTIONARY_H__ */
dlls/ole32/stg_prop.c
View file @
be84f8d9
...
...
@@ -9,6 +9,7 @@
* 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
...
...
@@ -23,6 +24,24 @@
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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: There's a lot missing in here. Biggies:
* - 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
* 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.
* There are lots more unimplemented features, see FIXMEs below.
*/
#include <assert.h>
...
...
@@ -41,7 +60,7 @@
#include "winuser.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "dictionary.h"
#include "storage32.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
storage
);
...
...
@@ -50,6 +69,54 @@ WINE_DEFAULT_DEBUG_CHANNEL(storage);
#define _ICOM_THIS_From_IPropertySetStorage(class, name) \
class* This = (class*)(((char*)name)-_IPropertySetStorage_Offset)
/* 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
/* 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
;
}
PROPERTYIDOFFSET
;
/* 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_WriteToStream
(
IPropertyStorage
*
iface
);
static
IPropertyStorageVtbl
IPropertyStorage_Vtbl
;
/***********************************************************************
...
...
@@ -59,7 +126,20 @@ typedef struct tagPropertyStorage_impl
{
IPropertyStorageVtbl
*
vtbl
;
DWORD
ref
;
CRITICAL_SECTION
cs
;
IStream
*
stm
;
BOOL
dirty
;
FMTID
fmtid
;
CLSID
clsid
;
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
;
}
PropertyStorage_impl
;
/************************************************************************
...
...
@@ -112,11 +192,50 @@ static ULONG WINAPI IPropertyStorage_fnRelease(
{
TRACE
(
"Destroying %p
\n
"
,
This
);
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
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
return
ref
;
}
static
PROPVARIANT
*
PropertyStorage_FindProperty
(
PropertyStorage_impl
*
This
,
DWORD
propid
)
{
PROPVARIANT
*
ret
=
NULL
;
if
(
!
This
)
return
NULL
;
dictionary_find
(
This
->
propid_to_prop
,
(
void
*
)
propid
,
(
void
**
)
&
ret
);
return
ret
;
}
static
PROPVARIANT
*
PropertyStorage_FindPropertyByName
(
PropertyStorage_impl
*
This
,
LPCWSTR
name
)
{
PROPVARIANT
*
ret
=
NULL
;
PROPID
propid
;
if
(
!
This
||
!
name
)
return
NULL
;
if
(
dictionary_find
(
This
->
name_to_propid
,
name
,
(
void
**
)
&
propid
))
ret
=
PropertyStorage_FindProperty
(
This
,
(
PROPID
)
propid
);
return
ret
;
}
static
LPWSTR
PropertyStorage_FindPropertyNameById
(
PropertyStorage_impl
*
This
,
DWORD
propid
)
{
LPWSTR
ret
=
NULL
;
if
(
!
This
)
return
NULL
;
dictionary_find
(
This
->
propid_to_name
,
(
void
*
)
propid
,
(
void
**
)
&
ret
);
return
ret
;
}
/************************************************************************
* IPropertyStorage_fnReadMultiple (IPropertyStorage)
*/
...
...
@@ -126,8 +245,64 @@ static HRESULT WINAPI IPropertyStorage_fnReadMultiple(
const
PROPSPEC
rgpspec
[],
PROPVARIANT
rgpropvar
[])
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
HRESULT
hr
=
S_OK
;
ULONG
i
;
TRACE
(
"(%p, %ld, %p, %p)
\n
"
,
iface
,
cpspec
,
rgpspec
,
rgpropvar
);
if
(
!
This
)
return
E_INVALIDARG
;
if
(
cpspec
&&
(
!
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
)
PropVariantCopy
(
&
rgpropvar
[
i
],
prop
);
}
else
{
PROPVARIANT
*
prop
=
PropertyStorage_FindProperty
(
This
,
rgpspec
[
i
].
u
.
propid
);
if
(
prop
)
PropVariantCopy
(
&
rgpropvar
[
i
],
prop
);
}
}
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
static
HRESULT
PropertyStorage_StorePropWithId
(
PropertyStorage_impl
*
This
,
PROPID
propid
,
const
PROPVARIANT
*
propvar
)
{
HRESULT
hr
=
S_OK
;
PROPVARIANT
*
prop
=
PropertyStorage_FindProperty
(
This
,
propid
);
if
(
prop
)
{
PropVariantClear
(
prop
);
PropVariantCopy
(
prop
,
propvar
);
}
else
{
prop
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
PROPVARIANT
));
if
(
prop
)
{
PropVariantCopy
(
prop
,
propvar
);
dictionary_insert
(
This
->
propid_to_prop
,
(
void
*
)
propid
,
prop
);
}
else
hr
=
STG_E_INSUFFICIENTMEMORY
;
}
return
hr
;
}
/************************************************************************
...
...
@@ -140,8 +315,65 @@ static HRESULT WINAPI IPropertyStorage_fnWriteMultiple(
const
PROPVARIANT
rgpropvar
[],
PROPID
propidNameFirst
)
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
HRESULT
hr
=
S_OK
;
ULONG
i
;
TRACE
(
"(%p, %ld, %p, %p)
\n
"
,
iface
,
cpspec
,
rgpspec
,
rgpropvar
);
if
(
!
This
)
return
E_INVALIDARG
;
if
(
cpspec
&&
(
!
rgpspec
||
!
rgpropvar
))
return
E_INVALIDARG
;
if
(
!
(
This
->
grfMode
&
STGM_READWRITE
))
return
STG_E_ACCESSDENIED
;
EnterCriticalSection
(
&
This
->
cs
);
This
->
dirty
=
TRUE
;
This
->
originatorOS
=
(
DWORD
)
MAKELONG
(
LOWORD
(
GetVersion
()),
PROPSETHDR_OSVER_KIND_WIN32
)
;
for
(
i
=
0
;
i
<
cpspec
;
i
++
)
{
if
(
rgpspec
[
i
].
ulKind
==
PRSPEC_LPWSTR
)
{
PROPVARIANT
*
prop
=
PropertyStorage_FindPropertyByName
(
This
,
rgpspec
[
i
].
u
.
lpwstr
);
if
(
prop
)
PropVariantCopy
(
prop
,
&
rgpropvar
[
i
]);
else
{
if
(
propidNameFirst
<
PID_FIRST_USABLE
||
propidNameFirst
>=
PID_MIN_READONLY
)
hr
=
STG_E_INVALIDPARAMETER
;
else
{
PROPID
nextId
=
max
(
propidNameFirst
,
This
->
highestProp
+
1
);
size_t
len
=
strlenW
(
rgpspec
[
i
].
u
.
lpwstr
)
+
1
;
LPWSTR
name
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
));
strcpyW
(
name
,
rgpspec
[
i
].
u
.
lpwstr
);
dictionary_insert
(
This
->
name_to_propid
,
name
,
(
void
*
)
nextId
);
dictionary_insert
(
This
->
propid_to_name
,
(
void
*
)
nextId
,
name
);
This
->
highestProp
=
nextId
;
hr
=
PropertyStorage_StorePropWithId
(
This
,
nextId
,
&
rgpropvar
[
i
]);
}
}
}
else
{
/* FIXME: certain propid's have special behavior. E.g., you can't
* set propid 0, and setting PID_BEHAVIOR affects the
* case-sensitivity.
*/
hr
=
PropertyStorage_StorePropWithId
(
This
,
rgpspec
[
i
].
u
.
propid
,
&
rgpropvar
[
i
]);
}
}
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
/************************************************************************
...
...
@@ -152,8 +384,42 @@ static HRESULT WINAPI IPropertyStorage_fnDeleteMultiple(
ULONG
cpspec
,
const
PROPSPEC
rgpspec
[])
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
ULONG
i
;
HRESULT
hr
;
TRACE
(
"(%p, %ld, %p)
\n
"
,
iface
,
cpspec
,
rgpspec
);
if
(
!
This
)
return
E_INVALIDARG
;
if
(
!
rgpspec
)
return
E_INVALIDARG
;
if
(
!
(
This
->
grfMode
&
STGM_READWRITE
))
return
STG_E_ACCESSDENIED
;
hr
=
S_OK
;
EnterCriticalSection
(
&
This
->
cs
);
for
(
i
=
0
;
i
<
cpspec
;
i
++
)
{
if
(
rgpspec
[
i
].
ulKind
==
PRSPEC_LPWSTR
)
{
PROPID
propid
;
if
(
dictionary_find
(
This
->
name_to_propid
,
(
void
*
)
rgpspec
[
i
].
u
.
lpwstr
,
(
void
**
)
&
propid
))
dictionary_remove
(
This
->
propid_to_prop
,
(
void
*
)
propid
);
}
else
{
/* FIXME: certain propid's have special meaning. For example,
* removing propid 0 is supposed to remove the dictionary, and
* removing PID_BEHAVIOR should change this to a case-insensitive
* property set. Unknown "read-only" propid's should be ignored.
*/
dictionary_remove
(
This
->
propid_to_prop
,
(
void
*
)
rgpspec
[
i
].
u
.
propid
);
}
}
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
/************************************************************************
...
...
@@ -165,8 +431,40 @@ static HRESULT WINAPI IPropertyStorage_fnReadPropertyNames(
const
PROPID
rgpropid
[],
LPOLESTR
rglpwstrName
[])
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
ULONG
i
;
HRESULT
hr
;
TRACE
(
"(%p, %ld, %p, %p)
\n
"
,
iface
,
cpropid
,
rgpropid
,
rglpwstrName
);
if
(
!
This
)
return
E_INVALIDARG
;
if
(
cpropid
&&
(
!
rgpropid
||
!
rglpwstrName
))
return
E_INVALIDARG
;
/* MSDN says S_FALSE is returned if no strings matching rgpropid are found,
* default to that
*/
hr
=
S_FALSE
;
EnterCriticalSection
(
&
This
->
cs
);
for
(
i
=
0
;
i
<
cpropid
&&
SUCCEEDED
(
hr
);
i
++
)
{
LPWSTR
name
=
PropertyStorage_FindPropertyNameById
(
This
,
rgpropid
[
i
]);
if
(
name
)
{
size_t
len
=
lstrlenW
(
name
);
hr
=
S_OK
;
rglpwstrName
[
i
]
=
CoTaskMemAlloc
((
len
+
1
)
*
sizeof
(
WCHAR
));
if
(
rglpwstrName
)
memcpy
(
rglpwstrName
,
name
,
(
len
+
1
)
*
sizeof
(
WCHAR
));
else
hr
=
STG_E_INSUFFICIENTMEMORY
;
}
else
rglpwstrName
[
i
]
=
NULL
;
}
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
/************************************************************************
...
...
@@ -178,8 +476,33 @@ static HRESULT WINAPI IPropertyStorage_fnWritePropertyNames(
const
PROPID
rgpropid
[],
const
LPOLESTR
rglpwstrName
[])
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
ULONG
i
;
HRESULT
hr
;
TRACE
(
"(%p, %ld, %p, %p)
\n
"
,
iface
,
cpropid
,
rgpropid
,
rglpwstrName
);
if
(
!
This
)
return
E_INVALIDARG
;
if
(
cpropid
&&
(
!
rgpropid
||
!
rglpwstrName
))
return
E_INVALIDARG
;
if
(
!
(
This
->
grfMode
&
STGM_READWRITE
))
return
STG_E_ACCESSDENIED
;
hr
=
S_OK
;
EnterCriticalSection
(
&
This
->
cs
);
for
(
i
=
0
;
i
<
cpropid
;
i
++
)
{
if
(
rgpropid
[
i
]
!=
PID_ILLEGAL
)
{
size_t
len
=
lstrlenW
(
rglpwstrName
[
i
]
+
1
);
LPWSTR
name
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
));
strcpyW
(
name
,
rglpwstrName
[
i
]);
dictionary_insert
(
This
->
name_to_propid
,
name
,
(
void
*
)
rgpropid
[
i
]);
dictionary_insert
(
This
->
propid_to_name
,
(
void
*
)
rgpropid
[
i
],
name
);
}
}
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
/************************************************************************
...
...
@@ -190,8 +513,32 @@ static HRESULT WINAPI IPropertyStorage_fnDeletePropertyNames(
ULONG
cpropid
,
const
PROPID
rgpropid
[])
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
ULONG
i
;
HRESULT
hr
;
TRACE
(
"(%p, %ld, %p)
\n
"
,
iface
,
cpropid
,
rgpropid
);
if
(
!
This
)
return
E_INVALIDARG
;
if
(
cpropid
&&
!
rgpropid
)
return
E_INVALIDARG
;
if
(
!
(
This
->
grfMode
&
STGM_READWRITE
))
return
STG_E_ACCESSDENIED
;
hr
=
S_OK
;
EnterCriticalSection
(
&
This
->
cs
);
for
(
i
=
0
;
i
<
cpropid
;
i
++
)
{
LPWSTR
name
=
NULL
;
if
(
dictionary_find
(
This
->
propid_to_name
,
(
void
*
)
rgpropid
[
i
],
(
void
**
)
&
name
))
{
dictionary_remove
(
This
->
propid_to_name
,
(
void
*
)
rgpropid
[
i
]);
dictionary_remove
(
This
->
name_to_propid
,
name
);
}
}
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
/************************************************************************
...
...
@@ -201,8 +548,21 @@ static HRESULT WINAPI IPropertyStorage_fnCommit(
IPropertyStorage
*
iface
,
DWORD
grfCommitFlags
)
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
HRESULT
hr
;
TRACE
(
"(%p, 0x%08lx)
\n
"
,
iface
,
grfCommitFlags
);
if
(
!
This
)
return
E_INVALIDARG
;
if
(
!
(
This
->
grfMode
&
STGM_READWRITE
))
return
STG_E_ACCESSDENIED
;
EnterCriticalSection
(
&
This
->
cs
);
if
(
This
->
dirty
)
hr
=
PropertyStorage_WriteToStream
(
iface
);
else
hr
=
S_OK
;
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
/************************************************************************
...
...
@@ -211,8 +571,20 @@ static HRESULT WINAPI IPropertyStorage_fnCommit(
static
HRESULT
WINAPI
IPropertyStorage_fnRevert
(
IPropertyStorage
*
iface
)
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
HRESULT
hr
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
TRACE
(
"%p
\n
"
,
iface
);
if
(
!
This
)
return
E_INVALIDARG
;
EnterCriticalSection
(
&
This
->
cs
);
if
(
This
->
dirty
)
hr
=
PropertyStorage_ReadFromStream
(
iface
);
else
hr
=
S_OK
;
LeaveCriticalSection
(
&
This
->
cs
);
return
hr
;
}
/************************************************************************
...
...
@@ -246,8 +618,16 @@ static HRESULT WINAPI IPropertyStorage_fnSetClass(
IPropertyStorage
*
iface
,
REFCLSID
clsid
)
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
TRACE
(
"%p, %s
\n
"
,
iface
,
debugstr_guid
(
clsid
));
if
(
!
This
||
!
clsid
)
return
E_INVALIDARG
;
if
(
!
(
This
->
grfMode
&
STGM_READWRITE
))
return
STG_E_ACCESSDENIED
;
memcpy
(
&
This
->
clsid
,
clsid
,
sizeof
(
This
->
clsid
));
This
->
dirty
=
TRUE
;
return
S_OK
;
}
/************************************************************************
...
...
@@ -257,30 +637,538 @@ static HRESULT WINAPI IPropertyStorage_fnStat(
IPropertyStorage
*
iface
,
STATPROPSETSTG
*
statpsstg
)
{
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
STATSTG
stat
;
HRESULT
hr
;
TRACE
(
"%p, %p
\n
"
,
iface
,
statpsstg
);
if
(
!
This
||
!
statpsstg
)
return
E_INVALIDARG
;
hr
=
IStream_Stat
(
This
->
stm
,
&
stat
,
STATFLAG_NONAME
);
if
(
SUCCEEDED
(
hr
))
{
memcpy
(
&
statpsstg
->
fmtid
,
&
This
->
fmtid
,
sizeof
(
statpsstg
->
fmtid
));
memcpy
(
&
statpsstg
->
clsid
,
&
This
->
clsid
,
sizeof
(
statpsstg
->
clsid
));
statpsstg
->
grfFlags
=
This
->
grfFlags
;
memcpy
(
&
statpsstg
->
mtime
,
&
stat
.
mtime
,
sizeof
(
statpsstg
->
mtime
));
memcpy
(
&
statpsstg
->
ctime
,
&
stat
.
ctime
,
sizeof
(
statpsstg
->
ctime
));
memcpy
(
&
statpsstg
->
atime
,
&
stat
.
atime
,
sizeof
(
statpsstg
->
atime
));
statpsstg
->
dwOSVersion
=
This
->
originatorOS
;
}
return
hr
;
}
static
int
PropertyStorage_PropNameCompare
(
const
void
*
a
,
const
void
*
b
,
void
*
extra
)
{
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
extra
;
if
(
This
->
grfFlags
&
PROPSETFLAG_CASE_SENSITIVE
)
return
strcmpW
((
LPCWSTR
)
a
,
(
LPCWSTR
)
b
);
else
return
strcmpiW
((
LPCWSTR
)
a
,
(
LPCWSTR
)
b
);
}
static
void
PropertyStorage_PropNameDestroy
(
void
*
k
,
void
*
d
,
void
*
extra
)
{
HeapFree
(
GetProcessHeap
(),
0
,
k
);
}
static
int
PropertyStorage_PropCompare
(
const
void
*
a
,
const
void
*
b
,
void
*
extra
)
{
return
(
PROPID
)
a
-
(
PROPID
)
b
;
}
static
void
PropertyStorage_PropertyDestroy
(
void
*
k
,
void
*
d
,
void
*
extra
)
{
PropVariantClear
((
PROPVARIANT
*
)
d
);
HeapFree
(
GetProcessHeap
(),
0
,
d
);
}
/* Reads the dictionary from the memory buffer beginning at ptr. Interprets
* the entries according to the values of This->codePage and This->locale.
* FIXME: there isn't any checking whether the read property extends past the
* end of the buffer.
*/
static
HRESULT
PropertyStorage_ReadDictionary
(
PropertyStorage_impl
*
This
,
BYTE
*
ptr
)
{
DWORD
numEntries
=
*
(
DWORD
*
)
ptr
;
HRESULT
hr
=
S_OK
;
ptr
+=
sizeof
(
DWORD
);
This
->
name_to_propid
=
dictionary_create
(
PropertyStorage_PropNameCompare
,
PropertyStorage_PropNameDestroy
,
This
);
This
->
propid_to_name
=
dictionary_create
(
PropertyStorage_PropCompare
,
NULL
,
This
);
if
(
This
->
name_to_propid
&&
This
->
propid_to_name
)
{
DWORD
i
;
for
(
i
=
0
;
SUCCEEDED
(
hr
)
&&
i
<
numEntries
;
i
++
)
{
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
);
if
(
!
len
)
hr
=
HRESULT_FROM_WIN32
(
GetLastError
());
else
{
LPWSTR
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
);
}
else
hr
=
STG_E_INSUFFICIENTMEMORY
;
}
ptr
+=
sizeof
(
DWORD
)
+
cbEntry
;
/* Unicode entries are padded to DWORD boundaries */
if
(
This
->
codePage
==
1200
&&
cbEntry
%
sizeof
(
DWORD
))
ptr
+=
sizeof
(
DWORD
)
-
(
cbEntry
%
sizeof
(
DWORD
));
}
}
else
{
/* one or the other failed, free the other */
if
(
This
->
name_to_propid
)
{
dictionary_destroy
(
This
->
name_to_propid
);
This
->
name_to_propid
=
NULL
;
}
if
(
This
->
propid_to_name
)
{
dictionary_destroy
(
This
->
propid_to_name
);
This
->
propid_to_name
=
NULL
;
}
hr
=
STG_E_INSUFFICIENTMEMORY
;
}
return
hr
;
}
/* 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
)
{
HRESULT
hr
=
S_OK
;
prop
->
vt
=
VT_EMPTY
;
switch
(
type
)
{
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
;
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.
*/
TRACE
(
"Read string value %s
\n
"
,
debugstr_a
(
prop
->
u
.
pszVal
));
}
else
hr
=
STG_E_INSUFFICIENTMEMORY
;
break
;
}
case
VT_LPWSTR
:
{
DWORD
count
=
*
(
DWORD
*
)
data
;
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
hr
=
STG_E_INSUFFICIENTMEMORY
;
break
;
}
case
VT_FILETIME
:
/* FIXME: endianness */
prop
->
vt
=
VT_FILETIME
;
memcpy
(
&
prop
->
u
.
filetime
,
data
,
sizeof
(
FILETIME
));
break
;
default:
FIXME
(
"unsupported type %ld
\n
"
,
type
);
hr
=
STG_E_INVALIDPARAMETER
;
}
return
hr
;
}
static
HRESULT
PropertyStorage_ReadHeaderFromStream
(
IStream
*
stm
,
PROPERTYSETHEADER
*
hdr
)
{
BYTE
buf
[
sizeof
(
PROPERTYSETHEADER
)];
ULONG
count
=
0
;
HRESULT
hr
;
hr
=
IStream_Read
(
stm
,
buf
,
sizeof
(
buf
),
&
count
);
if
(
SUCCEEDED
(
hr
))
{
if
(
count
!=
sizeof
(
buf
))
{
WARN
(
"read %ld, expected %d
\n
"
,
count
,
sizeof
(
buf
));
hr
=
STG_E_INVALIDHEADER
;
}
else
{
StorageUtl_ReadWord
(
buf
,
offsetof
(
PROPERTYSETHEADER
,
wByteOrder
),
&
hdr
->
wByteOrder
);
StorageUtl_ReadWord
(
buf
,
offsetof
(
PROPERTYSETHEADER
,
wFormat
),
&
hdr
->
wFormat
);
StorageUtl_ReadDWord
(
buf
,
offsetof
(
PROPERTYSETHEADER
,
dwOSVer
),
&
hdr
->
dwOSVer
);
StorageUtl_ReadGUID
(
buf
,
offsetof
(
PROPERTYSETHEADER
,
clsid
),
&
hdr
->
clsid
);
StorageUtl_ReadDWord
(
buf
,
offsetof
(
PROPERTYSETHEADER
,
reserved
),
&
hdr
->
reserved
);
}
}
TRACE
(
"returning 0x%08lx
\n
"
,
hr
);
return
hr
;
}
static
HRESULT
PropertyStorage_ReadFmtIdOffsetFromStream
(
IStream
*
stm
,
FORMATIDOFFSET
*
fmt
)
{
BYTE
buf
[
sizeof
(
FORMATIDOFFSET
)];
ULONG
count
=
0
;
HRESULT
hr
;
hr
=
IStream_Read
(
stm
,
buf
,
sizeof
(
buf
),
&
count
);
if
(
SUCCEEDED
(
hr
))
{
if
(
count
!=
sizeof
(
buf
))
{
WARN
(
"read %ld, expected %d
\n
"
,
count
,
sizeof
(
buf
));
hr
=
STG_E_INVALIDHEADER
;
}
else
{
StorageUtl_ReadGUID
(
buf
,
offsetof
(
FORMATIDOFFSET
,
fmtid
),
&
fmt
->
fmtid
);
StorageUtl_ReadDWord
(
buf
,
offsetof
(
FORMATIDOFFSET
,
dwOffset
),
&
fmt
->
dwOffset
);
}
}
TRACE
(
"returning 0x%08lx
\n
"
,
hr
);
return
hr
;
}
static
HRESULT
PropertyStorage_ReadSectionHeaderFromStream
(
IStream
*
stm
,
PROPERTYSECTIONHEADER
*
hdr
)
{
BYTE
buf
[
sizeof
(
PROPERTYSECTIONHEADER
)];
ULONG
count
=
0
;
HRESULT
hr
;
hr
=
IStream_Read
(
stm
,
buf
,
sizeof
(
buf
),
&
count
);
if
(
SUCCEEDED
(
hr
))
{
if
(
count
!=
sizeof
(
buf
))
{
WARN
(
"read %ld, expected %d
\n
"
,
count
,
sizeof
(
buf
));
hr
=
STG_E_INVALIDHEADER
;
}
else
{
StorageUtl_ReadDWord
(
buf
,
offsetof
(
PROPERTYSECTIONHEADER
,
cbSection
),
&
hdr
->
cbSection
);
StorageUtl_ReadDWord
(
buf
,
offsetof
(
PROPERTYSECTIONHEADER
,
cProperties
),
&
hdr
->
cProperties
);
}
}
TRACE
(
"returning 0x%08lx
\n
"
,
hr
);
return
hr
;
}
static
HRESULT
PropertyStorage_ReadFromStream
(
IPropertyStorage
*
iface
)
{
PropertyStorage_impl
*
This
=
(
PropertyStorage_impl
*
)
iface
;
PROPERTYSETHEADER
hdr
;
FORMATIDOFFSET
fmtOffset
;
PROPERTYSECTIONHEADER
sectionHdr
;
ULONG
i
;
STATSTG
stat
;
HRESULT
hr
;
BYTE
*
buf
=
NULL
;
ULONG
count
=
0
;
DWORD
dictOffset
=
0
;
if
(
!
This
)
return
E_INVALIDARG
;
This
->
dirty
=
FALSE
;
This
->
highestProp
=
0
;
dictionary_destroy
(
This
->
name_to_propid
);
This
->
name_to_propid
=
NULL
;
dictionary_destroy
(
This
->
propid_to_name
);
This
->
propid_to_name
=
NULL
;
hr
=
IStream_Stat
(
This
->
stm
,
&
stat
,
STATFLAG_NONAME
);
if
(
FAILED
(
hr
))
goto
end
;
if
(
stat
.
cbSize
.
u
.
HighPart
)
{
WARN
(
"stream too big
\n
"
);
/* maximum size varies, but it can't be this big */
hr
=
STG_E_INVALIDHEADER
;
goto
end
;
}
if
(
stat
.
cbSize
.
u
.
LowPart
==
0
)
{
/* empty stream is okay, we might be being called from Create */
hr
=
S_OK
;
goto
end
;
}
else
if
(
stat
.
cbSize
.
u
.
LowPart
<
sizeof
(
PROPERTYSETHEADER
)
+
sizeof
(
FORMATIDOFFSET
))
{
WARN
(
"stream too small
\n
"
);
hr
=
STG_E_INVALIDHEADER
;
goto
end
;
}
hr
=
PropertyStorage_ReadHeaderFromStream
(
This
->
stm
,
&
hdr
);
/* I've only seen reserved == 1, but the article says I shouldn't disallow
* higher values.
*/
if
(
hdr
.
wByteOrder
!=
PROPSETHDR_BYTEORDER_MAGIC
||
hdr
.
reserved
<
1
)
{
WARN
(
"bad magic in prop set header
\n
"
);
hr
=
STG_E_INVALIDHEADER
;
goto
end
;
}
if
(
hdr
.
wFormat
!=
0
&&
hdr
.
wFormat
!=
1
)
{
WARN
(
"bad format version %d
\n
"
,
hdr
.
wFormat
);
hr
=
STG_E_INVALIDHEADER
;
goto
end
;
}
memcpy
(
&
This
->
clsid
,
&
hdr
.
clsid
,
sizeof
(
This
->
clsid
));
This
->
originatorOS
=
hdr
.
dwOSVer
;
if
(
PROPSETHDR_OSVER_KIND
(
hdr
.
dwOSVer
)
==
PROPSETHDR_OSVER_KIND_MAC
)
WARN
(
"File comes from a Mac, strings will probably be screwed up
\n
"
);
hr
=
PropertyStorage_ReadFmtIdOffsetFromStream
(
This
->
stm
,
&
fmtOffset
);
if
(
FAILED
(
hr
))
goto
end
;
if
(
fmtOffset
.
dwOffset
>
stat
.
cbSize
.
u
.
LowPart
)
{
WARN
(
"invalid offset %ld (stream length is %ld)
\n
"
,
fmtOffset
.
dwOffset
,
stat
.
cbSize
.
u
.
LowPart
);
hr
=
STG_E_INVALIDHEADER
;
goto
end
;
}
/* wackiness alert: if the format ID is FMTID_DocSummaryInformation, there
* follow not one, but two sections. The first is the standard properties
* for the document summary information, and the second is user-defined
* properties. This is the only case in which multiple sections are
* allowed.
* Reading the second stream isn't implemented yet.
*/
hr
=
PropertyStorage_ReadSectionHeaderFromStream
(
This
->
stm
,
&
sectionHdr
);
if
(
FAILED
(
hr
))
goto
end
;
/* The section size includes the section header, so check it */
if
(
sectionHdr
.
cbSection
<
sizeof
(
PROPERTYSECTIONHEADER
))
{
WARN
(
"section header too small, got %ld, expected at least %d
\n
"
,
sectionHdr
.
cbSection
,
sizeof
(
PROPERTYSECTIONHEADER
));
hr
=
STG_E_INVALIDHEADER
;
goto
end
;
}
buf
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sectionHdr
.
cbSection
-
sizeof
(
PROPERTYSECTIONHEADER
));
if
(
!
buf
)
{
hr
=
STG_E_INSUFFICIENTMEMORY
;
goto
end
;
}
hr
=
IStream_Read
(
This
->
stm
,
buf
,
sectionHdr
.
cbSection
-
sizeof
(
PROPERTYSECTIONHEADER
),
&
count
);
if
(
FAILED
(
hr
))
goto
end
;
dictionary_destroy
(
This
->
propid_to_prop
);
This
->
propid_to_prop
=
dictionary_create
(
PropertyStorage_PropCompare
,
PropertyStorage_PropertyDestroy
,
This
);
for
(
i
=
0
;
SUCCEEDED
(
hr
)
&&
i
<
sectionHdr
.
cProperties
;
i
++
)
{
PROPERTYIDOFFSET
*
idOffset
=
(
PROPERTYIDOFFSET
*
)(
buf
+
i
*
sizeof
(
PROPERTYIDOFFSET
));
if
(
idOffset
->
dwOffset
<
sizeof
(
PROPERTYSECTIONHEADER
)
||
idOffset
->
dwOffset
>=
sectionHdr
.
cbSection
-
sizeof
(
DWORD
))
hr
=
STG_E_INVALIDPOINTER
;
else
{
if
(
idOffset
->
propid
>=
PID_FIRST_USABLE
&&
idOffset
->
propid
<
PID_MIN_READONLY
&&
idOffset
->
propid
>
This
->
highestProp
)
This
->
highestProp
=
idOffset
->
propid
;
if
(
idOffset
->
propid
==
0
)
{
/* Don't read the dictionary yet, its entries depend on the
* code page. Just store the offset so we know to read it
* later.
*/
dictOffset
=
idOffset
->
dwOffset
;
}
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
))))
{
/* FIXME: the PID_CODEPAGE and PID_LOCALE special cases
* aren't really needed, just look them up in
* propid_to_prop when needed
*/
switch
(
idOffset
->
propid
)
{
case
PID_CODEPAGE
:
if
(
prop
.
vt
==
VT_I2
)
This
->
codePage
=
(
UINT
)
prop
.
u
.
iVal
;
break
;
case
PID_LOCALE
:
if
(
prop
.
vt
==
VT_I4
)
This
->
locale
=
(
LCID
)
prop
.
u
.
lVal
;
break
;
case
PID_BEHAVIOR
:
if
(
prop
.
vt
==
VT_I4
&&
prop
.
u
.
lVal
)
This
->
grfFlags
|=
PROPSETFLAG_CASE_SENSITIVE
;
break
;
default:
hr
=
PropertyStorage_StorePropWithId
(
This
,
idOffset
->
propid
,
&
prop
);
}
}
}
}
}
if
(
!
This
->
codePage
)
{
/* default to Unicode unless told not to, as specified here:
* http://msdn.microsoft.com/library/en-us/stg/stg/names_in_istorage.asp
*/
if
(
This
->
grfFlags
&
PROPSETFLAG_ANSI
)
This
->
codePage
=
GetACP
();
else
This
->
codePage
=
1200
;
}
if
(
!
This
->
locale
)
This
->
locale
=
LOCALE_SYSTEM_DEFAULT
;
TRACE
(
"Code page is %d, locale is %ld
\n
"
,
This
->
codePage
,
This
->
locale
);
if
(
dictOffset
)
PropertyStorage_ReadDictionary
(
This
,
buf
+
dictOffset
-
sizeof
(
PROPERTYSECTIONHEADER
));
end:
HeapFree
(
GetProcessHeap
(),
0
,
buf
);
return
hr
;
}
static
HRESULT
PropertyStorage_WriteToStream
(
IPropertyStorage
*
iface
)
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
}
/***********************************************************************
* PropertyStorage_Contruct
* PropertyStorage_Con
s
truct
*/
static
HRESULT
PropertyStorage_Contruct
(
IStream
*
stm
,
IPropertyStorage
**
pps
)
static
HRESULT
PropertyStorage_Construct
(
IStream
*
stm
,
REFFMTID
rfmtid
,
DWORD
grfFlags
,
DWORD
grfMode
,
IPropertyStorage
**
pps
)
{
PropertyStorage_impl
*
ps
;
HRESULT
hr
;
ps
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
*
ps
);
ps
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
*
ps
);
if
(
!
ps
)
return
E_OUTOFMEMORY
;
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
;
*
pps
=
(
IPropertyStorage
*
)
ps
;
TRACE
(
"PropertyStorage %p constructed
\n
"
,
ps
);
return
S_OK
;
hr
=
PropertyStorage_ReadFromStream
((
IPropertyStorage
*
)
ps
);
if
(
SUCCEEDED
(
hr
))
{
*
pps
=
(
IPropertyStorage
*
)
ps
;
TRACE
(
"PropertyStorage %p constructed
\n
"
,
ps
);
hr
=
S_OK
;
}
else
HeapFree
(
GetProcessHeap
(),
0
,
ps
);
return
hr
;
}
...
...
@@ -288,15 +1176,68 @@ static HRESULT PropertyStorage_Contruct(IStream *stm, IPropertyStorage** pps)
* Implementation of IPropertySetStorage
*/
static
LPCWSTR
format_id_to_name
(
REFFMTID
rfmtid
)
#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
))
return
szSummaryInfo
;
ERR
(
"Unknown format id %s
\n
"
,
debugstr_guid
(
rfmtid
));
return
NULL
;
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
;
}
/************************************************************************
...
...
@@ -349,28 +1290,48 @@ static HRESULT WINAPI IPropertySetStorage_fnCreate(
IPropertyStorage
**
ppprstg
)
{
_ICOM_THIS_From_IPropertySetStorage
(
StorageImpl
,
ppstg
);
WCHAR
nameBuf
[
27
];
LPCWSTR
name
=
NULL
;
IStream
*
stm
=
NULL
;
HRESULT
r
;
TRACE
(
"%p %s %08lx %p
\n
"
,
This
,
debugstr_guid
(
rfmtid
),
grfMode
,
ppprstg
);
TRACE
(
"%p %s %08lx %08lx %p
\n
"
,
This
,
debugstr_guid
(
rfmtid
),
grfFlags
,
grfMode
,
ppprstg
);
/* be picky */
if
(
grfMode
!=
(
STGM_CREATE
|
STGM_READWRITE
|
STGM_SHARE_EXCLUSIVE
))
return
STG_E_INVALIDFLAG
;
{
r
=
STG_E_INVALIDFLAG
;
goto
end
;
}
if
(
!
rfmtid
)
return
E_INVALIDARG
;
{
r
=
E_INVALIDARG
;
goto
end
;
}
name
=
format_id_to_name
(
rfmtid
);
if
(
!
name
)
return
STG_E_FILENOTFOUND
;
/* FIXME: if (grfFlags & PROPSETFLAG_NONSIMPLE), we need to create a
* storage, not a stream. For now, disallow it.
*/
if
(
grfFlags
&
PROPSETFLAG_NONSIMPLE
)
{
FIXME
(
"PROPSETFLAG_NONSIMPLE not supported
\n
"
);
r
=
STG_E_INVALIDFLAG
;
goto
end
;
}
name
=
format_id_to_name
(
rfmtid
,
nameBuf
);
r
=
IStorage_CreateStream
(
(
IStorage
*
)
This
,
name
,
grfMode
,
0
,
0
,
&
stm
);
if
(
FAILED
(
r
))
return
r
;
goto
end
;
return
PropertyStorage_Contruct
(
stm
,
ppprstg
);
r
=
PropertyStorage_Construct
(
stm
,
rfmtid
,
grfFlags
,
grfMode
,
ppprstg
);
end:
TRACE
(
"returning 0x%08lx
\n
"
,
r
);
return
r
;
}
/************************************************************************
...
...
@@ -384,6 +1345,7 @@ static HRESULT WINAPI IPropertySetStorage_fnOpen(
{
_ICOM_THIS_From_IPropertySetStorage
(
StorageImpl
,
ppstg
);
IStream
*
stm
=
NULL
;
WCHAR
nameBuf
[
27
];
LPCWSTR
name
=
NULL
;
HRESULT
r
;
...
...
@@ -392,20 +1354,29 @@ static HRESULT WINAPI IPropertySetStorage_fnOpen(
/* be picky */
if
(
grfMode
!=
(
STGM_READWRITE
|
STGM_SHARE_EXCLUSIVE
)
&&
grfMode
!=
(
STGM_READ
|
STGM_SHARE_EXCLUSIVE
))
return
STG_E_INVALIDFLAG
;
{
r
=
STG_E_INVALIDFLAG
;
goto
end
;
}
if
(
!
rfmtid
)
return
E_INVALIDARG
;
{
r
=
E_INVALIDARG
;
goto
end
;
}
name
=
format_id_to_name
(
rfmtid
);
if
(
!
name
)
return
STG_E_FILENOTFOUND
;
name
=
format_id_to_name
(
rfmtid
,
nameBuf
);
r
=
IStorage_OpenStream
((
IStorage
*
)
This
,
name
,
0
,
grfMode
,
0
,
&
stm
);
if
(
FAILED
(
r
))
return
r
;
goto
end
;
r
=
PropertyStorage_Construct
(
stm
,
rfmtid
,
PROPSETFLAG_DEFAULT
,
grfMode
,
ppprstg
);
return
PropertyStorage_Contruct
(
stm
,
ppprstg
);
end:
TRACE
(
"returning 0x%08lx
\n
"
,
r
);
return
r
;
}
/************************************************************************
...
...
@@ -417,6 +1388,7 @@ static HRESULT WINAPI IPropertySetStorage_fnDelete(
{
_ICOM_THIS_From_IPropertySetStorage
(
StorageImpl
,
ppstg
);
IStorage
*
stg
=
NULL
;
WCHAR
nameBuf
[
27
];
LPCWSTR
name
=
NULL
;
TRACE
(
"%p %s
\n
"
,
This
,
debugstr_guid
(
rfmtid
));
...
...
@@ -424,7 +1396,7 @@ static HRESULT WINAPI IPropertySetStorage_fnDelete(
if
(
!
rfmtid
)
return
E_INVALIDARG
;
name
=
format_id_to_name
(
rfmtid
);
name
=
format_id_to_name
(
rfmtid
,
nameBuf
);
if
(
!
name
)
return
STG_E_FILENOTFOUND
;
...
...
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