2 * Compound Storage (32 bit version)
3 * Storage implementation
5 * This file contains the compound file implementation
6 * of the storage interface.
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Sylvain St-Germain
10 * Copyright 1999 Thuy Nguyen
20 #include "wine/obj_storage.h"
21 #include "wine/winestring.h"
24 #include "debugtools.h"
27 #include "storage32.h"
30 DEFAULT_DEBUG_CHANNEL(storage
)
34 static const char rootPropertyName
[] = "Root Entry";
36 /***********************************************************************
37 * Forward declaration of internal functions used by the method DestroyElement
39 static HRESULT
deleteStorageProperty(
40 StorageImpl
*parentStorage
,
41 OLECHAR
*propertyToDeleteName
);
43 static HRESULT
deleteStreamProperty(
44 StorageImpl
*parentStorage
,
45 ULONG foundPropertyIndexToDelete
,
46 StgProperty propertyToDelete
);
48 static HRESULT
findPlaceholder(
50 ULONG propertyIndexToStore
,
51 ULONG storagePropertyIndex
,
54 static HRESULT
adjustPropertyChain(
56 StgProperty propertyToDelete
,
57 StgProperty parentProperty
,
58 ULONG parentPropertyId
,
61 /***********************************************************************
62 * Declaration of the functions used to manipulate StgProperty
65 static ULONG
getFreeProperty(
66 StorageImpl
*storage
);
68 static void updatePropertyChain(
70 ULONG newPropertyIndex
,
71 StgProperty newProperty
);
73 static LONG
propertyNameCmp(
75 OLECHAR
*currentProperty
);
78 /***********************************************************************
79 * Declaration of miscellaneous functions...
81 static HRESULT
validateSTGM(DWORD stgmValue
);
83 static DWORD
GetShareModeFromSTGM(DWORD stgm
);
84 static DWORD
GetAccessModeFromSTGM(DWORD stgm
);
85 static DWORD
GetCreationModeFromSTGM(DWORD stgm
);
88 * Virtual function table for the IStorage32Impl class.
90 static ICOM_VTABLE(IStorage
) Storage32Impl_Vtbl
=
92 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
93 StorageBaseImpl_QueryInterface
,
94 StorageBaseImpl_AddRef
,
95 StorageBaseImpl_Release
,
96 StorageBaseImpl_CreateStream
,
97 StorageBaseImpl_OpenStream
,
98 StorageImpl_CreateStorage
,
99 StorageBaseImpl_OpenStorage
,
101 StorageImpl_MoveElementTo
,
104 StorageBaseImpl_EnumElements
,
105 StorageImpl_DestroyElement
,
106 StorageBaseImpl_RenameElement
,
107 StorageImpl_SetElementTimes
,
108 StorageBaseImpl_SetClass
,
109 StorageImpl_SetStateBits
,
114 * Virtual function table for the Storage32InternalImpl class.
116 static ICOM_VTABLE(IStorage
) Storage32InternalImpl_Vtbl
=
118 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
119 StorageBaseImpl_QueryInterface
,
120 StorageBaseImpl_AddRef
,
121 StorageBaseImpl_Release
,
122 StorageBaseImpl_CreateStream
,
123 StorageBaseImpl_OpenStream
,
124 StorageImpl_CreateStorage
,
125 StorageBaseImpl_OpenStorage
,
127 StorageImpl_MoveElementTo
,
128 StorageInternalImpl_Commit
,
129 StorageInternalImpl_Revert
,
130 StorageBaseImpl_EnumElements
,
131 StorageImpl_DestroyElement
,
132 StorageBaseImpl_RenameElement
,
133 StorageImpl_SetElementTimes
,
134 StorageBaseImpl_SetClass
,
135 StorageImpl_SetStateBits
,
140 * Virtual function table for the IEnumSTATSTGImpl class.
142 static ICOM_VTABLE(IEnumSTATSTG
) IEnumSTATSTGImpl_Vtbl
=
144 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
145 IEnumSTATSTGImpl_QueryInterface
,
146 IEnumSTATSTGImpl_AddRef
,
147 IEnumSTATSTGImpl_Release
,
148 IEnumSTATSTGImpl_Next
,
149 IEnumSTATSTGImpl_Skip
,
150 IEnumSTATSTGImpl_Reset
,
151 IEnumSTATSTGImpl_Clone
158 /************************************************************************
159 ** Storage32BaseImpl implementatiion
162 /************************************************************************
163 * Storage32BaseImpl_QueryInterface (IUnknown)
165 * This method implements the common QueryInterface for all IStorage32
166 * implementations contained in this file.
168 * See Windows documentation for more details on IUnknown methods.
170 HRESULT WINAPI
StorageBaseImpl_QueryInterface(
175 ICOM_THIS(StorageBaseImpl
,iface
);
177 * Perform a sanity check on the parameters.
179 if ( (This
==0) || (ppvObject
==0) )
183 * Initialize the return parameter.
188 * Compare the riid with the interface IDs implemented by this object.
190 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
192 *ppvObject
= (IStorage
*)This
;
194 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
196 *ppvObject
= (IStorage
*)This
;
200 * Check that we obtained an interface.
203 return E_NOINTERFACE
;
206 * Query Interface always increases the reference count by one when it is
209 StorageBaseImpl_AddRef(iface
);
214 /************************************************************************
215 * Storage32BaseImpl_AddRef (IUnknown)
217 * This method implements the common AddRef for all IStorage32
218 * implementations contained in this file.
220 * See Windows documentation for more details on IUnknown methods.
222 ULONG WINAPI
StorageBaseImpl_AddRef(
225 ICOM_THIS(StorageBaseImpl
,iface
);
231 /************************************************************************
232 * Storage32BaseImpl_Release (IUnknown)
234 * This method implements the common Release for all IStorage32
235 * implementations contained in this file.
237 * See Windows documentation for more details on IUnknown methods.
239 ULONG WINAPI
StorageBaseImpl_Release(
242 ICOM_THIS(StorageBaseImpl
,iface
);
244 * Decrease the reference count on this object.
249 * If the reference count goes down to 0, perform suicide.
254 * Since we are using a system of base-classes, we want to call the
255 * destructor of the appropriate derived class. To do this, we are
256 * using virtual functions to implement the destructor.
258 This
->v_destructor(This
);
266 /************************************************************************
267 * Storage32BaseImpl_OpenStream (IStorage)
269 * This method will open the specified stream object from the current storage.
271 * See Windows documentation for more details on IStorage methods.
273 HRESULT WINAPI
StorageBaseImpl_OpenStream(
275 const OLECHAR
* pwcsName
, /* [string][in] */
276 void* reserved1
, /* [unique][in] */
277 DWORD grfMode
, /* [in] */
278 DWORD reserved2
, /* [in] */
279 IStream
** ppstm
) /* [out] */
281 ICOM_THIS(StorageBaseImpl
,iface
);
282 IEnumSTATSTGImpl
* propertyEnumeration
;
283 StgStreamImpl
* newStream
;
284 StgProperty currentProperty
;
285 ULONG foundPropertyIndex
;
287 TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
288 iface
, debugstr_w(pwcsName
), reserved1
, grfMode
, reserved2
, ppstm
);
291 * Perform a sanity check on the parameters.
293 if ( (pwcsName
==NULL
) || (ppstm
==0) )
297 * Initialize the out parameter
302 * Validate the STGM flags
304 if ( FAILED( validateSTGM(grfMode
) ))
305 return STG_E_INVALIDFLAG
;
310 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
311 (grfMode
& STGM_DELETEONRELEASE
) ||
312 (grfMode
& STGM_TRANSACTED
) )
313 return STG_E_INVALIDFUNCTION
;
316 * Create a property enumeration to search the properties
318 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
319 This
->ancestorStorage
,
320 This
->rootPropertySetIndex
);
323 * Search the enumeration for the property with the given name
325 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
331 * Delete the property enumeration since we don't need it anymore
333 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
336 * If it was found, construct the stream object and return a pointer to it.
338 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
339 (currentProperty
.propertyType
==PROPTYPE_STREAM
) )
341 newStream
= StgStreamImpl_Construct(This
, foundPropertyIndex
);
345 *ppstm
= (IStream
*)newStream
;
348 * Since we are returning a pointer to the interface, we have to
349 * nail down the reference.
351 StgStreamImpl_AddRef(*ppstm
);
356 return E_OUTOFMEMORY
;
359 return STG_E_FILENOTFOUND
;
362 /************************************************************************
363 * Storage32BaseImpl_OpenStorage (IStorage)
365 * This method will open a new storage object from the current storage.
367 * See Windows documentation for more details on IStorage methods.
369 HRESULT WINAPI
StorageBaseImpl_OpenStorage(
371 const OLECHAR
* pwcsName
, /* [string][unique][in] */
372 IStorage
* pstgPriority
, /* [unique][in] */
373 DWORD grfMode
, /* [in] */
374 SNB snbExclude
, /* [unique][in] */
375 DWORD reserved
, /* [in] */
376 IStorage
** ppstg
) /* [out] */
378 ICOM_THIS(StorageBaseImpl
,iface
);
379 StorageInternalImpl
* newStorage
;
380 IEnumSTATSTGImpl
* propertyEnumeration
;
381 StgProperty currentProperty
;
382 ULONG foundPropertyIndex
;
384 TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
385 iface
, debugstr_w(pwcsName
), pstgPriority
,
386 grfMode
, snbExclude
, reserved
, ppstg
);
389 * Perform a sanity check on the parameters.
391 if ( (This
==0) || (pwcsName
==NULL
) || (ppstg
==0) )
395 * Validate the STGM flags
397 if ( FAILED( validateSTGM(grfMode
) ))
398 return STG_E_INVALIDFLAG
;
403 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
404 (grfMode
& STGM_DELETEONRELEASE
) ||
405 (grfMode
& STGM_PRIORITY
) )
406 return STG_E_INVALIDFUNCTION
;
409 * Initialize the out parameter
414 * Create a property enumeration to search the properties
416 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
417 This
->ancestorStorage
,
418 This
->rootPropertySetIndex
);
421 * Search the enumeration for the property with the given name
423 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
429 * Delete the property enumeration since we don't need it anymore
431 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
434 * If it was found, construct the stream object and return a pointer to it.
436 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
437 (currentProperty
.propertyType
==PROPTYPE_STORAGE
) )
440 * Construct a new Storage object
442 newStorage
= StorageInternalImpl_Construct(
443 This
->ancestorStorage
,
448 *ppstg
= (IStorage
*)newStorage
;
451 * Since we are returning a pointer to the interface,
452 * we have to nail down the reference.
454 StorageBaseImpl_AddRef(*ppstg
);
459 return STG_E_INSUFFICIENTMEMORY
;
462 return STG_E_FILENOTFOUND
;
465 /************************************************************************
466 * Storage32BaseImpl_EnumElements (IStorage)
468 * This method will create an enumerator object that can be used to
469 * retrieve informatino about all the properties in the storage object.
471 * See Windows documentation for more details on IStorage methods.
473 HRESULT WINAPI
StorageBaseImpl_EnumElements(
475 DWORD reserved1
, /* [in] */
476 void* reserved2
, /* [size_is][unique][in] */
477 DWORD reserved3
, /* [in] */
478 IEnumSTATSTG
** ppenum
) /* [out] */
480 ICOM_THIS(StorageBaseImpl
,iface
);
481 IEnumSTATSTGImpl
* newEnum
;
483 TRACE("(%p, %ld, %p, %ld, %p)\n",
484 iface
, reserved1
, reserved2
, reserved3
, ppenum
);
487 * Perform a sanity check on the parameters.
489 if ( (This
==0) || (ppenum
==0))
493 * Construct the enumerator.
495 newEnum
= IEnumSTATSTGImpl_Construct(
496 This
->ancestorStorage
,
497 This
->rootPropertySetIndex
);
501 *ppenum
= (IEnumSTATSTG
*)newEnum
;
504 * Don't forget to nail down a reference to the new object before
507 IEnumSTATSTGImpl_AddRef(*ppenum
);
512 return E_OUTOFMEMORY
;
515 /************************************************************************
516 * Storage32BaseImpl_Stat (IStorage)
518 * This method will retrieve information about this storage object.
520 * See Windows documentation for more details on IStorage methods.
522 HRESULT WINAPI
StorageBaseImpl_Stat(
524 STATSTG
* pstatstg
, /* [out] */
525 DWORD grfStatFlag
) /* [in] */
527 ICOM_THIS(StorageBaseImpl
,iface
);
528 StgProperty curProperty
;
531 TRACE("(%p, %p, %lx)\n",
532 iface
, pstatstg
, grfStatFlag
);
535 * Perform a sanity check on the parameters.
537 if ( (This
==0) || (pstatstg
==0))
541 * Read the information from the property.
543 readSucessful
= StorageImpl_ReadProperty(
544 This
->ancestorStorage
,
545 This
->rootPropertySetIndex
,
550 StorageUtl_CopyPropertyToSTATSTG(
561 /************************************************************************
562 * Storage32BaseImpl_RenameElement (IStorage)
564 * This method will rename the specified element.
566 * See Windows documentation for more details on IStorage methods.
568 * Implementation notes: The method used to rename consists of creating a clone
569 * of the deleted StgProperty object setting it with the new name and to
570 * perform a DestroyElement of the old StgProperty.
572 HRESULT WINAPI
StorageBaseImpl_RenameElement(
574 const OLECHAR
* pwcsOldName
, /* [in] */
575 const OLECHAR
* pwcsNewName
) /* [in] */
577 ICOM_THIS(StorageBaseImpl
,iface
);
578 IEnumSTATSTGImpl
* propertyEnumeration
;
579 StgProperty currentProperty
;
580 ULONG foundPropertyIndex
;
582 TRACE("(%p, %s, %s)\n",
583 iface
, debugstr_w(pwcsOldName
), debugstr_w(pwcsNewName
));
586 * Create a property enumeration to search the properties
588 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
589 This
->rootPropertySetIndex
);
592 * Search the enumeration for the new property name
594 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
598 if (foundPropertyIndex
!= PROPERTY_NULL
)
601 * There is already a property with the new name
603 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
604 return STG_E_FILEALREADYEXISTS
;
607 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)propertyEnumeration
);
610 * Search the enumeration for the old property name
612 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
617 * Delete the property enumeration since we don't need it anymore
619 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
621 if (foundPropertyIndex
!= PROPERTY_NULL
)
623 StgProperty renamedProperty
;
624 ULONG renamedPropertyIndex
;
627 * Setup a new property for the renamed property
629 renamedProperty
.sizeOfNameString
=
630 ( lstrlenW(pwcsNewName
)+1 ) * sizeof(WCHAR
);
632 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
633 return STG_E_INVALIDNAME
;
635 lstrcpyW(renamedProperty
.name
, pwcsNewName
);
637 renamedProperty
.propertyType
= currentProperty
.propertyType
;
638 renamedProperty
.startingBlock
= currentProperty
.startingBlock
;
639 renamedProperty
.size
.LowPart
= currentProperty
.size
.LowPart
;
640 renamedProperty
.size
.HighPart
= currentProperty
.size
.HighPart
;
642 renamedProperty
.previousProperty
= PROPERTY_NULL
;
643 renamedProperty
.nextProperty
= PROPERTY_NULL
;
646 * Bring the dirProperty link in case it is a storage and in which
647 * case the renamed storage elements don't require to be reorganized.
649 renamedProperty
.dirProperty
= currentProperty
.dirProperty
;
651 /* call CoFileTime to get the current time
652 renamedProperty.timeStampS1
653 renamedProperty.timeStampD1
654 renamedProperty.timeStampS2
655 renamedProperty.timeStampD2
656 renamedProperty.propertyUniqueID
660 * Obtain a free property in the property chain
662 renamedPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
665 * Save the new property into the new property spot
667 StorageImpl_WriteProperty(
668 This
->ancestorStorage
,
669 renamedPropertyIndex
,
673 * Find a spot in the property chain for our newly created property.
677 renamedPropertyIndex
,
681 * At this point the renamed property has been inserted in the tree,
682 * now, before to Destroy the old property we must zeroed it's dirProperty
683 * otherwise the DestroyProperty below will zap it all and we do not want
685 * Also, we fake that the old property is a storage so the DestroyProperty
686 * will not do a SetSize(0) on the stream data.
688 * This means that we need to tweek the StgProperty if it is a stream or a
691 currentProperty
.dirProperty
= PROPERTY_NULL
;
692 currentProperty
.propertyType
= PROPTYPE_STORAGE
;
693 StorageImpl_WriteProperty(
694 This
->ancestorStorage
,
699 * Invoke Destroy to get rid of the ole property and automatically redo
700 * the linking of it's previous and next members...
702 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsOldName
);
708 * There is no property with the old name
710 return STG_E_FILENOTFOUND
;
716 /************************************************************************
717 * Storage32BaseImpl_CreateStream (IStorage)
719 * This method will create a stream object within this storage
721 * See Windows documentation for more details on IStorage methods.
723 HRESULT WINAPI
StorageBaseImpl_CreateStream(
725 const OLECHAR
* pwcsName
, /* [string][in] */
726 DWORD grfMode
, /* [in] */
727 DWORD reserved1
, /* [in] */
728 DWORD reserved2
, /* [in] */
729 IStream
** ppstm
) /* [out] */
731 ICOM_THIS(StorageBaseImpl
,iface
);
732 IEnumSTATSTGImpl
* propertyEnumeration
;
733 StgStreamImpl
* newStream
;
734 StgProperty currentProperty
, newStreamProperty
;
735 ULONG foundPropertyIndex
, newPropertyIndex
;
737 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
738 iface
, debugstr_w(pwcsName
), grfMode
,
739 reserved1
, reserved2
, ppstm
);
742 * Validate parameters
745 return STG_E_INVALIDPOINTER
;
748 return STG_E_INVALIDNAME
;
751 * Validate the STGM flags
753 if ( FAILED( validateSTGM(grfMode
) ))
754 return STG_E_INVALIDFLAG
;
759 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
760 (grfMode
& STGM_DELETEONRELEASE
) ||
761 (grfMode
& STGM_TRANSACTED
) )
762 return STG_E_INVALIDFUNCTION
;
765 * Initialize the out parameter
770 * Create a property enumeration to search the properties
772 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
773 This
->rootPropertySetIndex
);
775 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
779 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
781 if (foundPropertyIndex
!= PROPERTY_NULL
)
784 * An element with this name already exists
786 if (grfMode
& STGM_CREATE
)
788 IStorage_DestroyElement(iface
, pwcsName
);
791 return STG_E_FILEALREADYEXISTS
;
795 * memset the empty property
797 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
799 newStreamProperty
.sizeOfNameString
=
800 ( lstrlenW(pwcsName
)+1 ) * sizeof(WCHAR
);
802 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
803 return STG_E_INVALIDNAME
;
805 lstrcpyW(newStreamProperty
.name
, pwcsName
);
807 newStreamProperty
.propertyType
= PROPTYPE_STREAM
;
808 newStreamProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
809 newStreamProperty
.size
.LowPart
= 0;
810 newStreamProperty
.size
.HighPart
= 0;
812 newStreamProperty
.previousProperty
= PROPERTY_NULL
;
813 newStreamProperty
.nextProperty
= PROPERTY_NULL
;
814 newStreamProperty
.dirProperty
= PROPERTY_NULL
;
816 /* call CoFileTime to get the current time
817 newStreamProperty.timeStampS1
818 newStreamProperty.timeStampD1
819 newStreamProperty.timeStampS2
820 newStreamProperty.timeStampD2
823 /* newStreamProperty.propertyUniqueID */
826 * Get a free property or create a new one
828 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
831 * Save the new property into the new property spot
833 StorageImpl_WriteProperty(
834 This
->ancestorStorage
,
839 * Find a spot in the property chain for our newly created property.
847 * Open the stream to return it.
849 newStream
= StgStreamImpl_Construct(This
, newPropertyIndex
);
853 *ppstm
= (IStream
*)newStream
;
856 * Since we are returning a pointer to the interface, we have to nail down
859 StgStreamImpl_AddRef(*ppstm
);
863 return STG_E_INSUFFICIENTMEMORY
;
869 /************************************************************************
870 * Storage32BaseImpl_SetClass (IStorage)
872 * This method will write the specified CLSID in the property of this
875 * See Windows documentation for more details on IStorage methods.
877 HRESULT WINAPI
StorageBaseImpl_SetClass(
879 REFCLSID clsid
) /* [in] */
881 ICOM_THIS(StorageBaseImpl
,iface
);
882 HRESULT hRes
= E_FAIL
;
883 StgProperty curProperty
;
886 TRACE("(%p, %p)\n", iface
, clsid
);
888 success
= StorageImpl_ReadProperty(This
->ancestorStorage
,
889 This
->rootPropertySetIndex
,
893 curProperty
.propertyUniqueID
= *clsid
;
895 success
= StorageImpl_WriteProperty(This
->ancestorStorage
,
896 This
->rootPropertySetIndex
,
905 /************************************************************************
906 ** Storage32Impl implementation
909 /************************************************************************
910 * Storage32Impl_CreateStorage (IStorage)
912 * This method will create the storage object within the provided storage.
914 * See Windows documentation for more details on IStorage methods.
916 HRESULT WINAPI
StorageImpl_CreateStorage(
918 const OLECHAR
*pwcsName
, /* [string][in] */
919 DWORD grfMode
, /* [in] */
920 DWORD reserved1
, /* [in] */
921 DWORD reserved2
, /* [in] */
922 IStorage
**ppstg
) /* [out] */
924 StorageImpl
* const This
=(StorageImpl
*)iface
;
926 IEnumSTATSTGImpl
*propertyEnumeration
;
927 StgProperty currentProperty
;
928 StgProperty newProperty
;
929 ULONG foundPropertyIndex
;
930 ULONG newPropertyIndex
;
933 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
934 iface
, debugstr_w(pwcsName
), grfMode
,
935 reserved1
, reserved2
, ppstg
);
938 * Validate parameters
941 return STG_E_INVALIDPOINTER
;
944 return STG_E_INVALIDNAME
;
947 * Validate the STGM flags
949 if ( FAILED( validateSTGM(grfMode
) ) ||
950 (grfMode
& STGM_DELETEONRELEASE
) )
951 return STG_E_INVALIDFLAG
;
954 * Initialize the out parameter
959 * Create a property enumeration and search the properties
961 propertyEnumeration
= IEnumSTATSTGImpl_Construct( This
->ancestorStorage
,
962 This
->rootPropertySetIndex
);
964 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
967 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
969 if (foundPropertyIndex
!= PROPERTY_NULL
)
972 * An element with this name already exists
974 if (grfMode
& STGM_CREATE
)
975 IStorage_DestroyElement(iface
, pwcsName
);
977 return STG_E_FILEALREADYEXISTS
;
981 * memset the empty property
983 memset(&newProperty
, 0, sizeof(StgProperty
));
985 newProperty
.sizeOfNameString
= (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
);
987 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
988 return STG_E_INVALIDNAME
;
990 lstrcpyW(newProperty
.name
, pwcsName
);
992 newProperty
.propertyType
= PROPTYPE_STORAGE
;
993 newProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
994 newProperty
.size
.LowPart
= 0;
995 newProperty
.size
.HighPart
= 0;
997 newProperty
.previousProperty
= PROPERTY_NULL
;
998 newProperty
.nextProperty
= PROPERTY_NULL
;
999 newProperty
.dirProperty
= PROPERTY_NULL
;
1001 /* call CoFileTime to get the current time
1002 newProperty.timeStampS1
1003 newProperty.timeStampD1
1004 newProperty.timeStampS2
1005 newProperty.timeStampD2
1008 /* newStorageProperty.propertyUniqueID */
1011 * Obtain a free property in the property chain
1013 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
1016 * Save the new property into the new property spot
1018 StorageImpl_WriteProperty(
1019 This
->ancestorStorage
,
1024 * Find a spot in the property chain for our newly created property.
1026 updatePropertyChain(
1032 * Open it to get a pointer to return.
1034 hr
= IStorage_OpenStorage(
1043 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1053 /***************************************************************************
1057 * Get a free property or create a new one.
1059 static ULONG
getFreeProperty(
1060 StorageImpl
*storage
)
1062 ULONG currentPropertyIndex
= 0;
1063 ULONG newPropertyIndex
= PROPERTY_NULL
;
1064 BOOL readSucessful
= TRUE
;
1065 StgProperty currentProperty
;
1070 * Start by reading the root property
1072 readSucessful
= StorageImpl_ReadProperty(storage
->ancestorStorage
,
1073 currentPropertyIndex
,
1077 if (currentProperty
.sizeOfNameString
== 0)
1080 * The property existis and is available, we found it.
1082 newPropertyIndex
= currentPropertyIndex
;
1088 * We exhausted the property list, we will create more space below
1090 newPropertyIndex
= currentPropertyIndex
;
1092 currentPropertyIndex
++;
1094 } while (newPropertyIndex
== PROPERTY_NULL
);
1097 * grow the property chain
1099 if (! readSucessful
)
1101 StgProperty emptyProperty
;
1102 ULARGE_INTEGER newSize
;
1103 ULONG propertyIndex
;
1104 ULONG lastProperty
= 0;
1105 ULONG blockCount
= 0;
1108 * obtain the new count of property blocks
1110 blockCount
= BlockChainStream_GetCount(
1111 storage
->ancestorStorage
->rootBlockChain
)+1;
1114 * initialize the size used by the property stream
1116 newSize
.HighPart
= 0;
1117 newSize
.LowPart
= storage
->bigBlockSize
* blockCount
;
1120 * add a property block to the property chain
1122 BlockChainStream_SetSize(storage
->ancestorStorage
->rootBlockChain
, newSize
);
1125 * memset the empty property in order to initialize the unused newly
1128 memset(&emptyProperty
, 0, sizeof(StgProperty
));
1133 lastProperty
= storage
->bigBlockSize
/ PROPSET_BLOCK_SIZE
* blockCount
;
1136 propertyIndex
= newPropertyIndex
;
1137 propertyIndex
< lastProperty
;
1140 StorageImpl_WriteProperty(
1141 storage
->ancestorStorage
,
1147 return newPropertyIndex
;
1150 /****************************************************************************
1154 * Case insensitive comparaison of StgProperty.name by first considering
1157 * Returns <0 when newPrpoerty < currentProperty
1158 * >0 when newPrpoerty > currentProperty
1159 * 0 when newPrpoerty == currentProperty
1161 static LONG
propertyNameCmp(
1162 OLECHAR
*newProperty
,
1163 OLECHAR
*currentProperty
)
1165 LONG diff
= lstrlenW(newProperty
) - lstrlenW(currentProperty
);
1170 * We compare the string themselves only when they are of the same lenght
1172 diff
= lstrcmpiW( newProperty
, currentProperty
);
1178 /****************************************************************************
1182 * Properly link this new element in the property chain.
1184 static void updatePropertyChain(
1185 StorageImpl
*storage
,
1186 ULONG newPropertyIndex
,
1187 StgProperty newProperty
)
1189 StgProperty currentProperty
;
1192 * Read the root property
1194 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1195 storage
->rootPropertySetIndex
,
1198 if (currentProperty
.dirProperty
!= PROPERTY_NULL
)
1201 * The root storage contains some element, therefore, start the research
1202 * for the appropriate location.
1205 ULONG current
, next
, previous
, currentPropertyId
;
1208 * Keep the StgProperty sequence number of the storage first property
1210 currentPropertyId
= currentProperty
.dirProperty
;
1215 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1216 currentProperty
.dirProperty
,
1219 previous
= currentProperty
.previousProperty
;
1220 next
= currentProperty
.nextProperty
;
1221 current
= currentPropertyId
;
1225 LONG diff
= propertyNameCmp( newProperty
.name
, currentProperty
.name
);
1229 if (previous
!= PROPERTY_NULL
)
1231 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1238 currentProperty
.previousProperty
= newPropertyIndex
;
1239 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1247 if (next
!= PROPERTY_NULL
)
1249 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1256 currentProperty
.nextProperty
= newPropertyIndex
;
1257 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1266 * Trying to insert an item with the same name in the
1267 * subtree structure.
1272 previous
= currentProperty
.previousProperty
;
1273 next
= currentProperty
.nextProperty
;
1279 * The root storage is empty, link the new property to it's dir property
1281 currentProperty
.dirProperty
= newPropertyIndex
;
1282 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1283 storage
->rootPropertySetIndex
,
1289 /*************************************************************************
1292 HRESULT WINAPI
StorageImpl_CopyTo(
1294 DWORD ciidExclude
, /* [in] */
1295 const IID
* rgiidExclude
, /* [size_is][unique][in] */
1296 SNB snbExclude
, /* [unique][in] */
1297 IStorage
* pstgDest
) /* [unique][in] */
1299 IEnumSTATSTG
*elements
= 0;
1300 STATSTG curElement
, strStat
;
1302 IStorage
*pstgTmp
, *pstgChild
;
1303 IStream
*pstrTmp
, *pstrChild
;
1305 if ((ciidExclude
!= 0) || (rgiidExclude
!= NULL
) || (snbExclude
!= NULL
))
1306 FIXME("Exclude option not implemented\n");
1308 TRACE("(%p, %ld, %p, %p, %p)\n",
1309 iface
, ciidExclude
, rgiidExclude
,
1310 snbExclude
, pstgDest
);
1313 * Perform a sanity check
1315 if ( pstgDest
== 0 )
1316 return STG_E_INVALIDPOINTER
;
1319 * Enumerate the elements
1321 hr
= IStorage_EnumElements( iface
, 0, 0, 0, &elements
);
1329 IStorage_Stat( iface
, &curElement
, STATFLAG_NONAME
);
1330 IStorage_SetClass( pstgDest
, &curElement
.clsid
);
1335 * Obtain the next element
1337 hr
= IEnumSTATSTG_Next( elements
, 1, &curElement
, NULL
);
1339 if ( hr
== S_FALSE
)
1341 hr
= S_OK
; /* done, every element has been copied */
1345 if (curElement
.type
== STGTY_STORAGE
)
1348 * open child source storage
1350 hr
= IStorage_OpenStorage( iface
, curElement
.pwcsName
, NULL
,
1351 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1352 NULL
, 0, &pstgChild
);
1358 * Check if destination storage is not a child of the source
1359 * storage, which will cause an infinite loop
1361 if (pstgChild
== pstgDest
)
1363 IEnumSTATSTG_Release(elements
);
1365 return STG_E_ACCESSDENIED
;
1369 * create a new storage in destination storage
1371 hr
= IStorage_CreateStorage( pstgDest
, curElement
.pwcsName
,
1372 STGM_FAILIFTHERE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1376 * if it already exist, don't create a new one use this one
1378 if (hr
== STG_E_FILEALREADYEXISTS
)
1380 hr
= IStorage_OpenStorage( pstgDest
, curElement
.pwcsName
, NULL
,
1381 STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1382 NULL
, 0, &pstgTmp
);
1390 * do the copy recursively
1392 hr
= IStorage_CopyTo( pstgChild
, ciidExclude
, rgiidExclude
,
1393 snbExclude
, pstgTmp
);
1395 IStorage_Release( pstgTmp
);
1396 IStorage_Release( pstgChild
);
1398 else if (curElement
.type
== STGTY_STREAM
)
1401 * create a new stream in destination storage. If the stream already
1402 * exist, it will be deleted and a new one will be created.
1404 hr
= IStorage_CreateStream( pstgDest
, curElement
.pwcsName
,
1405 STGM_CREATE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1412 * open child stream storage
1414 hr
= IStorage_OpenStream( iface
, curElement
.pwcsName
, NULL
,
1415 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1422 * Get the size of the source stream
1424 IStream_Stat( pstrChild
, &strStat
, STATFLAG_NONAME
);
1427 * Set the size of the destination stream.
1429 IStream_SetSize(pstrTmp
, strStat
.cbSize
);
1434 hr
= IStream_CopyTo( pstrChild
, pstrTmp
, strStat
.cbSize
,
1437 IStream_Release( pstrTmp
);
1438 IStream_Release( pstrChild
);
1442 WARN("unknown element type: %ld\n", curElement
.type
);
1445 } while (hr
== S_OK
);
1450 IEnumSTATSTG_Release(elements
);
1455 /*************************************************************************
1456 * MoveElementTo (IStorage)
1458 HRESULT WINAPI
StorageImpl_MoveElementTo(
1460 const OLECHAR
*pwcsName
, /* [string][in] */
1461 IStorage
*pstgDest
, /* [unique][in] */
1462 const OLECHAR
*pwcsNewName
,/* [string][in] */
1463 DWORD grfFlags
) /* [in] */
1465 FIXME("not implemented!\n");
1469 /*************************************************************************
1472 HRESULT WINAPI
StorageImpl_Commit(
1474 DWORD grfCommitFlags
)/* [in] */
1476 FIXME("(%ld): stub!\n", grfCommitFlags
);
1480 /*************************************************************************
1483 HRESULT WINAPI
StorageImpl_Revert(
1486 FIXME("not implemented!\n");
1490 /*************************************************************************
1491 * DestroyElement (IStorage)
1493 * Stategy: This implementation is build this way for simplicity not for speed.
1494 * I always delete the top most element of the enumeration and adjust
1495 * the deleted element pointer all the time. This takes longer to
1496 * do but allow to reinvoke DestroyElement whenever we encounter a
1497 * storage object. The optimisation reside in the usage of another
1498 * enumeration stategy that would give all the leaves of a storage
1499 * first. (postfix order)
1501 HRESULT WINAPI
StorageImpl_DestroyElement(
1503 const OLECHAR
*pwcsName
)/* [string][in] */
1505 StorageImpl
* const This
=(StorageImpl
*)iface
;
1507 IEnumSTATSTGImpl
* propertyEnumeration
;
1510 StgProperty propertyToDelete
;
1511 StgProperty parentProperty
;
1512 ULONG foundPropertyIndexToDelete
;
1513 ULONG typeOfRelation
;
1514 ULONG parentPropertyId
;
1517 iface
, debugstr_w(pwcsName
));
1520 * Perform a sanity check on the parameters.
1523 return STG_E_INVALIDPOINTER
;
1526 * Create a property enumeration to search the property with the given name
1528 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
1529 This
->ancestorStorage
,
1530 This
->rootPropertySetIndex
);
1532 foundPropertyIndexToDelete
= IEnumSTATSTGImpl_FindProperty(
1533 propertyEnumeration
,
1537 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1539 if ( foundPropertyIndexToDelete
== PROPERTY_NULL
)
1541 return STG_E_FILENOTFOUND
;
1545 * Find the parent property of the property to delete (the one that
1546 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1547 * the parent is This. Otherwise, the parent is one of it's sibling...
1551 * First, read This's StgProperty..
1553 res
= StorageImpl_ReadProperty(
1554 This
->ancestorStorage
,
1555 This
->rootPropertySetIndex
,
1561 * Second, check to see if by any chance the actual storage (This) is not
1562 * the parent of the property to delete... We never know...
1564 if ( parentProperty
.dirProperty
== foundPropertyIndexToDelete
)
1567 * Set data as it would have been done in the else part...
1569 typeOfRelation
= PROPERTY_RELATION_DIR
;
1570 parentPropertyId
= This
->rootPropertySetIndex
;
1575 * Create a property enumeration to search the parent properties, and
1576 * delete it once done.
1578 IEnumSTATSTGImpl
* propertyEnumeration2
;
1580 propertyEnumeration2
= IEnumSTATSTGImpl_Construct(
1581 This
->ancestorStorage
,
1582 This
->rootPropertySetIndex
);
1584 typeOfRelation
= IEnumSTATSTGImpl_FindParentProperty(
1585 propertyEnumeration2
,
1586 foundPropertyIndexToDelete
,
1590 IEnumSTATSTGImpl_Destroy(propertyEnumeration2
);
1593 if ( propertyToDelete
.propertyType
== PROPTYPE_STORAGE
)
1595 hr
= deleteStorageProperty(
1597 propertyToDelete
.name
);
1599 else if ( propertyToDelete
.propertyType
== PROPTYPE_STREAM
)
1601 hr
= deleteStreamProperty(
1603 foundPropertyIndexToDelete
,
1611 * Adjust the property chain
1613 hr
= adjustPropertyChain(
1624 /*********************************************************************
1628 * Perform the deletion of a complete storage node
1631 static HRESULT
deleteStorageProperty(
1632 StorageImpl
*parentStorage
,
1633 OLECHAR
*propertyToDeleteName
)
1635 IEnumSTATSTG
*elements
= 0;
1636 IStorage
*childStorage
= 0;
1637 STATSTG currentElement
;
1639 HRESULT destroyHr
= S_OK
;
1642 * Open the storage and enumerate it
1644 hr
= StorageBaseImpl_OpenStorage(
1645 (IStorage
*)parentStorage
,
1646 propertyToDeleteName
,
1648 STGM_SHARE_EXCLUSIVE
,
1659 * Enumerate the elements
1661 IStorage_EnumElements( childStorage
, 0, 0, 0, &elements
);
1666 * Obtain the next element
1668 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1671 destroyHr
= StorageImpl_DestroyElement(
1672 (IStorage
*)childStorage
,
1673 (OLECHAR
*)currentElement
.pwcsName
);
1675 CoTaskMemFree(currentElement
.pwcsName
);
1679 * We need to Reset the enumeration every time because we delete elements
1680 * and the enumeration could be invalid
1682 IEnumSTATSTG_Reset(elements
);
1684 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1686 IStorage_Release(childStorage
);
1687 IEnumSTATSTG_Release(elements
);
1692 /*********************************************************************
1696 * Perform the deletion of a stream node
1699 static HRESULT
deleteStreamProperty(
1700 StorageImpl
*parentStorage
,
1701 ULONG indexOfPropertyToDelete
,
1702 StgProperty propertyToDelete
)
1706 ULARGE_INTEGER size
;
1711 hr
= StorageBaseImpl_OpenStream(
1712 (IStorage
*)parentStorage
,
1713 (OLECHAR
*)propertyToDelete
.name
,
1715 STGM_SHARE_EXCLUSIVE
,
1727 hr
= IStream_SetSize(pis
, size
);
1735 * Release the stream object.
1737 IStream_Release(pis
);
1740 * Invalidate the property by zeroing it's name member.
1742 propertyToDelete
.sizeOfNameString
= 0;
1745 * Here we should re-read the property so we get the updated pointer
1746 * but since we are here to zap it, I don't do it...
1748 StorageImpl_WriteProperty(
1749 parentStorage
->ancestorStorage
,
1750 indexOfPropertyToDelete
,
1756 /*********************************************************************
1760 * Finds a placeholder for the StgProperty within the Storage
1763 static HRESULT
findPlaceholder(
1764 StorageImpl
*storage
,
1765 ULONG propertyIndexToStore
,
1766 ULONG storePropertyIndex
,
1769 StgProperty storeProperty
;
1774 * Read the storage property
1776 res
= StorageImpl_ReadProperty(
1777 storage
->ancestorStorage
,
1786 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1788 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1790 return findPlaceholder(
1792 propertyIndexToStore
,
1793 storeProperty
.previousProperty
,
1798 storeProperty
.previousProperty
= propertyIndexToStore
;
1801 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1803 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1805 return findPlaceholder(
1807 propertyIndexToStore
,
1808 storeProperty
.nextProperty
,
1813 storeProperty
.nextProperty
= propertyIndexToStore
;
1816 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1818 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1820 return findPlaceholder(
1822 propertyIndexToStore
,
1823 storeProperty
.dirProperty
,
1828 storeProperty
.dirProperty
= propertyIndexToStore
;
1832 hr
= StorageImpl_WriteProperty(
1833 storage
->ancestorStorage
,
1845 /*************************************************************************
1849 * This method takes the previous and the next property link of a property
1850 * to be deleted and find them a place in the Storage.
1852 static HRESULT
adjustPropertyChain(
1854 StgProperty propertyToDelete
,
1855 StgProperty parentProperty
,
1856 ULONG parentPropertyId
,
1859 ULONG newLinkProperty
= PROPERTY_NULL
;
1860 BOOL needToFindAPlaceholder
= FALSE
;
1861 ULONG storeNode
= PROPERTY_NULL
;
1862 ULONG toStoreNode
= PROPERTY_NULL
;
1863 INT relationType
= 0;
1867 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1869 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1872 * Set the parent previous to the property to delete previous
1874 newLinkProperty
= propertyToDelete
.previousProperty
;
1876 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1879 * We also need to find a storage for the other link, setup variables
1880 * to do this at the end...
1882 needToFindAPlaceholder
= TRUE
;
1883 storeNode
= propertyToDelete
.previousProperty
;
1884 toStoreNode
= propertyToDelete
.nextProperty
;
1885 relationType
= PROPERTY_RELATION_NEXT
;
1888 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1891 * Set the parent previous to the property to delete next
1893 newLinkProperty
= propertyToDelete
.nextProperty
;
1897 * Link it for real...
1899 parentProperty
.previousProperty
= newLinkProperty
;
1902 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1904 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1907 * Set the parent next to the property to delete next previous
1909 newLinkProperty
= propertyToDelete
.previousProperty
;
1911 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1914 * We also need to find a storage for the other link, setup variables
1915 * to do this at the end...
1917 needToFindAPlaceholder
= TRUE
;
1918 storeNode
= propertyToDelete
.previousProperty
;
1919 toStoreNode
= propertyToDelete
.nextProperty
;
1920 relationType
= PROPERTY_RELATION_NEXT
;
1923 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1926 * Set the parent next to the property to delete next
1928 newLinkProperty
= propertyToDelete
.nextProperty
;
1932 * Link it for real...
1934 parentProperty
.nextProperty
= newLinkProperty
;
1936 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1938 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1941 * Set the parent dir to the property to delete previous
1943 newLinkProperty
= propertyToDelete
.previousProperty
;
1945 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1948 * We also need to find a storage for the other link, setup variables
1949 * to do this at the end...
1951 needToFindAPlaceholder
= TRUE
;
1952 storeNode
= propertyToDelete
.previousProperty
;
1953 toStoreNode
= propertyToDelete
.nextProperty
;
1954 relationType
= PROPERTY_RELATION_NEXT
;
1957 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1960 * Set the parent dir to the property to delete next
1962 newLinkProperty
= propertyToDelete
.nextProperty
;
1966 * Link it for real...
1968 parentProperty
.dirProperty
= newLinkProperty
;
1972 * Write back the parent property
1974 res
= StorageImpl_WriteProperty(
1975 This
->ancestorStorage
,
1984 * If a placeholder is required for the other link, then, find one and
1985 * get out of here...
1987 if (needToFindAPlaceholder
)
1989 hr
= findPlaceholder(
2000 /******************************************************************************
2001 * SetElementTimes (IStorage)
2003 HRESULT WINAPI
StorageImpl_SetElementTimes(
2005 const OLECHAR
*pwcsName
,/* [string][in] */
2006 const FILETIME
*pctime
, /* [in] */
2007 const FILETIME
*patime
, /* [in] */
2008 const FILETIME
*pmtime
) /* [in] */
2010 FIXME("not implemented!\n");
2014 /******************************************************************************
2015 * SetStateBits (IStorage)
2017 HRESULT WINAPI
StorageImpl_SetStateBits(
2019 DWORD grfStateBits
,/* [in] */
2020 DWORD grfMask
) /* [in] */
2022 FIXME("not implemented!\n");
2026 HRESULT
StorageImpl_Construct(
2034 StgProperty currentProperty
;
2036 ULONG currentPropertyIndex
;
2038 if ( FAILED( validateSTGM(openFlags
) ))
2039 return STG_E_INVALIDFLAG
;
2041 memset(This
, 0, sizeof(StorageImpl
));
2044 * Initialize the virtual fgunction table.
2046 This
->lpvtbl
= &Storage32Impl_Vtbl
;
2047 This
->v_destructor
= &StorageImpl_Destroy
;
2050 * This is the top-level storage so initialize the ancester pointer
2053 This
->ancestorStorage
= This
;
2056 * Initialize the physical support of the storage.
2058 This
->hFile
= hFile
;
2061 * Initialize the big block cache.
2063 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
2064 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
2065 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
,
2071 if (This
->bigBlockFile
== 0)
2074 if (openFlags
& STGM_CREATE
)
2076 ULARGE_INTEGER size
;
2077 BYTE
* bigBlockBuffer
;
2080 * Initialize all header variables:
2081 * - The big block depot consists of one block and it is at block 0
2082 * - The properties start at block 1
2083 * - There is no small block depot
2085 memset( This
->bigBlockDepotStart
,
2087 sizeof(This
->bigBlockDepotStart
));
2089 This
->bigBlockDepotCount
= 1;
2090 This
->bigBlockDepotStart
[0] = 0;
2091 This
->rootStartBlock
= 1;
2092 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2093 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
2094 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
2095 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2096 This
->extBigBlockDepotCount
= 0;
2098 StorageImpl_SaveFileHeader(This
);
2101 * Add one block for the big block depot and one block for the properties
2104 size
.LowPart
= This
->bigBlockSize
* 3;
2105 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
2108 * Initialize the big block depot
2110 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, 0);
2111 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2112 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
2113 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
2114 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2119 * Load the header for the file.
2121 hr
= StorageImpl_LoadFileHeader(This
);
2125 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2132 * There is no block depot cached yet.
2134 This
->indexBlockDepotCached
= 0xFFFFFFFF;
2137 * Start searching for free blocks with block 0.
2139 This
->prevFreeBlock
= 0;
2142 * Create the block chain abstractions.
2144 This
->rootBlockChain
=
2145 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
2147 This
->smallBlockDepotChain
= BlockChainStream_Construct(
2149 &This
->smallBlockDepotStart
,
2153 * Write the root property
2155 if (openFlags
& STGM_CREATE
)
2157 StgProperty rootProp
;
2159 * Initialize the property chain
2161 memset(&rootProp
, 0, sizeof(rootProp
));
2162 lstrcpyAtoW(rootProp
.name
, rootPropertyName
);
2164 rootProp
.sizeOfNameString
= (lstrlenW(rootProp
.name
)+1) * sizeof(WCHAR
);
2165 rootProp
.propertyType
= PROPTYPE_ROOT
;
2166 rootProp
.previousProperty
= PROPERTY_NULL
;
2167 rootProp
.nextProperty
= PROPERTY_NULL
;
2168 rootProp
.dirProperty
= PROPERTY_NULL
;
2169 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
2170 rootProp
.size
.HighPart
= 0;
2171 rootProp
.size
.LowPart
= 0;
2173 StorageImpl_WriteProperty(This
, 0, &rootProp
);
2177 * Find the ID of the root int he property sets.
2179 currentPropertyIndex
= 0;
2183 readSucessful
= StorageImpl_ReadProperty(
2185 currentPropertyIndex
,
2190 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
2191 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
2193 This
->rootPropertySetIndex
= currentPropertyIndex
;
2197 currentPropertyIndex
++;
2199 } while (readSucessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
2208 * Create the block chain abstraction for the small block root chain.
2210 This
->smallBlockRootChain
= BlockChainStream_Construct(
2213 This
->rootPropertySetIndex
);
2218 void StorageImpl_Destroy(
2221 TRACE("(%p)\n", This
);
2223 BlockChainStream_Destroy(This
->smallBlockRootChain
);
2224 BlockChainStream_Destroy(This
->rootBlockChain
);
2225 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
2227 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2231 /******************************************************************************
2232 * Storage32Impl_GetNextFreeBigBlock
2234 * Returns the index of the next free big block.
2235 * If the big block depot is filled, this method will enlarge it.
2238 ULONG
StorageImpl_GetNextFreeBigBlock(
2241 ULONG depotBlockIndexPos
;
2243 ULONG depotBlockOffset
;
2244 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
2245 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2247 ULONG freeBlock
= BLOCK_UNUSED
;
2249 depotIndex
= This
->prevFreeBlock
/ blocksPerDepot
;
2250 depotBlockOffset
= (This
->prevFreeBlock
% blocksPerDepot
) * sizeof(ULONG
);
2253 * Scan the entire big block depot until we find a block marked free
2255 while (nextBlockIndex
!= BLOCK_UNUSED
)
2257 if (depotIndex
< COUNT_BBDEPOTINHEADER
)
2259 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2262 * Grow the primary depot.
2264 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2266 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2269 * Add a block depot.
2271 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2272 This
->bigBlockDepotCount
++;
2273 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2276 * Flag it as a block depot.
2278 StorageImpl_SetNextBlockInChain(This
,
2282 /* Save new header information.
2284 StorageImpl_SaveFileHeader(This
);
2289 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotIndex
);
2291 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2294 * Grow the extended depot.
2296 ULONG extIndex
= BLOCK_UNUSED
;
2297 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2298 ULONG extBlockOffset
= numExtBlocks
% (blocksPerDepot
- 1);
2300 if (extBlockOffset
== 0)
2302 /* We need an extended block.
2304 extIndex
= Storage32Impl_AddExtBlockDepot(This
);
2305 This
->extBigBlockDepotCount
++;
2306 depotBlockIndexPos
= extIndex
+ 1;
2309 depotBlockIndexPos
= depotIndex
* blocksPerDepot
;
2312 * Add a block depot and mark it in the extended block.
2314 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2315 This
->bigBlockDepotCount
++;
2316 Storage32Impl_SetExtDepotBlock(This
, depotIndex
, depotBlockIndexPos
);
2318 /* Flag the block depot.
2320 StorageImpl_SetNextBlockInChain(This
,
2324 /* If necessary, flag the extended depot block.
2326 if (extIndex
!= BLOCK_UNUSED
)
2327 StorageImpl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2329 /* Save header information.
2331 StorageImpl_SaveFileHeader(This
);
2335 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2337 if (depotBuffer
!= 0)
2339 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2340 ( nextBlockIndex
!= BLOCK_UNUSED
))
2342 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2344 if (nextBlockIndex
== BLOCK_UNUSED
)
2346 freeBlock
= (depotIndex
* blocksPerDepot
) +
2347 (depotBlockOffset
/sizeof(ULONG
));
2350 depotBlockOffset
+= sizeof(ULONG
);
2353 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2357 depotBlockOffset
= 0;
2360 This
->prevFreeBlock
= freeBlock
;
2365 /******************************************************************************
2366 * Storage32Impl_AddBlockDepot
2368 * This will create a depot block, essentially it is a block initialized
2371 void Storage32Impl_AddBlockDepot(StorageImpl
* This
, ULONG blockIndex
)
2375 blockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2378 * Initialize blocks as free
2380 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2382 StorageImpl_ReleaseBigBlock(This
, blockBuffer
);
2385 /******************************************************************************
2386 * Storage32Impl_GetExtDepotBlock
2388 * Returns the index of the block that corresponds to the specified depot
2389 * index. This method is only for depot indexes equal or greater than
2390 * COUNT_BBDEPOTINHEADER.
2392 ULONG
Storage32Impl_GetExtDepotBlock(StorageImpl
* This
, ULONG depotIndex
)
2394 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2395 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2396 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2397 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2398 ULONG blockIndex
= BLOCK_UNUSED
;
2399 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2401 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2403 if (This
->extBigBlockDepotStart
== BLOCK_END_OF_CHAIN
)
2404 return BLOCK_UNUSED
;
2406 while (extBlockCount
> 0)
2408 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2412 if (extBlockIndex
!= BLOCK_UNUSED
)
2416 depotBuffer
= StorageImpl_GetROBigBlock(This
, extBlockIndex
);
2418 if (depotBuffer
!= 0)
2420 StorageUtl_ReadDWord(depotBuffer
,
2421 extBlockOffset
* sizeof(ULONG
),
2424 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2431 /******************************************************************************
2432 * Storage32Impl_SetExtDepotBlock
2434 * Associates the specified block index to the specified depot index.
2435 * This method is only for depot indexes equal or greater than
2436 * COUNT_BBDEPOTINHEADER.
2438 void Storage32Impl_SetExtDepotBlock(StorageImpl
* This
,
2442 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2443 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2444 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2445 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2446 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2448 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2450 while (extBlockCount
> 0)
2452 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2456 if (extBlockIndex
!= BLOCK_UNUSED
)
2460 depotBuffer
= StorageImpl_GetBigBlock(This
, extBlockIndex
);
2462 if (depotBuffer
!= 0)
2464 StorageUtl_WriteDWord(depotBuffer
,
2465 extBlockOffset
* sizeof(ULONG
),
2468 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2473 /******************************************************************************
2474 * Storage32Impl_AddExtBlockDepot
2476 * Creates an extended depot block.
2478 ULONG
Storage32Impl_AddExtBlockDepot(StorageImpl
* This
)
2480 ULONG numExtBlocks
= This
->extBigBlockDepotCount
;
2481 ULONG nextExtBlock
= This
->extBigBlockDepotStart
;
2482 BYTE
* depotBuffer
= NULL
;
2483 ULONG index
= BLOCK_UNUSED
;
2484 ULONG nextBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2485 ULONG blocksPerDepotBlock
= This
->bigBlockSize
/ sizeof(ULONG
);
2486 ULONG depotBlocksPerExtBlock
= blocksPerDepotBlock
- 1;
2488 index
= (COUNT_BBDEPOTINHEADER
+ (numExtBlocks
* depotBlocksPerExtBlock
)) *
2489 blocksPerDepotBlock
;
2491 if ((numExtBlocks
== 0) && (nextExtBlock
== BLOCK_END_OF_CHAIN
))
2494 * The first extended block.
2496 This
->extBigBlockDepotStart
= index
;
2502 * Follow the chain to the last one.
2504 for (i
= 0; i
< (numExtBlocks
- 1); i
++)
2506 nextExtBlock
= Storage32Impl_GetNextExtendedBlock(This
, nextExtBlock
);
2510 * Add the new extended block to the chain.
2512 depotBuffer
= StorageImpl_GetBigBlock(This
, nextExtBlock
);
2513 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2514 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2518 * Initialize this block.
2520 depotBuffer
= StorageImpl_GetBigBlock(This
, index
);
2521 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2522 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2527 /******************************************************************************
2528 * Storage32Impl_FreeBigBlock
2530 * This method will flag the specified block as free in the big block depot.
2532 void StorageImpl_FreeBigBlock(
2536 StorageImpl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2538 if (blockIndex
< This
->prevFreeBlock
)
2539 This
->prevFreeBlock
= blockIndex
;
2542 /************************************************************************
2543 * Storage32Impl_GetNextBlockInChain
2545 * This method will retrieve the block index of the next big block in
2548 * Params: This - Pointer to the Storage object.
2549 * blockIndex - Index of the block to retrieve the chain
2552 * Returns: This method returns the index of the next block in the chain.
2553 * It will return the constants:
2554 * BLOCK_SPECIAL - If the block given was not part of a
2556 * BLOCK_END_OF_CHAIN - If the block given was the last in
2558 * BLOCK_UNUSED - If the block given was not past of a chain
2560 * BLOCK_EXTBBDEPOT - This block is part of the extended
2563 * See Windows documentation for more details on IStorage methods.
2565 ULONG
StorageImpl_GetNextBlockInChain(
2569 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2570 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2571 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2572 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2574 ULONG depotBlockIndexPos
;
2576 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2579 * Cache the currently accessed depot block.
2581 if (depotBlockCount
!= This
->indexBlockDepotCached
)
2583 This
->indexBlockDepotCached
= depotBlockCount
;
2585 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2587 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2592 * We have to look in the extended depot.
2594 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2597 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2603 for (index
= 0; index
< NUM_BLOCKS_PER_DEPOT_BLOCK
; index
++)
2605 StorageUtl_ReadDWord(depotBuffer
, index
*sizeof(ULONG
), &nextBlockIndex
);
2606 This
->blockDepotCached
[index
] = nextBlockIndex
;
2609 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2613 nextBlockIndex
= This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)];
2615 return nextBlockIndex
;
2618 /******************************************************************************
2619 * Storage32Impl_GetNextExtendedBlock
2621 * Given an extended block this method will return the next extended block.
2624 * The last ULONG of an extended block is the block index of the next
2625 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2629 * - The index of the next extended block
2630 * - BLOCK_UNUSED: there is no next extended block.
2631 * - Any other return values denotes failure.
2633 ULONG
Storage32Impl_GetNextExtendedBlock(StorageImpl
* This
, ULONG blockIndex
)
2635 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2636 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2639 depotBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2643 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2645 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2648 return nextBlockIndex
;
2651 /******************************************************************************
2652 * Storage32Impl_SetNextBlockInChain
2654 * This method will write the index of the specified block's next block
2655 * in the big block depot.
2657 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2660 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2661 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2662 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2665 void StorageImpl_SetNextBlockInChain(
2670 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2671 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2672 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2673 ULONG depotBlockIndexPos
;
2676 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2677 assert(blockIndex
!= nextBlock
);
2679 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2681 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2686 * We have to look in the extended depot.
2688 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2691 depotBuffer
= StorageImpl_GetBigBlock(This
, depotBlockIndexPos
);
2695 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2696 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2700 * Update the cached block depot, if necessary.
2702 if (depotBlockCount
== This
->indexBlockDepotCached
)
2704 This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)] = nextBlock
;
2708 /******************************************************************************
2709 * Storage32Impl_LoadFileHeader
2711 * This method will read in the file header, i.e. big block index -1.
2713 HRESULT
StorageImpl_LoadFileHeader(
2716 HRESULT hr
= STG_E_FILENOTFOUND
;
2717 void* headerBigBlock
= NULL
;
2721 * Get a pointer to the big block of data containing the header.
2723 headerBigBlock
= StorageImpl_GetROBigBlock(This
, -1);
2726 * Extract the information from the header.
2728 if (headerBigBlock
!=0)
2731 * Check for the "magic number" signature and return an error if it is not
2734 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2736 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2737 return STG_E_OLDFORMAT
;
2740 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2742 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2743 return STG_E_INVALIDHEADER
;
2746 StorageUtl_ReadWord(
2748 OFFSET_BIGBLOCKSIZEBITS
,
2749 &This
->bigBlockSizeBits
);
2751 StorageUtl_ReadWord(
2753 OFFSET_SMALLBLOCKSIZEBITS
,
2754 &This
->smallBlockSizeBits
);
2756 StorageUtl_ReadDWord(
2758 OFFSET_BBDEPOTCOUNT
,
2759 &This
->bigBlockDepotCount
);
2761 StorageUtl_ReadDWord(
2763 OFFSET_ROOTSTARTBLOCK
,
2764 &This
->rootStartBlock
);
2766 StorageUtl_ReadDWord(
2768 OFFSET_SBDEPOTSTART
,
2769 &This
->smallBlockDepotStart
);
2771 StorageUtl_ReadDWord(
2773 OFFSET_EXTBBDEPOTSTART
,
2774 &This
->extBigBlockDepotStart
);
2776 StorageUtl_ReadDWord(
2778 OFFSET_EXTBBDEPOTCOUNT
,
2779 &This
->extBigBlockDepotCount
);
2781 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2783 StorageUtl_ReadDWord(
2785 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2786 &(This
->bigBlockDepotStart
[index
]));
2790 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2794 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2795 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2799 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2800 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2804 * Right now, the code is making some assumptions about the size of the
2805 * blocks, just make sure they are what we're expecting.
2807 assert( (This
->bigBlockSize
==DEF_BIG_BLOCK_SIZE
) &&
2808 (This
->smallBlockSize
==DEF_SMALL_BLOCK_SIZE
));
2811 * Release the block.
2813 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2821 /******************************************************************************
2822 * Storage32Impl_SaveFileHeader
2824 * This method will save to the file the header, i.e. big block -1.
2826 void StorageImpl_SaveFileHeader(
2829 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2834 * Get a pointer to the big block of data containing the header.
2836 success
= StorageImpl_ReadBigBlock(This
, -1, headerBigBlock
);
2839 * If the block read failed, the file is probably new.
2844 * Initialize for all unknown fields.
2846 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
2849 * Initialize the magic number.
2851 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
2854 * And a bunch of things we don't know what they mean
2856 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
2857 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
2858 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
2859 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
2860 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
2864 * Write the information to the header.
2866 if (headerBigBlock
!=0)
2868 StorageUtl_WriteWord(
2870 OFFSET_BIGBLOCKSIZEBITS
,
2871 This
->bigBlockSizeBits
);
2873 StorageUtl_WriteWord(
2875 OFFSET_SMALLBLOCKSIZEBITS
,
2876 This
->smallBlockSizeBits
);
2878 StorageUtl_WriteDWord(
2880 OFFSET_BBDEPOTCOUNT
,
2881 This
->bigBlockDepotCount
);
2883 StorageUtl_WriteDWord(
2885 OFFSET_ROOTSTARTBLOCK
,
2886 This
->rootStartBlock
);
2888 StorageUtl_WriteDWord(
2890 OFFSET_SBDEPOTSTART
,
2891 This
->smallBlockDepotStart
);
2893 StorageUtl_WriteDWord(
2895 OFFSET_EXTBBDEPOTSTART
,
2896 This
->extBigBlockDepotStart
);
2898 StorageUtl_WriteDWord(
2900 OFFSET_EXTBBDEPOTCOUNT
,
2901 This
->extBigBlockDepotCount
);
2903 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2905 StorageUtl_WriteDWord(
2907 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2908 (This
->bigBlockDepotStart
[index
]));
2913 * Write the big block back to the file.
2915 StorageImpl_WriteBigBlock(This
, -1, headerBigBlock
);
2918 /******************************************************************************
2919 * Storage32Impl_ReadProperty
2921 * This method will read the specified property from the property chain.
2923 BOOL
StorageImpl_ReadProperty(
2926 StgProperty
* buffer
)
2928 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2929 ULARGE_INTEGER offsetInPropSet
;
2933 offsetInPropSet
.HighPart
= 0;
2934 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
2936 readSucessful
= BlockChainStream_ReadAt(
2937 This
->rootBlockChain
,
2945 memset(buffer
->name
, 0, sizeof(buffer
->name
));
2948 currentProperty
+OFFSET_PS_NAME
,
2949 PROPERTY_NAME_BUFFER_LEN
);
2951 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
2953 StorageUtl_ReadWord(
2955 OFFSET_PS_NAMELENGTH
,
2956 &buffer
->sizeOfNameString
);
2958 StorageUtl_ReadDWord(
2960 OFFSET_PS_PREVIOUSPROP
,
2961 &buffer
->previousProperty
);
2963 StorageUtl_ReadDWord(
2966 &buffer
->nextProperty
);
2968 StorageUtl_ReadDWord(
2971 &buffer
->dirProperty
);
2973 StorageUtl_ReadGUID(
2976 &buffer
->propertyUniqueID
);
2978 StorageUtl_ReadDWord(
2981 &buffer
->timeStampS1
);
2983 StorageUtl_ReadDWord(
2986 &buffer
->timeStampD1
);
2988 StorageUtl_ReadDWord(
2991 &buffer
->timeStampS2
);
2993 StorageUtl_ReadDWord(
2996 &buffer
->timeStampD2
);
2998 StorageUtl_ReadDWord(
3000 OFFSET_PS_STARTBLOCK
,
3001 &buffer
->startingBlock
);
3003 StorageUtl_ReadDWord(
3006 &buffer
->size
.LowPart
);
3008 buffer
->size
.HighPart
= 0;
3011 return readSucessful
;
3014 /*********************************************************************
3015 * Write the specified property into the property chain
3017 BOOL
StorageImpl_WriteProperty(
3020 StgProperty
* buffer
)
3022 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3023 ULARGE_INTEGER offsetInPropSet
;
3024 BOOL writeSucessful
;
3027 offsetInPropSet
.HighPart
= 0;
3028 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3030 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
3033 currentProperty
+ OFFSET_PS_NAME
,
3035 PROPERTY_NAME_BUFFER_LEN
);
3037 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
3040 * Reassign the size in case of mistake....
3042 buffer
->sizeOfNameString
= (lstrlenW(buffer
->name
)+1) * sizeof(WCHAR
);
3044 StorageUtl_WriteWord(
3046 OFFSET_PS_NAMELENGTH
,
3047 buffer
->sizeOfNameString
);
3049 StorageUtl_WriteDWord(
3051 OFFSET_PS_PREVIOUSPROP
,
3052 buffer
->previousProperty
);
3054 StorageUtl_WriteDWord(
3057 buffer
->nextProperty
);
3059 StorageUtl_WriteDWord(
3062 buffer
->dirProperty
);
3064 StorageUtl_WriteGUID(
3067 &buffer
->propertyUniqueID
);
3069 StorageUtl_WriteDWord(
3072 buffer
->timeStampS1
);
3074 StorageUtl_WriteDWord(
3077 buffer
->timeStampD1
);
3079 StorageUtl_WriteDWord(
3082 buffer
->timeStampS2
);
3084 StorageUtl_WriteDWord(
3087 buffer
->timeStampD2
);
3089 StorageUtl_WriteDWord(
3091 OFFSET_PS_STARTBLOCK
,
3092 buffer
->startingBlock
);
3094 StorageUtl_WriteDWord(
3097 buffer
->size
.LowPart
);
3099 writeSucessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
3104 return writeSucessful
;
3107 BOOL
StorageImpl_ReadBigBlock(
3112 void* bigBlockBuffer
;
3114 bigBlockBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
3116 if (bigBlockBuffer
!=0)
3118 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
3120 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3128 BOOL
StorageImpl_WriteBigBlock(
3133 void* bigBlockBuffer
;
3135 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
3137 if (bigBlockBuffer
!=0)
3139 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
3141 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3149 void* StorageImpl_GetROBigBlock(
3153 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
3156 void* StorageImpl_GetBigBlock(
3160 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
3163 void StorageImpl_ReleaseBigBlock(
3167 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
3170 /******************************************************************************
3171 * Storage32Impl_SmallBlocksToBigBlocks
3173 * This method will convert a small block chain to a big block chain.
3174 * The small block chain will be destroyed.
3176 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
3178 SmallBlockChainStream
** ppsbChain
)
3180 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
3181 ULARGE_INTEGER size
, offset
;
3182 ULONG cbRead
, cbWritten
, cbTotalRead
, cbTotalWritten
;
3183 ULONG propertyIndex
;
3184 BOOL successRead
, successWrite
;
3185 StgProperty chainProperty
;
3186 BYTE buffer
[DEF_SMALL_BLOCK_SIZE
];
3187 BlockChainStream
*bbTempChain
= NULL
;
3188 BlockChainStream
*bigBlockChain
= NULL
;
3191 * Create a temporary big block chain that doesn't have
3192 * an associated property. This temporary chain will be
3193 * used to copy data from small blocks to big blocks.
3195 bbTempChain
= BlockChainStream_Construct(This
,
3200 * Grow the big block chain.
3202 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
3203 BlockChainStream_SetSize(bbTempChain
, size
);
3206 * Copy the contents of the small block chain to the big block chain
3207 * by small block size increments.
3210 offset
.HighPart
= 0;
3216 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
3221 cbTotalRead
+= cbRead
;
3223 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
3228 cbTotalWritten
+= cbWritten
;
3230 offset
.LowPart
+= This
->smallBlockSize
;
3232 } while (successRead
&& successWrite
);
3234 assert(cbTotalRead
== cbTotalWritten
);
3237 * Destroy the small block chain.
3239 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
3242 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
3243 SmallBlockChainStream_Destroy(*ppsbChain
);
3247 * Change the property information. This chain is now a big block chain
3248 * and it doesn't reside in the small blocks chain anymore.
3250 StorageImpl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3252 chainProperty
.startingBlock
= bbHeadOfChain
;
3254 StorageImpl_WriteProperty(This
, propertyIndex
, &chainProperty
);
3257 * Destroy the temporary propertyless big block chain.
3258 * Create a new big block chain associated with this property.
3260 BlockChainStream_Destroy(bbTempChain
);
3261 bigBlockChain
= BlockChainStream_Construct(This
,
3265 return bigBlockChain
;
3268 /******************************************************************************
3269 ** Storage32InternalImpl implementation
3272 StorageInternalImpl
* StorageInternalImpl_Construct(
3273 StorageImpl
* ancestorStorage
,
3274 ULONG rootPropertyIndex
)
3276 StorageInternalImpl
* newStorage
;
3279 * Allocate space for the new storage object
3281 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl
));
3285 memset(newStorage
, 0, sizeof(StorageInternalImpl
));
3288 * Initialize the virtual function table.
3290 newStorage
->lpvtbl
= &Storage32InternalImpl_Vtbl
;
3291 newStorage
->v_destructor
= &StorageInternalImpl_Destroy
;
3294 * Keep the ancestor storage pointer and nail a reference to it.
3296 newStorage
->ancestorStorage
= ancestorStorage
;
3297 StorageBaseImpl_AddRef((IStorage
*)(newStorage
->ancestorStorage
));
3300 * Keep the index of the root property set for this storage,
3302 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3310 void StorageInternalImpl_Destroy(
3311 StorageInternalImpl
* This
)
3313 StorageBaseImpl_Release((IStorage
*)This
->ancestorStorage
);
3314 HeapFree(GetProcessHeap(), 0, This
);
3317 /******************************************************************************
3319 ** Storage32InternalImpl_Commit
3321 ** The non-root storages cannot be opened in transacted mode thus this function
3324 HRESULT WINAPI
StorageInternalImpl_Commit(
3326 DWORD grfCommitFlags
) /* [in] */
3331 /******************************************************************************
3333 ** Storage32InternalImpl_Revert
3335 ** The non-root storages cannot be opened in transacted mode thus this function
3338 HRESULT WINAPI
StorageInternalImpl_Revert(
3344 /******************************************************************************
3345 ** IEnumSTATSTGImpl implementation
3348 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3349 StorageImpl
* parentStorage
,
3350 ULONG firstPropertyNode
)
3352 IEnumSTATSTGImpl
* newEnumeration
;
3354 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3356 if (newEnumeration
!=0)
3359 * Set-up the virtual function table and reference count.
3361 newEnumeration
->lpvtbl
= &IEnumSTATSTGImpl_Vtbl
;
3362 newEnumeration
->ref
= 0;
3365 * We want to nail-down the reference to the storage in case the
3366 * enumeration out-lives the storage in the client application.
3368 newEnumeration
->parentStorage
= parentStorage
;
3369 IStorage_AddRef((IStorage
*)newEnumeration
->parentStorage
);
3371 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3374 * Initialize the search stack
3376 newEnumeration
->stackSize
= 0;
3377 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3378 newEnumeration
->stackToVisit
=
3379 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3382 * Make sure the current node of the iterator is the first one.
3384 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3387 return newEnumeration
;
3390 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3392 IStorage_Release((IStorage
*)This
->parentStorage
);
3393 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3394 HeapFree(GetProcessHeap(), 0, This
);
3397 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3398 IEnumSTATSTG
* iface
,
3402 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3405 * Perform a sanity check on the parameters.
3408 return E_INVALIDARG
;
3411 * Initialize the return parameter.
3416 * Compare the riid with the interface IDs implemented by this object.
3418 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3420 *ppvObject
= (IEnumSTATSTG
*)This
;
3422 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3424 *ppvObject
= (IEnumSTATSTG
*)This
;
3428 * Check that we obtained an interface.
3430 if ((*ppvObject
)==0)
3431 return E_NOINTERFACE
;
3434 * Query Interface always increases the reference count by one when it is
3437 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3442 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3443 IEnumSTATSTG
* iface
)
3445 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3451 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3452 IEnumSTATSTG
* iface
)
3454 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3462 * If the reference count goes down to 0, perform suicide.
3466 IEnumSTATSTGImpl_Destroy(This
);
3472 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3473 IEnumSTATSTG
* iface
,
3476 ULONG
* pceltFetched
)
3478 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3480 StgProperty currentProperty
;
3481 STATSTG
* currentReturnStruct
= rgelt
;
3482 ULONG objectFetched
= 0;
3483 ULONG currentSearchNode
;
3486 * Perform a sanity check on the parameters.
3488 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3489 return E_INVALIDARG
;
3492 * To avoid the special case, get another pointer to a ULONG value if
3493 * the caller didn't supply one.
3495 if (pceltFetched
==0)
3496 pceltFetched
= &objectFetched
;
3499 * Start the iteration, we will iterate until we hit the end of the
3500 * linked list or until we hit the number of items to iterate through
3505 * Start with the node at the top of the stack.
3507 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3509 while ( ( *pceltFetched
< celt
) &&
3510 ( currentSearchNode
!=PROPERTY_NULL
) )
3513 * Remove the top node from the stack
3515 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3518 * Read the property from the storage.
3520 StorageImpl_ReadProperty(This
->parentStorage
,
3525 * Copy the information to the return buffer.
3527 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3532 * Step to the next item in the iteration
3535 currentReturnStruct
++;
3538 * Push the next search node in the search stack.
3540 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3543 * continue the iteration.
3545 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3548 if (*pceltFetched
== celt
)
3555 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3556 IEnumSTATSTG
* iface
,
3559 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3561 StgProperty currentProperty
;
3562 ULONG objectFetched
= 0;
3563 ULONG currentSearchNode
;
3566 * Start with the node at the top of the stack.
3568 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3570 while ( (objectFetched
< celt
) &&
3571 (currentSearchNode
!=PROPERTY_NULL
) )
3574 * Remove the top node from the stack
3576 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3579 * Read the property from the storage.
3581 StorageImpl_ReadProperty(This
->parentStorage
,
3586 * Step to the next item in the iteration
3591 * Push the next search node in the search stack.
3593 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3596 * continue the iteration.
3598 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3601 if (objectFetched
== celt
)
3607 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3608 IEnumSTATSTG
* iface
)
3610 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3612 StgProperty rootProperty
;
3616 * Re-initialize the search stack to an empty stack
3618 This
->stackSize
= 0;
3621 * Read the root property from the storage.
3623 readSucessful
= StorageImpl_ReadProperty(
3624 This
->parentStorage
,
3625 This
->firstPropertyNode
,
3630 assert(rootProperty
.sizeOfNameString
!=0);
3633 * Push the search node in the search stack.
3635 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3641 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3642 IEnumSTATSTG
* iface
,
3643 IEnumSTATSTG
** ppenum
)
3645 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3647 IEnumSTATSTGImpl
* newClone
;
3650 * Perform a sanity check on the parameters.
3653 return E_INVALIDARG
;
3655 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3656 This
->firstPropertyNode
);
3660 * The new clone enumeration must point to the same current node as
3663 newClone
->stackSize
= This
->stackSize
;
3664 newClone
->stackMaxSize
= This
->stackMaxSize
;
3665 newClone
->stackToVisit
=
3666 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3669 newClone
->stackToVisit
,
3671 sizeof(ULONG
) * newClone
->stackSize
);
3673 *ppenum
= (IEnumSTATSTG
*)newClone
;
3676 * Don't forget to nail down a reference to the clone before
3679 IEnumSTATSTGImpl_AddRef(*ppenum
);
3684 INT
IEnumSTATSTGImpl_FindParentProperty(
3685 IEnumSTATSTGImpl
*This
,
3686 ULONG childProperty
,
3687 StgProperty
*currentProperty
,
3690 ULONG currentSearchNode
;
3694 * To avoid the special case, get another pointer to a ULONG value if
3695 * the caller didn't supply one.
3698 thisNodeId
= &foundNode
;
3701 * Start with the node at the top of the stack.
3703 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3706 while (currentSearchNode
!=PROPERTY_NULL
)
3709 * Store the current node in the returned parameters
3711 *thisNodeId
= currentSearchNode
;
3714 * Remove the top node from the stack
3716 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3719 * Read the property from the storage.
3721 StorageImpl_ReadProperty(
3722 This
->parentStorage
,
3726 if (currentProperty
->previousProperty
== childProperty
)
3727 return PROPERTY_RELATION_PREVIOUS
;
3729 else if (currentProperty
->nextProperty
== childProperty
)
3730 return PROPERTY_RELATION_NEXT
;
3732 else if (currentProperty
->dirProperty
== childProperty
)
3733 return PROPERTY_RELATION_DIR
;
3736 * Push the next search node in the search stack.
3738 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3741 * continue the iteration.
3743 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3746 return PROPERTY_NULL
;
3749 ULONG
IEnumSTATSTGImpl_FindProperty(
3750 IEnumSTATSTGImpl
* This
,
3751 const OLECHAR
* lpszPropName
,
3752 StgProperty
* currentProperty
)
3754 ULONG currentSearchNode
;
3757 * Start with the node at the top of the stack.
3759 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3761 while (currentSearchNode
!=PROPERTY_NULL
)
3764 * Remove the top node from the stack
3766 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3769 * Read the property from the storage.
3771 StorageImpl_ReadProperty(This
->parentStorage
,
3775 if ( propertyNameCmp(
3776 (OLECHAR
*)currentProperty
->name
,
3777 (OLECHAR
*)lpszPropName
) == 0)
3778 return currentSearchNode
;
3781 * Push the next search node in the search stack.
3783 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3786 * continue the iteration.
3788 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3791 return PROPERTY_NULL
;
3794 void IEnumSTATSTGImpl_PushSearchNode(
3795 IEnumSTATSTGImpl
* This
,
3798 StgProperty rootProperty
;
3802 * First, make sure we're not trying to push an unexisting node.
3804 if (nodeToPush
==PROPERTY_NULL
)
3808 * First push the node to the stack
3810 if (This
->stackSize
== This
->stackMaxSize
)
3812 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3814 This
->stackToVisit
= HeapReAlloc(
3818 sizeof(ULONG
) * This
->stackMaxSize
);
3821 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3825 * Read the root property from the storage.
3827 readSucessful
= StorageImpl_ReadProperty(
3828 This
->parentStorage
,
3834 assert(rootProperty
.sizeOfNameString
!=0);
3837 * Push the previous search node in the search stack.
3839 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3843 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3844 IEnumSTATSTGImpl
* This
,
3849 if (This
->stackSize
== 0)
3850 return PROPERTY_NULL
;
3852 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3860 /******************************************************************************
3861 ** StorageUtl implementation
3864 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3866 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3869 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3871 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3874 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3876 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3879 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3881 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3884 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3886 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3887 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3888 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3890 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
3893 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
3895 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
3896 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
3897 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
3899 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
3902 void StorageUtl_CopyPropertyToSTATSTG(
3903 STATSTG
* destination
,
3904 StgProperty
* source
,
3908 * The copy of the string occurs only when the flag is not set
3910 if ((statFlags
& STATFLAG_NONAME
) != 0)
3912 destination
->pwcsName
= 0;
3916 destination
->pwcsName
=
3917 CoTaskMemAlloc((lstrlenW(source
->name
)+1)*sizeof(WCHAR
));
3919 lstrcpyW((LPWSTR
)destination
->pwcsName
, source
->name
);
3922 switch (source
->propertyType
)
3924 case PROPTYPE_STORAGE
:
3926 destination
->type
= STGTY_STORAGE
;
3928 case PROPTYPE_STREAM
:
3929 destination
->type
= STGTY_STREAM
;
3932 destination
->type
= STGTY_STREAM
;
3936 destination
->cbSize
= source
->size
;
3938 currentReturnStruct->mtime = {0}; TODO
3939 currentReturnStruct->ctime = {0};
3940 currentReturnStruct->atime = {0};
3942 destination
->grfMode
= 0;
3943 destination
->grfLocksSupported
= 0;
3944 destination
->clsid
= source
->propertyUniqueID
;
3945 destination
->grfStateBits
= 0;
3946 destination
->reserved
= 0;
3949 /******************************************************************************
3950 ** BlockChainStream implementation
3953 BlockChainStream
* BlockChainStream_Construct(
3954 StorageImpl
* parentStorage
,
3955 ULONG
* headOfStreamPlaceHolder
,
3956 ULONG propertyIndex
)
3958 BlockChainStream
* newStream
;
3961 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
3963 newStream
->parentStorage
= parentStorage
;
3964 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
3965 newStream
->ownerPropertyIndex
= propertyIndex
;
3966 newStream
->lastBlockNoInSequence
= 0xFFFFFFFF;
3967 newStream
->tailIndex
= BLOCK_END_OF_CHAIN
;
3968 newStream
->numBlocks
= 0;
3970 blockIndex
= BlockChainStream_GetHeadOfChain(newStream
);
3972 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
3974 newStream
->numBlocks
++;
3975 newStream
->tailIndex
= blockIndex
;
3977 blockIndex
= StorageImpl_GetNextBlockInChain(
3985 void BlockChainStream_Destroy(BlockChainStream
* This
)
3987 HeapFree(GetProcessHeap(), 0, This
);
3990 /******************************************************************************
3991 * BlockChainStream_GetHeadOfChain
3993 * Returns the head of this stream chain.
3994 * Some special chains don't have properties, their heads are kept in
3995 * This->headOfStreamPlaceHolder.
3998 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
4000 StgProperty chainProperty
;
4003 if (This
->headOfStreamPlaceHolder
!= 0)
4004 return *(This
->headOfStreamPlaceHolder
);
4006 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
4008 readSucessful
= StorageImpl_ReadProperty(
4009 This
->parentStorage
,
4010 This
->ownerPropertyIndex
,
4015 return chainProperty
.startingBlock
;
4019 return BLOCK_END_OF_CHAIN
;
4022 /******************************************************************************
4023 * BlockChainStream_GetCount
4025 * Returns the number of blocks that comprises this chain.
4026 * This is not the size of the stream as the last block may not be full!
4029 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
4034 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4036 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4040 blockIndex
= StorageImpl_GetNextBlockInChain(
4041 This
->parentStorage
,
4048 /******************************************************************************
4049 * BlockChainStream_ReadAt
4051 * Reads a specified number of bytes from this chain at the specified offset.
4052 * bytesRead may be NULL.
4053 * Failure will be returned if the specified number of bytes has not been read.
4055 BOOL
BlockChainStream_ReadAt(BlockChainStream
* This
,
4056 ULARGE_INTEGER offset
,
4061 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4062 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
4063 ULONG bytesToReadInBuffer
;
4066 BYTE
* bigBlockBuffer
;
4069 * Find the first block in the stream that contains part of the buffer.
4071 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4072 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4073 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4075 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4076 This
->lastBlockNoInSequence
= blockNoInSequence
;
4080 ULONG temp
= blockNoInSequence
;
4082 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4083 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4084 This
->lastBlockNoInSequence
= temp
;
4087 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4090 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4092 blockNoInSequence
--;
4095 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4098 * Start reading the buffer.
4101 bufferWalker
= buffer
;
4103 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4106 * Calculate how many bytes we can copy from this big block.
4108 bytesToReadInBuffer
=
4109 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4112 * Copy those bytes to the buffer
4115 StorageImpl_GetROBigBlock(This
->parentStorage
, blockIndex
);
4117 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
4119 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4122 * Step to the next big block.
4125 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4127 bufferWalker
+= bytesToReadInBuffer
;
4128 size
-= bytesToReadInBuffer
;
4129 *bytesRead
+= bytesToReadInBuffer
;
4130 offsetInBlock
= 0; /* There is no offset on the next block */
4137 /******************************************************************************
4138 * BlockChainStream_WriteAt
4140 * Writes the specified number of bytes to this chain at the specified offset.
4141 * bytesWritten may be NULL.
4142 * Will fail if not all specified number of bytes have been written.
4144 BOOL
BlockChainStream_WriteAt(BlockChainStream
* This
,
4145 ULARGE_INTEGER offset
,
4148 ULONG
* bytesWritten
)
4150 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4151 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
4155 BYTE
* bigBlockBuffer
;
4158 * Find the first block in the stream that contains part of the buffer.
4160 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4161 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4162 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4164 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4165 This
->lastBlockNoInSequence
= blockNoInSequence
;
4169 ULONG temp
= blockNoInSequence
;
4171 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4172 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4173 This
->lastBlockNoInSequence
= temp
;
4176 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4179 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4181 blockNoInSequence
--;
4184 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4187 * Here, I'm casting away the constness on the buffer variable
4188 * This is OK since we don't intend to modify that buffer.
4191 bufferWalker
= (BYTE
*)buffer
;
4193 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4196 * Calculate how many bytes we can copy from this big block.
4199 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4202 * Copy those bytes to the buffer
4204 bigBlockBuffer
= StorageImpl_GetBigBlock(This
->parentStorage
, blockIndex
);
4206 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
4208 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4211 * Step to the next big block.
4214 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4216 bufferWalker
+= bytesToWrite
;
4217 size
-= bytesToWrite
;
4218 *bytesWritten
+= bytesToWrite
;
4219 offsetInBlock
= 0; /* There is no offset on the next block */
4225 /******************************************************************************
4226 * BlockChainStream_Shrink
4228 * Shrinks this chain in the big block depot.
4230 BOOL
BlockChainStream_Shrink(BlockChainStream
* This
,
4231 ULARGE_INTEGER newSize
)
4233 ULONG blockIndex
, extraBlock
;
4238 * Reset the last accessed block cache.
4240 This
->lastBlockNoInSequence
= 0xFFFFFFFF;
4241 This
->lastBlockNoInSequenceIndex
= BLOCK_END_OF_CHAIN
;
4244 * Figure out how many blocks are needed to contain the new size
4246 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4248 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4251 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4254 * Go to the new end of chain
4256 while (count
< numBlocks
)
4259 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4264 /* Get the next block before marking the new end */
4266 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4268 /* Mark the new end of chain */
4269 StorageImpl_SetNextBlockInChain(
4270 This
->parentStorage
,
4272 BLOCK_END_OF_CHAIN
);
4274 This
->tailIndex
= blockIndex
;
4275 This
->numBlocks
= numBlocks
;
4278 * Mark the extra blocks as free
4280 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4283 StorageImpl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4285 StorageImpl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4286 extraBlock
= blockIndex
;
4292 /******************************************************************************
4293 * BlockChainStream_Enlarge
4295 * Grows this chain in the big block depot.
4297 BOOL
BlockChainStream_Enlarge(BlockChainStream
* This
,
4298 ULARGE_INTEGER newSize
)
4300 ULONG blockIndex
, currentBlock
;
4302 ULONG oldNumBlocks
= 0;
4304 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4307 * Empty chain. Create the head.
4309 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4311 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4312 StorageImpl_SetNextBlockInChain(This
->parentStorage
,
4314 BLOCK_END_OF_CHAIN
);
4316 if (This
->headOfStreamPlaceHolder
!= 0)
4318 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4322 StgProperty chainProp
;
4323 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4325 StorageImpl_ReadProperty(
4326 This
->parentStorage
,
4327 This
->ownerPropertyIndex
,
4330 chainProp
.startingBlock
= blockIndex
;
4332 StorageImpl_WriteProperty(
4333 This
->parentStorage
,
4334 This
->ownerPropertyIndex
,
4338 This
->tailIndex
= blockIndex
;
4339 This
->numBlocks
= 1;
4343 * Figure out how many blocks are needed to contain this stream
4345 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4347 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4351 * Go to the current end of chain
4353 if (This
->tailIndex
== BLOCK_END_OF_CHAIN
)
4355 currentBlock
= blockIndex
;
4357 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4360 currentBlock
= blockIndex
;
4363 StorageImpl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4366 This
->tailIndex
= currentBlock
;
4369 currentBlock
= This
->tailIndex
;
4370 oldNumBlocks
= This
->numBlocks
;
4373 * Add new blocks to the chain
4375 if (oldNumBlocks
< newNumBlocks
)
4377 while (oldNumBlocks
< newNumBlocks
)
4379 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4381 StorageImpl_SetNextBlockInChain(
4382 This
->parentStorage
,
4386 StorageImpl_SetNextBlockInChain(
4387 This
->parentStorage
,
4389 BLOCK_END_OF_CHAIN
);
4391 currentBlock
= blockIndex
;
4395 This
->tailIndex
= blockIndex
;
4396 This
->numBlocks
= newNumBlocks
;
4402 /******************************************************************************
4403 * BlockChainStream_SetSize
4405 * Sets the size of this stream. The big block depot will be updated.
4406 * The file will grow if we grow the chain.
4408 * TODO: Free the actual blocks in the file when we shrink the chain.
4409 * Currently, the blocks are still in the file. So the file size
4410 * doesn't shrink even if we shrink streams.
4412 BOOL
BlockChainStream_SetSize(
4413 BlockChainStream
* This
,
4414 ULARGE_INTEGER newSize
)
4416 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4418 if (newSize
.LowPart
== size
.LowPart
)
4421 if (newSize
.LowPart
< size
.LowPart
)
4423 BlockChainStream_Shrink(This
, newSize
);
4427 ULARGE_INTEGER fileSize
=
4428 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4430 ULONG diff
= newSize
.LowPart
- size
.LowPart
;
4433 * Make sure the file stays a multiple of blocksize
4435 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4436 diff
+= (This
->parentStorage
->bigBlockSize
-
4437 (diff
% This
->parentStorage
->bigBlockSize
) );
4439 fileSize
.LowPart
+= diff
;
4440 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4442 BlockChainStream_Enlarge(This
, newSize
);
4448 /******************************************************************************
4449 * BlockChainStream_GetSize
4451 * Returns the size of this chain.
4452 * Will return the block count if this chain doesn't have a property.
4454 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4456 StgProperty chainProperty
;
4458 if(This
->headOfStreamPlaceHolder
== NULL
)
4461 * This chain is a data stream read the property and return
4462 * the appropriate size
4464 StorageImpl_ReadProperty(
4465 This
->parentStorage
,
4466 This
->ownerPropertyIndex
,
4469 return chainProperty
.size
;
4474 * this chain is a chain that does not have a property, figure out the
4475 * size by making the product number of used blocks times the
4478 ULARGE_INTEGER result
;
4479 result
.HighPart
= 0;
4482 BlockChainStream_GetCount(This
) *
4483 This
->parentStorage
->bigBlockSize
;
4489 /******************************************************************************
4490 ** SmallBlockChainStream implementation
4493 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4494 StorageImpl
* parentStorage
,
4495 ULONG propertyIndex
)
4497 SmallBlockChainStream
* newStream
;
4499 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4501 newStream
->parentStorage
= parentStorage
;
4502 newStream
->ownerPropertyIndex
= propertyIndex
;
4507 void SmallBlockChainStream_Destroy(
4508 SmallBlockChainStream
* This
)
4510 HeapFree(GetProcessHeap(), 0, This
);
4513 /******************************************************************************
4514 * SmallBlockChainStream_GetHeadOfChain
4516 * Returns the head of this chain of small blocks.
4518 ULONG
SmallBlockChainStream_GetHeadOfChain(
4519 SmallBlockChainStream
* This
)
4521 StgProperty chainProperty
;
4524 if (This
->ownerPropertyIndex
)
4526 readSucessful
= StorageImpl_ReadProperty(
4527 This
->parentStorage
,
4528 This
->ownerPropertyIndex
,
4533 return chainProperty
.startingBlock
;
4538 return BLOCK_END_OF_CHAIN
;
4541 /******************************************************************************
4542 * SmallBlockChainStream_GetNextBlockInChain
4544 * Returns the index of the next small block in this chain.
4547 * - BLOCK_END_OF_CHAIN: end of this chain
4548 * - BLOCK_UNUSED: small block 'blockIndex' is free
4550 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4551 SmallBlockChainStream
* This
,
4554 ULARGE_INTEGER offsetOfBlockInDepot
;
4556 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4560 offsetOfBlockInDepot
.HighPart
= 0;
4561 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4564 * Read those bytes in the buffer from the small block file.
4566 success
= BlockChainStream_ReadAt(
4567 This
->parentStorage
->smallBlockDepotChain
,
4568 offsetOfBlockInDepot
,
4575 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4578 return nextBlockInChain
;
4581 /******************************************************************************
4582 * SmallBlockChainStream_SetNextBlockInChain
4584 * Writes the index of the next block of the specified block in the small
4586 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4587 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4589 void SmallBlockChainStream_SetNextBlockInChain(
4590 SmallBlockChainStream
* This
,
4594 ULARGE_INTEGER offsetOfBlockInDepot
;
4598 offsetOfBlockInDepot
.HighPart
= 0;
4599 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4601 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4604 * Read those bytes in the buffer from the small block file.
4606 BlockChainStream_WriteAt(
4607 This
->parentStorage
->smallBlockDepotChain
,
4608 offsetOfBlockInDepot
,
4614 /******************************************************************************
4615 * SmallBlockChainStream_FreeBlock
4617 * Flag small block 'blockIndex' as free in the small block depot.
4619 void SmallBlockChainStream_FreeBlock(
4620 SmallBlockChainStream
* This
,
4623 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4626 /******************************************************************************
4627 * SmallBlockChainStream_GetNextFreeBlock
4629 * Returns the index of a free small block. The small block depot will be
4630 * enlarged if necessary. The small block chain will also be enlarged if
4633 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4634 SmallBlockChainStream
* This
)
4636 ULARGE_INTEGER offsetOfBlockInDepot
;
4639 ULONG blockIndex
= 0;
4640 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4641 BOOL success
= TRUE
;
4642 ULONG smallBlocksPerBigBlock
;
4644 offsetOfBlockInDepot
.HighPart
= 0;
4647 * Scan the small block depot for a free block
4649 while (nextBlockIndex
!= BLOCK_UNUSED
)
4651 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4653 success
= BlockChainStream_ReadAt(
4654 This
->parentStorage
->smallBlockDepotChain
,
4655 offsetOfBlockInDepot
,
4661 * If we run out of space for the small block depot, enlarge it
4665 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4667 if (nextBlockIndex
!= BLOCK_UNUSED
)
4673 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4675 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4676 ULONG nextBlock
, newsbdIndex
;
4677 BYTE
* smallBlockDepot
;
4679 nextBlock
= sbdIndex
;
4680 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4682 sbdIndex
= nextBlock
;
4684 StorageImpl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4687 newsbdIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4688 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4689 StorageImpl_SetNextBlockInChain(
4690 This
->parentStorage
,
4694 StorageImpl_SetNextBlockInChain(
4695 This
->parentStorage
,
4697 BLOCK_END_OF_CHAIN
);
4700 * Initialize all the small blocks to free
4703 StorageImpl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4705 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4706 StorageImpl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4711 * We have just created the small block depot.
4713 StgProperty rootProp
;
4717 * Save it in the header
4719 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4720 StorageImpl_SaveFileHeader(This
->parentStorage
);
4723 * And allocate the first big block that will contain small blocks
4726 StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4728 StorageImpl_SetNextBlockInChain(
4729 This
->parentStorage
,
4731 BLOCK_END_OF_CHAIN
);
4733 StorageImpl_ReadProperty(
4734 This
->parentStorage
,
4735 This
->parentStorage
->rootPropertySetIndex
,
4738 rootProp
.startingBlock
= sbStartIndex
;
4739 rootProp
.size
.HighPart
= 0;
4740 rootProp
.size
.LowPart
= This
->parentStorage
->bigBlockSize
;
4742 StorageImpl_WriteProperty(
4743 This
->parentStorage
,
4744 This
->parentStorage
->rootPropertySetIndex
,
4750 smallBlocksPerBigBlock
=
4751 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4754 * Verify if we have to allocate big blocks to contain small blocks
4756 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4758 StgProperty rootProp
;
4759 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4761 StorageImpl_ReadProperty(
4762 This
->parentStorage
,
4763 This
->parentStorage
->rootPropertySetIndex
,
4766 if (rootProp
.size
.LowPart
<
4767 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4769 rootProp
.size
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4771 BlockChainStream_SetSize(
4772 This
->parentStorage
->smallBlockRootChain
,
4775 StorageImpl_WriteProperty(
4776 This
->parentStorage
,
4777 This
->parentStorage
->rootPropertySetIndex
,
4785 /******************************************************************************
4786 * SmallBlockChainStream_ReadAt
4788 * Reads a specified number of bytes from this chain at the specified offset.
4789 * bytesRead may be NULL.
4790 * Failure will be returned if the specified number of bytes has not been read.
4792 BOOL
SmallBlockChainStream_ReadAt(
4793 SmallBlockChainStream
* This
,
4794 ULARGE_INTEGER offset
,
4799 ULARGE_INTEGER offsetInBigBlockFile
;
4800 ULONG blockNoInSequence
=
4801 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4803 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4804 ULONG bytesToReadInBuffer
;
4806 ULONG bytesReadFromBigBlockFile
;
4810 * This should never happen on a small block file.
4812 assert(offset
.HighPart
==0);
4815 * Find the first block in the stream that contains part of the buffer.
4817 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4819 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4821 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4823 blockNoInSequence
--;
4827 * Start reading the buffer.
4830 bufferWalker
= buffer
;
4832 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4835 * Calculate how many bytes we can copy from this small block.
4837 bytesToReadInBuffer
=
4838 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4841 * Calculate the offset of the small block in the small block file.
4843 offsetInBigBlockFile
.HighPart
= 0;
4844 offsetInBigBlockFile
.LowPart
=
4845 blockIndex
* This
->parentStorage
->smallBlockSize
;
4847 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4850 * Read those bytes in the buffer from the small block file.
4852 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4853 offsetInBigBlockFile
,
4854 bytesToReadInBuffer
,
4856 &bytesReadFromBigBlockFile
);
4858 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4861 * Step to the next big block.
4863 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4864 bufferWalker
+= bytesToReadInBuffer
;
4865 size
-= bytesToReadInBuffer
;
4866 *bytesRead
+= bytesToReadInBuffer
;
4867 offsetInBlock
= 0; /* There is no offset on the next block */
4873 /******************************************************************************
4874 * SmallBlockChainStream_WriteAt
4876 * Writes the specified number of bytes to this chain at the specified offset.
4877 * bytesWritten may be NULL.
4878 * Will fail if not all specified number of bytes have been written.
4880 BOOL
SmallBlockChainStream_WriteAt(
4881 SmallBlockChainStream
* This
,
4882 ULARGE_INTEGER offset
,
4885 ULONG
* bytesWritten
)
4887 ULARGE_INTEGER offsetInBigBlockFile
;
4888 ULONG blockNoInSequence
=
4889 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4891 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4892 ULONG bytesToWriteInBuffer
;
4894 ULONG bytesWrittenFromBigBlockFile
;
4898 * This should never happen on a small block file.
4900 assert(offset
.HighPart
==0);
4903 * Find the first block in the stream that contains part of the buffer.
4905 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4907 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4909 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4911 blockNoInSequence
--;
4915 * Start writing the buffer.
4917 * Here, I'm casting away the constness on the buffer variable
4918 * This is OK since we don't intend to modify that buffer.
4921 bufferWalker
= (BYTE
*)buffer
;
4922 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4925 * Calculate how many bytes we can copy to this small block.
4927 bytesToWriteInBuffer
=
4928 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4931 * Calculate the offset of the small block in the small block file.
4933 offsetInBigBlockFile
.HighPart
= 0;
4934 offsetInBigBlockFile
.LowPart
=
4935 blockIndex
* This
->parentStorage
->smallBlockSize
;
4937 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4940 * Write those bytes in the buffer to the small block file.
4942 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
4943 offsetInBigBlockFile
,
4944 bytesToWriteInBuffer
,
4946 &bytesWrittenFromBigBlockFile
);
4948 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
4951 * Step to the next big block.
4953 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4954 bufferWalker
+= bytesToWriteInBuffer
;
4955 size
-= bytesToWriteInBuffer
;
4956 *bytesWritten
+= bytesToWriteInBuffer
;
4957 offsetInBlock
= 0; /* There is no offset on the next block */
4963 /******************************************************************************
4964 * SmallBlockChainStream_Shrink
4966 * Shrinks this chain in the small block depot.
4968 BOOL
SmallBlockChainStream_Shrink(
4969 SmallBlockChainStream
* This
,
4970 ULARGE_INTEGER newSize
)
4972 ULONG blockIndex
, extraBlock
;
4976 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4978 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4981 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4984 * Go to the new end of chain
4986 while (count
< numBlocks
)
4988 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4993 * If the count is 0, we have a special case, the head of the chain was
4998 StgProperty chainProp
;
5000 StorageImpl_ReadProperty(This
->parentStorage
,
5001 This
->ownerPropertyIndex
,
5004 chainProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
5006 StorageImpl_WriteProperty(This
->parentStorage
,
5007 This
->ownerPropertyIndex
,
5011 * We start freeing the chain at the head block.
5013 extraBlock
= blockIndex
;
5017 /* Get the next block before marking the new end */
5018 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5020 /* Mark the new end of chain */
5021 SmallBlockChainStream_SetNextBlockInChain(
5024 BLOCK_END_OF_CHAIN
);
5028 * Mark the extra blocks as free
5030 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
5032 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
5033 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
5034 extraBlock
= blockIndex
;
5040 /******************************************************************************
5041 * SmallBlockChainStream_Enlarge
5043 * Grows this chain in the small block depot.
5045 BOOL
SmallBlockChainStream_Enlarge(
5046 SmallBlockChainStream
* This
,
5047 ULARGE_INTEGER newSize
)
5049 ULONG blockIndex
, currentBlock
;
5051 ULONG oldNumBlocks
= 0;
5053 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5058 if (blockIndex
== BLOCK_END_OF_CHAIN
)
5061 StgProperty chainProp
;
5063 StorageImpl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5066 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
5068 StorageImpl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5071 blockIndex
= chainProp
.startingBlock
;
5072 SmallBlockChainStream_SetNextBlockInChain(
5075 BLOCK_END_OF_CHAIN
);
5078 currentBlock
= blockIndex
;
5081 * Figure out how many blocks are needed to contain this stream
5083 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5085 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5089 * Go to the current end of chain
5091 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5094 currentBlock
= blockIndex
;
5095 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
5099 * Add new blocks to the chain
5101 while (oldNumBlocks
< newNumBlocks
)
5103 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
5104 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
5106 SmallBlockChainStream_SetNextBlockInChain(
5109 BLOCK_END_OF_CHAIN
);
5111 currentBlock
= blockIndex
;
5118 /******************************************************************************
5119 * SmallBlockChainStream_GetCount
5121 * Returns the number of blocks that comprises this chain.
5122 * This is not the size of this chain as the last block may not be full!
5124 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
5129 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5131 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5135 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5141 /******************************************************************************
5142 * SmallBlockChainStream_SetSize
5144 * Sets the size of this stream.
5145 * The file will grow if we grow the chain.
5147 * TODO: Free the actual blocks in the file when we shrink the chain.
5148 * Currently, the blocks are still in the file. So the file size
5149 * doesn't shrink even if we shrink streams.
5151 BOOL
SmallBlockChainStream_SetSize(
5152 SmallBlockChainStream
* This
,
5153 ULARGE_INTEGER newSize
)
5155 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
5157 if (newSize
.LowPart
== size
.LowPart
)
5160 if (newSize
.LowPart
< size
.LowPart
)
5162 SmallBlockChainStream_Shrink(This
, newSize
);
5166 SmallBlockChainStream_Enlarge(This
, newSize
);
5172 /******************************************************************************
5173 * SmallBlockChainStream_GetSize
5175 * Returns the size of this chain.
5177 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
5179 StgProperty chainProperty
;
5181 StorageImpl_ReadProperty(
5182 This
->parentStorage
,
5183 This
->ownerPropertyIndex
,
5186 return chainProperty
.size
;
5189 /******************************************************************************
5190 * StgCreateDocfile32 [OLE32.144]
5192 HRESULT WINAPI
StgCreateDocfile(
5196 IStorage
**ppstgOpen
)
5198 StorageImpl
* newStorage
= 0;
5199 HANDLE hFile
= INVALID_HANDLE_VALUE
;
5204 DWORD fileAttributes
;
5205 WCHAR tempFileName
[MAX_PATH
];
5207 TRACE("(%s, %lx, %ld, %p)\n",
5208 debugstr_w(pwcsName
), grfMode
,
5209 reserved
, ppstgOpen
);
5212 * Validate the parameters
5215 return STG_E_INVALIDPOINTER
;
5218 * Validate the STGM flags
5220 if ( FAILED( validateSTGM(grfMode
) ))
5221 return STG_E_INVALIDFLAG
;
5224 * Generate a unique name.
5228 WCHAR tempPath
[MAX_PATH
];
5229 WCHAR prefix
[] = { 'S', 'T', 'O', 0 };
5231 memset(tempPath
, 0, sizeof(tempPath
));
5232 memset(tempFileName
, 0, sizeof(tempFileName
));
5234 if ((GetTempPathW(MAX_PATH
, tempPath
)) == 0 )
5237 if (GetTempFileNameW(tempPath
, prefix
, 0, tempFileName
) != 0)
5238 pwcsName
= tempFileName
;
5240 return STG_E_INSUFFICIENTMEMORY
;
5244 * Interpret the STGM value grfMode
5246 shareMode
= GetShareModeFromSTGM(grfMode
);
5247 accessMode
= GetAccessModeFromSTGM(grfMode
);
5248 creationMode
= GetCreationModeFromSTGM(grfMode
);
5250 if (grfMode
& STGM_DELETEONRELEASE
)
5251 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
5253 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
5255 if (grfMode
& STGM_TRANSACTED
)
5256 FIXME("Transacted mode not implemented.\n");
5259 * Initialize the "out" parameter.
5263 hFile
= CreateFileW(pwcsName
,
5271 if (hFile
== INVALID_HANDLE_VALUE
)
5277 * Allocate and initialize the new IStorage32object.
5279 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5281 if (newStorage
== 0)
5282 return STG_E_INSUFFICIENTMEMORY
;
5284 hr
= StorageImpl_Construct(
5293 HeapFree(GetProcessHeap(), 0, newStorage
);
5298 * Get an "out" pointer for the caller.
5300 hr
= StorageBaseImpl_QueryInterface(
5301 (IStorage
*)newStorage
,
5302 (REFIID
)&IID_IStorage
,
5308 /******************************************************************************
5309 * StgOpenStorage32 [OLE32.148]
5311 HRESULT WINAPI
StgOpenStorage(
5312 const OLECHAR
*pwcsName
,
5313 IStorage
*pstgPriority
,
5317 IStorage
**ppstgOpen
)
5319 StorageImpl
* newStorage
= 0;
5325 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5326 debugstr_w(pwcsName
), pstgPriority
, grfMode
,
5327 snbExclude
, reserved
, ppstgOpen
);
5330 * Perform a sanity check
5332 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
5333 return STG_E_INVALIDPOINTER
;
5336 * Validate the STGM flags
5338 if ( FAILED( validateSTGM(grfMode
) ))
5339 return STG_E_INVALIDFLAG
;
5342 * Interpret the STGM value grfMode
5344 shareMode
= GetShareModeFromSTGM(grfMode
);
5345 accessMode
= GetAccessModeFromSTGM(grfMode
);
5348 * Initialize the "out" parameter.
5352 hFile
= CreateFileW( pwcsName
,
5357 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5361 if (hFile
==INVALID_HANDLE_VALUE
)
5367 * Allocate and initialize the new IStorage32object.
5369 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5371 if (newStorage
== 0)
5372 return STG_E_INSUFFICIENTMEMORY
;
5374 hr
= StorageImpl_Construct(
5383 HeapFree(GetProcessHeap(), 0, newStorage
);
5388 * Get an "out" pointer for the caller.
5390 hr
= StorageBaseImpl_QueryInterface(
5391 (IStorage
*)newStorage
,
5392 (REFIID
)&IID_IStorage
,
5398 /******************************************************************************
5399 * StgCreateDocfileOnILockBytes [OLE32.145]
5401 HRESULT WINAPI
StgCreateDocfileOnILockBytes(
5405 IStorage
** ppstgOpen
)
5407 StorageImpl
* newStorage
= 0;
5411 * Validate the parameters
5413 if ((ppstgOpen
== 0) || (plkbyt
== 0))
5414 return STG_E_INVALIDPOINTER
;
5417 * Allocate and initialize the new IStorage object.
5419 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5421 if (newStorage
== 0)
5422 return STG_E_INSUFFICIENTMEMORY
;
5424 hr
= StorageImpl_Construct(
5433 HeapFree(GetProcessHeap(), 0, newStorage
);
5438 * Get an "out" pointer for the caller.
5440 hr
= StorageBaseImpl_QueryInterface(
5441 (IStorage
*)newStorage
,
5442 (REFIID
)&IID_IStorage
,
5448 /******************************************************************************
5449 * StgOpenStorageOnILockBytes [OLE32.149]
5451 HRESULT WINAPI
StgOpenStorageOnILockBytes(
5453 IStorage
*pstgPriority
,
5457 IStorage
**ppstgOpen
)
5459 StorageImpl
* newStorage
= 0;
5463 * Perform a sanity check
5465 if ((plkbyt
== 0) || (ppstgOpen
== 0))
5466 return STG_E_INVALIDPOINTER
;
5469 * Validate the STGM flags
5471 if ( FAILED( validateSTGM(grfMode
) ))
5472 return STG_E_INVALIDFLAG
;
5475 * Initialize the "out" parameter.
5480 * Allocate and initialize the new IStorage object.
5482 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5484 if (newStorage
== 0)
5485 return STG_E_INSUFFICIENTMEMORY
;
5487 hr
= StorageImpl_Construct(
5496 HeapFree(GetProcessHeap(), 0, newStorage
);
5501 * Get an "out" pointer for the caller.
5503 hr
= StorageBaseImpl_QueryInterface(
5504 (IStorage
*)newStorage
,
5505 (REFIID
)&IID_IStorage
,
5511 /******************************************************************************
5512 * StgIsStorageILockBytes [OLE32.147]
5514 * Determines if the ILockBytes contains a storage object.
5516 HRESULT WINAPI
StgIsStorageILockBytes(ILockBytes
*plkbyt
)
5519 ULARGE_INTEGER offset
;
5521 offset
.HighPart
= 0;
5524 ILockBytes_ReadAt(plkbyt
, offset
, sig
, sizeof(sig
), NULL
);
5526 if (memcmp(sig
, STORAGE_magic
, sizeof(STORAGE_magic
)) == 0)
5532 /******************************************************************************
5533 * WriteClassStg32 [OLE32.158]
5535 * This method will store the specified CLSID in the specified storage object
5537 HRESULT WINAPI
WriteClassStg(IStorage
* pStg
, REFCLSID rclsid
)
5543 hRes
= IStorage_SetClass(pStg
, rclsid
);
5548 /*******************************************************************************************
5551 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5553 HRESULT WINAPI
ReadClassStg(IStorage
*pstg
,CLSID
*pclsid
){
5563 * read a STATSTG structure (contains the clsid) from the storage
5565 hRes
=IStorage_Stat(pstg
,&pstatstg
,STATFLAG_DEFAULT
);
5568 *pclsid
=pstatstg
.clsid
;
5573 /*************************************************************************************
5576 * This function loads an object from stream
5578 HRESULT WINAPI
OleLoadFromStream(IStream
*pStm
,REFIID iidInterface
,void** ppvObj
)
5583 FIXME("(),stub!\n");
5585 res
=ReadClassStm(pStm
,&clsid
);
5587 if (SUCCEEDED(res
)){
5589 res
=CoCreateInstance(&clsid
,NULL
,CLSCTX_INPROC_SERVER
,iidInterface
,ppvObj
);
5593 res
=IPersistStream_Load((IPersistStream
*)ppvObj
,pStm
);
5599 /************************************************************************************************
5602 * This function saves an object with the IPersistStream interface on it to the specified stream
5604 HRESULT WINAPI
OleSaveToStream(IPersistStream
*pPStm
,IStream
*pStm
)
5610 TRACE("(%p,%p)\n",pPStm
,pStm
);
5612 res
=IPersistStream_GetClassID(pPStm
,&clsid
);
5614 if (SUCCEEDED(res
)){
5616 res
=WriteClassStm(pStm
,&clsid
);
5620 res
=IPersistStream_Save(pPStm
,pStm
,FALSE
);
5626 /****************************************************************************
5627 * This method validate a STGM parameter that can contain the values below
5629 * STGM_DIRECT 0x00000000
5630 * STGM_TRANSACTED 0x00010000
5631 * STGM_SIMPLE 0x08000000
5633 * STGM_READ 0x00000000
5634 * STGM_WRITE 0x00000001
5635 * STGM_READWRITE 0x00000002
5637 * STGM_SHARE_DENY_NONE 0x00000040
5638 * STGM_SHARE_DENY_READ 0x00000030
5639 * STGM_SHARE_DENY_WRITE 0x00000020
5640 * STGM_SHARE_EXCLUSIVE 0x00000010
5642 * STGM_PRIORITY 0x00040000
5643 * STGM_DELETEONRELEASE 0x04000000
5645 * STGM_CREATE 0x00001000
5646 * STGM_CONVERT 0x00020000
5647 * STGM_FAILIFTHERE 0x00000000
5649 * STGM_NOSCRATCH 0x00100000
5650 * STGM_NOSNAPSHOT 0x00200000
5652 static HRESULT
validateSTGM(DWORD stgm
)
5654 BOOL bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5655 BOOL bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5656 BOOL bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5658 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5659 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5660 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5662 BOOL bSTGM_SHARE_DENY_NONE
=
5663 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5665 BOOL bSTGM_SHARE_DENY_READ
=
5666 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5668 BOOL bSTGM_SHARE_DENY_WRITE
=
5669 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5671 BOOL bSTGM_SHARE_EXCLUSIVE
=
5672 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5674 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5675 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5677 BOOL bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5678 BOOL bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5681 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5683 if ( ! bSTGM_DIRECT
)
5684 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5688 * STGM_WRITE | STGM_READWRITE | STGM_READ
5691 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5695 * STGM_SHARE_DENY_NONE | others
5696 * (I assume here that DENY_READ implies DENY_WRITE)
5698 if ( bSTGM_SHARE_DENY_NONE
)
5699 if ( bSTGM_SHARE_DENY_READ
||
5700 bSTGM_SHARE_DENY_WRITE
||
5701 bSTGM_SHARE_EXCLUSIVE
)
5705 * STGM_CREATE | STGM_CONVERT
5706 * if both are false, STGM_FAILIFTHERE is set to TRUE
5708 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5712 * STGM_NOSCRATCH requires STGM_TRANSACTED
5714 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5718 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5719 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5721 if (bSTGM_NOSNAPSHOT
)
5723 if ( ! ( bSTGM_TRANSACTED
&&
5724 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
5731 /****************************************************************************
5732 * GetShareModeFromSTGM
5734 * This method will return a share mode flag from a STGM value.
5735 * The STGM value is assumed valid.
5737 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
5739 DWORD dwShareMode
= 0;
5740 BOOL bSTGM_SHARE_DENY_NONE
=
5741 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5743 BOOL bSTGM_SHARE_DENY_READ
=
5744 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5746 BOOL bSTGM_SHARE_DENY_WRITE
=
5747 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5749 BOOL bSTGM_SHARE_EXCLUSIVE
=
5750 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5752 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
5755 if (bSTGM_SHARE_DENY_NONE
)
5756 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
5758 if (bSTGM_SHARE_DENY_WRITE
)
5759 dwShareMode
= FILE_SHARE_READ
;
5764 /****************************************************************************
5765 * GetAccessModeFromSTGM
5767 * This method will return an access mode flag from a STGM value.
5768 * The STGM value is assumed valid.
5770 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
5772 DWORD dwDesiredAccess
= GENERIC_READ
;
5773 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5774 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5775 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5778 dwDesiredAccess
= GENERIC_READ
;
5781 dwDesiredAccess
|= GENERIC_WRITE
;
5783 if (bSTGM_READWRITE
)
5784 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
5786 return dwDesiredAccess
;
5789 /****************************************************************************
5790 * GetCreationModeFromSTGM
5792 * This method will return a creation mode flag from a STGM value.
5793 * The STGM value is assumed valid.
5795 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
5797 if ( stgm
& STGM_CREATE
)
5798 return CREATE_ALWAYS
;
5799 if (stgm
& STGM_CONVERT
) {
5800 FIXME("STGM_CONVERT not implemented!\n");
5803 /* All other cases */
5804 if (stgm
& ~ (STGM_CREATE
|STGM_CONVERT
))
5805 FIXME("unhandled storage mode : 0x%08lx\n",stgm
& ~ (STGM_CREATE
|STGM_CONVERT
));