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
18 #include "winbase.h" /* for lstrlenW() and the likes */
19 #include "debugtools.h"
21 #include "storage32.h"
22 #include "ole2.h" /* For Write/ReadClassStm */
24 DEFAULT_DEBUG_CHANNEL(storage
)
28 static const char rootPropertyName
[] = "Root Entry";
30 /***********************************************************************
31 * Forward declaration of internal functions used by the method DestroyElement
33 static HRESULT
deleteStorageProperty(
34 StorageImpl
*parentStorage
,
35 OLECHAR
*propertyToDeleteName
);
37 static HRESULT
deleteStreamProperty(
38 StorageImpl
*parentStorage
,
39 ULONG foundPropertyIndexToDelete
,
40 StgProperty propertyToDelete
);
42 static HRESULT
findPlaceholder(
44 ULONG propertyIndexToStore
,
45 ULONG storagePropertyIndex
,
48 static HRESULT
adjustPropertyChain(
50 StgProperty propertyToDelete
,
51 StgProperty parentProperty
,
52 ULONG parentPropertyId
,
55 /***********************************************************************
56 * Declaration of the functions used to manipulate StgProperty
59 static ULONG
getFreeProperty(
60 StorageImpl
*storage
);
62 static void updatePropertyChain(
64 ULONG newPropertyIndex
,
65 StgProperty newProperty
);
67 static LONG
propertyNameCmp(
69 OLECHAR
*currentProperty
);
72 /***********************************************************************
73 * Declaration of miscellaneous functions...
75 static HRESULT
validateSTGM(DWORD stgmValue
);
77 static DWORD
GetShareModeFromSTGM(DWORD stgm
);
78 static DWORD
GetAccessModeFromSTGM(DWORD stgm
);
79 static DWORD
GetCreationModeFromSTGM(DWORD stgm
);
82 * Virtual function table for the IStorage32Impl class.
84 static ICOM_VTABLE(IStorage
) Storage32Impl_Vtbl
=
86 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
87 StorageBaseImpl_QueryInterface
,
88 StorageBaseImpl_AddRef
,
89 StorageBaseImpl_Release
,
90 StorageBaseImpl_CreateStream
,
91 StorageBaseImpl_OpenStream
,
92 StorageImpl_CreateStorage
,
93 StorageBaseImpl_OpenStorage
,
95 StorageImpl_MoveElementTo
,
98 StorageBaseImpl_EnumElements
,
99 StorageImpl_DestroyElement
,
100 StorageBaseImpl_RenameElement
,
101 StorageImpl_SetElementTimes
,
102 StorageBaseImpl_SetClass
,
103 StorageImpl_SetStateBits
,
108 * Virtual function table for the Storage32InternalImpl class.
110 static ICOM_VTABLE(IStorage
) Storage32InternalImpl_Vtbl
=
112 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
113 StorageBaseImpl_QueryInterface
,
114 StorageBaseImpl_AddRef
,
115 StorageBaseImpl_Release
,
116 StorageBaseImpl_CreateStream
,
117 StorageBaseImpl_OpenStream
,
118 StorageImpl_CreateStorage
,
119 StorageBaseImpl_OpenStorage
,
121 StorageImpl_MoveElementTo
,
122 StorageInternalImpl_Commit
,
123 StorageInternalImpl_Revert
,
124 StorageBaseImpl_EnumElements
,
125 StorageImpl_DestroyElement
,
126 StorageBaseImpl_RenameElement
,
127 StorageImpl_SetElementTimes
,
128 StorageBaseImpl_SetClass
,
129 StorageImpl_SetStateBits
,
134 * Virtual function table for the IEnumSTATSTGImpl class.
136 static ICOM_VTABLE(IEnumSTATSTG
) IEnumSTATSTGImpl_Vtbl
=
138 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
139 IEnumSTATSTGImpl_QueryInterface
,
140 IEnumSTATSTGImpl_AddRef
,
141 IEnumSTATSTGImpl_Release
,
142 IEnumSTATSTGImpl_Next
,
143 IEnumSTATSTGImpl_Skip
,
144 IEnumSTATSTGImpl_Reset
,
145 IEnumSTATSTGImpl_Clone
152 /************************************************************************
153 ** Storage32BaseImpl implementatiion
156 /************************************************************************
157 * Storage32BaseImpl_QueryInterface (IUnknown)
159 * This method implements the common QueryInterface for all IStorage32
160 * implementations contained in this file.
162 * See Windows documentation for more details on IUnknown methods.
164 HRESULT WINAPI
StorageBaseImpl_QueryInterface(
169 ICOM_THIS(StorageBaseImpl
,iface
);
171 * Perform a sanity check on the parameters.
173 if ( (This
==0) || (ppvObject
==0) )
177 * Initialize the return parameter.
182 * Compare the riid with the interface IDs implemented by this object.
184 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
186 *ppvObject
= (IStorage
*)This
;
188 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
190 *ppvObject
= (IStorage
*)This
;
194 * Check that we obtained an interface.
197 return E_NOINTERFACE
;
200 * Query Interface always increases the reference count by one when it is
203 StorageBaseImpl_AddRef(iface
);
208 /************************************************************************
209 * Storage32BaseImpl_AddRef (IUnknown)
211 * This method implements the common AddRef for all IStorage32
212 * implementations contained in this file.
214 * See Windows documentation for more details on IUnknown methods.
216 ULONG WINAPI
StorageBaseImpl_AddRef(
219 ICOM_THIS(StorageBaseImpl
,iface
);
225 /************************************************************************
226 * Storage32BaseImpl_Release (IUnknown)
228 * This method implements the common Release for all IStorage32
229 * implementations contained in this file.
231 * See Windows documentation for more details on IUnknown methods.
233 ULONG WINAPI
StorageBaseImpl_Release(
236 ICOM_THIS(StorageBaseImpl
,iface
);
238 * Decrease the reference count on this object.
243 * If the reference count goes down to 0, perform suicide.
248 * Since we are using a system of base-classes, we want to call the
249 * destructor of the appropriate derived class. To do this, we are
250 * using virtual functions to implement the destructor.
252 This
->v_destructor(This
);
260 /************************************************************************
261 * Storage32BaseImpl_OpenStream (IStorage)
263 * This method will open the specified stream object from the current storage.
265 * See Windows documentation for more details on IStorage methods.
267 HRESULT WINAPI
StorageBaseImpl_OpenStream(
269 const OLECHAR
* pwcsName
, /* [string][in] */
270 void* reserved1
, /* [unique][in] */
271 DWORD grfMode
, /* [in] */
272 DWORD reserved2
, /* [in] */
273 IStream
** ppstm
) /* [out] */
275 ICOM_THIS(StorageBaseImpl
,iface
);
276 IEnumSTATSTGImpl
* propertyEnumeration
;
277 StgStreamImpl
* newStream
;
278 StgProperty currentProperty
;
279 ULONG foundPropertyIndex
;
281 TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
282 iface
, debugstr_w(pwcsName
), reserved1
, grfMode
, reserved2
, ppstm
);
285 * Perform a sanity check on the parameters.
287 if ( (pwcsName
==NULL
) || (ppstm
==0) )
291 * Initialize the out parameter
296 * Validate the STGM flags
298 if ( FAILED( validateSTGM(grfMode
) ))
299 return STG_E_INVALIDFLAG
;
304 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
305 (grfMode
& STGM_DELETEONRELEASE
) ||
306 (grfMode
& STGM_TRANSACTED
) )
307 return STG_E_INVALIDFUNCTION
;
310 * Create a property enumeration to search the properties
312 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
313 This
->ancestorStorage
,
314 This
->rootPropertySetIndex
);
317 * Search the enumeration for the property with the given name
319 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
325 * Delete the property enumeration since we don't need it anymore
327 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
330 * If it was found, construct the stream object and return a pointer to it.
332 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
333 (currentProperty
.propertyType
==PROPTYPE_STREAM
) )
335 newStream
= StgStreamImpl_Construct(This
, foundPropertyIndex
);
339 *ppstm
= (IStream
*)newStream
;
342 * Since we are returning a pointer to the interface, we have to
343 * nail down the reference.
345 StgStreamImpl_AddRef(*ppstm
);
350 return E_OUTOFMEMORY
;
353 return STG_E_FILENOTFOUND
;
356 /************************************************************************
357 * Storage32BaseImpl_OpenStorage (IStorage)
359 * This method will open a new storage object from the current storage.
361 * See Windows documentation for more details on IStorage methods.
363 HRESULT WINAPI
StorageBaseImpl_OpenStorage(
365 const OLECHAR
* pwcsName
, /* [string][unique][in] */
366 IStorage
* pstgPriority
, /* [unique][in] */
367 DWORD grfMode
, /* [in] */
368 SNB snbExclude
, /* [unique][in] */
369 DWORD reserved
, /* [in] */
370 IStorage
** ppstg
) /* [out] */
372 ICOM_THIS(StorageBaseImpl
,iface
);
373 StorageInternalImpl
* newStorage
;
374 IEnumSTATSTGImpl
* propertyEnumeration
;
375 StgProperty currentProperty
;
376 ULONG foundPropertyIndex
;
378 TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
379 iface
, debugstr_w(pwcsName
), pstgPriority
,
380 grfMode
, snbExclude
, reserved
, ppstg
);
383 * Perform a sanity check on the parameters.
385 if ( (This
==0) || (pwcsName
==NULL
) || (ppstg
==0) )
389 * Validate the STGM flags
391 if ( FAILED( validateSTGM(grfMode
) ))
392 return STG_E_INVALIDFLAG
;
397 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
398 (grfMode
& STGM_DELETEONRELEASE
) ||
399 (grfMode
& STGM_PRIORITY
) )
400 return STG_E_INVALIDFUNCTION
;
403 * Initialize the out parameter
408 * Create a property enumeration to search the properties
410 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
411 This
->ancestorStorage
,
412 This
->rootPropertySetIndex
);
415 * Search the enumeration for the property with the given name
417 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
423 * Delete the property enumeration since we don't need it anymore
425 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
428 * If it was found, construct the stream object and return a pointer to it.
430 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
431 (currentProperty
.propertyType
==PROPTYPE_STORAGE
) )
434 * Construct a new Storage object
436 newStorage
= StorageInternalImpl_Construct(
437 This
->ancestorStorage
,
442 *ppstg
= (IStorage
*)newStorage
;
445 * Since we are returning a pointer to the interface,
446 * we have to nail down the reference.
448 StorageBaseImpl_AddRef(*ppstg
);
453 return STG_E_INSUFFICIENTMEMORY
;
456 return STG_E_FILENOTFOUND
;
459 /************************************************************************
460 * Storage32BaseImpl_EnumElements (IStorage)
462 * This method will create an enumerator object that can be used to
463 * retrieve informatino about all the properties in the storage object.
465 * See Windows documentation for more details on IStorage methods.
467 HRESULT WINAPI
StorageBaseImpl_EnumElements(
469 DWORD reserved1
, /* [in] */
470 void* reserved2
, /* [size_is][unique][in] */
471 DWORD reserved3
, /* [in] */
472 IEnumSTATSTG
** ppenum
) /* [out] */
474 ICOM_THIS(StorageBaseImpl
,iface
);
475 IEnumSTATSTGImpl
* newEnum
;
477 TRACE("(%p, %ld, %p, %ld, %p)\n",
478 iface
, reserved1
, reserved2
, reserved3
, ppenum
);
481 * Perform a sanity check on the parameters.
483 if ( (This
==0) || (ppenum
==0))
487 * Construct the enumerator.
489 newEnum
= IEnumSTATSTGImpl_Construct(
490 This
->ancestorStorage
,
491 This
->rootPropertySetIndex
);
495 *ppenum
= (IEnumSTATSTG
*)newEnum
;
498 * Don't forget to nail down a reference to the new object before
501 IEnumSTATSTGImpl_AddRef(*ppenum
);
506 return E_OUTOFMEMORY
;
509 /************************************************************************
510 * Storage32BaseImpl_Stat (IStorage)
512 * This method will retrieve information about this storage object.
514 * See Windows documentation for more details on IStorage methods.
516 HRESULT WINAPI
StorageBaseImpl_Stat(
518 STATSTG
* pstatstg
, /* [out] */
519 DWORD grfStatFlag
) /* [in] */
521 ICOM_THIS(StorageBaseImpl
,iface
);
522 StgProperty curProperty
;
525 TRACE("(%p, %p, %lx)\n",
526 iface
, pstatstg
, grfStatFlag
);
529 * Perform a sanity check on the parameters.
531 if ( (This
==0) || (pstatstg
==0))
535 * Read the information from the property.
537 readSucessful
= StorageImpl_ReadProperty(
538 This
->ancestorStorage
,
539 This
->rootPropertySetIndex
,
544 StorageUtl_CopyPropertyToSTATSTG(
555 /************************************************************************
556 * Storage32BaseImpl_RenameElement (IStorage)
558 * This method will rename the specified element.
560 * See Windows documentation for more details on IStorage methods.
562 * Implementation notes: The method used to rename consists of creating a clone
563 * of the deleted StgProperty object setting it with the new name and to
564 * perform a DestroyElement of the old StgProperty.
566 HRESULT WINAPI
StorageBaseImpl_RenameElement(
568 const OLECHAR
* pwcsOldName
, /* [in] */
569 const OLECHAR
* pwcsNewName
) /* [in] */
571 ICOM_THIS(StorageBaseImpl
,iface
);
572 IEnumSTATSTGImpl
* propertyEnumeration
;
573 StgProperty currentProperty
;
574 ULONG foundPropertyIndex
;
576 TRACE("(%p, %s, %s)\n",
577 iface
, debugstr_w(pwcsOldName
), debugstr_w(pwcsNewName
));
580 * Create a property enumeration to search the properties
582 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
583 This
->rootPropertySetIndex
);
586 * Search the enumeration for the new property name
588 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
592 if (foundPropertyIndex
!= PROPERTY_NULL
)
595 * There is already a property with the new name
597 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
598 return STG_E_FILEALREADYEXISTS
;
601 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)propertyEnumeration
);
604 * Search the enumeration for the old property name
606 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
611 * Delete the property enumeration since we don't need it anymore
613 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
615 if (foundPropertyIndex
!= PROPERTY_NULL
)
617 StgProperty renamedProperty
;
618 ULONG renamedPropertyIndex
;
621 * Setup a new property for the renamed property
623 renamedProperty
.sizeOfNameString
=
624 ( lstrlenW(pwcsNewName
)+1 ) * sizeof(WCHAR
);
626 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
627 return STG_E_INVALIDNAME
;
629 lstrcpyW(renamedProperty
.name
, pwcsNewName
);
631 renamedProperty
.propertyType
= currentProperty
.propertyType
;
632 renamedProperty
.startingBlock
= currentProperty
.startingBlock
;
633 renamedProperty
.size
.s
.LowPart
= currentProperty
.size
.s
.LowPart
;
634 renamedProperty
.size
.s
.HighPart
= currentProperty
.size
.s
.HighPart
;
636 renamedProperty
.previousProperty
= PROPERTY_NULL
;
637 renamedProperty
.nextProperty
= PROPERTY_NULL
;
640 * Bring the dirProperty link in case it is a storage and in which
641 * case the renamed storage elements don't require to be reorganized.
643 renamedProperty
.dirProperty
= currentProperty
.dirProperty
;
645 /* call CoFileTime to get the current time
646 renamedProperty.timeStampS1
647 renamedProperty.timeStampD1
648 renamedProperty.timeStampS2
649 renamedProperty.timeStampD2
650 renamedProperty.propertyUniqueID
654 * Obtain a free property in the property chain
656 renamedPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
659 * Save the new property into the new property spot
661 StorageImpl_WriteProperty(
662 This
->ancestorStorage
,
663 renamedPropertyIndex
,
667 * Find a spot in the property chain for our newly created property.
671 renamedPropertyIndex
,
675 * At this point the renamed property has been inserted in the tree,
676 * now, before to Destroy the old property we must zeroed it's dirProperty
677 * otherwise the DestroyProperty below will zap it all and we do not want
679 * Also, we fake that the old property is a storage so the DestroyProperty
680 * will not do a SetSize(0) on the stream data.
682 * This means that we need to tweek the StgProperty if it is a stream or a
685 currentProperty
.dirProperty
= PROPERTY_NULL
;
686 currentProperty
.propertyType
= PROPTYPE_STORAGE
;
687 StorageImpl_WriteProperty(
688 This
->ancestorStorage
,
693 * Invoke Destroy to get rid of the ole property and automatically redo
694 * the linking of it's previous and next members...
696 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsOldName
);
702 * There is no property with the old name
704 return STG_E_FILENOTFOUND
;
710 /************************************************************************
711 * Storage32BaseImpl_CreateStream (IStorage)
713 * This method will create a stream object within this storage
715 * See Windows documentation for more details on IStorage methods.
717 HRESULT WINAPI
StorageBaseImpl_CreateStream(
719 const OLECHAR
* pwcsName
, /* [string][in] */
720 DWORD grfMode
, /* [in] */
721 DWORD reserved1
, /* [in] */
722 DWORD reserved2
, /* [in] */
723 IStream
** ppstm
) /* [out] */
725 ICOM_THIS(StorageBaseImpl
,iface
);
726 IEnumSTATSTGImpl
* propertyEnumeration
;
727 StgStreamImpl
* newStream
;
728 StgProperty currentProperty
, newStreamProperty
;
729 ULONG foundPropertyIndex
, newPropertyIndex
;
731 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
732 iface
, debugstr_w(pwcsName
), grfMode
,
733 reserved1
, reserved2
, ppstm
);
736 * Validate parameters
739 return STG_E_INVALIDPOINTER
;
742 return STG_E_INVALIDNAME
;
745 * Validate the STGM flags
747 if ( FAILED( validateSTGM(grfMode
) ))
748 return STG_E_INVALIDFLAG
;
753 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
754 (grfMode
& STGM_DELETEONRELEASE
) ||
755 (grfMode
& STGM_TRANSACTED
) )
756 return STG_E_INVALIDFUNCTION
;
759 * Initialize the out parameter
764 * Create a property enumeration to search the properties
766 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
767 This
->rootPropertySetIndex
);
769 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
773 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
775 if (foundPropertyIndex
!= PROPERTY_NULL
)
778 * An element with this name already exists
780 if (grfMode
& STGM_CREATE
)
782 IStorage_DestroyElement(iface
, pwcsName
);
785 return STG_E_FILEALREADYEXISTS
;
789 * memset the empty property
791 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
793 newStreamProperty
.sizeOfNameString
=
794 ( lstrlenW(pwcsName
)+1 ) * sizeof(WCHAR
);
796 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
797 return STG_E_INVALIDNAME
;
799 lstrcpyW(newStreamProperty
.name
, pwcsName
);
801 newStreamProperty
.propertyType
= PROPTYPE_STREAM
;
802 newStreamProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
803 newStreamProperty
.size
.s
.LowPart
= 0;
804 newStreamProperty
.size
.s
.HighPart
= 0;
806 newStreamProperty
.previousProperty
= PROPERTY_NULL
;
807 newStreamProperty
.nextProperty
= PROPERTY_NULL
;
808 newStreamProperty
.dirProperty
= PROPERTY_NULL
;
810 /* call CoFileTime to get the current time
811 newStreamProperty.timeStampS1
812 newStreamProperty.timeStampD1
813 newStreamProperty.timeStampS2
814 newStreamProperty.timeStampD2
817 /* newStreamProperty.propertyUniqueID */
820 * Get a free property or create a new one
822 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
825 * Save the new property into the new property spot
827 StorageImpl_WriteProperty(
828 This
->ancestorStorage
,
833 * Find a spot in the property chain for our newly created property.
841 * Open the stream to return it.
843 newStream
= StgStreamImpl_Construct(This
, newPropertyIndex
);
847 *ppstm
= (IStream
*)newStream
;
850 * Since we are returning a pointer to the interface, we have to nail down
853 StgStreamImpl_AddRef(*ppstm
);
857 return STG_E_INSUFFICIENTMEMORY
;
863 /************************************************************************
864 * Storage32BaseImpl_SetClass (IStorage)
866 * This method will write the specified CLSID in the property of this
869 * See Windows documentation for more details on IStorage methods.
871 HRESULT WINAPI
StorageBaseImpl_SetClass(
873 REFCLSID clsid
) /* [in] */
875 ICOM_THIS(StorageBaseImpl
,iface
);
876 HRESULT hRes
= E_FAIL
;
877 StgProperty curProperty
;
880 TRACE("(%p, %p)\n", iface
, clsid
);
882 success
= StorageImpl_ReadProperty(This
->ancestorStorage
,
883 This
->rootPropertySetIndex
,
887 curProperty
.propertyUniqueID
= *clsid
;
889 success
= StorageImpl_WriteProperty(This
->ancestorStorage
,
890 This
->rootPropertySetIndex
,
899 /************************************************************************
900 ** Storage32Impl implementation
903 /************************************************************************
904 * Storage32Impl_CreateStorage (IStorage)
906 * This method will create the storage object within the provided storage.
908 * See Windows documentation for more details on IStorage methods.
910 HRESULT WINAPI
StorageImpl_CreateStorage(
912 const OLECHAR
*pwcsName
, /* [string][in] */
913 DWORD grfMode
, /* [in] */
914 DWORD reserved1
, /* [in] */
915 DWORD reserved2
, /* [in] */
916 IStorage
**ppstg
) /* [out] */
918 StorageImpl
* const This
=(StorageImpl
*)iface
;
920 IEnumSTATSTGImpl
*propertyEnumeration
;
921 StgProperty currentProperty
;
922 StgProperty newProperty
;
923 ULONG foundPropertyIndex
;
924 ULONG newPropertyIndex
;
927 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
928 iface
, debugstr_w(pwcsName
), grfMode
,
929 reserved1
, reserved2
, ppstg
);
932 * Validate parameters
935 return STG_E_INVALIDPOINTER
;
938 return STG_E_INVALIDNAME
;
941 * Validate the STGM flags
943 if ( FAILED( validateSTGM(grfMode
) ) ||
944 (grfMode
& STGM_DELETEONRELEASE
) )
945 return STG_E_INVALIDFLAG
;
948 * Initialize the out parameter
953 * Create a property enumeration and search the properties
955 propertyEnumeration
= IEnumSTATSTGImpl_Construct( This
->ancestorStorage
,
956 This
->rootPropertySetIndex
);
958 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
961 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
963 if (foundPropertyIndex
!= PROPERTY_NULL
)
966 * An element with this name already exists
968 if (grfMode
& STGM_CREATE
)
969 IStorage_DestroyElement(iface
, pwcsName
);
971 return STG_E_FILEALREADYEXISTS
;
975 * memset the empty property
977 memset(&newProperty
, 0, sizeof(StgProperty
));
979 newProperty
.sizeOfNameString
= (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
);
981 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
982 return STG_E_INVALIDNAME
;
984 lstrcpyW(newProperty
.name
, pwcsName
);
986 newProperty
.propertyType
= PROPTYPE_STORAGE
;
987 newProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
988 newProperty
.size
.s
.LowPart
= 0;
989 newProperty
.size
.s
.HighPart
= 0;
991 newProperty
.previousProperty
= PROPERTY_NULL
;
992 newProperty
.nextProperty
= PROPERTY_NULL
;
993 newProperty
.dirProperty
= PROPERTY_NULL
;
995 /* call CoFileTime to get the current time
996 newProperty.timeStampS1
997 newProperty.timeStampD1
998 newProperty.timeStampS2
999 newProperty.timeStampD2
1002 /* newStorageProperty.propertyUniqueID */
1005 * Obtain a free property in the property chain
1007 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
1010 * Save the new property into the new property spot
1012 StorageImpl_WriteProperty(
1013 This
->ancestorStorage
,
1018 * Find a spot in the property chain for our newly created property.
1020 updatePropertyChain(
1026 * Open it to get a pointer to return.
1028 hr
= IStorage_OpenStorage(
1037 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1047 /***************************************************************************
1051 * Get a free property or create a new one.
1053 static ULONG
getFreeProperty(
1054 StorageImpl
*storage
)
1056 ULONG currentPropertyIndex
= 0;
1057 ULONG newPropertyIndex
= PROPERTY_NULL
;
1058 BOOL readSucessful
= TRUE
;
1059 StgProperty currentProperty
;
1064 * Start by reading the root property
1066 readSucessful
= StorageImpl_ReadProperty(storage
->ancestorStorage
,
1067 currentPropertyIndex
,
1071 if (currentProperty
.sizeOfNameString
== 0)
1074 * The property existis and is available, we found it.
1076 newPropertyIndex
= currentPropertyIndex
;
1082 * We exhausted the property list, we will create more space below
1084 newPropertyIndex
= currentPropertyIndex
;
1086 currentPropertyIndex
++;
1088 } while (newPropertyIndex
== PROPERTY_NULL
);
1091 * grow the property chain
1093 if (! readSucessful
)
1095 StgProperty emptyProperty
;
1096 ULARGE_INTEGER newSize
;
1097 ULONG propertyIndex
;
1098 ULONG lastProperty
= 0;
1099 ULONG blockCount
= 0;
1102 * obtain the new count of property blocks
1104 blockCount
= BlockChainStream_GetCount(
1105 storage
->ancestorStorage
->rootBlockChain
)+1;
1108 * initialize the size used by the property stream
1110 newSize
.s
.HighPart
= 0;
1111 newSize
.s
.LowPart
= storage
->bigBlockSize
* blockCount
;
1114 * add a property block to the property chain
1116 BlockChainStream_SetSize(storage
->ancestorStorage
->rootBlockChain
, newSize
);
1119 * memset the empty property in order to initialize the unused newly
1122 memset(&emptyProperty
, 0, sizeof(StgProperty
));
1127 lastProperty
= storage
->bigBlockSize
/ PROPSET_BLOCK_SIZE
* blockCount
;
1130 propertyIndex
= newPropertyIndex
;
1131 propertyIndex
< lastProperty
;
1134 StorageImpl_WriteProperty(
1135 storage
->ancestorStorage
,
1141 return newPropertyIndex
;
1144 /****************************************************************************
1148 * Case insensitive comparaison of StgProperty.name by first considering
1151 * Returns <0 when newPrpoerty < currentProperty
1152 * >0 when newPrpoerty > currentProperty
1153 * 0 when newPrpoerty == currentProperty
1155 static LONG
propertyNameCmp(
1156 OLECHAR
*newProperty
,
1157 OLECHAR
*currentProperty
)
1159 LONG diff
= lstrlenW(newProperty
) - lstrlenW(currentProperty
);
1164 * We compare the string themselves only when they are of the same lenght
1166 diff
= lstrcmpiW( newProperty
, currentProperty
);
1172 /****************************************************************************
1176 * Properly link this new element in the property chain.
1178 static void updatePropertyChain(
1179 StorageImpl
*storage
,
1180 ULONG newPropertyIndex
,
1181 StgProperty newProperty
)
1183 StgProperty currentProperty
;
1186 * Read the root property
1188 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1189 storage
->rootPropertySetIndex
,
1192 if (currentProperty
.dirProperty
!= PROPERTY_NULL
)
1195 * The root storage contains some element, therefore, start the research
1196 * for the appropriate location.
1199 ULONG current
, next
, previous
, currentPropertyId
;
1202 * Keep the StgProperty sequence number of the storage first property
1204 currentPropertyId
= currentProperty
.dirProperty
;
1209 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1210 currentProperty
.dirProperty
,
1213 previous
= currentProperty
.previousProperty
;
1214 next
= currentProperty
.nextProperty
;
1215 current
= currentPropertyId
;
1219 LONG diff
= propertyNameCmp( newProperty
.name
, currentProperty
.name
);
1223 if (previous
!= PROPERTY_NULL
)
1225 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1232 currentProperty
.previousProperty
= newPropertyIndex
;
1233 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1241 if (next
!= PROPERTY_NULL
)
1243 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1250 currentProperty
.nextProperty
= newPropertyIndex
;
1251 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1260 * Trying to insert an item with the same name in the
1261 * subtree structure.
1266 previous
= currentProperty
.previousProperty
;
1267 next
= currentProperty
.nextProperty
;
1273 * The root storage is empty, link the new property to it's dir property
1275 currentProperty
.dirProperty
= newPropertyIndex
;
1276 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1277 storage
->rootPropertySetIndex
,
1283 /*************************************************************************
1286 HRESULT WINAPI
StorageImpl_CopyTo(
1288 DWORD ciidExclude
, /* [in] */
1289 const IID
* rgiidExclude
, /* [size_is][unique][in] */
1290 SNB snbExclude
, /* [unique][in] */
1291 IStorage
* pstgDest
) /* [unique][in] */
1293 IEnumSTATSTG
*elements
= 0;
1294 STATSTG curElement
, strStat
;
1296 IStorage
*pstgTmp
, *pstgChild
;
1297 IStream
*pstrTmp
, *pstrChild
;
1299 if ((ciidExclude
!= 0) || (rgiidExclude
!= NULL
) || (snbExclude
!= NULL
))
1300 FIXME("Exclude option not implemented\n");
1302 TRACE("(%p, %ld, %p, %p, %p)\n",
1303 iface
, ciidExclude
, rgiidExclude
,
1304 snbExclude
, pstgDest
);
1307 * Perform a sanity check
1309 if ( pstgDest
== 0 )
1310 return STG_E_INVALIDPOINTER
;
1313 * Enumerate the elements
1315 hr
= IStorage_EnumElements( iface
, 0, 0, 0, &elements
);
1323 IStorage_Stat( iface
, &curElement
, STATFLAG_NONAME
);
1324 IStorage_SetClass( pstgDest
, &curElement
.clsid
);
1329 * Obtain the next element
1331 hr
= IEnumSTATSTG_Next( elements
, 1, &curElement
, NULL
);
1333 if ( hr
== S_FALSE
)
1335 hr
= S_OK
; /* done, every element has been copied */
1339 if (curElement
.type
== STGTY_STORAGE
)
1342 * open child source storage
1344 hr
= IStorage_OpenStorage( iface
, curElement
.pwcsName
, NULL
,
1345 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1346 NULL
, 0, &pstgChild
);
1352 * Check if destination storage is not a child of the source
1353 * storage, which will cause an infinite loop
1355 if (pstgChild
== pstgDest
)
1357 IEnumSTATSTG_Release(elements
);
1359 return STG_E_ACCESSDENIED
;
1363 * create a new storage in destination storage
1365 hr
= IStorage_CreateStorage( pstgDest
, curElement
.pwcsName
,
1366 STGM_FAILIFTHERE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1370 * if it already exist, don't create a new one use this one
1372 if (hr
== STG_E_FILEALREADYEXISTS
)
1374 hr
= IStorage_OpenStorage( pstgDest
, curElement
.pwcsName
, NULL
,
1375 STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1376 NULL
, 0, &pstgTmp
);
1384 * do the copy recursively
1386 hr
= IStorage_CopyTo( pstgChild
, ciidExclude
, rgiidExclude
,
1387 snbExclude
, pstgTmp
);
1389 IStorage_Release( pstgTmp
);
1390 IStorage_Release( pstgChild
);
1392 else if (curElement
.type
== STGTY_STREAM
)
1395 * create a new stream in destination storage. If the stream already
1396 * exist, it will be deleted and a new one will be created.
1398 hr
= IStorage_CreateStream( pstgDest
, curElement
.pwcsName
,
1399 STGM_CREATE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1406 * open child stream storage
1408 hr
= IStorage_OpenStream( iface
, curElement
.pwcsName
, NULL
,
1409 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1416 * Get the size of the source stream
1418 IStream_Stat( pstrChild
, &strStat
, STATFLAG_NONAME
);
1421 * Set the size of the destination stream.
1423 IStream_SetSize(pstrTmp
, strStat
.cbSize
);
1428 hr
= IStream_CopyTo( pstrChild
, pstrTmp
, strStat
.cbSize
,
1431 IStream_Release( pstrTmp
);
1432 IStream_Release( pstrChild
);
1436 WARN("unknown element type: %ld\n", curElement
.type
);
1439 } while (hr
== S_OK
);
1444 IEnumSTATSTG_Release(elements
);
1449 /*************************************************************************
1450 * MoveElementTo (IStorage)
1452 HRESULT WINAPI
StorageImpl_MoveElementTo(
1454 const OLECHAR
*pwcsName
, /* [string][in] */
1455 IStorage
*pstgDest
, /* [unique][in] */
1456 const OLECHAR
*pwcsNewName
,/* [string][in] */
1457 DWORD grfFlags
) /* [in] */
1459 FIXME("not implemented!\n");
1463 /*************************************************************************
1466 HRESULT WINAPI
StorageImpl_Commit(
1468 DWORD grfCommitFlags
)/* [in] */
1470 FIXME("(%ld): stub!\n", grfCommitFlags
);
1474 /*************************************************************************
1477 HRESULT WINAPI
StorageImpl_Revert(
1480 FIXME("not implemented!\n");
1484 /*************************************************************************
1485 * DestroyElement (IStorage)
1487 * Stategy: This implementation is build this way for simplicity not for speed.
1488 * I always delete the top most element of the enumeration and adjust
1489 * the deleted element pointer all the time. This takes longer to
1490 * do but allow to reinvoke DestroyElement whenever we encounter a
1491 * storage object. The optimisation reside in the usage of another
1492 * enumeration stategy that would give all the leaves of a storage
1493 * first. (postfix order)
1495 HRESULT WINAPI
StorageImpl_DestroyElement(
1497 const OLECHAR
*pwcsName
)/* [string][in] */
1499 StorageImpl
* const This
=(StorageImpl
*)iface
;
1501 IEnumSTATSTGImpl
* propertyEnumeration
;
1504 StgProperty propertyToDelete
;
1505 StgProperty parentProperty
;
1506 ULONG foundPropertyIndexToDelete
;
1507 ULONG typeOfRelation
;
1508 ULONG parentPropertyId
;
1511 iface
, debugstr_w(pwcsName
));
1514 * Perform a sanity check on the parameters.
1517 return STG_E_INVALIDPOINTER
;
1520 * Create a property enumeration to search the property with the given name
1522 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
1523 This
->ancestorStorage
,
1524 This
->rootPropertySetIndex
);
1526 foundPropertyIndexToDelete
= IEnumSTATSTGImpl_FindProperty(
1527 propertyEnumeration
,
1531 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1533 if ( foundPropertyIndexToDelete
== PROPERTY_NULL
)
1535 return STG_E_FILENOTFOUND
;
1539 * Find the parent property of the property to delete (the one that
1540 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1541 * the parent is This. Otherwise, the parent is one of it's sibling...
1545 * First, read This's StgProperty..
1547 res
= StorageImpl_ReadProperty(
1548 This
->ancestorStorage
,
1549 This
->rootPropertySetIndex
,
1555 * Second, check to see if by any chance the actual storage (This) is not
1556 * the parent of the property to delete... We never know...
1558 if ( parentProperty
.dirProperty
== foundPropertyIndexToDelete
)
1561 * Set data as it would have been done in the else part...
1563 typeOfRelation
= PROPERTY_RELATION_DIR
;
1564 parentPropertyId
= This
->rootPropertySetIndex
;
1569 * Create a property enumeration to search the parent properties, and
1570 * delete it once done.
1572 IEnumSTATSTGImpl
* propertyEnumeration2
;
1574 propertyEnumeration2
= IEnumSTATSTGImpl_Construct(
1575 This
->ancestorStorage
,
1576 This
->rootPropertySetIndex
);
1578 typeOfRelation
= IEnumSTATSTGImpl_FindParentProperty(
1579 propertyEnumeration2
,
1580 foundPropertyIndexToDelete
,
1584 IEnumSTATSTGImpl_Destroy(propertyEnumeration2
);
1587 if ( propertyToDelete
.propertyType
== PROPTYPE_STORAGE
)
1589 hr
= deleteStorageProperty(
1591 propertyToDelete
.name
);
1593 else if ( propertyToDelete
.propertyType
== PROPTYPE_STREAM
)
1595 hr
= deleteStreamProperty(
1597 foundPropertyIndexToDelete
,
1605 * Adjust the property chain
1607 hr
= adjustPropertyChain(
1618 /*********************************************************************
1622 * Perform the deletion of a complete storage node
1625 static HRESULT
deleteStorageProperty(
1626 StorageImpl
*parentStorage
,
1627 OLECHAR
*propertyToDeleteName
)
1629 IEnumSTATSTG
*elements
= 0;
1630 IStorage
*childStorage
= 0;
1631 STATSTG currentElement
;
1633 HRESULT destroyHr
= S_OK
;
1636 * Open the storage and enumerate it
1638 hr
= StorageBaseImpl_OpenStorage(
1639 (IStorage
*)parentStorage
,
1640 propertyToDeleteName
,
1642 STGM_SHARE_EXCLUSIVE
,
1653 * Enumerate the elements
1655 IStorage_EnumElements( childStorage
, 0, 0, 0, &elements
);
1660 * Obtain the next element
1662 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1665 destroyHr
= StorageImpl_DestroyElement(
1666 (IStorage
*)childStorage
,
1667 (OLECHAR
*)currentElement
.pwcsName
);
1669 CoTaskMemFree(currentElement
.pwcsName
);
1673 * We need to Reset the enumeration every time because we delete elements
1674 * and the enumeration could be invalid
1676 IEnumSTATSTG_Reset(elements
);
1678 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1680 IStorage_Release(childStorage
);
1681 IEnumSTATSTG_Release(elements
);
1686 /*********************************************************************
1690 * Perform the deletion of a stream node
1693 static HRESULT
deleteStreamProperty(
1694 StorageImpl
*parentStorage
,
1695 ULONG indexOfPropertyToDelete
,
1696 StgProperty propertyToDelete
)
1700 ULARGE_INTEGER size
;
1702 size
.s
.HighPart
= 0;
1705 hr
= StorageBaseImpl_OpenStream(
1706 (IStorage
*)parentStorage
,
1707 (OLECHAR
*)propertyToDelete
.name
,
1709 STGM_SHARE_EXCLUSIVE
,
1721 hr
= IStream_SetSize(pis
, size
);
1729 * Release the stream object.
1731 IStream_Release(pis
);
1734 * Invalidate the property by zeroing it's name member.
1736 propertyToDelete
.sizeOfNameString
= 0;
1739 * Here we should re-read the property so we get the updated pointer
1740 * but since we are here to zap it, I don't do it...
1742 StorageImpl_WriteProperty(
1743 parentStorage
->ancestorStorage
,
1744 indexOfPropertyToDelete
,
1750 /*********************************************************************
1754 * Finds a placeholder for the StgProperty within the Storage
1757 static HRESULT
findPlaceholder(
1758 StorageImpl
*storage
,
1759 ULONG propertyIndexToStore
,
1760 ULONG storePropertyIndex
,
1763 StgProperty storeProperty
;
1768 * Read the storage property
1770 res
= StorageImpl_ReadProperty(
1771 storage
->ancestorStorage
,
1780 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1782 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1784 return findPlaceholder(
1786 propertyIndexToStore
,
1787 storeProperty
.previousProperty
,
1792 storeProperty
.previousProperty
= propertyIndexToStore
;
1795 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1797 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1799 return findPlaceholder(
1801 propertyIndexToStore
,
1802 storeProperty
.nextProperty
,
1807 storeProperty
.nextProperty
= propertyIndexToStore
;
1810 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1812 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1814 return findPlaceholder(
1816 propertyIndexToStore
,
1817 storeProperty
.dirProperty
,
1822 storeProperty
.dirProperty
= propertyIndexToStore
;
1826 hr
= StorageImpl_WriteProperty(
1827 storage
->ancestorStorage
,
1839 /*************************************************************************
1843 * This method takes the previous and the next property link of a property
1844 * to be deleted and find them a place in the Storage.
1846 static HRESULT
adjustPropertyChain(
1848 StgProperty propertyToDelete
,
1849 StgProperty parentProperty
,
1850 ULONG parentPropertyId
,
1853 ULONG newLinkProperty
= PROPERTY_NULL
;
1854 BOOL needToFindAPlaceholder
= FALSE
;
1855 ULONG storeNode
= PROPERTY_NULL
;
1856 ULONG toStoreNode
= PROPERTY_NULL
;
1857 INT relationType
= 0;
1861 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1863 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1866 * Set the parent previous to the property to delete previous
1868 newLinkProperty
= propertyToDelete
.previousProperty
;
1870 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1873 * We also need to find a storage for the other link, setup variables
1874 * to do this at the end...
1876 needToFindAPlaceholder
= TRUE
;
1877 storeNode
= propertyToDelete
.previousProperty
;
1878 toStoreNode
= propertyToDelete
.nextProperty
;
1879 relationType
= PROPERTY_RELATION_NEXT
;
1882 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1885 * Set the parent previous to the property to delete next
1887 newLinkProperty
= propertyToDelete
.nextProperty
;
1891 * Link it for real...
1893 parentProperty
.previousProperty
= newLinkProperty
;
1896 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1898 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1901 * Set the parent next to the property to delete next previous
1903 newLinkProperty
= propertyToDelete
.previousProperty
;
1905 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1908 * We also need to find a storage for the other link, setup variables
1909 * to do this at the end...
1911 needToFindAPlaceholder
= TRUE
;
1912 storeNode
= propertyToDelete
.previousProperty
;
1913 toStoreNode
= propertyToDelete
.nextProperty
;
1914 relationType
= PROPERTY_RELATION_NEXT
;
1917 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1920 * Set the parent next to the property to delete next
1922 newLinkProperty
= propertyToDelete
.nextProperty
;
1926 * Link it for real...
1928 parentProperty
.nextProperty
= newLinkProperty
;
1930 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1932 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1935 * Set the parent dir to the property to delete previous
1937 newLinkProperty
= propertyToDelete
.previousProperty
;
1939 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1942 * We also need to find a storage for the other link, setup variables
1943 * to do this at the end...
1945 needToFindAPlaceholder
= TRUE
;
1946 storeNode
= propertyToDelete
.previousProperty
;
1947 toStoreNode
= propertyToDelete
.nextProperty
;
1948 relationType
= PROPERTY_RELATION_NEXT
;
1951 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1954 * Set the parent dir to the property to delete next
1956 newLinkProperty
= propertyToDelete
.nextProperty
;
1960 * Link it for real...
1962 parentProperty
.dirProperty
= newLinkProperty
;
1966 * Write back the parent property
1968 res
= StorageImpl_WriteProperty(
1969 This
->ancestorStorage
,
1978 * If a placeholder is required for the other link, then, find one and
1979 * get out of here...
1981 if (needToFindAPlaceholder
)
1983 hr
= findPlaceholder(
1994 /******************************************************************************
1995 * SetElementTimes (IStorage)
1997 HRESULT WINAPI
StorageImpl_SetElementTimes(
1999 const OLECHAR
*pwcsName
,/* [string][in] */
2000 const FILETIME
*pctime
, /* [in] */
2001 const FILETIME
*patime
, /* [in] */
2002 const FILETIME
*pmtime
) /* [in] */
2004 FIXME("not implemented!\n");
2008 /******************************************************************************
2009 * SetStateBits (IStorage)
2011 HRESULT WINAPI
StorageImpl_SetStateBits(
2013 DWORD grfStateBits
,/* [in] */
2014 DWORD grfMask
) /* [in] */
2016 FIXME("not implemented!\n");
2020 HRESULT
StorageImpl_Construct(
2028 StgProperty currentProperty
;
2030 ULONG currentPropertyIndex
;
2032 if ( FAILED( validateSTGM(openFlags
) ))
2033 return STG_E_INVALIDFLAG
;
2035 memset(This
, 0, sizeof(StorageImpl
));
2038 * Initialize the virtual fgunction table.
2040 ICOM_VTBL(This
) = &Storage32Impl_Vtbl
;
2041 This
->v_destructor
= &StorageImpl_Destroy
;
2044 * This is the top-level storage so initialize the ancester pointer
2047 This
->ancestorStorage
= This
;
2050 * Initialize the physical support of the storage.
2052 This
->hFile
= hFile
;
2055 * Initialize the big block cache.
2057 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
2058 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
2059 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
,
2065 if (This
->bigBlockFile
== 0)
2068 if (openFlags
& STGM_CREATE
)
2070 ULARGE_INTEGER size
;
2071 BYTE
* bigBlockBuffer
;
2074 * Initialize all header variables:
2075 * - The big block depot consists of one block and it is at block 0
2076 * - The properties start at block 1
2077 * - There is no small block depot
2079 memset( This
->bigBlockDepotStart
,
2081 sizeof(This
->bigBlockDepotStart
));
2083 This
->bigBlockDepotCount
= 1;
2084 This
->bigBlockDepotStart
[0] = 0;
2085 This
->rootStartBlock
= 1;
2086 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2087 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
2088 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
2089 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2090 This
->extBigBlockDepotCount
= 0;
2092 StorageImpl_SaveFileHeader(This
);
2095 * Add one block for the big block depot and one block for the properties
2097 size
.s
.HighPart
= 0;
2098 size
.s
.LowPart
= This
->bigBlockSize
* 3;
2099 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
2102 * Initialize the big block depot
2104 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, 0);
2105 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2106 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
2107 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
2108 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2113 * Load the header for the file.
2115 hr
= StorageImpl_LoadFileHeader(This
);
2119 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2126 * There is no block depot cached yet.
2128 This
->indexBlockDepotCached
= 0xFFFFFFFF;
2131 * Start searching for free blocks with block 0.
2133 This
->prevFreeBlock
= 0;
2136 * Create the block chain abstractions.
2138 This
->rootBlockChain
=
2139 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
2141 This
->smallBlockDepotChain
= BlockChainStream_Construct(
2143 &This
->smallBlockDepotStart
,
2147 * Write the root property
2149 if (openFlags
& STGM_CREATE
)
2151 StgProperty rootProp
;
2153 * Initialize the property chain
2155 memset(&rootProp
, 0, sizeof(rootProp
));
2156 lstrcpyAtoW(rootProp
.name
, rootPropertyName
);
2158 rootProp
.sizeOfNameString
= (lstrlenW(rootProp
.name
)+1) * sizeof(WCHAR
);
2159 rootProp
.propertyType
= PROPTYPE_ROOT
;
2160 rootProp
.previousProperty
= PROPERTY_NULL
;
2161 rootProp
.nextProperty
= PROPERTY_NULL
;
2162 rootProp
.dirProperty
= PROPERTY_NULL
;
2163 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
2164 rootProp
.size
.s
.HighPart
= 0;
2165 rootProp
.size
.s
.LowPart
= 0;
2167 StorageImpl_WriteProperty(This
, 0, &rootProp
);
2171 * Find the ID of the root int he property sets.
2173 currentPropertyIndex
= 0;
2177 readSucessful
= StorageImpl_ReadProperty(
2179 currentPropertyIndex
,
2184 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
2185 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
2187 This
->rootPropertySetIndex
= currentPropertyIndex
;
2191 currentPropertyIndex
++;
2193 } while (readSucessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
2202 * Create the block chain abstraction for the small block root chain.
2204 This
->smallBlockRootChain
= BlockChainStream_Construct(
2207 This
->rootPropertySetIndex
);
2212 void StorageImpl_Destroy(
2215 TRACE("(%p)\n", This
);
2217 BlockChainStream_Destroy(This
->smallBlockRootChain
);
2218 BlockChainStream_Destroy(This
->rootBlockChain
);
2219 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
2221 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2225 /******************************************************************************
2226 * Storage32Impl_GetNextFreeBigBlock
2228 * Returns the index of the next free big block.
2229 * If the big block depot is filled, this method will enlarge it.
2232 ULONG
StorageImpl_GetNextFreeBigBlock(
2235 ULONG depotBlockIndexPos
;
2237 ULONG depotBlockOffset
;
2238 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
2239 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2241 ULONG freeBlock
= BLOCK_UNUSED
;
2243 depotIndex
= This
->prevFreeBlock
/ blocksPerDepot
;
2244 depotBlockOffset
= (This
->prevFreeBlock
% blocksPerDepot
) * sizeof(ULONG
);
2247 * Scan the entire big block depot until we find a block marked free
2249 while (nextBlockIndex
!= BLOCK_UNUSED
)
2251 if (depotIndex
< COUNT_BBDEPOTINHEADER
)
2253 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2256 * Grow the primary depot.
2258 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2260 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2263 * Add a block depot.
2265 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2266 This
->bigBlockDepotCount
++;
2267 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2270 * Flag it as a block depot.
2272 StorageImpl_SetNextBlockInChain(This
,
2276 /* Save new header information.
2278 StorageImpl_SaveFileHeader(This
);
2283 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotIndex
);
2285 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2288 * Grow the extended depot.
2290 ULONG extIndex
= BLOCK_UNUSED
;
2291 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2292 ULONG extBlockOffset
= numExtBlocks
% (blocksPerDepot
- 1);
2294 if (extBlockOffset
== 0)
2296 /* We need an extended block.
2298 extIndex
= Storage32Impl_AddExtBlockDepot(This
);
2299 This
->extBigBlockDepotCount
++;
2300 depotBlockIndexPos
= extIndex
+ 1;
2303 depotBlockIndexPos
= depotIndex
* blocksPerDepot
;
2306 * Add a block depot and mark it in the extended block.
2308 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2309 This
->bigBlockDepotCount
++;
2310 Storage32Impl_SetExtDepotBlock(This
, depotIndex
, depotBlockIndexPos
);
2312 /* Flag the block depot.
2314 StorageImpl_SetNextBlockInChain(This
,
2318 /* If necessary, flag the extended depot block.
2320 if (extIndex
!= BLOCK_UNUSED
)
2321 StorageImpl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2323 /* Save header information.
2325 StorageImpl_SaveFileHeader(This
);
2329 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2331 if (depotBuffer
!= 0)
2333 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2334 ( nextBlockIndex
!= BLOCK_UNUSED
))
2336 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2338 if (nextBlockIndex
== BLOCK_UNUSED
)
2340 freeBlock
= (depotIndex
* blocksPerDepot
) +
2341 (depotBlockOffset
/sizeof(ULONG
));
2344 depotBlockOffset
+= sizeof(ULONG
);
2347 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2351 depotBlockOffset
= 0;
2354 This
->prevFreeBlock
= freeBlock
;
2359 /******************************************************************************
2360 * Storage32Impl_AddBlockDepot
2362 * This will create a depot block, essentially it is a block initialized
2365 void Storage32Impl_AddBlockDepot(StorageImpl
* This
, ULONG blockIndex
)
2369 blockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2372 * Initialize blocks as free
2374 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2376 StorageImpl_ReleaseBigBlock(This
, blockBuffer
);
2379 /******************************************************************************
2380 * Storage32Impl_GetExtDepotBlock
2382 * Returns the index of the block that corresponds to the specified depot
2383 * index. This method is only for depot indexes equal or greater than
2384 * COUNT_BBDEPOTINHEADER.
2386 ULONG
Storage32Impl_GetExtDepotBlock(StorageImpl
* This
, ULONG depotIndex
)
2388 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2389 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2390 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2391 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2392 ULONG blockIndex
= BLOCK_UNUSED
;
2393 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2395 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2397 if (This
->extBigBlockDepotStart
== BLOCK_END_OF_CHAIN
)
2398 return BLOCK_UNUSED
;
2400 while (extBlockCount
> 0)
2402 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2406 if (extBlockIndex
!= BLOCK_UNUSED
)
2410 depotBuffer
= StorageImpl_GetROBigBlock(This
, extBlockIndex
);
2412 if (depotBuffer
!= 0)
2414 StorageUtl_ReadDWord(depotBuffer
,
2415 extBlockOffset
* sizeof(ULONG
),
2418 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2425 /******************************************************************************
2426 * Storage32Impl_SetExtDepotBlock
2428 * Associates the specified block index to the specified depot index.
2429 * This method is only for depot indexes equal or greater than
2430 * COUNT_BBDEPOTINHEADER.
2432 void Storage32Impl_SetExtDepotBlock(StorageImpl
* This
,
2436 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2437 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2438 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2439 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2440 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2442 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2444 while (extBlockCount
> 0)
2446 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2450 if (extBlockIndex
!= BLOCK_UNUSED
)
2454 depotBuffer
= StorageImpl_GetBigBlock(This
, extBlockIndex
);
2456 if (depotBuffer
!= 0)
2458 StorageUtl_WriteDWord(depotBuffer
,
2459 extBlockOffset
* sizeof(ULONG
),
2462 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2467 /******************************************************************************
2468 * Storage32Impl_AddExtBlockDepot
2470 * Creates an extended depot block.
2472 ULONG
Storage32Impl_AddExtBlockDepot(StorageImpl
* This
)
2474 ULONG numExtBlocks
= This
->extBigBlockDepotCount
;
2475 ULONG nextExtBlock
= This
->extBigBlockDepotStart
;
2476 BYTE
* depotBuffer
= NULL
;
2477 ULONG index
= BLOCK_UNUSED
;
2478 ULONG nextBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2479 ULONG blocksPerDepotBlock
= This
->bigBlockSize
/ sizeof(ULONG
);
2480 ULONG depotBlocksPerExtBlock
= blocksPerDepotBlock
- 1;
2482 index
= (COUNT_BBDEPOTINHEADER
+ (numExtBlocks
* depotBlocksPerExtBlock
)) *
2483 blocksPerDepotBlock
;
2485 if ((numExtBlocks
== 0) && (nextExtBlock
== BLOCK_END_OF_CHAIN
))
2488 * The first extended block.
2490 This
->extBigBlockDepotStart
= index
;
2496 * Follow the chain to the last one.
2498 for (i
= 0; i
< (numExtBlocks
- 1); i
++)
2500 nextExtBlock
= Storage32Impl_GetNextExtendedBlock(This
, nextExtBlock
);
2504 * Add the new extended block to the chain.
2506 depotBuffer
= StorageImpl_GetBigBlock(This
, nextExtBlock
);
2507 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2508 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2512 * Initialize this block.
2514 depotBuffer
= StorageImpl_GetBigBlock(This
, index
);
2515 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2516 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2521 /******************************************************************************
2522 * Storage32Impl_FreeBigBlock
2524 * This method will flag the specified block as free in the big block depot.
2526 void StorageImpl_FreeBigBlock(
2530 StorageImpl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2532 if (blockIndex
< This
->prevFreeBlock
)
2533 This
->prevFreeBlock
= blockIndex
;
2536 /************************************************************************
2537 * Storage32Impl_GetNextBlockInChain
2539 * This method will retrieve the block index of the next big block in
2542 * Params: This - Pointer to the Storage object.
2543 * blockIndex - Index of the block to retrieve the chain
2546 * Returns: This method returns the index of the next block in the chain.
2547 * It will return the constants:
2548 * BLOCK_SPECIAL - If the block given was not part of a
2550 * BLOCK_END_OF_CHAIN - If the block given was the last in
2552 * BLOCK_UNUSED - If the block given was not past of a chain
2554 * BLOCK_EXTBBDEPOT - This block is part of the extended
2557 * See Windows documentation for more details on IStorage methods.
2559 ULONG
StorageImpl_GetNextBlockInChain(
2563 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2564 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2565 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2566 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2568 ULONG depotBlockIndexPos
;
2570 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2573 * Cache the currently accessed depot block.
2575 if (depotBlockCount
!= This
->indexBlockDepotCached
)
2577 This
->indexBlockDepotCached
= depotBlockCount
;
2579 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2581 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2586 * We have to look in the extended depot.
2588 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2591 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2597 for (index
= 0; index
< NUM_BLOCKS_PER_DEPOT_BLOCK
; index
++)
2599 StorageUtl_ReadDWord(depotBuffer
, index
*sizeof(ULONG
), &nextBlockIndex
);
2600 This
->blockDepotCached
[index
] = nextBlockIndex
;
2603 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2607 nextBlockIndex
= This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)];
2609 return nextBlockIndex
;
2612 /******************************************************************************
2613 * Storage32Impl_GetNextExtendedBlock
2615 * Given an extended block this method will return the next extended block.
2618 * The last ULONG of an extended block is the block index of the next
2619 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2623 * - The index of the next extended block
2624 * - BLOCK_UNUSED: there is no next extended block.
2625 * - Any other return values denotes failure.
2627 ULONG
Storage32Impl_GetNextExtendedBlock(StorageImpl
* This
, ULONG blockIndex
)
2629 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2630 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2633 depotBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2637 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2639 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2642 return nextBlockIndex
;
2645 /******************************************************************************
2646 * Storage32Impl_SetNextBlockInChain
2648 * This method will write the index of the specified block's next block
2649 * in the big block depot.
2651 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2654 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2655 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2656 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2659 void StorageImpl_SetNextBlockInChain(
2664 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2665 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2666 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2667 ULONG depotBlockIndexPos
;
2670 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2671 assert(blockIndex
!= nextBlock
);
2673 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2675 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2680 * We have to look in the extended depot.
2682 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2685 depotBuffer
= StorageImpl_GetBigBlock(This
, depotBlockIndexPos
);
2689 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2690 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2694 * Update the cached block depot, if necessary.
2696 if (depotBlockCount
== This
->indexBlockDepotCached
)
2698 This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)] = nextBlock
;
2702 /******************************************************************************
2703 * Storage32Impl_LoadFileHeader
2705 * This method will read in the file header, i.e. big block index -1.
2707 HRESULT
StorageImpl_LoadFileHeader(
2710 HRESULT hr
= STG_E_FILENOTFOUND
;
2711 void* headerBigBlock
= NULL
;
2715 * Get a pointer to the big block of data containing the header.
2717 headerBigBlock
= StorageImpl_GetROBigBlock(This
, -1);
2720 * Extract the information from the header.
2722 if (headerBigBlock
!=0)
2725 * Check for the "magic number" signature and return an error if it is not
2728 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2730 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2731 return STG_E_OLDFORMAT
;
2734 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2736 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2737 return STG_E_INVALIDHEADER
;
2740 StorageUtl_ReadWord(
2742 OFFSET_BIGBLOCKSIZEBITS
,
2743 &This
->bigBlockSizeBits
);
2745 StorageUtl_ReadWord(
2747 OFFSET_SMALLBLOCKSIZEBITS
,
2748 &This
->smallBlockSizeBits
);
2750 StorageUtl_ReadDWord(
2752 OFFSET_BBDEPOTCOUNT
,
2753 &This
->bigBlockDepotCount
);
2755 StorageUtl_ReadDWord(
2757 OFFSET_ROOTSTARTBLOCK
,
2758 &This
->rootStartBlock
);
2760 StorageUtl_ReadDWord(
2762 OFFSET_SBDEPOTSTART
,
2763 &This
->smallBlockDepotStart
);
2765 StorageUtl_ReadDWord(
2767 OFFSET_EXTBBDEPOTSTART
,
2768 &This
->extBigBlockDepotStart
);
2770 StorageUtl_ReadDWord(
2772 OFFSET_EXTBBDEPOTCOUNT
,
2773 &This
->extBigBlockDepotCount
);
2775 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2777 StorageUtl_ReadDWord(
2779 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2780 &(This
->bigBlockDepotStart
[index
]));
2784 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2788 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2789 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2793 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2794 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2798 * Right now, the code is making some assumptions about the size of the
2799 * blocks, just make sure they are what we're expecting.
2801 assert( (This
->bigBlockSize
==DEF_BIG_BLOCK_SIZE
) &&
2802 (This
->smallBlockSize
==DEF_SMALL_BLOCK_SIZE
));
2805 * Release the block.
2807 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2815 /******************************************************************************
2816 * Storage32Impl_SaveFileHeader
2818 * This method will save to the file the header, i.e. big block -1.
2820 void StorageImpl_SaveFileHeader(
2823 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2828 * Get a pointer to the big block of data containing the header.
2830 success
= StorageImpl_ReadBigBlock(This
, -1, headerBigBlock
);
2833 * If the block read failed, the file is probably new.
2838 * Initialize for all unknown fields.
2840 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
2843 * Initialize the magic number.
2845 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
2848 * And a bunch of things we don't know what they mean
2850 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
2851 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
2852 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
2853 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
2854 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
2858 * Write the information to the header.
2860 if (headerBigBlock
!=0)
2862 StorageUtl_WriteWord(
2864 OFFSET_BIGBLOCKSIZEBITS
,
2865 This
->bigBlockSizeBits
);
2867 StorageUtl_WriteWord(
2869 OFFSET_SMALLBLOCKSIZEBITS
,
2870 This
->smallBlockSizeBits
);
2872 StorageUtl_WriteDWord(
2874 OFFSET_BBDEPOTCOUNT
,
2875 This
->bigBlockDepotCount
);
2877 StorageUtl_WriteDWord(
2879 OFFSET_ROOTSTARTBLOCK
,
2880 This
->rootStartBlock
);
2882 StorageUtl_WriteDWord(
2884 OFFSET_SBDEPOTSTART
,
2885 This
->smallBlockDepotStart
);
2887 StorageUtl_WriteDWord(
2889 OFFSET_EXTBBDEPOTSTART
,
2890 This
->extBigBlockDepotStart
);
2892 StorageUtl_WriteDWord(
2894 OFFSET_EXTBBDEPOTCOUNT
,
2895 This
->extBigBlockDepotCount
);
2897 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2899 StorageUtl_WriteDWord(
2901 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2902 (This
->bigBlockDepotStart
[index
]));
2907 * Write the big block back to the file.
2909 StorageImpl_WriteBigBlock(This
, -1, headerBigBlock
);
2912 /******************************************************************************
2913 * Storage32Impl_ReadProperty
2915 * This method will read the specified property from the property chain.
2917 BOOL
StorageImpl_ReadProperty(
2920 StgProperty
* buffer
)
2922 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2923 ULARGE_INTEGER offsetInPropSet
;
2927 offsetInPropSet
.s
.HighPart
= 0;
2928 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
2930 readSucessful
= BlockChainStream_ReadAt(
2931 This
->rootBlockChain
,
2939 memset(buffer
->name
, 0, sizeof(buffer
->name
));
2942 currentProperty
+OFFSET_PS_NAME
,
2943 PROPERTY_NAME_BUFFER_LEN
);
2945 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
2947 StorageUtl_ReadWord(
2949 OFFSET_PS_NAMELENGTH
,
2950 &buffer
->sizeOfNameString
);
2952 StorageUtl_ReadDWord(
2954 OFFSET_PS_PREVIOUSPROP
,
2955 &buffer
->previousProperty
);
2957 StorageUtl_ReadDWord(
2960 &buffer
->nextProperty
);
2962 StorageUtl_ReadDWord(
2965 &buffer
->dirProperty
);
2967 StorageUtl_ReadGUID(
2970 &buffer
->propertyUniqueID
);
2972 StorageUtl_ReadDWord(
2975 &buffer
->timeStampS1
);
2977 StorageUtl_ReadDWord(
2980 &buffer
->timeStampD1
);
2982 StorageUtl_ReadDWord(
2985 &buffer
->timeStampS2
);
2987 StorageUtl_ReadDWord(
2990 &buffer
->timeStampD2
);
2992 StorageUtl_ReadDWord(
2994 OFFSET_PS_STARTBLOCK
,
2995 &buffer
->startingBlock
);
2997 StorageUtl_ReadDWord(
3000 &buffer
->size
.s
.LowPart
);
3002 buffer
->size
.s
.HighPart
= 0;
3005 return readSucessful
;
3008 /*********************************************************************
3009 * Write the specified property into the property chain
3011 BOOL
StorageImpl_WriteProperty(
3014 StgProperty
* buffer
)
3016 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3017 ULARGE_INTEGER offsetInPropSet
;
3018 BOOL writeSucessful
;
3021 offsetInPropSet
.s
.HighPart
= 0;
3022 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3024 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
3027 currentProperty
+ OFFSET_PS_NAME
,
3029 PROPERTY_NAME_BUFFER_LEN
);
3031 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
3034 * Reassign the size in case of mistake....
3036 buffer
->sizeOfNameString
= (lstrlenW(buffer
->name
)+1) * sizeof(WCHAR
);
3038 StorageUtl_WriteWord(
3040 OFFSET_PS_NAMELENGTH
,
3041 buffer
->sizeOfNameString
);
3043 StorageUtl_WriteDWord(
3045 OFFSET_PS_PREVIOUSPROP
,
3046 buffer
->previousProperty
);
3048 StorageUtl_WriteDWord(
3051 buffer
->nextProperty
);
3053 StorageUtl_WriteDWord(
3056 buffer
->dirProperty
);
3058 StorageUtl_WriteGUID(
3061 &buffer
->propertyUniqueID
);
3063 StorageUtl_WriteDWord(
3066 buffer
->timeStampS1
);
3068 StorageUtl_WriteDWord(
3071 buffer
->timeStampD1
);
3073 StorageUtl_WriteDWord(
3076 buffer
->timeStampS2
);
3078 StorageUtl_WriteDWord(
3081 buffer
->timeStampD2
);
3083 StorageUtl_WriteDWord(
3085 OFFSET_PS_STARTBLOCK
,
3086 buffer
->startingBlock
);
3088 StorageUtl_WriteDWord(
3091 buffer
->size
.s
.LowPart
);
3093 writeSucessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
3098 return writeSucessful
;
3101 BOOL
StorageImpl_ReadBigBlock(
3106 void* bigBlockBuffer
;
3108 bigBlockBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
3110 if (bigBlockBuffer
!=0)
3112 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
3114 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3122 BOOL
StorageImpl_WriteBigBlock(
3127 void* bigBlockBuffer
;
3129 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
3131 if (bigBlockBuffer
!=0)
3133 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
3135 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3143 void* StorageImpl_GetROBigBlock(
3147 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
3150 void* StorageImpl_GetBigBlock(
3154 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
3157 void StorageImpl_ReleaseBigBlock(
3161 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
3164 /******************************************************************************
3165 * Storage32Impl_SmallBlocksToBigBlocks
3167 * This method will convert a small block chain to a big block chain.
3168 * The small block chain will be destroyed.
3170 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
3172 SmallBlockChainStream
** ppsbChain
)
3174 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
3175 ULARGE_INTEGER size
, offset
;
3176 ULONG cbRead
, cbWritten
, cbTotalRead
, cbTotalWritten
;
3177 ULONG propertyIndex
;
3178 BOOL successRead
, successWrite
;
3179 StgProperty chainProperty
;
3181 BlockChainStream
*bbTempChain
= NULL
;
3182 BlockChainStream
*bigBlockChain
= NULL
;
3185 * Create a temporary big block chain that doesn't have
3186 * an associated property. This temporary chain will be
3187 * used to copy data from small blocks to big blocks.
3189 bbTempChain
= BlockChainStream_Construct(This
,
3194 * Grow the big block chain.
3196 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
3197 BlockChainStream_SetSize(bbTempChain
, size
);
3200 * Copy the contents of the small block chain to the big block chain
3201 * by small block size increments.
3203 offset
.s
.LowPart
= 0;
3204 offset
.s
.HighPart
= 0;
3208 buffer
= (BYTE
*) malloc(DEF_SMALL_BLOCK_SIZE
);
3211 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
3213 DEF_SMALL_BLOCK_SIZE
,
3216 cbTotalRead
+= cbRead
;
3218 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
3223 cbTotalWritten
+= cbWritten
;
3225 offset
.s
.LowPart
+= This
->smallBlockSize
;
3227 } while (successRead
&& successWrite
);
3230 assert(cbTotalRead
== cbTotalWritten
);
3233 * Destroy the small block chain.
3235 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
3236 size
.s
.HighPart
= 0;
3238 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
3239 SmallBlockChainStream_Destroy(*ppsbChain
);
3243 * Change the property information. This chain is now a big block chain
3244 * and it doesn't reside in the small blocks chain anymore.
3246 StorageImpl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3248 chainProperty
.startingBlock
= bbHeadOfChain
;
3250 StorageImpl_WriteProperty(This
, propertyIndex
, &chainProperty
);
3253 * Destroy the temporary propertyless big block chain.
3254 * Create a new big block chain associated with this property.
3256 BlockChainStream_Destroy(bbTempChain
);
3257 bigBlockChain
= BlockChainStream_Construct(This
,
3261 return bigBlockChain
;
3264 /******************************************************************************
3265 ** Storage32InternalImpl implementation
3268 StorageInternalImpl
* StorageInternalImpl_Construct(
3269 StorageImpl
* ancestorStorage
,
3270 ULONG rootPropertyIndex
)
3272 StorageInternalImpl
* newStorage
;
3275 * Allocate space for the new storage object
3277 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl
));
3281 memset(newStorage
, 0, sizeof(StorageInternalImpl
));
3284 * Initialize the virtual function table.
3286 ICOM_VTBL(newStorage
) = &Storage32InternalImpl_Vtbl
;
3287 newStorage
->v_destructor
= &StorageInternalImpl_Destroy
;
3290 * Keep the ancestor storage pointer and nail a reference to it.
3292 newStorage
->ancestorStorage
= ancestorStorage
;
3293 StorageBaseImpl_AddRef((IStorage
*)(newStorage
->ancestorStorage
));
3296 * Keep the index of the root property set for this storage,
3298 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3306 void StorageInternalImpl_Destroy(
3307 StorageInternalImpl
* This
)
3309 StorageBaseImpl_Release((IStorage
*)This
->ancestorStorage
);
3310 HeapFree(GetProcessHeap(), 0, This
);
3313 /******************************************************************************
3315 ** Storage32InternalImpl_Commit
3317 ** The non-root storages cannot be opened in transacted mode thus this function
3320 HRESULT WINAPI
StorageInternalImpl_Commit(
3322 DWORD grfCommitFlags
) /* [in] */
3327 /******************************************************************************
3329 ** Storage32InternalImpl_Revert
3331 ** The non-root storages cannot be opened in transacted mode thus this function
3334 HRESULT WINAPI
StorageInternalImpl_Revert(
3340 /******************************************************************************
3341 ** IEnumSTATSTGImpl implementation
3344 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3345 StorageImpl
* parentStorage
,
3346 ULONG firstPropertyNode
)
3348 IEnumSTATSTGImpl
* newEnumeration
;
3350 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3352 if (newEnumeration
!=0)
3355 * Set-up the virtual function table and reference count.
3357 ICOM_VTBL(newEnumeration
) = &IEnumSTATSTGImpl_Vtbl
;
3358 newEnumeration
->ref
= 0;
3361 * We want to nail-down the reference to the storage in case the
3362 * enumeration out-lives the storage in the client application.
3364 newEnumeration
->parentStorage
= parentStorage
;
3365 IStorage_AddRef((IStorage
*)newEnumeration
->parentStorage
);
3367 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3370 * Initialize the search stack
3372 newEnumeration
->stackSize
= 0;
3373 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3374 newEnumeration
->stackToVisit
=
3375 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3378 * Make sure the current node of the iterator is the first one.
3380 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3383 return newEnumeration
;
3386 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3388 IStorage_Release((IStorage
*)This
->parentStorage
);
3389 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3390 HeapFree(GetProcessHeap(), 0, This
);
3393 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3394 IEnumSTATSTG
* iface
,
3398 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3401 * Perform a sanity check on the parameters.
3404 return E_INVALIDARG
;
3407 * Initialize the return parameter.
3412 * Compare the riid with the interface IDs implemented by this object.
3414 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3416 *ppvObject
= (IEnumSTATSTG
*)This
;
3418 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3420 *ppvObject
= (IEnumSTATSTG
*)This
;
3424 * Check that we obtained an interface.
3426 if ((*ppvObject
)==0)
3427 return E_NOINTERFACE
;
3430 * Query Interface always increases the reference count by one when it is
3433 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3438 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3439 IEnumSTATSTG
* iface
)
3441 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3447 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3448 IEnumSTATSTG
* iface
)
3450 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3458 * If the reference count goes down to 0, perform suicide.
3462 IEnumSTATSTGImpl_Destroy(This
);
3468 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3469 IEnumSTATSTG
* iface
,
3472 ULONG
* pceltFetched
)
3474 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3476 StgProperty currentProperty
;
3477 STATSTG
* currentReturnStruct
= rgelt
;
3478 ULONG objectFetched
= 0;
3479 ULONG currentSearchNode
;
3482 * Perform a sanity check on the parameters.
3484 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3485 return E_INVALIDARG
;
3488 * To avoid the special case, get another pointer to a ULONG value if
3489 * the caller didn't supply one.
3491 if (pceltFetched
==0)
3492 pceltFetched
= &objectFetched
;
3495 * Start the iteration, we will iterate until we hit the end of the
3496 * linked list or until we hit the number of items to iterate through
3501 * Start with the node at the top of the stack.
3503 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3505 while ( ( *pceltFetched
< celt
) &&
3506 ( currentSearchNode
!=PROPERTY_NULL
) )
3509 * Remove the top node from the stack
3511 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3514 * Read the property from the storage.
3516 StorageImpl_ReadProperty(This
->parentStorage
,
3521 * Copy the information to the return buffer.
3523 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3528 * Step to the next item in the iteration
3531 currentReturnStruct
++;
3534 * Push the next search node in the search stack.
3536 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3539 * continue the iteration.
3541 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3544 if (*pceltFetched
== celt
)
3551 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3552 IEnumSTATSTG
* iface
,
3555 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3557 StgProperty currentProperty
;
3558 ULONG objectFetched
= 0;
3559 ULONG currentSearchNode
;
3562 * Start with the node at the top of the stack.
3564 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3566 while ( (objectFetched
< celt
) &&
3567 (currentSearchNode
!=PROPERTY_NULL
) )
3570 * Remove the top node from the stack
3572 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3575 * Read the property from the storage.
3577 StorageImpl_ReadProperty(This
->parentStorage
,
3582 * Step to the next item in the iteration
3587 * Push the next search node in the search stack.
3589 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3592 * continue the iteration.
3594 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3597 if (objectFetched
== celt
)
3603 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3604 IEnumSTATSTG
* iface
)
3606 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3608 StgProperty rootProperty
;
3612 * Re-initialize the search stack to an empty stack
3614 This
->stackSize
= 0;
3617 * Read the root property from the storage.
3619 readSucessful
= StorageImpl_ReadProperty(
3620 This
->parentStorage
,
3621 This
->firstPropertyNode
,
3626 assert(rootProperty
.sizeOfNameString
!=0);
3629 * Push the search node in the search stack.
3631 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3637 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3638 IEnumSTATSTG
* iface
,
3639 IEnumSTATSTG
** ppenum
)
3641 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3643 IEnumSTATSTGImpl
* newClone
;
3646 * Perform a sanity check on the parameters.
3649 return E_INVALIDARG
;
3651 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3652 This
->firstPropertyNode
);
3656 * The new clone enumeration must point to the same current node as
3659 newClone
->stackSize
= This
->stackSize
;
3660 newClone
->stackMaxSize
= This
->stackMaxSize
;
3661 newClone
->stackToVisit
=
3662 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3665 newClone
->stackToVisit
,
3667 sizeof(ULONG
) * newClone
->stackSize
);
3669 *ppenum
= (IEnumSTATSTG
*)newClone
;
3672 * Don't forget to nail down a reference to the clone before
3675 IEnumSTATSTGImpl_AddRef(*ppenum
);
3680 INT
IEnumSTATSTGImpl_FindParentProperty(
3681 IEnumSTATSTGImpl
*This
,
3682 ULONG childProperty
,
3683 StgProperty
*currentProperty
,
3686 ULONG currentSearchNode
;
3690 * To avoid the special case, get another pointer to a ULONG value if
3691 * the caller didn't supply one.
3694 thisNodeId
= &foundNode
;
3697 * Start with the node at the top of the stack.
3699 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3702 while (currentSearchNode
!=PROPERTY_NULL
)
3705 * Store the current node in the returned parameters
3707 *thisNodeId
= currentSearchNode
;
3710 * Remove the top node from the stack
3712 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3715 * Read the property from the storage.
3717 StorageImpl_ReadProperty(
3718 This
->parentStorage
,
3722 if (currentProperty
->previousProperty
== childProperty
)
3723 return PROPERTY_RELATION_PREVIOUS
;
3725 else if (currentProperty
->nextProperty
== childProperty
)
3726 return PROPERTY_RELATION_NEXT
;
3728 else if (currentProperty
->dirProperty
== childProperty
)
3729 return PROPERTY_RELATION_DIR
;
3732 * Push the next search node in the search stack.
3734 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3737 * continue the iteration.
3739 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3742 return PROPERTY_NULL
;
3745 ULONG
IEnumSTATSTGImpl_FindProperty(
3746 IEnumSTATSTGImpl
* This
,
3747 const OLECHAR
* lpszPropName
,
3748 StgProperty
* currentProperty
)
3750 ULONG currentSearchNode
;
3753 * Start with the node at the top of the stack.
3755 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3757 while (currentSearchNode
!=PROPERTY_NULL
)
3760 * Remove the top node from the stack
3762 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3765 * Read the property from the storage.
3767 StorageImpl_ReadProperty(This
->parentStorage
,
3771 if ( propertyNameCmp(
3772 (OLECHAR
*)currentProperty
->name
,
3773 (OLECHAR
*)lpszPropName
) == 0)
3774 return currentSearchNode
;
3777 * Push the next search node in the search stack.
3779 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3782 * continue the iteration.
3784 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3787 return PROPERTY_NULL
;
3790 void IEnumSTATSTGImpl_PushSearchNode(
3791 IEnumSTATSTGImpl
* This
,
3794 StgProperty rootProperty
;
3798 * First, make sure we're not trying to push an unexisting node.
3800 if (nodeToPush
==PROPERTY_NULL
)
3804 * First push the node to the stack
3806 if (This
->stackSize
== This
->stackMaxSize
)
3808 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3810 This
->stackToVisit
= HeapReAlloc(
3814 sizeof(ULONG
) * This
->stackMaxSize
);
3817 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3821 * Read the root property from the storage.
3823 readSucessful
= StorageImpl_ReadProperty(
3824 This
->parentStorage
,
3830 assert(rootProperty
.sizeOfNameString
!=0);
3833 * Push the previous search node in the search stack.
3835 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3839 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3840 IEnumSTATSTGImpl
* This
,
3845 if (This
->stackSize
== 0)
3846 return PROPERTY_NULL
;
3848 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3856 /******************************************************************************
3857 ** StorageUtl implementation
3860 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3862 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3865 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3867 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3870 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3872 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3875 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3877 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3880 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3882 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3883 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3884 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3886 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
3889 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
3891 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
3892 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
3893 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
3895 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
3898 void StorageUtl_CopyPropertyToSTATSTG(
3899 STATSTG
* destination
,
3900 StgProperty
* source
,
3904 * The copy of the string occurs only when the flag is not set
3906 if ((statFlags
& STATFLAG_NONAME
) != 0)
3908 destination
->pwcsName
= 0;
3912 destination
->pwcsName
=
3913 CoTaskMemAlloc((lstrlenW(source
->name
)+1)*sizeof(WCHAR
));
3915 lstrcpyW((LPWSTR
)destination
->pwcsName
, source
->name
);
3918 switch (source
->propertyType
)
3920 case PROPTYPE_STORAGE
:
3922 destination
->type
= STGTY_STORAGE
;
3924 case PROPTYPE_STREAM
:
3925 destination
->type
= STGTY_STREAM
;
3928 destination
->type
= STGTY_STREAM
;
3932 destination
->cbSize
= source
->size
;
3934 currentReturnStruct->mtime = {0}; TODO
3935 currentReturnStruct->ctime = {0};
3936 currentReturnStruct->atime = {0};
3938 destination
->grfMode
= 0;
3939 destination
->grfLocksSupported
= 0;
3940 destination
->clsid
= source
->propertyUniqueID
;
3941 destination
->grfStateBits
= 0;
3942 destination
->reserved
= 0;
3945 /******************************************************************************
3946 ** BlockChainStream implementation
3949 BlockChainStream
* BlockChainStream_Construct(
3950 StorageImpl
* parentStorage
,
3951 ULONG
* headOfStreamPlaceHolder
,
3952 ULONG propertyIndex
)
3954 BlockChainStream
* newStream
;
3957 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
3959 newStream
->parentStorage
= parentStorage
;
3960 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
3961 newStream
->ownerPropertyIndex
= propertyIndex
;
3962 newStream
->lastBlockNoInSequence
= 0xFFFFFFFF;
3963 newStream
->tailIndex
= BLOCK_END_OF_CHAIN
;
3964 newStream
->numBlocks
= 0;
3966 blockIndex
= BlockChainStream_GetHeadOfChain(newStream
);
3968 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
3970 newStream
->numBlocks
++;
3971 newStream
->tailIndex
= blockIndex
;
3973 blockIndex
= StorageImpl_GetNextBlockInChain(
3981 void BlockChainStream_Destroy(BlockChainStream
* This
)
3983 HeapFree(GetProcessHeap(), 0, This
);
3986 /******************************************************************************
3987 * BlockChainStream_GetHeadOfChain
3989 * Returns the head of this stream chain.
3990 * Some special chains don't have properties, their heads are kept in
3991 * This->headOfStreamPlaceHolder.
3994 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
3996 StgProperty chainProperty
;
3999 if (This
->headOfStreamPlaceHolder
!= 0)
4000 return *(This
->headOfStreamPlaceHolder
);
4002 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
4004 readSucessful
= StorageImpl_ReadProperty(
4005 This
->parentStorage
,
4006 This
->ownerPropertyIndex
,
4011 return chainProperty
.startingBlock
;
4015 return BLOCK_END_OF_CHAIN
;
4018 /******************************************************************************
4019 * BlockChainStream_GetCount
4021 * Returns the number of blocks that comprises this chain.
4022 * This is not the size of the stream as the last block may not be full!
4025 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
4030 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4032 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4036 blockIndex
= StorageImpl_GetNextBlockInChain(
4037 This
->parentStorage
,
4044 /******************************************************************************
4045 * BlockChainStream_ReadAt
4047 * Reads a specified number of bytes from this chain at the specified offset.
4048 * bytesRead may be NULL.
4049 * Failure will be returned if the specified number of bytes has not been read.
4051 BOOL
BlockChainStream_ReadAt(BlockChainStream
* This
,
4052 ULARGE_INTEGER offset
,
4057 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4058 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4059 ULONG bytesToReadInBuffer
;
4062 BYTE
* bigBlockBuffer
;
4065 * Find the first block in the stream that contains part of the buffer.
4067 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4068 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4069 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4071 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4072 This
->lastBlockNoInSequence
= blockNoInSequence
;
4076 ULONG temp
= blockNoInSequence
;
4078 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4079 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4080 This
->lastBlockNoInSequence
= temp
;
4083 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4086 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4088 blockNoInSequence
--;
4091 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4094 * Start reading the buffer.
4097 bufferWalker
= buffer
;
4099 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4102 * Calculate how many bytes we can copy from this big block.
4104 bytesToReadInBuffer
=
4105 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4108 * Copy those bytes to the buffer
4111 StorageImpl_GetROBigBlock(This
->parentStorage
, blockIndex
);
4113 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
4115 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4118 * Step to the next big block.
4121 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4123 bufferWalker
+= bytesToReadInBuffer
;
4124 size
-= bytesToReadInBuffer
;
4125 *bytesRead
+= bytesToReadInBuffer
;
4126 offsetInBlock
= 0; /* There is no offset on the next block */
4133 /******************************************************************************
4134 * BlockChainStream_WriteAt
4136 * Writes the specified number of bytes to this chain at the specified offset.
4137 * bytesWritten may be NULL.
4138 * Will fail if not all specified number of bytes have been written.
4140 BOOL
BlockChainStream_WriteAt(BlockChainStream
* This
,
4141 ULARGE_INTEGER offset
,
4144 ULONG
* bytesWritten
)
4146 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4147 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4151 BYTE
* bigBlockBuffer
;
4154 * Find the first block in the stream that contains part of the buffer.
4156 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4157 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4158 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4160 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4161 This
->lastBlockNoInSequence
= blockNoInSequence
;
4165 ULONG temp
= blockNoInSequence
;
4167 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4168 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4169 This
->lastBlockNoInSequence
= temp
;
4172 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4175 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4177 blockNoInSequence
--;
4180 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4183 * Here, I'm casting away the constness on the buffer variable
4184 * This is OK since we don't intend to modify that buffer.
4187 bufferWalker
= (BYTE
*)buffer
;
4189 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4192 * Calculate how many bytes we can copy from this big block.
4195 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4198 * Copy those bytes to the buffer
4200 bigBlockBuffer
= StorageImpl_GetBigBlock(This
->parentStorage
, blockIndex
);
4202 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
4204 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4207 * Step to the next big block.
4210 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4212 bufferWalker
+= bytesToWrite
;
4213 size
-= bytesToWrite
;
4214 *bytesWritten
+= bytesToWrite
;
4215 offsetInBlock
= 0; /* There is no offset on the next block */
4221 /******************************************************************************
4222 * BlockChainStream_Shrink
4224 * Shrinks this chain in the big block depot.
4226 BOOL
BlockChainStream_Shrink(BlockChainStream
* This
,
4227 ULARGE_INTEGER newSize
)
4229 ULONG blockIndex
, extraBlock
;
4234 * Reset the last accessed block cache.
4236 This
->lastBlockNoInSequence
= 0xFFFFFFFF;
4237 This
->lastBlockNoInSequenceIndex
= BLOCK_END_OF_CHAIN
;
4240 * Figure out how many blocks are needed to contain the new size
4242 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4244 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4247 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4250 * Go to the new end of chain
4252 while (count
< numBlocks
)
4255 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4260 /* Get the next block before marking the new end */
4262 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4264 /* Mark the new end of chain */
4265 StorageImpl_SetNextBlockInChain(
4266 This
->parentStorage
,
4268 BLOCK_END_OF_CHAIN
);
4270 This
->tailIndex
= blockIndex
;
4271 This
->numBlocks
= numBlocks
;
4274 * Mark the extra blocks as free
4276 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4279 StorageImpl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4281 StorageImpl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4282 extraBlock
= blockIndex
;
4288 /******************************************************************************
4289 * BlockChainStream_Enlarge
4291 * Grows this chain in the big block depot.
4293 BOOL
BlockChainStream_Enlarge(BlockChainStream
* This
,
4294 ULARGE_INTEGER newSize
)
4296 ULONG blockIndex
, currentBlock
;
4298 ULONG oldNumBlocks
= 0;
4300 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4303 * Empty chain. Create the head.
4305 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4307 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4308 StorageImpl_SetNextBlockInChain(This
->parentStorage
,
4310 BLOCK_END_OF_CHAIN
);
4312 if (This
->headOfStreamPlaceHolder
!= 0)
4314 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4318 StgProperty chainProp
;
4319 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4321 StorageImpl_ReadProperty(
4322 This
->parentStorage
,
4323 This
->ownerPropertyIndex
,
4326 chainProp
.startingBlock
= blockIndex
;
4328 StorageImpl_WriteProperty(
4329 This
->parentStorage
,
4330 This
->ownerPropertyIndex
,
4334 This
->tailIndex
= blockIndex
;
4335 This
->numBlocks
= 1;
4339 * Figure out how many blocks are needed to contain this stream
4341 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4343 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4347 * Go to the current end of chain
4349 if (This
->tailIndex
== BLOCK_END_OF_CHAIN
)
4351 currentBlock
= blockIndex
;
4353 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4356 currentBlock
= blockIndex
;
4359 StorageImpl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4362 This
->tailIndex
= currentBlock
;
4365 currentBlock
= This
->tailIndex
;
4366 oldNumBlocks
= This
->numBlocks
;
4369 * Add new blocks to the chain
4371 if (oldNumBlocks
< newNumBlocks
)
4373 while (oldNumBlocks
< newNumBlocks
)
4375 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4377 StorageImpl_SetNextBlockInChain(
4378 This
->parentStorage
,
4382 StorageImpl_SetNextBlockInChain(
4383 This
->parentStorage
,
4385 BLOCK_END_OF_CHAIN
);
4387 currentBlock
= blockIndex
;
4391 This
->tailIndex
= blockIndex
;
4392 This
->numBlocks
= newNumBlocks
;
4398 /******************************************************************************
4399 * BlockChainStream_SetSize
4401 * Sets the size of this stream. The big block depot will be updated.
4402 * The file will grow if we grow the chain.
4404 * TODO: Free the actual blocks in the file when we shrink the chain.
4405 * Currently, the blocks are still in the file. So the file size
4406 * doesn't shrink even if we shrink streams.
4408 BOOL
BlockChainStream_SetSize(
4409 BlockChainStream
* This
,
4410 ULARGE_INTEGER newSize
)
4412 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4414 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
4417 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
4419 BlockChainStream_Shrink(This
, newSize
);
4423 ULARGE_INTEGER fileSize
=
4424 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4426 ULONG diff
= newSize
.s
.LowPart
- size
.s
.LowPart
;
4429 * Make sure the file stays a multiple of blocksize
4431 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4432 diff
+= (This
->parentStorage
->bigBlockSize
-
4433 (diff
% This
->parentStorage
->bigBlockSize
) );
4435 fileSize
.s
.LowPart
+= diff
;
4436 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4438 BlockChainStream_Enlarge(This
, newSize
);
4444 /******************************************************************************
4445 * BlockChainStream_GetSize
4447 * Returns the size of this chain.
4448 * Will return the block count if this chain doesn't have a property.
4450 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4452 StgProperty chainProperty
;
4454 if(This
->headOfStreamPlaceHolder
== NULL
)
4457 * This chain is a data stream read the property and return
4458 * the appropriate size
4460 StorageImpl_ReadProperty(
4461 This
->parentStorage
,
4462 This
->ownerPropertyIndex
,
4465 return chainProperty
.size
;
4470 * this chain is a chain that does not have a property, figure out the
4471 * size by making the product number of used blocks times the
4474 ULARGE_INTEGER result
;
4475 result
.s
.HighPart
= 0;
4478 BlockChainStream_GetCount(This
) *
4479 This
->parentStorage
->bigBlockSize
;
4485 /******************************************************************************
4486 ** SmallBlockChainStream implementation
4489 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4490 StorageImpl
* parentStorage
,
4491 ULONG propertyIndex
)
4493 SmallBlockChainStream
* newStream
;
4495 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4497 newStream
->parentStorage
= parentStorage
;
4498 newStream
->ownerPropertyIndex
= propertyIndex
;
4503 void SmallBlockChainStream_Destroy(
4504 SmallBlockChainStream
* This
)
4506 HeapFree(GetProcessHeap(), 0, This
);
4509 /******************************************************************************
4510 * SmallBlockChainStream_GetHeadOfChain
4512 * Returns the head of this chain of small blocks.
4514 ULONG
SmallBlockChainStream_GetHeadOfChain(
4515 SmallBlockChainStream
* This
)
4517 StgProperty chainProperty
;
4520 if (This
->ownerPropertyIndex
)
4522 readSucessful
= StorageImpl_ReadProperty(
4523 This
->parentStorage
,
4524 This
->ownerPropertyIndex
,
4529 return chainProperty
.startingBlock
;
4534 return BLOCK_END_OF_CHAIN
;
4537 /******************************************************************************
4538 * SmallBlockChainStream_GetNextBlockInChain
4540 * Returns the index of the next small block in this chain.
4543 * - BLOCK_END_OF_CHAIN: end of this chain
4544 * - BLOCK_UNUSED: small block 'blockIndex' is free
4546 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4547 SmallBlockChainStream
* This
,
4550 ULARGE_INTEGER offsetOfBlockInDepot
;
4552 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4556 offsetOfBlockInDepot
.s
.HighPart
= 0;
4557 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4560 * Read those bytes in the buffer from the small block file.
4562 success
= BlockChainStream_ReadAt(
4563 This
->parentStorage
->smallBlockDepotChain
,
4564 offsetOfBlockInDepot
,
4571 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4574 return nextBlockInChain
;
4577 /******************************************************************************
4578 * SmallBlockChainStream_SetNextBlockInChain
4580 * Writes the index of the next block of the specified block in the small
4582 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4583 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4585 void SmallBlockChainStream_SetNextBlockInChain(
4586 SmallBlockChainStream
* This
,
4590 ULARGE_INTEGER offsetOfBlockInDepot
;
4594 offsetOfBlockInDepot
.s
.HighPart
= 0;
4595 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4597 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4600 * Read those bytes in the buffer from the small block file.
4602 BlockChainStream_WriteAt(
4603 This
->parentStorage
->smallBlockDepotChain
,
4604 offsetOfBlockInDepot
,
4610 /******************************************************************************
4611 * SmallBlockChainStream_FreeBlock
4613 * Flag small block 'blockIndex' as free in the small block depot.
4615 void SmallBlockChainStream_FreeBlock(
4616 SmallBlockChainStream
* This
,
4619 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4622 /******************************************************************************
4623 * SmallBlockChainStream_GetNextFreeBlock
4625 * Returns the index of a free small block. The small block depot will be
4626 * enlarged if necessary. The small block chain will also be enlarged if
4629 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4630 SmallBlockChainStream
* This
)
4632 ULARGE_INTEGER offsetOfBlockInDepot
;
4635 ULONG blockIndex
= 0;
4636 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4637 BOOL success
= TRUE
;
4638 ULONG smallBlocksPerBigBlock
;
4640 offsetOfBlockInDepot
.s
.HighPart
= 0;
4643 * Scan the small block depot for a free block
4645 while (nextBlockIndex
!= BLOCK_UNUSED
)
4647 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4649 success
= BlockChainStream_ReadAt(
4650 This
->parentStorage
->smallBlockDepotChain
,
4651 offsetOfBlockInDepot
,
4657 * If we run out of space for the small block depot, enlarge it
4661 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4663 if (nextBlockIndex
!= BLOCK_UNUSED
)
4669 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4671 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4672 ULONG nextBlock
, newsbdIndex
;
4673 BYTE
* smallBlockDepot
;
4675 nextBlock
= sbdIndex
;
4676 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4678 sbdIndex
= nextBlock
;
4680 StorageImpl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4683 newsbdIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4684 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4685 StorageImpl_SetNextBlockInChain(
4686 This
->parentStorage
,
4690 StorageImpl_SetNextBlockInChain(
4691 This
->parentStorage
,
4693 BLOCK_END_OF_CHAIN
);
4696 * Initialize all the small blocks to free
4699 StorageImpl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4701 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4702 StorageImpl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4707 * We have just created the small block depot.
4709 StgProperty rootProp
;
4713 * Save it in the header
4715 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4716 StorageImpl_SaveFileHeader(This
->parentStorage
);
4719 * And allocate the first big block that will contain small blocks
4722 StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4724 StorageImpl_SetNextBlockInChain(
4725 This
->parentStorage
,
4727 BLOCK_END_OF_CHAIN
);
4729 StorageImpl_ReadProperty(
4730 This
->parentStorage
,
4731 This
->parentStorage
->rootPropertySetIndex
,
4734 rootProp
.startingBlock
= sbStartIndex
;
4735 rootProp
.size
.s
.HighPart
= 0;
4736 rootProp
.size
.s
.LowPart
= This
->parentStorage
->bigBlockSize
;
4738 StorageImpl_WriteProperty(
4739 This
->parentStorage
,
4740 This
->parentStorage
->rootPropertySetIndex
,
4746 smallBlocksPerBigBlock
=
4747 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4750 * Verify if we have to allocate big blocks to contain small blocks
4752 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4754 StgProperty rootProp
;
4755 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4757 StorageImpl_ReadProperty(
4758 This
->parentStorage
,
4759 This
->parentStorage
->rootPropertySetIndex
,
4762 if (rootProp
.size
.s
.LowPart
<
4763 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4765 rootProp
.size
.s
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4767 BlockChainStream_SetSize(
4768 This
->parentStorage
->smallBlockRootChain
,
4771 StorageImpl_WriteProperty(
4772 This
->parentStorage
,
4773 This
->parentStorage
->rootPropertySetIndex
,
4781 /******************************************************************************
4782 * SmallBlockChainStream_ReadAt
4784 * Reads a specified number of bytes from this chain at the specified offset.
4785 * bytesRead may be NULL.
4786 * Failure will be returned if the specified number of bytes has not been read.
4788 BOOL
SmallBlockChainStream_ReadAt(
4789 SmallBlockChainStream
* This
,
4790 ULARGE_INTEGER offset
,
4795 ULARGE_INTEGER offsetInBigBlockFile
;
4796 ULONG blockNoInSequence
=
4797 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4799 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
4800 ULONG bytesToReadInBuffer
;
4802 ULONG bytesReadFromBigBlockFile
;
4806 * This should never happen on a small block file.
4808 assert(offset
.s
.HighPart
==0);
4811 * Find the first block in the stream that contains part of the buffer.
4813 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4815 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4817 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4819 blockNoInSequence
--;
4823 * Start reading the buffer.
4826 bufferWalker
= buffer
;
4828 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4831 * Calculate how many bytes we can copy from this small block.
4833 bytesToReadInBuffer
=
4834 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4837 * Calculate the offset of the small block in the small block file.
4839 offsetInBigBlockFile
.s
.HighPart
= 0;
4840 offsetInBigBlockFile
.s
.LowPart
=
4841 blockIndex
* This
->parentStorage
->smallBlockSize
;
4843 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
4846 * Read those bytes in the buffer from the small block file.
4848 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4849 offsetInBigBlockFile
,
4850 bytesToReadInBuffer
,
4852 &bytesReadFromBigBlockFile
);
4854 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4857 * Step to the next big block.
4859 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4860 bufferWalker
+= bytesToReadInBuffer
;
4861 size
-= bytesToReadInBuffer
;
4862 *bytesRead
+= bytesToReadInBuffer
;
4863 offsetInBlock
= 0; /* There is no offset on the next block */
4869 /******************************************************************************
4870 * SmallBlockChainStream_WriteAt
4872 * Writes the specified number of bytes to this chain at the specified offset.
4873 * bytesWritten may be NULL.
4874 * Will fail if not all specified number of bytes have been written.
4876 BOOL
SmallBlockChainStream_WriteAt(
4877 SmallBlockChainStream
* This
,
4878 ULARGE_INTEGER offset
,
4881 ULONG
* bytesWritten
)
4883 ULARGE_INTEGER offsetInBigBlockFile
;
4884 ULONG blockNoInSequence
=
4885 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4887 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
4888 ULONG bytesToWriteInBuffer
;
4890 ULONG bytesWrittenFromBigBlockFile
;
4894 * This should never happen on a small block file.
4896 assert(offset
.s
.HighPart
==0);
4899 * Find the first block in the stream that contains part of the buffer.
4901 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4903 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4905 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4907 blockNoInSequence
--;
4911 * Start writing the buffer.
4913 * Here, I'm casting away the constness on the buffer variable
4914 * This is OK since we don't intend to modify that buffer.
4917 bufferWalker
= (BYTE
*)buffer
;
4918 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4921 * Calculate how many bytes we can copy to this small block.
4923 bytesToWriteInBuffer
=
4924 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4927 * Calculate the offset of the small block in the small block file.
4929 offsetInBigBlockFile
.s
.HighPart
= 0;
4930 offsetInBigBlockFile
.s
.LowPart
=
4931 blockIndex
* This
->parentStorage
->smallBlockSize
;
4933 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
4936 * Write those bytes in the buffer to the small block file.
4938 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
4939 offsetInBigBlockFile
,
4940 bytesToWriteInBuffer
,
4942 &bytesWrittenFromBigBlockFile
);
4944 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
4947 * Step to the next big block.
4949 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4950 bufferWalker
+= bytesToWriteInBuffer
;
4951 size
-= bytesToWriteInBuffer
;
4952 *bytesWritten
+= bytesToWriteInBuffer
;
4953 offsetInBlock
= 0; /* There is no offset on the next block */
4959 /******************************************************************************
4960 * SmallBlockChainStream_Shrink
4962 * Shrinks this chain in the small block depot.
4964 BOOL
SmallBlockChainStream_Shrink(
4965 SmallBlockChainStream
* This
,
4966 ULARGE_INTEGER newSize
)
4968 ULONG blockIndex
, extraBlock
;
4972 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4974 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4977 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4980 * Go to the new end of chain
4982 while (count
< numBlocks
)
4984 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4989 * If the count is 0, we have a special case, the head of the chain was
4994 StgProperty chainProp
;
4996 StorageImpl_ReadProperty(This
->parentStorage
,
4997 This
->ownerPropertyIndex
,
5000 chainProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
5002 StorageImpl_WriteProperty(This
->parentStorage
,
5003 This
->ownerPropertyIndex
,
5007 * We start freeing the chain at the head block.
5009 extraBlock
= blockIndex
;
5013 /* Get the next block before marking the new end */
5014 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5016 /* Mark the new end of chain */
5017 SmallBlockChainStream_SetNextBlockInChain(
5020 BLOCK_END_OF_CHAIN
);
5024 * Mark the extra blocks as free
5026 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
5028 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
5029 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
5030 extraBlock
= blockIndex
;
5036 /******************************************************************************
5037 * SmallBlockChainStream_Enlarge
5039 * Grows this chain in the small block depot.
5041 BOOL
SmallBlockChainStream_Enlarge(
5042 SmallBlockChainStream
* This
,
5043 ULARGE_INTEGER newSize
)
5045 ULONG blockIndex
, currentBlock
;
5047 ULONG oldNumBlocks
= 0;
5049 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5054 if (blockIndex
== BLOCK_END_OF_CHAIN
)
5057 StgProperty chainProp
;
5059 StorageImpl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5062 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
5064 StorageImpl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5067 blockIndex
= chainProp
.startingBlock
;
5068 SmallBlockChainStream_SetNextBlockInChain(
5071 BLOCK_END_OF_CHAIN
);
5074 currentBlock
= blockIndex
;
5077 * Figure out how many blocks are needed to contain this stream
5079 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5081 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5085 * Go to the current end of chain
5087 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5090 currentBlock
= blockIndex
;
5091 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
5095 * Add new blocks to the chain
5097 while (oldNumBlocks
< newNumBlocks
)
5099 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
5100 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
5102 SmallBlockChainStream_SetNextBlockInChain(
5105 BLOCK_END_OF_CHAIN
);
5107 currentBlock
= blockIndex
;
5114 /******************************************************************************
5115 * SmallBlockChainStream_GetCount
5117 * Returns the number of blocks that comprises this chain.
5118 * This is not the size of this chain as the last block may not be full!
5120 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
5125 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5127 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5131 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5137 /******************************************************************************
5138 * SmallBlockChainStream_SetSize
5140 * Sets the size of this stream.
5141 * The file will grow if we grow the chain.
5143 * TODO: Free the actual blocks in the file when we shrink the chain.
5144 * Currently, the blocks are still in the file. So the file size
5145 * doesn't shrink even if we shrink streams.
5147 BOOL
SmallBlockChainStream_SetSize(
5148 SmallBlockChainStream
* This
,
5149 ULARGE_INTEGER newSize
)
5151 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
5153 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
5156 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
5158 SmallBlockChainStream_Shrink(This
, newSize
);
5162 SmallBlockChainStream_Enlarge(This
, newSize
);
5168 /******************************************************************************
5169 * SmallBlockChainStream_GetSize
5171 * Returns the size of this chain.
5173 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
5175 StgProperty chainProperty
;
5177 StorageImpl_ReadProperty(
5178 This
->parentStorage
,
5179 This
->ownerPropertyIndex
,
5182 return chainProperty
.size
;
5185 /******************************************************************************
5186 * StgCreateDocfile32 [OLE32.144]
5188 HRESULT WINAPI
StgCreateDocfile(
5192 IStorage
**ppstgOpen
)
5194 StorageImpl
* newStorage
= 0;
5195 HANDLE hFile
= INVALID_HANDLE_VALUE
;
5200 DWORD fileAttributes
;
5201 WCHAR tempFileName
[MAX_PATH
];
5203 TRACE("(%s, %lx, %ld, %p)\n",
5204 debugstr_w(pwcsName
), grfMode
,
5205 reserved
, ppstgOpen
);
5208 * Validate the parameters
5211 return STG_E_INVALIDPOINTER
;
5214 * Validate the STGM flags
5216 if ( FAILED( validateSTGM(grfMode
) ))
5217 return STG_E_INVALIDFLAG
;
5220 * Generate a unique name.
5224 WCHAR tempPath
[MAX_PATH
];
5225 WCHAR prefix
[] = { 'S', 'T', 'O', 0 };
5227 memset(tempPath
, 0, sizeof(tempPath
));
5228 memset(tempFileName
, 0, sizeof(tempFileName
));
5230 if ((GetTempPathW(MAX_PATH
, tempPath
)) == 0 )
5233 if (GetTempFileNameW(tempPath
, prefix
, 0, tempFileName
) != 0)
5234 pwcsName
= tempFileName
;
5236 return STG_E_INSUFFICIENTMEMORY
;
5240 * Interpret the STGM value grfMode
5242 shareMode
= GetShareModeFromSTGM(grfMode
);
5243 accessMode
= GetAccessModeFromSTGM(grfMode
);
5244 creationMode
= GetCreationModeFromSTGM(grfMode
);
5246 if (grfMode
& STGM_DELETEONRELEASE
)
5247 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
5249 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
5251 if (grfMode
& STGM_TRANSACTED
)
5252 FIXME("Transacted mode not implemented.\n");
5255 * Initialize the "out" parameter.
5259 hFile
= CreateFileW(pwcsName
,
5267 if (hFile
== INVALID_HANDLE_VALUE
)
5273 * Allocate and initialize the new IStorage32object.
5275 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5277 if (newStorage
== 0)
5278 return STG_E_INSUFFICIENTMEMORY
;
5280 hr
= StorageImpl_Construct(
5289 HeapFree(GetProcessHeap(), 0, newStorage
);
5294 * Get an "out" pointer for the caller.
5296 hr
= StorageBaseImpl_QueryInterface(
5297 (IStorage
*)newStorage
,
5298 (REFIID
)&IID_IStorage
,
5304 /******************************************************************************
5305 * StgOpenStorage32 [OLE32.148]
5307 HRESULT WINAPI
StgOpenStorage(
5308 const OLECHAR
*pwcsName
,
5309 IStorage
*pstgPriority
,
5313 IStorage
**ppstgOpen
)
5315 StorageImpl
* newStorage
= 0;
5321 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5322 debugstr_w(pwcsName
), pstgPriority
, grfMode
,
5323 snbExclude
, reserved
, ppstgOpen
);
5326 * Perform a sanity check
5328 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
5329 return STG_E_INVALIDPOINTER
;
5332 * Validate the STGM flags
5334 if ( FAILED( validateSTGM(grfMode
) ))
5335 return STG_E_INVALIDFLAG
;
5338 * Interpret the STGM value grfMode
5340 shareMode
= GetShareModeFromSTGM(grfMode
);
5341 accessMode
= GetAccessModeFromSTGM(grfMode
);
5344 * Initialize the "out" parameter.
5348 hFile
= CreateFileW( pwcsName
,
5353 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5357 if (hFile
==INVALID_HANDLE_VALUE
)
5363 * Allocate and initialize the new IStorage32object.
5365 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5367 if (newStorage
== 0)
5368 return STG_E_INSUFFICIENTMEMORY
;
5370 hr
= StorageImpl_Construct(
5379 HeapFree(GetProcessHeap(), 0, newStorage
);
5384 * Get an "out" pointer for the caller.
5386 hr
= StorageBaseImpl_QueryInterface(
5387 (IStorage
*)newStorage
,
5388 (REFIID
)&IID_IStorage
,
5394 /******************************************************************************
5395 * StgCreateDocfileOnILockBytes [OLE32.145]
5397 HRESULT WINAPI
StgCreateDocfileOnILockBytes(
5401 IStorage
** ppstgOpen
)
5403 StorageImpl
* newStorage
= 0;
5407 * Validate the parameters
5409 if ((ppstgOpen
== 0) || (plkbyt
== 0))
5410 return STG_E_INVALIDPOINTER
;
5413 * Allocate and initialize the new IStorage object.
5415 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5417 if (newStorage
== 0)
5418 return STG_E_INSUFFICIENTMEMORY
;
5420 hr
= StorageImpl_Construct(
5429 HeapFree(GetProcessHeap(), 0, newStorage
);
5434 * Get an "out" pointer for the caller.
5436 hr
= StorageBaseImpl_QueryInterface(
5437 (IStorage
*)newStorage
,
5438 (REFIID
)&IID_IStorage
,
5444 /******************************************************************************
5445 * StgOpenStorageOnILockBytes [OLE32.149]
5447 HRESULT WINAPI
StgOpenStorageOnILockBytes(
5449 IStorage
*pstgPriority
,
5453 IStorage
**ppstgOpen
)
5455 StorageImpl
* newStorage
= 0;
5459 * Perform a sanity check
5461 if ((plkbyt
== 0) || (ppstgOpen
== 0))
5462 return STG_E_INVALIDPOINTER
;
5465 * Validate the STGM flags
5467 if ( FAILED( validateSTGM(grfMode
) ))
5468 return STG_E_INVALIDFLAG
;
5471 * Initialize the "out" parameter.
5476 * Allocate and initialize the new IStorage object.
5478 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5480 if (newStorage
== 0)
5481 return STG_E_INSUFFICIENTMEMORY
;
5483 hr
= StorageImpl_Construct(
5492 HeapFree(GetProcessHeap(), 0, newStorage
);
5497 * Get an "out" pointer for the caller.
5499 hr
= StorageBaseImpl_QueryInterface(
5500 (IStorage
*)newStorage
,
5501 (REFIID
)&IID_IStorage
,
5507 /******************************************************************************
5508 * StgSetTimes [ole32.150]
5512 HRESULT WINAPI
StgSetTimes(WCHAR
* str
, FILETIME
* a
, FILETIME
* b
, FILETIME
*c
)
5515 FIXME("(%p, %p, %p, %p),stub!\n", str
, a
, b
, c
);
5519 /******************************************************************************
5520 * StgIsStorageILockBytes [OLE32.147]
5522 * Determines if the ILockBytes contains a storage object.
5524 HRESULT WINAPI
StgIsStorageILockBytes(ILockBytes
*plkbyt
)
5527 ULARGE_INTEGER offset
;
5529 offset
.s
.HighPart
= 0;
5530 offset
.s
.LowPart
= 0;
5532 ILockBytes_ReadAt(plkbyt
, offset
, sig
, sizeof(sig
), NULL
);
5534 if (memcmp(sig
, STORAGE_magic
, sizeof(STORAGE_magic
)) == 0)
5540 /******************************************************************************
5541 * WriteClassStg32 [OLE32.158]
5543 * This method will store the specified CLSID in the specified storage object
5545 HRESULT WINAPI
WriteClassStg(IStorage
* pStg
, REFCLSID rclsid
)
5551 hRes
= IStorage_SetClass(pStg
, rclsid
);
5556 /*******************************************************************************************
5559 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5561 HRESULT WINAPI
ReadClassStg(IStorage
*pstg
,CLSID
*pclsid
){
5571 * read a STATSTG structure (contains the clsid) from the storage
5573 hRes
=IStorage_Stat(pstg
,&pstatstg
,STATFLAG_DEFAULT
);
5576 *pclsid
=pstatstg
.clsid
;
5581 /*************************************************************************************
5584 * This function loads an object from stream
5586 HRESULT WINAPI
OleLoadFromStream(IStream
*pStm
,REFIID iidInterface
,void** ppvObj
)
5591 FIXME("(),stub!\n");
5593 res
=ReadClassStm(pStm
,&clsid
);
5595 if (SUCCEEDED(res
)){
5597 res
=CoCreateInstance(&clsid
,NULL
,CLSCTX_INPROC_SERVER
,iidInterface
,ppvObj
);
5601 res
=IPersistStream_Load((IPersistStream
*)ppvObj
,pStm
);
5607 /************************************************************************************************
5610 * This function saves an object with the IPersistStream interface on it to the specified stream
5612 HRESULT WINAPI
OleSaveToStream(IPersistStream
*pPStm
,IStream
*pStm
)
5618 TRACE("(%p,%p)\n",pPStm
,pStm
);
5620 res
=IPersistStream_GetClassID(pPStm
,&clsid
);
5622 if (SUCCEEDED(res
)){
5624 res
=WriteClassStm(pStm
,&clsid
);
5628 res
=IPersistStream_Save(pPStm
,pStm
,FALSE
);
5634 /****************************************************************************
5635 * This method validate a STGM parameter that can contain the values below
5637 * STGM_DIRECT 0x00000000
5638 * STGM_TRANSACTED 0x00010000
5639 * STGM_SIMPLE 0x08000000
5641 * STGM_READ 0x00000000
5642 * STGM_WRITE 0x00000001
5643 * STGM_READWRITE 0x00000002
5645 * STGM_SHARE_DENY_NONE 0x00000040
5646 * STGM_SHARE_DENY_READ 0x00000030
5647 * STGM_SHARE_DENY_WRITE 0x00000020
5648 * STGM_SHARE_EXCLUSIVE 0x00000010
5650 * STGM_PRIORITY 0x00040000
5651 * STGM_DELETEONRELEASE 0x04000000
5653 * STGM_CREATE 0x00001000
5654 * STGM_CONVERT 0x00020000
5655 * STGM_FAILIFTHERE 0x00000000
5657 * STGM_NOSCRATCH 0x00100000
5658 * STGM_NOSNAPSHOT 0x00200000
5660 static HRESULT
validateSTGM(DWORD stgm
)
5662 BOOL bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5663 BOOL bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5664 BOOL bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5666 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5667 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5668 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5670 BOOL bSTGM_SHARE_DENY_NONE
=
5671 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5673 BOOL bSTGM_SHARE_DENY_READ
=
5674 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5676 BOOL bSTGM_SHARE_DENY_WRITE
=
5677 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5679 BOOL bSTGM_SHARE_EXCLUSIVE
=
5680 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5682 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5683 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5685 BOOL bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5686 BOOL bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5689 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5691 if ( ! bSTGM_DIRECT
)
5692 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5696 * STGM_WRITE | STGM_READWRITE | STGM_READ
5699 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5703 * STGM_SHARE_DENY_NONE | others
5704 * (I assume here that DENY_READ implies DENY_WRITE)
5706 if ( bSTGM_SHARE_DENY_NONE
)
5707 if ( bSTGM_SHARE_DENY_READ
||
5708 bSTGM_SHARE_DENY_WRITE
||
5709 bSTGM_SHARE_EXCLUSIVE
)
5713 * STGM_CREATE | STGM_CONVERT
5714 * if both are false, STGM_FAILIFTHERE is set to TRUE
5716 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5720 * STGM_NOSCRATCH requires STGM_TRANSACTED
5722 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5726 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5727 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5729 if (bSTGM_NOSNAPSHOT
)
5731 if ( ! ( bSTGM_TRANSACTED
&&
5732 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
5739 /****************************************************************************
5740 * GetShareModeFromSTGM
5742 * This method will return a share mode flag from a STGM value.
5743 * The STGM value is assumed valid.
5745 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
5747 DWORD dwShareMode
= 0;
5748 BOOL bSTGM_SHARE_DENY_NONE
=
5749 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5751 BOOL bSTGM_SHARE_DENY_READ
=
5752 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5754 BOOL bSTGM_SHARE_DENY_WRITE
=
5755 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5757 BOOL bSTGM_SHARE_EXCLUSIVE
=
5758 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5760 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
5763 if (bSTGM_SHARE_DENY_NONE
)
5764 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
5766 if (bSTGM_SHARE_DENY_WRITE
)
5767 dwShareMode
= FILE_SHARE_READ
;
5772 /****************************************************************************
5773 * GetAccessModeFromSTGM
5775 * This method will return an access mode flag from a STGM value.
5776 * The STGM value is assumed valid.
5778 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
5780 DWORD dwDesiredAccess
= GENERIC_READ
;
5781 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5782 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5783 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5786 dwDesiredAccess
= GENERIC_READ
;
5789 dwDesiredAccess
|= GENERIC_WRITE
;
5791 if (bSTGM_READWRITE
)
5792 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
5794 return dwDesiredAccess
;
5797 /****************************************************************************
5798 * GetCreationModeFromSTGM
5800 * This method will return a creation mode flag from a STGM value.
5801 * The STGM value is assumed valid.
5803 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
5805 if ( stgm
& STGM_CREATE
)
5806 return CREATE_ALWAYS
;
5807 if (stgm
& STGM_CONVERT
) {
5808 FIXME("STGM_CONVERT not implemented!\n");
5811 /* All other cases */
5812 if (stgm
& ~ (STGM_CREATE
|STGM_CONVERT
))
5813 FIXME("unhandled storage mode : 0x%08lx\n",stgm
& ~ (STGM_CREATE
|STGM_CONVERT
));