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"
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 StorageBaseImpl_QueryInterface
,
93 StorageBaseImpl_AddRef
,
94 StorageBaseImpl_Release
,
95 StorageBaseImpl_CreateStream
,
96 StorageBaseImpl_OpenStream
,
97 StorageImpl_CreateStorage
,
98 StorageBaseImpl_OpenStorage
,
100 StorageImpl_MoveElementTo
,
103 StorageBaseImpl_EnumElements
,
104 StorageImpl_DestroyElement
,
105 StorageBaseImpl_RenameElement
,
106 StorageImpl_SetElementTimes
,
107 StorageBaseImpl_SetClass
,
108 StorageImpl_SetStateBits
,
113 * Virtual function table for the Storage32InternalImpl class.
115 static ICOM_VTABLE(IStorage
) Storage32InternalImpl_Vtbl
=
117 StorageBaseImpl_QueryInterface
,
118 StorageBaseImpl_AddRef
,
119 StorageBaseImpl_Release
,
120 StorageBaseImpl_CreateStream
,
121 StorageBaseImpl_OpenStream
,
122 StorageImpl_CreateStorage
,
123 StorageBaseImpl_OpenStorage
,
125 StorageImpl_MoveElementTo
,
126 StorageInternalImpl_Commit
,
127 StorageInternalImpl_Revert
,
128 StorageBaseImpl_EnumElements
,
129 StorageImpl_DestroyElement
,
130 StorageBaseImpl_RenameElement
,
131 StorageImpl_SetElementTimes
,
132 StorageBaseImpl_SetClass
,
133 StorageImpl_SetStateBits
,
138 * Virtual function table for the IEnumSTATSTGImpl class.
140 static ICOM_VTABLE(IEnumSTATSTG
) IEnumSTATSTGImpl_Vtbl
=
142 IEnumSTATSTGImpl_QueryInterface
,
143 IEnumSTATSTGImpl_AddRef
,
144 IEnumSTATSTGImpl_Release
,
145 IEnumSTATSTGImpl_Next
,
146 IEnumSTATSTGImpl_Skip
,
147 IEnumSTATSTGImpl_Reset
,
148 IEnumSTATSTGImpl_Clone
155 /************************************************************************
156 ** Storage32BaseImpl implementatiion
159 /************************************************************************
160 * Storage32BaseImpl_QueryInterface (IUnknown)
162 * This method implements the common QueryInterface for all IStorage32
163 * implementations contained in this file.
165 * See Windows documentation for more details on IUnknown methods.
167 HRESULT WINAPI
StorageBaseImpl_QueryInterface(
172 ICOM_THIS(StorageBaseImpl
,iface
);
174 * Perform a sanity check on the parameters.
176 if ( (This
==0) || (ppvObject
==0) )
180 * Initialize the return parameter.
185 * Compare the riid with the interface IDs implemented by this object.
187 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
189 *ppvObject
= (IStorage
*)This
;
191 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
193 *ppvObject
= (IStorage
*)This
;
197 * Check that we obtained an interface.
200 return E_NOINTERFACE
;
203 * Query Interface always increases the reference count by one when it is
206 StorageBaseImpl_AddRef(iface
);
211 /************************************************************************
212 * Storage32BaseImpl_AddRef (IUnknown)
214 * This method implements the common AddRef for all IStorage32
215 * implementations contained in this file.
217 * See Windows documentation for more details on IUnknown methods.
219 ULONG WINAPI
StorageBaseImpl_AddRef(
222 ICOM_THIS(StorageBaseImpl
,iface
);
228 /************************************************************************
229 * Storage32BaseImpl_Release (IUnknown)
231 * This method implements the common Release for all IStorage32
232 * implementations contained in this file.
234 * See Windows documentation for more details on IUnknown methods.
236 ULONG WINAPI
StorageBaseImpl_Release(
239 ICOM_THIS(StorageBaseImpl
,iface
);
241 * Decrease the reference count on this object.
246 * If the reference count goes down to 0, perform suicide.
251 * Since we are using a system of base-classes, we want to call the
252 * destructor of the appropriate derived class. To do this, we are
253 * using virtual functions to implement the destructor.
255 This
->v_destructor(This
);
263 /************************************************************************
264 * Storage32BaseImpl_OpenStream (IStorage)
266 * This method will open the specified stream object from the current storage.
268 * See Windows documentation for more details on IStorage methods.
270 HRESULT WINAPI
StorageBaseImpl_OpenStream(
272 const OLECHAR
* pwcsName
, /* [string][in] */
273 void* reserved1
, /* [unique][in] */
274 DWORD grfMode
, /* [in] */
275 DWORD reserved2
, /* [in] */
276 IStream
** ppstm
) /* [out] */
278 ICOM_THIS(StorageBaseImpl
,iface
);
279 IEnumSTATSTGImpl
* propertyEnumeration
;
280 StgStreamImpl
* newStream
;
281 StgProperty currentProperty
;
282 ULONG foundPropertyIndex
;
284 TRACE(storage
, "(%p, %s, %p, %lx, %ld, %p)\n",
285 iface
, debugstr_w(pwcsName
), reserved1
, grfMode
, reserved2
, ppstm
);
288 * Perform a sanity check on the parameters.
290 if ( (pwcsName
==NULL
) || (ppstm
==0) )
294 * Initialize the out parameter
299 * Validate the STGM flags
301 if ( FAILED( validateSTGM(grfMode
) ))
302 return STG_E_INVALIDFLAG
;
307 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
308 (grfMode
& STGM_DELETEONRELEASE
) ||
309 (grfMode
& STGM_TRANSACTED
) )
310 return STG_E_INVALIDFUNCTION
;
313 * Create a property enumeration to search the properties
315 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
316 This
->ancestorStorage
,
317 This
->rootPropertySetIndex
);
320 * Search the enumeration for the property with the given name
322 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
328 * Delete the property enumeration since we don't need it anymore
330 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
333 * If it was found, construct the stream object and return a pointer to it.
335 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
336 (currentProperty
.propertyType
==PROPTYPE_STREAM
) )
338 newStream
= StgStreamImpl_Construct(This
, foundPropertyIndex
);
342 *ppstm
= (IStream
*)newStream
;
345 * Since we are returning a pointer to the interface, we have to
346 * nail down the reference.
348 StgStreamImpl_AddRef(*ppstm
);
353 return E_OUTOFMEMORY
;
356 return STG_E_FILENOTFOUND
;
359 /************************************************************************
360 * Storage32BaseImpl_OpenStorage (IStorage)
362 * This method will open a new storage object from the current storage.
364 * See Windows documentation for more details on IStorage methods.
366 HRESULT WINAPI
StorageBaseImpl_OpenStorage(
368 const OLECHAR
* pwcsName
, /* [string][unique][in] */
369 IStorage
* pstgPriority
, /* [unique][in] */
370 DWORD grfMode
, /* [in] */
371 SNB snbExclude
, /* [unique][in] */
372 DWORD reserved
, /* [in] */
373 IStorage
** ppstg
) /* [out] */
375 ICOM_THIS(StorageBaseImpl
,iface
);
376 StorageInternalImpl
* newStorage
;
377 IEnumSTATSTGImpl
* propertyEnumeration
;
378 StgProperty currentProperty
;
379 ULONG foundPropertyIndex
;
381 TRACE(storage
, "(%p, %s, %p, %lx, %p, %ld, %p)\n",
382 iface
, debugstr_w(pwcsName
), pstgPriority
,
383 grfMode
, snbExclude
, reserved
, ppstg
);
386 * Perform a sanity check on the parameters.
388 if ( (This
==0) || (pwcsName
==NULL
) || (ppstg
==0) )
392 * Validate the STGM flags
394 if ( FAILED( validateSTGM(grfMode
) ))
395 return STG_E_INVALIDFLAG
;
400 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
401 (grfMode
& STGM_DELETEONRELEASE
) ||
402 (grfMode
& STGM_PRIORITY
) )
403 return STG_E_INVALIDFUNCTION
;
406 * Initialize the out parameter
411 * Create a property enumeration to search the properties
413 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
414 This
->ancestorStorage
,
415 This
->rootPropertySetIndex
);
418 * Search the enumeration for the property with the given name
420 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
426 * Delete the property enumeration since we don't need it anymore
428 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
431 * If it was found, construct the stream object and return a pointer to it.
433 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
434 (currentProperty
.propertyType
==PROPTYPE_STORAGE
) )
437 * Construct a new Storage object
439 newStorage
= StorageInternalImpl_Construct(
440 This
->ancestorStorage
,
445 *ppstg
= (IStorage
*)newStorage
;
448 * Since we are returning a pointer to the interface,
449 * we have to nail down the reference.
451 StorageBaseImpl_AddRef(*ppstg
);
456 return STG_E_INSUFFICIENTMEMORY
;
459 return STG_E_FILENOTFOUND
;
462 /************************************************************************
463 * Storage32BaseImpl_EnumElements (IStorage)
465 * This method will create an enumerator object that can be used to
466 * retrieve informatino about all the properties in the storage object.
468 * See Windows documentation for more details on IStorage methods.
470 HRESULT WINAPI
StorageBaseImpl_EnumElements(
472 DWORD reserved1
, /* [in] */
473 void* reserved2
, /* [size_is][unique][in] */
474 DWORD reserved3
, /* [in] */
475 IEnumSTATSTG
** ppenum
) /* [out] */
477 ICOM_THIS(StorageBaseImpl
,iface
);
478 IEnumSTATSTGImpl
* newEnum
;
480 TRACE(storage
, "(%p, %ld, %p, %ld, %p)\n",
481 iface
, reserved1
, reserved2
, reserved3
, ppenum
);
484 * Perform a sanity check on the parameters.
486 if ( (This
==0) || (ppenum
==0))
490 * Construct the enumerator.
492 newEnum
= IEnumSTATSTGImpl_Construct(
493 This
->ancestorStorage
,
494 This
->rootPropertySetIndex
);
498 *ppenum
= (IEnumSTATSTG
*)newEnum
;
501 * Don't forget to nail down a reference to the new object before
504 IEnumSTATSTGImpl_AddRef(*ppenum
);
509 return E_OUTOFMEMORY
;
512 /************************************************************************
513 * Storage32BaseImpl_Stat (IStorage)
515 * This method will retrieve information about this storage object.
517 * See Windows documentation for more details on IStorage methods.
519 HRESULT WINAPI
StorageBaseImpl_Stat(
521 STATSTG
* pstatstg
, /* [out] */
522 DWORD grfStatFlag
) /* [in] */
524 ICOM_THIS(StorageBaseImpl
,iface
);
525 StgProperty curProperty
;
528 TRACE(storage
, "(%p, %p, %lx)\n",
529 iface
, pstatstg
, grfStatFlag
);
532 * Perform a sanity check on the parameters.
534 if ( (This
==0) || (pstatstg
==0))
538 * Read the information from the property.
540 readSucessful
= StorageImpl_ReadProperty(
541 This
->ancestorStorage
,
542 This
->rootPropertySetIndex
,
547 StorageUtl_CopyPropertyToSTATSTG(
558 /************************************************************************
559 * Storage32BaseImpl_RenameElement (IStorage)
561 * This method will rename the specified element.
563 * See Windows documentation for more details on IStorage methods.
565 * Implementation notes: The method used to rename consists of creating a clone
566 * of the deleted StgProperty object setting it with the new name and to
567 * perform a DestroyElement of the old StgProperty.
569 HRESULT WINAPI
StorageBaseImpl_RenameElement(
571 const OLECHAR
* pwcsOldName
, /* [in] */
572 const OLECHAR
* pwcsNewName
) /* [in] */
574 ICOM_THIS(StorageBaseImpl
,iface
);
575 IEnumSTATSTGImpl
* propertyEnumeration
;
576 StgProperty currentProperty
;
577 ULONG foundPropertyIndex
;
579 TRACE(storage
, "(%p, %s, %s)\n",
580 iface
, debugstr_w(pwcsOldName
), debugstr_w(pwcsNewName
));
583 * Create a property enumeration to search the properties
585 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
586 This
->rootPropertySetIndex
);
589 * Search the enumeration for the new property name
591 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
595 if (foundPropertyIndex
!= PROPERTY_NULL
)
598 * There is already a property with the new name
600 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
601 return STG_E_FILEALREADYEXISTS
;
604 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)propertyEnumeration
);
607 * Search the enumeration for the old property name
609 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
614 * Delete the property enumeration since we don't need it anymore
616 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
618 if (foundPropertyIndex
!= PROPERTY_NULL
)
620 StgProperty renamedProperty
;
621 ULONG renamedPropertyIndex
;
624 * Setup a new property for the renamed property
626 renamedProperty
.sizeOfNameString
=
627 ( lstrlenW(pwcsNewName
)+1 ) * sizeof(WCHAR
);
629 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
630 return STG_E_INVALIDNAME
;
632 lstrcpyW(renamedProperty
.name
, pwcsNewName
);
634 renamedProperty
.propertyType
= currentProperty
.propertyType
;
635 renamedProperty
.startingBlock
= currentProperty
.startingBlock
;
636 renamedProperty
.size
.LowPart
= currentProperty
.size
.LowPart
;
637 renamedProperty
.size
.HighPart
= currentProperty
.size
.HighPart
;
639 renamedProperty
.previousProperty
= PROPERTY_NULL
;
640 renamedProperty
.nextProperty
= PROPERTY_NULL
;
643 * Bring the dirProperty link in case it is a storage and in which
644 * case the renamed storage elements don't require to be reorganized.
646 renamedProperty
.dirProperty
= currentProperty
.dirProperty
;
648 /* call CoFileTime to get the current time
649 renamedProperty.timeStampS1
650 renamedProperty.timeStampD1
651 renamedProperty.timeStampS2
652 renamedProperty.timeStampD2
653 renamedProperty.propertyUniqueID
657 * Obtain a free property in the property chain
659 renamedPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
662 * Save the new property into the new property spot
664 StorageImpl_WriteProperty(
665 This
->ancestorStorage
,
666 renamedPropertyIndex
,
670 * Find a spot in the property chain for our newly created property.
674 renamedPropertyIndex
,
678 * At this point the renamed property has been inserted in the tree,
679 * now, before to Destroy the old property we must zeroed it's dirProperty
680 * otherwise the DestroyProperty below will zap it all and we do not want
682 * Also, we fake that the old property is a storage so the DestroyProperty
683 * will not do a SetSize(0) on the stream data.
685 * This means that we need to tweek the StgProperty if it is a stream or a
688 currentProperty
.dirProperty
= PROPERTY_NULL
;
689 currentProperty
.propertyType
= PROPTYPE_STORAGE
;
690 StorageImpl_WriteProperty(
691 This
->ancestorStorage
,
696 * Invoke Destroy to get rid of the ole property and automatically redo
697 * the linking of it's previous and next members...
699 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsOldName
);
705 * There is no property with the old name
707 return STG_E_FILENOTFOUND
;
713 /************************************************************************
714 * Storage32BaseImpl_CreateStream (IStorage)
716 * This method will create a stream object within this storage
718 * See Windows documentation for more details on IStorage methods.
720 HRESULT WINAPI
StorageBaseImpl_CreateStream(
722 const OLECHAR
* pwcsName
, /* [string][in] */
723 DWORD grfMode
, /* [in] */
724 DWORD reserved1
, /* [in] */
725 DWORD reserved2
, /* [in] */
726 IStream
** ppstm
) /* [out] */
728 ICOM_THIS(StorageBaseImpl
,iface
);
729 IEnumSTATSTGImpl
* propertyEnumeration
;
730 StgStreamImpl
* newStream
;
731 StgProperty currentProperty
, newStreamProperty
;
732 ULONG foundPropertyIndex
, newPropertyIndex
;
734 TRACE(storage
, "(%p, %s, %lx, %ld, %ld, %p)\n",
735 iface
, debugstr_w(pwcsName
), grfMode
,
736 reserved1
, reserved2
, ppstm
);
739 * Validate parameters
742 return STG_E_INVALIDPOINTER
;
745 return STG_E_INVALIDNAME
;
748 * Validate the STGM flags
750 if ( FAILED( validateSTGM(grfMode
) ))
751 return STG_E_INVALIDFLAG
;
756 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
757 (grfMode
& STGM_DELETEONRELEASE
) ||
758 (grfMode
& STGM_TRANSACTED
) )
759 return STG_E_INVALIDFUNCTION
;
762 * Initialize the out parameter
767 * Create a property enumeration to search the properties
769 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
770 This
->rootPropertySetIndex
);
772 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
776 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
778 if (foundPropertyIndex
!= PROPERTY_NULL
)
781 * An element with this name already exists
783 if (grfMode
& STGM_CREATE
)
785 IStorage_DestroyElement(iface
, pwcsName
);
788 return STG_E_FILEALREADYEXISTS
;
792 * memset the empty property
794 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
796 newStreamProperty
.sizeOfNameString
=
797 ( lstrlenW(pwcsName
)+1 ) * sizeof(WCHAR
);
799 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
800 return STG_E_INVALIDNAME
;
802 lstrcpyW(newStreamProperty
.name
, pwcsName
);
804 newStreamProperty
.propertyType
= PROPTYPE_STREAM
;
805 newStreamProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
806 newStreamProperty
.size
.LowPart
= 0;
807 newStreamProperty
.size
.HighPart
= 0;
809 newStreamProperty
.previousProperty
= PROPERTY_NULL
;
810 newStreamProperty
.nextProperty
= PROPERTY_NULL
;
811 newStreamProperty
.dirProperty
= PROPERTY_NULL
;
813 /* call CoFileTime to get the current time
814 newStreamProperty.timeStampS1
815 newStreamProperty.timeStampD1
816 newStreamProperty.timeStampS2
817 newStreamProperty.timeStampD2
820 /* newStreamProperty.propertyUniqueID */
823 * Get a free property or create a new one
825 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
828 * Save the new property into the new property spot
830 StorageImpl_WriteProperty(
831 This
->ancestorStorage
,
836 * Find a spot in the property chain for our newly created property.
844 * Open the stream to return it.
846 newStream
= StgStreamImpl_Construct(This
, newPropertyIndex
);
850 *ppstm
= (IStream
*)newStream
;
853 * Since we are returning a pointer to the interface, we have to nail down
856 StgStreamImpl_AddRef(*ppstm
);
860 return STG_E_INSUFFICIENTMEMORY
;
866 /************************************************************************
867 * Storage32BaseImpl_SetClass (IStorage)
869 * This method will write the specified CLSID in the property of this
872 * See Windows documentation for more details on IStorage methods.
874 HRESULT WINAPI
StorageBaseImpl_SetClass(
876 REFCLSID clsid
) /* [in] */
878 ICOM_THIS(StorageBaseImpl
,iface
);
879 HRESULT hRes
= E_FAIL
;
880 StgProperty curProperty
;
883 TRACE(storage
, "(%p, %p)\n", iface
, clsid
);
885 success
= StorageImpl_ReadProperty(This
->ancestorStorage
,
886 This
->rootPropertySetIndex
,
890 curProperty
.propertyUniqueID
= *clsid
;
892 success
= StorageImpl_WriteProperty(This
->ancestorStorage
,
893 This
->rootPropertySetIndex
,
902 /************************************************************************
903 ** Storage32Impl implementation
906 /************************************************************************
907 * Storage32Impl_CreateStorage (IStorage)
909 * This method will create the storage object within the provided storage.
911 * See Windows documentation for more details on IStorage methods.
913 HRESULT WINAPI
StorageImpl_CreateStorage(
915 const OLECHAR
*pwcsName
, /* [string][in] */
916 DWORD grfMode
, /* [in] */
917 DWORD reserved1
, /* [in] */
918 DWORD reserved2
, /* [in] */
919 IStorage
**ppstg
) /* [out] */
921 StorageImpl
* const This
=(StorageImpl
*)iface
;
923 IEnumSTATSTGImpl
*propertyEnumeration
;
924 StgProperty currentProperty
;
925 StgProperty newProperty
;
926 ULONG foundPropertyIndex
;
927 ULONG newPropertyIndex
;
930 TRACE(storage
, "(%p, %s, %lx, %ld, %ld, %p)\n",
931 iface
, debugstr_w(pwcsName
), grfMode
,
932 reserved1
, reserved2
, ppstg
);
935 * Validate parameters
938 return STG_E_INVALIDPOINTER
;
941 return STG_E_INVALIDNAME
;
944 * Validate the STGM flags
946 if ( FAILED( validateSTGM(grfMode
) ) ||
947 (grfMode
& STGM_DELETEONRELEASE
) )
948 return STG_E_INVALIDFLAG
;
951 * Initialize the out parameter
956 * Create a property enumeration and search the properties
958 propertyEnumeration
= IEnumSTATSTGImpl_Construct( This
->ancestorStorage
,
959 This
->rootPropertySetIndex
);
961 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
964 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
966 if (foundPropertyIndex
!= PROPERTY_NULL
)
969 * An element with this name already exists
971 if (grfMode
& STGM_CREATE
)
972 IStorage_DestroyElement(iface
, pwcsName
);
974 return STG_E_FILEALREADYEXISTS
;
978 * memset the empty property
980 memset(&newProperty
, 0, sizeof(StgProperty
));
982 newProperty
.sizeOfNameString
= (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
);
984 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
985 return STG_E_INVALIDNAME
;
987 lstrcpyW(newProperty
.name
, pwcsName
);
989 newProperty
.propertyType
= PROPTYPE_STORAGE
;
990 newProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
991 newProperty
.size
.LowPart
= 0;
992 newProperty
.size
.HighPart
= 0;
994 newProperty
.previousProperty
= PROPERTY_NULL
;
995 newProperty
.nextProperty
= PROPERTY_NULL
;
996 newProperty
.dirProperty
= PROPERTY_NULL
;
998 /* call CoFileTime to get the current time
999 newProperty.timeStampS1
1000 newProperty.timeStampD1
1001 newProperty.timeStampS2
1002 newProperty.timeStampD2
1005 /* newStorageProperty.propertyUniqueID */
1008 * Obtain a free property in the property chain
1010 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
1013 * Save the new property into the new property spot
1015 StorageImpl_WriteProperty(
1016 This
->ancestorStorage
,
1021 * Find a spot in the property chain for our newly created property.
1023 updatePropertyChain(
1029 * Open it to get a pointer to return.
1031 hr
= IStorage_OpenStorage(
1040 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1050 /***************************************************************************
1054 * Get a free property or create a new one.
1056 static ULONG
getFreeProperty(
1057 StorageImpl
*storage
)
1059 ULONG currentPropertyIndex
= 0;
1060 ULONG newPropertyIndex
= PROPERTY_NULL
;
1061 BOOL readSucessful
= TRUE
;
1062 StgProperty currentProperty
;
1067 * Start by reading the root property
1069 readSucessful
= StorageImpl_ReadProperty(storage
->ancestorStorage
,
1070 currentPropertyIndex
,
1074 if (currentProperty
.sizeOfNameString
== 0)
1077 * The property existis and is available, we found it.
1079 newPropertyIndex
= currentPropertyIndex
;
1085 * We exhausted the property list, we will create more space below
1087 newPropertyIndex
= currentPropertyIndex
;
1089 currentPropertyIndex
++;
1091 } while (newPropertyIndex
== PROPERTY_NULL
);
1094 * grow the property chain
1096 if (! readSucessful
)
1098 StgProperty emptyProperty
;
1099 ULARGE_INTEGER newSize
;
1100 ULONG propertyIndex
;
1101 ULONG lastProperty
= 0;
1102 ULONG blockCount
= 0;
1105 * obtain the new count of property blocks
1107 blockCount
= BlockChainStream_GetCount(
1108 storage
->ancestorStorage
->rootBlockChain
)+1;
1111 * initialize the size used by the property stream
1113 newSize
.HighPart
= 0;
1114 newSize
.LowPart
= storage
->bigBlockSize
* blockCount
;
1117 * add a property block to the property chain
1119 BlockChainStream_SetSize(storage
->ancestorStorage
->rootBlockChain
, newSize
);
1122 * memset the empty property in order to initialize the unused newly
1125 memset(&emptyProperty
, 0, sizeof(StgProperty
));
1130 lastProperty
= storage
->bigBlockSize
/ PROPSET_BLOCK_SIZE
* blockCount
;
1133 propertyIndex
= newPropertyIndex
;
1134 propertyIndex
< lastProperty
;
1137 StorageImpl_WriteProperty(
1138 storage
->ancestorStorage
,
1144 return newPropertyIndex
;
1147 /****************************************************************************
1151 * Case insensitive comparaison of StgProperty.name by first considering
1154 * Returns <0 when newPrpoerty < currentProperty
1155 * >0 when newPrpoerty > currentProperty
1156 * 0 when newPrpoerty == currentProperty
1158 static LONG
propertyNameCmp(
1159 OLECHAR
*newProperty
,
1160 OLECHAR
*currentProperty
)
1162 LONG diff
= lstrlenW(newProperty
) - lstrlenW(currentProperty
);
1167 * We compare the string themselves only when they are of the same lenght
1169 diff
= lstrcmpiW( newProperty
, currentProperty
);
1175 /****************************************************************************
1179 * Properly link this new element in the property chain.
1181 static void updatePropertyChain(
1182 StorageImpl
*storage
,
1183 ULONG newPropertyIndex
,
1184 StgProperty newProperty
)
1186 StgProperty currentProperty
;
1189 * Read the root property
1191 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1192 storage
->rootPropertySetIndex
,
1195 if (currentProperty
.dirProperty
!= PROPERTY_NULL
)
1198 * The root storage contains some element, therefore, start the research
1199 * for the appropriate location.
1202 ULONG current
, next
, previous
, currentPropertyId
;
1205 * Keep the StgProperty sequence number of the storage first property
1207 currentPropertyId
= currentProperty
.dirProperty
;
1212 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1213 currentProperty
.dirProperty
,
1216 previous
= currentProperty
.previousProperty
;
1217 next
= currentProperty
.nextProperty
;
1218 current
= currentPropertyId
;
1222 LONG diff
= propertyNameCmp( newProperty
.name
, currentProperty
.name
);
1226 if (previous
!= PROPERTY_NULL
)
1228 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1235 currentProperty
.previousProperty
= newPropertyIndex
;
1236 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1244 if (next
!= PROPERTY_NULL
)
1246 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1253 currentProperty
.nextProperty
= newPropertyIndex
;
1254 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1263 * Trying to insert an item with the same name in the
1264 * subtree structure.
1269 previous
= currentProperty
.previousProperty
;
1270 next
= currentProperty
.nextProperty
;
1276 * The root storage is empty, link the new property to it's dir property
1278 currentProperty
.dirProperty
= newPropertyIndex
;
1279 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1280 storage
->rootPropertySetIndex
,
1286 /*************************************************************************
1289 HRESULT WINAPI
StorageImpl_CopyTo(
1291 DWORD ciidExclude
, /* [in] */
1292 const IID
* rgiidExclude
, /* [size_is][unique][in] */
1293 SNB snbExclude
, /* [unique][in] */
1294 IStorage
* pstgDest
) /* [unique][in] */
1296 IEnumSTATSTG
*elements
= 0;
1297 STATSTG curElement
, strStat
;
1299 IStorage
*pstgTmp
, *pstgChild
;
1300 IStream
*pstrTmp
, *pstrChild
;
1302 if ((ciidExclude
!= 0) || (rgiidExclude
!= NULL
) || (snbExclude
!= NULL
))
1303 FIXME( storage
, "Exclude option not implemented\n");
1305 TRACE(storage
, "(%p, %ld, %p, %p, %p)\n",
1306 iface
, ciidExclude
, rgiidExclude
,
1307 snbExclude
, pstgDest
);
1310 * Perform a sanity check
1312 if ( pstgDest
== 0 )
1313 return STG_E_INVALIDPOINTER
;
1316 * Enumerate the elements
1318 hr
= IStorage_EnumElements( iface
, 0, 0, 0, &elements
);
1326 IStorage_Stat( iface
, &curElement
, STATFLAG_NONAME
);
1327 IStorage_SetClass( pstgDest
, &curElement
.clsid
);
1332 * Obtain the next element
1334 hr
= IEnumSTATSTG_Next( elements
, 1, &curElement
, NULL
);
1336 if ( hr
== S_FALSE
)
1338 hr
= S_OK
; /* done, every element has been copied */
1342 if (curElement
.type
== STGTY_STORAGE
)
1345 * open child source storage
1347 hr
= IStorage_OpenStorage( iface
, curElement
.pwcsName
, NULL
,
1348 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1349 NULL
, 0, &pstgChild
);
1355 * Check if destination storage is not a child of the source
1356 * storage, which will cause an infinite loop
1358 if (pstgChild
== pstgDest
)
1360 IEnumSTATSTG_Release(elements
);
1362 return STG_E_ACCESSDENIED
;
1366 * create a new storage in destination storage
1368 hr
= IStorage_CreateStorage( pstgDest
, curElement
.pwcsName
,
1369 STGM_FAILIFTHERE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1373 * if it already exist, don't create a new one use this one
1375 if (hr
== STG_E_FILEALREADYEXISTS
)
1377 hr
= IStorage_OpenStorage( pstgDest
, curElement
.pwcsName
, NULL
,
1378 STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1379 NULL
, 0, &pstgTmp
);
1387 * do the copy recursively
1389 hr
= IStorage_CopyTo( pstgChild
, ciidExclude
, rgiidExclude
,
1390 snbExclude
, pstgTmp
);
1392 IStorage_Release( pstgTmp
);
1393 IStorage_Release( pstgChild
);
1395 else if (curElement
.type
== STGTY_STREAM
)
1398 * create a new stream in destination storage. If the stream already
1399 * exist, it will be deleted and a new one will be created.
1401 hr
= IStorage_CreateStream( pstgDest
, curElement
.pwcsName
,
1402 STGM_CREATE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1409 * open child stream storage
1411 hr
= IStorage_OpenStream( iface
, curElement
.pwcsName
, NULL
,
1412 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1419 * Get the size of the source stream
1421 IStream_Stat( pstrChild
, &strStat
, STATFLAG_NONAME
);
1424 * Set the size of the destination stream.
1426 IStream_SetSize(pstrTmp
, strStat
.cbSize
);
1431 hr
= IStream_CopyTo( pstrChild
, pstrTmp
, strStat
.cbSize
,
1434 IStream_Release( pstrTmp
);
1435 IStream_Release( pstrChild
);
1439 WARN(storage
, "unknown element type: %ld\n", curElement
.type
);
1442 } while (hr
== S_OK
);
1447 IEnumSTATSTG_Release(elements
);
1452 /*************************************************************************
1453 * MoveElementTo (IStorage)
1455 HRESULT WINAPI
StorageImpl_MoveElementTo(
1457 const OLECHAR
*pwcsName
, /* [string][in] */
1458 IStorage
*pstgDest
, /* [unique][in] */
1459 const OLECHAR
*pwcsNewName
,/* [string][in] */
1460 DWORD grfFlags
) /* [in] */
1462 FIXME(storage
, "not implemented!\n");
1466 /*************************************************************************
1469 HRESULT WINAPI
StorageImpl_Commit(
1471 DWORD grfCommitFlags
)/* [in] */
1473 FIXME(storage
, "(%ld): stub!\n", grfCommitFlags
);
1477 /*************************************************************************
1480 HRESULT WINAPI
StorageImpl_Revert(
1483 FIXME(storage
, "not implemented!\n");
1487 /*************************************************************************
1488 * DestroyElement (IStorage)
1490 * Stategy: This implementation is build this way for simplicity not for speed.
1491 * I always delete the top most element of the enumeration and adjust
1492 * the deleted element pointer all the time. This takes longer to
1493 * do but allow to reinvoke DestroyElement whenever we encounter a
1494 * storage object. The optimisation reside in the usage of another
1495 * enumeration stategy that would give all the leaves of a storage
1496 * first. (postfix order)
1498 HRESULT WINAPI
StorageImpl_DestroyElement(
1500 const OLECHAR
*pwcsName
)/* [string][in] */
1502 StorageImpl
* const This
=(StorageImpl
*)iface
;
1504 IEnumSTATSTGImpl
* propertyEnumeration
;
1507 StgProperty propertyToDelete
;
1508 StgProperty parentProperty
;
1509 ULONG foundPropertyIndexToDelete
;
1510 ULONG typeOfRelation
;
1511 ULONG parentPropertyId
;
1513 TRACE(storage
, "(%p, %s)\n",
1514 iface
, debugstr_w(pwcsName
));
1517 * Perform a sanity check on the parameters.
1520 return STG_E_INVALIDPOINTER
;
1523 * Create a property enumeration to search the property with the given name
1525 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
1526 This
->ancestorStorage
,
1527 This
->rootPropertySetIndex
);
1529 foundPropertyIndexToDelete
= IEnumSTATSTGImpl_FindProperty(
1530 propertyEnumeration
,
1534 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1536 if ( foundPropertyIndexToDelete
== PROPERTY_NULL
)
1538 return STG_E_FILENOTFOUND
;
1542 * Find the parent property of the property to delete (the one that
1543 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1544 * the parent is This. Otherwise, the parent is one of it's sibling...
1548 * First, read This's StgProperty..
1550 res
= StorageImpl_ReadProperty(
1551 This
->ancestorStorage
,
1552 This
->rootPropertySetIndex
,
1558 * Second, check to see if by any chance the actual storage (This) is not
1559 * the parent of the property to delete... We never know...
1561 if ( parentProperty
.dirProperty
== foundPropertyIndexToDelete
)
1564 * Set data as it would have been done in the else part...
1566 typeOfRelation
= PROPERTY_RELATION_DIR
;
1567 parentPropertyId
= This
->rootPropertySetIndex
;
1572 * Create a property enumeration to search the parent properties, and
1573 * delete it once done.
1575 IEnumSTATSTGImpl
* propertyEnumeration2
;
1577 propertyEnumeration2
= IEnumSTATSTGImpl_Construct(
1578 This
->ancestorStorage
,
1579 This
->rootPropertySetIndex
);
1581 typeOfRelation
= IEnumSTATSTGImpl_FindParentProperty(
1582 propertyEnumeration2
,
1583 foundPropertyIndexToDelete
,
1587 IEnumSTATSTGImpl_Destroy(propertyEnumeration2
);
1590 if ( propertyToDelete
.propertyType
== PROPTYPE_STORAGE
)
1592 hr
= deleteStorageProperty(
1594 propertyToDelete
.name
);
1596 else if ( propertyToDelete
.propertyType
== PROPTYPE_STREAM
)
1598 hr
= deleteStreamProperty(
1600 foundPropertyIndexToDelete
,
1608 * Adjust the property chain
1610 hr
= adjustPropertyChain(
1621 /*********************************************************************
1625 * Perform the deletion of a complete storage node
1628 static HRESULT
deleteStorageProperty(
1629 StorageImpl
*parentStorage
,
1630 OLECHAR
*propertyToDeleteName
)
1632 IEnumSTATSTG
*elements
= 0;
1633 IStorage
*childStorage
= 0;
1634 STATSTG currentElement
;
1636 HRESULT destroyHr
= S_OK
;
1639 * Open the storage and enumerate it
1641 hr
= StorageBaseImpl_OpenStorage(
1642 (IStorage
*)parentStorage
,
1643 propertyToDeleteName
,
1645 STGM_SHARE_EXCLUSIVE
,
1656 * Enumerate the elements
1658 IStorage_EnumElements( childStorage
, 0, 0, 0, &elements
);
1663 * Obtain the next element
1665 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1668 destroyHr
= StorageImpl_DestroyElement(
1669 (IStorage
*)childStorage
,
1670 (OLECHAR
*)currentElement
.pwcsName
);
1672 CoTaskMemFree(currentElement
.pwcsName
);
1676 * We need to Reset the enumeration every time because we delete elements
1677 * and the enumeration could be invalid
1679 IEnumSTATSTG_Reset(elements
);
1681 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1683 IStorage_Release(childStorage
);
1684 IEnumSTATSTG_Release(elements
);
1689 /*********************************************************************
1693 * Perform the deletion of a stream node
1696 static HRESULT
deleteStreamProperty(
1697 StorageImpl
*parentStorage
,
1698 ULONG indexOfPropertyToDelete
,
1699 StgProperty propertyToDelete
)
1703 ULARGE_INTEGER size
;
1708 hr
= StorageBaseImpl_OpenStream(
1709 (IStorage
*)parentStorage
,
1710 (OLECHAR
*)propertyToDelete
.name
,
1712 STGM_SHARE_EXCLUSIVE
,
1724 hr
= IStream_SetSize(pis
, size
);
1732 * Release the stream object.
1734 IStream_Release(pis
);
1737 * Invalidate the property by zeroing it's name member.
1739 propertyToDelete
.sizeOfNameString
= 0;
1742 * Here we should re-read the property so we get the updated pointer
1743 * but since we are here to zap it, I don't do it...
1745 StorageImpl_WriteProperty(
1746 parentStorage
->ancestorStorage
,
1747 indexOfPropertyToDelete
,
1753 /*********************************************************************
1757 * Finds a placeholder for the StgProperty within the Storage
1760 static HRESULT
findPlaceholder(
1761 StorageImpl
*storage
,
1762 ULONG propertyIndexToStore
,
1763 ULONG storePropertyIndex
,
1766 StgProperty storeProperty
;
1771 * Read the storage property
1773 res
= StorageImpl_ReadProperty(
1774 storage
->ancestorStorage
,
1783 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1785 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1787 return findPlaceholder(
1789 propertyIndexToStore
,
1790 storeProperty
.previousProperty
,
1795 storeProperty
.previousProperty
= propertyIndexToStore
;
1798 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1800 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1802 return findPlaceholder(
1804 propertyIndexToStore
,
1805 storeProperty
.nextProperty
,
1810 storeProperty
.nextProperty
= propertyIndexToStore
;
1813 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1815 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1817 return findPlaceholder(
1819 propertyIndexToStore
,
1820 storeProperty
.dirProperty
,
1825 storeProperty
.dirProperty
= propertyIndexToStore
;
1829 hr
= StorageImpl_WriteProperty(
1830 storage
->ancestorStorage
,
1842 /*************************************************************************
1846 * This method takes the previous and the next property link of a property
1847 * to be deleted and find them a place in the Storage.
1849 static HRESULT
adjustPropertyChain(
1851 StgProperty propertyToDelete
,
1852 StgProperty parentProperty
,
1853 ULONG parentPropertyId
,
1856 ULONG newLinkProperty
= PROPERTY_NULL
;
1857 BOOL needToFindAPlaceholder
= FALSE
;
1858 ULONG storeNode
= PROPERTY_NULL
;
1859 ULONG toStoreNode
= PROPERTY_NULL
;
1860 INT relationType
= 0;
1864 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1866 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1869 * Set the parent previous to the property to delete previous
1871 newLinkProperty
= propertyToDelete
.previousProperty
;
1873 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1876 * We also need to find a storage for the other link, setup variables
1877 * to do this at the end...
1879 needToFindAPlaceholder
= TRUE
;
1880 storeNode
= propertyToDelete
.previousProperty
;
1881 toStoreNode
= propertyToDelete
.nextProperty
;
1882 relationType
= PROPERTY_RELATION_NEXT
;
1885 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1888 * Set the parent previous to the property to delete next
1890 newLinkProperty
= propertyToDelete
.nextProperty
;
1894 * Link it for real...
1896 parentProperty
.previousProperty
= newLinkProperty
;
1899 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1901 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1904 * Set the parent next to the property to delete next previous
1906 newLinkProperty
= propertyToDelete
.previousProperty
;
1908 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1911 * We also need to find a storage for the other link, setup variables
1912 * to do this at the end...
1914 needToFindAPlaceholder
= TRUE
;
1915 storeNode
= propertyToDelete
.previousProperty
;
1916 toStoreNode
= propertyToDelete
.nextProperty
;
1917 relationType
= PROPERTY_RELATION_NEXT
;
1920 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1923 * Set the parent next to the property to delete next
1925 newLinkProperty
= propertyToDelete
.nextProperty
;
1929 * Link it for real...
1931 parentProperty
.nextProperty
= newLinkProperty
;
1933 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1935 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1938 * Set the parent dir to the property to delete previous
1940 newLinkProperty
= propertyToDelete
.previousProperty
;
1942 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1945 * We also need to find a storage for the other link, setup variables
1946 * to do this at the end...
1948 needToFindAPlaceholder
= TRUE
;
1949 storeNode
= propertyToDelete
.previousProperty
;
1950 toStoreNode
= propertyToDelete
.nextProperty
;
1951 relationType
= PROPERTY_RELATION_NEXT
;
1954 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1957 * Set the parent dir to the property to delete next
1959 newLinkProperty
= propertyToDelete
.nextProperty
;
1963 * Link it for real...
1965 parentProperty
.dirProperty
= newLinkProperty
;
1969 * Write back the parent property
1971 res
= StorageImpl_WriteProperty(
1972 This
->ancestorStorage
,
1981 * If a placeholder is required for the other link, then, find one and
1982 * get out of here...
1984 if (needToFindAPlaceholder
)
1986 hr
= findPlaceholder(
1997 /******************************************************************************
1998 * SetElementTimes (IStorage)
2000 HRESULT WINAPI
StorageImpl_SetElementTimes(
2002 const OLECHAR
*pwcsName
,/* [string][in] */
2003 const FILETIME
*pctime
, /* [in] */
2004 const FILETIME
*patime
, /* [in] */
2005 const FILETIME
*pmtime
) /* [in] */
2007 FIXME(storage
, "not implemented!\n");
2011 /******************************************************************************
2012 * SetStateBits (IStorage)
2014 HRESULT WINAPI
StorageImpl_SetStateBits(
2016 DWORD grfStateBits
,/* [in] */
2017 DWORD grfMask
) /* [in] */
2019 FIXME(storage
, "not implemented!\n");
2023 HRESULT
StorageImpl_Construct(
2031 StgProperty currentProperty
;
2033 ULONG currentPropertyIndex
;
2035 if ( FAILED( validateSTGM(openFlags
) ))
2036 return STG_E_INVALIDFLAG
;
2038 memset(This
, 0, sizeof(StorageImpl
));
2041 * Initialize the virtual fgunction table.
2043 This
->lpvtbl
= &Storage32Impl_Vtbl
;
2044 This
->v_destructor
= &StorageImpl_Destroy
;
2047 * This is the top-level storage so initialize the ancester pointer
2050 This
->ancestorStorage
= This
;
2053 * Initialize the physical support of the storage.
2055 This
->hFile
= hFile
;
2058 * Initialize the big block cache.
2060 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
2061 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
2062 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
,
2068 if (This
->bigBlockFile
== 0)
2071 if (openFlags
& STGM_CREATE
)
2073 ULARGE_INTEGER size
;
2074 BYTE
* bigBlockBuffer
;
2077 * Initialize all header variables:
2078 * - The big block depot consists of one block and it is at block 0
2079 * - The properties start at block 1
2080 * - There is no small block depot
2082 memset( This
->bigBlockDepotStart
,
2084 sizeof(This
->bigBlockDepotStart
));
2086 This
->bigBlockDepotCount
= 1;
2087 This
->bigBlockDepotStart
[0] = 0;
2088 This
->rootStartBlock
= 1;
2089 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2090 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
2091 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
2092 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2093 This
->extBigBlockDepotCount
= 0;
2095 StorageImpl_SaveFileHeader(This
);
2098 * Add one block for the big block depot and one block for the properties
2101 size
.LowPart
= This
->bigBlockSize
* 3;
2102 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
2105 * Initialize the big block depot
2107 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, 0);
2108 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2109 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
2110 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
2111 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2116 * Load the header for the file.
2118 hr
= StorageImpl_LoadFileHeader(This
);
2122 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2129 * There is no block depot cached yet.
2131 This
->indexBlockDepotCached
= 0xFFFFFFFF;
2134 * Start searching for free blocks with block 0.
2136 This
->prevFreeBlock
= 0;
2139 * Create the block chain abstractions.
2141 This
->rootBlockChain
=
2142 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
2144 This
->smallBlockDepotChain
= BlockChainStream_Construct(
2146 &This
->smallBlockDepotStart
,
2150 * Write the root property
2152 if (openFlags
& STGM_CREATE
)
2154 StgProperty rootProp
;
2156 * Initialize the property chain
2158 memset(&rootProp
, 0, sizeof(rootProp
));
2159 lstrcpyAtoW(rootProp
.name
, rootPropertyName
);
2161 rootProp
.sizeOfNameString
= (lstrlenW(rootProp
.name
)+1) * sizeof(WCHAR
);
2162 rootProp
.propertyType
= PROPTYPE_ROOT
;
2163 rootProp
.previousProperty
= PROPERTY_NULL
;
2164 rootProp
.nextProperty
= PROPERTY_NULL
;
2165 rootProp
.dirProperty
= PROPERTY_NULL
;
2166 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
2167 rootProp
.size
.HighPart
= 0;
2168 rootProp
.size
.LowPart
= 0;
2170 StorageImpl_WriteProperty(This
, 0, &rootProp
);
2174 * Find the ID of the root int he property sets.
2176 currentPropertyIndex
= 0;
2180 readSucessful
= StorageImpl_ReadProperty(
2182 currentPropertyIndex
,
2187 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
2188 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
2190 This
->rootPropertySetIndex
= currentPropertyIndex
;
2194 currentPropertyIndex
++;
2196 } while (readSucessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
2205 * Create the block chain abstraction for the small block root chain.
2207 This
->smallBlockRootChain
= BlockChainStream_Construct(
2210 This
->rootPropertySetIndex
);
2215 void StorageImpl_Destroy(
2218 TRACE(storage
, "(%p)\n", This
);
2220 BlockChainStream_Destroy(This
->smallBlockRootChain
);
2221 BlockChainStream_Destroy(This
->rootBlockChain
);
2222 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
2224 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2228 /******************************************************************************
2229 * Storage32Impl_GetNextFreeBigBlock
2231 * Returns the index of the next free big block.
2232 * If the big block depot is filled, this method will enlarge it.
2235 ULONG
StorageImpl_GetNextFreeBigBlock(
2238 ULONG depotBlockIndexPos
;
2240 ULONG depotBlockOffset
;
2241 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
2242 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2244 ULONG freeBlock
= BLOCK_UNUSED
;
2246 depotIndex
= This
->prevFreeBlock
/ blocksPerDepot
;
2247 depotBlockOffset
= (This
->prevFreeBlock
% blocksPerDepot
) * sizeof(ULONG
);
2250 * Scan the entire big block depot until we find a block marked free
2252 while (nextBlockIndex
!= BLOCK_UNUSED
)
2254 if (depotIndex
< COUNT_BBDEPOTINHEADER
)
2256 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2259 * Grow the primary depot.
2261 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2263 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2266 * Add a block depot.
2268 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2269 This
->bigBlockDepotCount
++;
2270 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2273 * Flag it as a block depot.
2275 StorageImpl_SetNextBlockInChain(This
,
2279 /* Save new header information.
2281 StorageImpl_SaveFileHeader(This
);
2286 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotIndex
);
2288 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2291 * Grow the extended depot.
2293 ULONG extIndex
= BLOCK_UNUSED
;
2294 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2295 ULONG extBlockOffset
= numExtBlocks
% (blocksPerDepot
- 1);
2297 if (extBlockOffset
== 0)
2299 /* We need an extended block.
2301 extIndex
= Storage32Impl_AddExtBlockDepot(This
);
2302 This
->extBigBlockDepotCount
++;
2303 depotBlockIndexPos
= extIndex
+ 1;
2306 depotBlockIndexPos
= depotIndex
* blocksPerDepot
;
2309 * Add a block depot and mark it in the extended block.
2311 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2312 This
->bigBlockDepotCount
++;
2313 Storage32Impl_SetExtDepotBlock(This
, depotIndex
, depotBlockIndexPos
);
2315 /* Flag the block depot.
2317 StorageImpl_SetNextBlockInChain(This
,
2321 /* If necessary, flag the extended depot block.
2323 if (extIndex
!= BLOCK_UNUSED
)
2324 StorageImpl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2326 /* Save header information.
2328 StorageImpl_SaveFileHeader(This
);
2332 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2334 if (depotBuffer
!= 0)
2336 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2337 ( nextBlockIndex
!= BLOCK_UNUSED
))
2339 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2341 if (nextBlockIndex
== BLOCK_UNUSED
)
2343 freeBlock
= (depotIndex
* blocksPerDepot
) +
2344 (depotBlockOffset
/sizeof(ULONG
));
2347 depotBlockOffset
+= sizeof(ULONG
);
2350 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2354 depotBlockOffset
= 0;
2357 This
->prevFreeBlock
= freeBlock
;
2362 /******************************************************************************
2363 * Storage32Impl_AddBlockDepot
2365 * This will create a depot block, essentially it is a block initialized
2368 void Storage32Impl_AddBlockDepot(StorageImpl
* This
, ULONG blockIndex
)
2372 blockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2375 * Initialize blocks as free
2377 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2379 StorageImpl_ReleaseBigBlock(This
, blockBuffer
);
2382 /******************************************************************************
2383 * Storage32Impl_GetExtDepotBlock
2385 * Returns the index of the block that corresponds to the specified depot
2386 * index. This method is only for depot indexes equal or greater than
2387 * COUNT_BBDEPOTINHEADER.
2389 ULONG
Storage32Impl_GetExtDepotBlock(StorageImpl
* This
, ULONG depotIndex
)
2391 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2392 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2393 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2394 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2395 ULONG blockIndex
= BLOCK_UNUSED
;
2396 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2398 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2400 if (This
->extBigBlockDepotStart
== BLOCK_END_OF_CHAIN
)
2401 return BLOCK_UNUSED
;
2403 while (extBlockCount
> 0)
2405 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2409 if (extBlockIndex
!= BLOCK_UNUSED
)
2413 depotBuffer
= StorageImpl_GetROBigBlock(This
, extBlockIndex
);
2415 if (depotBuffer
!= 0)
2417 StorageUtl_ReadDWord(depotBuffer
,
2418 extBlockOffset
* sizeof(ULONG
),
2421 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2428 /******************************************************************************
2429 * Storage32Impl_SetExtDepotBlock
2431 * Associates the specified block index to the specified depot index.
2432 * This method is only for depot indexes equal or greater than
2433 * COUNT_BBDEPOTINHEADER.
2435 void Storage32Impl_SetExtDepotBlock(StorageImpl
* This
,
2439 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2440 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2441 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2442 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2443 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2445 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2447 while (extBlockCount
> 0)
2449 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2453 if (extBlockIndex
!= BLOCK_UNUSED
)
2457 depotBuffer
= StorageImpl_GetBigBlock(This
, extBlockIndex
);
2459 if (depotBuffer
!= 0)
2461 StorageUtl_WriteDWord(depotBuffer
,
2462 extBlockOffset
* sizeof(ULONG
),
2465 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2470 /******************************************************************************
2471 * Storage32Impl_AddExtBlockDepot
2473 * Creates an extended depot block.
2475 ULONG
Storage32Impl_AddExtBlockDepot(StorageImpl
* This
)
2477 ULONG numExtBlocks
= This
->extBigBlockDepotCount
;
2478 ULONG nextExtBlock
= This
->extBigBlockDepotStart
;
2479 BYTE
* depotBuffer
= NULL
;
2480 ULONG index
= BLOCK_UNUSED
;
2481 ULONG nextBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2482 ULONG blocksPerDepotBlock
= This
->bigBlockSize
/ sizeof(ULONG
);
2483 ULONG depotBlocksPerExtBlock
= blocksPerDepotBlock
- 1;
2485 index
= (COUNT_BBDEPOTINHEADER
+ (numExtBlocks
* depotBlocksPerExtBlock
)) *
2486 blocksPerDepotBlock
;
2488 if ((numExtBlocks
== 0) && (nextExtBlock
== BLOCK_END_OF_CHAIN
))
2491 * The first extended block.
2493 This
->extBigBlockDepotStart
= index
;
2499 * Follow the chain to the last one.
2501 for (i
= 0; i
< (numExtBlocks
- 1); i
++)
2503 nextExtBlock
= Storage32Impl_GetNextExtendedBlock(This
, nextExtBlock
);
2507 * Add the new extended block to the chain.
2509 depotBuffer
= StorageImpl_GetBigBlock(This
, nextExtBlock
);
2510 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2511 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2515 * Initialize this block.
2517 depotBuffer
= StorageImpl_GetBigBlock(This
, index
);
2518 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2519 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2524 /******************************************************************************
2525 * Storage32Impl_FreeBigBlock
2527 * This method will flag the specified block as free in the big block depot.
2529 void StorageImpl_FreeBigBlock(
2533 StorageImpl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2535 if (blockIndex
< This
->prevFreeBlock
)
2536 This
->prevFreeBlock
= blockIndex
;
2539 /************************************************************************
2540 * Storage32Impl_GetNextBlockInChain
2542 * This method will retrieve the block index of the next big block in
2545 * Params: This - Pointer to the Storage object.
2546 * blockIndex - Index of the block to retrieve the chain
2549 * Returns: This method returns the index of the next block in the chain.
2550 * It will return the constants:
2551 * BLOCK_SPECIAL - If the block given was not part of a
2553 * BLOCK_END_OF_CHAIN - If the block given was the last in
2555 * BLOCK_UNUSED - If the block given was not past of a chain
2557 * BLOCK_EXTBBDEPOT - This block is part of the extended
2560 * See Windows documentation for more details on IStorage methods.
2562 ULONG
StorageImpl_GetNextBlockInChain(
2566 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2567 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2568 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2569 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2571 ULONG depotBlockIndexPos
;
2573 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2576 * Cache the currently accessed depot block.
2578 if (depotBlockCount
!= This
->indexBlockDepotCached
)
2580 This
->indexBlockDepotCached
= depotBlockCount
;
2582 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2584 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2589 * We have to look in the extended depot.
2591 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2594 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2600 for (index
= 0; index
< NUM_BLOCKS_PER_DEPOT_BLOCK
; index
++)
2602 StorageUtl_ReadDWord(depotBuffer
, index
*sizeof(ULONG
), &nextBlockIndex
);
2603 This
->blockDepotCached
[index
] = nextBlockIndex
;
2606 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2610 nextBlockIndex
= This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)];
2612 return nextBlockIndex
;
2615 /******************************************************************************
2616 * Storage32Impl_GetNextExtendedBlock
2618 * Given an extended block this method will return the next extended block.
2621 * The last ULONG of an extended block is the block index of the next
2622 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2626 * - The index of the next extended block
2627 * - BLOCK_UNUSED: there is no next extended block.
2628 * - Any other return values denotes failure.
2630 ULONG
Storage32Impl_GetNextExtendedBlock(StorageImpl
* This
, ULONG blockIndex
)
2632 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2633 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2636 depotBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2640 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2642 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2645 return nextBlockIndex
;
2648 /******************************************************************************
2649 * Storage32Impl_SetNextBlockInChain
2651 * This method will write the index of the specified block's next block
2652 * in the big block depot.
2654 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2657 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2658 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2659 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2662 void StorageImpl_SetNextBlockInChain(
2667 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2668 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2669 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2670 ULONG depotBlockIndexPos
;
2673 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2674 assert(blockIndex
!= nextBlock
);
2676 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2678 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2683 * We have to look in the extended depot.
2685 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2688 depotBuffer
= StorageImpl_GetBigBlock(This
, depotBlockIndexPos
);
2692 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2693 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2697 * Update the cached block depot, if necessary.
2699 if (depotBlockCount
== This
->indexBlockDepotCached
)
2701 This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)] = nextBlock
;
2705 /******************************************************************************
2706 * Storage32Impl_LoadFileHeader
2708 * This method will read in the file header, i.e. big block index -1.
2710 HRESULT
StorageImpl_LoadFileHeader(
2713 HRESULT hr
= STG_E_FILENOTFOUND
;
2714 void* headerBigBlock
= NULL
;
2718 * Get a pointer to the big block of data containing the header.
2720 headerBigBlock
= StorageImpl_GetROBigBlock(This
, -1);
2723 * Extract the information from the header.
2725 if (headerBigBlock
!=0)
2728 * Check for the "magic number" signature and return an error if it is not
2731 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2733 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2734 return STG_E_OLDFORMAT
;
2737 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2739 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2740 return STG_E_INVALIDHEADER
;
2743 StorageUtl_ReadWord(
2745 OFFSET_BIGBLOCKSIZEBITS
,
2746 &This
->bigBlockSizeBits
);
2748 StorageUtl_ReadWord(
2750 OFFSET_SMALLBLOCKSIZEBITS
,
2751 &This
->smallBlockSizeBits
);
2753 StorageUtl_ReadDWord(
2755 OFFSET_BBDEPOTCOUNT
,
2756 &This
->bigBlockDepotCount
);
2758 StorageUtl_ReadDWord(
2760 OFFSET_ROOTSTARTBLOCK
,
2761 &This
->rootStartBlock
);
2763 StorageUtl_ReadDWord(
2765 OFFSET_SBDEPOTSTART
,
2766 &This
->smallBlockDepotStart
);
2768 StorageUtl_ReadDWord(
2770 OFFSET_EXTBBDEPOTSTART
,
2771 &This
->extBigBlockDepotStart
);
2773 StorageUtl_ReadDWord(
2775 OFFSET_EXTBBDEPOTCOUNT
,
2776 &This
->extBigBlockDepotCount
);
2778 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2780 StorageUtl_ReadDWord(
2782 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2783 &(This
->bigBlockDepotStart
[index
]));
2787 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2791 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2792 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2796 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2797 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2801 * Right now, the code is making some assumptions about the size of the
2802 * blocks, just make sure they are what we're expecting.
2804 assert( (This
->bigBlockSize
==DEF_BIG_BLOCK_SIZE
) &&
2805 (This
->smallBlockSize
==DEF_SMALL_BLOCK_SIZE
));
2808 * Release the block.
2810 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2818 /******************************************************************************
2819 * Storage32Impl_SaveFileHeader
2821 * This method will save to the file the header, i.e. big block -1.
2823 void StorageImpl_SaveFileHeader(
2826 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2831 * Get a pointer to the big block of data containing the header.
2833 success
= StorageImpl_ReadBigBlock(This
, -1, headerBigBlock
);
2836 * If the block read failed, the file is probably new.
2841 * Initialize for all unknown fields.
2843 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
2846 * Initialize the magic number.
2848 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
2851 * And a bunch of things we don't know what they mean
2853 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
2854 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
2855 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
2856 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
2857 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
2861 * Write the information to the header.
2863 if (headerBigBlock
!=0)
2865 StorageUtl_WriteWord(
2867 OFFSET_BIGBLOCKSIZEBITS
,
2868 This
->bigBlockSizeBits
);
2870 StorageUtl_WriteWord(
2872 OFFSET_SMALLBLOCKSIZEBITS
,
2873 This
->smallBlockSizeBits
);
2875 StorageUtl_WriteDWord(
2877 OFFSET_BBDEPOTCOUNT
,
2878 This
->bigBlockDepotCount
);
2880 StorageUtl_WriteDWord(
2882 OFFSET_ROOTSTARTBLOCK
,
2883 This
->rootStartBlock
);
2885 StorageUtl_WriteDWord(
2887 OFFSET_SBDEPOTSTART
,
2888 This
->smallBlockDepotStart
);
2890 StorageUtl_WriteDWord(
2892 OFFSET_EXTBBDEPOTSTART
,
2893 This
->extBigBlockDepotStart
);
2895 StorageUtl_WriteDWord(
2897 OFFSET_EXTBBDEPOTCOUNT
,
2898 This
->extBigBlockDepotCount
);
2900 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2902 StorageUtl_WriteDWord(
2904 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2905 (This
->bigBlockDepotStart
[index
]));
2910 * Write the big block back to the file.
2912 StorageImpl_WriteBigBlock(This
, -1, headerBigBlock
);
2915 /******************************************************************************
2916 * Storage32Impl_ReadProperty
2918 * This method will read the specified property from the property chain.
2920 BOOL
StorageImpl_ReadProperty(
2923 StgProperty
* buffer
)
2925 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2926 ULARGE_INTEGER offsetInPropSet
;
2930 offsetInPropSet
.HighPart
= 0;
2931 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
2933 readSucessful
= BlockChainStream_ReadAt(
2934 This
->rootBlockChain
,
2942 memset(buffer
->name
, 0, sizeof(buffer
->name
));
2945 currentProperty
+OFFSET_PS_NAME
,
2946 PROPERTY_NAME_BUFFER_LEN
);
2948 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
2950 StorageUtl_ReadWord(
2952 OFFSET_PS_NAMELENGTH
,
2953 &buffer
->sizeOfNameString
);
2955 StorageUtl_ReadDWord(
2957 OFFSET_PS_PREVIOUSPROP
,
2958 &buffer
->previousProperty
);
2960 StorageUtl_ReadDWord(
2963 &buffer
->nextProperty
);
2965 StorageUtl_ReadDWord(
2968 &buffer
->dirProperty
);
2970 StorageUtl_ReadGUID(
2973 &buffer
->propertyUniqueID
);
2975 StorageUtl_ReadDWord(
2978 &buffer
->timeStampS1
);
2980 StorageUtl_ReadDWord(
2983 &buffer
->timeStampD1
);
2985 StorageUtl_ReadDWord(
2988 &buffer
->timeStampS2
);
2990 StorageUtl_ReadDWord(
2993 &buffer
->timeStampD2
);
2995 StorageUtl_ReadDWord(
2997 OFFSET_PS_STARTBLOCK
,
2998 &buffer
->startingBlock
);
3000 StorageUtl_ReadDWord(
3003 &buffer
->size
.LowPart
);
3005 buffer
->size
.HighPart
= 0;
3008 return readSucessful
;
3011 /*********************************************************************
3012 * Write the specified property into the property chain
3014 BOOL
StorageImpl_WriteProperty(
3017 StgProperty
* buffer
)
3019 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3020 ULARGE_INTEGER offsetInPropSet
;
3021 BOOL writeSucessful
;
3024 offsetInPropSet
.HighPart
= 0;
3025 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3027 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
3030 currentProperty
+ OFFSET_PS_NAME
,
3032 PROPERTY_NAME_BUFFER_LEN
);
3034 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
3037 * Reassign the size in case of mistake....
3039 buffer
->sizeOfNameString
= (lstrlenW(buffer
->name
)+1) * sizeof(WCHAR
);
3041 StorageUtl_WriteWord(
3043 OFFSET_PS_NAMELENGTH
,
3044 buffer
->sizeOfNameString
);
3046 StorageUtl_WriteDWord(
3048 OFFSET_PS_PREVIOUSPROP
,
3049 buffer
->previousProperty
);
3051 StorageUtl_WriteDWord(
3054 buffer
->nextProperty
);
3056 StorageUtl_WriteDWord(
3059 buffer
->dirProperty
);
3061 StorageUtl_WriteGUID(
3064 &buffer
->propertyUniqueID
);
3066 StorageUtl_WriteDWord(
3069 buffer
->timeStampS1
);
3071 StorageUtl_WriteDWord(
3074 buffer
->timeStampD1
);
3076 StorageUtl_WriteDWord(
3079 buffer
->timeStampS2
);
3081 StorageUtl_WriteDWord(
3084 buffer
->timeStampD2
);
3086 StorageUtl_WriteDWord(
3088 OFFSET_PS_STARTBLOCK
,
3089 buffer
->startingBlock
);
3091 StorageUtl_WriteDWord(
3094 buffer
->size
.LowPart
);
3096 writeSucessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
3101 return writeSucessful
;
3104 BOOL
StorageImpl_ReadBigBlock(
3109 void* bigBlockBuffer
;
3111 bigBlockBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
3113 if (bigBlockBuffer
!=0)
3115 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
3117 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3125 BOOL
StorageImpl_WriteBigBlock(
3130 void* bigBlockBuffer
;
3132 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
3134 if (bigBlockBuffer
!=0)
3136 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
3138 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3146 void* StorageImpl_GetROBigBlock(
3150 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
3153 void* StorageImpl_GetBigBlock(
3157 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
3160 void StorageImpl_ReleaseBigBlock(
3164 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
3167 /******************************************************************************
3168 * Storage32Impl_SmallBlocksToBigBlocks
3170 * This method will convert a small block chain to a big block chain.
3171 * The small block chain will be destroyed.
3173 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
3175 SmallBlockChainStream
** ppsbChain
)
3177 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
3178 ULARGE_INTEGER size
, offset
;
3179 ULONG cbRead
, cbWritten
, cbTotalRead
, cbTotalWritten
;
3180 ULONG propertyIndex
;
3181 BOOL successRead
, successWrite
;
3182 StgProperty chainProperty
;
3183 BYTE buffer
[DEF_SMALL_BLOCK_SIZE
];
3184 BlockChainStream
*bbTempChain
= NULL
;
3185 BlockChainStream
*bigBlockChain
= NULL
;
3188 * Create a temporary big block chain that doesn't have
3189 * an associated property. This temporary chain will be
3190 * used to copy data from small blocks to big blocks.
3192 bbTempChain
= BlockChainStream_Construct(This
,
3197 * Grow the big block chain.
3199 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
3200 BlockChainStream_SetSize(bbTempChain
, size
);
3203 * Copy the contents of the small block chain to the big block chain
3204 * by small block size increments.
3207 offset
.HighPart
= 0;
3213 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
3218 cbTotalRead
+= cbRead
;
3220 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
3225 cbTotalWritten
+= cbWritten
;
3227 offset
.LowPart
+= This
->smallBlockSize
;
3229 } while (successRead
&& successWrite
);
3231 assert(cbTotalRead
== cbTotalWritten
);
3234 * Destroy the small block chain.
3236 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
3239 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
3240 SmallBlockChainStream_Destroy(*ppsbChain
);
3244 * Change the property information. This chain is now a big block chain
3245 * and it doesn't reside in the small blocks chain anymore.
3247 StorageImpl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3249 chainProperty
.startingBlock
= bbHeadOfChain
;
3251 StorageImpl_WriteProperty(This
, propertyIndex
, &chainProperty
);
3254 * Destroy the temporary propertyless big block chain.
3255 * Create a new big block chain associated with this property.
3257 BlockChainStream_Destroy(bbTempChain
);
3258 bigBlockChain
= BlockChainStream_Construct(This
,
3262 return bigBlockChain
;
3265 /******************************************************************************
3266 ** Storage32InternalImpl implementation
3269 StorageInternalImpl
* StorageInternalImpl_Construct(
3270 StorageImpl
* ancestorStorage
,
3271 ULONG rootPropertyIndex
)
3273 StorageInternalImpl
* newStorage
;
3276 * Allocate space for the new storage object
3278 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl
));
3282 memset(newStorage
, 0, sizeof(StorageInternalImpl
));
3285 * Initialize the virtual function table.
3287 newStorage
->lpvtbl
= &Storage32InternalImpl_Vtbl
;
3288 newStorage
->v_destructor
= &StorageInternalImpl_Destroy
;
3291 * Keep the ancestor storage pointer and nail a reference to it.
3293 newStorage
->ancestorStorage
= ancestorStorage
;
3294 StorageBaseImpl_AddRef((IStorage
*)(newStorage
->ancestorStorage
));
3297 * Keep the index of the root property set for this storage,
3299 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3307 void StorageInternalImpl_Destroy(
3308 StorageInternalImpl
* This
)
3310 StorageBaseImpl_Release((IStorage
*)This
->ancestorStorage
);
3311 HeapFree(GetProcessHeap(), 0, This
);
3314 /******************************************************************************
3316 ** Storage32InternalImpl_Commit
3318 ** The non-root storages cannot be opened in transacted mode thus this function
3321 HRESULT WINAPI
StorageInternalImpl_Commit(
3323 DWORD grfCommitFlags
) /* [in] */
3328 /******************************************************************************
3330 ** Storage32InternalImpl_Revert
3332 ** The non-root storages cannot be opened in transacted mode thus this function
3335 HRESULT WINAPI
StorageInternalImpl_Revert(
3341 /******************************************************************************
3342 ** IEnumSTATSTGImpl implementation
3345 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3346 StorageImpl
* parentStorage
,
3347 ULONG firstPropertyNode
)
3349 IEnumSTATSTGImpl
* newEnumeration
;
3351 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3353 if (newEnumeration
!=0)
3356 * Set-up the virtual function table and reference count.
3358 newEnumeration
->lpvtbl
= &IEnumSTATSTGImpl_Vtbl
;
3359 newEnumeration
->ref
= 0;
3362 * We want to nail-down the reference to the storage in case the
3363 * enumeration out-lives the storage in the client application.
3365 newEnumeration
->parentStorage
= parentStorage
;
3366 IStorage_AddRef((IStorage
*)newEnumeration
->parentStorage
);
3368 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3371 * Initialize the search stack
3373 newEnumeration
->stackSize
= 0;
3374 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3375 newEnumeration
->stackToVisit
=
3376 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3379 * Make sure the current node of the iterator is the first one.
3381 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3384 return newEnumeration
;
3387 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3389 IStorage_Release((IStorage
*)This
->parentStorage
);
3390 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3391 HeapFree(GetProcessHeap(), 0, This
);
3394 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3395 IEnumSTATSTG
* iface
,
3399 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3402 * Perform a sanity check on the parameters.
3405 return E_INVALIDARG
;
3408 * Initialize the return parameter.
3413 * Compare the riid with the interface IDs implemented by this object.
3415 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3417 *ppvObject
= (IEnumSTATSTG
*)This
;
3419 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3421 *ppvObject
= (IEnumSTATSTG
*)This
;
3425 * Check that we obtained an interface.
3427 if ((*ppvObject
)==0)
3428 return E_NOINTERFACE
;
3431 * Query Interface always increases the reference count by one when it is
3434 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3439 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3440 IEnumSTATSTG
* iface
)
3442 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3448 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3449 IEnumSTATSTG
* iface
)
3451 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3459 * If the reference count goes down to 0, perform suicide.
3463 IEnumSTATSTGImpl_Destroy(This
);
3469 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3470 IEnumSTATSTG
* iface
,
3473 ULONG
* pceltFetched
)
3475 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3477 StgProperty currentProperty
;
3478 STATSTG
* currentReturnStruct
= rgelt
;
3479 ULONG objectFetched
= 0;
3480 ULONG currentSearchNode
;
3483 * Perform a sanity check on the parameters.
3485 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3486 return E_INVALIDARG
;
3489 * To avoid the special case, get another pointer to a ULONG value if
3490 * the caller didn't supply one.
3492 if (pceltFetched
==0)
3493 pceltFetched
= &objectFetched
;
3496 * Start the iteration, we will iterate until we hit the end of the
3497 * linked list or until we hit the number of items to iterate through
3502 * Start with the node at the top of the stack.
3504 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3506 while ( ( *pceltFetched
< celt
) &&
3507 ( currentSearchNode
!=PROPERTY_NULL
) )
3510 * Remove the top node from the stack
3512 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3515 * Read the property from the storage.
3517 StorageImpl_ReadProperty(This
->parentStorage
,
3522 * Copy the information to the return buffer.
3524 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3529 * Step to the next item in the iteration
3532 currentReturnStruct
++;
3535 * Push the next search node in the search stack.
3537 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3540 * continue the iteration.
3542 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3545 if (*pceltFetched
== celt
)
3552 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3553 IEnumSTATSTG
* iface
,
3556 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3558 StgProperty currentProperty
;
3559 ULONG objectFetched
= 0;
3560 ULONG currentSearchNode
;
3563 * Start with the node at the top of the stack.
3565 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3567 while ( (objectFetched
< celt
) &&
3568 (currentSearchNode
!=PROPERTY_NULL
) )
3571 * Remove the top node from the stack
3573 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3576 * Read the property from the storage.
3578 StorageImpl_ReadProperty(This
->parentStorage
,
3583 * Step to the next item in the iteration
3588 * Push the next search node in the search stack.
3590 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3593 * continue the iteration.
3595 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3598 if (objectFetched
== celt
)
3604 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3605 IEnumSTATSTG
* iface
)
3607 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3609 StgProperty rootProperty
;
3613 * Re-initialize the search stack to an empty stack
3615 This
->stackSize
= 0;
3618 * Read the root property from the storage.
3620 readSucessful
= StorageImpl_ReadProperty(
3621 This
->parentStorage
,
3622 This
->firstPropertyNode
,
3627 assert(rootProperty
.sizeOfNameString
!=0);
3630 * Push the search node in the search stack.
3632 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3638 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3639 IEnumSTATSTG
* iface
,
3640 IEnumSTATSTG
** ppenum
)
3642 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3644 IEnumSTATSTGImpl
* newClone
;
3647 * Perform a sanity check on the parameters.
3650 return E_INVALIDARG
;
3652 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3653 This
->firstPropertyNode
);
3657 * The new clone enumeration must point to the same current node as
3660 newClone
->stackSize
= This
->stackSize
;
3661 newClone
->stackMaxSize
= This
->stackMaxSize
;
3662 newClone
->stackToVisit
=
3663 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3666 newClone
->stackToVisit
,
3668 sizeof(ULONG
) * newClone
->stackSize
);
3670 *ppenum
= (IEnumSTATSTG
*)newClone
;
3673 * Don't forget to nail down a reference to the clone before
3676 IEnumSTATSTGImpl_AddRef(*ppenum
);
3681 INT
IEnumSTATSTGImpl_FindParentProperty(
3682 IEnumSTATSTGImpl
*This
,
3683 ULONG childProperty
,
3684 StgProperty
*currentProperty
,
3687 ULONG currentSearchNode
;
3691 * To avoid the special case, get another pointer to a ULONG value if
3692 * the caller didn't supply one.
3695 thisNodeId
= &foundNode
;
3698 * Start with the node at the top of the stack.
3700 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3703 while (currentSearchNode
!=PROPERTY_NULL
)
3706 * Store the current node in the returned parameters
3708 *thisNodeId
= currentSearchNode
;
3711 * Remove the top node from the stack
3713 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3716 * Read the property from the storage.
3718 StorageImpl_ReadProperty(
3719 This
->parentStorage
,
3723 if (currentProperty
->previousProperty
== childProperty
)
3724 return PROPERTY_RELATION_PREVIOUS
;
3726 else if (currentProperty
->nextProperty
== childProperty
)
3727 return PROPERTY_RELATION_NEXT
;
3729 else if (currentProperty
->dirProperty
== childProperty
)
3730 return PROPERTY_RELATION_DIR
;
3733 * Push the next search node in the search stack.
3735 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3738 * continue the iteration.
3740 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3743 return PROPERTY_NULL
;
3746 ULONG
IEnumSTATSTGImpl_FindProperty(
3747 IEnumSTATSTGImpl
* This
,
3748 const OLECHAR
* lpszPropName
,
3749 StgProperty
* currentProperty
)
3751 ULONG currentSearchNode
;
3754 * Start with the node at the top of the stack.
3756 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3758 while (currentSearchNode
!=PROPERTY_NULL
)
3761 * Remove the top node from the stack
3763 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3766 * Read the property from the storage.
3768 StorageImpl_ReadProperty(This
->parentStorage
,
3772 if ( propertyNameCmp(
3773 (OLECHAR
*)currentProperty
->name
,
3774 (OLECHAR
*)lpszPropName
) == 0)
3775 return currentSearchNode
;
3778 * Push the next search node in the search stack.
3780 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3783 * continue the iteration.
3785 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3788 return PROPERTY_NULL
;
3791 void IEnumSTATSTGImpl_PushSearchNode(
3792 IEnumSTATSTGImpl
* This
,
3795 StgProperty rootProperty
;
3799 * First, make sure we're not trying to push an unexisting node.
3801 if (nodeToPush
==PROPERTY_NULL
)
3805 * First push the node to the stack
3807 if (This
->stackSize
== This
->stackMaxSize
)
3809 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3811 This
->stackToVisit
= HeapReAlloc(
3815 sizeof(ULONG
) * This
->stackMaxSize
);
3818 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3822 * Read the root property from the storage.
3824 readSucessful
= StorageImpl_ReadProperty(
3825 This
->parentStorage
,
3831 assert(rootProperty
.sizeOfNameString
!=0);
3834 * Push the previous search node in the search stack.
3836 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3840 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3841 IEnumSTATSTGImpl
* This
,
3846 if (This
->stackSize
== 0)
3847 return PROPERTY_NULL
;
3849 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3857 /******************************************************************************
3858 ** StorageUtl implementation
3861 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3863 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3866 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3868 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3871 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3873 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3876 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3878 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3881 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3883 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3884 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3885 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3887 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
3890 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
3892 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
3893 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
3894 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
3896 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
3899 void StorageUtl_CopyPropertyToSTATSTG(
3900 STATSTG
* destination
,
3901 StgProperty
* source
,
3905 * The copy of the string occurs only when the flag is not set
3907 if ((statFlags
& STATFLAG_NONAME
) != 0)
3909 destination
->pwcsName
= 0;
3913 destination
->pwcsName
=
3914 CoTaskMemAlloc((lstrlenW(source
->name
)+1)*sizeof(WCHAR
));
3916 lstrcpyW((LPWSTR
)destination
->pwcsName
, source
->name
);
3919 switch (source
->propertyType
)
3921 case PROPTYPE_STORAGE
:
3923 destination
->type
= STGTY_STORAGE
;
3925 case PROPTYPE_STREAM
:
3926 destination
->type
= STGTY_STREAM
;
3929 destination
->type
= STGTY_STREAM
;
3933 destination
->cbSize
= source
->size
;
3935 currentReturnStruct->mtime = {0}; TODO
3936 currentReturnStruct->ctime = {0};
3937 currentReturnStruct->atime = {0};
3939 destination
->grfMode
= 0;
3940 destination
->grfLocksSupported
= 0;
3941 destination
->clsid
= source
->propertyUniqueID
;
3942 destination
->grfStateBits
= 0;
3943 destination
->reserved
= 0;
3946 /******************************************************************************
3947 ** BlockChainStream implementation
3950 BlockChainStream
* BlockChainStream_Construct(
3951 StorageImpl
* parentStorage
,
3952 ULONG
* headOfStreamPlaceHolder
,
3953 ULONG propertyIndex
)
3955 BlockChainStream
* newStream
;
3958 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
3960 newStream
->parentStorage
= parentStorage
;
3961 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
3962 newStream
->ownerPropertyIndex
= propertyIndex
;
3963 newStream
->lastBlockNoInSequence
= 0xFFFFFFFF;
3964 newStream
->tailIndex
= BLOCK_END_OF_CHAIN
;
3965 newStream
->numBlocks
= 0;
3967 blockIndex
= BlockChainStream_GetHeadOfChain(newStream
);
3969 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
3971 newStream
->numBlocks
++;
3972 newStream
->tailIndex
= blockIndex
;
3974 blockIndex
= StorageImpl_GetNextBlockInChain(
3982 void BlockChainStream_Destroy(BlockChainStream
* This
)
3984 HeapFree(GetProcessHeap(), 0, This
);
3987 /******************************************************************************
3988 * BlockChainStream_GetHeadOfChain
3990 * Returns the head of this stream chain.
3991 * Some special chains don't have properties, their heads are kept in
3992 * This->headOfStreamPlaceHolder.
3995 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
3997 StgProperty chainProperty
;
4000 if (This
->headOfStreamPlaceHolder
!= 0)
4001 return *(This
->headOfStreamPlaceHolder
);
4003 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
4005 readSucessful
= StorageImpl_ReadProperty(
4006 This
->parentStorage
,
4007 This
->ownerPropertyIndex
,
4012 return chainProperty
.startingBlock
;
4016 return BLOCK_END_OF_CHAIN
;
4019 /******************************************************************************
4020 * BlockChainStream_GetCount
4022 * Returns the number of blocks that comprises this chain.
4023 * This is not the size of the stream as the last block may not be full!
4026 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
4031 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4033 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4037 blockIndex
= StorageImpl_GetNextBlockInChain(
4038 This
->parentStorage
,
4045 /******************************************************************************
4046 * BlockChainStream_ReadAt
4048 * Reads a specified number of bytes from this chain at the specified offset.
4049 * bytesRead may be NULL.
4050 * Failure will be returned if the specified number of bytes has not been read.
4052 BOOL
BlockChainStream_ReadAt(BlockChainStream
* This
,
4053 ULARGE_INTEGER offset
,
4058 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4059 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
4060 ULONG bytesToReadInBuffer
;
4063 BYTE
* bigBlockBuffer
;
4066 * Find the first block in the stream that contains part of the buffer.
4068 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4069 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4070 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4072 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4073 This
->lastBlockNoInSequence
= blockNoInSequence
;
4077 ULONG temp
= blockNoInSequence
;
4079 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4080 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4081 This
->lastBlockNoInSequence
= temp
;
4084 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4087 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4089 blockNoInSequence
--;
4092 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4095 * Start reading the buffer.
4098 bufferWalker
= buffer
;
4100 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4103 * Calculate how many bytes we can copy from this big block.
4105 bytesToReadInBuffer
=
4106 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4109 * Copy those bytes to the buffer
4112 StorageImpl_GetROBigBlock(This
->parentStorage
, blockIndex
);
4114 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
4116 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4119 * Step to the next big block.
4122 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4124 bufferWalker
+= bytesToReadInBuffer
;
4125 size
-= bytesToReadInBuffer
;
4126 *bytesRead
+= bytesToReadInBuffer
;
4127 offsetInBlock
= 0; /* There is no offset on the next block */
4134 /******************************************************************************
4135 * BlockChainStream_WriteAt
4137 * Writes the specified number of bytes to this chain at the specified offset.
4138 * bytesWritten may be NULL.
4139 * Will fail if not all specified number of bytes have been written.
4141 BOOL
BlockChainStream_WriteAt(BlockChainStream
* This
,
4142 ULARGE_INTEGER offset
,
4145 ULONG
* bytesWritten
)
4147 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4148 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
4152 BYTE
* bigBlockBuffer
;
4155 * Find the first block in the stream that contains part of the buffer.
4157 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4158 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4159 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4161 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4162 This
->lastBlockNoInSequence
= blockNoInSequence
;
4166 ULONG temp
= blockNoInSequence
;
4168 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4169 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4170 This
->lastBlockNoInSequence
= temp
;
4173 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4176 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4178 blockNoInSequence
--;
4181 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4184 * Here, I'm casting away the constness on the buffer variable
4185 * This is OK since we don't intend to modify that buffer.
4188 bufferWalker
= (BYTE
*)buffer
;
4190 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4193 * Calculate how many bytes we can copy from this big block.
4196 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4199 * Copy those bytes to the buffer
4201 bigBlockBuffer
= StorageImpl_GetBigBlock(This
->parentStorage
, blockIndex
);
4203 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
4205 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4208 * Step to the next big block.
4211 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4213 bufferWalker
+= bytesToWrite
;
4214 size
-= bytesToWrite
;
4215 *bytesWritten
+= bytesToWrite
;
4216 offsetInBlock
= 0; /* There is no offset on the next block */
4222 /******************************************************************************
4223 * BlockChainStream_Shrink
4225 * Shrinks this chain in the big block depot.
4227 BOOL
BlockChainStream_Shrink(BlockChainStream
* This
,
4228 ULARGE_INTEGER newSize
)
4230 ULONG blockIndex
, extraBlock
;
4235 * Reset the last accessed block cache.
4237 This
->lastBlockNoInSequence
= 0xFFFFFFFF;
4238 This
->lastBlockNoInSequenceIndex
= BLOCK_END_OF_CHAIN
;
4241 * Figure out how many blocks are needed to contain the new size
4243 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4245 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4248 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4251 * Go to the new end of chain
4253 while (count
< numBlocks
)
4256 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4261 /* Get the next block before marking the new end */
4263 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4265 /* Mark the new end of chain */
4266 StorageImpl_SetNextBlockInChain(
4267 This
->parentStorage
,
4269 BLOCK_END_OF_CHAIN
);
4271 This
->tailIndex
= blockIndex
;
4272 This
->numBlocks
= numBlocks
;
4275 * Mark the extra blocks as free
4277 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4280 StorageImpl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4282 StorageImpl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4283 extraBlock
= blockIndex
;
4289 /******************************************************************************
4290 * BlockChainStream_Enlarge
4292 * Grows this chain in the big block depot.
4294 BOOL
BlockChainStream_Enlarge(BlockChainStream
* This
,
4295 ULARGE_INTEGER newSize
)
4297 ULONG blockIndex
, currentBlock
;
4299 ULONG oldNumBlocks
= 0;
4301 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4304 * Empty chain. Create the head.
4306 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4308 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4309 StorageImpl_SetNextBlockInChain(This
->parentStorage
,
4311 BLOCK_END_OF_CHAIN
);
4313 if (This
->headOfStreamPlaceHolder
!= 0)
4315 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4319 StgProperty chainProp
;
4320 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4322 StorageImpl_ReadProperty(
4323 This
->parentStorage
,
4324 This
->ownerPropertyIndex
,
4327 chainProp
.startingBlock
= blockIndex
;
4329 StorageImpl_WriteProperty(
4330 This
->parentStorage
,
4331 This
->ownerPropertyIndex
,
4335 This
->tailIndex
= blockIndex
;
4336 This
->numBlocks
= 1;
4340 * Figure out how many blocks are needed to contain this stream
4342 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4344 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4348 * Go to the current end of chain
4350 if (This
->tailIndex
== BLOCK_END_OF_CHAIN
)
4352 currentBlock
= blockIndex
;
4354 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4357 currentBlock
= blockIndex
;
4360 StorageImpl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4363 This
->tailIndex
= currentBlock
;
4366 currentBlock
= This
->tailIndex
;
4367 oldNumBlocks
= This
->numBlocks
;
4370 * Add new blocks to the chain
4372 if (oldNumBlocks
< newNumBlocks
)
4374 while (oldNumBlocks
< newNumBlocks
)
4376 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4378 StorageImpl_SetNextBlockInChain(
4379 This
->parentStorage
,
4383 StorageImpl_SetNextBlockInChain(
4384 This
->parentStorage
,
4386 BLOCK_END_OF_CHAIN
);
4388 currentBlock
= blockIndex
;
4392 This
->tailIndex
= blockIndex
;
4393 This
->numBlocks
= newNumBlocks
;
4399 /******************************************************************************
4400 * BlockChainStream_SetSize
4402 * Sets the size of this stream. The big block depot will be updated.
4403 * The file will grow if we grow the chain.
4405 * TODO: Free the actual blocks in the file when we shrink the chain.
4406 * Currently, the blocks are still in the file. So the file size
4407 * doesn't shrink even if we shrink streams.
4409 BOOL
BlockChainStream_SetSize(
4410 BlockChainStream
* This
,
4411 ULARGE_INTEGER newSize
)
4413 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4415 if (newSize
.LowPart
== size
.LowPart
)
4418 if (newSize
.LowPart
< size
.LowPart
)
4420 BlockChainStream_Shrink(This
, newSize
);
4424 ULARGE_INTEGER fileSize
=
4425 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4427 ULONG diff
= newSize
.LowPart
- size
.LowPart
;
4430 * Make sure the file stays a multiple of blocksize
4432 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4433 diff
+= (This
->parentStorage
->bigBlockSize
-
4434 (diff
% This
->parentStorage
->bigBlockSize
) );
4436 fileSize
.LowPart
+= diff
;
4437 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4439 BlockChainStream_Enlarge(This
, newSize
);
4445 /******************************************************************************
4446 * BlockChainStream_GetSize
4448 * Returns the size of this chain.
4449 * Will return the block count if this chain doesn't have a property.
4451 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4453 StgProperty chainProperty
;
4455 if(This
->headOfStreamPlaceHolder
== NULL
)
4458 * This chain is a data stream read the property and return
4459 * the appropriate size
4461 StorageImpl_ReadProperty(
4462 This
->parentStorage
,
4463 This
->ownerPropertyIndex
,
4466 return chainProperty
.size
;
4471 * this chain is a chain that does not have a property, figure out the
4472 * size by making the product number of used blocks times the
4475 ULARGE_INTEGER result
;
4476 result
.HighPart
= 0;
4479 BlockChainStream_GetCount(This
) *
4480 This
->parentStorage
->bigBlockSize
;
4486 /******************************************************************************
4487 ** SmallBlockChainStream implementation
4490 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4491 StorageImpl
* parentStorage
,
4492 ULONG propertyIndex
)
4494 SmallBlockChainStream
* newStream
;
4496 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4498 newStream
->parentStorage
= parentStorage
;
4499 newStream
->ownerPropertyIndex
= propertyIndex
;
4504 void SmallBlockChainStream_Destroy(
4505 SmallBlockChainStream
* This
)
4507 HeapFree(GetProcessHeap(), 0, This
);
4510 /******************************************************************************
4511 * SmallBlockChainStream_GetHeadOfChain
4513 * Returns the head of this chain of small blocks.
4515 ULONG
SmallBlockChainStream_GetHeadOfChain(
4516 SmallBlockChainStream
* This
)
4518 StgProperty chainProperty
;
4521 if (This
->ownerPropertyIndex
)
4523 readSucessful
= StorageImpl_ReadProperty(
4524 This
->parentStorage
,
4525 This
->ownerPropertyIndex
,
4530 return chainProperty
.startingBlock
;
4535 return BLOCK_END_OF_CHAIN
;
4538 /******************************************************************************
4539 * SmallBlockChainStream_GetNextBlockInChain
4541 * Returns the index of the next small block in this chain.
4544 * - BLOCK_END_OF_CHAIN: end of this chain
4545 * - BLOCK_UNUSED: small block 'blockIndex' is free
4547 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4548 SmallBlockChainStream
* This
,
4551 ULARGE_INTEGER offsetOfBlockInDepot
;
4553 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4557 offsetOfBlockInDepot
.HighPart
= 0;
4558 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4561 * Read those bytes in the buffer from the small block file.
4563 success
= BlockChainStream_ReadAt(
4564 This
->parentStorage
->smallBlockDepotChain
,
4565 offsetOfBlockInDepot
,
4572 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4575 return nextBlockInChain
;
4578 /******************************************************************************
4579 * SmallBlockChainStream_SetNextBlockInChain
4581 * Writes the index of the next block of the specified block in the small
4583 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4584 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4586 void SmallBlockChainStream_SetNextBlockInChain(
4587 SmallBlockChainStream
* This
,
4591 ULARGE_INTEGER offsetOfBlockInDepot
;
4595 offsetOfBlockInDepot
.HighPart
= 0;
4596 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4598 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4601 * Read those bytes in the buffer from the small block file.
4603 BlockChainStream_WriteAt(
4604 This
->parentStorage
->smallBlockDepotChain
,
4605 offsetOfBlockInDepot
,
4611 /******************************************************************************
4612 * SmallBlockChainStream_FreeBlock
4614 * Flag small block 'blockIndex' as free in the small block depot.
4616 void SmallBlockChainStream_FreeBlock(
4617 SmallBlockChainStream
* This
,
4620 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4623 /******************************************************************************
4624 * SmallBlockChainStream_GetNextFreeBlock
4626 * Returns the index of a free small block. The small block depot will be
4627 * enlarged if necessary. The small block chain will also be enlarged if
4630 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4631 SmallBlockChainStream
* This
)
4633 ULARGE_INTEGER offsetOfBlockInDepot
;
4636 ULONG blockIndex
= 0;
4637 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4638 BOOL success
= TRUE
;
4639 ULONG smallBlocksPerBigBlock
;
4641 offsetOfBlockInDepot
.HighPart
= 0;
4644 * Scan the small block depot for a free block
4646 while (nextBlockIndex
!= BLOCK_UNUSED
)
4648 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4650 success
= BlockChainStream_ReadAt(
4651 This
->parentStorage
->smallBlockDepotChain
,
4652 offsetOfBlockInDepot
,
4658 * If we run out of space for the small block depot, enlarge it
4662 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4664 if (nextBlockIndex
!= BLOCK_UNUSED
)
4670 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4672 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4673 ULONG nextBlock
, newsbdIndex
;
4674 BYTE
* smallBlockDepot
;
4676 nextBlock
= sbdIndex
;
4677 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4679 sbdIndex
= nextBlock
;
4681 StorageImpl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4684 newsbdIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4685 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4686 StorageImpl_SetNextBlockInChain(
4687 This
->parentStorage
,
4691 StorageImpl_SetNextBlockInChain(
4692 This
->parentStorage
,
4694 BLOCK_END_OF_CHAIN
);
4697 * Initialize all the small blocks to free
4700 StorageImpl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4702 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4703 StorageImpl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4708 * We have just created the small block depot.
4710 StgProperty rootProp
;
4714 * Save it in the header
4716 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4717 StorageImpl_SaveFileHeader(This
->parentStorage
);
4720 * And allocate the first big block that will contain small blocks
4723 StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4725 StorageImpl_SetNextBlockInChain(
4726 This
->parentStorage
,
4728 BLOCK_END_OF_CHAIN
);
4730 StorageImpl_ReadProperty(
4731 This
->parentStorage
,
4732 This
->parentStorage
->rootPropertySetIndex
,
4735 rootProp
.startingBlock
= sbStartIndex
;
4736 rootProp
.size
.HighPart
= 0;
4737 rootProp
.size
.LowPart
= This
->parentStorage
->bigBlockSize
;
4739 StorageImpl_WriteProperty(
4740 This
->parentStorage
,
4741 This
->parentStorage
->rootPropertySetIndex
,
4747 smallBlocksPerBigBlock
=
4748 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4751 * Verify if we have to allocate big blocks to contain small blocks
4753 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4755 StgProperty rootProp
;
4756 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4758 StorageImpl_ReadProperty(
4759 This
->parentStorage
,
4760 This
->parentStorage
->rootPropertySetIndex
,
4763 if (rootProp
.size
.LowPart
<
4764 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4766 rootProp
.size
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4768 BlockChainStream_SetSize(
4769 This
->parentStorage
->smallBlockRootChain
,
4772 StorageImpl_WriteProperty(
4773 This
->parentStorage
,
4774 This
->parentStorage
->rootPropertySetIndex
,
4782 /******************************************************************************
4783 * SmallBlockChainStream_ReadAt
4785 * Reads a specified number of bytes from this chain at the specified offset.
4786 * bytesRead may be NULL.
4787 * Failure will be returned if the specified number of bytes has not been read.
4789 BOOL
SmallBlockChainStream_ReadAt(
4790 SmallBlockChainStream
* This
,
4791 ULARGE_INTEGER offset
,
4796 ULARGE_INTEGER offsetInBigBlockFile
;
4797 ULONG blockNoInSequence
=
4798 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4800 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4801 ULONG bytesToReadInBuffer
;
4803 ULONG bytesReadFromBigBlockFile
;
4807 * This should never happen on a small block file.
4809 assert(offset
.HighPart
==0);
4812 * Find the first block in the stream that contains part of the buffer.
4814 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4816 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4818 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4820 blockNoInSequence
--;
4824 * Start reading the buffer.
4827 bufferWalker
= buffer
;
4829 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4832 * Calculate how many bytes we can copy from this small block.
4834 bytesToReadInBuffer
=
4835 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4838 * Calculate the offset of the small block in the small block file.
4840 offsetInBigBlockFile
.HighPart
= 0;
4841 offsetInBigBlockFile
.LowPart
=
4842 blockIndex
* This
->parentStorage
->smallBlockSize
;
4844 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4847 * Read those bytes in the buffer from the small block file.
4849 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4850 offsetInBigBlockFile
,
4851 bytesToReadInBuffer
,
4853 &bytesReadFromBigBlockFile
);
4855 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4858 * Step to the next big block.
4860 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4861 bufferWalker
+= bytesToReadInBuffer
;
4862 size
-= bytesToReadInBuffer
;
4863 *bytesRead
+= bytesToReadInBuffer
;
4864 offsetInBlock
= 0; /* There is no offset on the next block */
4870 /******************************************************************************
4871 * SmallBlockChainStream_WriteAt
4873 * Writes the specified number of bytes to this chain at the specified offset.
4874 * bytesWritten may be NULL.
4875 * Will fail if not all specified number of bytes have been written.
4877 BOOL
SmallBlockChainStream_WriteAt(
4878 SmallBlockChainStream
* This
,
4879 ULARGE_INTEGER offset
,
4882 ULONG
* bytesWritten
)
4884 ULARGE_INTEGER offsetInBigBlockFile
;
4885 ULONG blockNoInSequence
=
4886 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4888 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4889 ULONG bytesToWriteInBuffer
;
4891 ULONG bytesWrittenFromBigBlockFile
;
4895 * This should never happen on a small block file.
4897 assert(offset
.HighPart
==0);
4900 * Find the first block in the stream that contains part of the buffer.
4902 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4904 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4906 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4908 blockNoInSequence
--;
4912 * Start writing the buffer.
4914 * Here, I'm casting away the constness on the buffer variable
4915 * This is OK since we don't intend to modify that buffer.
4918 bufferWalker
= (BYTE
*)buffer
;
4919 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4922 * Calculate how many bytes we can copy to this small block.
4924 bytesToWriteInBuffer
=
4925 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4928 * Calculate the offset of the small block in the small block file.
4930 offsetInBigBlockFile
.HighPart
= 0;
4931 offsetInBigBlockFile
.LowPart
=
4932 blockIndex
* This
->parentStorage
->smallBlockSize
;
4934 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4937 * Write those bytes in the buffer to the small block file.
4939 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
4940 offsetInBigBlockFile
,
4941 bytesToWriteInBuffer
,
4943 &bytesWrittenFromBigBlockFile
);
4945 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
4948 * Step to the next big block.
4950 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4951 bufferWalker
+= bytesToWriteInBuffer
;
4952 size
-= bytesToWriteInBuffer
;
4953 *bytesWritten
+= bytesToWriteInBuffer
;
4954 offsetInBlock
= 0; /* There is no offset on the next block */
4960 /******************************************************************************
4961 * SmallBlockChainStream_Shrink
4963 * Shrinks this chain in the small block depot.
4965 BOOL
SmallBlockChainStream_Shrink(
4966 SmallBlockChainStream
* This
,
4967 ULARGE_INTEGER newSize
)
4969 ULONG blockIndex
, extraBlock
;
4973 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4975 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4978 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4981 * Go to the new end of chain
4983 while (count
< numBlocks
)
4985 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4990 * If the count is 0, we have a special case, the head of the chain was
4995 StgProperty chainProp
;
4997 StorageImpl_ReadProperty(This
->parentStorage
,
4998 This
->ownerPropertyIndex
,
5001 chainProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
5003 StorageImpl_WriteProperty(This
->parentStorage
,
5004 This
->ownerPropertyIndex
,
5008 * We start freeing the chain at the head block.
5010 extraBlock
= blockIndex
;
5014 /* Get the next block before marking the new end */
5015 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5017 /* Mark the new end of chain */
5018 SmallBlockChainStream_SetNextBlockInChain(
5021 BLOCK_END_OF_CHAIN
);
5025 * Mark the extra blocks as free
5027 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
5029 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
5030 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
5031 extraBlock
= blockIndex
;
5037 /******************************************************************************
5038 * SmallBlockChainStream_Enlarge
5040 * Grows this chain in the small block depot.
5042 BOOL
SmallBlockChainStream_Enlarge(
5043 SmallBlockChainStream
* This
,
5044 ULARGE_INTEGER newSize
)
5046 ULONG blockIndex
, currentBlock
;
5048 ULONG oldNumBlocks
= 0;
5050 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5055 if (blockIndex
== BLOCK_END_OF_CHAIN
)
5058 StgProperty chainProp
;
5060 StorageImpl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5063 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
5065 StorageImpl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5068 blockIndex
= chainProp
.startingBlock
;
5069 SmallBlockChainStream_SetNextBlockInChain(
5072 BLOCK_END_OF_CHAIN
);
5075 currentBlock
= blockIndex
;
5078 * Figure out how many blocks are needed to contain this stream
5080 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5082 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5086 * Go to the current end of chain
5088 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5091 currentBlock
= blockIndex
;
5092 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
5096 * Add new blocks to the chain
5098 while (oldNumBlocks
< newNumBlocks
)
5100 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
5101 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
5103 SmallBlockChainStream_SetNextBlockInChain(
5106 BLOCK_END_OF_CHAIN
);
5108 currentBlock
= blockIndex
;
5115 /******************************************************************************
5116 * SmallBlockChainStream_GetCount
5118 * Returns the number of blocks that comprises this chain.
5119 * This is not the size of this chain as the last block may not be full!
5121 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
5126 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5128 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5132 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5138 /******************************************************************************
5139 * SmallBlockChainStream_SetSize
5141 * Sets the size of this stream.
5142 * The file will grow if we grow the chain.
5144 * TODO: Free the actual blocks in the file when we shrink the chain.
5145 * Currently, the blocks are still in the file. So the file size
5146 * doesn't shrink even if we shrink streams.
5148 BOOL
SmallBlockChainStream_SetSize(
5149 SmallBlockChainStream
* This
,
5150 ULARGE_INTEGER newSize
)
5152 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
5154 if (newSize
.LowPart
== size
.LowPart
)
5157 if (newSize
.LowPart
< size
.LowPart
)
5159 SmallBlockChainStream_Shrink(This
, newSize
);
5163 SmallBlockChainStream_Enlarge(This
, newSize
);
5169 /******************************************************************************
5170 * SmallBlockChainStream_GetSize
5172 * Returns the size of this chain.
5174 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
5176 StgProperty chainProperty
;
5178 StorageImpl_ReadProperty(
5179 This
->parentStorage
,
5180 This
->ownerPropertyIndex
,
5183 return chainProperty
.size
;
5186 /******************************************************************************
5187 * StgCreateDocfile32 [OLE32.144]
5189 HRESULT WINAPI
StgCreateDocfile(
5193 IStorage
**ppstgOpen
)
5195 StorageImpl
* newStorage
= 0;
5196 HANDLE hFile
= INVALID_HANDLE_VALUE
;
5201 DWORD fileAttributes
;
5202 WCHAR tempFileName
[MAX_PATH
];
5204 TRACE(storage
, "(%s, %lx, %ld, %p)\n",
5205 debugstr_w(pwcsName
), grfMode
,
5206 reserved
, ppstgOpen
);
5209 * Validate the parameters
5212 return STG_E_INVALIDPOINTER
;
5215 * Validate the STGM flags
5217 if ( FAILED( validateSTGM(grfMode
) ))
5218 return STG_E_INVALIDFLAG
;
5221 * Generate a unique name.
5225 WCHAR tempPath
[MAX_PATH
];
5226 WCHAR prefix
[] = { 'S', 'T', 'O', 0 };
5228 memset(tempPath
, 0, sizeof(tempPath
));
5229 memset(tempFileName
, 0, sizeof(tempFileName
));
5231 if ((GetTempPathW(MAX_PATH
, tempPath
)) == 0 )
5234 if (GetTempFileNameW(tempPath
, prefix
, 0, tempFileName
) != 0)
5235 pwcsName
= tempFileName
;
5237 return STG_E_INSUFFICIENTMEMORY
;
5241 * Interpret the STGM value grfMode
5243 shareMode
= GetShareModeFromSTGM(grfMode
);
5244 accessMode
= GetAccessModeFromSTGM(grfMode
);
5245 creationMode
= GetCreationModeFromSTGM(grfMode
);
5247 if (grfMode
& STGM_DELETEONRELEASE
)
5248 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
5250 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
5252 if (grfMode
& STGM_TRANSACTED
)
5253 FIXME(storage
, "Transacted mode not implemented.\n");
5256 * Initialize the "out" parameter.
5260 hFile
= CreateFileW(pwcsName
,
5268 if (hFile
== INVALID_HANDLE_VALUE
)
5274 * Allocate and initialize the new IStorage32object.
5276 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5278 if (newStorage
== 0)
5279 return STG_E_INSUFFICIENTMEMORY
;
5281 hr
= StorageImpl_Construct(
5290 HeapFree(GetProcessHeap(), 0, newStorage
);
5295 * Get an "out" pointer for the caller.
5297 hr
= StorageBaseImpl_QueryInterface(
5298 (IStorage
*)newStorage
,
5299 (REFIID
)&IID_IStorage
,
5305 /******************************************************************************
5306 * StgOpenStorage32 [OLE32.148]
5308 HRESULT WINAPI
StgOpenStorage(
5309 const OLECHAR
*pwcsName
,
5310 IStorage
*pstgPriority
,
5314 IStorage
**ppstgOpen
)
5316 StorageImpl
* newStorage
= 0;
5322 TRACE(storage
, "(%s, %p, %lx, %p, %ld, %p)\n",
5323 debugstr_w(pwcsName
), pstgPriority
, grfMode
,
5324 snbExclude
, reserved
, ppstgOpen
);
5327 * Perform a sanity check
5329 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
5330 return STG_E_INVALIDPOINTER
;
5333 * Validate the STGM flags
5335 if ( FAILED( validateSTGM(grfMode
) ))
5336 return STG_E_INVALIDFLAG
;
5339 * Interpret the STGM value grfMode
5341 shareMode
= GetShareModeFromSTGM(grfMode
);
5342 accessMode
= GetAccessModeFromSTGM(grfMode
);
5345 * Initialize the "out" parameter.
5349 hFile
= CreateFileW( pwcsName
,
5354 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5358 if (hFile
==INVALID_HANDLE_VALUE
)
5364 * Allocate and initialize the new IStorage32object.
5366 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5368 if (newStorage
== 0)
5369 return STG_E_INSUFFICIENTMEMORY
;
5371 hr
= StorageImpl_Construct(
5380 HeapFree(GetProcessHeap(), 0, newStorage
);
5385 * Get an "out" pointer for the caller.
5387 hr
= StorageBaseImpl_QueryInterface(
5388 (IStorage
*)newStorage
,
5389 (REFIID
)&IID_IStorage
,
5395 /******************************************************************************
5396 * StgCreateDocfileOnILockBytes [OLE32.145]
5398 HRESULT WINAPI
StgCreateDocfileOnILockBytes(
5402 IStorage
** ppstgOpen
)
5404 StorageImpl
* newStorage
= 0;
5408 * Validate the parameters
5410 if ((ppstgOpen
== 0) || (plkbyt
== 0))
5411 return STG_E_INVALIDPOINTER
;
5414 * Allocate and initialize the new IStorage object.
5416 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5418 if (newStorage
== 0)
5419 return STG_E_INSUFFICIENTMEMORY
;
5421 hr
= StorageImpl_Construct(
5430 HeapFree(GetProcessHeap(), 0, newStorage
);
5435 * Get an "out" pointer for the caller.
5437 hr
= StorageBaseImpl_QueryInterface(
5438 (IStorage
*)newStorage
,
5439 (REFIID
)&IID_IStorage
,
5445 /******************************************************************************
5446 * StgOpenStorageOnILockBytes [OLE32.149]
5448 HRESULT WINAPI
StgOpenStorageOnILockBytes(
5450 IStorage
*pstgPriority
,
5454 IStorage
**ppstgOpen
)
5456 StorageImpl
* newStorage
= 0;
5460 * Perform a sanity check
5462 if ((plkbyt
== 0) || (ppstgOpen
== 0))
5463 return STG_E_INVALIDPOINTER
;
5466 * Validate the STGM flags
5468 if ( FAILED( validateSTGM(grfMode
) ))
5469 return STG_E_INVALIDFLAG
;
5472 * Initialize the "out" parameter.
5477 * Allocate and initialize the new IStorage object.
5479 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5481 if (newStorage
== 0)
5482 return STG_E_INSUFFICIENTMEMORY
;
5484 hr
= StorageImpl_Construct(
5493 HeapFree(GetProcessHeap(), 0, newStorage
);
5498 * Get an "out" pointer for the caller.
5500 hr
= StorageBaseImpl_QueryInterface(
5501 (IStorage
*)newStorage
,
5502 (REFIID
)&IID_IStorage
,
5508 /******************************************************************************
5509 * StgIsStorageILockBytes [OLE32.147]
5511 * Determines if the ILockBytes contains a storage object.
5513 HRESULT WINAPI
StgIsStorageILockBytes(ILockBytes
*plkbyt
)
5516 ULARGE_INTEGER offset
;
5518 offset
.HighPart
= 0;
5521 ILockBytes_ReadAt(plkbyt
, offset
, sig
, sizeof(sig
), NULL
);
5523 if (memcmp(sig
, STORAGE_magic
, sizeof(STORAGE_magic
)) == 0)
5529 /******************************************************************************
5530 * WriteClassStg32 [OLE32.158]
5532 * This method will store the specified CLSID in the specified storage object
5534 HRESULT WINAPI
WriteClassStg(IStorage
* pStg
, REFCLSID rclsid
)
5540 hRes
= IStorage_SetClass(pStg
, rclsid
);
5545 /*******************************************************************************************
5548 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5550 HRESULT WINAPI
ReadClassStg(IStorage
*pstg
,CLSID
*pclsid
){
5555 TRACE(storage
,"()\n");
5560 * read a STATSTG structure (contains the clsid) from the storage
5562 hRes
=IStorage_Stat(pstg
,&pstatstg
,STATFLAG_DEFAULT
);
5565 *pclsid
=pstatstg
.clsid
;
5570 /*************************************************************************************
5573 * This function loads an object from stream
5575 HRESULT WINAPI
OleLoadFromStream(IStream
*pStm
,REFIID iidInterface
,void** ppvObj
)
5580 FIXME(storage
,"(),stub!\n");
5582 res
=ReadClassStm(pStm
,&clsid
);
5584 if (SUCCEEDED(res
)){
5586 res
=CoCreateInstance(&clsid
,NULL
,CLSCTX_INPROC_SERVER
,iidInterface
,ppvObj
);
5590 res
=IPersistStream_Load((IPersistStream
*)ppvObj
,pStm
);
5596 /************************************************************************************************
5599 * This function saves an object with the IPersistStream interface on it to the specified stream
5601 HRESULT WINAPI
OleSaveToStream(IPersistStream
*pPStm
,IStream
*pStm
)
5607 TRACE(storage
,"(%p,%p)\n",pPStm
,pStm
);
5609 res
=IPersistStream_GetClassID(pPStm
,&clsid
);
5611 if (SUCCEEDED(res
)){
5613 res
=WriteClassStm(pStm
,&clsid
);
5617 res
=IPersistStream_Save(pPStm
,pStm
,FALSE
);
5623 /****************************************************************************
5624 * This method validate a STGM parameter that can contain the values below
5626 * STGM_DIRECT 0x00000000
5627 * STGM_TRANSACTED 0x00010000
5628 * STGM_SIMPLE 0x08000000
5630 * STGM_READ 0x00000000
5631 * STGM_WRITE 0x00000001
5632 * STGM_READWRITE 0x00000002
5634 * STGM_SHARE_DENY_NONE 0x00000040
5635 * STGM_SHARE_DENY_READ 0x00000030
5636 * STGM_SHARE_DENY_WRITE 0x00000020
5637 * STGM_SHARE_EXCLUSIVE 0x00000010
5639 * STGM_PRIORITY 0x00040000
5640 * STGM_DELETEONRELEASE 0x04000000
5642 * STGM_CREATE 0x00001000
5643 * STGM_CONVERT 0x00020000
5644 * STGM_FAILIFTHERE 0x00000000
5646 * STGM_NOSCRATCH 0x00100000
5647 * STGM_NOSNAPSHOT 0x00200000
5649 static HRESULT
validateSTGM(DWORD stgm
)
5651 BOOL bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5652 BOOL bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5653 BOOL bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5655 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5656 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5657 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5659 BOOL bSTGM_SHARE_DENY_NONE
=
5660 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5662 BOOL bSTGM_SHARE_DENY_READ
=
5663 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5665 BOOL bSTGM_SHARE_DENY_WRITE
=
5666 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5668 BOOL bSTGM_SHARE_EXCLUSIVE
=
5669 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5671 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5672 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5674 BOOL bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5675 BOOL bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5678 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5680 if ( ! bSTGM_DIRECT
)
5681 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5685 * STGM_WRITE | STGM_READWRITE | STGM_READ
5688 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5692 * STGM_SHARE_DENY_NONE | others
5693 * (I assume here that DENY_READ implies DENY_WRITE)
5695 if ( bSTGM_SHARE_DENY_NONE
)
5696 if ( bSTGM_SHARE_DENY_READ
||
5697 bSTGM_SHARE_DENY_WRITE
||
5698 bSTGM_SHARE_EXCLUSIVE
)
5702 * STGM_CREATE | STGM_CONVERT
5703 * if both are false, STGM_FAILIFTHERE is set to TRUE
5705 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5709 * STGM_NOSCRATCH requires STGM_TRANSACTED
5711 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5715 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5716 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5718 if (bSTGM_NOSNAPSHOT
)
5720 if ( ! ( bSTGM_TRANSACTED
&&
5721 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
5728 /****************************************************************************
5729 * GetShareModeFromSTGM
5731 * This method will return a share mode flag from a STGM value.
5732 * The STGM value is assumed valid.
5734 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
5736 DWORD dwShareMode
= 0;
5737 BOOL bSTGM_SHARE_DENY_NONE
=
5738 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5740 BOOL bSTGM_SHARE_DENY_READ
=
5741 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5743 BOOL bSTGM_SHARE_DENY_WRITE
=
5744 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5746 BOOL bSTGM_SHARE_EXCLUSIVE
=
5747 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5749 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
5752 if (bSTGM_SHARE_DENY_NONE
)
5753 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
5755 if (bSTGM_SHARE_DENY_WRITE
)
5756 dwShareMode
= FILE_SHARE_READ
;
5761 /****************************************************************************
5762 * GetAccessModeFromSTGM
5764 * This method will return an access mode flag from a STGM value.
5765 * The STGM value is assumed valid.
5767 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
5769 DWORD dwDesiredAccess
= GENERIC_READ
;
5770 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5771 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5772 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5775 dwDesiredAccess
= GENERIC_READ
;
5778 dwDesiredAccess
|= GENERIC_WRITE
;
5780 if (bSTGM_READWRITE
)
5781 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
5783 return dwDesiredAccess
;
5786 /****************************************************************************
5787 * GetCreationModeFromSTGM
5789 * This method will return a creation mode flag from a STGM value.
5790 * The STGM value is assumed valid.
5792 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
5794 if ( stgm
& STGM_CREATE
)
5795 return CREATE_ALWAYS
;
5796 if (stgm
& STGM_CONVERT
) {
5797 FIXME(storage
, "STGM_CONVERT not implemented!\n");
5800 /* All other cases */
5801 if (stgm
& ~ (STGM_CREATE
|STGM_CONVERT
))
5802 FIXME(storage
,"unhandled storage mode : 0x%08lx\n",stgm
& ~ (STGM_CREATE
|STGM_CONVERT
));