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
32 #include "storage32.h"
36 static const char rootPropertyName
[] = "Root Entry";
38 /***********************************************************************
39 * Forward declaration of internal functions used by the method DestroyElement
41 static HRESULT
deleteStorageProperty(
42 Storage32Impl
*parentStorage
,
43 OLECHAR32
*propertyToDeleteName
);
45 static HRESULT
deleteStreamProperty(
46 Storage32Impl
*parentStorage
,
47 ULONG foundPropertyIndexToDelete
,
48 StgProperty propertyToDelete
);
50 static HRESULT
findPlaceholder(
51 Storage32Impl
*storage
,
52 ULONG propertyIndexToStore
,
53 ULONG storagePropertyIndex
,
54 INT32 typeOfRelation
);
56 static HRESULT
adjustPropertyChain(
58 StgProperty propertyToDelete
,
59 StgProperty parentProperty
,
60 ULONG parentPropertyId
,
61 INT32 typeOfRelation
);
63 /***********************************************************************
64 * Declaration of the functions used to manipulate StgProperty
67 static ULONG
getFreeProperty(
68 Storage32Impl
*storage
);
70 static void updatePropertyChain(
71 Storage32Impl
*storage
,
72 ULONG newPropertyIndex
,
73 StgProperty newProperty
);
75 static LONG
propertyNameCmp(
76 OLECHAR32
*newProperty
,
77 OLECHAR32
*currentProperty
);
80 /***********************************************************************
81 * Declaration of miscellaneous functions...
83 static HRESULT
validateSTGM(DWORD stgmValue
);
85 static DWORD
GetShareModeFromSTGM(DWORD stgm
);
86 static DWORD
GetAccessModeFromSTGM(DWORD stgm
);
87 static DWORD
GetCreationModeFromSTGM(DWORD stgm
);
90 * Virtual function table for the IStorage32Impl class.
92 static ICOM_VTABLE(IStorage32
) Storage32Impl_VTable
=
95 VTABLE_FUNC(Storage32BaseImpl_QueryInterface
),
96 VTABLE_FUNC(Storage32BaseImpl_AddRef
),
97 VTABLE_FUNC(Storage32BaseImpl_Release
)
99 VTABLE_FUNC(Storage32BaseImpl_CreateStream
),
100 VTABLE_FUNC(Storage32BaseImpl_OpenStream
),
101 VTABLE_FUNC(Storage32Impl_CreateStorage
),
102 VTABLE_FUNC(Storage32BaseImpl_OpenStorage
),
103 VTABLE_FUNC(Storage32Impl_CopyTo
),
104 VTABLE_FUNC(Storage32Impl_MoveElementTo
),
105 VTABLE_FUNC(Storage32Impl_Commit
),
106 VTABLE_FUNC(Storage32Impl_Revert
),
107 VTABLE_FUNC(Storage32BaseImpl_EnumElements
),
108 VTABLE_FUNC(Storage32Impl_DestroyElement
),
109 VTABLE_FUNC(Storage32BaseImpl_RenameElement
),
110 VTABLE_FUNC(Storage32Impl_SetElementTimes
),
111 VTABLE_FUNC(Storage32BaseImpl_SetClass
),
112 VTABLE_FUNC(Storage32Impl_SetStateBits
),
113 VTABLE_FUNC(Storage32BaseImpl_Stat
)
117 * Virtual function table for the Storage32InternalImpl class.
119 static ICOM_VTABLE(IStorage32
) Storage32InternalImpl_VTable
=
122 VTABLE_FUNC(Storage32BaseImpl_QueryInterface
),
123 VTABLE_FUNC(Storage32BaseImpl_AddRef
),
124 VTABLE_FUNC(Storage32BaseImpl_Release
)
126 VTABLE_FUNC(Storage32BaseImpl_CreateStream
),
127 VTABLE_FUNC(Storage32BaseImpl_OpenStream
),
128 VTABLE_FUNC(Storage32Impl_CreateStorage
),
129 VTABLE_FUNC(Storage32BaseImpl_OpenStorage
),
130 VTABLE_FUNC(Storage32Impl_CopyTo
),
131 VTABLE_FUNC(Storage32Impl_MoveElementTo
),
132 VTABLE_FUNC(Storage32InternalImpl_Commit
),
133 VTABLE_FUNC(Storage32InternalImpl_Revert
),
134 VTABLE_FUNC(Storage32BaseImpl_EnumElements
),
135 VTABLE_FUNC(Storage32Impl_DestroyElement
),
136 VTABLE_FUNC(Storage32BaseImpl_RenameElement
),
137 VTABLE_FUNC(Storage32Impl_SetElementTimes
),
138 VTABLE_FUNC(Storage32BaseImpl_SetClass
),
139 VTABLE_FUNC(Storage32Impl_SetStateBits
),
140 VTABLE_FUNC(Storage32BaseImpl_Stat
)
144 * Virtual function table for the IEnumSTATSTGImpl class.
146 static ICOM_VTABLE(IEnumSTATSTG
) IEnumSTATSTGImpl_Vtbl
=
149 VTABLE_FUNC(IEnumSTATSTGImpl_QueryInterface
),
150 VTABLE_FUNC(IEnumSTATSTGImpl_AddRef
),
151 VTABLE_FUNC(IEnumSTATSTGImpl_Release
)
153 VTABLE_FUNC(IEnumSTATSTGImpl_Next
),
154 VTABLE_FUNC(IEnumSTATSTGImpl_Skip
),
155 VTABLE_FUNC(IEnumSTATSTGImpl_Reset
),
156 VTABLE_FUNC(IEnumSTATSTGImpl_Clone
)
163 /************************************************************************
164 ** Storage32BaseImpl implementatiion
167 /************************************************************************
168 * Storage32BaseImpl_QueryInterface (IUnknown)
170 * This method implements the common QueryInterface for all IStorage32
171 * implementations contained in this file.
173 * See Windows documentation for more details on IUnknown methods.
175 HRESULT WINAPI
Storage32BaseImpl_QueryInterface(
176 Storage32BaseImpl
* This
,
181 * Perform a sanity check on the parameters.
183 if ( (This
==0) || (ppvObject
==0) )
187 * Initialize the return parameter.
192 * Compare the riid with the interface IDs implemented by this object.
194 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
196 *ppvObject
= (IStorage32
*)This
;
198 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
200 *ppvObject
= (IStorage32
*)This
;
204 * Check that we obtained an interface.
207 return E_NOINTERFACE
;
210 * Query Interface always increases the reference count by one when it is
213 Storage32BaseImpl_AddRef(This
);
218 /************************************************************************
219 * Storage32BaseImpl_AddRef (IUnknown)
221 * This method implements the common AddRef for all IStorage32
222 * implementations contained in this file.
224 * See Windows documentation for more details on IUnknown methods.
226 ULONG WINAPI
Storage32BaseImpl_AddRef(
227 Storage32BaseImpl
* This
)
234 /************************************************************************
235 * Storage32BaseImpl_Release (IUnknown)
237 * This method implements the common Release for all IStorage32
238 * implementations contained in this file.
240 * See Windows documentation for more details on IUnknown methods.
242 ULONG WINAPI
Storage32BaseImpl_Release(
243 Storage32BaseImpl
* This
)
246 * Decrease the reference count on this object.
251 * If the reference count goes down to 0, perform suicide.
256 * Since we are using a system of base-classes, we want to call the
257 * destructor of the appropriate derived class. To do this, we are
258 * using virtual functions to implement the destructor.
260 This
->v_destructor(This
);
268 /************************************************************************
269 * Storage32BaseImpl_OpenStream (IStorage)
271 * This method will open the specified stream object from the current storage.
273 * See Windows documentation for more details on IStorage methods.
275 HRESULT WINAPI
Storage32BaseImpl_OpenStream(
276 Storage32BaseImpl
* This
,
277 const OLECHAR32
* pwcsName
, /* [string][in] */
278 void* reserved1
, /* [unique][in] */
279 DWORD grfMode
, /* [in] */
280 DWORD reserved2
, /* [in] */
281 IStream32
** ppstm
) /* [out] */
283 IEnumSTATSTGImpl
* propertyEnumeration
;
284 StgStreamImpl
* newStream
;
285 StgProperty currentProperty
;
286 ULONG foundPropertyIndex
;
289 * Perform a sanity check on the parameters.
291 if ( (pwcsName
==NULL
) || (ppstm
==0) )
295 * Initialize the out parameter
300 * Validate the STGM flags
302 if ( FAILED( validateSTGM(grfMode
) ))
303 return STG_E_INVALIDFLAG
;
308 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
309 (grfMode
& STGM_DELETEONRELEASE
) ||
310 (grfMode
& STGM_TRANSACTED
) )
311 return STG_E_INVALIDFUNCTION
;
314 * Create a property enumeration to search the properties
316 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
317 This
->ancestorStorage
,
318 This
->rootPropertySetIndex
);
321 * Search the enumeration for the property with the given name
323 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
329 * Delete the property enumeration since we don't need it anymore
331 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
334 * If it was found, construct the stream object and return a pointer to it.
336 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
337 (currentProperty
.propertyType
==PROPTYPE_STREAM
) )
339 newStream
= StgStreamImpl_Construct(This
, foundPropertyIndex
);
344 * Since we are returning a pointer to the interface, we have to
345 * nail down the reference.
347 StgStreamImpl_AddRef(newStream
);
349 *ppstm
= (IStream32
*)newStream
;
354 return E_OUTOFMEMORY
;
357 return STG_E_FILENOTFOUND
;
360 /************************************************************************
361 * Storage32BaseImpl_OpenStorage (IStorage)
363 * This method will open a new storage object from the current storage.
365 * See Windows documentation for more details on IStorage methods.
367 HRESULT WINAPI
Storage32BaseImpl_OpenStorage(
368 Storage32BaseImpl
* This
,
369 const OLECHAR32
* pwcsName
, /* [string][unique][in] */
370 IStorage32
* pstgPriority
, /* [unique][in] */
371 DWORD grfMode
, /* [in] */
372 SNB32 snbExclude
, /* [unique][in] */
373 DWORD reserved
, /* [in] */
374 IStorage32
** ppstg
) /* [out] */
376 Storage32InternalImpl
* newStorage
;
377 IEnumSTATSTGImpl
* propertyEnumeration
;
378 StgProperty currentProperty
;
379 ULONG foundPropertyIndex
;
382 * Perform a sanity check on the parameters.
384 if ( (This
==0) || (pwcsName
==NULL
) || (ppstg
==0) )
388 * Validate the STGM flags
390 if ( FAILED( validateSTGM(grfMode
) ))
391 return STG_E_INVALIDFLAG
;
396 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
397 (grfMode
& STGM_DELETEONRELEASE
) ||
398 (grfMode
& STGM_PRIORITY
) )
399 return STG_E_INVALIDFUNCTION
;
402 * Initialize the out parameter
407 * Create a property enumeration to search the properties
409 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
410 This
->ancestorStorage
,
411 This
->rootPropertySetIndex
);
414 * Search the enumeration for the property with the given name
416 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
422 * Delete the property enumeration since we don't need it anymore
424 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
427 * If it was found, construct the stream object and return a pointer to it.
429 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
430 (currentProperty
.propertyType
==PROPTYPE_STORAGE
) )
433 * Construct a new Storage object
435 newStorage
= Storage32InternalImpl_Construct(
436 This
->ancestorStorage
,
442 * Since we are returning a pointer to the interface,
443 * we have to nail down the reference.
445 Storage32BaseImpl_AddRef((Storage32BaseImpl
*)newStorage
);
447 *ppstg
= (IStorage32
*)newStorage
;
452 return STG_E_INSUFFICIENTMEMORY
;
455 return STG_E_FILENOTFOUND
;
458 /************************************************************************
459 * Storage32BaseImpl_EnumElements (IStorage)
461 * This method will create an enumerator object that can be used to
462 * retrieve informatino about all the properties in the storage object.
464 * See Windows documentation for more details on IStorage methods.
466 HRESULT WINAPI
Storage32BaseImpl_EnumElements(
467 Storage32BaseImpl
* This
,
468 DWORD reserved1
, /* [in] */
469 void* reserved2
, /* [size_is][unique][in] */
470 DWORD reserved3
, /* [in] */
471 IEnumSTATSTG
** ppenum
) /* [out] */
473 IEnumSTATSTGImpl
* newEnum
;
476 * Perform a sanity check on the parameters.
478 if ( (This
==0) || (ppenum
==0))
482 * Construct the enumerator.
484 newEnum
= IEnumSTATSTGImpl_Construct(
485 This
->ancestorStorage
,
486 This
->rootPropertySetIndex
);
491 * Don't forget to nail down a reference to the new object before
494 IEnumSTATSTGImpl_AddRef(newEnum
);
496 *ppenum
= (IEnumSTATSTG
*)newEnum
;
501 return E_OUTOFMEMORY
;
504 /************************************************************************
505 * Storage32BaseImpl_Stat (IStorage)
507 * This method will retrieve information about this storage object.
509 * See Windows documentation for more details on IStorage methods.
511 HRESULT WINAPI
Storage32BaseImpl_Stat(
512 Storage32BaseImpl
* This
,
513 STATSTG
* pstatstg
, /* [out] */
514 DWORD grfStatFlag
) /* [in] */
516 StgProperty curProperty
;
517 BOOL32 readSucessful
;
520 * Perform a sanity check on the parameters.
522 if ( (This
==0) || (pstatstg
==0))
526 * Read the information from the property.
528 readSucessful
= Storage32Impl_ReadProperty(
529 This
->ancestorStorage
,
530 This
->rootPropertySetIndex
,
535 StorageUtl_CopyPropertyToSTATSTG(
546 /************************************************************************
547 * Storage32BaseImpl_RenameElement (IStorage)
549 * This method will rename the specified element.
551 * See Windows documentation for more details on IStorage methods.
553 * Implementation notes: The method used to rename consists of creating a clone
554 * of the deleted StgProperty object setting it with the new name and to
555 * perform a DestroyElement of the old StgProperty.
557 HRESULT WINAPI
Storage32BaseImpl_RenameElement(
558 Storage32BaseImpl
* This
,
559 const OLECHAR32
* pwcsOldName
, /* [in] */
560 const OLECHAR32
* pwcsNewName
) /* [in] */
562 IEnumSTATSTGImpl
* propertyEnumeration
;
563 StgProperty currentProperty
;
564 ULONG foundPropertyIndex
;
567 * Create a property enumeration to search the properties
569 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
570 This
->rootPropertySetIndex
);
573 * Search the enumeration for the new property name
575 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
579 if (foundPropertyIndex
!= PROPERTY_NULL
)
582 * There is already a property with the new name
584 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
585 return STG_E_FILEALREADYEXISTS
;
588 IEnumSTATSTGImpl_Reset(propertyEnumeration
);
591 * Search the enumeration for the old property name
593 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
598 * Delete the property enumeration since we don't need it anymore
600 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
602 if (foundPropertyIndex
!= PROPERTY_NULL
)
604 StgProperty renamedProperty
;
605 ULONG renamedPropertyIndex
;
608 * Setup a new property for the renamed property
610 renamedProperty
.sizeOfNameString
=
611 ( lstrlen32W(pwcsNewName
)+1 ) * sizeof(WCHAR
);
613 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
614 return STG_E_INVALIDNAME
;
616 lstrcpy32W(renamedProperty
.name
, pwcsNewName
);
618 renamedProperty
.propertyType
= currentProperty
.propertyType
;
619 renamedProperty
.startingBlock
= currentProperty
.startingBlock
;
620 renamedProperty
.size
.LowPart
= currentProperty
.size
.LowPart
;
621 renamedProperty
.size
.HighPart
= currentProperty
.size
.HighPart
;
623 renamedProperty
.previousProperty
= PROPERTY_NULL
;
624 renamedProperty
.nextProperty
= PROPERTY_NULL
;
627 * Bring the dirProperty link in case it is a storage and in which
628 * case the renamed storage elements don't require to be reorganized.
630 renamedProperty
.dirProperty
= currentProperty
.dirProperty
;
632 /* call CoFileTime to get the current time
633 renamedProperty.timeStampS1
634 renamedProperty.timeStampD1
635 renamedProperty.timeStampS2
636 renamedProperty.timeStampD2
637 renamedProperty.propertyUniqueID
641 * Obtain a free property in the property chain
643 renamedPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
646 * Save the new property into the new property spot
648 Storage32Impl_WriteProperty(
649 This
->ancestorStorage
,
650 renamedPropertyIndex
,
654 * Find a spot in the property chain for our newly created property.
657 (Storage32Impl
*)This
,
658 renamedPropertyIndex
,
662 * At this point the renamed property has been inserted in the tree,
663 * now, before to Destroy the old property we must zeroed it's dirProperty
664 * otherwise the DestroyProperty below will zap it all and we do not want
666 * Also, we fake that the old property is a storage so the DestroyProperty
667 * will not do a SetSize(0) on the stream data.
669 * This means that we need to tweek the StgProperty if it is a stream or a
672 currentProperty
.dirProperty
= PROPERTY_NULL
;
673 currentProperty
.propertyType
= PROPTYPE_STORAGE
;
674 Storage32Impl_WriteProperty(
675 This
->ancestorStorage
,
680 * Invoke Destroy to get rid of the ole property and automatically redo
681 * the linking of it's previous and next members...
683 Storage32Impl_DestroyElement(This
->ancestorStorage
, pwcsOldName
);
689 * There is no property with the old name
691 return STG_E_FILENOTFOUND
;
697 /************************************************************************
698 * Storage32BaseImpl_CreateStream (IStorage)
700 * This method will create a stream object within this storage
702 * See Windows documentation for more details on IStorage methods.
704 HRESULT WINAPI
Storage32BaseImpl_CreateStream(
705 Storage32BaseImpl
* This
,
706 const OLECHAR32
* pwcsName
, /* [string][in] */
707 DWORD grfMode
, /* [in] */
708 DWORD reserved1
, /* [in] */
709 DWORD reserved2
, /* [in] */
710 IStream32
** ppstm
) /* [out] */
712 IEnumSTATSTGImpl
* propertyEnumeration
;
713 StgStreamImpl
* newStream
;
714 StgProperty currentProperty
, newStreamProperty
;
715 ULONG foundPropertyIndex
, newPropertyIndex
;
718 * Validate parameters
721 return STG_E_INVALIDPOINTER
;
724 return STG_E_INVALIDNAME
;
727 * Validate the STGM flags
729 if ( FAILED( validateSTGM(grfMode
) ))
730 return STG_E_INVALIDFLAG
;
735 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
736 (grfMode
& STGM_DELETEONRELEASE
) ||
737 (grfMode
& STGM_TRANSACTED
) )
738 return STG_E_INVALIDFUNCTION
;
741 * Initialize the out parameter
746 * Create a property enumeration to search the properties
748 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
749 This
->rootPropertySetIndex
);
751 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
755 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
757 if (foundPropertyIndex
!= PROPERTY_NULL
)
760 * An element with this name already exists
762 if (grfMode
& STGM_CREATE
)
763 Storage32Impl_DestroyElement(This
->ancestorStorage
, pwcsName
);
765 return STG_E_FILEALREADYEXISTS
;
769 * memset the empty property
771 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
773 newStreamProperty
.sizeOfNameString
=
774 ( lstrlen32W(pwcsName
)+1 ) * sizeof(WCHAR
);
776 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
777 return STG_E_INVALIDNAME
;
779 lstrcpy32W(newStreamProperty
.name
, pwcsName
);
781 newStreamProperty
.propertyType
= PROPTYPE_STREAM
;
782 newStreamProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
783 newStreamProperty
.size
.LowPart
= 0;
784 newStreamProperty
.size
.HighPart
= 0;
786 newStreamProperty
.previousProperty
= PROPERTY_NULL
;
787 newStreamProperty
.nextProperty
= PROPERTY_NULL
;
788 newStreamProperty
.dirProperty
= PROPERTY_NULL
;
790 /* call CoFileTime to get the current time
791 newStreamProperty.timeStampS1
792 newStreamProperty.timeStampD1
793 newStreamProperty.timeStampS2
794 newStreamProperty.timeStampD2
797 /* newStreamProperty.propertyUniqueID */
800 * Get a free property or create a new one
802 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
805 * Save the new property into the new property spot
807 Storage32Impl_WriteProperty(
808 This
->ancestorStorage
,
813 * Find a spot in the property chain for our newly created property.
816 (Storage32Impl
*)This
,
821 * Open the stream to return it.
823 newStream
= StgStreamImpl_Construct(This
, newPropertyIndex
);
828 * Since we are returning a pointer to the interface, we have to nail down
831 StgStreamImpl_AddRef(newStream
);
833 *ppstm
= (IStream32
*)newStream
;
837 return STG_E_INSUFFICIENTMEMORY
;
843 /************************************************************************
844 * Storage32BaseImpl_SetClass (IStorage)
846 * This method will write the specified CLSID in the property of this
849 * See Windows documentation for more details on IStorage methods.
851 HRESULT WINAPI
Storage32BaseImpl_SetClass(
852 Storage32BaseImpl
* This
,
853 REFCLSID clsid
) /* [in] */
855 HRESULT hRes
= E_FAIL
;
856 StgProperty curProperty
;
859 success
= Storage32Impl_ReadProperty(This
->ancestorStorage
,
860 This
->rootPropertySetIndex
,
864 curProperty
.propertyUniqueID
= *clsid
;
866 success
= Storage32Impl_WriteProperty(This
->ancestorStorage
,
867 This
->rootPropertySetIndex
,
876 /************************************************************************
877 ** Storage32Impl implementation
880 /************************************************************************
881 * Storage32Impl_CreateStorage
883 * This method will create the storage object within the provided storage.
885 * See Windows documentation for more details on IStorage methods.
887 HRESULT WINAPI
Storage32Impl_CreateStorage(
889 const OLECHAR32
*pwcsName
, /* [string][in] */
890 DWORD grfMode
, /* [in] */
891 DWORD reserved1
, /* [in] */
892 DWORD reserved2
, /* [in] */
893 IStorage32
**ppstg
) /* [out] */
895 IEnumSTATSTGImpl
*propertyEnumeration
;
896 StgProperty currentProperty
;
897 StgProperty newProperty
;
898 ULONG foundPropertyIndex
;
899 ULONG newPropertyIndex
;
903 * Validate parameters
906 return STG_E_INVALIDPOINTER
;
909 return STG_E_INVALIDNAME
;
912 * Validate the STGM flags
914 if ( FAILED( validateSTGM(grfMode
) ) ||
915 (grfMode
& STGM_DELETEONRELEASE
) )
916 return STG_E_INVALIDFLAG
;
919 * Initialize the out parameter
924 * Create a property enumeration and search the properties
926 propertyEnumeration
= IEnumSTATSTGImpl_Construct( This
->ancestorStorage
,
927 This
->rootPropertySetIndex
);
929 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
932 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
934 if (foundPropertyIndex
!= PROPERTY_NULL
)
937 * An element with this name already exists
939 if (grfMode
& STGM_CREATE
)
940 Storage32Impl_DestroyElement(This
->ancestorStorage
, pwcsName
);
942 return STG_E_FILEALREADYEXISTS
;
946 * memset the empty property
948 memset(&newProperty
, 0, sizeof(StgProperty
));
950 newProperty
.sizeOfNameString
= (lstrlen32W(pwcsName
)+1)*sizeof(WCHAR
);
952 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
953 return STG_E_INVALIDNAME
;
955 lstrcpy32W(newProperty
.name
, pwcsName
);
957 newProperty
.propertyType
= PROPTYPE_STORAGE
;
958 newProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
959 newProperty
.size
.LowPart
= 0;
960 newProperty
.size
.HighPart
= 0;
962 newProperty
.previousProperty
= PROPERTY_NULL
;
963 newProperty
.nextProperty
= PROPERTY_NULL
;
964 newProperty
.dirProperty
= PROPERTY_NULL
;
966 /* call CoFileTime to get the current time
967 newProperty.timeStampS1
968 newProperty.timeStampD1
969 newProperty.timeStampS2
970 newProperty.timeStampD2
973 /* newStorageProperty.propertyUniqueID */
976 * Obtain a free property in the property chain
978 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
981 * Save the new property into the new property spot
983 Storage32Impl_WriteProperty(
984 This
->ancestorStorage
,
989 * Find a spot in the property chain for our newly created property.
997 * Open it to get a pointer to return.
999 hr
= Storage32BaseImpl_OpenStorage(
1000 (Storage32BaseImpl
*)This
,
1001 (OLECHAR32
*)pwcsName
,
1008 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1017 /***************************************************************************
1021 * Get a free property or create a new one.
1023 static ULONG
getFreeProperty(
1024 Storage32Impl
*storage
)
1026 ULONG currentPropertyIndex
= 0;
1027 ULONG newPropertyIndex
= PROPERTY_NULL
;
1028 BOOL32 readSucessful
= TRUE
;
1029 StgProperty currentProperty
;
1034 * Start by reading the root property
1036 readSucessful
= Storage32Impl_ReadProperty(storage
->ancestorStorage
,
1037 currentPropertyIndex
,
1041 if (currentProperty
.sizeOfNameString
== 0)
1044 * The property existis and is available, we found it.
1046 newPropertyIndex
= currentPropertyIndex
;
1052 * We exhausted the property list, we will create more space below
1054 newPropertyIndex
= currentPropertyIndex
;
1056 currentPropertyIndex
++;
1058 } while (newPropertyIndex
== PROPERTY_NULL
);
1061 * grow the property chain
1063 if (! readSucessful
)
1065 StgProperty emptyProperty
;
1066 ULARGE_INTEGER newSize
;
1067 ULONG propertyIndex
;
1068 ULONG lastProperty
= 0;
1069 ULONG blockCount
= 0;
1072 * obtain the new count of property blocks
1074 blockCount
= BlockChainStream_GetCount(
1075 storage
->ancestorStorage
->rootBlockChain
)+1;
1078 * initialize the size used by the property stream
1080 newSize
.HighPart
= 0;
1081 newSize
.LowPart
= storage
->bigBlockSize
* blockCount
;
1084 * add a property block to the property chain
1086 BlockChainStream_SetSize(storage
->ancestorStorage
->rootBlockChain
, newSize
);
1089 * memset the empty property in order to initialize the unused newly
1092 memset(&emptyProperty
, 0, sizeof(StgProperty
));
1097 lastProperty
= storage
->bigBlockSize
/ PROPSET_BLOCK_SIZE
* blockCount
;
1100 propertyIndex
= newPropertyIndex
;
1101 propertyIndex
< lastProperty
;
1104 Storage32Impl_WriteProperty(
1105 storage
->ancestorStorage
,
1111 return newPropertyIndex
;
1114 /****************************************************************************
1118 * Case insensitive comparaison of StgProperty.name by first considering
1121 * Returns <0 when newPrpoerty < currentProperty
1122 * >0 when newPrpoerty > currentProperty
1123 * 0 when newPrpoerty == currentProperty
1125 static LONG
propertyNameCmp(
1126 OLECHAR32
*newProperty
,
1127 OLECHAR32
*currentProperty
)
1129 LONG sizeOfNew
= (lstrlen32W(newProperty
) +1) * sizeof(WCHAR
);
1130 LONG sizeOfCur
= (lstrlen32W(currentProperty
)+1) * sizeof(WCHAR
);
1131 LONG diff
= sizeOfNew
- sizeOfCur
;
1136 * We compare the string themselves only when they are of the same lenght
1138 WCHAR wsnew
[PROPERTY_NAME_MAX_LEN
];
1139 WCHAR wscur
[PROPERTY_NAME_MAX_LEN
];
1141 diff
= lstrcmp32W( (LPCWSTR
)CRTDLL__wcsupr(
1142 lstrcpyn32W(wsnew
, newProperty
, sizeOfNew
)),
1143 (LPCWSTR
)CRTDLL__wcsupr(
1144 lstrcpyn32W(wscur
, currentProperty
, sizeOfCur
)));
1150 /****************************************************************************
1154 * Properly link this new element in the property chain.
1156 static void updatePropertyChain(
1157 Storage32Impl
*storage
,
1158 ULONG newPropertyIndex
,
1159 StgProperty newProperty
)
1161 StgProperty currentProperty
;
1164 * Read the root property
1166 Storage32Impl_ReadProperty(storage
->ancestorStorage
,
1167 storage
->rootPropertySetIndex
,
1170 if (currentProperty
.dirProperty
!= PROPERTY_NULL
)
1173 * The root storage contains some element, therefore, start the research
1174 * for the appropriate location.
1177 ULONG current
, next
, previous
, currentPropertyId
;
1180 * Keep the StgProperty sequence number of the storage first property
1182 currentPropertyId
= currentProperty
.dirProperty
;
1187 Storage32Impl_ReadProperty(storage
->ancestorStorage
,
1188 currentProperty
.dirProperty
,
1191 previous
= currentProperty
.previousProperty
;
1192 next
= currentProperty
.nextProperty
;
1193 current
= currentPropertyId
;
1197 LONG diff
= propertyNameCmp( newProperty
.name
, currentProperty
.name
);
1201 if (previous
!= PROPERTY_NULL
)
1203 Storage32Impl_ReadProperty(storage
->ancestorStorage
,
1210 currentProperty
.previousProperty
= newPropertyIndex
;
1211 Storage32Impl_WriteProperty(storage
->ancestorStorage
,
1219 if (next
!= PROPERTY_NULL
)
1221 Storage32Impl_ReadProperty(storage
->ancestorStorage
,
1228 currentProperty
.nextProperty
= newPropertyIndex
;
1229 Storage32Impl_WriteProperty(storage
->ancestorStorage
,
1236 previous
= currentProperty
.previousProperty
;
1237 next
= currentProperty
.nextProperty
;
1243 * The root storage is empty, link the new property to it's dir property
1245 currentProperty
.dirProperty
= newPropertyIndex
;
1246 Storage32Impl_WriteProperty(storage
->ancestorStorage
,
1247 storage
->rootPropertySetIndex
,
1253 HRESULT WINAPI
Storage32Impl_CopyTo(
1254 Storage32Impl
*This
,
1255 DWORD ciidExclude
, /* [in] */
1256 const IID
*rgiidExclude
,/* [size_is][unique][in] */
1257 SNB32 snbExclude
, /* [unique][in] */
1258 IStorage32
*pstgDest
) /* [unique][in] */
1263 HRESULT WINAPI
Storage32Impl_MoveElementTo(
1264 Storage32Impl
*This
,
1265 const OLECHAR32
*pwcsName
, /* [string][in] */
1266 IStorage32
*pstgDest
, /* [unique][in] */
1267 const OLECHAR32
*pwcsNewName
,/* [string][in] */
1268 DWORD grfFlags
) /* [in] */
1273 HRESULT WINAPI
Storage32Impl_Commit(
1274 Storage32Impl
*This
,
1275 DWORD grfCommitFlags
)/* [in] */
1277 FIXME(ole
, "(%ld): stub!\n", grfCommitFlags
);
1281 HRESULT WINAPI
Storage32Impl_Revert(
1282 Storage32Impl
* This
)
1287 /*************************************************************************
1290 * Stategy: This implementation is build this way for simplicity not for speed.
1291 * I allways delete the top most element of the enumeration and adjust
1292 * the deleted element pointer all the time. This takes longer to
1293 * do but allow to reinvoke DestroyElement whenever we encounter a
1294 * storage object. The optimisation reside in the usage of another
1295 * enumeration stategy that would give all the leaves of a storage
1296 * first. (postfix order)
1298 HRESULT WINAPI
Storage32Impl_DestroyElement(
1299 Storage32Impl
*This
,
1300 const OLECHAR32
*pwcsName
)/* [string][in] */
1302 IEnumSTATSTGImpl
* propertyEnumeration
;
1305 StgProperty propertyToDelete
;
1306 StgProperty parentProperty
;
1307 ULONG foundPropertyIndexToDelete
;
1308 ULONG typeOfRelation
;
1309 ULONG parentPropertyId
;
1312 * Perform a sanity check on the parameters.
1315 return STG_E_INVALIDPOINTER
;
1318 * Create a property enumeration to search the property with the given name
1320 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
1321 This
->ancestorStorage
,
1322 This
->rootPropertySetIndex
);
1324 foundPropertyIndexToDelete
= IEnumSTATSTGImpl_FindProperty(
1325 propertyEnumeration
,
1329 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1331 if ( foundPropertyIndexToDelete
== PROPERTY_NULL
)
1333 return STG_E_FILENOTFOUND
;
1337 * Find the parent property of the property to delete (the one that
1338 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1339 * the parent is This. Otherwise, the parent is one of it's sibling...
1343 * First, read This's StgProperty..
1345 res
= Storage32Impl_ReadProperty(
1346 This
->ancestorStorage
,
1347 This
->rootPropertySetIndex
,
1353 * Second, check to see if by any chance the actual storage (This) is not
1354 * the parent of the property to delete... We never know...
1356 if ( parentProperty
.dirProperty
== foundPropertyIndexToDelete
)
1359 * Set data as it would have been done in the else part...
1361 typeOfRelation
= PROPERTY_RELATION_DIR
;
1362 parentPropertyId
= This
->rootPropertySetIndex
;
1367 * Create a property enumeration to search the parent properties, and
1368 * delete it once done.
1370 IEnumSTATSTGImpl
* propertyEnumeration2
;
1372 propertyEnumeration2
= IEnumSTATSTGImpl_Construct(
1373 This
->ancestorStorage
,
1374 This
->rootPropertySetIndex
);
1376 typeOfRelation
= IEnumSTATSTGImpl_FindParentProperty(
1377 propertyEnumeration2
,
1378 foundPropertyIndexToDelete
,
1382 IEnumSTATSTGImpl_Destroy(propertyEnumeration2
);
1385 if ( propertyToDelete
.propertyType
== PROPTYPE_STORAGE
)
1387 hr
= deleteStorageProperty(
1389 propertyToDelete
.name
);
1391 else if ( propertyToDelete
.propertyType
== PROPTYPE_STREAM
)
1393 hr
= deleteStreamProperty(
1395 foundPropertyIndexToDelete
,
1403 * Adjust the property chain
1405 hr
= adjustPropertyChain(
1416 /*********************************************************************
1420 * Perform the deletion of a complete storage node
1423 static HRESULT
deleteStorageProperty(
1424 Storage32Impl
*parentStorage
,
1425 OLECHAR32
*propertyToDeleteName
)
1427 IEnumSTATSTG
*elements
= 0;
1428 IStorage32
*childStorage
= 0;
1429 STATSTG currentElement
;
1431 HRESULT destroyHr
= S_OK
;
1434 * Open the storage and enumerate it
1436 hr
= Storage32BaseImpl_OpenStorage(
1437 (Storage32BaseImpl
*)parentStorage
,
1438 propertyToDeleteName
,
1440 STGM_SHARE_EXCLUSIVE
,
1451 * Enumerate the elements
1453 IStorage32_EnumElements( childStorage
, 0, 0, 0, &elements
);
1458 * Obtain the next element
1460 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1463 destroyHr
= Storage32Impl_DestroyElement(
1464 (Storage32Impl
*)childStorage
,
1465 (OLECHAR32
*)currentElement
.pwcsName
);
1467 CoTaskMemFree(currentElement
.pwcsName
);
1471 * We need to Reset the enumeration every time because we delete elements
1472 * and the enumeration could be invalid
1474 IEnumSTATSTG_Reset(elements
);
1476 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1478 IStorage32_Release(childStorage
);
1479 IEnumSTATSTG_Release(elements
);
1484 /*********************************************************************
1488 * Perform the deletion of a stream node
1491 static HRESULT
deleteStreamProperty(
1492 Storage32Impl
*parentStorage
,
1493 ULONG indexOfPropertyToDelete
,
1494 StgProperty propertyToDelete
)
1498 ULARGE_INTEGER size
;
1503 hr
= Storage32BaseImpl_OpenStream(
1504 (Storage32BaseImpl
*)parentStorage
,
1505 (OLECHAR32
*)propertyToDelete
.name
,
1507 STGM_SHARE_EXCLUSIVE
,
1519 hr
= IStream32_SetSize(pis
, size
);
1527 * Invalidate the property by zeroing it's name member.
1529 propertyToDelete
.sizeOfNameString
= 0;
1532 * Here we should re-read the property so we get the updated pointer
1533 * but since we are here to zap it, I don't do it...
1536 Storage32Impl_WriteProperty(
1537 parentStorage
->ancestorStorage
,
1538 indexOfPropertyToDelete
,
1544 /*********************************************************************
1548 * Finds a placeholder for the StgProperty within the Storage
1551 static HRESULT
findPlaceholder(
1552 Storage32Impl
*storage
,
1553 ULONG propertyIndexToStore
,
1554 ULONG storePropertyIndex
,
1555 INT32 typeOfRelation
)
1557 StgProperty storeProperty
;
1562 * Read the storage property
1564 res
= Storage32Impl_ReadProperty(
1565 storage
->ancestorStorage
,
1574 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1576 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1578 return findPlaceholder(
1580 propertyIndexToStore
,
1581 storeProperty
.previousProperty
,
1586 storeProperty
.previousProperty
= propertyIndexToStore
;
1589 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1591 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1593 return findPlaceholder(
1595 propertyIndexToStore
,
1596 storeProperty
.nextProperty
,
1601 storeProperty
.nextProperty
= propertyIndexToStore
;
1604 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1606 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1608 return findPlaceholder(
1610 propertyIndexToStore
,
1611 storeProperty
.dirProperty
,
1616 storeProperty
.dirProperty
= propertyIndexToStore
;
1620 hr
= Storage32Impl_WriteProperty(
1621 storage
->ancestorStorage
,
1633 /*************************************************************************
1637 * This method takes the previous and the next property link of a property
1638 * to be deleted and find them a place in the Storage.
1640 static HRESULT
adjustPropertyChain(
1641 Storage32Impl
*This
,
1642 StgProperty propertyToDelete
,
1643 StgProperty parentProperty
,
1644 ULONG parentPropertyId
,
1645 INT32 typeOfRelation
)
1647 ULONG newLinkProperty
= PROPERTY_NULL
;
1648 BOOL32 needToFindAPlaceholder
= FALSE
;
1649 ULONG storeNode
= PROPERTY_NULL
;
1650 ULONG toStoreNode
= PROPERTY_NULL
;
1651 INT32 relationType
= 0;
1655 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1657 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1660 * Set the parent previous to the property to delete previous
1662 newLinkProperty
= propertyToDelete
.previousProperty
;
1664 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1667 * We also need to find a storage for the other link, setup variables
1668 * to do this at the end...
1670 needToFindAPlaceholder
= TRUE
;
1671 storeNode
= propertyToDelete
.previousProperty
;
1672 toStoreNode
= propertyToDelete
.nextProperty
;
1673 relationType
= PROPERTY_RELATION_NEXT
;
1676 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1679 * Set the parent previous to the property to delete next
1681 newLinkProperty
= propertyToDelete
.nextProperty
;
1685 * Link it for real...
1687 parentProperty
.previousProperty
= newLinkProperty
;
1690 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1692 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1695 * Set the parent next to the property to delete next previous
1697 newLinkProperty
= propertyToDelete
.previousProperty
;
1699 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1702 * We also need to find a storage for the other link, setup variables
1703 * to do this at the end...
1705 needToFindAPlaceholder
= TRUE
;
1706 storeNode
= propertyToDelete
.previousProperty
;
1707 toStoreNode
= propertyToDelete
.nextProperty
;
1708 relationType
= PROPERTY_RELATION_NEXT
;
1711 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1714 * Set the parent next to the property to delete next
1716 newLinkProperty
= propertyToDelete
.nextProperty
;
1720 * Link it for real...
1722 parentProperty
.nextProperty
= newLinkProperty
;
1724 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1726 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1729 * Set the parent dir to the property to delete previous
1731 newLinkProperty
= propertyToDelete
.previousProperty
;
1733 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1736 * We also need to find a storage for the other link, setup variables
1737 * to do this at the end...
1739 needToFindAPlaceholder
= TRUE
;
1740 storeNode
= propertyToDelete
.previousProperty
;
1741 toStoreNode
= propertyToDelete
.nextProperty
;
1742 relationType
= PROPERTY_RELATION_NEXT
;
1745 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1748 * Set the parent dir to the property to delete next
1750 newLinkProperty
= propertyToDelete
.nextProperty
;
1754 * Link it for real...
1756 parentProperty
.dirProperty
= newLinkProperty
;
1760 * Write back the parent property
1762 res
= Storage32Impl_WriteProperty(
1763 This
->ancestorStorage
,
1772 * If a placeholder is required for the other link, then, find one and
1773 * get out of here...
1775 if (needToFindAPlaceholder
)
1777 hr
= findPlaceholder(
1788 HRESULT WINAPI
Storage32Impl_SetElementTimes(
1789 Storage32Impl
*This
,
1790 const OLECHAR32
*pwcsName
,/* [string][in] */
1791 const FILETIME
*pctime
, /* [in] */
1792 const FILETIME
*patime
, /* [in] */
1793 const FILETIME
*pmtime
) /* [in] */
1798 HRESULT WINAPI
Storage32Impl_SetStateBits(
1799 Storage32Impl
*This
,
1800 DWORD grfStateBits
,/* [in] */
1801 DWORD grfMask
) /* [in] */
1806 HRESULT
Storage32Impl_Construct(
1807 Storage32Impl
* This
,
1812 StgProperty currentProperty
;
1813 BOOL32 readSucessful
;
1814 ULONG currentPropertyIndex
;
1816 if ( FAILED( validateSTGM(openFlags
) ))
1817 return STG_E_INVALIDFLAG
;
1819 memset(This
, 0, sizeof(Storage32Impl
));
1822 * Initialize the virtual fgunction table.
1824 This
->lpvtbl
= &Storage32Impl_VTable
;
1825 This
->v_destructor
= &Storage32Impl_Destroy
;
1828 * This is the top-level storage so initialize the ancester pointer
1831 This
->ancestorStorage
= This
;
1834 * Initialize the physical support of the storage.
1836 This
->hFile
= hFile
;
1839 * Initialize the big block cache.
1841 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
1842 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
1843 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
, This
->bigBlockSize
);
1845 if (openFlags
& STGM_CREATE
)
1847 ULARGE_INTEGER size
;
1848 BYTE
* bigBlockBuffer
;
1851 * Initialize all header variables:
1852 * - The big block depot consists of one block and it is at block 0
1853 * - The properties start at block 1
1854 * - There is no small block depot
1856 memset( This
->bigBlockDepotStart
,
1858 sizeof(This
->bigBlockDepotStart
));
1860 This
->bigBlockDepotCount
= 1;
1861 This
->bigBlockDepotStart
[0] = 0;
1862 This
->rootStartBlock
= 1;
1863 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
1864 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
1865 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
1866 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
1867 This
->extBigBlockDepotCount
= 0;
1869 Storage32Impl_SaveFileHeader(This
);
1872 * Add one block for the big block depot and one block for the properties
1875 size
.LowPart
= This
->bigBlockSize
* 3;
1876 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
1879 * Initialize the big block depot
1881 bigBlockBuffer
= Storage32Impl_GetBigBlock(This
, 0);
1882 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
1883 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
1884 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
1885 Storage32Impl_ReleaseBigBlock(This
, bigBlockBuffer
);
1890 * Load the header for the file.
1892 Storage32Impl_LoadFileHeader(This
);
1896 * Create the block chain abstractions.
1898 This
->rootBlockChain
=
1899 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
1901 This
->smallBlockDepotChain
= BlockChainStream_Construct(
1903 &This
->smallBlockDepotStart
,
1907 * Write the root property
1909 if (openFlags
& STGM_CREATE
)
1911 StgProperty rootProp
;
1913 * Initialize the property chain
1915 memset(&rootProp
, 0, sizeof(rootProp
));
1916 lstrcpyAtoW(rootProp
.name
, rootPropertyName
);
1918 rootProp
.sizeOfNameString
= (lstrlen32W(rootProp
.name
)+1) * sizeof(WCHAR
);
1919 rootProp
.propertyType
= PROPTYPE_ROOT
;
1920 rootProp
.previousProperty
= PROPERTY_NULL
;
1921 rootProp
.nextProperty
= PROPERTY_NULL
;
1922 rootProp
.dirProperty
= PROPERTY_NULL
;
1923 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
1924 rootProp
.size
.HighPart
= 0;
1925 rootProp
.size
.LowPart
= 0;
1927 Storage32Impl_WriteProperty(This
, 0, &rootProp
);
1931 * Find the ID of the root int he property sets.
1933 currentPropertyIndex
= 0;
1937 readSucessful
= Storage32Impl_ReadProperty(
1939 currentPropertyIndex
,
1944 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
1945 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
1947 This
->rootPropertySetIndex
= currentPropertyIndex
;
1951 currentPropertyIndex
++;
1953 } while (readSucessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
1962 * Create the block chain abstraction for the small block root chain.
1964 This
->smallBlockRootChain
= BlockChainStream_Construct(
1967 This
->rootPropertySetIndex
);
1972 void Storage32Impl_Destroy(
1973 Storage32Impl
* This
)
1975 BlockChainStream_Destroy(This
->smallBlockRootChain
);
1976 BlockChainStream_Destroy(This
->rootBlockChain
);
1977 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
1979 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
1983 /******************************************************************************
1984 * Storage32Impl_GetNextFreeBigBlock
1986 * Returns the index of the next free big block.
1987 * If the big block depot is filled, this method will enlarge it.
1989 * TODO: Handle the case when the big block depot becomes bigger
1990 * than COUNT_BBDEPOTINHEADER.
1992 ULONG
Storage32Impl_GetNextFreeBigBlock(
1993 Storage32Impl
* This
)
1995 ULONG depotBlockIndexPos
;
1997 ULONG depotBlockOffset
;
1998 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
1999 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2001 ULONG blockNoInSequence
= 0;
2004 * Scan the entire big block depot until we find a block marked free
2006 while ( (depotIndex
< COUNT_BBDEPOTINHEADER
) &&
2007 (nextBlockIndex
!= BLOCK_UNUSED
))
2009 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2011 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2014 * No more space in the big block depot, we have to enlarge it
2016 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2017 depotBuffer
= Storage32Impl_GetBigBlock(This
, depotBlockIndexPos
);
2019 depotBlockOffset
= 0;
2021 /* mark this block as being part of the big block depot
2023 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, BLOCK_SPECIAL
);
2024 depotBlockOffset
+= sizeof(ULONG
);
2026 /* initialize blocks as free
2028 while ((depotBlockOffset
< blocksPerDepot
))
2030 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, BLOCK_UNUSED
);
2031 depotBlockOffset
+= sizeof(ULONG
);
2034 Storage32Impl_ReleaseBigBlock(This
, depotBuffer
);
2036 /* Save the information to the file header
2038 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2039 This
->bigBlockDepotCount
++;
2040 Storage32Impl_SaveFileHeader(This
);
2043 depotBuffer
= Storage32Impl_GetROBigBlock(This
, depotBlockIndexPos
);
2045 if (depotBuffer
!= 0)
2047 depotBlockOffset
= 0;
2049 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2050 ( nextBlockIndex
!= BLOCK_UNUSED
))
2052 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2054 if (nextBlockIndex
!= BLOCK_UNUSED
)
2055 blockNoInSequence
++;
2057 depotBlockOffset
+= sizeof(ULONG
);
2060 Storage32Impl_ReleaseBigBlock(This
, depotBuffer
);
2066 return blockNoInSequence
;
2069 /******************************************************************************
2070 * Storage32Impl_FreeBigBlock
2072 * This method will flag the specified block as free in the big block depot.
2074 void Storage32Impl_FreeBigBlock(
2075 Storage32Impl
* This
,
2078 Storage32Impl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2081 /************************************************************************
2082 * Storage32Impl_GetNextBlockInChain
2084 * This method will retrieve the block index of the next big block in
2087 * Params: This - Pointer to the Storage object.
2088 * blockIndex - Index of the block to retrieve the chain
2091 * Returns: This method returns the index of the next block in the chain.
2092 * It will return the constants:
2093 * BLOCK_SPECIAL - If the block given was not part of a
2095 * BLOCK_END_OF_CHAIN - If the block given was the last in
2097 * BLOCK_UNUSED - If the block given was not past of a chain
2100 * See Windows documentation for more details on IStorage methods.
2102 ULONG
Storage32Impl_GetNextBlockInChain(
2103 Storage32Impl
* This
,
2106 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2107 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2108 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2109 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2111 ULONG depotBlockIndexPos
;
2113 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2114 assert(depotBlockCount
< COUNT_BBDEPOTINHEADER
);
2116 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2118 depotBuffer
= Storage32Impl_GetROBigBlock(This
, depotBlockIndexPos
);
2122 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2124 Storage32Impl_ReleaseBigBlock(This
, depotBuffer
);
2127 return nextBlockIndex
;
2130 /******************************************************************************
2131 * Storage32Impl_SetNextBlockInChain
2133 * This method will write the index of the specified block's next block
2134 * in the big block depot.
2136 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2139 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2140 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2141 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2144 void Storage32Impl_SetNextBlockInChain(
2145 Storage32Impl
* This
,
2149 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2150 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2151 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2152 ULONG depotBlockIndexPos
;
2155 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2156 assert(depotBlockCount
< COUNT_BBDEPOTINHEADER
);
2158 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2160 depotBuffer
= Storage32Impl_GetBigBlock(This
, depotBlockIndexPos
);
2164 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2165 Storage32Impl_ReleaseBigBlock(This
, depotBuffer
);
2171 /******************************************************************************
2172 * Storage32Impl_LoadFileHeader
2174 * This method will read in the file header, i.e. big block index -1.
2176 HRESULT
Storage32Impl_LoadFileHeader(
2177 Storage32Impl
* This
)
2179 HRESULT hr
= STG_E_FILENOTFOUND
;
2180 void* headerBigBlock
= NULL
;
2184 * Get a pointer to the big block of data containing the header.
2186 headerBigBlock
= Storage32Impl_GetROBigBlock(This
, -1);
2189 * Extract the information from the header.
2191 if (headerBigBlock
!=0)
2194 * Check for the "magic number" signature and return an error if it is not
2197 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2199 Storage32Impl_ReleaseBigBlock(This
, headerBigBlock
);
2200 return STG_E_OLDFORMAT
;
2203 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2205 Storage32Impl_ReleaseBigBlock(This
, headerBigBlock
);
2206 return STG_E_INVALIDHEADER
;
2209 StorageUtl_ReadWord(
2211 OFFSET_BIGBLOCKSIZEBITS
,
2212 &This
->bigBlockSizeBits
);
2214 StorageUtl_ReadWord(
2216 OFFSET_SMALLBLOCKSIZEBITS
,
2217 &This
->smallBlockSizeBits
);
2219 StorageUtl_ReadDWord(
2221 OFFSET_BBDEPOTCOUNT
,
2222 &This
->bigBlockDepotCount
);
2224 StorageUtl_ReadDWord(
2226 OFFSET_ROOTSTARTBLOCK
,
2227 &This
->rootStartBlock
);
2229 StorageUtl_ReadDWord(
2231 OFFSET_SBDEPOTSTART
,
2232 &This
->smallBlockDepotStart
);
2234 StorageUtl_ReadDWord(
2236 OFFSET_EXTBBDEPOTSTART
,
2237 &This
->extBigBlockDepotStart
);
2239 StorageUtl_ReadDWord(
2241 OFFSET_EXTBBDEPOTCOUNT
,
2242 &This
->extBigBlockDepotCount
);
2244 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2246 StorageUtl_ReadDWord(
2248 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2249 &(This
->bigBlockDepotStart
[index
]));
2253 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2257 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2258 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2262 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2263 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2267 * Right now, the code is making some assumptions about the size of the
2268 * blocks, just make sure they are what we're expecting.
2270 assert( (This
->bigBlockSize
==DEF_BIG_BLOCK_SIZE
) &&
2271 (This
->smallBlockSize
==DEF_SMALL_BLOCK_SIZE
));
2274 * Release the block.
2276 Storage32Impl_ReleaseBigBlock(This
, headerBigBlock
);
2282 /******************************************************************************
2283 * Storage32Impl_SaveFileHeader
2285 * This method will save to the file the header, i.e. big block -1.
2287 void Storage32Impl_SaveFileHeader(
2288 Storage32Impl
* This
)
2290 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2295 * Get a pointer to the big block of data containing the header.
2297 success
= Storage32Impl_ReadBigBlock(This
, -1, headerBigBlock
);
2300 * If the block read failed, the file is probably new.
2305 * Initialize for all unknown fields.
2307 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
2310 * Initialize the magic number.
2312 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
2315 * And a bunch of things we don't know what they mean
2317 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
2318 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
2319 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
2320 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
2321 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
2325 * Write the information to the header.
2327 if (headerBigBlock
!=0)
2329 StorageUtl_WriteWord(
2331 OFFSET_BIGBLOCKSIZEBITS
,
2332 This
->bigBlockSizeBits
);
2334 StorageUtl_WriteWord(
2336 OFFSET_SMALLBLOCKSIZEBITS
,
2337 This
->smallBlockSizeBits
);
2339 StorageUtl_WriteDWord(
2341 OFFSET_BBDEPOTCOUNT
,
2342 This
->bigBlockDepotCount
);
2344 StorageUtl_WriteDWord(
2346 OFFSET_ROOTSTARTBLOCK
,
2347 This
->rootStartBlock
);
2349 StorageUtl_WriteDWord(
2351 OFFSET_SBDEPOTSTART
,
2352 This
->smallBlockDepotStart
);
2354 StorageUtl_WriteDWord(
2356 OFFSET_EXTBBDEPOTSTART
,
2357 This
->extBigBlockDepotStart
);
2359 StorageUtl_WriteDWord(
2361 OFFSET_EXTBBDEPOTCOUNT
,
2362 This
->extBigBlockDepotCount
);
2364 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2366 StorageUtl_WriteDWord(
2368 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2369 (This
->bigBlockDepotStart
[index
]));
2374 * Write the big block back to the file.
2376 Storage32Impl_WriteBigBlock(This
, -1, headerBigBlock
);
2379 /******************************************************************************
2380 * Storage32Impl_ReadProperty
2382 * This method will read the specified property from the property chain.
2384 BOOL32
Storage32Impl_ReadProperty(
2385 Storage32Impl
* This
,
2387 StgProperty
* buffer
)
2389 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2390 ULARGE_INTEGER offsetInPropSet
;
2391 BOOL32 readSucessful
;
2394 offsetInPropSet
.HighPart
= 0;
2395 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
2397 readSucessful
= BlockChainStream_ReadAt(
2398 This
->rootBlockChain
,
2406 memset(buffer
->name
, 0, sizeof(buffer
->name
));
2409 currentProperty
+OFFSET_PS_NAME
,
2410 PROPERTY_NAME_BUFFER_LEN
);
2412 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
2414 StorageUtl_ReadWord(
2416 OFFSET_PS_NAMELENGTH
,
2417 &buffer
->sizeOfNameString
);
2419 StorageUtl_ReadDWord(
2421 OFFSET_PS_PREVIOUSPROP
,
2422 &buffer
->previousProperty
);
2424 StorageUtl_ReadDWord(
2427 &buffer
->nextProperty
);
2429 StorageUtl_ReadDWord(
2432 &buffer
->dirProperty
);
2434 StorageUtl_ReadGUID(
2437 &buffer
->propertyUniqueID
);
2439 StorageUtl_ReadDWord(
2442 &buffer
->timeStampS1
);
2444 StorageUtl_ReadDWord(
2447 &buffer
->timeStampD1
);
2449 StorageUtl_ReadDWord(
2452 &buffer
->timeStampS2
);
2454 StorageUtl_ReadDWord(
2457 &buffer
->timeStampD2
);
2459 StorageUtl_ReadDWord(
2461 OFFSET_PS_STARTBLOCK
,
2462 &buffer
->startingBlock
);
2464 StorageUtl_ReadDWord(
2467 &buffer
->size
.LowPart
);
2469 buffer
->size
.HighPart
= 0;
2472 return readSucessful
;
2475 /*********************************************************************
2476 * Write the specified property into the property chain
2478 BOOL32
Storage32Impl_WriteProperty(
2479 Storage32Impl
* This
,
2481 StgProperty
* buffer
)
2483 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2484 ULARGE_INTEGER offsetInPropSet
;
2485 BOOL32 writeSucessful
;
2488 offsetInPropSet
.HighPart
= 0;
2489 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
2491 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
2494 currentProperty
+ OFFSET_PS_NAME
,
2496 PROPERTY_NAME_BUFFER_LEN
);
2498 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
2501 * Reassign the size in case of mistake....
2503 buffer
->sizeOfNameString
= (lstrlen32W(buffer
->name
)+1) * sizeof(WCHAR
);
2505 StorageUtl_WriteWord(
2507 OFFSET_PS_NAMELENGTH
,
2508 buffer
->sizeOfNameString
);
2510 StorageUtl_WriteDWord(
2512 OFFSET_PS_PREVIOUSPROP
,
2513 buffer
->previousProperty
);
2515 StorageUtl_WriteDWord(
2518 buffer
->nextProperty
);
2520 StorageUtl_WriteDWord(
2523 buffer
->dirProperty
);
2525 StorageUtl_WriteGUID(
2528 &buffer
->propertyUniqueID
);
2530 StorageUtl_WriteDWord(
2533 buffer
->timeStampS1
);
2535 StorageUtl_WriteDWord(
2538 buffer
->timeStampD1
);
2540 StorageUtl_WriteDWord(
2543 buffer
->timeStampS2
);
2545 StorageUtl_WriteDWord(
2548 buffer
->timeStampD2
);
2550 StorageUtl_WriteDWord(
2552 OFFSET_PS_STARTBLOCK
,
2553 buffer
->startingBlock
);
2555 StorageUtl_WriteDWord(
2558 buffer
->size
.LowPart
);
2560 writeSucessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
2565 return writeSucessful
;
2568 BOOL32
Storage32Impl_ReadBigBlock(
2569 Storage32Impl
* This
,
2573 void* bigBlockBuffer
;
2575 bigBlockBuffer
= Storage32Impl_GetROBigBlock(This
, blockIndex
);
2577 if (bigBlockBuffer
!=0)
2579 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
2581 Storage32Impl_ReleaseBigBlock(This
, bigBlockBuffer
);
2589 BOOL32
Storage32Impl_WriteBigBlock(
2590 Storage32Impl
* This
,
2594 void* bigBlockBuffer
;
2596 bigBlockBuffer
= Storage32Impl_GetBigBlock(This
, blockIndex
);
2598 if (bigBlockBuffer
!=0)
2600 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
2602 Storage32Impl_ReleaseBigBlock(This
, bigBlockBuffer
);
2610 void* Storage32Impl_GetROBigBlock(
2611 Storage32Impl
* This
,
2614 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
2617 void* Storage32Impl_GetBigBlock(
2618 Storage32Impl
* This
,
2621 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
2624 void Storage32Impl_ReleaseBigBlock(
2625 Storage32Impl
* This
,
2628 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
2631 /******************************************************************************
2632 * Storage32Impl_SmallBlocksToBigBlocks
2634 * This method will convert a small block chain to a big block chain.
2635 * The small block chain will be destroyed.
2637 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
2638 Storage32Impl
* This
,
2639 SmallBlockChainStream
** ppsbChain
)
2641 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
2642 ULARGE_INTEGER size
, offset
;
2643 ULONG cbRead
, cbWritten
;
2644 ULONG propertyIndex
;
2645 BOOL32 successRead
, successWrite
;
2646 StgProperty chainProperty
;
2647 BYTE buffer
[DEF_SMALL_BLOCK_SIZE
];
2648 BlockChainStream
*bbTempChain
= NULL
;
2649 BlockChainStream
*bigBlockChain
= NULL
;
2652 * Create a temporary big block chain that doesn't have
2653 * an associated property. This temporary chain will be
2654 * used to copy data from small blocks to big blocks.
2656 bbTempChain
= BlockChainStream_Construct(This
,
2661 * Grow the big block chain.
2663 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
2664 BlockChainStream_SetSize(bbTempChain
, size
);
2667 * Copy the contents of the small block chain to the big block chain
2668 * by small block size increments.
2671 offset
.HighPart
= 0;
2675 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
2681 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
2686 offset
.LowPart
+= This
->smallBlockSize
;
2688 } while (successRead
&& successWrite
);
2690 assert(cbRead
== cbWritten
);
2693 * Destroy the small block chain.
2695 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
2698 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
2699 SmallBlockChainStream_Destroy(*ppsbChain
);
2703 * Change the property information. This chain is now a big block chain
2704 * and it doesn't reside in the small blocks chain anymore.
2706 Storage32Impl_ReadProperty(This
, propertyIndex
, &chainProperty
);
2708 chainProperty
.startingBlock
= bbHeadOfChain
;
2710 Storage32Impl_WriteProperty(This
, propertyIndex
, &chainProperty
);
2713 * Destroy the temporary propertyless big block chain.
2714 * Create a new big block chain associated with this property.
2716 BlockChainStream_Destroy(bbTempChain
);
2717 bigBlockChain
= BlockChainStream_Construct(This
,
2721 return bigBlockChain
;
2724 /******************************************************************************
2725 ** Storage32InternalImpl implementation
2728 Storage32InternalImpl
* Storage32InternalImpl_Construct(
2729 Storage32Impl
* ancestorStorage
,
2730 ULONG rootPropertyIndex
)
2732 Storage32InternalImpl
* newStorage
;
2735 * Allocate space for the new storage object
2737 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32InternalImpl
));
2741 memset(newStorage
, 0, sizeof(Storage32InternalImpl
));
2744 * Initialize the virtual function table.
2746 newStorage
->lpvtbl
= &Storage32InternalImpl_VTable
;
2747 newStorage
->v_destructor
= &Storage32InternalImpl_Destroy
;
2750 * Keep the ancestor storage pointer and nail a reference to it.
2752 newStorage
->ancestorStorage
= ancestorStorage
;
2753 Storage32BaseImpl_AddRef((Storage32BaseImpl
*)(newStorage
->ancestorStorage
));
2756 * Keep the index of the root property set for this storage,
2758 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
2766 void Storage32InternalImpl_Destroy(
2767 Storage32InternalImpl
* This
)
2769 HeapFree(GetProcessHeap(), 0, This
);
2772 /******************************************************************************
2774 ** Storage32InternalImpl_Commit
2776 ** The non-root storages cannot be opened in transacted mode thus this function
2779 HRESULT WINAPI
Storage32InternalImpl_Commit(
2780 Storage32InternalImpl
* This
,
2781 DWORD grfCommitFlags
) /* [in] */
2786 /******************************************************************************
2788 ** Storage32InternalImpl_Revert
2790 ** The non-root storages cannot be opened in transacted mode thus this function
2793 HRESULT WINAPI
Storage32InternalImpl_Revert(
2794 Storage32InternalImpl
* This
)
2799 /******************************************************************************
2800 ** IEnumSTATSTGImpl implementation
2803 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
2804 Storage32Impl
* parentStorage
,
2805 ULONG firstPropertyNode
)
2807 IEnumSTATSTGImpl
* newEnumeration
;
2809 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
2811 if (newEnumeration
!=0)
2814 * Set-up the virtual function table and reference count.
2816 newEnumeration
->lpvtbl
= &IEnumSTATSTGImpl_Vtbl
;
2817 newEnumeration
->ref
= 0;
2820 * We want to nail-down the reference to the storage in case the
2821 * enumeration out-lives the storage in the client application.
2823 newEnumeration
->parentStorage
= parentStorage
;
2824 IStorage32_AddRef(newEnumeration
->parentStorage
);
2826 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
2829 * Initialize the search stack
2831 newEnumeration
->stackSize
= 0;
2832 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
2833 newEnumeration
->stackToVisit
=
2834 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
2837 * Make sure the current node of the iterator is the first one.
2839 IEnumSTATSTGImpl_Reset(newEnumeration
);
2842 return newEnumeration
;
2845 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
2847 IStorage32_Release(This
->parentStorage
);
2848 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
2849 HeapFree(GetProcessHeap(), 0, This
);
2852 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
2853 IEnumSTATSTGImpl
* This
,
2858 * Perform a sanity check on the parameters.
2861 return E_INVALIDARG
;
2864 * Initialize the return parameter.
2869 * Compare the riid with the interface IDs implemented by this object.
2871 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
2873 *ppvObject
= (IEnumSTATSTG
*)This
;
2875 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
2877 *ppvObject
= (IEnumSTATSTG
*)This
;
2881 * Check that we obtained an interface.
2883 if ((*ppvObject
)==0)
2884 return E_NOINTERFACE
;
2887 * Query Interface always increases the reference count by one when it is
2890 IEnumSTATSTGImpl_AddRef(This
);
2895 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
2896 IEnumSTATSTGImpl
* This
)
2902 ULONG WINAPI
IEnumSTATSTGImpl_Release(
2903 IEnumSTATSTGImpl
* This
)
2911 * If the reference count goes down to 0, perform suicide.
2915 IEnumSTATSTGImpl_Destroy(This
);
2921 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
2922 IEnumSTATSTGImpl
* This
,
2925 ULONG
* pceltFetched
)
2927 StgProperty currentProperty
;
2928 STATSTG
* currentReturnStruct
= rgelt
;
2929 ULONG objectFetched
= 0;
2930 ULONG currentSearchNode
;
2933 * Perform a sanity check on the parameters.
2935 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
2936 return E_INVALIDARG
;
2939 * To avoid the special case, get another pointer to a ULONG value if
2940 * the caller didn't supply one.
2942 if (pceltFetched
==0)
2943 pceltFetched
= &objectFetched
;
2946 * Start the iteration, we will iterate until we hit the end of the
2947 * linked list or until we hit the number of items to iterate through
2952 * Start with the node at the top of the stack.
2954 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
2956 while ( ( *pceltFetched
< celt
) &&
2957 ( currentSearchNode
!=PROPERTY_NULL
) )
2960 * Remove the top node from the stack
2962 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
2965 * Read the property from the storage.
2967 Storage32Impl_ReadProperty(This
->parentStorage
,
2972 * Copy the information to the return buffer.
2974 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
2979 * Step to the next item in the iteration
2982 currentReturnStruct
++;
2985 * Push the next search node in the search stack.
2987 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
2990 * continue the iteration.
2992 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
2995 if (*pceltFetched
== celt
)
3002 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3003 IEnumSTATSTGImpl
* This
,
3006 StgProperty currentProperty
;
3007 ULONG objectFetched
= 0;
3008 ULONG currentSearchNode
;
3011 * Start with the node at the top of the stack.
3013 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3015 while ( (objectFetched
< celt
) &&
3016 (currentSearchNode
!=PROPERTY_NULL
) )
3019 * Remove the top node from the stack
3021 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3024 * Read the property from the storage.
3026 Storage32Impl_ReadProperty(This
->parentStorage
,
3031 * Step to the next item in the iteration
3036 * Push the next search node in the search stack.
3038 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3041 * continue the iteration.
3043 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3046 if (objectFetched
== celt
)
3052 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3053 IEnumSTATSTGImpl
* This
)
3055 StgProperty rootProperty
;
3056 BOOL32 readSucessful
;
3059 * Re-initialize the search stack to an empty stack
3061 This
->stackSize
= 0;
3064 * Read the root property from the storage.
3066 readSucessful
= Storage32Impl_ReadProperty(
3067 This
->parentStorage
,
3068 This
->firstPropertyNode
,
3073 assert(rootProperty
.sizeOfNameString
!=0);
3076 * Push the search node in the search stack.
3078 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3084 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3085 IEnumSTATSTGImpl
* This
,
3086 IEnumSTATSTG
** ppenum
)
3088 IEnumSTATSTGImpl
* newClone
;
3091 * Perform a sanity check on the parameters.
3094 return E_INVALIDARG
;
3096 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3097 This
->firstPropertyNode
);
3101 * The new clone enumeration must point to the same current node as
3104 newClone
->stackSize
= This
->stackSize
;
3105 newClone
->stackMaxSize
= This
->stackMaxSize
;
3106 newClone
->stackToVisit
=
3107 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3110 newClone
->stackToVisit
,
3112 sizeof(ULONG
) * newClone
->stackSize
);
3115 * Don't forget to nail down a reference to the clone before
3118 IEnumSTATSTGImpl_AddRef(newClone
);
3120 *ppenum
= (IEnumSTATSTG
*)newClone
;
3125 INT32
IEnumSTATSTGImpl_FindParentProperty(
3126 IEnumSTATSTGImpl
*This
,
3127 ULONG childProperty
,
3128 StgProperty
*currentProperty
,
3131 ULONG currentSearchNode
;
3135 * To avoid the special case, get another pointer to a ULONG value if
3136 * the caller didn't supply one.
3139 thisNodeId
= &foundNode
;
3142 * Start with the node at the top of the stack.
3144 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3147 while (currentSearchNode
!=PROPERTY_NULL
)
3150 * Store the current node in the returned parameters
3152 *thisNodeId
= currentSearchNode
;
3155 * Remove the top node from the stack
3157 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3160 * Read the property from the storage.
3162 Storage32Impl_ReadProperty(
3163 This
->parentStorage
,
3167 if (currentProperty
->previousProperty
== childProperty
)
3168 return PROPERTY_RELATION_PREVIOUS
;
3170 else if (currentProperty
->nextProperty
== childProperty
)
3171 return PROPERTY_RELATION_NEXT
;
3173 else if (currentProperty
->dirProperty
== childProperty
)
3174 return PROPERTY_RELATION_DIR
;
3177 * Push the next search node in the search stack.
3179 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3182 * continue the iteration.
3184 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3187 return PROPERTY_NULL
;
3190 ULONG
IEnumSTATSTGImpl_FindProperty(
3191 IEnumSTATSTGImpl
* This
,
3192 const OLECHAR32
* lpszPropName
,
3193 StgProperty
* currentProperty
)
3195 ULONG currentSearchNode
;
3198 * Start with the node at the top of the stack.
3200 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3202 while (currentSearchNode
!=PROPERTY_NULL
)
3205 * Remove the top node from the stack
3207 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3210 * Read the property from the storage.
3212 Storage32Impl_ReadProperty(This
->parentStorage
,
3216 if ( propertyNameCmp(
3217 (OLECHAR32
*)currentProperty
->name
,
3218 (OLECHAR32
*)lpszPropName
) == 0)
3219 return currentSearchNode
;
3222 * Push the next search node in the search stack.
3224 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3227 * continue the iteration.
3229 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3232 return PROPERTY_NULL
;
3235 void IEnumSTATSTGImpl_PushSearchNode(
3236 IEnumSTATSTGImpl
* This
,
3239 StgProperty rootProperty
;
3240 BOOL32 readSucessful
;
3243 * First, make sure we're not trying to push an unexisting node.
3245 if (nodeToPush
==PROPERTY_NULL
)
3249 * First push the node to the stack
3251 if (This
->stackSize
== This
->stackMaxSize
)
3253 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3255 This
->stackToVisit
= HeapReAlloc(
3259 sizeof(ULONG
) * This
->stackMaxSize
);
3262 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3266 * Read the root property from the storage.
3268 readSucessful
= Storage32Impl_ReadProperty(
3269 This
->parentStorage
,
3275 assert(rootProperty
.sizeOfNameString
!=0);
3278 * Push the previous search node in the search stack.
3280 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3284 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3285 IEnumSTATSTGImpl
* This
,
3290 if (This
->stackSize
== 0)
3291 return PROPERTY_NULL
;
3293 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3301 /******************************************************************************
3302 ** StorageUtl implementation
3305 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3307 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3310 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3312 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3315 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3317 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3320 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3322 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3325 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3327 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3328 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3329 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3331 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
3334 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
3336 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
3337 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
3338 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
3340 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
3343 void StorageUtl_CopyPropertyToSTATSTG(
3344 STATSTG
* destination
,
3345 StgProperty
* source
,
3349 * The copy of the string occurs only when the flag is not set
3351 if ((statFlags
& STATFLAG_NONAME
) != 0)
3353 destination
->pwcsName
= 0;
3357 destination
->pwcsName
=
3358 CoTaskMemAlloc((lstrlen32W(source
->name
)+1)*sizeof(WCHAR
));
3360 lstrcpy32W((LPWSTR
)destination
->pwcsName
, source
->name
);
3363 switch (source
->propertyType
)
3365 case PROPTYPE_STORAGE
:
3367 destination
->type
= STGTY_STORAGE
;
3369 case PROPTYPE_STREAM
:
3370 destination
->type
= STGTY_STREAM
;
3373 destination
->type
= STGTY_STREAM
;
3377 destination
->cbSize
= source
->size
;
3379 currentReturnStruct->mtime = {0}; TODO
3380 currentReturnStruct->ctime = {0};
3381 currentReturnStruct->atime = {0};
3383 destination
->grfMode
= 0;
3384 destination
->grfLocksSupported
= 0;
3385 destination
->clsid
= source
->propertyUniqueID
;
3386 destination
->grfStateBits
= 0;
3387 destination
->reserved
= 0;
3390 /******************************************************************************
3391 ** BlockChainStream implementation
3394 BlockChainStream
* BlockChainStream_Construct(
3395 Storage32Impl
* parentStorage
,
3396 ULONG
* headOfStreamPlaceHolder
,
3397 ULONG propertyIndex
)
3399 BlockChainStream
* newStream
;
3401 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
3403 newStream
->parentStorage
= parentStorage
;
3404 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
3405 newStream
->ownerPropertyIndex
= propertyIndex
;
3410 void BlockChainStream_Destroy(BlockChainStream
* This
)
3412 HeapFree(GetProcessHeap(), 0, This
);
3415 /******************************************************************************
3416 * BlockChainStream_GetHeadOfChain
3418 * Returns the head of this stream chain.
3419 * Some special chains don't have properties, their heads are kept in
3420 * This->headOfStreamPlaceHolder.
3423 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
3425 StgProperty chainProperty
;
3426 BOOL32 readSucessful
;
3428 if (This
->headOfStreamPlaceHolder
!= 0)
3429 return *(This
->headOfStreamPlaceHolder
);
3431 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
3433 readSucessful
= Storage32Impl_ReadProperty(
3434 This
->parentStorage
,
3435 This
->ownerPropertyIndex
,
3440 return chainProperty
.startingBlock
;
3444 return BLOCK_END_OF_CHAIN
;
3447 /******************************************************************************
3448 * BlockChainStream_GetCount
3450 * Returns the number of blocks that comprises this chain.
3451 * This is not the size of the stream as the last block may not be full!
3454 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
3459 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3461 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
3465 blockIndex
= Storage32Impl_GetNextBlockInChain(
3466 This
->parentStorage
,
3473 /******************************************************************************
3474 * BlockChainStream_ReadAt
3476 * Reads a specified number of bytes from this chain at the specified offset.
3477 * bytesRead may be NULL.
3478 * Failure will be returned if the specified number of bytes has not been read.
3480 BOOL32
BlockChainStream_ReadAt(BlockChainStream
* This
,
3481 ULARGE_INTEGER offset
,
3486 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3487 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
3488 ULONG bytesToReadInBuffer
;
3491 BYTE
* bigBlockBuffer
;
3494 * Find the first block in the stream that contains part of the buffer.
3496 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3498 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
3501 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3503 blockNoInSequence
--;
3507 * Start reading the buffer.
3510 bufferWalker
= buffer
;
3512 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
3515 * Calculate how many bytes we can copy from this big block.
3517 bytesToReadInBuffer
=
3518 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
3521 * Copy those bytes to the buffer
3524 Storage32Impl_GetROBigBlock(This
->parentStorage
, blockIndex
);
3526 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
3528 Storage32Impl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
3531 * Step to the next big block.
3534 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3536 bufferWalker
+= bytesToReadInBuffer
;
3537 size
-= bytesToReadInBuffer
;
3538 *bytesRead
+= bytesToReadInBuffer
;
3539 offsetInBlock
= 0; /* There is no offset on the next block */
3546 /******************************************************************************
3547 * BlockChainStream_WriteAt
3549 * Writes the specified number of bytes to this chain at the specified offset.
3550 * bytesWritten may be NULL.
3551 * Will fail if not all specified number of bytes have been written.
3553 BOOL32
BlockChainStream_WriteAt(BlockChainStream
* This
,
3554 ULARGE_INTEGER offset
,
3557 ULONG
* bytesWritten
)
3559 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3560 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
3564 BYTE
* bigBlockBuffer
;
3567 * Find the first block in the stream that contains part of the buffer.
3569 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3571 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
3574 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3576 blockNoInSequence
--;
3580 * Here, I'm casting away the constness on the buffer variable
3581 * This is OK since we don't intend to modify that buffer.
3584 bufferWalker
= (BYTE
*)buffer
;
3586 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
3589 * Calculate how many bytes we can copy from this big block.
3592 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
3595 * Copy those bytes to the buffer
3597 bigBlockBuffer
= Storage32Impl_GetBigBlock(This
->parentStorage
, blockIndex
);
3599 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
3601 Storage32Impl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
3604 * Step to the next big block.
3607 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3609 bufferWalker
+= bytesToWrite
;
3610 size
-= bytesToWrite
;
3611 *bytesWritten
+= bytesToWrite
;
3612 offsetInBlock
= 0; /* There is no offset on the next block */
3618 /******************************************************************************
3619 * BlockChainStream_Shrink
3621 * Shrinks this chain in the big block depot.
3623 BOOL32
BlockChainStream_Shrink(BlockChainStream
* This
,
3624 ULARGE_INTEGER newSize
)
3626 ULONG blockIndex
, extraBlock
;
3631 * Figure out how many blocks are needed to contain the new size
3633 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3635 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
3638 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3641 * Go to the new end of chain
3643 while (count
< numBlocks
)
3646 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3651 /* Get the next block before marking the new end */
3653 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3655 /* Mark the new end of chain */
3656 Storage32Impl_SetNextBlockInChain(
3657 This
->parentStorage
,
3659 BLOCK_END_OF_CHAIN
);
3662 * Mark the extra blocks as free
3664 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
3667 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
3669 Storage32Impl_FreeBigBlock(This
->parentStorage
, extraBlock
);
3670 extraBlock
= blockIndex
;
3676 /******************************************************************************
3677 * BlockChainStream_Enlarge
3679 * Grows this chain in the big block depot.
3681 BOOL32
BlockChainStream_Enlarge(BlockChainStream
* This
,
3682 ULARGE_INTEGER newSize
)
3684 ULONG blockIndex
, currentBlock
;
3686 ULONG oldNumBlocks
= 0;
3688 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3691 * Empty chain. Create the head.
3693 if (blockIndex
== BLOCK_END_OF_CHAIN
)
3695 blockIndex
= Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
3696 Storage32Impl_SetNextBlockInChain(This
->parentStorage
,
3698 BLOCK_END_OF_CHAIN
);
3700 if (This
->headOfStreamPlaceHolder
!= 0)
3702 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
3706 StgProperty chainProp
;
3707 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
3709 Storage32Impl_ReadProperty(
3710 This
->parentStorage
,
3711 This
->ownerPropertyIndex
,
3714 chainProp
.startingBlock
= blockIndex
;
3716 Storage32Impl_WriteProperty(
3717 This
->parentStorage
,
3718 This
->ownerPropertyIndex
,
3723 currentBlock
= blockIndex
;
3726 * Figure out how many blocks are needed to contain this stream
3728 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3730 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
3734 * Go to the current end of chain
3736 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
3739 currentBlock
= blockIndex
;
3742 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
3746 * Add new blocks to the chain
3748 while (oldNumBlocks
< newNumBlocks
)
3750 blockIndex
= Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
3752 Storage32Impl_SetNextBlockInChain(
3753 This
->parentStorage
,
3757 Storage32Impl_SetNextBlockInChain(
3758 This
->parentStorage
,
3760 BLOCK_END_OF_CHAIN
);
3762 currentBlock
= blockIndex
;
3769 /******************************************************************************
3770 * BlockChainStream_SetSize
3772 * Sets the size of this stream. The big block depot will be updated.
3773 * The file will grow if we grow the chain.
3775 * TODO: Free the actual blocks in the file when we shrink the chain.
3776 * Currently, the blocks are still in the file. So the file size
3777 * doesn't shrink even if we shrink streams.
3779 BOOL32
BlockChainStream_SetSize(
3780 BlockChainStream
* This
,
3781 ULARGE_INTEGER newSize
)
3783 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
3785 if (newSize
.LowPart
== size
.LowPart
)
3788 if (newSize
.LowPart
< size
.LowPart
)
3790 BlockChainStream_Shrink(This
, newSize
);
3794 ULARGE_INTEGER fileSize
=
3795 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
3797 ULONG diff
= newSize
.LowPart
- size
.LowPart
;
3800 * Make sure the file stays a multiple of blocksize
3802 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
3803 diff
+= (This
->parentStorage
->bigBlockSize
-
3804 (diff
% This
->parentStorage
->bigBlockSize
) );
3806 fileSize
.LowPart
+= diff
;
3807 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
3809 BlockChainStream_Enlarge(This
, newSize
);
3815 /******************************************************************************
3816 * BlockChainStream_GetSize
3818 * Returns the size of this chain.
3819 * Will return the block count if this chain doesn't have a property.
3821 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
3823 StgProperty chainProperty
;
3825 if(This
->headOfStreamPlaceHolder
== NULL
)
3828 * This chain is a data stream read the property and return
3829 * the appropriate size
3831 Storage32Impl_ReadProperty(
3832 This
->parentStorage
,
3833 This
->ownerPropertyIndex
,
3836 return chainProperty
.size
;
3841 * this chain is a chain that does not have a property, figure out the
3842 * size by making the product number of used blocks times the
3845 ULARGE_INTEGER result
;
3846 result
.HighPart
= 0;
3849 BlockChainStream_GetCount(This
) *
3850 This
->parentStorage
->bigBlockSize
;
3856 /******************************************************************************
3857 ** SmallBlockChainStream implementation
3860 SmallBlockChainStream
* SmallBlockChainStream_Construct(
3861 Storage32Impl
* parentStorage
,
3862 ULONG propertyIndex
)
3864 SmallBlockChainStream
* newStream
;
3866 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
3868 newStream
->parentStorage
= parentStorage
;
3869 newStream
->ownerPropertyIndex
= propertyIndex
;
3874 void SmallBlockChainStream_Destroy(
3875 SmallBlockChainStream
* This
)
3877 HeapFree(GetProcessHeap(), 0, This
);
3880 /******************************************************************************
3881 * SmallBlockChainStream_GetHeadOfChain
3883 * Returns the head of this chain of small blocks.
3885 ULONG
SmallBlockChainStream_GetHeadOfChain(
3886 SmallBlockChainStream
* This
)
3888 StgProperty chainProperty
;
3889 BOOL32 readSucessful
;
3891 if (This
->ownerPropertyIndex
)
3893 readSucessful
= Storage32Impl_ReadProperty(
3894 This
->parentStorage
,
3895 This
->ownerPropertyIndex
,
3900 return chainProperty
.startingBlock
;
3905 return BLOCK_END_OF_CHAIN
;
3908 /******************************************************************************
3909 * SmallBlockChainStream_GetNextBlockInChain
3911 * Returns the index of the next small block in this chain.
3914 * - BLOCK_END_OF_CHAIN: end of this chain
3915 * - BLOCK_UNUSED: small block 'blockIndex' is free
3917 ULONG
SmallBlockChainStream_GetNextBlockInChain(
3918 SmallBlockChainStream
* This
,
3921 ULARGE_INTEGER offsetOfBlockInDepot
;
3923 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
3927 offsetOfBlockInDepot
.HighPart
= 0;
3928 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
3931 * Read those bytes in the buffer from the small block file.
3933 success
= BlockChainStream_ReadAt(
3934 This
->parentStorage
->smallBlockDepotChain
,
3935 offsetOfBlockInDepot
,
3942 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
3945 return nextBlockInChain
;
3948 /******************************************************************************
3949 * SmallBlockChainStream_SetNextBlockInChain
3951 * Writes the index of the next block of the specified block in the small
3953 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
3954 * To flag a block as free use BLOCK_UNUSED as nextBlock.
3956 void SmallBlockChainStream_SetNextBlockInChain(
3957 SmallBlockChainStream
* This
,
3961 ULARGE_INTEGER offsetOfBlockInDepot
;
3965 offsetOfBlockInDepot
.HighPart
= 0;
3966 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
3968 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
3971 * Read those bytes in the buffer from the small block file.
3973 BlockChainStream_WriteAt(
3974 This
->parentStorage
->smallBlockDepotChain
,
3975 offsetOfBlockInDepot
,
3981 /******************************************************************************
3982 * SmallBlockChainStream_FreeBlock
3984 * Flag small block 'blockIndex' as free in the small block depot.
3986 void SmallBlockChainStream_FreeBlock(
3987 SmallBlockChainStream
* This
,
3990 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
3993 /******************************************************************************
3994 * SmallBlockChainStream_GetNextFreeBlock
3996 * Returns the index of a free small block. The small block depot will be
3997 * enlarged if necessary. The small block chain will also be enlarged if
4000 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4001 SmallBlockChainStream
* This
)
4003 ULARGE_INTEGER offsetOfBlockInDepot
;
4006 ULONG blockIndex
= 0;
4007 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4008 BOOL32 success
= TRUE
;
4009 ULONG smallBlocksPerBigBlock
;
4011 offsetOfBlockInDepot
.HighPart
= 0;
4014 * Scan the small block depot for a free block
4016 while (nextBlockIndex
!= BLOCK_UNUSED
)
4018 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4020 success
= BlockChainStream_ReadAt(
4021 This
->parentStorage
->smallBlockDepotChain
,
4022 offsetOfBlockInDepot
,
4028 * If we run out of space for the small block depot, enlarge it
4032 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4034 if (nextBlockIndex
!= BLOCK_UNUSED
)
4040 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4042 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4043 ULONG nextBlock
, newsbdIndex
;
4044 BYTE
* smallBlockDepot
;
4046 nextBlock
= sbdIndex
;
4047 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4049 sbdIndex
= nextBlock
;
4051 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4054 newsbdIndex
= Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
4055 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4056 Storage32Impl_SetNextBlockInChain(
4057 This
->parentStorage
,
4061 Storage32Impl_SetNextBlockInChain(
4062 This
->parentStorage
,
4064 BLOCK_END_OF_CHAIN
);
4067 * Initialize all the small blocks to free
4070 Storage32Impl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4072 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4073 Storage32Impl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4078 * We have just created the small block depot.
4080 StgProperty rootProp
;
4084 * Save it in the header
4086 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4087 Storage32Impl_SaveFileHeader(This
->parentStorage
);
4090 * And allocate the first big block that will contain small blocks
4093 Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
4095 Storage32Impl_SetNextBlockInChain(
4096 This
->parentStorage
,
4098 BLOCK_END_OF_CHAIN
);
4100 Storage32Impl_ReadProperty(
4101 This
->parentStorage
,
4102 This
->parentStorage
->rootPropertySetIndex
,
4105 rootProp
.startingBlock
= sbStartIndex
;
4106 rootProp
.size
.HighPart
= 0;
4107 rootProp
.size
.LowPart
= This
->parentStorage
->bigBlockSize
;
4109 Storage32Impl_WriteProperty(
4110 This
->parentStorage
,
4111 This
->parentStorage
->rootPropertySetIndex
,
4117 smallBlocksPerBigBlock
=
4118 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4121 * Verify if we have to allocate big blocks to contain small blocks
4123 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4125 StgProperty rootProp
;
4126 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4128 Storage32Impl_ReadProperty(
4129 This
->parentStorage
,
4130 This
->parentStorage
->rootPropertySetIndex
,
4133 if (rootProp
.size
.LowPart
<
4134 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4136 rootProp
.size
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4138 BlockChainStream_SetSize(
4139 This
->parentStorage
->smallBlockRootChain
,
4142 Storage32Impl_WriteProperty(
4143 This
->parentStorage
,
4144 This
->parentStorage
->rootPropertySetIndex
,
4152 /******************************************************************************
4153 * SmallBlockChainStream_ReadAt
4155 * Reads a specified number of bytes from this chain at the specified offset.
4156 * bytesRead may be NULL.
4157 * Failure will be returned if the specified number of bytes has not been read.
4159 BOOL32
SmallBlockChainStream_ReadAt(
4160 SmallBlockChainStream
* This
,
4161 ULARGE_INTEGER offset
,
4166 ULARGE_INTEGER offsetInBigBlockFile
;
4167 ULONG blockNoInSequence
=
4168 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4170 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4171 ULONG bytesToReadInBuffer
;
4173 ULONG bytesReadFromBigBlockFile
;
4177 * This should never happen on a small block file.
4179 assert(offset
.HighPart
==0);
4182 * Find the first block in the stream that contains part of the buffer.
4184 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4186 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4188 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4190 blockNoInSequence
--;
4194 * Start reading the buffer.
4197 bufferWalker
= buffer
;
4199 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4202 * Calculate how many bytes we can copy from this small block.
4204 bytesToReadInBuffer
=
4205 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4208 * Calculate the offset of the small block in the small block file.
4210 offsetInBigBlockFile
.HighPart
= 0;
4211 offsetInBigBlockFile
.LowPart
=
4212 blockIndex
* This
->parentStorage
->smallBlockSize
;
4214 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4217 * Read those bytes in the buffer from the small block file.
4219 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4220 offsetInBigBlockFile
,
4221 bytesToReadInBuffer
,
4223 &bytesReadFromBigBlockFile
);
4225 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4228 * Step to the next big block.
4230 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4231 bufferWalker
+= bytesToReadInBuffer
;
4232 size
-= bytesToReadInBuffer
;
4233 *bytesRead
+= bytesToReadInBuffer
;
4234 offsetInBlock
= 0; /* There is no offset on the next block */
4240 /******************************************************************************
4241 * SmallBlockChainStream_WriteAt
4243 * Writes the specified number of bytes to this chain at the specified offset.
4244 * bytesWritten may be NULL.
4245 * Will fail if not all specified number of bytes have been written.
4247 BOOL32
SmallBlockChainStream_WriteAt(
4248 SmallBlockChainStream
* This
,
4249 ULARGE_INTEGER offset
,
4252 ULONG
* bytesWritten
)
4254 ULARGE_INTEGER offsetInBigBlockFile
;
4255 ULONG blockNoInSequence
=
4256 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4258 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4259 ULONG bytesToWriteInBuffer
;
4261 ULONG bytesWrittenFromBigBlockFile
;
4265 * This should never happen on a small block file.
4267 assert(offset
.HighPart
==0);
4270 * Find the first block in the stream that contains part of the buffer.
4272 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4274 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4276 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4278 blockNoInSequence
--;
4282 * Start writing the buffer.
4284 * Here, I'm casting away the constness on the buffer variable
4285 * This is OK since we don't intend to modify that buffer.
4288 bufferWalker
= (BYTE
*)buffer
;
4289 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4292 * Calculate how many bytes we can copy to this small block.
4294 bytesToWriteInBuffer
=
4295 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4298 * Calculate the offset of the small block in the small block file.
4300 offsetInBigBlockFile
.HighPart
= 0;
4301 offsetInBigBlockFile
.LowPart
=
4302 blockIndex
* This
->parentStorage
->smallBlockSize
;
4304 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4307 * Write those bytes in the buffer to the small block file.
4309 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
4310 offsetInBigBlockFile
,
4311 bytesToWriteInBuffer
,
4313 &bytesWrittenFromBigBlockFile
);
4315 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
4318 * Step to the next big block.
4320 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4321 bufferWalker
+= bytesToWriteInBuffer
;
4322 size
-= bytesToWriteInBuffer
;
4323 *bytesWritten
+= bytesToWriteInBuffer
;
4324 offsetInBlock
= 0; /* There is no offset on the next block */
4330 /******************************************************************************
4331 * SmallBlockChainStream_Shrink
4333 * Shrinks this chain in the small block depot.
4335 BOOL32
SmallBlockChainStream_Shrink(
4336 SmallBlockChainStream
* This
,
4337 ULARGE_INTEGER newSize
)
4339 ULONG blockIndex
, extraBlock
;
4343 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4345 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4348 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4351 * Go to the new end of chain
4353 while (count
< numBlocks
)
4355 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4359 /* Get the next block before marking the new end */
4360 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4362 /* Mark the new end of chain */
4363 SmallBlockChainStream_SetNextBlockInChain(
4366 BLOCK_END_OF_CHAIN
);
4369 * Mark the extra blocks as free
4371 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4373 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
4374 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
4375 extraBlock
= blockIndex
;
4381 /******************************************************************************
4382 * SmallBlockChainStream_Enlarge
4384 * Grows this chain in the small block depot.
4386 BOOL32
SmallBlockChainStream_Enlarge(
4387 SmallBlockChainStream
* This
,
4388 ULARGE_INTEGER newSize
)
4390 ULONG blockIndex
, currentBlock
;
4392 ULONG oldNumBlocks
= 0;
4394 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4399 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4401 StgProperty chainProp
;
4403 Storage32Impl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
4406 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
4408 Storage32Impl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
4411 blockIndex
= chainProp
.startingBlock
;
4412 SmallBlockChainStream_SetNextBlockInChain(
4415 BLOCK_END_OF_CHAIN
);
4418 currentBlock
= blockIndex
;
4421 * Figure out how many blocks are needed to contain this stream
4423 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4425 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4429 * Go to the current end of chain
4431 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4434 currentBlock
= blockIndex
;
4435 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
4439 * Add new blocks to the chain
4441 while (oldNumBlocks
< newNumBlocks
)
4443 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
4444 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
4446 SmallBlockChainStream_SetNextBlockInChain(
4449 BLOCK_END_OF_CHAIN
);
4451 currentBlock
= blockIndex
;
4458 /******************************************************************************
4459 * SmallBlockChainStream_GetCount
4461 * Returns the number of blocks that comprises this chain.
4462 * This is not the size of this chain as the last block may not be full!
4464 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
4469 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4471 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4475 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4481 /******************************************************************************
4482 * SmallBlockChainStream_SetSize
4484 * Sets the size of this stream.
4485 * The file will grow if we grow the chain.
4487 * TODO: Free the actual blocks in the file when we shrink the chain.
4488 * Currently, the blocks are still in the file. So the file size
4489 * doesn't shrink even if we shrink streams.
4491 BOOL32
SmallBlockChainStream_SetSize(
4492 SmallBlockChainStream
* This
,
4493 ULARGE_INTEGER newSize
)
4495 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
4497 if (newSize
.LowPart
== size
.LowPart
)
4500 if (newSize
.LowPart
< size
.LowPart
)
4502 SmallBlockChainStream_Shrink(This
, newSize
);
4506 SmallBlockChainStream_Enlarge(This
, newSize
);
4512 /******************************************************************************
4513 * SmallBlockChainStream_GetSize
4515 * Returns the size of this chain.
4517 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
4519 StgProperty chainProperty
;
4521 Storage32Impl_ReadProperty(
4522 This
->parentStorage
,
4523 This
->ownerPropertyIndex
,
4526 return chainProperty
.size
;
4529 /******************************************************************************
4530 * StgCreateDocfile32 [OLE32.144]
4531 * TODO Validate grfMode (STGM)
4533 HRESULT WINAPI
StgCreateDocfile32(
4534 LPCOLESTR32 pwcsName
,
4537 IStorage32
**ppstgOpen
)
4539 Storage32Impl
* newStorage
= 0;
4540 HANDLE32 hFile
= INVALID_HANDLE_VALUE32
;
4545 DWORD fileAttributes
;
4548 * Validate the parameters
4550 if ((ppstgOpen
== 0) || (pwcsName
== 0))
4551 return STG_E_INVALIDPOINTER
;
4554 * Validate the STGM flags
4556 if ( FAILED( validateSTGM(grfMode
) ))
4557 return STG_E_INVALIDFLAG
;
4560 * Interpret the STGM value grfMode
4562 shareMode
= GetShareModeFromSTGM(grfMode
);
4563 accessMode
= GetAccessModeFromSTGM(grfMode
);
4564 creationMode
= GetCreationModeFromSTGM(grfMode
);
4566 if (grfMode
& STGM_DELETEONRELEASE
)
4567 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
4569 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
4571 if (grfMode
& STGM_TRANSACTED
)
4572 FIXME(ole
, "Transacted mode not implemented.\n");
4575 * Initialize the "out" parameter.
4579 hFile
= CreateFile32W(pwcsName
,
4587 if (hFile
== INVALID_HANDLE_VALUE32
)
4593 * Allocate and initialize the new IStorage32object.
4595 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl
));
4597 if (newStorage
== 0)
4598 return STG_E_INSUFFICIENTMEMORY
;
4600 hr
= Storage32Impl_Construct(
4609 * Get an "out" pointer for the caller.
4611 hr
= Storage32BaseImpl_QueryInterface(
4612 (Storage32BaseImpl
*)newStorage
,
4613 (REFIID
)&IID_IStorage
,
4619 /******************************************************************************
4620 * StgOpenStorage32 [OLE32.148]
4622 HRESULT WINAPI
StgOpenStorage32(
4623 const OLECHAR32
*pwcsName
,
4624 IStorage32
*pstgPriority
,
4628 IStorage32
**ppstgOpen
)
4630 Storage32Impl
* newStorage
= 0;
4637 * Perform a sanity check
4639 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
4640 return STG_E_INVALIDPOINTER
;
4643 * Validate the STGM flags
4645 if ( FAILED( validateSTGM(grfMode
) ))
4646 return STG_E_INVALIDFLAG
;
4649 * Interpret the STGM value grfMode
4651 shareMode
= GetShareModeFromSTGM(grfMode
);
4652 accessMode
= GetAccessModeFromSTGM(grfMode
);
4655 * Initialize the "out" parameter.
4659 hFile
= CreateFile32W( pwcsName
,
4664 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
4668 if (hFile
==INVALID_HANDLE_VALUE32
)
4674 * Allocate and initialize the new IStorage32object.
4676 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl
));
4678 if (newStorage
== 0)
4679 return STG_E_INSUFFICIENTMEMORY
;
4681 hr
= Storage32Impl_Construct(
4690 * Get an "out" pointer for the caller.
4692 hr
= Storage32BaseImpl_QueryInterface(
4693 (Storage32BaseImpl
*)newStorage
,
4694 (REFIID
)&IID_IStorage
,
4700 /******************************************************************************
4701 * WriteClassStg32 [OLE32.148]
4703 * This method will store the specified CLSID in the specified storage object
4705 HRESULT WINAPI
WriteClassStg32(IStorage32
* pStg
, REFCLSID rclsid
)
4711 hRes
= IStorage32_SetClass(pStg
, rclsid
);
4717 /****************************************************************************
4718 * This method validate a STGM parameter that can contain the values below
4720 * STGM_DIRECT 0x00000000
4721 * STGM_TRANSACTED 0x00010000
4722 * STGM_SIMPLE 0x08000000
4724 * STGM_READ 0x00000000
4725 * STGM_WRITE 0x00000001
4726 * STGM_READWRITE 0x00000002
4728 * STGM_SHARE_DENY_NONE 0x00000040
4729 * STGM_SHARE_DENY_READ 0x00000030
4730 * STGM_SHARE_DENY_WRITE 0x00000020
4731 * STGM_SHARE_EXCLUSIVE 0x00000010
4733 * STGM_PRIORITY 0x00040000
4734 * STGM_DELETEONRELEASE 0x04000000
4736 * STGM_CREATE 0x00001000
4737 * STGM_CONVERT 0x00020000
4738 * STGM_FAILIFTHERE 0x00000000
4740 * STGM_NOSCRATCH 0x00100000
4741 * STGM_NOSNAPSHOT 0x00200000
4743 static HRESULT
validateSTGM(DWORD stgm
)
4745 BOOL32 bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
4746 BOOL32 bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
4747 BOOL32 bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
4749 BOOL32 bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
4750 BOOL32 bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
4751 BOOL32 bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
4753 BOOL32 bSTGM_SHARE_DENY_NONE
=
4754 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
4756 BOOL32 bSTGM_SHARE_DENY_READ
=
4757 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
4759 BOOL32 bSTGM_SHARE_DENY_WRITE
=
4760 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
4762 BOOL32 bSTGM_SHARE_EXCLUSIVE
=
4763 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
4765 BOOL32 bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
4766 BOOL32 bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
4768 BOOL32 bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
4769 BOOL32 bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
4772 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
4774 if ( ! bSTGM_DIRECT
)
4775 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
4779 * STGM_WRITE | STGM_READWRITE | STGM_READ
4782 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
4786 * STGM_SHARE_DENY_NONE | others
4787 * (I assume here that DENY_READ implies DENY_WRITE)
4789 if ( bSTGM_SHARE_DENY_NONE
)
4790 if ( bSTGM_SHARE_DENY_READ
||
4791 bSTGM_SHARE_DENY_WRITE
||
4792 bSTGM_SHARE_EXCLUSIVE
)
4796 * STGM_CREATE | STGM_CONVERT
4797 * if both are false, STGM_FAILIFTHERE is set to TRUE
4799 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
4803 * STGM_NOSCRATCH requires STGM_TRANSACTED
4805 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
4809 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
4810 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
4812 if (bSTGM_NOSNAPSHOT
)
4814 if ( ! ( bSTGM_TRANSACTED
&&
4815 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
4822 /****************************************************************************
4823 * GetShareModeFromSTGM
4825 * This method will return a share mode flag from a STGM value.
4826 * The STGM value is assumed valid.
4828 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
4830 DWORD dwShareMode
= 0;
4831 BOOL32 bSTGM_SHARE_DENY_NONE
=
4832 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
4834 BOOL32 bSTGM_SHARE_DENY_READ
=
4835 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
4837 BOOL32 bSTGM_SHARE_DENY_WRITE
=
4838 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
4840 BOOL32 bSTGM_SHARE_EXCLUSIVE
=
4841 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
4843 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
4846 if (bSTGM_SHARE_DENY_NONE
)
4847 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
4849 if (bSTGM_SHARE_DENY_WRITE
)
4850 dwShareMode
= FILE_SHARE_READ
;
4855 /****************************************************************************
4856 * GetAccessModeFromSTGM
4858 * This method will return an access mode flag from a STGM value.
4859 * The STGM value is assumed valid.
4861 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
4863 DWORD dwDesiredAccess
= 0;
4864 BOOL32 bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
4865 BOOL32 bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
4866 BOOL32 bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
4869 dwDesiredAccess
= GENERIC_READ
;
4872 dwDesiredAccess
|= GENERIC_WRITE
;
4874 if (bSTGM_READWRITE
)
4875 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
4877 return dwDesiredAccess
;
4880 /****************************************************************************
4881 * GetCreationModeFromSTGM
4883 * This method will return a creation mode flag from a STGM value.
4884 * The STGM value is assumed valid.
4886 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
4888 DWORD dwCreationDistribution
;
4889 BOOL32 bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
4890 BOOL32 bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
4891 BOOL32 bSTGM_FAILIFTHERE
= ! (bSTGM_CREATE
|| bSTGM_CONVERT
);
4894 dwCreationDistribution
= CREATE_NEW
;
4895 else if (bSTGM_FAILIFTHERE
)
4896 dwCreationDistribution
= CREATE_NEW
;
4897 else if (bSTGM_CONVERT
)
4899 FIXME(ole
, "STGM_CONVERT not implemented!\n");
4900 dwCreationDistribution
= CREATE_NEW
;
4903 return dwCreationDistribution
;