2 * Compound Storage (32 bit version)
3 * Storage implementation
5 * This file contains the compound file implementation
6 * of the storage interface.
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Sylvain St-Germain
10 * Copyright 1999 Thuy Nguyen
32 #include "storage32.h"
36 static const char rootPropertyName
[] = "Root Entry";
38 /***********************************************************************
39 * Forward declaration of internal functions used by the method DestroyElement
41 static HRESULT
deleteStorageProperty(
42 Storage32Impl
*parentStorage
,
43 OLECHAR32
*propertyToDeleteName
);
45 static HRESULT
deleteStreamProperty(
46 Storage32Impl
*parentStorage
,
47 ULONG foundPropertyIndexToDelete
,
48 StgProperty propertyToDelete
);
50 static HRESULT
findPlaceholder(
51 Storage32Impl
*storage
,
52 ULONG propertyIndexToStore
,
53 ULONG storagePropertyIndex
,
54 INT32 typeOfRelation
);
56 static HRESULT
adjustPropertyChain(
58 StgProperty propertyToDelete
,
59 StgProperty parentProperty
,
60 ULONG parentPropertyId
,
61 INT32 typeOfRelation
);
63 /***********************************************************************
64 * Declaration of the functions used to manipulate StgProperty
67 static ULONG
getFreeProperty(
68 Storage32Impl
*storage
);
70 static void updatePropertyChain(
71 Storage32Impl
*storage
,
72 ULONG newPropertyIndex
,
73 StgProperty newProperty
);
75 static LONG
propertyNameCmp(
76 OLECHAR32
*newProperty
,
77 OLECHAR32
*currentProperty
);
80 /***********************************************************************
81 * Declaration of miscellaneous functions...
83 static HRESULT
validateSTGM(DWORD stgmValue
);
85 static DWORD
GetShareModeFromSTGM(DWORD stgm
);
86 static DWORD
GetAccessModeFromSTGM(DWORD stgm
);
87 static DWORD
GetCreationModeFromSTGM(DWORD stgm
);
90 * Virtual function table for the IStorage32Impl class.
92 static ICOM_VTABLE(IStorage32
) Storage32Impl_Vtbl
=
94 Storage32BaseImpl_QueryInterface
,
95 Storage32BaseImpl_AddRef
,
96 Storage32BaseImpl_Release
,
97 Storage32BaseImpl_CreateStream
,
98 Storage32BaseImpl_OpenStream
,
99 Storage32Impl_CreateStorage
,
100 Storage32BaseImpl_OpenStorage
,
101 Storage32Impl_CopyTo
,
102 Storage32Impl_MoveElementTo
,
103 Storage32Impl_Commit
,
104 Storage32Impl_Revert
,
105 Storage32BaseImpl_EnumElements
,
106 Storage32Impl_DestroyElement
,
107 Storage32BaseImpl_RenameElement
,
108 Storage32Impl_SetElementTimes
,
109 Storage32BaseImpl_SetClass
,
110 Storage32Impl_SetStateBits
,
111 Storage32BaseImpl_Stat
115 * Virtual function table for the Storage32InternalImpl class.
117 static ICOM_VTABLE(IStorage32
) Storage32InternalImpl_Vtbl
=
119 Storage32BaseImpl_QueryInterface
,
120 Storage32BaseImpl_AddRef
,
121 Storage32BaseImpl_Release
,
122 Storage32BaseImpl_CreateStream
,
123 Storage32BaseImpl_OpenStream
,
124 Storage32Impl_CreateStorage
,
125 Storage32BaseImpl_OpenStorage
,
126 Storage32Impl_CopyTo
,
127 Storage32Impl_MoveElementTo
,
128 Storage32InternalImpl_Commit
,
129 Storage32InternalImpl_Revert
,
130 Storage32BaseImpl_EnumElements
,
131 Storage32Impl_DestroyElement
,
132 Storage32BaseImpl_RenameElement
,
133 Storage32Impl_SetElementTimes
,
134 Storage32BaseImpl_SetClass
,
135 Storage32Impl_SetStateBits
,
136 Storage32BaseImpl_Stat
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
Storage32BaseImpl_QueryInterface(
174 ICOM_THIS(Storage32BaseImpl
,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
= (IStorage32
*)This
;
193 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
195 *ppvObject
= (IStorage32
*)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 Storage32BaseImpl_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
Storage32BaseImpl_AddRef(
224 ICOM_THIS(Storage32BaseImpl
,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
Storage32BaseImpl_Release(
241 ICOM_THIS(Storage32BaseImpl
,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
Storage32BaseImpl_OpenStream(
274 const OLECHAR32
* pwcsName
, /* [string][in] */
275 void* reserved1
, /* [unique][in] */
276 DWORD grfMode
, /* [in] */
277 DWORD reserved2
, /* [in] */
278 IStream32
** ppstm
) /* [out] */
280 ICOM_THIS(Storage32BaseImpl
,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
= (IStream32
*)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
Storage32BaseImpl_OpenStorage(
367 const OLECHAR32
* pwcsName
, /* [string][unique][in] */
368 IStorage32
* pstgPriority
, /* [unique][in] */
369 DWORD grfMode
, /* [in] */
370 SNB32 snbExclude
, /* [unique][in] */
371 DWORD reserved
, /* [in] */
372 IStorage32
** ppstg
) /* [out] */
374 ICOM_THIS(Storage32BaseImpl
,iface
);
375 Storage32InternalImpl
* 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
= Storage32InternalImpl_Construct(
435 This
->ancestorStorage
,
440 *ppstg
= (IStorage32
*)newStorage
;
443 * Since we are returning a pointer to the interface,
444 * we have to nail down the reference.
446 Storage32BaseImpl_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
Storage32BaseImpl_EnumElements(
467 DWORD reserved1
, /* [in] */
468 void* reserved2
, /* [size_is][unique][in] */
469 DWORD reserved3
, /* [in] */
470 IEnumSTATSTG
** ppenum
) /* [out] */
472 ICOM_THIS(Storage32BaseImpl
,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
Storage32BaseImpl_Stat(
513 STATSTG
* pstatstg
, /* [out] */
514 DWORD grfStatFlag
) /* [in] */
516 ICOM_THIS(Storage32BaseImpl
,iface
);
517 StgProperty curProperty
;
518 BOOL32 readSucessful
;
521 * Perform a sanity check on the parameters.
523 if ( (This
==0) || (pstatstg
==0))
527 * Read the information from the property.
529 readSucessful
= Storage32Impl_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
Storage32BaseImpl_RenameElement(
560 const OLECHAR32
* pwcsOldName
, /* [in] */
561 const OLECHAR32
* pwcsNewName
) /* [in] */
563 ICOM_THIS(Storage32BaseImpl
,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 ( lstrlen32W(pwcsNewName
)+1 ) * sizeof(WCHAR
);
615 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
616 return STG_E_INVALIDNAME
;
618 lstrcpy32W(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 Storage32Impl_WriteProperty(
651 This
->ancestorStorage
,
652 renamedPropertyIndex
,
656 * Find a spot in the property chain for our newly created property.
659 (Storage32Impl
*)This
,
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 Storage32Impl_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 Storage32Impl_DestroyElement((IStorage32
*)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
Storage32BaseImpl_CreateStream(
708 const OLECHAR32
* pwcsName
, /* [string][in] */
709 DWORD grfMode
, /* [in] */
710 DWORD reserved1
, /* [in] */
711 DWORD reserved2
, /* [in] */
712 IStream32
** ppstm
) /* [out] */
714 ICOM_THIS(Storage32BaseImpl
,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 Storage32Impl_DestroyElement((IStorage32
*)This
->ancestorStorage
, pwcsName
);
768 return STG_E_FILEALREADYEXISTS
;
772 * memset the empty property
774 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
776 newStreamProperty
.sizeOfNameString
=
777 ( lstrlen32W(pwcsName
)+1 ) * sizeof(WCHAR
);
779 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
780 return STG_E_INVALIDNAME
;
782 lstrcpy32W(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 Storage32Impl_WriteProperty(
811 This
->ancestorStorage
,
816 * Find a spot in the property chain for our newly created property.
819 (Storage32Impl
*)This
,
824 * Open the stream to return it.
826 newStream
= StgStreamImpl_Construct(This
, newPropertyIndex
);
830 *ppstm
= (IStream32
*)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
Storage32BaseImpl_SetClass(
856 REFCLSID clsid
) /* [in] */
858 ICOM_THIS(Storage32BaseImpl
,iface
);
859 HRESULT hRes
= E_FAIL
;
860 StgProperty curProperty
;
863 success
= Storage32Impl_ReadProperty(This
->ancestorStorage
,
864 This
->rootPropertySetIndex
,
868 curProperty
.propertyUniqueID
= *clsid
;
870 success
= Storage32Impl_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
Storage32Impl_CreateStorage(
893 const OLECHAR32
*pwcsName
, /* [string][in] */
894 DWORD grfMode
, /* [in] */
895 DWORD reserved1
, /* [in] */
896 DWORD reserved2
, /* [in] */
897 IStorage32
**ppstg
) /* [out] */
899 Storage32Impl
* const This
=(Storage32Impl
*)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 Storage32Impl_DestroyElement((IStorage32
*)This
->ancestorStorage
, pwcsName
);
948 return STG_E_FILEALREADYEXISTS
;
952 * memset the empty property
954 memset(&newProperty
, 0, sizeof(StgProperty
));
956 newProperty
.sizeOfNameString
= (lstrlen32W(pwcsName
)+1)*sizeof(WCHAR
);
958 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
959 return STG_E_INVALIDNAME
;
961 lstrcpy32W(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 Storage32Impl_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
= Storage32BaseImpl_OpenStorage(
1007 (OLECHAR32
*)pwcsName
,
1014 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1023 /***************************************************************************
1027 * Get a free property or create a new one.
1029 static ULONG
getFreeProperty(
1030 Storage32Impl
*storage
)
1032 ULONG currentPropertyIndex
= 0;
1033 ULONG newPropertyIndex
= PROPERTY_NULL
;
1034 BOOL32 readSucessful
= TRUE
;
1035 StgProperty currentProperty
;
1040 * Start by reading the root property
1042 readSucessful
= Storage32Impl_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 Storage32Impl_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 OLECHAR32
*newProperty
,
1133 OLECHAR32
*currentProperty
)
1135 LONG sizeOfNew
= (lstrlen32W(newProperty
) +1) * sizeof(WCHAR
);
1136 LONG sizeOfCur
= (lstrlen32W(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
= lstrcmp32W( (LPCWSTR
)CRTDLL__wcsupr(
1148 lstrcpyn32W(wsnew
, newProperty
, sizeOfNew
)),
1149 (LPCWSTR
)CRTDLL__wcsupr(
1150 lstrcpyn32W(wscur
, currentProperty
, sizeOfCur
)));
1156 /****************************************************************************
1160 * Properly link this new element in the property chain.
1162 static void updatePropertyChain(
1163 Storage32Impl
*storage
,
1164 ULONG newPropertyIndex
,
1165 StgProperty newProperty
)
1167 StgProperty currentProperty
;
1170 * Read the root property
1172 Storage32Impl_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 Storage32Impl_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 Storage32Impl_ReadProperty(storage
->ancestorStorage
,
1216 currentProperty
.previousProperty
= newPropertyIndex
;
1217 Storage32Impl_WriteProperty(storage
->ancestorStorage
,
1225 if (next
!= PROPERTY_NULL
)
1227 Storage32Impl_ReadProperty(storage
->ancestorStorage
,
1234 currentProperty
.nextProperty
= newPropertyIndex
;
1235 Storage32Impl_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 Storage32Impl_WriteProperty(storage
->ancestorStorage
,
1253 storage
->rootPropertySetIndex
,
1259 /*************************************************************************
1262 HRESULT WINAPI
Storage32Impl_CopyTo(
1264 DWORD ciidExclude
, /* [in] */
1265 const IID
*rgiidExclude
,/* [size_is][unique][in] */
1266 SNB32 snbExclude
, /* [unique][in] */
1267 IStorage32
*pstgDest
) /* [unique][in] */
1272 /*************************************************************************
1273 * MoveElementTo (IStorage)
1275 HRESULT WINAPI
Storage32Impl_MoveElementTo(
1277 const OLECHAR32
*pwcsName
, /* [string][in] */
1278 IStorage32
*pstgDest
, /* [unique][in] */
1279 const OLECHAR32
*pwcsNewName
,/* [string][in] */
1280 DWORD grfFlags
) /* [in] */
1285 /*************************************************************************
1288 HRESULT WINAPI
Storage32Impl_Commit(
1290 DWORD grfCommitFlags
)/* [in] */
1292 FIXME(ole
, "(%ld): stub!\n", grfCommitFlags
);
1296 /*************************************************************************
1299 HRESULT WINAPI
Storage32Impl_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
Storage32Impl_DestroyElement(
1318 const OLECHAR32
*pwcsName
)/* [string][in] */
1320 Storage32Impl
* const This
=(Storage32Impl
*)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
= Storage32Impl_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 Storage32Impl
*parentStorage
,
1445 OLECHAR32
*propertyToDeleteName
)
1447 IEnumSTATSTG
*elements
= 0;
1448 IStorage32
*childStorage
= 0;
1449 STATSTG currentElement
;
1451 HRESULT destroyHr
= S_OK
;
1454 * Open the storage and enumerate it
1456 hr
= Storage32BaseImpl_OpenStorage(
1457 (IStorage32
*)parentStorage
,
1458 propertyToDeleteName
,
1460 STGM_SHARE_EXCLUSIVE
,
1471 * Enumerate the elements
1473 IStorage32_EnumElements( childStorage
, 0, 0, 0, &elements
);
1478 * Obtain the next element
1480 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1483 destroyHr
= Storage32Impl_DestroyElement(
1484 (IStorage32
*)childStorage
,
1485 (OLECHAR32
*)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 IStorage32_Release(childStorage
);
1499 IEnumSTATSTG_Release(elements
);
1504 /*********************************************************************
1508 * Perform the deletion of a stream node
1511 static HRESULT
deleteStreamProperty(
1512 Storage32Impl
*parentStorage
,
1513 ULONG indexOfPropertyToDelete
,
1514 StgProperty propertyToDelete
)
1518 ULARGE_INTEGER size
;
1523 hr
= Storage32BaseImpl_OpenStream(
1524 (IStorage32
*)parentStorage
,
1525 (OLECHAR32
*)propertyToDelete
.name
,
1527 STGM_SHARE_EXCLUSIVE
,
1539 hr
= IStream32_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 Storage32Impl_WriteProperty(
1557 parentStorage
->ancestorStorage
,
1558 indexOfPropertyToDelete
,
1564 /*********************************************************************
1568 * Finds a placeholder for the StgProperty within the Storage
1571 static HRESULT
findPlaceholder(
1572 Storage32Impl
*storage
,
1573 ULONG propertyIndexToStore
,
1574 ULONG storePropertyIndex
,
1575 INT32 typeOfRelation
)
1577 StgProperty storeProperty
;
1582 * Read the storage property
1584 res
= Storage32Impl_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
= Storage32Impl_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(
1661 Storage32Impl
*This
,
1662 StgProperty propertyToDelete
,
1663 StgProperty parentProperty
,
1664 ULONG parentPropertyId
,
1665 INT32 typeOfRelation
)
1667 ULONG newLinkProperty
= PROPERTY_NULL
;
1668 BOOL32 needToFindAPlaceholder
= FALSE
;
1669 ULONG storeNode
= PROPERTY_NULL
;
1670 ULONG toStoreNode
= PROPERTY_NULL
;
1671 INT32 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
= Storage32Impl_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
Storage32Impl_SetElementTimes(
1813 const OLECHAR32
*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
Storage32Impl_SetStateBits(
1826 DWORD grfStateBits
,/* [in] */
1827 DWORD grfMask
) /* [in] */
1832 HRESULT
Storage32Impl_Construct(
1833 Storage32Impl
* This
,
1838 StgProperty currentProperty
;
1839 BOOL32 readSucessful
;
1840 ULONG currentPropertyIndex
;
1842 if ( FAILED( validateSTGM(openFlags
) ))
1843 return STG_E_INVALIDFLAG
;
1845 memset(This
, 0, sizeof(Storage32Impl
));
1848 * Initialize the virtual fgunction table.
1850 This
->lpvtbl
= &Storage32Impl_Vtbl
;
1851 This
->v_destructor
= &Storage32Impl_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 Storage32Impl_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
= Storage32Impl_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 Storage32Impl_ReleaseBigBlock(This
, bigBlockBuffer
);
1921 * Load the header for the file.
1923 Storage32Impl_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
= (lstrlen32W(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 Storage32Impl_WriteProperty(This
, 0, &rootProp
);
1967 * Find the ID of the root int he property sets.
1969 currentPropertyIndex
= 0;
1973 readSucessful
= Storage32Impl_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 Storage32Impl_Destroy(
2009 Storage32Impl
* This
)
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
Storage32Impl_GetNextFreeBigBlock(
2027 Storage32Impl
* This
)
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 Storage32Impl_SetNextBlockInChain(This
,
2067 /* Save new header information.
2069 Storage32Impl_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 Storage32Impl_SetNextBlockInChain(This
,
2109 /* If necessary, flag the extended depot block.
2111 if (extIndex
!= BLOCK_UNUSED
)
2112 Storage32Impl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2114 /* Save header information.
2116 Storage32Impl_SaveFileHeader(This
);
2120 depotBuffer
= Storage32Impl_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 Storage32Impl_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(Storage32Impl
* This
, ULONG blockIndex
)
2156 blockBuffer
= Storage32Impl_GetBigBlock(This
, blockIndex
);
2159 * Initialize blocks as free
2161 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2163 Storage32Impl_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(Storage32Impl
* 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
= Storage32Impl_GetROBigBlock(This
, extBlockIndex
);
2199 if (depotBuffer
!= 0)
2201 StorageUtl_ReadDWord(depotBuffer
,
2202 extBlockOffset
* sizeof(ULONG
),
2205 Storage32Impl_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(Storage32Impl
* 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
= Storage32Impl_GetBigBlock(This
, extBlockIndex
);
2243 if (depotBuffer
!= 0)
2245 StorageUtl_WriteDWord(depotBuffer
,
2246 extBlockOffset
* sizeof(ULONG
),
2249 Storage32Impl_ReleaseBigBlock(This
, depotBuffer
);
2254 /******************************************************************************
2255 * Storage32Impl_AddExtBlockDepot
2257 * Creates an extended depot block.
2259 ULONG
Storage32Impl_AddExtBlockDepot(Storage32Impl
* 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
= Storage32Impl_GetBigBlock(This
, nextExtBlock
);
2294 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2295 Storage32Impl_ReleaseBigBlock(This
, depotBuffer
);
2299 * Initialize this block.
2301 depotBuffer
= Storage32Impl_GetBigBlock(This
, index
);
2302 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2303 Storage32Impl_ReleaseBigBlock(This
, depotBuffer
);
2308 /******************************************************************************
2309 * Storage32Impl_FreeBigBlock
2311 * This method will flag the specified block as free in the big block depot.
2313 void Storage32Impl_FreeBigBlock(
2314 Storage32Impl
* This
,
2317 Storage32Impl_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
Storage32Impl_GetNextBlockInChain(
2344 Storage32Impl
* This
,
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
= Storage32Impl_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 Storage32Impl_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(Storage32Impl
* This
, ULONG blockIndex
)
2413 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2414 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2417 depotBuffer
= Storage32Impl_GetROBigBlock(This
, blockIndex
);
2421 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2423 Storage32Impl_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 Storage32Impl_SetNextBlockInChain(
2444 Storage32Impl
* This
,
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
= Storage32Impl_GetBigBlock(This
, depotBlockIndexPos
);
2472 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2473 Storage32Impl_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
Storage32Impl_LoadFileHeader(
2491 Storage32Impl
* This
)
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
= Storage32Impl_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 Storage32Impl_ReleaseBigBlock(This
, headerBigBlock
);
2514 return STG_E_OLDFORMAT
;
2517 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2519 Storage32Impl_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 Storage32Impl_ReleaseBigBlock(This
, headerBigBlock
);
2596 /******************************************************************************
2597 * Storage32Impl_SaveFileHeader
2599 * This method will save to the file the header, i.e. big block -1.
2601 void Storage32Impl_SaveFileHeader(
2602 Storage32Impl
* This
)
2604 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2609 * Get a pointer to the big block of data containing the header.
2611 success
= Storage32Impl_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 Storage32Impl_WriteBigBlock(This
, -1, headerBigBlock
);
2693 /******************************************************************************
2694 * Storage32Impl_ReadProperty
2696 * This method will read the specified property from the property chain.
2698 BOOL32
Storage32Impl_ReadProperty(
2699 Storage32Impl
* This
,
2701 StgProperty
* buffer
)
2703 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2704 ULARGE_INTEGER offsetInPropSet
;
2705 BOOL32 readSucessful
;
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 BOOL32
Storage32Impl_WriteProperty(
2793 Storage32Impl
* This
,
2795 StgProperty
* buffer
)
2797 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2798 ULARGE_INTEGER offsetInPropSet
;
2799 BOOL32 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
= (lstrlen32W(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 BOOL32
Storage32Impl_ReadBigBlock(
2883 Storage32Impl
* This
,
2887 void* bigBlockBuffer
;
2889 bigBlockBuffer
= Storage32Impl_GetROBigBlock(This
, blockIndex
);
2891 if (bigBlockBuffer
!=0)
2893 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
2895 Storage32Impl_ReleaseBigBlock(This
, bigBlockBuffer
);
2903 BOOL32
Storage32Impl_WriteBigBlock(
2904 Storage32Impl
* This
,
2908 void* bigBlockBuffer
;
2910 bigBlockBuffer
= Storage32Impl_GetBigBlock(This
, blockIndex
);
2912 if (bigBlockBuffer
!=0)
2914 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
2916 Storage32Impl_ReleaseBigBlock(This
, bigBlockBuffer
);
2924 void* Storage32Impl_GetROBigBlock(
2925 Storage32Impl
* This
,
2928 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
2931 void* Storage32Impl_GetBigBlock(
2932 Storage32Impl
* This
,
2935 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
2938 void Storage32Impl_ReleaseBigBlock(
2939 Storage32Impl
* This
,
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(
2952 Storage32Impl
* This
,
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 BOOL32 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 Storage32Impl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3027 chainProperty
.startingBlock
= bbHeadOfChain
;
3029 Storage32Impl_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 Storage32InternalImpl
* Storage32InternalImpl_Construct(
3048 Storage32Impl
* ancestorStorage
,
3049 ULONG rootPropertyIndex
)
3051 Storage32InternalImpl
* newStorage
;
3054 * Allocate space for the new storage object
3056 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32InternalImpl
));
3060 memset(newStorage
, 0, sizeof(Storage32InternalImpl
));
3063 * Initialize the virtual function table.
3065 newStorage
->lpvtbl
= &Storage32InternalImpl_Vtbl
;
3066 newStorage
->v_destructor
= &Storage32InternalImpl_Destroy
;
3069 * Keep the ancestor storage pointer and nail a reference to it.
3071 newStorage
->ancestorStorage
= ancestorStorage
;
3072 Storage32BaseImpl_AddRef((IStorage32
*)(newStorage
->ancestorStorage
));
3075 * Keep the index of the root property set for this storage,
3077 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3085 void Storage32InternalImpl_Destroy(
3086 Storage32InternalImpl
* This
)
3088 HeapFree(GetProcessHeap(), 0, This
);
3091 /******************************************************************************
3093 ** Storage32InternalImpl_Commit
3095 ** The non-root storages cannot be opened in transacted mode thus this function
3098 HRESULT WINAPI
Storage32InternalImpl_Commit(
3100 DWORD grfCommitFlags
) /* [in] */
3105 /******************************************************************************
3107 ** Storage32InternalImpl_Revert
3109 ** The non-root storages cannot be opened in transacted mode thus this function
3112 HRESULT WINAPI
Storage32InternalImpl_Revert(
3118 /******************************************************************************
3119 ** IEnumSTATSTGImpl implementation
3122 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3123 Storage32Impl
* parentStorage
,
3124 ULONG firstPropertyNode
)
3126 IEnumSTATSTGImpl
* newEnumeration
;
3128 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3130 if (newEnumeration
!=0)
3133 * Set-up the virtual function table and reference count.
3135 newEnumeration
->lpvtbl
= &IEnumSTATSTGImpl_Vtbl
;
3136 newEnumeration
->ref
= 0;
3139 * We want to nail-down the reference to the storage in case the
3140 * enumeration out-lives the storage in the client application.
3142 newEnumeration
->parentStorage
= parentStorage
;
3143 IStorage32_AddRef((IStorage32
*)newEnumeration
->parentStorage
);
3145 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3148 * Initialize the search stack
3150 newEnumeration
->stackSize
= 0;
3151 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3152 newEnumeration
->stackToVisit
=
3153 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3156 * Make sure the current node of the iterator is the first one.
3158 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3161 return newEnumeration
;
3164 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3166 IStorage32_Release((IStorage32
*)This
->parentStorage
);
3167 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3168 HeapFree(GetProcessHeap(), 0, This
);
3171 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3172 IEnumSTATSTG
* iface
,
3176 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3179 * Perform a sanity check on the parameters.
3182 return E_INVALIDARG
;
3185 * Initialize the return parameter.
3190 * Compare the riid with the interface IDs implemented by this object.
3192 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3194 *ppvObject
= (IEnumSTATSTG
*)This
;
3196 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3198 *ppvObject
= (IEnumSTATSTG
*)This
;
3202 * Check that we obtained an interface.
3204 if ((*ppvObject
)==0)
3205 return E_NOINTERFACE
;
3208 * Query Interface always increases the reference count by one when it is
3211 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3216 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3217 IEnumSTATSTG
* iface
)
3219 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3225 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3226 IEnumSTATSTG
* iface
)
3228 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3236 * If the reference count goes down to 0, perform suicide.
3240 IEnumSTATSTGImpl_Destroy(This
);
3246 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3247 IEnumSTATSTG
* iface
,
3250 ULONG
* pceltFetched
)
3252 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3254 StgProperty currentProperty
;
3255 STATSTG
* currentReturnStruct
= rgelt
;
3256 ULONG objectFetched
= 0;
3257 ULONG currentSearchNode
;
3260 * Perform a sanity check on the parameters.
3262 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3263 return E_INVALIDARG
;
3266 * To avoid the special case, get another pointer to a ULONG value if
3267 * the caller didn't supply one.
3269 if (pceltFetched
==0)
3270 pceltFetched
= &objectFetched
;
3273 * Start the iteration, we will iterate until we hit the end of the
3274 * linked list or until we hit the number of items to iterate through
3279 * Start with the node at the top of the stack.
3281 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3283 while ( ( *pceltFetched
< celt
) &&
3284 ( currentSearchNode
!=PROPERTY_NULL
) )
3287 * Remove the top node from the stack
3289 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3292 * Read the property from the storage.
3294 Storage32Impl_ReadProperty(This
->parentStorage
,
3299 * Copy the information to the return buffer.
3301 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3306 * Step to the next item in the iteration
3309 currentReturnStruct
++;
3312 * Push the next search node in the search stack.
3314 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3317 * continue the iteration.
3319 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3322 if (*pceltFetched
== celt
)
3329 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3330 IEnumSTATSTG
* iface
,
3333 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3335 StgProperty currentProperty
;
3336 ULONG objectFetched
= 0;
3337 ULONG currentSearchNode
;
3340 * Start with the node at the top of the stack.
3342 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3344 while ( (objectFetched
< celt
) &&
3345 (currentSearchNode
!=PROPERTY_NULL
) )
3348 * Remove the top node from the stack
3350 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3353 * Read the property from the storage.
3355 Storage32Impl_ReadProperty(This
->parentStorage
,
3360 * Step to the next item in the iteration
3365 * Push the next search node in the search stack.
3367 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3370 * continue the iteration.
3372 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3375 if (objectFetched
== celt
)
3381 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3382 IEnumSTATSTG
* iface
)
3384 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3386 StgProperty rootProperty
;
3387 BOOL32 readSucessful
;
3390 * Re-initialize the search stack to an empty stack
3392 This
->stackSize
= 0;
3395 * Read the root property from the storage.
3397 readSucessful
= Storage32Impl_ReadProperty(
3398 This
->parentStorage
,
3399 This
->firstPropertyNode
,
3404 assert(rootProperty
.sizeOfNameString
!=0);
3407 * Push the search node in the search stack.
3409 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3415 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3416 IEnumSTATSTG
* iface
,
3417 IEnumSTATSTG
** ppenum
)
3419 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3421 IEnumSTATSTGImpl
* newClone
;
3424 * Perform a sanity check on the parameters.
3427 return E_INVALIDARG
;
3429 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3430 This
->firstPropertyNode
);
3434 * The new clone enumeration must point to the same current node as
3437 newClone
->stackSize
= This
->stackSize
;
3438 newClone
->stackMaxSize
= This
->stackMaxSize
;
3439 newClone
->stackToVisit
=
3440 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3443 newClone
->stackToVisit
,
3445 sizeof(ULONG
) * newClone
->stackSize
);
3447 *ppenum
= (IEnumSTATSTG
*)newClone
;
3450 * Don't forget to nail down a reference to the clone before
3453 IEnumSTATSTGImpl_AddRef(*ppenum
);
3458 INT32
IEnumSTATSTGImpl_FindParentProperty(
3459 IEnumSTATSTGImpl
*This
,
3460 ULONG childProperty
,
3461 StgProperty
*currentProperty
,
3464 ULONG currentSearchNode
;
3468 * To avoid the special case, get another pointer to a ULONG value if
3469 * the caller didn't supply one.
3472 thisNodeId
= &foundNode
;
3475 * Start with the node at the top of the stack.
3477 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3480 while (currentSearchNode
!=PROPERTY_NULL
)
3483 * Store the current node in the returned parameters
3485 *thisNodeId
= currentSearchNode
;
3488 * Remove the top node from the stack
3490 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3493 * Read the property from the storage.
3495 Storage32Impl_ReadProperty(
3496 This
->parentStorage
,
3500 if (currentProperty
->previousProperty
== childProperty
)
3501 return PROPERTY_RELATION_PREVIOUS
;
3503 else if (currentProperty
->nextProperty
== childProperty
)
3504 return PROPERTY_RELATION_NEXT
;
3506 else if (currentProperty
->dirProperty
== childProperty
)
3507 return PROPERTY_RELATION_DIR
;
3510 * Push the next search node in the search stack.
3512 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3515 * continue the iteration.
3517 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3520 return PROPERTY_NULL
;
3523 ULONG
IEnumSTATSTGImpl_FindProperty(
3524 IEnumSTATSTGImpl
* This
,
3525 const OLECHAR32
* lpszPropName
,
3526 StgProperty
* currentProperty
)
3528 ULONG currentSearchNode
;
3531 * Start with the node at the top of the stack.
3533 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3535 while (currentSearchNode
!=PROPERTY_NULL
)
3538 * Remove the top node from the stack
3540 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3543 * Read the property from the storage.
3545 Storage32Impl_ReadProperty(This
->parentStorage
,
3549 if ( propertyNameCmp(
3550 (OLECHAR32
*)currentProperty
->name
,
3551 (OLECHAR32
*)lpszPropName
) == 0)
3552 return currentSearchNode
;
3555 * Push the next search node in the search stack.
3557 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3560 * continue the iteration.
3562 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3565 return PROPERTY_NULL
;
3568 void IEnumSTATSTGImpl_PushSearchNode(
3569 IEnumSTATSTGImpl
* This
,
3572 StgProperty rootProperty
;
3573 BOOL32 readSucessful
;
3576 * First, make sure we're not trying to push an unexisting node.
3578 if (nodeToPush
==PROPERTY_NULL
)
3582 * First push the node to the stack
3584 if (This
->stackSize
== This
->stackMaxSize
)
3586 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3588 This
->stackToVisit
= HeapReAlloc(
3592 sizeof(ULONG
) * This
->stackMaxSize
);
3595 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3599 * Read the root property from the storage.
3601 readSucessful
= Storage32Impl_ReadProperty(
3602 This
->parentStorage
,
3608 assert(rootProperty
.sizeOfNameString
!=0);
3611 * Push the previous search node in the search stack.
3613 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3617 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3618 IEnumSTATSTGImpl
* This
,
3623 if (This
->stackSize
== 0)
3624 return PROPERTY_NULL
;
3626 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3634 /******************************************************************************
3635 ** StorageUtl implementation
3638 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3640 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3643 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3645 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3648 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3650 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3653 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3655 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3658 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3660 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3661 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3662 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3664 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
3667 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
3669 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
3670 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
3671 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
3673 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
3676 void StorageUtl_CopyPropertyToSTATSTG(
3677 STATSTG
* destination
,
3678 StgProperty
* source
,
3682 * The copy of the string occurs only when the flag is not set
3684 if ((statFlags
& STATFLAG_NONAME
) != 0)
3686 destination
->pwcsName
= 0;
3690 destination
->pwcsName
=
3691 CoTaskMemAlloc((lstrlen32W(source
->name
)+1)*sizeof(WCHAR
));
3693 lstrcpy32W((LPWSTR
)destination
->pwcsName
, source
->name
);
3696 switch (source
->propertyType
)
3698 case PROPTYPE_STORAGE
:
3700 destination
->type
= STGTY_STORAGE
;
3702 case PROPTYPE_STREAM
:
3703 destination
->type
= STGTY_STREAM
;
3706 destination
->type
= STGTY_STREAM
;
3710 destination
->cbSize
= source
->size
;
3712 currentReturnStruct->mtime = {0}; TODO
3713 currentReturnStruct->ctime = {0};
3714 currentReturnStruct->atime = {0};
3716 destination
->grfMode
= 0;
3717 destination
->grfLocksSupported
= 0;
3718 destination
->clsid
= source
->propertyUniqueID
;
3719 destination
->grfStateBits
= 0;
3720 destination
->reserved
= 0;
3723 /******************************************************************************
3724 ** BlockChainStream implementation
3727 BlockChainStream
* BlockChainStream_Construct(
3728 Storage32Impl
* parentStorage
,
3729 ULONG
* headOfStreamPlaceHolder
,
3730 ULONG propertyIndex
)
3732 BlockChainStream
* newStream
;
3734 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
3736 newStream
->parentStorage
= parentStorage
;
3737 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
3738 newStream
->ownerPropertyIndex
= propertyIndex
;
3743 void BlockChainStream_Destroy(BlockChainStream
* This
)
3745 HeapFree(GetProcessHeap(), 0, This
);
3748 /******************************************************************************
3749 * BlockChainStream_GetHeadOfChain
3751 * Returns the head of this stream chain.
3752 * Some special chains don't have properties, their heads are kept in
3753 * This->headOfStreamPlaceHolder.
3756 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
3758 StgProperty chainProperty
;
3759 BOOL32 readSucessful
;
3761 if (This
->headOfStreamPlaceHolder
!= 0)
3762 return *(This
->headOfStreamPlaceHolder
);
3764 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
3766 readSucessful
= Storage32Impl_ReadProperty(
3767 This
->parentStorage
,
3768 This
->ownerPropertyIndex
,
3773 return chainProperty
.startingBlock
;
3777 return BLOCK_END_OF_CHAIN
;
3780 /******************************************************************************
3781 * BlockChainStream_GetCount
3783 * Returns the number of blocks that comprises this chain.
3784 * This is not the size of the stream as the last block may not be full!
3787 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
3792 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3794 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
3798 blockIndex
= Storage32Impl_GetNextBlockInChain(
3799 This
->parentStorage
,
3806 /******************************************************************************
3807 * BlockChainStream_ReadAt
3809 * Reads a specified number of bytes from this chain at the specified offset.
3810 * bytesRead may be NULL.
3811 * Failure will be returned if the specified number of bytes has not been read.
3813 BOOL32
BlockChainStream_ReadAt(BlockChainStream
* This
,
3814 ULARGE_INTEGER offset
,
3819 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3820 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
3821 ULONG bytesToReadInBuffer
;
3824 BYTE
* bigBlockBuffer
;
3827 * Find the first block in the stream that contains part of the buffer.
3829 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3831 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
3834 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3836 blockNoInSequence
--;
3840 * Start reading the buffer.
3843 bufferWalker
= buffer
;
3845 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
3848 * Calculate how many bytes we can copy from this big block.
3850 bytesToReadInBuffer
=
3851 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
3854 * Copy those bytes to the buffer
3857 Storage32Impl_GetROBigBlock(This
->parentStorage
, blockIndex
);
3859 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
3861 Storage32Impl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
3864 * Step to the next big block.
3867 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3869 bufferWalker
+= bytesToReadInBuffer
;
3870 size
-= bytesToReadInBuffer
;
3871 *bytesRead
+= bytesToReadInBuffer
;
3872 offsetInBlock
= 0; /* There is no offset on the next block */
3879 /******************************************************************************
3880 * BlockChainStream_WriteAt
3882 * Writes the specified number of bytes to this chain at the specified offset.
3883 * bytesWritten may be NULL.
3884 * Will fail if not all specified number of bytes have been written.
3886 BOOL32
BlockChainStream_WriteAt(BlockChainStream
* This
,
3887 ULARGE_INTEGER offset
,
3890 ULONG
* bytesWritten
)
3892 ULONG blockNoInSequence
= offset
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3893 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->bigBlockSize
;
3897 BYTE
* bigBlockBuffer
;
3900 * Find the first block in the stream that contains part of the buffer.
3902 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3904 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
3907 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3909 blockNoInSequence
--;
3913 * Here, I'm casting away the constness on the buffer variable
3914 * This is OK since we don't intend to modify that buffer.
3917 bufferWalker
= (BYTE
*)buffer
;
3919 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
3922 * Calculate how many bytes we can copy from this big block.
3925 MIN(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
3928 * Copy those bytes to the buffer
3930 bigBlockBuffer
= Storage32Impl_GetBigBlock(This
->parentStorage
, blockIndex
);
3932 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
3934 Storage32Impl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
3937 * Step to the next big block.
3940 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3942 bufferWalker
+= bytesToWrite
;
3943 size
-= bytesToWrite
;
3944 *bytesWritten
+= bytesToWrite
;
3945 offsetInBlock
= 0; /* There is no offset on the next block */
3951 /******************************************************************************
3952 * BlockChainStream_Shrink
3954 * Shrinks this chain in the big block depot.
3956 BOOL32
BlockChainStream_Shrink(BlockChainStream
* This
,
3957 ULARGE_INTEGER newSize
)
3959 ULONG blockIndex
, extraBlock
;
3964 * Figure out how many blocks are needed to contain the new size
3966 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
3968 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
3971 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
3974 * Go to the new end of chain
3976 while (count
< numBlocks
)
3979 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3984 /* Get the next block before marking the new end */
3986 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
3988 /* Mark the new end of chain */
3989 Storage32Impl_SetNextBlockInChain(
3990 This
->parentStorage
,
3992 BLOCK_END_OF_CHAIN
);
3995 * Mark the extra blocks as free
3997 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4000 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4002 Storage32Impl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4003 extraBlock
= blockIndex
;
4009 /******************************************************************************
4010 * BlockChainStream_Enlarge
4012 * Grows this chain in the big block depot.
4014 BOOL32
BlockChainStream_Enlarge(BlockChainStream
* This
,
4015 ULARGE_INTEGER newSize
)
4017 ULONG blockIndex
, currentBlock
;
4019 ULONG oldNumBlocks
= 0;
4021 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4024 * Empty chain. Create the head.
4026 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4028 blockIndex
= Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
4029 Storage32Impl_SetNextBlockInChain(This
->parentStorage
,
4031 BLOCK_END_OF_CHAIN
);
4033 if (This
->headOfStreamPlaceHolder
!= 0)
4035 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4039 StgProperty chainProp
;
4040 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4042 Storage32Impl_ReadProperty(
4043 This
->parentStorage
,
4044 This
->ownerPropertyIndex
,
4047 chainProp
.startingBlock
= blockIndex
;
4049 Storage32Impl_WriteProperty(
4050 This
->parentStorage
,
4051 This
->ownerPropertyIndex
,
4056 currentBlock
= blockIndex
;
4059 * Figure out how many blocks are needed to contain this stream
4061 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4063 if ((newSize
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4067 * Go to the current end of chain
4069 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4072 currentBlock
= blockIndex
;
4075 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4079 * Add new blocks to the chain
4081 while (oldNumBlocks
< newNumBlocks
)
4083 blockIndex
= Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
4085 Storage32Impl_SetNextBlockInChain(
4086 This
->parentStorage
,
4090 Storage32Impl_SetNextBlockInChain(
4091 This
->parentStorage
,
4093 BLOCK_END_OF_CHAIN
);
4095 currentBlock
= blockIndex
;
4102 /******************************************************************************
4103 * BlockChainStream_SetSize
4105 * Sets the size of this stream. The big block depot will be updated.
4106 * The file will grow if we grow the chain.
4108 * TODO: Free the actual blocks in the file when we shrink the chain.
4109 * Currently, the blocks are still in the file. So the file size
4110 * doesn't shrink even if we shrink streams.
4112 BOOL32
BlockChainStream_SetSize(
4113 BlockChainStream
* This
,
4114 ULARGE_INTEGER newSize
)
4116 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4118 if (newSize
.LowPart
== size
.LowPart
)
4121 if (newSize
.LowPart
< size
.LowPart
)
4123 BlockChainStream_Shrink(This
, newSize
);
4127 ULARGE_INTEGER fileSize
=
4128 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4130 ULONG diff
= newSize
.LowPart
- size
.LowPart
;
4133 * Make sure the file stays a multiple of blocksize
4135 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4136 diff
+= (This
->parentStorage
->bigBlockSize
-
4137 (diff
% This
->parentStorage
->bigBlockSize
) );
4139 fileSize
.LowPart
+= diff
;
4140 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4142 BlockChainStream_Enlarge(This
, newSize
);
4148 /******************************************************************************
4149 * BlockChainStream_GetSize
4151 * Returns the size of this chain.
4152 * Will return the block count if this chain doesn't have a property.
4154 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4156 StgProperty chainProperty
;
4158 if(This
->headOfStreamPlaceHolder
== NULL
)
4161 * This chain is a data stream read the property and return
4162 * the appropriate size
4164 Storage32Impl_ReadProperty(
4165 This
->parentStorage
,
4166 This
->ownerPropertyIndex
,
4169 return chainProperty
.size
;
4174 * this chain is a chain that does not have a property, figure out the
4175 * size by making the product number of used blocks times the
4178 ULARGE_INTEGER result
;
4179 result
.HighPart
= 0;
4182 BlockChainStream_GetCount(This
) *
4183 This
->parentStorage
->bigBlockSize
;
4189 /******************************************************************************
4190 ** SmallBlockChainStream implementation
4193 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4194 Storage32Impl
* parentStorage
,
4195 ULONG propertyIndex
)
4197 SmallBlockChainStream
* newStream
;
4199 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4201 newStream
->parentStorage
= parentStorage
;
4202 newStream
->ownerPropertyIndex
= propertyIndex
;
4207 void SmallBlockChainStream_Destroy(
4208 SmallBlockChainStream
* This
)
4210 HeapFree(GetProcessHeap(), 0, This
);
4213 /******************************************************************************
4214 * SmallBlockChainStream_GetHeadOfChain
4216 * Returns the head of this chain of small blocks.
4218 ULONG
SmallBlockChainStream_GetHeadOfChain(
4219 SmallBlockChainStream
* This
)
4221 StgProperty chainProperty
;
4222 BOOL32 readSucessful
;
4224 if (This
->ownerPropertyIndex
)
4226 readSucessful
= Storage32Impl_ReadProperty(
4227 This
->parentStorage
,
4228 This
->ownerPropertyIndex
,
4233 return chainProperty
.startingBlock
;
4238 return BLOCK_END_OF_CHAIN
;
4241 /******************************************************************************
4242 * SmallBlockChainStream_GetNextBlockInChain
4244 * Returns the index of the next small block in this chain.
4247 * - BLOCK_END_OF_CHAIN: end of this chain
4248 * - BLOCK_UNUSED: small block 'blockIndex' is free
4250 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4251 SmallBlockChainStream
* This
,
4254 ULARGE_INTEGER offsetOfBlockInDepot
;
4256 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4260 offsetOfBlockInDepot
.HighPart
= 0;
4261 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4264 * Read those bytes in the buffer from the small block file.
4266 success
= BlockChainStream_ReadAt(
4267 This
->parentStorage
->smallBlockDepotChain
,
4268 offsetOfBlockInDepot
,
4275 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4278 return nextBlockInChain
;
4281 /******************************************************************************
4282 * SmallBlockChainStream_SetNextBlockInChain
4284 * Writes the index of the next block of the specified block in the small
4286 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4287 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4289 void SmallBlockChainStream_SetNextBlockInChain(
4290 SmallBlockChainStream
* This
,
4294 ULARGE_INTEGER offsetOfBlockInDepot
;
4298 offsetOfBlockInDepot
.HighPart
= 0;
4299 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4301 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4304 * Read those bytes in the buffer from the small block file.
4306 BlockChainStream_WriteAt(
4307 This
->parentStorage
->smallBlockDepotChain
,
4308 offsetOfBlockInDepot
,
4314 /******************************************************************************
4315 * SmallBlockChainStream_FreeBlock
4317 * Flag small block 'blockIndex' as free in the small block depot.
4319 void SmallBlockChainStream_FreeBlock(
4320 SmallBlockChainStream
* This
,
4323 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4326 /******************************************************************************
4327 * SmallBlockChainStream_GetNextFreeBlock
4329 * Returns the index of a free small block. The small block depot will be
4330 * enlarged if necessary. The small block chain will also be enlarged if
4333 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4334 SmallBlockChainStream
* This
)
4336 ULARGE_INTEGER offsetOfBlockInDepot
;
4339 ULONG blockIndex
= 0;
4340 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4341 BOOL32 success
= TRUE
;
4342 ULONG smallBlocksPerBigBlock
;
4344 offsetOfBlockInDepot
.HighPart
= 0;
4347 * Scan the small block depot for a free block
4349 while (nextBlockIndex
!= BLOCK_UNUSED
)
4351 offsetOfBlockInDepot
.LowPart
= blockIndex
* sizeof(ULONG
);
4353 success
= BlockChainStream_ReadAt(
4354 This
->parentStorage
->smallBlockDepotChain
,
4355 offsetOfBlockInDepot
,
4361 * If we run out of space for the small block depot, enlarge it
4365 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4367 if (nextBlockIndex
!= BLOCK_UNUSED
)
4373 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4375 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4376 ULONG nextBlock
, newsbdIndex
;
4377 BYTE
* smallBlockDepot
;
4379 nextBlock
= sbdIndex
;
4380 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4382 sbdIndex
= nextBlock
;
4384 Storage32Impl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4387 newsbdIndex
= Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
4388 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4389 Storage32Impl_SetNextBlockInChain(
4390 This
->parentStorage
,
4394 Storage32Impl_SetNextBlockInChain(
4395 This
->parentStorage
,
4397 BLOCK_END_OF_CHAIN
);
4400 * Initialize all the small blocks to free
4403 Storage32Impl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4405 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4406 Storage32Impl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4411 * We have just created the small block depot.
4413 StgProperty rootProp
;
4417 * Save it in the header
4419 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4420 Storage32Impl_SaveFileHeader(This
->parentStorage
);
4423 * And allocate the first big block that will contain small blocks
4426 Storage32Impl_GetNextFreeBigBlock(This
->parentStorage
);
4428 Storage32Impl_SetNextBlockInChain(
4429 This
->parentStorage
,
4431 BLOCK_END_OF_CHAIN
);
4433 Storage32Impl_ReadProperty(
4434 This
->parentStorage
,
4435 This
->parentStorage
->rootPropertySetIndex
,
4438 rootProp
.startingBlock
= sbStartIndex
;
4439 rootProp
.size
.HighPart
= 0;
4440 rootProp
.size
.LowPart
= This
->parentStorage
->bigBlockSize
;
4442 Storage32Impl_WriteProperty(
4443 This
->parentStorage
,
4444 This
->parentStorage
->rootPropertySetIndex
,
4450 smallBlocksPerBigBlock
=
4451 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4454 * Verify if we have to allocate big blocks to contain small blocks
4456 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4458 StgProperty rootProp
;
4459 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4461 Storage32Impl_ReadProperty(
4462 This
->parentStorage
,
4463 This
->parentStorage
->rootPropertySetIndex
,
4466 if (rootProp
.size
.LowPart
<
4467 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4469 rootProp
.size
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4471 BlockChainStream_SetSize(
4472 This
->parentStorage
->smallBlockRootChain
,
4475 Storage32Impl_WriteProperty(
4476 This
->parentStorage
,
4477 This
->parentStorage
->rootPropertySetIndex
,
4485 /******************************************************************************
4486 * SmallBlockChainStream_ReadAt
4488 * Reads a specified number of bytes from this chain at the specified offset.
4489 * bytesRead may be NULL.
4490 * Failure will be returned if the specified number of bytes has not been read.
4492 BOOL32
SmallBlockChainStream_ReadAt(
4493 SmallBlockChainStream
* This
,
4494 ULARGE_INTEGER offset
,
4499 ULARGE_INTEGER offsetInBigBlockFile
;
4500 ULONG blockNoInSequence
=
4501 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4503 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4504 ULONG bytesToReadInBuffer
;
4506 ULONG bytesReadFromBigBlockFile
;
4510 * This should never happen on a small block file.
4512 assert(offset
.HighPart
==0);
4515 * Find the first block in the stream that contains part of the buffer.
4517 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4519 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4521 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4523 blockNoInSequence
--;
4527 * Start reading the buffer.
4530 bufferWalker
= buffer
;
4532 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4535 * Calculate how many bytes we can copy from this small block.
4537 bytesToReadInBuffer
=
4538 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4541 * Calculate the offset of the small block in the small block file.
4543 offsetInBigBlockFile
.HighPart
= 0;
4544 offsetInBigBlockFile
.LowPart
=
4545 blockIndex
* This
->parentStorage
->smallBlockSize
;
4547 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4550 * Read those bytes in the buffer from the small block file.
4552 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4553 offsetInBigBlockFile
,
4554 bytesToReadInBuffer
,
4556 &bytesReadFromBigBlockFile
);
4558 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4561 * Step to the next big block.
4563 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4564 bufferWalker
+= bytesToReadInBuffer
;
4565 size
-= bytesToReadInBuffer
;
4566 *bytesRead
+= bytesToReadInBuffer
;
4567 offsetInBlock
= 0; /* There is no offset on the next block */
4573 /******************************************************************************
4574 * SmallBlockChainStream_WriteAt
4576 * Writes the specified number of bytes to this chain at the specified offset.
4577 * bytesWritten may be NULL.
4578 * Will fail if not all specified number of bytes have been written.
4580 BOOL32
SmallBlockChainStream_WriteAt(
4581 SmallBlockChainStream
* This
,
4582 ULARGE_INTEGER offset
,
4585 ULONG
* bytesWritten
)
4587 ULARGE_INTEGER offsetInBigBlockFile
;
4588 ULONG blockNoInSequence
=
4589 offset
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4591 ULONG offsetInBlock
= offset
.LowPart
% This
->parentStorage
->smallBlockSize
;
4592 ULONG bytesToWriteInBuffer
;
4594 ULONG bytesWrittenFromBigBlockFile
;
4598 * This should never happen on a small block file.
4600 assert(offset
.HighPart
==0);
4603 * Find the first block in the stream that contains part of the buffer.
4605 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4607 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4609 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4611 blockNoInSequence
--;
4615 * Start writing the buffer.
4617 * Here, I'm casting away the constness on the buffer variable
4618 * This is OK since we don't intend to modify that buffer.
4621 bufferWalker
= (BYTE
*)buffer
;
4622 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4625 * Calculate how many bytes we can copy to this small block.
4627 bytesToWriteInBuffer
=
4628 MIN(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4631 * Calculate the offset of the small block in the small block file.
4633 offsetInBigBlockFile
.HighPart
= 0;
4634 offsetInBigBlockFile
.LowPart
=
4635 blockIndex
* This
->parentStorage
->smallBlockSize
;
4637 offsetInBigBlockFile
.LowPart
+= offsetInBlock
;
4640 * Write those bytes in the buffer to the small block file.
4642 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
4643 offsetInBigBlockFile
,
4644 bytesToWriteInBuffer
,
4646 &bytesWrittenFromBigBlockFile
);
4648 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
4651 * Step to the next big block.
4653 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4654 bufferWalker
+= bytesToWriteInBuffer
;
4655 size
-= bytesToWriteInBuffer
;
4656 *bytesWritten
+= bytesToWriteInBuffer
;
4657 offsetInBlock
= 0; /* There is no offset on the next block */
4663 /******************************************************************************
4664 * SmallBlockChainStream_Shrink
4666 * Shrinks this chain in the small block depot.
4668 BOOL32
SmallBlockChainStream_Shrink(
4669 SmallBlockChainStream
* This
,
4670 ULARGE_INTEGER newSize
)
4672 ULONG blockIndex
, extraBlock
;
4676 numBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4678 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4681 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4684 * Go to the new end of chain
4686 while (count
< numBlocks
)
4688 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4692 /* Get the next block before marking the new end */
4693 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4695 /* Mark the new end of chain */
4696 SmallBlockChainStream_SetNextBlockInChain(
4699 BLOCK_END_OF_CHAIN
);
4702 * Mark the extra blocks as free
4704 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4706 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
4707 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
4708 extraBlock
= blockIndex
;
4714 /******************************************************************************
4715 * SmallBlockChainStream_Enlarge
4717 * Grows this chain in the small block depot.
4719 BOOL32
SmallBlockChainStream_Enlarge(
4720 SmallBlockChainStream
* This
,
4721 ULARGE_INTEGER newSize
)
4723 ULONG blockIndex
, currentBlock
;
4725 ULONG oldNumBlocks
= 0;
4727 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4732 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4734 StgProperty chainProp
;
4736 Storage32Impl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
4739 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
4741 Storage32Impl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
4744 blockIndex
= chainProp
.startingBlock
;
4745 SmallBlockChainStream_SetNextBlockInChain(
4748 BLOCK_END_OF_CHAIN
);
4751 currentBlock
= blockIndex
;
4754 * Figure out how many blocks are needed to contain this stream
4756 newNumBlocks
= newSize
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4758 if ((newSize
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
4762 * Go to the current end of chain
4764 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4767 currentBlock
= blockIndex
;
4768 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
4772 * Add new blocks to the chain
4774 while (oldNumBlocks
< newNumBlocks
)
4776 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
4777 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
4779 SmallBlockChainStream_SetNextBlockInChain(
4782 BLOCK_END_OF_CHAIN
);
4784 currentBlock
= blockIndex
;
4791 /******************************************************************************
4792 * SmallBlockChainStream_GetCount
4794 * Returns the number of blocks that comprises this chain.
4795 * This is not the size of this chain as the last block may not be full!
4797 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
4802 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4804 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4808 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4814 /******************************************************************************
4815 * SmallBlockChainStream_SetSize
4817 * Sets the size of this stream.
4818 * The file will grow if we grow the chain.
4820 * TODO: Free the actual blocks in the file when we shrink the chain.
4821 * Currently, the blocks are still in the file. So the file size
4822 * doesn't shrink even if we shrink streams.
4824 BOOL32
SmallBlockChainStream_SetSize(
4825 SmallBlockChainStream
* This
,
4826 ULARGE_INTEGER newSize
)
4828 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
4830 if (newSize
.LowPart
== size
.LowPart
)
4833 if (newSize
.LowPart
< size
.LowPart
)
4835 SmallBlockChainStream_Shrink(This
, newSize
);
4839 SmallBlockChainStream_Enlarge(This
, newSize
);
4845 /******************************************************************************
4846 * SmallBlockChainStream_GetSize
4848 * Returns the size of this chain.
4850 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
4852 StgProperty chainProperty
;
4854 Storage32Impl_ReadProperty(
4855 This
->parentStorage
,
4856 This
->ownerPropertyIndex
,
4859 return chainProperty
.size
;
4862 /******************************************************************************
4863 * StgCreateDocfile32 [OLE32.144]
4864 * TODO Validate grfMode (STGM)
4866 HRESULT WINAPI
StgCreateDocfile32(
4867 LPCOLESTR32 pwcsName
,
4870 IStorage32
**ppstgOpen
)
4872 Storage32Impl
* newStorage
= 0;
4873 HANDLE32 hFile
= INVALID_HANDLE_VALUE32
;
4878 DWORD fileAttributes
;
4881 * Validate the parameters
4883 if ((ppstgOpen
== 0) || (pwcsName
== 0))
4884 return STG_E_INVALIDPOINTER
;
4887 * Validate the STGM flags
4889 if ( FAILED( validateSTGM(grfMode
) ))
4890 return STG_E_INVALIDFLAG
;
4893 * Interpret the STGM value grfMode
4895 shareMode
= GetShareModeFromSTGM(grfMode
);
4896 accessMode
= GetAccessModeFromSTGM(grfMode
);
4897 creationMode
= GetCreationModeFromSTGM(grfMode
);
4899 if (grfMode
& STGM_DELETEONRELEASE
)
4900 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
4902 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
4904 if (grfMode
& STGM_TRANSACTED
)
4905 FIXME(ole
, "Transacted mode not implemented.\n");
4908 * Initialize the "out" parameter.
4912 hFile
= CreateFile32W(pwcsName
,
4920 if (hFile
== INVALID_HANDLE_VALUE32
)
4926 * Allocate and initialize the new IStorage32object.
4928 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl
));
4930 if (newStorage
== 0)
4931 return STG_E_INSUFFICIENTMEMORY
;
4933 hr
= Storage32Impl_Construct(
4942 * Get an "out" pointer for the caller.
4944 hr
= Storage32BaseImpl_QueryInterface(
4945 (IStorage32
*)newStorage
,
4946 (REFIID
)&IID_IStorage
,
4952 /******************************************************************************
4953 * StgOpenStorage32 [OLE32.148]
4955 HRESULT WINAPI
StgOpenStorage32(
4956 const OLECHAR32
*pwcsName
,
4957 IStorage32
*pstgPriority
,
4961 IStorage32
**ppstgOpen
)
4963 Storage32Impl
* newStorage
= 0;
4970 * Perform a sanity check
4972 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
4973 return STG_E_INVALIDPOINTER
;
4976 * Validate the STGM flags
4978 if ( FAILED( validateSTGM(grfMode
) ))
4979 return STG_E_INVALIDFLAG
;
4982 * Interpret the STGM value grfMode
4984 shareMode
= GetShareModeFromSTGM(grfMode
);
4985 accessMode
= GetAccessModeFromSTGM(grfMode
);
4988 * Initialize the "out" parameter.
4992 hFile
= CreateFile32W( pwcsName
,
4997 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5001 if (hFile
==INVALID_HANDLE_VALUE32
)
5007 * Allocate and initialize the new IStorage32object.
5009 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl
));
5011 if (newStorage
== 0)
5012 return STG_E_INSUFFICIENTMEMORY
;
5014 hr
= Storage32Impl_Construct(
5023 * Get an "out" pointer for the caller.
5025 hr
= Storage32BaseImpl_QueryInterface(
5026 (IStorage32
*)newStorage
,
5027 (REFIID
)&IID_IStorage
,
5033 /******************************************************************************
5034 * WriteClassStg32 [OLE32.148]
5036 * This method will store the specified CLSID in the specified storage object
5038 HRESULT WINAPI
WriteClassStg32(IStorage32
* pStg
, REFCLSID rclsid
)
5044 hRes
= IStorage32_SetClass(pStg
, rclsid
);
5050 /****************************************************************************
5051 * This method validate a STGM parameter that can contain the values below
5053 * STGM_DIRECT 0x00000000
5054 * STGM_TRANSACTED 0x00010000
5055 * STGM_SIMPLE 0x08000000
5057 * STGM_READ 0x00000000
5058 * STGM_WRITE 0x00000001
5059 * STGM_READWRITE 0x00000002
5061 * STGM_SHARE_DENY_NONE 0x00000040
5062 * STGM_SHARE_DENY_READ 0x00000030
5063 * STGM_SHARE_DENY_WRITE 0x00000020
5064 * STGM_SHARE_EXCLUSIVE 0x00000010
5066 * STGM_PRIORITY 0x00040000
5067 * STGM_DELETEONRELEASE 0x04000000
5069 * STGM_CREATE 0x00001000
5070 * STGM_CONVERT 0x00020000
5071 * STGM_FAILIFTHERE 0x00000000
5073 * STGM_NOSCRATCH 0x00100000
5074 * STGM_NOSNAPSHOT 0x00200000
5076 static HRESULT
validateSTGM(DWORD stgm
)
5078 BOOL32 bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5079 BOOL32 bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5080 BOOL32 bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5082 BOOL32 bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5083 BOOL32 bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5084 BOOL32 bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5086 BOOL32 bSTGM_SHARE_DENY_NONE
=
5087 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5089 BOOL32 bSTGM_SHARE_DENY_READ
=
5090 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5092 BOOL32 bSTGM_SHARE_DENY_WRITE
=
5093 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5095 BOOL32 bSTGM_SHARE_EXCLUSIVE
=
5096 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5098 BOOL32 bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5099 BOOL32 bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5101 BOOL32 bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5102 BOOL32 bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5105 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5107 if ( ! bSTGM_DIRECT
)
5108 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5112 * STGM_WRITE | STGM_READWRITE | STGM_READ
5115 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5119 * STGM_SHARE_DENY_NONE | others
5120 * (I assume here that DENY_READ implies DENY_WRITE)
5122 if ( bSTGM_SHARE_DENY_NONE
)
5123 if ( bSTGM_SHARE_DENY_READ
||
5124 bSTGM_SHARE_DENY_WRITE
||
5125 bSTGM_SHARE_EXCLUSIVE
)
5129 * STGM_CREATE | STGM_CONVERT
5130 * if both are false, STGM_FAILIFTHERE is set to TRUE
5132 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5136 * STGM_NOSCRATCH requires STGM_TRANSACTED
5138 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5142 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5143 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5145 if (bSTGM_NOSNAPSHOT
)
5147 if ( ! ( bSTGM_TRANSACTED
&&
5148 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
5155 /****************************************************************************
5156 * GetShareModeFromSTGM
5158 * This method will return a share mode flag from a STGM value.
5159 * The STGM value is assumed valid.
5161 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
5163 DWORD dwShareMode
= 0;
5164 BOOL32 bSTGM_SHARE_DENY_NONE
=
5165 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5167 BOOL32 bSTGM_SHARE_DENY_READ
=
5168 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5170 BOOL32 bSTGM_SHARE_DENY_WRITE
=
5171 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5173 BOOL32 bSTGM_SHARE_EXCLUSIVE
=
5174 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5176 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
5179 if (bSTGM_SHARE_DENY_NONE
)
5180 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
5182 if (bSTGM_SHARE_DENY_WRITE
)
5183 dwShareMode
= FILE_SHARE_READ
;
5188 /****************************************************************************
5189 * GetAccessModeFromSTGM
5191 * This method will return an access mode flag from a STGM value.
5192 * The STGM value is assumed valid.
5194 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
5196 DWORD dwDesiredAccess
= 0;
5197 BOOL32 bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5198 BOOL32 bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5199 BOOL32 bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5202 dwDesiredAccess
= GENERIC_READ
;
5205 dwDesiredAccess
|= GENERIC_WRITE
;
5207 if (bSTGM_READWRITE
)
5208 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
5210 return dwDesiredAccess
;
5213 /****************************************************************************
5214 * GetCreationModeFromSTGM
5216 * This method will return a creation mode flag from a STGM value.
5217 * The STGM value is assumed valid.
5219 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
5221 DWORD dwCreationDistribution
;
5222 BOOL32 bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5223 BOOL32 bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5224 BOOL32 bSTGM_FAILIFTHERE
= ! (bSTGM_CREATE
|| bSTGM_CONVERT
);
5227 dwCreationDistribution
= CREATE_NEW
;
5228 else if (bSTGM_FAILIFTHERE
)
5229 dwCreationDistribution
= CREATE_NEW
;
5230 else if (bSTGM_CONVERT
)
5232 FIXME(ole
, "STGM_CONVERT not implemented!\n");
5233 dwCreationDistribution
= CREATE_NEW
;
5236 return dwCreationDistribution
;