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 StorageImpl
*parentStorage
,
43 OLECHAR
*propertyToDeleteName
);
45 static HRESULT
deleteStreamProperty(
46 StorageImpl
*parentStorage
,
47 ULONG foundPropertyIndexToDelete
,
48 StgProperty propertyToDelete
);
50 static HRESULT
findPlaceholder(
52 ULONG propertyIndexToStore
,
53 ULONG storagePropertyIndex
,
56 static HRESULT
adjustPropertyChain(
58 StgProperty propertyToDelete
,
59 StgProperty parentProperty
,
60 ULONG parentPropertyId
,
63 /***********************************************************************
64 * Declaration of the functions used to manipulate StgProperty
67 static ULONG
getFreeProperty(
68 StorageImpl
*storage
);
70 static void updatePropertyChain(
72 ULONG newPropertyIndex
,
73 StgProperty newProperty
);
75 static LONG
propertyNameCmp(
77 OLECHAR
*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(IStorage
) Storage32Impl_Vtbl
=
94 StorageBaseImpl_QueryInterface
,
95 StorageBaseImpl_AddRef
,
96 StorageBaseImpl_Release
,
97 StorageBaseImpl_CreateStream
,
98 StorageBaseImpl_OpenStream
,
99 StorageImpl_CreateStorage
,
100 StorageBaseImpl_OpenStorage
,
102 StorageImpl_MoveElementTo
,
105 StorageBaseImpl_EnumElements
,
106 StorageImpl_DestroyElement
,
107 StorageBaseImpl_RenameElement
,
108 StorageImpl_SetElementTimes
,
109 StorageBaseImpl_SetClass
,
110 StorageImpl_SetStateBits
,
115 * Virtual function table for the Storage32InternalImpl class.
117 static ICOM_VTABLE(IStorage
) Storage32InternalImpl_Vtbl
=
119 StorageBaseImpl_QueryInterface
,
120 StorageBaseImpl_AddRef
,
121 StorageBaseImpl_Release
,
122 StorageBaseImpl_CreateStream
,
123 StorageBaseImpl_OpenStream
,
124 StorageImpl_CreateStorage
,
125 StorageBaseImpl_OpenStorage
,
127 StorageImpl_MoveElementTo
,
128 StorageInternalImpl_Commit
,
129 StorageInternalImpl_Revert
,
130 StorageBaseImpl_EnumElements
,
131 StorageImpl_DestroyElement
,
132 StorageBaseImpl_RenameElement
,
133 StorageImpl_SetElementTimes
,
134 StorageBaseImpl_SetClass
,
135 StorageImpl_SetStateBits
,
140 * Virtual function table for the IEnumSTATSTGImpl class.
142 static ICOM_VTABLE(IEnumSTATSTG
) IEnumSTATSTGImpl_Vtbl
=
144 IEnumSTATSTGImpl_QueryInterface
,
145 IEnumSTATSTGImpl_AddRef
,
146 IEnumSTATSTGImpl_Release
,
147 IEnumSTATSTGImpl_Next
,
148 IEnumSTATSTGImpl_Skip
,
149 IEnumSTATSTGImpl_Reset
,
150 IEnumSTATSTGImpl_Clone
157 /************************************************************************
158 ** Storage32BaseImpl implementatiion
161 /************************************************************************
162 * Storage32BaseImpl_QueryInterface (IUnknown)
164 * This method implements the common QueryInterface for all IStorage32
165 * implementations contained in this file.
167 * See Windows documentation for more details on IUnknown methods.
169 HRESULT WINAPI
StorageBaseImpl_QueryInterface(
174 ICOM_THIS(StorageBaseImpl
,iface
);
176 * Perform a sanity check on the parameters.
178 if ( (This
==0) || (ppvObject
==0) )
182 * Initialize the return parameter.
187 * Compare the riid with the interface IDs implemented by this object.
189 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
191 *ppvObject
= (IStorage
*)This
;
193 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
195 *ppvObject
= (IStorage
*)This
;
199 * Check that we obtained an interface.
202 return E_NOINTERFACE
;
205 * Query Interface always increases the reference count by one when it is
208 StorageBaseImpl_AddRef(iface
);
213 /************************************************************************
214 * Storage32BaseImpl_AddRef (IUnknown)
216 * This method implements the common AddRef for all IStorage32
217 * implementations contained in this file.
219 * See Windows documentation for more details on IUnknown methods.
221 ULONG WINAPI
StorageBaseImpl_AddRef(
224 ICOM_THIS(StorageBaseImpl
,iface
);
230 /************************************************************************
231 * Storage32BaseImpl_Release (IUnknown)
233 * This method implements the common Release for all IStorage32
234 * implementations contained in this file.
236 * See Windows documentation for more details on IUnknown methods.
238 ULONG WINAPI
StorageBaseImpl_Release(
241 ICOM_THIS(StorageBaseImpl
,iface
);
243 * Decrease the reference count on this object.
248 * If the reference count goes down to 0, perform suicide.
253 * Since we are using a system of base-classes, we want to call the
254 * destructor of the appropriate derived class. To do this, we are
255 * using virtual functions to implement the destructor.
257 This
->v_destructor(This
);
265 /************************************************************************
266 * Storage32BaseImpl_OpenStream (IStorage)
268 * This method will open the specified stream object from the current storage.
270 * See Windows documentation for more details on IStorage methods.
272 HRESULT WINAPI
StorageBaseImpl_OpenStream(
274 const OLECHAR
* pwcsName
, /* [string][in] */
275 void* reserved1
, /* [unique][in] */
276 DWORD grfMode
, /* [in] */
277 DWORD reserved2
, /* [in] */
278 IStream
** ppstm
) /* [out] */
280 ICOM_THIS(StorageBaseImpl
,iface
);
281 IEnumSTATSTGImpl
* propertyEnumeration
;
282 StgStreamImpl
* newStream
;
283 StgProperty currentProperty
;
284 ULONG foundPropertyIndex
;
287 * Perform a sanity check on the parameters.
289 if ( (pwcsName
==NULL
) || (ppstm
==0) )
293 * Initialize the out parameter
298 * Validate the STGM flags
300 if ( FAILED( validateSTGM(grfMode
) ))
301 return STG_E_INVALIDFLAG
;
306 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
307 (grfMode
& STGM_DELETEONRELEASE
) ||
308 (grfMode
& STGM_TRANSACTED
) )
309 return STG_E_INVALIDFUNCTION
;
312 * Create a property enumeration to search the properties
314 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
315 This
->ancestorStorage
,
316 This
->rootPropertySetIndex
);
319 * Search the enumeration for the property with the given name
321 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
327 * Delete the property enumeration since we don't need it anymore
329 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
332 * If it was found, construct the stream object and return a pointer to it.
334 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
335 (currentProperty
.propertyType
==PROPTYPE_STREAM
) )
337 newStream
= StgStreamImpl_Construct(This
, foundPropertyIndex
);
341 *ppstm
= (IStream
*)newStream
;
344 * Since we are returning a pointer to the interface, we have to
345 * nail down the reference.
347 StgStreamImpl_AddRef(*ppstm
);
352 return E_OUTOFMEMORY
;
355 return STG_E_FILENOTFOUND
;
358 /************************************************************************
359 * Storage32BaseImpl_OpenStorage (IStorage)
361 * This method will open a new storage object from the current storage.
363 * See Windows documentation for more details on IStorage methods.
365 HRESULT WINAPI
StorageBaseImpl_OpenStorage(
367 const OLECHAR
* pwcsName
, /* [string][unique][in] */
368 IStorage
* pstgPriority
, /* [unique][in] */
369 DWORD grfMode
, /* [in] */
370 SNB snbExclude
, /* [unique][in] */
371 DWORD reserved
, /* [in] */
372 IStorage
** ppstg
) /* [out] */
374 ICOM_THIS(StorageBaseImpl
,iface
);
375 StorageInternalImpl
* newStorage
;
376 IEnumSTATSTGImpl
* propertyEnumeration
;
377 StgProperty currentProperty
;
378 ULONG foundPropertyIndex
;
381 * Perform a sanity check on the parameters.
383 if ( (This
==0) || (pwcsName
==NULL
) || (ppstg
==0) )
387 * Validate the STGM flags
389 if ( FAILED( validateSTGM(grfMode
) ))
390 return STG_E_INVALIDFLAG
;
395 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
396 (grfMode
& STGM_DELETEONRELEASE
) ||
397 (grfMode
& STGM_PRIORITY
) )
398 return STG_E_INVALIDFUNCTION
;
401 * Initialize the out parameter
406 * Create a property enumeration to search the properties
408 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
409 This
->ancestorStorage
,
410 This
->rootPropertySetIndex
);
413 * Search the enumeration for the property with the given name
415 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
421 * Delete the property enumeration since we don't need it anymore
423 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
426 * If it was found, construct the stream object and return a pointer to it.
428 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
429 (currentProperty
.propertyType
==PROPTYPE_STORAGE
) )
432 * Construct a new Storage object
434 newStorage
= StorageInternalImpl_Construct(
435 This
->ancestorStorage
,
440 *ppstg
= (IStorage
*)newStorage
;
443 * Since we are returning a pointer to the interface,
444 * we have to nail down the reference.
446 StorageBaseImpl_AddRef(*ppstg
);
451 return STG_E_INSUFFICIENTMEMORY
;
454 return STG_E_FILENOTFOUND
;
457 /************************************************************************
458 * Storage32BaseImpl_EnumElements (IStorage)
460 * This method will create an enumerator object that can be used to
461 * retrieve informatino about all the properties in the storage object.
463 * See Windows documentation for more details on IStorage methods.
465 HRESULT WINAPI
StorageBaseImpl_EnumElements(
467 DWORD reserved1
, /* [in] */
468 void* reserved2
, /* [size_is][unique][in] */
469 DWORD reserved3
, /* [in] */
470 IEnumSTATSTG
** ppenum
) /* [out] */
472 ICOM_THIS(StorageBaseImpl
,iface
);
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
);
490 *ppenum
= (IEnumSTATSTG
*)newEnum
;
493 * Don't forget to nail down a reference to the new object before
496 IEnumSTATSTGImpl_AddRef(*ppenum
);
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
StorageBaseImpl_Stat(
513 STATSTG
* pstatstg
, /* [out] */
514 DWORD grfStatFlag
) /* [in] */
516 ICOM_THIS(StorageBaseImpl
,iface
);
517 StgProperty curProperty
;
521 * Perform a sanity check on the parameters.
523 if ( (This
==0) || (pstatstg
==0))
527 * Read the information from the property.
529 readSucessful
= StorageImpl_ReadProperty(
530 This
->ancestorStorage
,
531 This
->rootPropertySetIndex
,
536 StorageUtl_CopyPropertyToSTATSTG(
547 /************************************************************************
548 * Storage32BaseImpl_RenameElement (IStorage)
550 * This method will rename the specified element.
552 * See Windows documentation for more details on IStorage methods.
554 * Implementation notes: The method used to rename consists of creating a clone
555 * of the deleted StgProperty object setting it with the new name and to
556 * perform a DestroyElement of the old StgProperty.
558 HRESULT WINAPI
StorageBaseImpl_RenameElement(
560 const OLECHAR
* pwcsOldName
, /* [in] */
561 const OLECHAR
* pwcsNewName
) /* [in] */
563 ICOM_THIS(StorageBaseImpl
,iface
);
564 IEnumSTATSTGImpl
* propertyEnumeration
;
565 StgProperty currentProperty
;
566 ULONG foundPropertyIndex
;
569 * Create a property enumeration to search the properties
571 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
572 This
->rootPropertySetIndex
);
575 * Search the enumeration for the new property name
577 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
581 if (foundPropertyIndex
!= PROPERTY_NULL
)
584 * There is already a property with the new name
586 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
587 return STG_E_FILEALREADYEXISTS
;
590 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)propertyEnumeration
);
593 * Search the enumeration for the old property name
595 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
600 * Delete the property enumeration since we don't need it anymore
602 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
604 if (foundPropertyIndex
!= PROPERTY_NULL
)
606 StgProperty renamedProperty
;
607 ULONG renamedPropertyIndex
;
610 * Setup a new property for the renamed property
612 renamedProperty
.sizeOfNameString
=
613 ( lstrlenW(pwcsNewName
)+1 ) * sizeof(WCHAR
);
615 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
616 return STG_E_INVALIDNAME
;
618 lstrcpyW(renamedProperty
.name
, pwcsNewName
);
620 renamedProperty
.propertyType
= currentProperty
.propertyType
;
621 renamedProperty
.startingBlock
= currentProperty
.startingBlock
;
622 renamedProperty
.size
.LowPart
= currentProperty
.size
.LowPart
;
623 renamedProperty
.size
.HighPart
= currentProperty
.size
.HighPart
;
625 renamedProperty
.previousProperty
= PROPERTY_NULL
;
626 renamedProperty
.nextProperty
= PROPERTY_NULL
;
629 * Bring the dirProperty link in case it is a storage and in which
630 * case the renamed storage elements don't require to be reorganized.
632 renamedProperty
.dirProperty
= currentProperty
.dirProperty
;
634 /* call CoFileTime to get the current time
635 renamedProperty.timeStampS1
636 renamedProperty.timeStampD1
637 renamedProperty.timeStampS2
638 renamedProperty.timeStampD2
639 renamedProperty.propertyUniqueID
643 * Obtain a free property in the property chain
645 renamedPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
648 * Save the new property into the new property spot
650 StorageImpl_WriteProperty(
651 This
->ancestorStorage
,
652 renamedPropertyIndex
,
656 * Find a spot in the property chain for our newly created property.
660 renamedPropertyIndex
,
664 * At this point the renamed property has been inserted in the tree,
665 * now, before to Destroy the old property we must zeroed it's dirProperty
666 * otherwise the DestroyProperty below will zap it all and we do not want
668 * Also, we fake that the old property is a storage so the DestroyProperty
669 * will not do a SetSize(0) on the stream data.
671 * This means that we need to tweek the StgProperty if it is a stream or a
674 currentProperty
.dirProperty
= PROPERTY_NULL
;
675 currentProperty
.propertyType
= PROPTYPE_STORAGE
;
676 StorageImpl_WriteProperty(
677 This
->ancestorStorage
,
682 * Invoke Destroy to get rid of the ole property and automatically redo
683 * the linking of it's previous and next members...
685 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsOldName
);
691 * There is no property with the old name
693 return STG_E_FILENOTFOUND
;
699 /************************************************************************
700 * Storage32BaseImpl_CreateStream (IStorage)
702 * This method will create a stream object within this storage
704 * See Windows documentation for more details on IStorage methods.
706 HRESULT WINAPI
StorageBaseImpl_CreateStream(
708 const OLECHAR
* pwcsName
, /* [string][in] */
709 DWORD grfMode
, /* [in] */
710 DWORD reserved1
, /* [in] */
711 DWORD reserved2
, /* [in] */
712 IStream
** ppstm
) /* [out] */
714 ICOM_THIS(StorageBaseImpl
,iface
);
715 IEnumSTATSTGImpl
* propertyEnumeration
;
716 StgStreamImpl
* newStream
;
717 StgProperty currentProperty
, newStreamProperty
;
718 ULONG foundPropertyIndex
, newPropertyIndex
;
721 * Validate parameters
724 return STG_E_INVALIDPOINTER
;
727 return STG_E_INVALIDNAME
;
730 * Validate the STGM flags
732 if ( FAILED( validateSTGM(grfMode
) ))
733 return STG_E_INVALIDFLAG
;
738 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
739 (grfMode
& STGM_DELETEONRELEASE
) ||
740 (grfMode
& STGM_TRANSACTED
) )
741 return STG_E_INVALIDFUNCTION
;
744 * Initialize the out parameter
749 * Create a property enumeration to search the properties
751 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
752 This
->rootPropertySetIndex
);
754 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
758 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
760 if (foundPropertyIndex
!= PROPERTY_NULL
)
763 * An element with this name already exists
765 if (grfMode
& STGM_CREATE
)
766 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsName
);
768 return STG_E_FILEALREADYEXISTS
;
772 * memset the empty property
774 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
776 newStreamProperty
.sizeOfNameString
=
777 ( lstrlenW(pwcsName
)+1 ) * sizeof(WCHAR
);
779 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
780 return STG_E_INVALIDNAME
;
782 lstrcpyW(newStreamProperty
.name
, pwcsName
);
784 newStreamProperty
.propertyType
= PROPTYPE_STREAM
;
785 newStreamProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
786 newStreamProperty
.size
.LowPart
= 0;
787 newStreamProperty
.size
.HighPart
= 0;
789 newStreamProperty
.previousProperty
= PROPERTY_NULL
;
790 newStreamProperty
.nextProperty
= PROPERTY_NULL
;
791 newStreamProperty
.dirProperty
= PROPERTY_NULL
;
793 /* call CoFileTime to get the current time
794 newStreamProperty.timeStampS1
795 newStreamProperty.timeStampD1
796 newStreamProperty.timeStampS2
797 newStreamProperty.timeStampD2
800 /* newStreamProperty.propertyUniqueID */
803 * Get a free property or create a new one
805 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
808 * Save the new property into the new property spot
810 StorageImpl_WriteProperty(
811 This
->ancestorStorage
,
816 * Find a spot in the property chain for our newly created property.
824 * Open the stream to return it.
826 newStream
= StgStreamImpl_Construct(This
, newPropertyIndex
);
830 *ppstm
= (IStream
*)newStream
;
833 * Since we are returning a pointer to the interface, we have to nail down
836 StgStreamImpl_AddRef(*ppstm
);
840 return STG_E_INSUFFICIENTMEMORY
;
846 /************************************************************************
847 * Storage32BaseImpl_SetClass (IStorage)
849 * This method will write the specified CLSID in the property of this
852 * See Windows documentation for more details on IStorage methods.
854 HRESULT WINAPI
StorageBaseImpl_SetClass(
856 REFCLSID clsid
) /* [in] */
858 ICOM_THIS(StorageBaseImpl
,iface
);
859 HRESULT hRes
= E_FAIL
;
860 StgProperty curProperty
;
863 success
= StorageImpl_ReadProperty(This
->ancestorStorage
,
864 This
->rootPropertySetIndex
,
868 curProperty
.propertyUniqueID
= *clsid
;
870 success
= StorageImpl_WriteProperty(This
->ancestorStorage
,
871 This
->rootPropertySetIndex
,
880 /************************************************************************
881 ** Storage32Impl implementation
884 /************************************************************************
885 * Storage32Impl_CreateStorage (IStorage)
887 * This method will create the storage object within the provided storage.
889 * See Windows documentation for more details on IStorage methods.
891 HRESULT WINAPI
StorageImpl_CreateStorage(
893 const OLECHAR
*pwcsName
, /* [string][in] */
894 DWORD grfMode
, /* [in] */
895 DWORD reserved1
, /* [in] */
896 DWORD reserved2
, /* [in] */
897 IStorage
**ppstg
) /* [out] */
899 StorageImpl
* const This
=(StorageImpl
*)iface
;
901 IEnumSTATSTGImpl
*propertyEnumeration
;
902 StgProperty currentProperty
;
903 StgProperty newProperty
;
904 ULONG foundPropertyIndex
;
905 ULONG newPropertyIndex
;
909 * Validate parameters
912 return STG_E_INVALIDPOINTER
;
915 return STG_E_INVALIDNAME
;
918 * Validate the STGM flags
920 if ( FAILED( validateSTGM(grfMode
) ) ||
921 (grfMode
& STGM_DELETEONRELEASE
) )
922 return STG_E_INVALIDFLAG
;
925 * Initialize the out parameter
930 * Create a property enumeration and search the properties
932 propertyEnumeration
= IEnumSTATSTGImpl_Construct( This
->ancestorStorage
,
933 This
->rootPropertySetIndex
);
935 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
938 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
940 if (foundPropertyIndex
!= PROPERTY_NULL
)
943 * An element with this name already exists
945 if (grfMode
& STGM_CREATE
)
946 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsName
);
948 return STG_E_FILEALREADYEXISTS
;
952 * memset the empty property
954 memset(&newProperty
, 0, sizeof(StgProperty
));
956 newProperty
.sizeOfNameString
= (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
);
958 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
959 return STG_E_INVALIDNAME
;
961 lstrcpyW(newProperty
.name
, pwcsName
);
963 newProperty
.propertyType
= PROPTYPE_STORAGE
;
964 newProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
965 newProperty
.size
.LowPart
= 0;
966 newProperty
.size
.HighPart
= 0;
968 newProperty
.previousProperty
= PROPERTY_NULL
;
969 newProperty
.nextProperty
= PROPERTY_NULL
;
970 newProperty
.dirProperty
= PROPERTY_NULL
;
972 /* call CoFileTime to get the current time
973 newProperty.timeStampS1
974 newProperty.timeStampD1
975 newProperty.timeStampS2
976 newProperty.timeStampD2
979 /* newStorageProperty.propertyUniqueID */
982 * Obtain a free property in the property chain
984 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
987 * Save the new property into the new property spot
989 StorageImpl_WriteProperty(
990 This
->ancestorStorage
,
995 * Find a spot in the property chain for our newly created property.
1003 * Open it to get a pointer to return.
1005 hr
= StorageBaseImpl_OpenStorage(
1014 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1023 /***************************************************************************
1027 * Get a free property or create a new one.
1029 static ULONG
getFreeProperty(
1030 StorageImpl
*storage
)
1032 ULONG currentPropertyIndex
= 0;
1033 ULONG newPropertyIndex
= PROPERTY_NULL
;
1034 BOOL readSucessful
= TRUE
;
1035 StgProperty currentProperty
;
1040 * Start by reading the root property
1042 readSucessful
= StorageImpl_ReadProperty(storage
->ancestorStorage
,
1043 currentPropertyIndex
,
1047 if (currentProperty
.sizeOfNameString
== 0)
1050 * The property existis and is available, we found it.
1052 newPropertyIndex
= currentPropertyIndex
;
1058 * We exhausted the property list, we will create more space below
1060 newPropertyIndex
= currentPropertyIndex
;
1062 currentPropertyIndex
++;
1064 } while (newPropertyIndex
== PROPERTY_NULL
);
1067 * grow the property chain
1069 if (! readSucessful
)
1071 StgProperty emptyProperty
;
1072 ULARGE_INTEGER newSize
;
1073 ULONG propertyIndex
;
1074 ULONG lastProperty
= 0;
1075 ULONG blockCount
= 0;
1078 * obtain the new count of property blocks
1080 blockCount
= BlockChainStream_GetCount(
1081 storage
->ancestorStorage
->rootBlockChain
)+1;
1084 * initialize the size used by the property stream
1086 newSize
.HighPart
= 0;
1087 newSize
.LowPart
= storage
->bigBlockSize
* blockCount
;
1090 * add a property block to the property chain
1092 BlockChainStream_SetSize(storage
->ancestorStorage
->rootBlockChain
, newSize
);
1095 * memset the empty property in order to initialize the unused newly
1098 memset(&emptyProperty
, 0, sizeof(StgProperty
));
1103 lastProperty
= storage
->bigBlockSize
/ PROPSET_BLOCK_SIZE
* blockCount
;
1106 propertyIndex
= newPropertyIndex
;
1107 propertyIndex
< lastProperty
;
1110 StorageImpl_WriteProperty(
1111 storage
->ancestorStorage
,
1117 return newPropertyIndex
;
1120 /****************************************************************************
1124 * Case insensitive comparaison of StgProperty.name by first considering
1127 * Returns <0 when newPrpoerty < currentProperty
1128 * >0 when newPrpoerty > currentProperty
1129 * 0 when newPrpoerty == currentProperty
1131 static LONG
propertyNameCmp(
1132 OLECHAR
*newProperty
,
1133 OLECHAR
*currentProperty
)
1135 LONG sizeOfNew
= (lstrlenW(newProperty
) +1) * sizeof(WCHAR
);
1136 LONG sizeOfCur
= (lstrlenW(currentProperty
)+1) * sizeof(WCHAR
);
1137 LONG diff
= sizeOfNew
- sizeOfCur
;
1142 * We compare the string themselves only when they are of the same lenght
1144 WCHAR wsnew
[PROPERTY_NAME_MAX_LEN
];
1145 WCHAR wscur
[PROPERTY_NAME_MAX_LEN
];
1147 diff
= lstrcmpW( (LPCWSTR
)CRTDLL__wcsupr(
1148 lstrcpynW(wsnew
, newProperty
, sizeOfNew
)),
1149 (LPCWSTR
)CRTDLL__wcsupr(
1150 lstrcpynW(wscur
, currentProperty
, sizeOfCur
)));
1156 /****************************************************************************
1160 * Properly link this new element in the property chain.
1162 static void updatePropertyChain(
1163 StorageImpl
*storage
,
1164 ULONG newPropertyIndex
,
1165 StgProperty newProperty
)
1167 StgProperty currentProperty
;
1170 * Read the root property
1172 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1173 storage
->rootPropertySetIndex
,
1176 if (currentProperty
.dirProperty
!= PROPERTY_NULL
)
1179 * The root storage contains some element, therefore, start the research
1180 * for the appropriate location.
1183 ULONG current
, next
, previous
, currentPropertyId
;
1186 * Keep the StgProperty sequence number of the storage first property
1188 currentPropertyId
= currentProperty
.dirProperty
;
1193 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1194 currentProperty
.dirProperty
,
1197 previous
= currentProperty
.previousProperty
;
1198 next
= currentProperty
.nextProperty
;
1199 current
= currentPropertyId
;
1203 LONG diff
= propertyNameCmp( newProperty
.name
, currentProperty
.name
);
1207 if (previous
!= PROPERTY_NULL
)
1209 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1216 currentProperty
.previousProperty
= newPropertyIndex
;
1217 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1225 if (next
!= PROPERTY_NULL
)
1227 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1234 currentProperty
.nextProperty
= newPropertyIndex
;
1235 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1242 previous
= currentProperty
.previousProperty
;
1243 next
= currentProperty
.nextProperty
;
1249 * The root storage is empty, link the new property to it's dir property
1251 currentProperty
.dirProperty
= newPropertyIndex
;
1252 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1253 storage
->rootPropertySetIndex
,
1259 /*************************************************************************
1262 HRESULT WINAPI
StorageImpl_CopyTo(
1264 DWORD ciidExclude
, /* [in] */
1265 const IID
*rgiidExclude
,/* [size_is][unique][in] */
1266 SNB snbExclude
, /* [unique][in] */
1267 IStorage
*pstgDest
) /* [unique][in] */
1272 /*************************************************************************
1273 * MoveElementTo (IStorage)
1275 HRESULT WINAPI
StorageImpl_MoveElementTo(
1277 const OLECHAR
*pwcsName
, /* [string][in] */
1278 IStorage
*pstgDest
, /* [unique][in] */
1279 const OLECHAR
*pwcsNewName
,/* [string][in] */
1280 DWORD grfFlags
) /* [in] */
1285 /*************************************************************************
1288 HRESULT WINAPI
StorageImpl_Commit(
1290 DWORD grfCommitFlags
)/* [in] */
1292 FIXME(ole
, "(%ld): stub!\n", grfCommitFlags
);
1296 /*************************************************************************
1299 HRESULT WINAPI
StorageImpl_Revert(
1305 /*************************************************************************
1306 * DestroyElement (IStorage)
1308 * Stategy: This implementation is build this way for simplicity not for speed.
1309 * I always delete the top most element of the enumeration and adjust
1310 * the deleted element pointer all the time. This takes longer to
1311 * do but allow to reinvoke DestroyElement whenever we encounter a
1312 * storage object. The optimisation reside in the usage of another
1313 * enumeration stategy that would give all the leaves of a storage
1314 * first. (postfix order)
1316 HRESULT WINAPI
StorageImpl_DestroyElement(
1318 const OLECHAR
*pwcsName
)/* [string][in] */
1320 StorageImpl
* const This
=(StorageImpl
*)iface
;
1322 IEnumSTATSTGImpl
* propertyEnumeration
;
1325 StgProperty propertyToDelete
;
1326 StgProperty parentProperty
;
1327 ULONG foundPropertyIndexToDelete
;
1328 ULONG typeOfRelation
;
1329 ULONG parentPropertyId
;
1332 * Perform a sanity check on the parameters.
1335 return STG_E_INVALIDPOINTER
;
1338 * Create a property enumeration to search the property with the given name
1340 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
1341 This
->ancestorStorage
,
1342 This
->rootPropertySetIndex
);
1344 foundPropertyIndexToDelete
= IEnumSTATSTGImpl_FindProperty(
1345 propertyEnumeration
,
1349 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1351 if ( foundPropertyIndexToDelete
== PROPERTY_NULL
)
1353 return STG_E_FILENOTFOUND
;
1357 * Find the parent property of the property to delete (the one that
1358 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1359 * the parent is This. Otherwise, the parent is one of it's sibling...
1363 * First, read This's StgProperty..
1365 res
= StorageImpl_ReadProperty(
1366 This
->ancestorStorage
,
1367 This
->rootPropertySetIndex
,
1373 * Second, check to see if by any chance the actual storage (This) is not
1374 * the parent of the property to delete... We never know...
1376 if ( parentProperty
.dirProperty
== foundPropertyIndexToDelete
)
1379 * Set data as it would have been done in the else part...
1381 typeOfRelation
= PROPERTY_RELATION_DIR
;
1382 parentPropertyId
= This
->rootPropertySetIndex
;
1387 * Create a property enumeration to search the parent properties, and
1388 * delete it once done.
1390 IEnumSTATSTGImpl
* propertyEnumeration2
;
1392 propertyEnumeration2
= IEnumSTATSTGImpl_Construct(
1393 This
->ancestorStorage
,
1394 This
->rootPropertySetIndex
);
1396 typeOfRelation
= IEnumSTATSTGImpl_FindParentProperty(
1397 propertyEnumeration2
,
1398 foundPropertyIndexToDelete
,
1402 IEnumSTATSTGImpl_Destroy(propertyEnumeration2
);
1405 if ( propertyToDelete
.propertyType
== PROPTYPE_STORAGE
)
1407 hr
= deleteStorageProperty(
1409 propertyToDelete
.name
);
1411 else if ( propertyToDelete
.propertyType
== PROPTYPE_STREAM
)
1413 hr
= deleteStreamProperty(
1415 foundPropertyIndexToDelete
,
1423 * Adjust the property chain
1425 hr
= adjustPropertyChain(
1436 /*********************************************************************
1440 * Perform the deletion of a complete storage node
1443 static HRESULT
deleteStorageProperty(
1444 StorageImpl
*parentStorage
,
1445 OLECHAR
*propertyToDeleteName
)
1447 IEnumSTATSTG
*elements
= 0;
1448 IStorage
*childStorage
= 0;
1449 STATSTG currentElement
;
1451 HRESULT destroyHr
= S_OK
;
1454 * Open the storage and enumerate it
1456 hr
= StorageBaseImpl_OpenStorage(
1457 (IStorage
*)parentStorage
,
1458 propertyToDeleteName
,
1460 STGM_SHARE_EXCLUSIVE
,
1471 * Enumerate the elements
1473 IStorage_EnumElements( childStorage
, 0, 0, 0, &elements
);
1478 * Obtain the next element
1480 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1483 destroyHr
= StorageImpl_DestroyElement(
1484 (IStorage
*)childStorage
,
1485 (OLECHAR
*)currentElement
.pwcsName
);
1487 CoTaskMemFree(currentElement
.pwcsName
);
1491 * We need to Reset the enumeration every time because we delete elements
1492 * and the enumeration could be invalid
1494 IEnumSTATSTG_Reset(elements
);
1496 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1498 IStorage_Release(childStorage
);
1499 IEnumSTATSTG_Release(elements
);
1504 /*********************************************************************
1508 * Perform the deletion of a stream node
1511 static HRESULT
deleteStreamProperty(
1512 StorageImpl
*parentStorage
,
1513 ULONG indexOfPropertyToDelete
,
1514 StgProperty propertyToDelete
)
1518 ULARGE_INTEGER size
;
1523 hr
= StorageBaseImpl_OpenStream(
1524 (IStorage
*)parentStorage
,
1525 (OLECHAR
*)propertyToDelete
.name
,
1527 STGM_SHARE_EXCLUSIVE
,
1539 hr
= IStream_SetSize(pis
, size
);
1547 * Invalidate the property by zeroing it's name member.
1549 propertyToDelete
.sizeOfNameString
= 0;
1552 * Here we should re-read the property so we get the updated pointer
1553 * but since we are here to zap it, I don't do it...
1556 StorageImpl_WriteProperty(
1557 parentStorage
->ancestorStorage
,
1558 indexOfPropertyToDelete
,
1564 /*********************************************************************
1568 * Finds a placeholder for the StgProperty within the Storage
1571 static HRESULT
findPlaceholder(
1572 StorageImpl
*storage
,
1573 ULONG propertyIndexToStore
,
1574 ULONG storePropertyIndex
,
1577 StgProperty storeProperty
;
1582 * Read the storage property
1584 res
= StorageImpl_ReadProperty(
1585 storage
->ancestorStorage
,
1594 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1596 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1598 return findPlaceholder(
1600 propertyIndexToStore
,
1601 storeProperty
.previousProperty
,
1606 storeProperty
.previousProperty
= propertyIndexToStore
;
1609 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1611 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1613 return findPlaceholder(
1615 propertyIndexToStore
,
1616 storeProperty
.nextProperty
,
1621 storeProperty
.nextProperty
= propertyIndexToStore
;
1624 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1626 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1628 return findPlaceholder(
1630 propertyIndexToStore
,
1631 storeProperty
.dirProperty
,
1636 storeProperty
.dirProperty
= propertyIndexToStore
;
1640 hr
= StorageImpl_WriteProperty(
1641 storage
->ancestorStorage
,
1653 /*************************************************************************
1657 * This method takes the previous and the next property link of a property
1658 * to be deleted and find them a place in the Storage.
1660 static HRESULT
adjustPropertyChain(
1662 StgProperty propertyToDelete
,
1663 StgProperty parentProperty
,
1664 ULONG parentPropertyId
,
1667 ULONG newLinkProperty
= PROPERTY_NULL
;
1668 BOOL needToFindAPlaceholder
= FALSE
;
1669 ULONG storeNode
= PROPERTY_NULL
;
1670 ULONG toStoreNode
= PROPERTY_NULL
;
1671 INT relationType
= 0;
1675 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1677 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1680 * Set the parent previous to the property to delete previous
1682 newLinkProperty
= propertyToDelete
.previousProperty
;
1684 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1687 * We also need to find a storage for the other link, setup variables
1688 * to do this at the end...
1690 needToFindAPlaceholder
= TRUE
;
1691 storeNode
= propertyToDelete
.previousProperty
;
1692 toStoreNode
= propertyToDelete
.nextProperty
;
1693 relationType
= PROPERTY_RELATION_NEXT
;
1696 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1699 * Set the parent previous to the property to delete next
1701 newLinkProperty
= propertyToDelete
.nextProperty
;
1705 * Link it for real...
1707 parentProperty
.previousProperty
= newLinkProperty
;
1710 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1712 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1715 * Set the parent next to the property to delete next previous
1717 newLinkProperty
= propertyToDelete
.previousProperty
;
1719 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1722 * We also need to find a storage for the other link, setup variables
1723 * to do this at the end...
1725 needToFindAPlaceholder
= TRUE
;
1726 storeNode
= propertyToDelete
.previousProperty
;
1727 toStoreNode
= propertyToDelete
.nextProperty
;
1728 relationType
= PROPERTY_RELATION_NEXT
;
1731 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1734 * Set the parent next to the property to delete next
1736 newLinkProperty
= propertyToDelete
.nextProperty
;
1740 * Link it for real...
1742 parentProperty
.nextProperty
= newLinkProperty
;
1744 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1746 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1749 * Set the parent dir to the property to delete previous
1751 newLinkProperty
= propertyToDelete
.previousProperty
;
1753 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1756 * We also need to find a storage for the other link, setup variables
1757 * to do this at the end...
1759 needToFindAPlaceholder
= TRUE
;
1760 storeNode
= propertyToDelete
.previousProperty
;
1761 toStoreNode
= propertyToDelete
.nextProperty
;
1762 relationType
= PROPERTY_RELATION_NEXT
;
1765 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1768 * Set the parent dir to the property to delete next
1770 newLinkProperty
= propertyToDelete
.nextProperty
;
1774 * Link it for real...
1776 parentProperty
.dirProperty
= newLinkProperty
;
1780 * Write back the parent property
1782 res
= StorageImpl_WriteProperty(
1783 This
->ancestorStorage
,
1792 * If a placeholder is required for the other link, then, find one and
1793 * get out of here...
1795 if (needToFindAPlaceholder
)
1797 hr
= findPlaceholder(
1808 /******************************************************************************
1809 * SetElementTimes (IStorage)
1811 HRESULT WINAPI
StorageImpl_SetElementTimes(
1813 const OLECHAR
*pwcsName
,/* [string][in] */
1814 const FILETIME
*pctime
, /* [in] */
1815 const FILETIME
*patime
, /* [in] */
1816 const FILETIME
*pmtime
) /* [in] */
1821 /******************************************************************************
1822 * SetStateBits (IStorage)
1824 HRESULT WINAPI
StorageImpl_SetStateBits(
1826 DWORD grfStateBits
,/* [in] */
1827 DWORD grfMask
) /* [in] */
1832 HRESULT
StorageImpl_Construct(
1838 StgProperty currentProperty
;
1840 ULONG currentPropertyIndex
;
1842 if ( FAILED( validateSTGM(openFlags
) ))
1843 return STG_E_INVALIDFLAG
;
1845 memset(This
, 0, sizeof(StorageImpl
));
1848 * Initialize the virtual fgunction table.
1850 This
->lpvtbl
= &Storage32Impl_Vtbl
;
1851 This
->v_destructor
= &StorageImpl_Destroy
;
1854 * This is the top-level storage so initialize the ancester pointer
1857 This
->ancestorStorage
= This
;
1860 * Initialize the physical support of the storage.
1862 This
->hFile
= hFile
;
1865 * Initialize the big block cache.
1867 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
1868 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
1869 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
,
1871 This
->bigBlockSize
);
1873 if (This
->bigBlockFile
== 0)
1876 if (openFlags
& STGM_CREATE
)
1878 ULARGE_INTEGER size
;
1879 BYTE
* bigBlockBuffer
;
1882 * Initialize all header variables:
1883 * - The big block depot consists of one block and it is at block 0
1884 * - The properties start at block 1
1885 * - There is no small block depot
1887 memset( This
->bigBlockDepotStart
,
1889 sizeof(This
->bigBlockDepotStart
));
1891 This
->bigBlockDepotCount
= 1;
1892 This
->bigBlockDepotStart
[0] = 0;
1893 This
->rootStartBlock
= 1;
1894 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
1895 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
1896 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
1897 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
1898 This
->extBigBlockDepotCount
= 0;
1900 StorageImpl_SaveFileHeader(This
);
1903 * Add one block for the big block depot and one block for the properties
1906 size
.LowPart
= This
->bigBlockSize
* 3;
1907 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
1910 * Initialize the big block depot
1912 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, 0);
1913 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
1914 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
1915 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
1916 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
1921 * Load the header for the file.
1923 StorageImpl_LoadFileHeader(This
);
1927 * There is no block depot cached yet.
1929 This
->indexBlockDepotCached
= 0xFFFFFFFF;
1932 * Create the block chain abstractions.
1934 This
->rootBlockChain
=
1935 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
1937 This
->smallBlockDepotChain
= BlockChainStream_Construct(
1939 &This
->smallBlockDepotStart
,
1943 * Write the root property
1945 if (openFlags
& STGM_CREATE
)
1947 StgProperty rootProp
;
1949 * Initialize the property chain
1951 memset(&rootProp
, 0, sizeof(rootProp
));
1952 lstrcpyAtoW(rootProp
.name
, rootPropertyName
);
1954 rootProp
.sizeOfNameString
= (lstrlenW(rootProp
.name
)+1) * sizeof(WCHAR
);
1955 rootProp
.propertyType
= PROPTYPE_ROOT
;
1956 rootProp
.previousProperty
= PROPERTY_NULL
;
1957 rootProp
.nextProperty
= PROPERTY_NULL
;
1958 rootProp
.dirProperty
= PROPERTY_NULL
;
1959 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
1960 rootProp
.size
.HighPart
= 0;
1961 rootProp
.size
.LowPart
= 0;
1963 StorageImpl_WriteProperty(This
, 0, &rootProp
);
1967 * Find the ID of the root int he property sets.
1969 currentPropertyIndex
= 0;
1973 readSucessful
= StorageImpl_ReadProperty(
1975 currentPropertyIndex
,
1980 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
1981 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
1983 This
->rootPropertySetIndex
= currentPropertyIndex
;
1987 currentPropertyIndex
++;
1989 } while (readSucessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
1998 * Create the block chain abstraction for the small block root chain.
2000 This
->smallBlockRootChain
= BlockChainStream_Construct(
2003 This
->rootPropertySetIndex
);
2008 void StorageImpl_Destroy(
2011 BlockChainStream_Destroy(This
->smallBlockRootChain
);
2012 BlockChainStream_Destroy(This
->rootBlockChain
);
2013 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
2015 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2019 /******************************************************************************
2020 * Storage32Impl_GetNextFreeBigBlock
2022 * Returns the index of the next free big block.
2023 * If the big block depot is filled, this method will enlarge it.
2026 ULONG
StorageImpl_GetNextFreeBigBlock(
2029 ULONG depotBlockIndexPos
;
2031 ULONG depotBlockOffset
;
2032 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
2033 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2035 ULONG blockNoInSequence
= 0;
2038 * Scan the entire big block depot until we find a block marked free
2040 while (nextBlockIndex
!= BLOCK_UNUSED
)
2042 if (depotIndex
< COUNT_BBDEPOTINHEADER
)
2044 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2047 * Grow the primary depot.
2049 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2051 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2054 * Add a block depot.
2056 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2057 This
->bigBlockDepotCount
++;
2058 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2061 * Flag it as a block depot.
2063 StorageImpl_SetNextBlockInChain(This
,
2067 /* Save new header information.
2069 StorageImpl_SaveFileHeader(This
);
2074 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotIndex
);
2076 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2079 * Grow the extended depot.
2081 ULONG extIndex
= BLOCK_UNUSED
;
2082 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2083 ULONG extBlockOffset
= numExtBlocks
% (blocksPerDepot
- 1);
2085 if (extBlockOffset
== 0)
2087 /* We need an extended block.
2089 extIndex
= Storage32Impl_AddExtBlockDepot(This
);
2090 This
->extBigBlockDepotCount
++;
2091 depotBlockIndexPos
= extIndex
+ 1;
2094 depotBlockIndexPos
= depotIndex
* blocksPerDepot
;
2097 * Add a block depot and mark it in the extended block.
2099 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2100 This
->bigBlockDepotCount
++;
2101 Storage32Impl_SetExtDepotBlock(This
, depotIndex
, depotBlockIndexPos
);
2103 /* Flag the block depot.
2105 StorageImpl_SetNextBlockInChain(This
,
2109 /* If necessary, flag the extended depot block.
2111 if (extIndex
!= BLOCK_UNUSED
)
2112 StorageImpl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2114 /* Save header information.
2116 StorageImpl_SaveFileHeader(This
);
2120 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2122 if (depotBuffer
!= 0)
2124 depotBlockOffset
= 0;
2126 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2127 ( nextBlockIndex
!= BLOCK_UNUSED
))
2129 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2131 if (nextBlockIndex
!= BLOCK_UNUSED
)
2132 blockNoInSequence
++;
2134 depotBlockOffset
+= sizeof(ULONG
);
2137 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2143 return blockNoInSequence
;
2146 /******************************************************************************
2147 * Storage32Impl_AddBlockDepot
2149 * This will create a depot block, essentially it is a block initialized
2152 void Storage32Impl_AddBlockDepot(StorageImpl
* This
, ULONG blockIndex
)
2156 blockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2159 * Initialize blocks as free
2161 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2163 StorageImpl_ReleaseBigBlock(This
, blockBuffer
);
2166 /******************************************************************************
2167 * Storage32Impl_GetExtDepotBlock
2169 * Returns the index of the block that corresponds to the specified depot
2170 * index. This method is only for depot indexes equal or greater than
2171 * COUNT_BBDEPOTINHEADER.
2173 ULONG
Storage32Impl_GetExtDepotBlock(StorageImpl
* This
, ULONG depotIndex
)
2175 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2176 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2177 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2178 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2179 ULONG blockIndex
= BLOCK_UNUSED
;
2180 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2182 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2184 if (This
->extBigBlockDepotStart
== BLOCK_END_OF_CHAIN
)
2185 return BLOCK_UNUSED
;
2187 while (extBlockCount
> 0)
2189 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2193 if (extBlockIndex
!= BLOCK_UNUSED
)
2197 depotBuffer
= StorageImpl_GetROBigBlock(This
, extBlockIndex
);
2199 if (depotBuffer
!= 0)
2201 StorageUtl_ReadDWord(depotBuffer
,
2202 extBlockOffset
* sizeof(ULONG
),
2205 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2212 /******************************************************************************
2213 * Storage32Impl_SetExtDepotBlock
2215 * Associates the specified block index to the specified depot index.
2216 * This method is only for depot indexes equal or greater than
2217 * COUNT_BBDEPOTINHEADER.
2219 void Storage32Impl_SetExtDepotBlock(StorageImpl
* This
,
2223 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2224 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2225 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2226 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2227 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2229 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2231 while (extBlockCount
> 0)
2233 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2237 if (extBlockIndex
!= BLOCK_UNUSED
)
2241 depotBuffer
= StorageImpl_GetBigBlock(This
, extBlockIndex
);
2243 if (depotBuffer
!= 0)
2245 StorageUtl_WriteDWord(depotBuffer
,
2246 extBlockOffset
* sizeof(ULONG
),
2249 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2254 /******************************************************************************
2255 * Storage32Impl_AddExtBlockDepot
2257 * Creates an extended depot block.
2259 ULONG
Storage32Impl_AddExtBlockDepot(StorageImpl
* This
)
2261 ULONG numExtBlocks
= This
->extBigBlockDepotCount
;
2262 ULONG nextExtBlock
= This
->extBigBlockDepotStart
;
2263 BYTE
* depotBuffer
= NULL
;
2264 ULONG index
= BLOCK_UNUSED
;
2265 ULONG nextBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2266 ULONG blocksPerDepotBlock
= This
->bigBlockSize
/ sizeof(ULONG
);
2267 ULONG depotBlocksPerExtBlock
= blocksPerDepotBlock
- 1;
2269 index
= (COUNT_BBDEPOTINHEADER
+ (numExtBlocks
* depotBlocksPerExtBlock
)) *
2270 blocksPerDepotBlock
;
2272 if ((numExtBlocks
== 0) && (nextExtBlock
== BLOCK_END_OF_CHAIN
))
2275 * The first extended block.
2277 This
->extBigBlockDepotStart
= index
;
2283 * Follow the chain to the last one.
2285 for (i
= 0; i
< (numExtBlocks
- 1); i
++)
2287 nextExtBlock
= Storage32Impl_GetNextExtendedBlock(This
, nextExtBlock
);
2291 * Add the new extended block to the chain.
2293 depotBuffer
= StorageImpl_GetBigBlock(This
, nextExtBlock
);
2294 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2295 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2299 * Initialize this block.
2301 depotBuffer
= StorageImpl_GetBigBlock(This
, index
);
2302 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2303 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2308 /******************************************************************************
2309 * Storage32Impl_FreeBigBlock
2311 * This method will flag the specified block as free in the big block depot.
2313 void StorageImpl_FreeBigBlock(
2317 StorageImpl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2320 /************************************************************************
2321 * Storage32Impl_GetNextBlockInChain
2323 * This method will retrieve the block index of the next big block in
2326 * Params: This - Pointer to the Storage object.
2327 * blockIndex - Index of the block to retrieve the chain
2330 * Returns: This method returns the index of the next block in the chain.
2331 * It will return the constants:
2332 * BLOCK_SPECIAL - If the block given was not part of a
2334 * BLOCK_END_OF_CHAIN - If the block given was the last in
2336 * BLOCK_UNUSED - If the block given was not past of a chain
2338 * BLOCK_EXTBBDEPOT - This block is part of the extended
2341 * See Windows documentation for more details on IStorage methods.
2343 ULONG
StorageImpl_GetNextBlockInChain(
2347 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2348 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2349 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2350 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2352 ULONG depotBlockIndexPos
;
2354 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2357 * Cache the currently accessed depot block.
2359 if (depotBlockCount
!= This
->indexBlockDepotCached
)
2361 This
->indexBlockDepotCached
= depotBlockCount
;
2363 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2365 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2370 * We have to look in the extended depot.
2372 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2375 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2381 for (index
= 0; index
< NUM_BLOCKS_PER_DEPOT_BLOCK
; index
++)
2383 StorageUtl_ReadDWord(depotBuffer
, index
*sizeof(ULONG
), &nextBlockIndex
);
2384 This
->blockDepotCached
[index
] = nextBlockIndex
;
2387 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2391 nextBlockIndex
= This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)];
2393 return nextBlockIndex
;
2396 /******************************************************************************
2397 * Storage32Impl_GetNextExtendedBlock
2399 * Given an extended block this method will return the next extended block.
2402 * The last ULONG of an extended block is the block index of the next
2403 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2407 * - The index of the next extended block
2408 * - BLOCK_UNUSED: there is no next extended block.
2409 * - Any other return values denotes failure.
2411 ULONG
Storage32Impl_GetNextExtendedBlock(StorageImpl
* This
, ULONG blockIndex
)
2413 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2414 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2417 depotBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2421 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2423 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2426 return nextBlockIndex
;
2429 /******************************************************************************
2430 * Storage32Impl_SetNextBlockInChain
2432 * This method will write the index of the specified block's next block
2433 * in the big block depot.
2435 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2438 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2439 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2440 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2443 void StorageImpl_SetNextBlockInChain(
2448 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2449 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2450 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2451 ULONG depotBlockIndexPos
;
2454 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2456 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2458 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2463 * We have to look in the extended depot.
2465 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2468 depotBuffer
= StorageImpl_GetBigBlock(This
, depotBlockIndexPos
);
2472 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2473 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2477 * Update the cached block depot, if necessary.
2479 if (depotBlockCount
== This
->indexBlockDepotCached
)
2481 This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)] = nextBlock
;
2485 /******************************************************************************
2486 * Storage32Impl_LoadFileHeader
2488 * This method will read in the file header, i.e. big block index -1.
2490 HRESULT
StorageImpl_LoadFileHeader(
2493 HRESULT hr
= STG_E_FILENOTFOUND
;
2494 void* headerBigBlock
= NULL
;
2498 * Get a pointer to the big block of data containing the header.
2500 headerBigBlock
= StorageImpl_GetROBigBlock(This
, -1);
2503 * Extract the information from the header.
2505 if (headerBigBlock
!=0)
2508 * Check for the "magic number" signature and return an error if it is not
2511 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2513 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2514 return STG_E_OLDFORMAT
;
2517 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2519 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2520 return STG_E_INVALIDHEADER
;
2523 StorageUtl_ReadWord(
2525 OFFSET_BIGBLOCKSIZEBITS
,
2526 &This
->bigBlockSizeBits
);
2528 StorageUtl_ReadWord(
2530 OFFSET_SMALLBLOCKSIZEBITS
,
2531 &This
->smallBlockSizeBits
);
2533 StorageUtl_ReadDWord(
2535 OFFSET_BBDEPOTCOUNT
,
2536 &This
->bigBlockDepotCount
);
2538 StorageUtl_ReadDWord(
2540 OFFSET_ROOTSTARTBLOCK
,
2541 &This
->rootStartBlock
);
2543 StorageUtl_ReadDWord(
2545 OFFSET_SBDEPOTSTART
,
2546 &This
->smallBlockDepotStart
);
2548 StorageUtl_ReadDWord(
2550 OFFSET_EXTBBDEPOTSTART
,
2551 &This
->extBigBlockDepotStart
);
2553 StorageUtl_ReadDWord(
2555 OFFSET_EXTBBDEPOTCOUNT
,
2556 &This
->extBigBlockDepotCount
);
2558 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2560 StorageUtl_ReadDWord(
2562 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2563 &(This
->bigBlockDepotStart
[index
]));
2567 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2571 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2572 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2576 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2577 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2581 * Right now, the code is making some assumptions about the size of the
2582 * blocks, just make sure they are what we're expecting.
2584 assert( (This
->bigBlockSize
==DEF_BIG_BLOCK_SIZE
) &&
2585 (This
->smallBlockSize
==DEF_SMALL_BLOCK_SIZE
));
2588 * Release the block.
2590 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2596 /******************************************************************************
2597 * Storage32Impl_SaveFileHeader
2599 * This method will save to the file the header, i.e. big block -1.
2601 void StorageImpl_SaveFileHeader(
2604 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2609 * Get a pointer to the big block of data containing the header.
2611 success
= StorageImpl_ReadBigBlock(This
, -1, headerBigBlock
);
2614 * If the block read failed, the file is probably new.
2619 * Initialize for all unknown fields.
2621 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
2624 * Initialize the magic number.
2626 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
2629 * And a bunch of things we don't know what they mean
2631 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
2632 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
2633 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
2634 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
2635 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
2639 * Write the information to the header.
2641 if (headerBigBlock
!=0)
2643 StorageUtl_WriteWord(
2645 OFFSET_BIGBLOCKSIZEBITS
,
2646 This
->bigBlockSizeBits
);
2648 StorageUtl_WriteWord(
2650 OFFSET_SMALLBLOCKSIZEBITS
,
2651 This
->smallBlockSizeBits
);
2653 StorageUtl_WriteDWord(
2655 OFFSET_BBDEPOTCOUNT
,
2656 This
->bigBlockDepotCount
);
2658 StorageUtl_WriteDWord(
2660 OFFSET_ROOTSTARTBLOCK
,
2661 This
->rootStartBlock
);
2663 StorageUtl_WriteDWord(
2665 OFFSET_SBDEPOTSTART
,
2666 This
->smallBlockDepotStart
);
2668 StorageUtl_WriteDWord(
2670 OFFSET_EXTBBDEPOTSTART
,
2671 This
->extBigBlockDepotStart
);
2673 StorageUtl_WriteDWord(
2675 OFFSET_EXTBBDEPOTCOUNT
,
2676 This
->extBigBlockDepotCount
);
2678 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2680 StorageUtl_WriteDWord(
2682 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2683 (This
->bigBlockDepotStart
[index
]));
2688 * Write the big block back to the file.
2690 StorageImpl_WriteBigBlock(This
, -1, headerBigBlock
);
2693 /******************************************************************************
2694 * Storage32Impl_ReadProperty
2696 * This method will read the specified property from the property chain.
2698 BOOL
StorageImpl_ReadProperty(
2701 StgProperty
* buffer
)
2703 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2704 ULARGE_INTEGER offsetInPropSet
;
2708 offsetInPropSet
.HighPart
= 0;
2709 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
2711 readSucessful
= BlockChainStream_ReadAt(
2712 This
->rootBlockChain
,
2720 memset(buffer
->name
, 0, sizeof(buffer
->name
));
2723 currentProperty
+OFFSET_PS_NAME
,
2724 PROPERTY_NAME_BUFFER_LEN
);
2726 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
2728 StorageUtl_ReadWord(
2730 OFFSET_PS_NAMELENGTH
,
2731 &buffer
->sizeOfNameString
);
2733 StorageUtl_ReadDWord(
2735 OFFSET_PS_PREVIOUSPROP
,
2736 &buffer
->previousProperty
);
2738 StorageUtl_ReadDWord(
2741 &buffer
->nextProperty
);
2743 StorageUtl_ReadDWord(
2746 &buffer
->dirProperty
);
2748 StorageUtl_ReadGUID(
2751 &buffer
->propertyUniqueID
);
2753 StorageUtl_ReadDWord(
2756 &buffer
->timeStampS1
);
2758 StorageUtl_ReadDWord(
2761 &buffer
->timeStampD1
);
2763 StorageUtl_ReadDWord(
2766 &buffer
->timeStampS2
);
2768 StorageUtl_ReadDWord(
2771 &buffer
->timeStampD2
);
2773 StorageUtl_ReadDWord(
2775 OFFSET_PS_STARTBLOCK
,
2776 &buffer
->startingBlock
);
2778 StorageUtl_ReadDWord(
2781 &buffer
->size
.LowPart
);
2783 buffer
->size
.HighPart
= 0;
2786 return readSucessful
;
2789 /*********************************************************************
2790 * Write the specified property into the property chain
2792 BOOL
StorageImpl_WriteProperty(
2795 StgProperty
* buffer
)
2797 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2798 ULARGE_INTEGER offsetInPropSet
;
2799 BOOL writeSucessful
;
2802 offsetInPropSet
.HighPart
= 0;
2803 offsetInPropSet
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
2805 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
2808 currentProperty
+ OFFSET_PS_NAME
,
2810 PROPERTY_NAME_BUFFER_LEN
);
2812 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
2815 * Reassign the size in case of mistake....
2817 buffer
->sizeOfNameString
= (lstrlenW(buffer
->name
)+1) * sizeof(WCHAR
);
2819 StorageUtl_WriteWord(
2821 OFFSET_PS_NAMELENGTH
,
2822 buffer
->sizeOfNameString
);
2824 StorageUtl_WriteDWord(
2826 OFFSET_PS_PREVIOUSPROP
,
2827 buffer
->previousProperty
);
2829 StorageUtl_WriteDWord(
2832 buffer
->nextProperty
);
2834 StorageUtl_WriteDWord(
2837 buffer
->dirProperty
);
2839 StorageUtl_WriteGUID(
2842 &buffer
->propertyUniqueID
);
2844 StorageUtl_WriteDWord(
2847 buffer
->timeStampS1
);
2849 StorageUtl_WriteDWord(
2852 buffer
->timeStampD1
);
2854 StorageUtl_WriteDWord(
2857 buffer
->timeStampS2
);
2859 StorageUtl_WriteDWord(
2862 buffer
->timeStampD2
);
2864 StorageUtl_WriteDWord(
2866 OFFSET_PS_STARTBLOCK
,
2867 buffer
->startingBlock
);
2869 StorageUtl_WriteDWord(
2872 buffer
->size
.LowPart
);
2874 writeSucessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
2879 return writeSucessful
;
2882 BOOL
StorageImpl_ReadBigBlock(
2887 void* bigBlockBuffer
;
2889 bigBlockBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2891 if (bigBlockBuffer
!=0)
2893 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
2895 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2903 BOOL
StorageImpl_WriteBigBlock(
2908 void* bigBlockBuffer
;
2910 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2912 if (bigBlockBuffer
!=0)
2914 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
2916 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2924 void* StorageImpl_GetROBigBlock(
2928 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
2931 void* StorageImpl_GetBigBlock(
2935 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
2938 void StorageImpl_ReleaseBigBlock(
2942 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
2945 /******************************************************************************
2946 * Storage32Impl_SmallBlocksToBigBlocks
2948 * This method will convert a small block chain to a big block chain.
2949 * The small block chain will be destroyed.
2951 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
2953 SmallBlockChainStream
** ppsbChain
)
2955 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
2956 ULARGE_INTEGER size
, offset
;
2957 ULONG cbRead
, cbWritten
, cbTotalRead
, cbTotalWritten
;
2958 ULONG propertyIndex
;
2959 BOOL successRead
, successWrite
;
2960 StgProperty chainProperty
;
2961 BYTE buffer
[DEF_SMALL_BLOCK_SIZE
];
2962 BlockChainStream
*bbTempChain
= NULL
;
2963 BlockChainStream
*bigBlockChain
= NULL
;
2966 * Create a temporary big block chain that doesn't have
2967 * an associated property. This temporary chain will be
2968 * used to copy data from small blocks to big blocks.
2970 bbTempChain
= BlockChainStream_Construct(This
,
2975 * Grow the big block chain.
2977 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
2978 BlockChainStream_SetSize(bbTempChain
, size
);
2981 * Copy the contents of the small block chain to the big block chain
2982 * by small block size increments.
2985 offset
.HighPart
= 0;
2991 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
2996 cbTotalRead
+= cbRead
;
2998 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
3003 cbTotalWritten
+= cbWritten
;
3005 offset
.LowPart
+= This
->smallBlockSize
;
3007 } while (successRead
&& successWrite
);
3009 assert(cbTotalRead
== cbTotalWritten
);
3012 * Destroy the small block chain.
3014 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
3017 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
3018 SmallBlockChainStream_Destroy(*ppsbChain
);
3022 * Change the property information. This chain is now a big block chain
3023 * and it doesn't reside in the small blocks chain anymore.
3025 StorageImpl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3027 chainProperty
.startingBlock
= bbHeadOfChain
;
3029 StorageImpl_WriteProperty(This
, propertyIndex
, &chainProperty
);
3032 * Destroy the temporary propertyless big block chain.
3033 * Create a new big block chain associated with this property.
3035 BlockChainStream_Destroy(bbTempChain
);
3036 bigBlockChain
= BlockChainStream_Construct(This
,
3040 return bigBlockChain
;
3043 /******************************************************************************
3044 ** Storage32InternalImpl implementation
3047 StorageInternalImpl
* StorageInternalImpl_Construct(
3048 StorageImpl
* ancestorStorage
,
3049 ULONG rootPropertyIndex
)
3051 StorageInternalImpl
* newStorage
;
3054 * Allocate space for the new storage object
3056 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl
));
3060 memset(newStorage
, 0, sizeof(StorageInternalImpl
));
3063 * Initialize the virtual function table.
3065 newStorage
->lpvtbl
= &Storage32InternalImpl_Vtbl
;
3066 newStorage
->v_destructor
= &StorageInternalImpl_Destroy
;
3069 * Keep the ancestor storage pointer and nail a reference to it.
3071 newStorage
->ancestorStorage
= ancestorStorage
;
3072 StorageBaseImpl_AddRef((IStorage
*)(newStorage
->ancestorStorage
));
3075 * Keep the index of the root property set for this storage,
3077 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3085 void StorageInternalImpl_Destroy(
3086 StorageInternalImpl
* This
)
3088 StorageBaseImpl_Release((IStorage
*)This
->ancestorStorage
);
3089 HeapFree(GetProcessHeap(), 0, This
);
3092 /******************************************************************************
3094 ** Storage32InternalImpl_Commit
3096 ** The non-root storages cannot be opened in transacted mode thus this function
3099 HRESULT WINAPI
StorageInternalImpl_Commit(
3101 DWORD grfCommitFlags
) /* [in] */
3106 /******************************************************************************
3108 ** Storage32InternalImpl_Revert
3110 ** The non-root storages cannot be opened in transacted mode thus this function
3113 HRESULT WINAPI
StorageInternalImpl_Revert(
3119 /******************************************************************************
3120 ** IEnumSTATSTGImpl implementation
3123 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3124 StorageImpl
* parentStorage
,
3125 ULONG firstPropertyNode
)
3127 IEnumSTATSTGImpl
* newEnumeration
;
3129 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3131 if (newEnumeration
!=0)
3134 * Set-up the virtual function table and reference count.
3136 newEnumeration
->lpvtbl
= &IEnumSTATSTGImpl_Vtbl
;
3137 newEnumeration
->ref
= 0;
3140 * We want to nail-down the reference to the storage in case the
3141 * enumeration out-lives the storage in the client application.
3143 newEnumeration
->parentStorage
= parentStorage
;
3144 IStorage_AddRef((IStorage
*)newEnumeration
->parentStorage
);
3146 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3149 * Initialize the search stack
3151 newEnumeration
->stackSize
= 0;
3152 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3153 newEnumeration
->stackToVisit
=
3154 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3157 * Make sure the current node of the iterator is the first one.
3159 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3162 return newEnumeration
;
3165 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3167 IStorage_Release((IStorage
*)This
->parentStorage
);
3168 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3169 HeapFree(GetProcessHeap(), 0, This
);
3172 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3173 IEnumSTATSTG
* iface
,
3177 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3180 * Perform a sanity check on the parameters.
3183 return E_INVALIDARG
;
3186 * Initialize the return parameter.
3191 * Compare the riid with the interface IDs implemented by this object.
3193 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3195 *ppvObject
= (IEnumSTATSTG
*)This
;
3197 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3199 *ppvObject
= (IEnumSTATSTG
*)This
;
3203 * Check that we obtained an interface.
3205 if ((*ppvObject
)==0)
3206 return E_NOINTERFACE
;
3209 * Query Interface always increases the reference count by one when it is
3212 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3217 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3218 IEnumSTATSTG
* iface
)
3220 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3226 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3227 IEnumSTATSTG
* iface
)
3229 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3237 * If the reference count goes down to 0, perform suicide.
3241 IEnumSTATSTGImpl_Destroy(This
);
3247 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3248 IEnumSTATSTG
* iface
,
3251 ULONG
* pceltFetched
)
3253 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3255 StgProperty currentProperty
;
3256 STATSTG
* currentReturnStruct
= rgelt
;
3257 ULONG objectFetched
= 0;
3258 ULONG currentSearchNode
;
3261 * Perform a sanity check on the parameters.
3263 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3264 return E_INVALIDARG
;
3267 * To avoid the special case, get another pointer to a ULONG value if
3268 * the caller didn't supply one.
3270 if (pceltFetched
==0)
3271 pceltFetched
= &objectFetched
;
3274 * Start the iteration, we will iterate until we hit the end of the
3275 * linked list or until we hit the number of items to iterate through
3280 * Start with the node at the top of the stack.
3282 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3284 while ( ( *pceltFetched
< celt
) &&
3285 ( currentSearchNode
!=PROPERTY_NULL
) )
3288 * Remove the top node from the stack
3290 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3293 * Read the property from the storage.
3295 StorageImpl_ReadProperty(This
->parentStorage
,
3300 * Copy the information to the return buffer.
3302 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3307 * Step to the next item in the iteration
3310 currentReturnStruct
++;
3313 * Push the next search node in the search stack.
3315 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3318 * continue the iteration.
3320 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3323 if (*pceltFetched
== celt
)
3330 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3331 IEnumSTATSTG
* iface
,
3334 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3336 StgProperty currentProperty
;
3337 ULONG objectFetched
= 0;
3338 ULONG currentSearchNode
;
3341 * Start with the node at the top of the stack.
3343 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3345 while ( (objectFetched
< celt
) &&
3346 (currentSearchNode
!=PROPERTY_NULL
) )
3349 * Remove the top node from the stack
3351 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3354 * Read the property from the storage.
3356 StorageImpl_ReadProperty(This
->parentStorage
,
3361 * Step to the next item in the iteration
3366 * Push the next search node in the search stack.
3368 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3371 * continue the iteration.
3373 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3376 if (objectFetched
== celt
)
3382 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3383 IEnumSTATSTG
* iface
)
3385 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3387 StgProperty rootProperty
;
3391 * Re-initialize the search stack to an empty stack
3393 This
->stackSize
= 0;
3396 * Read the root property from the storage.
3398 readSucessful
= StorageImpl_ReadProperty(
3399 This
->parentStorage
,
3400 This
->firstPropertyNode
,
3405 assert(rootProperty
.sizeOfNameString
!=0);
3408 * Push the search node in the search stack.
3410 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3416 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3417 IEnumSTATSTG
* iface
,
3418 IEnumSTATSTG
** ppenum
)
3420 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3422 IEnumSTATSTGImpl
* newClone
;
3425 * Perform a sanity check on the parameters.
3428 return E_INVALIDARG
;
3430 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3431 This
->firstPropertyNode
);
3435 * The new clone enumeration must point to the same current node as
3438 newClone
->stackSize
= This
->stackSize
;
3439 newClone
->stackMaxSize
= This
->stackMaxSize
;
3440 newClone
->stackToVisit
=
3441 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3444 newClone
->stackToVisit
,
3446 sizeof(ULONG
) * newClone
->stackSize
);
3448 *ppenum
= (IEnumSTATSTG
*)newClone
;
3451 * Don't forget to nail down a reference to the clone before
3454 IEnumSTATSTGImpl_AddRef(*ppenum
);
3459 INT
IEnumSTATSTGImpl_FindParentProperty(
3460 IEnumSTATSTGImpl
*This
,
3461 ULONG childProperty
,
3462 StgProperty
*currentProperty
,
3465 ULONG currentSearchNode
;
3469 * To avoid the special case, get another pointer to a ULONG value if
3470 * the caller didn't supply one.
3473 thisNodeId
= &foundNode
;
3476 * Start with the node at the top of the stack.
3478 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3481 while (currentSearchNode
!=PROPERTY_NULL
)
3484 * Store the current node in the returned parameters
3486 *thisNodeId
= currentSearchNode
;
3489 * Remove the top node from the stack
3491 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3494 * Read the property from the storage.
3496 StorageImpl_ReadProperty(
3497 This
->parentStorage
,
3501 if (currentProperty
->previousProperty
== childProperty
)
3502 return PROPERTY_RELATION_PREVIOUS
;
3504 else if (currentProperty
->nextProperty
== childProperty
)
3505 return PROPERTY_RELATION_NEXT
;
3507 else if (currentProperty
->dirProperty
== childProperty
)
3508 return PROPERTY_RELATION_DIR
;
3511 * Push the next search node in the search stack.
3513 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3516 * continue the iteration.
3518 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3521 return PROPERTY_NULL
;
3524 ULONG
IEnumSTATSTGImpl_FindProperty(
3525 IEnumSTATSTGImpl
* This
,
3526 const OLECHAR
* lpszPropName
,
3527 StgProperty
* currentProperty
)
3529 ULONG currentSearchNode
;
3532 * Start with the node at the top of the stack.
3534 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3536 while (currentSearchNode
!=PROPERTY_NULL
)
3539 * Remove the top node from the stack
3541 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3544 * Read the property from the storage.
3546 StorageImpl_ReadProperty(This
->parentStorage
,
3550 if ( propertyNameCmp(
3551 (OLECHAR
*)currentProperty
->name
,
3552 (OLECHAR
*)lpszPropName
) == 0)
3553 return currentSearchNode
;
3556 * Push the next search node in the search stack.
3558 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3561 * continue the iteration.
3563 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3566 return PROPERTY_NULL
;
3569 void IEnumSTATSTGImpl_PushSearchNode(
3570 IEnumSTATSTGImpl
* This
,
3573 StgProperty rootProperty
;
3577 * First, make sure we're not trying to push an unexisting node.
3579 if (nodeToPush
==PROPERTY_NULL
)
3583 * First push the node to the stack
3585 if (This
->stackSize
== This
->stackMaxSize
)
3587 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3589 This
->stackToVisit
= HeapReAlloc(
3593 sizeof(ULONG
) * This
->stackMaxSize
);
3596 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3600 * Read the root property from the storage.
3602 readSucessful
= StorageImpl_ReadProperty(
3603 This
->parentStorage
,
3609 assert(rootProperty
.sizeOfNameString
!=0);
3612 * Push the previous search node in the search stack.
3614 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3618 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3619 IEnumSTATSTGImpl
* This
,
3624 if (This
->stackSize
== 0)
3625 return PROPERTY_NULL
;
3627 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3635 /******************************************************************************
3636 ** StorageUtl implementation
3639 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3641 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3644 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3646 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3649 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3651 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3654 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3656 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3659 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3661 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3662 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3663 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3665 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
3668 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
3670 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
3671 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
3672 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
3674 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
3677 void StorageUtl_CopyPropertyToSTATSTG(
3678 STATSTG
* destination
,
3679 StgProperty
* source
,
3683 * The copy of the string occurs only when the flag is not set
3685 if ((statFlags
& STATFLAG_NONAME
) != 0)
3687 destination
->pwcsName
= 0;
3691 destination
->pwcsName
=
3692 CoTaskMemAlloc((lstrlenW(source
->name
)+1)*sizeof(WCHAR
));
3694 lstrcpyW((LPWSTR
)destination
->pwcsName
, source
->name
);
3697 switch (source
->propertyType
)
3699 case PROPTYPE_STORAGE
:
3701 destination
->type
= STGTY_STORAGE
;
3703 case PROPTYPE_STREAM
:
3704 destination
->type
= STGTY_STREAM
;
3707 destination
->type
= STGTY_STREAM
;
3711 destination
->cbSize
= source
->size
;
3713 currentReturnStruct->mtime = {0}; TODO
3714 currentReturnStruct->ctime = {0};
3715 currentReturnStruct->atime = {0};
3717 destination
->grfMode
= 0;
3718 destination
->grfLocksSupported
= 0;
3719 destination
->clsid
= source
->propertyUniqueID
;
3720 destination
->grfStateBits
= 0;
3721 destination
->reserved
= 0;
3724 /******************************************************************************
3725 ** BlockChainStream implementation
3728 BlockChainStream
* BlockChainStream_Construct(
3729 StorageImpl
* parentStorage
,
3730 ULONG
* headOfStreamPlaceHolder
,
3731 ULONG propertyIndex
)
3733 BlockChainStream
* newStream
;
3735 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
3737 newStream
->parentStorage
= parentStorage
;
3738 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
3739 newStream
->ownerPropertyIndex
= propertyIndex
;
3744 void BlockChainStream_Destroy(BlockChainStream
* This
)
3746 HeapFree(GetProcessHeap(), 0, This
);
3749 /******************************************************************************
3750 * BlockChainStream_GetHeadOfChain
3752 * Returns the head of this stream chain.
3753 * Some special chains don't have properties, their heads are kept in
3754 * This->headOfStreamPlaceHolder.
3757 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
3759 StgProperty chainProperty
;
3762 if (This
->headOfStreamPlaceHolder
!= 0)
3763 return *(This
->headOfStreamPlaceHolder
);
3765 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
3767 readSucessful
= StorageImpl_ReadProperty(
3768 This
->parentStorage
,
3769 This
->ownerPropertyIndex
,
3774 return chainProperty
.startingBlock
;
3778 return BLOCK_END_OF_CHAIN
;
3781 /******************************************************************************
3782 * BlockChainStream_GetCount
3784 * Returns the number of blocks that comprises this chain.
3785 * This is not the size of the stream as the last block may not be full!
3788 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
3793 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3795 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
3799 blockIndex
= StorageImpl_GetNextBlockInChain(
3800 This
->parentStorage
,
3807 /******************************************************************************
3808 * BlockChainStream_ReadAt
3810 * Reads a specified number of bytes from this chain at the specified offset.
3811 * bytesRead may be NULL.
3812 * Failure will be returned if the specified number of bytes has not been read.
3814 BOOL
BlockChainStream_ReadAt(BlockChainStream
* This
,
3815 ULARGE_INTEGER offset
,
3820 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3821 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
3822 ULONG bytesToReadInBuffer
;
3825 BYTE
* bigBlockBuffer
;
3828 * Find the first block in the stream that contains part of the buffer.
3830 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3832 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
3835 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3837 blockNoInSequence
--;
3841 * Start reading the buffer.
3844 bufferWalker
= buffer
;
3846 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
3849 * Calculate how many bytes we can copy from this big block.
3851 bytesToReadInBuffer
=
3852 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
3855 * Copy those bytes to the buffer
3858 StorageImpl_GetROBigBlock(This
->parentStorage
, blockIndex
);
3860 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
3862 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
3865 * Step to the next big block.
3868 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3870 bufferWalker
+= bytesToReadInBuffer
;
3871 size
-= bytesToReadInBuffer
;
3872 *bytesRead
+= bytesToReadInBuffer
;
3873 offsetInBlock
= 0; /* There is no offset on the next block */
3880 /******************************************************************************
3881 * BlockChainStream_WriteAt
3883 * Writes the specified number of bytes to this chain at the specified offset.
3884 * bytesWritten may be NULL.
3885 * Will fail if not all specified number of bytes have been written.
3887 BOOL
BlockChainStream_WriteAt(BlockChainStream
* This
,
3888 ULARGE_INTEGER offset
,
3891 ULONG
* bytesWritten
)
3893 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3894 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
3898 BYTE
* bigBlockBuffer
;
3901 * Find the first block in the stream that contains part of the buffer.
3903 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3905 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
3908 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3910 blockNoInSequence
--;
3914 * Here, I'm casting away the constness on the buffer variable
3915 * This is OK since we don't intend to modify that buffer.
3918 bufferWalker
= (BYTE
*)buffer
;
3920 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
3923 * Calculate how many bytes we can copy from this big block.
3926 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
3929 * Copy those bytes to the buffer
3931 bigBlockBuffer
= StorageImpl_GetBigBlock(This
->parentStorage
, blockIndex
);
3933 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
3935 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
3938 * Step to the next big block.
3941 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3943 bufferWalker
+= bytesToWrite
;
3944 size
-= bytesToWrite
;
3945 *bytesWritten
+= bytesToWrite
;
3946 offsetInBlock
= 0; /* There is no offset on the next block */
3952 /******************************************************************************
3953 * BlockChainStream_Shrink
3955 * Shrinks this chain in the big block depot.
3957 BOOL
BlockChainStream_Shrink(BlockChainStream
* This
,
3958 ULARGE_INTEGER newSize
)
3960 ULONG blockIndex
, extraBlock
;
3965 * Figure out how many blocks are needed to contain the new size
3967 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3969 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
3972 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3975 * Go to the new end of chain
3977 while (count
< numBlocks
)
3980 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3985 /* Get the next block before marking the new end */
3987 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3989 /* Mark the new end of chain */
3990 StorageImpl_SetNextBlockInChain(
3991 This
->parentStorage
,
3993 BLOCK_END_OF_CHAIN
);
3996 * Mark the extra blocks as free
3998 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4001 StorageImpl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4003 StorageImpl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4004 extraBlock
= blockIndex
;
4010 /******************************************************************************
4011 * BlockChainStream_Enlarge
4013 * Grows this chain in the big block depot.
4015 BOOL
BlockChainStream_Enlarge(BlockChainStream
* This
,
4016 ULARGE_INTEGER newSize
)
4018 ULONG blockIndex
, currentBlock
;
4020 ULONG oldNumBlocks
= 0;
4022 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4025 * Empty chain. Create the head.
4027 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4029 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4030 StorageImpl_SetNextBlockInChain(This
->parentStorage
,
4032 BLOCK_END_OF_CHAIN
);
4034 if (This
->headOfStreamPlaceHolder
!= 0)
4036 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4040 StgProperty chainProp
;
4041 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4043 StorageImpl_ReadProperty(
4044 This
->parentStorage
,
4045 This
->ownerPropertyIndex
,
4048 chainProp
.startingBlock
= blockIndex
;
4050 StorageImpl_WriteProperty(
4051 This
->parentStorage
,
4052 This
->ownerPropertyIndex
,
4057 currentBlock
= blockIndex
;
4060 * Figure out how many blocks are needed to contain this stream
4062 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4064 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4068 * Go to the current end of chain
4070 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4073 currentBlock
= blockIndex
;
4076 StorageImpl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4080 * Add new blocks to the chain
4082 while (oldNumBlocks
< newNumBlocks
)
4084 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4086 StorageImpl_SetNextBlockInChain(
4087 This
->parentStorage
,
4091 StorageImpl_SetNextBlockInChain(
4092 This
->parentStorage
,
4094 BLOCK_END_OF_CHAIN
);
4096 currentBlock
= blockIndex
;
4103 /******************************************************************************
4104 * BlockChainStream_SetSize
4106 * Sets the size of this stream. The big block depot will be updated.
4107 * The file will grow if we grow the chain.
4109 * TODO: Free the actual blocks in the file when we shrink the chain.
4110 * Currently, the blocks are still in the file. So the file size
4111 * doesn't shrink even if we shrink streams.
4113 BOOL
BlockChainStream_SetSize(
4114 BlockChainStream
* This
,
4115 ULARGE_INTEGER newSize
)
4117 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4119 if (newSize
.LowPart
== size
.LowPart
)
4122 if (newSize
.LowPart
< size
.LowPart
)
4124 BlockChainStream_Shrink(This
, newSize
);
4128 ULARGE_INTEGER fileSize
=
4129 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4131 ULONG diff
= newSize
.LowPart
- size
.LowPart
;
4134 * Make sure the file stays a multiple of blocksize
4136 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4137 diff
+= (This
->parentStorage
->bigBlockSize
-
4138 (diff
% This
->parentStorage
->bigBlockSize
) );
4140 fileSize
.LowPart
+= diff
;
4141 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4143 BlockChainStream_Enlarge(This
, newSize
);
4149 /******************************************************************************
4150 * BlockChainStream_GetSize
4152 * Returns the size of this chain.
4153 * Will return the block count if this chain doesn't have a property.
4155 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4157 StgProperty chainProperty
;
4159 if(This
->headOfStreamPlaceHolder
== NULL
)
4162 * This chain is a data stream read the property and return
4163 * the appropriate size
4165 StorageImpl_ReadProperty(
4166 This
->parentStorage
,
4167 This
->ownerPropertyIndex
,
4170 return chainProperty
.size
;
4175 * this chain is a chain that does not have a property, figure out the
4176 * size by making the product number of used blocks times the
4179 ULARGE_INTEGER result
;
4180 result
.HighPart
= 0;
4183 BlockChainStream_GetCount(This
) *
4184 This
->parentStorage
->bigBlockSize
;
4190 /******************************************************************************
4191 ** SmallBlockChainStream implementation
4194 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4195 StorageImpl
* parentStorage
,
4196 ULONG propertyIndex
)
4198 SmallBlockChainStream
* newStream
;
4200 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4202 newStream
->parentStorage
= parentStorage
;
4203 newStream
->ownerPropertyIndex
= propertyIndex
;
4208 void SmallBlockChainStream_Destroy(
4209 SmallBlockChainStream
* This
)
4211 HeapFree(GetProcessHeap(), 0, This
);
4214 /******************************************************************************
4215 * SmallBlockChainStream_GetHeadOfChain
4217 * Returns the head of this chain of small blocks.
4219 ULONG
SmallBlockChainStream_GetHeadOfChain(
4220 SmallBlockChainStream
* This
)
4222 StgProperty chainProperty
;
4225 if (This
->ownerPropertyIndex
)
4227 readSucessful
= StorageImpl_ReadProperty(
4228 This
->parentStorage
,
4229 This
->ownerPropertyIndex
,
4234 return chainProperty
.startingBlock
;
4239 return BLOCK_END_OF_CHAIN
;
4242 /******************************************************************************
4243 * SmallBlockChainStream_GetNextBlockInChain
4245 * Returns the index of the next small block in this chain.
4248 * - BLOCK_END_OF_CHAIN: end of this chain
4249 * - BLOCK_UNUSED: small block 'blockIndex' is free
4251 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4252 SmallBlockChainStream
* This
,
4255 ULARGE_INTEGER offsetOfBlockInDepot
;
4257 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4261 offsetOfBlockInDepot
.HighPart
= 0;
4262 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4265 * Read those bytes in the buffer from the small block file.
4267 success
= BlockChainStream_ReadAt(
4268 This
->parentStorage
->smallBlockDepotChain
,
4269 offsetOfBlockInDepot
,
4276 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4279 return nextBlockInChain
;
4282 /******************************************************************************
4283 * SmallBlockChainStream_SetNextBlockInChain
4285 * Writes the index of the next block of the specified block in the small
4287 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4288 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4290 void SmallBlockChainStream_SetNextBlockInChain(
4291 SmallBlockChainStream
* This
,
4295 ULARGE_INTEGER offsetOfBlockInDepot
;
4299 offsetOfBlockInDepot
.HighPart
= 0;
4300 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4302 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4305 * Read those bytes in the buffer from the small block file.
4307 BlockChainStream_WriteAt(
4308 This
->parentStorage
->smallBlockDepotChain
,
4309 offsetOfBlockInDepot
,
4315 /******************************************************************************
4316 * SmallBlockChainStream_FreeBlock
4318 * Flag small block 'blockIndex' as free in the small block depot.
4320 void SmallBlockChainStream_FreeBlock(
4321 SmallBlockChainStream
* This
,
4324 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4327 /******************************************************************************
4328 * SmallBlockChainStream_GetNextFreeBlock
4330 * Returns the index of a free small block. The small block depot will be
4331 * enlarged if necessary. The small block chain will also be enlarged if
4334 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4335 SmallBlockChainStream
* This
)
4337 ULARGE_INTEGER offsetOfBlockInDepot
;
4340 ULONG blockIndex
= 0;
4341 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4342 BOOL success
= TRUE
;
4343 ULONG smallBlocksPerBigBlock
;
4345 offsetOfBlockInDepot
.HighPart
= 0;
4348 * Scan the small block depot for a free block
4350 while (nextBlockIndex
!= BLOCK_UNUSED
)
4352 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4354 success
= BlockChainStream_ReadAt(
4355 This
->parentStorage
->smallBlockDepotChain
,
4356 offsetOfBlockInDepot
,
4362 * If we run out of space for the small block depot, enlarge it
4366 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4368 if (nextBlockIndex
!= BLOCK_UNUSED
)
4374 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4376 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4377 ULONG nextBlock
, newsbdIndex
;
4378 BYTE
* smallBlockDepot
;
4380 nextBlock
= sbdIndex
;
4381 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4383 sbdIndex
= nextBlock
;
4385 StorageImpl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4388 newsbdIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4389 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4390 StorageImpl_SetNextBlockInChain(
4391 This
->parentStorage
,
4395 StorageImpl_SetNextBlockInChain(
4396 This
->parentStorage
,
4398 BLOCK_END_OF_CHAIN
);
4401 * Initialize all the small blocks to free
4404 StorageImpl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4406 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4407 StorageImpl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4412 * We have just created the small block depot.
4414 StgProperty rootProp
;
4418 * Save it in the header
4420 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4421 StorageImpl_SaveFileHeader(This
->parentStorage
);
4424 * And allocate the first big block that will contain small blocks
4427 StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4429 StorageImpl_SetNextBlockInChain(
4430 This
->parentStorage
,
4432 BLOCK_END_OF_CHAIN
);
4434 StorageImpl_ReadProperty(
4435 This
->parentStorage
,
4436 This
->parentStorage
->rootPropertySetIndex
,
4439 rootProp
.startingBlock
= sbStartIndex
;
4440 rootProp
.size
.HighPart
= 0;
4441 rootProp
.size
.LowPart
= This
->parentStorage
->bigBlockSize
;
4443 StorageImpl_WriteProperty(
4444 This
->parentStorage
,
4445 This
->parentStorage
->rootPropertySetIndex
,
4451 smallBlocksPerBigBlock
=
4452 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4455 * Verify if we have to allocate big blocks to contain small blocks
4457 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4459 StgProperty rootProp
;
4460 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4462 StorageImpl_ReadProperty(
4463 This
->parentStorage
,
4464 This
->parentStorage
->rootPropertySetIndex
,
4467 if (rootProp
.size
.LowPart
<
4468 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4470 rootProp
.size
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4472 BlockChainStream_SetSize(
4473 This
->parentStorage
->smallBlockRootChain
,
4476 StorageImpl_WriteProperty(
4477 This
->parentStorage
,
4478 This
->parentStorage
->rootPropertySetIndex
,
4486 /******************************************************************************
4487 * SmallBlockChainStream_ReadAt
4489 * Reads a specified number of bytes from this chain at the specified offset.
4490 * bytesRead may be NULL.
4491 * Failure will be returned if the specified number of bytes has not been read.
4493 BOOL
SmallBlockChainStream_ReadAt(
4494 SmallBlockChainStream
* This
,
4495 ULARGE_INTEGER offset
,
4500 ULARGE_INTEGER offsetInBigBlockFile
;
4501 ULONG blockNoInSequence
=
4502 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4504 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4505 ULONG bytesToReadInBuffer
;
4507 ULONG bytesReadFromBigBlockFile
;
4511 * This should never happen on a small block file.
4513 assert(offset
.HighPart
==0);
4516 * Find the first block in the stream that contains part of the buffer.
4518 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4520 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4522 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4524 blockNoInSequence
--;
4528 * Start reading the buffer.
4531 bufferWalker
= buffer
;
4533 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4536 * Calculate how many bytes we can copy from this small block.
4538 bytesToReadInBuffer
=
4539 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4542 * Calculate the offset of the small block in the small block file.
4544 offsetInBigBlockFile
.HighPart
= 0;
4545 offsetInBigBlockFile
.LowPart
=
4546 blockIndex
* This
->parentStorage
->smallBlockSize
;
4548 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4551 * Read those bytes in the buffer from the small block file.
4553 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4554 offsetInBigBlockFile
,
4555 bytesToReadInBuffer
,
4557 &bytesReadFromBigBlockFile
);
4559 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4562 * Step to the next big block.
4564 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4565 bufferWalker
+= bytesToReadInBuffer
;
4566 size
-= bytesToReadInBuffer
;
4567 *bytesRead
+= bytesToReadInBuffer
;
4568 offsetInBlock
= 0; /* There is no offset on the next block */
4574 /******************************************************************************
4575 * SmallBlockChainStream_WriteAt
4577 * Writes the specified number of bytes to this chain at the specified offset.
4578 * bytesWritten may be NULL.
4579 * Will fail if not all specified number of bytes have been written.
4581 BOOL
SmallBlockChainStream_WriteAt(
4582 SmallBlockChainStream
* This
,
4583 ULARGE_INTEGER offset
,
4586 ULONG
* bytesWritten
)
4588 ULARGE_INTEGER offsetInBigBlockFile
;
4589 ULONG blockNoInSequence
=
4590 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4592 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4593 ULONG bytesToWriteInBuffer
;
4595 ULONG bytesWrittenFromBigBlockFile
;
4599 * This should never happen on a small block file.
4601 assert(offset
.HighPart
==0);
4604 * Find the first block in the stream that contains part of the buffer.
4606 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4608 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4610 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4612 blockNoInSequence
--;
4616 * Start writing the buffer.
4618 * Here, I'm casting away the constness on the buffer variable
4619 * This is OK since we don't intend to modify that buffer.
4622 bufferWalker
= (BYTE
*)buffer
;
4623 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4626 * Calculate how many bytes we can copy to this small block.
4628 bytesToWriteInBuffer
=
4629 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4632 * Calculate the offset of the small block in the small block file.
4634 offsetInBigBlockFile
.HighPart
= 0;
4635 offsetInBigBlockFile
.LowPart
=
4636 blockIndex
* This
->parentStorage
->smallBlockSize
;
4638 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4641 * Write those bytes in the buffer to the small block file.
4643 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
4644 offsetInBigBlockFile
,
4645 bytesToWriteInBuffer
,
4647 &bytesWrittenFromBigBlockFile
);
4649 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
4652 * Step to the next big block.
4654 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4655 bufferWalker
+= bytesToWriteInBuffer
;
4656 size
-= bytesToWriteInBuffer
;
4657 *bytesWritten
+= bytesToWriteInBuffer
;
4658 offsetInBlock
= 0; /* There is no offset on the next block */
4664 /******************************************************************************
4665 * SmallBlockChainStream_Shrink
4667 * Shrinks this chain in the small block depot.
4669 BOOL
SmallBlockChainStream_Shrink(
4670 SmallBlockChainStream
* This
,
4671 ULARGE_INTEGER newSize
)
4673 ULONG blockIndex
, extraBlock
;
4677 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4679 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4682 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4685 * Go to the new end of chain
4687 while (count
< numBlocks
)
4689 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4693 /* Get the next block before marking the new end */
4694 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4696 /* Mark the new end of chain */
4697 SmallBlockChainStream_SetNextBlockInChain(
4700 BLOCK_END_OF_CHAIN
);
4703 * Mark the extra blocks as free
4705 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4707 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
4708 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
4709 extraBlock
= blockIndex
;
4715 /******************************************************************************
4716 * SmallBlockChainStream_Enlarge
4718 * Grows this chain in the small block depot.
4720 BOOL
SmallBlockChainStream_Enlarge(
4721 SmallBlockChainStream
* This
,
4722 ULARGE_INTEGER newSize
)
4724 ULONG blockIndex
, currentBlock
;
4726 ULONG oldNumBlocks
= 0;
4728 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4733 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4735 StgProperty chainProp
;
4737 StorageImpl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
4740 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
4742 StorageImpl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
4745 blockIndex
= chainProp
.startingBlock
;
4746 SmallBlockChainStream_SetNextBlockInChain(
4749 BLOCK_END_OF_CHAIN
);
4752 currentBlock
= blockIndex
;
4755 * Figure out how many blocks are needed to contain this stream
4757 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4759 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4763 * Go to the current end of chain
4765 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4768 currentBlock
= blockIndex
;
4769 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
4773 * Add new blocks to the chain
4775 while (oldNumBlocks
< newNumBlocks
)
4777 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
4778 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
4780 SmallBlockChainStream_SetNextBlockInChain(
4783 BLOCK_END_OF_CHAIN
);
4785 currentBlock
= blockIndex
;
4792 /******************************************************************************
4793 * SmallBlockChainStream_GetCount
4795 * Returns the number of blocks that comprises this chain.
4796 * This is not the size of this chain as the last block may not be full!
4798 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
4803 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4805 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4809 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4815 /******************************************************************************
4816 * SmallBlockChainStream_SetSize
4818 * Sets the size of this stream.
4819 * The file will grow if we grow the chain.
4821 * TODO: Free the actual blocks in the file when we shrink the chain.
4822 * Currently, the blocks are still in the file. So the file size
4823 * doesn't shrink even if we shrink streams.
4825 BOOL
SmallBlockChainStream_SetSize(
4826 SmallBlockChainStream
* This
,
4827 ULARGE_INTEGER newSize
)
4829 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
4831 if (newSize
.LowPart
== size
.LowPart
)
4834 if (newSize
.LowPart
< size
.LowPart
)
4836 SmallBlockChainStream_Shrink(This
, newSize
);
4840 SmallBlockChainStream_Enlarge(This
, newSize
);
4846 /******************************************************************************
4847 * SmallBlockChainStream_GetSize
4849 * Returns the size of this chain.
4851 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
4853 StgProperty chainProperty
;
4855 StorageImpl_ReadProperty(
4856 This
->parentStorage
,
4857 This
->ownerPropertyIndex
,
4860 return chainProperty
.size
;
4863 /******************************************************************************
4864 * StgCreateDocfile32 [OLE32.144]
4865 * TODO Validate grfMode (STGM)
4867 HRESULT WINAPI
StgCreateDocfile(
4871 IStorage
**ppstgOpen
)
4873 StorageImpl
* newStorage
= 0;
4874 HANDLE hFile
= INVALID_HANDLE_VALUE
;
4879 DWORD fileAttributes
;
4882 * Validate the parameters
4884 if ((ppstgOpen
== 0) || (pwcsName
== 0))
4885 return STG_E_INVALIDPOINTER
;
4888 * Validate the STGM flags
4890 if ( FAILED( validateSTGM(grfMode
) ))
4891 return STG_E_INVALIDFLAG
;
4894 * Interpret the STGM value grfMode
4896 shareMode
= GetShareModeFromSTGM(grfMode
);
4897 accessMode
= GetAccessModeFromSTGM(grfMode
);
4898 creationMode
= GetCreationModeFromSTGM(grfMode
);
4900 if (grfMode
& STGM_DELETEONRELEASE
)
4901 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
4903 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
4905 if (grfMode
& STGM_TRANSACTED
)
4906 FIXME(ole
, "Transacted mode not implemented.\n");
4909 * Initialize the "out" parameter.
4913 hFile
= CreateFileW(pwcsName
,
4921 if (hFile
== INVALID_HANDLE_VALUE
)
4927 * Allocate and initialize the new IStorage32object.
4929 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
4931 if (newStorage
== 0)
4932 return STG_E_INSUFFICIENTMEMORY
;
4934 hr
= StorageImpl_Construct(
4943 * Get an "out" pointer for the caller.
4945 hr
= StorageBaseImpl_QueryInterface(
4946 (IStorage
*)newStorage
,
4947 (REFIID
)&IID_IStorage
,
4953 /******************************************************************************
4954 * StgOpenStorage32 [OLE32.148]
4956 HRESULT WINAPI
StgOpenStorage(
4957 const OLECHAR
*pwcsName
,
4958 IStorage
*pstgPriority
,
4962 IStorage
**ppstgOpen
)
4964 StorageImpl
* newStorage
= 0;
4971 * Perform a sanity check
4973 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
4974 return STG_E_INVALIDPOINTER
;
4977 * Validate the STGM flags
4979 if ( FAILED( validateSTGM(grfMode
) ))
4980 return STG_E_INVALIDFLAG
;
4983 * Interpret the STGM value grfMode
4985 shareMode
= GetShareModeFromSTGM(grfMode
);
4986 accessMode
= GetAccessModeFromSTGM(grfMode
);
4989 * Initialize the "out" parameter.
4993 hFile
= CreateFileW( pwcsName
,
4998 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5002 if (hFile
==INVALID_HANDLE_VALUE
)
5008 * Allocate and initialize the new IStorage32object.
5010 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5012 if (newStorage
== 0)
5013 return STG_E_INSUFFICIENTMEMORY
;
5015 hr
= StorageImpl_Construct(
5024 * Get an "out" pointer for the caller.
5026 hr
= StorageBaseImpl_QueryInterface(
5027 (IStorage
*)newStorage
,
5028 (REFIID
)&IID_IStorage
,
5034 /******************************************************************************
5035 * WriteClassStg32 [OLE32.148]
5037 * This method will store the specified CLSID in the specified storage object
5039 HRESULT WINAPI
WriteClassStg(IStorage
* pStg
, REFCLSID rclsid
)
5045 hRes
= IStorage_SetClass(pStg
, rclsid
);
5051 /****************************************************************************
5052 * This method validate a STGM parameter that can contain the values below
5054 * STGM_DIRECT 0x00000000
5055 * STGM_TRANSACTED 0x00010000
5056 * STGM_SIMPLE 0x08000000
5058 * STGM_READ 0x00000000
5059 * STGM_WRITE 0x00000001
5060 * STGM_READWRITE 0x00000002
5062 * STGM_SHARE_DENY_NONE 0x00000040
5063 * STGM_SHARE_DENY_READ 0x00000030
5064 * STGM_SHARE_DENY_WRITE 0x00000020
5065 * STGM_SHARE_EXCLUSIVE 0x00000010
5067 * STGM_PRIORITY 0x00040000
5068 * STGM_DELETEONRELEASE 0x04000000
5070 * STGM_CREATE 0x00001000
5071 * STGM_CONVERT 0x00020000
5072 * STGM_FAILIFTHERE 0x00000000
5074 * STGM_NOSCRATCH 0x00100000
5075 * STGM_NOSNAPSHOT 0x00200000
5077 static HRESULT
validateSTGM(DWORD stgm
)
5079 BOOL bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5080 BOOL bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5081 BOOL bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5083 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5084 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5085 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5087 BOOL bSTGM_SHARE_DENY_NONE
=
5088 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5090 BOOL bSTGM_SHARE_DENY_READ
=
5091 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5093 BOOL bSTGM_SHARE_DENY_WRITE
=
5094 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5096 BOOL bSTGM_SHARE_EXCLUSIVE
=
5097 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5099 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5100 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5102 BOOL bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5103 BOOL bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5106 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5108 if ( ! bSTGM_DIRECT
)
5109 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5113 * STGM_WRITE | STGM_READWRITE | STGM_READ
5116 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5120 * STGM_SHARE_DENY_NONE | others
5121 * (I assume here that DENY_READ implies DENY_WRITE)
5123 if ( bSTGM_SHARE_DENY_NONE
)
5124 if ( bSTGM_SHARE_DENY_READ
||
5125 bSTGM_SHARE_DENY_WRITE
||
5126 bSTGM_SHARE_EXCLUSIVE
)
5130 * STGM_CREATE | STGM_CONVERT
5131 * if both are false, STGM_FAILIFTHERE is set to TRUE
5133 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5137 * STGM_NOSCRATCH requires STGM_TRANSACTED
5139 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5143 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5144 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5146 if (bSTGM_NOSNAPSHOT
)
5148 if ( ! ( bSTGM_TRANSACTED
&&
5149 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
5156 /****************************************************************************
5157 * GetShareModeFromSTGM
5159 * This method will return a share mode flag from a STGM value.
5160 * The STGM value is assumed valid.
5162 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
5164 DWORD dwShareMode
= 0;
5165 BOOL bSTGM_SHARE_DENY_NONE
=
5166 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5168 BOOL bSTGM_SHARE_DENY_READ
=
5169 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5171 BOOL bSTGM_SHARE_DENY_WRITE
=
5172 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5174 BOOL bSTGM_SHARE_EXCLUSIVE
=
5175 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5177 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
5180 if (bSTGM_SHARE_DENY_NONE
)
5181 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
5183 if (bSTGM_SHARE_DENY_WRITE
)
5184 dwShareMode
= FILE_SHARE_READ
;
5189 /****************************************************************************
5190 * GetAccessModeFromSTGM
5192 * This method will return an access mode flag from a STGM value.
5193 * The STGM value is assumed valid.
5195 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
5197 DWORD dwDesiredAccess
= 0;
5198 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5199 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5200 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5203 dwDesiredAccess
= GENERIC_READ
;
5206 dwDesiredAccess
|= GENERIC_WRITE
;
5208 if (bSTGM_READWRITE
)
5209 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
5211 return dwDesiredAccess
;
5214 /****************************************************************************
5215 * GetCreationModeFromSTGM
5217 * This method will return a creation mode flag from a STGM value.
5218 * The STGM value is assumed valid.
5220 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
5222 DWORD dwCreationDistribution
;
5223 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5224 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5225 BOOL bSTGM_FAILIFTHERE
= ! (bSTGM_CREATE
|| bSTGM_CONVERT
);
5228 dwCreationDistribution
= CREATE_ALWAYS
;
5229 else if (bSTGM_FAILIFTHERE
)
5230 dwCreationDistribution
= CREATE_NEW
;
5231 else if (bSTGM_CONVERT
)
5233 FIXME(ole
, "STGM_CONVERT not implemented!\n");
5234 dwCreationDistribution
= CREATE_NEW
;
5237 return dwCreationDistribution
;