Release 990225.
[wine.git] / ole / storage32.c
blob1073db7350de17fa336b04c63d24a2310ceae410
1 /*
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
13 #include <assert.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
18 #include "windows.h"
19 #include "winerror.h"
20 #include "file.h"
21 #include "ole.h"
22 #include "ole2.h"
23 #include "objbase.h"
24 #include "crtdll.h"
25 #include "tchar.h"
26 #include "heap.h"
28 #include "winnt.h"
29 #include "winbase.h"
30 #include "debug.h"
32 #include "storage32.h"
34 #define FILE_BEGIN 0
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(
57 Storage32Impl *This,
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(
170 IStorage32* iface,
171 REFIID riid,
172 void** ppvObject)
174 ICOM_THIS(Storage32BaseImpl,iface);
176 * Perform a sanity check on the parameters.
178 if ( (This==0) || (ppvObject==0) )
179 return E_INVALIDARG;
182 * Initialize the return parameter.
184 *ppvObject = 0;
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.
201 if ((*ppvObject)==0)
202 return E_NOINTERFACE;
205 * Query Interface always increases the reference count by one when it is
206 * successful
208 Storage32BaseImpl_AddRef(iface);
210 return S_OK;
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(
222 IStorage32* iface)
224 ICOM_THIS(Storage32BaseImpl,iface);
225 This->ref++;
227 return This->ref;
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(
239 IStorage32* iface)
241 ICOM_THIS(Storage32BaseImpl,iface);
243 * Decrease the reference count on this object.
245 This->ref--;
248 * If the reference count goes down to 0, perform suicide.
250 if (This->ref==0)
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);
259 return 0;
262 return This->ref;
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(
273 IStorage32* iface,
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) )
290 return E_INVALIDARG;
293 * Initialize the out parameter
295 *ppstm = 0;
298 * Validate the STGM flags
300 if ( FAILED( validateSTGM(grfMode) ))
301 return STG_E_INVALIDFLAG;
304 * As documented.
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(
322 propertyEnumeration,
323 pwcsName,
324 &currentProperty);
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);
339 if (newStream!=0)
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);
349 return S_OK;
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(
366 IStorage32* iface,
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) )
384 return E_INVALIDARG;
387 * Validate the STGM flags
389 if ( FAILED( validateSTGM(grfMode) ))
390 return STG_E_INVALIDFLAG;
393 * As documented.
395 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
396 (grfMode & STGM_DELETEONRELEASE) ||
397 (grfMode & STGM_PRIORITY) )
398 return STG_E_INVALIDFUNCTION;
401 * Initialize the out parameter
403 *ppstg = 0;
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(
416 propertyEnumeration,
417 pwcsName,
418 &currentProperty);
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,
436 foundPropertyIndex);
438 if (newStorage != 0)
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);
448 return S_OK;
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(
466 IStorage32* iface,
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))
479 return E_INVALIDARG;
482 * Construct the enumerator.
484 newEnum = IEnumSTATSTGImpl_Construct(
485 This->ancestorStorage,
486 This->rootPropertySetIndex);
488 if (newEnum!=0)
490 *ppenum = (IEnumSTATSTG*)newEnum;
493 * Don't forget to nail down a reference to the new object before
494 * returning it.
496 IEnumSTATSTGImpl_AddRef(*ppenum);
498 return S_OK;
501 return E_OUTOFMEMORY;
504 /************************************************************************
505 * Storage32BaseImpl_Stat (IStorage)
507 * This method will retrieve information about this storage object.
509 * See Windows documentation for more details on IStorage methods.
511 HRESULT WINAPI Storage32BaseImpl_Stat(
512 IStorage32* iface,
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))
524 return E_INVALIDARG;
527 * Read the information from the property.
529 readSucessful = Storage32Impl_ReadProperty(
530 This->ancestorStorage,
531 This->rootPropertySetIndex,
532 &curProperty);
534 if (readSucessful)
536 StorageUtl_CopyPropertyToSTATSTG(
537 pstatstg,
538 &curProperty,
539 grfStatFlag);
541 return S_OK;
544 return E_FAIL;
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(
559 IStorage32* iface,
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,
578 pwcsNewName,
579 &currentProperty);
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,
596 pwcsOldName,
597 &currentProperty);
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,
653 &renamedProperty);
656 * Find a spot in the property chain for our newly created property.
658 updatePropertyChain(
659 (Storage32Impl*)This,
660 renamedPropertyIndex,
661 renamedProperty);
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
667 * this to happen.
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
672 * non empty storage.
674 currentProperty.dirProperty = PROPERTY_NULL;
675 currentProperty.propertyType = PROPTYPE_STORAGE;
676 Storage32Impl_WriteProperty(
677 This->ancestorStorage,
678 foundPropertyIndex,
679 &currentProperty);
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);
688 else
691 * There is no property with the old name
693 return STG_E_FILENOTFOUND;
696 return S_OK;
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(
707 IStorage32* iface,
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
723 if (ppstm == 0)
724 return STG_E_INVALIDPOINTER;
726 if (pwcsName == 0)
727 return STG_E_INVALIDNAME;
730 * Validate the STGM flags
732 if ( FAILED( validateSTGM(grfMode) ))
733 return STG_E_INVALIDFLAG;
736 * As documented.
738 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
739 (grfMode & STGM_DELETEONRELEASE) ||
740 (grfMode & STGM_TRANSACTED) )
741 return STG_E_INVALIDFUNCTION;
744 * Initialize the out parameter
746 *ppstm = 0;
749 * Create a property enumeration to search the properties
751 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
752 This->rootPropertySetIndex);
754 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
755 pwcsName,
756 &currentProperty);
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);
767 else
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,
812 newPropertyIndex,
813 &newStreamProperty);
816 * Find a spot in the property chain for our newly created property.
818 updatePropertyChain(
819 (Storage32Impl*)This,
820 newPropertyIndex,
821 newStreamProperty);
824 * Open the stream to return it.
826 newStream = StgStreamImpl_Construct(This, newPropertyIndex);
828 if (newStream != 0)
830 *ppstm = (IStream32*)newStream;
833 * Since we are returning a pointer to the interface, we have to nail down
834 * the reference.
836 StgStreamImpl_AddRef(*ppstm);
838 else
840 return STG_E_INSUFFICIENTMEMORY;
843 return S_OK;
846 /************************************************************************
847 * Storage32BaseImpl_SetClass (IStorage)
849 * This method will write the specified CLSID in the property of this
850 * storage.
852 * See Windows documentation for more details on IStorage methods.
854 HRESULT WINAPI Storage32BaseImpl_SetClass(
855 IStorage32* iface,
856 REFCLSID clsid) /* [in] */
858 ICOM_THIS(Storage32BaseImpl,iface);
859 HRESULT hRes = E_FAIL;
860 StgProperty curProperty;
861 BOOL32 success;
863 success = Storage32Impl_ReadProperty(This->ancestorStorage,
864 This->rootPropertySetIndex,
865 &curProperty);
866 if (success)
868 curProperty.propertyUniqueID = *clsid;
870 success = Storage32Impl_WriteProperty(This->ancestorStorage,
871 This->rootPropertySetIndex,
872 &curProperty);
873 if (success)
874 hRes = S_OK;
877 return hRes;
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(
892 IStorage32* iface,
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;
906 HRESULT hr;
909 * Validate parameters
911 if (ppstg == 0)
912 return STG_E_INVALIDPOINTER;
914 if (pwcsName == 0)
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
927 *ppstg = 0;
930 * Create a property enumeration and search the properties
932 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
933 This->rootPropertySetIndex);
935 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
936 pwcsName,
937 &currentProperty);
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);
947 else
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,
991 newPropertyIndex,
992 &newProperty);
995 * Find a spot in the property chain for our newly created property.
997 updatePropertyChain(
998 This,
999 newPropertyIndex,
1000 newProperty);
1003 * Open it to get a pointer to return.
1005 hr = Storage32BaseImpl_OpenStorage(
1006 iface,
1007 (OLECHAR32*)pwcsName,
1009 grfMode,
1012 ppstg);
1014 if( (hr != S_OK) || (*ppstg == NULL))
1016 return hr;
1019 return S_OK;
1023 /***************************************************************************
1025 * Internal Method
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,
1044 &currentProperty);
1045 if (readSucessful)
1047 if (currentProperty.sizeOfNameString == 0)
1050 * The property existis and is available, we found it.
1052 newPropertyIndex = currentPropertyIndex;
1055 else
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
1096 * created property
1098 memset(&emptyProperty, 0, sizeof(StgProperty));
1101 * initialize them
1103 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1105 for(
1106 propertyIndex = newPropertyIndex;
1107 propertyIndex < lastProperty;
1108 propertyIndex++)
1110 Storage32Impl_WriteProperty(
1111 storage->ancestorStorage,
1112 propertyIndex,
1113 &emptyProperty);
1117 return newPropertyIndex;
1120 /****************************************************************************
1122 * Internal Method
1124 * Case insensitive comparaison of StgProperty.name by first considering
1125 * their size.
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;
1139 if (diff == 0)
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)));
1153 return diff;
1156 /****************************************************************************
1158 * Internal Method
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,
1174 &currentProperty);
1176 if (currentProperty.dirProperty != PROPERTY_NULL)
1179 * The root storage contains some element, therefore, start the research
1180 * for the appropriate location.
1182 BOOL32 found = 0;
1183 ULONG current, next, previous, currentPropertyId;
1186 * Keep the StgProperty sequence number of the storage first property
1188 currentPropertyId = currentProperty.dirProperty;
1191 * Read
1193 Storage32Impl_ReadProperty(storage->ancestorStorage,
1194 currentProperty.dirProperty,
1195 &currentProperty);
1197 previous = currentProperty.previousProperty;
1198 next = currentProperty.nextProperty;
1199 current = currentPropertyId;
1201 while (found == 0)
1203 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1205 if (diff < 0)
1207 if (previous != PROPERTY_NULL)
1209 Storage32Impl_ReadProperty(storage->ancestorStorage,
1210 previous,
1211 &currentProperty);
1212 current = previous;
1214 else
1216 currentProperty.previousProperty = newPropertyIndex;
1217 Storage32Impl_WriteProperty(storage->ancestorStorage,
1218 current,
1219 &currentProperty);
1220 found = 1;
1223 else
1225 if (next != PROPERTY_NULL)
1227 Storage32Impl_ReadProperty(storage->ancestorStorage,
1228 next,
1229 &currentProperty);
1230 current = next;
1232 else
1234 currentProperty.nextProperty = newPropertyIndex;
1235 Storage32Impl_WriteProperty(storage->ancestorStorage,
1236 current,
1237 &currentProperty);
1238 found = 1;
1242 previous = currentProperty.previousProperty;
1243 next = currentProperty.nextProperty;
1246 else
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,
1254 &currentProperty);
1259 /*************************************************************************
1260 * CopyTo (IStorage)
1262 HRESULT WINAPI Storage32Impl_CopyTo(
1263 IStorage32* iface,
1264 DWORD ciidExclude, /* [in] */
1265 const IID *rgiidExclude,/* [size_is][unique][in] */
1266 SNB32 snbExclude, /* [unique][in] */
1267 IStorage32 *pstgDest) /* [unique][in] */
1269 return E_NOTIMPL;
1272 /*************************************************************************
1273 * MoveElementTo (IStorage)
1275 HRESULT WINAPI Storage32Impl_MoveElementTo(
1276 IStorage32* iface,
1277 const OLECHAR32 *pwcsName, /* [string][in] */
1278 IStorage32 *pstgDest, /* [unique][in] */
1279 const OLECHAR32 *pwcsNewName,/* [string][in] */
1280 DWORD grfFlags) /* [in] */
1282 return E_NOTIMPL;
1285 /*************************************************************************
1286 * Commit (IStorage)
1288 HRESULT WINAPI Storage32Impl_Commit(
1289 IStorage32* iface,
1290 DWORD grfCommitFlags)/* [in] */
1292 FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1293 return S_OK;
1296 /*************************************************************************
1297 * Revert (IStorage)
1299 HRESULT WINAPI Storage32Impl_Revert(
1300 IStorage32* iface)
1302 return E_NOTIMPL;
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(
1317 IStorage32* iface,
1318 const OLECHAR32 *pwcsName)/* [string][in] */
1320 Storage32Impl* const This=(Storage32Impl*)iface;
1322 IEnumSTATSTGImpl* propertyEnumeration;
1323 HRESULT hr = S_OK;
1324 BOOL32 res;
1325 StgProperty propertyToDelete;
1326 StgProperty parentProperty;
1327 ULONG foundPropertyIndexToDelete;
1328 ULONG typeOfRelation;
1329 ULONG parentPropertyId;
1332 * Perform a sanity check on the parameters.
1334 if (pwcsName==NULL)
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,
1346 pwcsName,
1347 &propertyToDelete);
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,
1368 &parentProperty);
1370 assert(res==TRUE);
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;
1384 else
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,
1399 &parentProperty,
1400 &parentPropertyId);
1402 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1405 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1407 hr = deleteStorageProperty(
1408 This,
1409 propertyToDelete.name);
1411 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1413 hr = deleteStreamProperty(
1414 This,
1415 foundPropertyIndexToDelete,
1416 propertyToDelete);
1419 if (hr!=S_OK)
1420 return hr;
1423 * Adjust the property chain
1425 hr = adjustPropertyChain(
1426 This,
1427 propertyToDelete,
1428 parentProperty,
1429 parentPropertyId,
1430 typeOfRelation);
1432 return hr;
1436 /*********************************************************************
1438 * Internal Method
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;
1450 HRESULT hr;
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,
1463 &childStorage);
1465 if (hr != S_OK)
1467 return hr;
1471 * Enumerate the elements
1473 IStorage32_EnumElements( childStorage, 0, 0, 0, &elements);
1478 * Obtain the next element
1480 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1481 if (hr==S_OK)
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);
1501 return destroyHr;
1504 /*********************************************************************
1506 * Internal Method
1508 * Perform the deletion of a stream node
1511 static HRESULT deleteStreamProperty(
1512 Storage32Impl *parentStorage,
1513 ULONG indexOfPropertyToDelete,
1514 StgProperty propertyToDelete)
1516 IStream32 *pis;
1517 HRESULT hr;
1518 ULARGE_INTEGER size;
1520 size.HighPart = 0;
1521 size.LowPart = 0;
1523 hr = Storage32BaseImpl_OpenStream(
1524 (IStorage32*)parentStorage,
1525 (OLECHAR32*)propertyToDelete.name,
1526 NULL,
1527 STGM_SHARE_EXCLUSIVE,
1529 &pis);
1531 if (hr!=S_OK)
1533 return(hr);
1537 * Zap the stream
1539 hr = IStream32_SetSize(pis, size);
1541 if(hr != S_OK)
1543 return hr;
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,
1559 &propertyToDelete);
1561 return S_OK;
1564 /*********************************************************************
1566 * Internal Method
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;
1578 HRESULT hr = S_OK;
1579 BOOL32 res = TRUE;
1582 * Read the storage property
1584 res = Storage32Impl_ReadProperty(
1585 storage->ancestorStorage,
1586 storePropertyIndex,
1587 &storeProperty);
1589 if(! res)
1591 return E_FAIL;
1594 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1596 if (storeProperty.previousProperty != PROPERTY_NULL)
1598 return findPlaceholder(
1599 storage,
1600 propertyIndexToStore,
1601 storeProperty.previousProperty,
1602 typeOfRelation);
1604 else
1606 storeProperty.previousProperty = propertyIndexToStore;
1609 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1611 if (storeProperty.nextProperty != PROPERTY_NULL)
1613 return findPlaceholder(
1614 storage,
1615 propertyIndexToStore,
1616 storeProperty.nextProperty,
1617 typeOfRelation);
1619 else
1621 storeProperty.nextProperty = propertyIndexToStore;
1624 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1626 if (storeProperty.dirProperty != PROPERTY_NULL)
1628 return findPlaceholder(
1629 storage,
1630 propertyIndexToStore,
1631 storeProperty.dirProperty,
1632 typeOfRelation);
1634 else
1636 storeProperty.dirProperty = propertyIndexToStore;
1640 hr = Storage32Impl_WriteProperty(
1641 storage->ancestorStorage,
1642 storePropertyIndex,
1643 &storeProperty);
1645 if(! hr)
1647 return E_FAIL;
1650 return S_OK;
1653 /*************************************************************************
1655 * Internal Method
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;
1672 HRESULT hr = S_OK;
1673 BOOL32 res = TRUE;
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,
1784 parentPropertyId,
1785 &parentProperty);
1786 if(! res)
1788 return E_FAIL;
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(
1798 This,
1799 toStoreNode,
1800 storeNode,
1801 relationType);
1804 return hr;
1808 /******************************************************************************
1809 * SetElementTimes (IStorage)
1811 HRESULT WINAPI Storage32Impl_SetElementTimes(
1812 IStorage32* iface,
1813 const OLECHAR32 *pwcsName,/* [string][in] */
1814 const FILETIME *pctime, /* [in] */
1815 const FILETIME *patime, /* [in] */
1816 const FILETIME *pmtime) /* [in] */
1818 return E_NOTIMPL;
1821 /******************************************************************************
1822 * SetStateBits (IStorage)
1824 HRESULT WINAPI Storage32Impl_SetStateBits(
1825 IStorage32* iface,
1826 DWORD grfStateBits,/* [in] */
1827 DWORD grfMask) /* [in] */
1829 return E_NOTIMPL;
1832 HRESULT Storage32Impl_Construct(
1833 Storage32Impl* This,
1834 HANDLE32 hFile,
1835 DWORD openFlags)
1837 HRESULT hr = S_OK;
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
1855 * to this.
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,
1870 openFlags,
1871 This->bigBlockSize);
1873 if (This->bigBlockFile == 0)
1874 return E_FAIL;
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,
1888 BLOCK_UNUSED,
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
1905 size.HighPart = 0;
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);
1918 else
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(
1938 This,
1939 &This->smallBlockDepotStart,
1940 PROPERTY_NULL);
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(
1974 This,
1975 currentPropertyIndex,
1976 &currentProperty);
1978 if (readSucessful)
1980 if ( (currentProperty.sizeOfNameString != 0 ) &&
1981 (currentProperty.propertyType == PROPTYPE_ROOT) )
1983 This->rootPropertySetIndex = currentPropertyIndex;
1987 currentPropertyIndex++;
1989 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1991 if (!readSucessful)
1993 /* TODO CLEANUP */
1994 return E_FAIL;
1998 * Create the block chain abstraction for the small block root chain.
2000 This->smallBlockRootChain = BlockChainStream_Construct(
2001 This,
2002 NULL,
2003 This->rootPropertySetIndex);
2005 return hr;
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);
2016 return;
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;
2030 void *depotBuffer;
2031 ULONG depotBlockOffset;
2032 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2033 ULONG nextBlockIndex = BLOCK_SPECIAL;
2034 int depotIndex = 0;
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,
2064 depotBlockIndexPos,
2065 BLOCK_SPECIAL);
2067 /* Save new header information.
2069 Storage32Impl_SaveFileHeader(This);
2072 else
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;
2093 else
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,
2106 depotBlockIndexPos,
2107 BLOCK_SPECIAL);
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);
2140 depotIndex++;
2143 return blockNoInSequence;
2146 /******************************************************************************
2147 * Storage32Impl_AddBlockDepot
2149 * This will create a depot block, essentially it is a block initialized
2150 * to BLOCK_UNUSEDs.
2152 void Storage32Impl_AddBlockDepot(Storage32Impl* This, ULONG blockIndex)
2154 BYTE* blockBuffer;
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);
2190 extBlockCount--;
2193 if (extBlockIndex != BLOCK_UNUSED)
2195 BYTE* depotBuffer;
2197 depotBuffer = Storage32Impl_GetROBigBlock(This, extBlockIndex);
2199 if (depotBuffer != 0)
2201 StorageUtl_ReadDWord(depotBuffer,
2202 extBlockOffset * sizeof(ULONG),
2203 &blockIndex);
2205 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2209 return blockIndex;
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,
2220 ULONG depotIndex,
2221 ULONG blockIndex)
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);
2234 extBlockCount--;
2237 if (extBlockIndex != BLOCK_UNUSED)
2239 BYTE* depotBuffer;
2241 depotBuffer = Storage32Impl_GetBigBlock(This, extBlockIndex);
2243 if (depotBuffer != 0)
2245 StorageUtl_WriteDWord(depotBuffer,
2246 extBlockOffset * sizeof(ULONG),
2247 blockIndex);
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;
2279 else
2281 int i;
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);
2305 return index;
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,
2315 ULONG blockIndex)
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
2324 * in the chain.
2326 * Params: This - Pointer to the Storage object.
2327 * blockIndex - Index of the block to retrieve the chain
2328 * for.
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
2333 * chain.
2334 * BLOCK_END_OF_CHAIN - If the block given was the last in
2335 * a chain.
2336 * BLOCK_UNUSED - If the block given was not past of a chain
2337 * and is available.
2338 * BLOCK_EXTBBDEPOT - This block is part of the extended
2339 * big block depot.
2341 * See Windows documentation for more details on IStorage methods.
2343 ULONG Storage32Impl_GetNextBlockInChain(
2344 Storage32Impl* This,
2345 ULONG blockIndex)
2347 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2348 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2349 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2350 ULONG nextBlockIndex = BLOCK_SPECIAL;
2351 void* depotBuffer;
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];
2367 else
2370 * We have to look in the extended depot.
2372 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2375 depotBuffer = Storage32Impl_GetROBigBlock(This, depotBlockIndexPos);
2377 if (depotBuffer!=0)
2379 int index;
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.
2401 * NOTES:
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
2404 * depot.
2406 * Return values:
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);
2415 void* depotBuffer;
2417 depotBuffer = Storage32Impl_GetROBigBlock(This, blockIndex);
2419 if (depotBuffer!=0)
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
2436 * do the following
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,
2445 ULONG blockIndex,
2446 ULONG nextBlock)
2448 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2449 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2450 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2451 ULONG depotBlockIndexPos;
2452 void* depotBuffer;
2454 assert(depotBlockCount < This->bigBlockDepotCount);
2456 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2458 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2460 else
2463 * We have to look in the extended depot.
2465 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2468 depotBuffer = Storage32Impl_GetBigBlock(This, depotBlockIndexPos);
2470 if (depotBuffer!=0)
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;
2495 int index;
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
2509 * found.
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(
2524 headerBigBlock,
2525 OFFSET_BIGBLOCKSIZEBITS,
2526 &This->bigBlockSizeBits);
2528 StorageUtl_ReadWord(
2529 headerBigBlock,
2530 OFFSET_SMALLBLOCKSIZEBITS,
2531 &This->smallBlockSizeBits);
2533 StorageUtl_ReadDWord(
2534 headerBigBlock,
2535 OFFSET_BBDEPOTCOUNT,
2536 &This->bigBlockDepotCount);
2538 StorageUtl_ReadDWord(
2539 headerBigBlock,
2540 OFFSET_ROOTSTARTBLOCK,
2541 &This->rootStartBlock);
2543 StorageUtl_ReadDWord(
2544 headerBigBlock,
2545 OFFSET_SBDEPOTSTART,
2546 &This->smallBlockDepotStart);
2548 StorageUtl_ReadDWord(
2549 headerBigBlock,
2550 OFFSET_EXTBBDEPOTSTART,
2551 &This->extBigBlockDepotStart);
2553 StorageUtl_ReadDWord(
2554 headerBigBlock,
2555 OFFSET_EXTBBDEPOTCOUNT,
2556 &This->extBigBlockDepotCount);
2558 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2560 StorageUtl_ReadDWord(
2561 headerBigBlock,
2562 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2563 &(This->bigBlockDepotStart[index]));
2567 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2569 if ((1 << 2) == 4)
2571 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2572 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2574 else
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);
2593 return hr;
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];
2605 int index;
2606 BOOL32 success;
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.
2616 if (!success)
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(
2644 headerBigBlock,
2645 OFFSET_BIGBLOCKSIZEBITS,
2646 This->bigBlockSizeBits);
2648 StorageUtl_WriteWord(
2649 headerBigBlock,
2650 OFFSET_SMALLBLOCKSIZEBITS,
2651 This->smallBlockSizeBits);
2653 StorageUtl_WriteDWord(
2654 headerBigBlock,
2655 OFFSET_BBDEPOTCOUNT,
2656 This->bigBlockDepotCount);
2658 StorageUtl_WriteDWord(
2659 headerBigBlock,
2660 OFFSET_ROOTSTARTBLOCK,
2661 This->rootStartBlock);
2663 StorageUtl_WriteDWord(
2664 headerBigBlock,
2665 OFFSET_SBDEPOTSTART,
2666 This->smallBlockDepotStart);
2668 StorageUtl_WriteDWord(
2669 headerBigBlock,
2670 OFFSET_EXTBBDEPOTSTART,
2671 This->extBigBlockDepotStart);
2673 StorageUtl_WriteDWord(
2674 headerBigBlock,
2675 OFFSET_EXTBBDEPOTCOUNT,
2676 This->extBigBlockDepotCount);
2678 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2680 StorageUtl_WriteDWord(
2681 headerBigBlock,
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,
2700 ULONG index,
2701 StgProperty* buffer)
2703 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2704 ULARGE_INTEGER offsetInPropSet;
2705 BOOL32 readSucessful;
2706 ULONG bytesRead;
2708 offsetInPropSet.HighPart = 0;
2709 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2711 readSucessful = BlockChainStream_ReadAt(
2712 This->rootBlockChain,
2713 offsetInPropSet,
2714 PROPSET_BLOCK_SIZE,
2715 currentProperty,
2716 &bytesRead);
2718 if (readSucessful)
2720 memset(buffer->name, 0, sizeof(buffer->name));
2721 memcpy(
2722 buffer->name,
2723 currentProperty+OFFSET_PS_NAME,
2724 PROPERTY_NAME_BUFFER_LEN );
2726 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2728 StorageUtl_ReadWord(
2729 currentProperty,
2730 OFFSET_PS_NAMELENGTH,
2731 &buffer->sizeOfNameString);
2733 StorageUtl_ReadDWord(
2734 currentProperty,
2735 OFFSET_PS_PREVIOUSPROP,
2736 &buffer->previousProperty);
2738 StorageUtl_ReadDWord(
2739 currentProperty,
2740 OFFSET_PS_NEXTPROP,
2741 &buffer->nextProperty);
2743 StorageUtl_ReadDWord(
2744 currentProperty,
2745 OFFSET_PS_DIRPROP,
2746 &buffer->dirProperty);
2748 StorageUtl_ReadGUID(
2749 currentProperty,
2750 OFFSET_PS_GUID,
2751 &buffer->propertyUniqueID);
2753 StorageUtl_ReadDWord(
2754 currentProperty,
2755 OFFSET_PS_TSS1,
2756 &buffer->timeStampS1);
2758 StorageUtl_ReadDWord(
2759 currentProperty,
2760 OFFSET_PS_TSD1,
2761 &buffer->timeStampD1);
2763 StorageUtl_ReadDWord(
2764 currentProperty,
2765 OFFSET_PS_TSS2,
2766 &buffer->timeStampS2);
2768 StorageUtl_ReadDWord(
2769 currentProperty,
2770 OFFSET_PS_TSD2,
2771 &buffer->timeStampD2);
2773 StorageUtl_ReadDWord(
2774 currentProperty,
2775 OFFSET_PS_STARTBLOCK,
2776 &buffer->startingBlock);
2778 StorageUtl_ReadDWord(
2779 currentProperty,
2780 OFFSET_PS_SIZE,
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,
2794 ULONG index,
2795 StgProperty* buffer)
2797 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2798 ULARGE_INTEGER offsetInPropSet;
2799 BOOL32 writeSucessful;
2800 ULONG bytesWritten;
2802 offsetInPropSet.HighPart = 0;
2803 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2805 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2807 memcpy(
2808 currentProperty + OFFSET_PS_NAME,
2809 buffer->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(
2820 currentProperty,
2821 OFFSET_PS_NAMELENGTH,
2822 buffer->sizeOfNameString);
2824 StorageUtl_WriteDWord(
2825 currentProperty,
2826 OFFSET_PS_PREVIOUSPROP,
2827 buffer->previousProperty);
2829 StorageUtl_WriteDWord(
2830 currentProperty,
2831 OFFSET_PS_NEXTPROP,
2832 buffer->nextProperty);
2834 StorageUtl_WriteDWord(
2835 currentProperty,
2836 OFFSET_PS_DIRPROP,
2837 buffer->dirProperty);
2839 StorageUtl_WriteGUID(
2840 currentProperty,
2841 OFFSET_PS_GUID,
2842 &buffer->propertyUniqueID);
2844 StorageUtl_WriteDWord(
2845 currentProperty,
2846 OFFSET_PS_TSS1,
2847 buffer->timeStampS1);
2849 StorageUtl_WriteDWord(
2850 currentProperty,
2851 OFFSET_PS_TSD1,
2852 buffer->timeStampD1);
2854 StorageUtl_WriteDWord(
2855 currentProperty,
2856 OFFSET_PS_TSS2,
2857 buffer->timeStampS2);
2859 StorageUtl_WriteDWord(
2860 currentProperty,
2861 OFFSET_PS_TSD2,
2862 buffer->timeStampD2);
2864 StorageUtl_WriteDWord(
2865 currentProperty,
2866 OFFSET_PS_STARTBLOCK,
2867 buffer->startingBlock);
2869 StorageUtl_WriteDWord(
2870 currentProperty,
2871 OFFSET_PS_SIZE,
2872 buffer->size.LowPart);
2874 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2875 offsetInPropSet,
2876 PROPSET_BLOCK_SIZE,
2877 currentProperty,
2878 &bytesWritten);
2879 return writeSucessful;
2882 BOOL32 Storage32Impl_ReadBigBlock(
2883 Storage32Impl* This,
2884 ULONG blockIndex,
2885 void* buffer)
2887 void* bigBlockBuffer;
2889 bigBlockBuffer = Storage32Impl_GetROBigBlock(This, blockIndex);
2891 if (bigBlockBuffer!=0)
2893 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2895 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2897 return TRUE;
2900 return FALSE;
2903 BOOL32 Storage32Impl_WriteBigBlock(
2904 Storage32Impl* This,
2905 ULONG blockIndex,
2906 void* buffer)
2908 void* bigBlockBuffer;
2910 bigBlockBuffer = Storage32Impl_GetBigBlock(This, blockIndex);
2912 if (bigBlockBuffer!=0)
2914 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2916 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2918 return TRUE;
2921 return FALSE;
2924 void* Storage32Impl_GetROBigBlock(
2925 Storage32Impl* This,
2926 ULONG blockIndex)
2928 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2931 void* Storage32Impl_GetBigBlock(
2932 Storage32Impl* This,
2933 ULONG blockIndex)
2935 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2938 void Storage32Impl_ReleaseBigBlock(
2939 Storage32Impl* This,
2940 void* pBigBlock)
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,
2971 &bbHeadOfChain,
2972 PROPERTY_NULL);
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.
2984 offset.LowPart = 0;
2985 offset.HighPart = 0;
2986 cbTotalRead = 0;
2987 cbTotalWritten = 0;
2991 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
2992 offset,
2993 sizeof(buffer),
2994 buffer,
2995 &cbRead);
2996 cbTotalRead += cbRead;
2998 successWrite = BlockChainStream_WriteAt(bbTempChain,
2999 offset,
3000 cbRead,
3001 buffer,
3002 &cbWritten);
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;
3015 size.HighPart = 0;
3016 size.LowPart = 0;
3017 SmallBlockChainStream_SetSize(*ppsbChain, size);
3018 SmallBlockChainStream_Destroy(*ppsbChain);
3019 *ppsbChain = 0;
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,
3037 NULL,
3038 propertyIndex);
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));
3058 if (newStorage!=0)
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;
3079 return newStorage;
3082 return 0;
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
3096 ** does nothing.
3098 HRESULT WINAPI Storage32InternalImpl_Commit(
3099 IStorage32* iface,
3100 DWORD grfCommitFlags) /* [in] */
3102 return S_OK;
3105 /******************************************************************************
3107 ** Storage32InternalImpl_Revert
3109 ** The non-root storages cannot be opened in transacted mode thus this function
3110 ** does nothing.
3112 HRESULT WINAPI Storage32InternalImpl_Revert(
3113 IStorage32* iface)
3115 return S_OK;
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,
3173 REFIID riid,
3174 void** ppvObject)
3176 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3179 * Perform a sanity check on the parameters.
3181 if (ppvObject==0)
3182 return E_INVALIDARG;
3185 * Initialize the return parameter.
3187 *ppvObject = 0;
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
3209 * successful
3211 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3213 return S_OK;
3216 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3217 IEnumSTATSTG* iface)
3219 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3221 This->ref++;
3222 return This->ref;
3225 ULONG WINAPI IEnumSTATSTGImpl_Release(
3226 IEnumSTATSTG* iface)
3228 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3230 ULONG newRef;
3232 This->ref--;
3233 newRef = This->ref;
3236 * If the reference count goes down to 0, perform suicide.
3238 if (newRef==0)
3240 IEnumSTATSTGImpl_Destroy(This);
3243 return newRef;;
3246 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3247 IEnumSTATSTG* iface,
3248 ULONG celt,
3249 STATSTG* rgelt,
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
3276 *pceltFetched = 0;
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,
3295 currentSearchNode,
3296 &currentProperty);
3299 * Copy the information to the return buffer.
3301 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3302 &currentProperty,
3303 STATFLAG_DEFAULT);
3306 * Step to the next item in the iteration
3308 (*pceltFetched)++;
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)
3323 return S_OK;
3325 return S_FALSE;
3329 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3330 IEnumSTATSTG* iface,
3331 ULONG celt)
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,
3356 currentSearchNode,
3357 &currentProperty);
3360 * Step to the next item in the iteration
3362 objectFetched++;
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)
3376 return S_OK;
3378 return S_FALSE;
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,
3400 &rootProperty);
3402 if (readSucessful)
3404 assert(rootProperty.sizeOfNameString!=0);
3407 * Push the search node in the search stack.
3409 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3412 return S_OK;
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.
3426 if (ppenum==0)
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
3435 * the ole one.
3437 newClone->stackSize = This->stackSize ;
3438 newClone->stackMaxSize = This->stackMaxSize ;
3439 newClone->stackToVisit =
3440 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3442 memcpy(
3443 newClone->stackToVisit,
3444 This->stackToVisit,
3445 sizeof(ULONG) * newClone->stackSize);
3447 *ppenum = (IEnumSTATSTG*)newClone;
3450 * Don't forget to nail down a reference to the clone before
3451 * returning it.
3453 IEnumSTATSTGImpl_AddRef(*ppenum);
3455 return S_OK;
3458 INT32 IEnumSTATSTGImpl_FindParentProperty(
3459 IEnumSTATSTGImpl *This,
3460 ULONG childProperty,
3461 StgProperty *currentProperty,
3462 ULONG *thisNodeId)
3464 ULONG currentSearchNode;
3465 ULONG foundNode;
3468 * To avoid the special case, get another pointer to a ULONG value if
3469 * the caller didn't supply one.
3471 if (thisNodeId==0)
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,
3497 currentSearchNode,
3498 currentProperty);
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,
3546 currentSearchNode,
3547 currentProperty);
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,
3570 ULONG nodeToPush)
3572 StgProperty rootProperty;
3573 BOOL32 readSucessful;
3576 * First, make sure we're not trying to push an unexisting node.
3578 if (nodeToPush==PROPERTY_NULL)
3579 return;
3582 * First push the node to the stack
3584 if (This->stackSize == This->stackMaxSize)
3586 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3588 This->stackToVisit = HeapReAlloc(
3589 GetProcessHeap(),
3591 This->stackToVisit,
3592 sizeof(ULONG) * This->stackMaxSize);
3595 This->stackToVisit[This->stackSize] = nodeToPush;
3596 This->stackSize++;
3599 * Read the root property from the storage.
3601 readSucessful = Storage32Impl_ReadProperty(
3602 This->parentStorage,
3603 nodeToPush,
3604 &rootProperty);
3606 if (readSucessful)
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,
3619 BOOL32 remove)
3621 ULONG topNode;
3623 if (This->stackSize == 0)
3624 return PROPERTY_NULL;
3626 topNode = This->stackToVisit[This->stackSize-1];
3628 if (remove)
3629 This->stackSize--;
3631 return topNode;
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,
3679 int statFlags)
3682 * The copy of the string occurs only when the flag is not set
3684 if ((statFlags & STATFLAG_NONAME) != 0)
3686 destination->pwcsName = 0;
3688 else
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:
3699 case PROPTYPE_ROOT:
3700 destination->type = STGTY_STORAGE;
3701 break;
3702 case PROPTYPE_STREAM:
3703 destination->type = STGTY_STREAM;
3704 break;
3705 default:
3706 destination->type = STGTY_STREAM;
3707 break;
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;
3740 return newStream;
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,
3769 &chainProperty);
3771 if (readSucessful)
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)
3789 ULONG blockIndex;
3790 ULONG count = 0;
3792 blockIndex = BlockChainStream_GetHeadOfChain(This);
3794 while (blockIndex != BLOCK_END_OF_CHAIN)
3796 count++;
3798 blockIndex = Storage32Impl_GetNextBlockInChain(
3799 This->parentStorage,
3800 blockIndex);
3803 return count;
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,
3815 ULONG size,
3816 void* buffer,
3817 ULONG* bytesRead)
3819 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3820 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3821 ULONG bytesToReadInBuffer;
3822 ULONG blockIndex;
3823 BYTE* bufferWalker;
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))
3833 blockIndex =
3834 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3836 blockNoInSequence--;
3840 * Start reading the buffer.
3842 *bytesRead = 0;
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
3856 bigBlockBuffer =
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.
3866 blockIndex =
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 */
3876 return (size == 0);
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,
3888 ULONG size,
3889 const void* buffer,
3890 ULONG* bytesWritten)
3892 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3893 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3894 ULONG bytesToWrite;
3895 ULONG blockIndex;
3896 BYTE* bufferWalker;
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))
3906 blockIndex =
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.
3916 *bytesWritten = 0;
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.
3924 bytesToWrite =
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.
3939 blockIndex =
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 */
3948 return (size == 0);
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;
3960 ULONG numBlocks;
3961 ULONG count = 1;
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)
3969 numBlocks++;
3971 blockIndex = BlockChainStream_GetHeadOfChain(This);
3974 * Go to the new end of chain
3976 while (count < numBlocks)
3978 blockIndex =
3979 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3981 count++;
3984 /* Get the next block before marking the new end */
3985 extraBlock =
3986 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3988 /* Mark the new end of chain */
3989 Storage32Impl_SetNextBlockInChain(
3990 This->parentStorage,
3991 blockIndex,
3992 BLOCK_END_OF_CHAIN);
3995 * Mark the extra blocks as free
3997 while (extraBlock != BLOCK_END_OF_CHAIN)
3999 blockIndex =
4000 Storage32Impl_GetNextBlockInChain(This->parentStorage, extraBlock);
4002 Storage32Impl_FreeBigBlock(This->parentStorage, extraBlock);
4003 extraBlock = blockIndex;
4006 return TRUE;
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;
4018 ULONG newNumBlocks;
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,
4030 blockIndex,
4031 BLOCK_END_OF_CHAIN);
4033 if (This->headOfStreamPlaceHolder != 0)
4035 *(This->headOfStreamPlaceHolder) = blockIndex;
4037 else
4039 StgProperty chainProp;
4040 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4042 Storage32Impl_ReadProperty(
4043 This->parentStorage,
4044 This->ownerPropertyIndex,
4045 &chainProp);
4047 chainProp.startingBlock = blockIndex;
4049 Storage32Impl_WriteProperty(
4050 This->parentStorage,
4051 This->ownerPropertyIndex,
4052 &chainProp);
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)
4064 newNumBlocks++;
4067 * Go to the current end of chain
4069 while (blockIndex != BLOCK_END_OF_CHAIN)
4071 oldNumBlocks++;
4072 currentBlock = blockIndex;
4074 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,
4087 currentBlock,
4088 blockIndex);
4090 Storage32Impl_SetNextBlockInChain(
4091 This->parentStorage,
4092 blockIndex,
4093 BLOCK_END_OF_CHAIN);
4095 currentBlock = blockIndex;
4096 oldNumBlocks++;
4099 return TRUE;
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)
4119 return TRUE;
4121 if (newSize.LowPart < size.LowPart)
4123 BlockChainStream_Shrink(This, newSize);
4125 else
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);
4145 return TRUE;
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,
4167 &chainProperty);
4169 return chainProperty.size;
4171 else
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
4176 * size of them
4178 ULARGE_INTEGER result;
4179 result.HighPart = 0;
4181 result.LowPart =
4182 BlockChainStream_GetCount(This) *
4183 This->parentStorage->bigBlockSize;
4185 return result;
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;
4204 return newStream;
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,
4229 &chainProperty);
4231 if (readSucessful)
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.
4246 * Return Values:
4247 * - BLOCK_END_OF_CHAIN: end of this chain
4248 * - BLOCK_UNUSED: small block 'blockIndex' is free
4250 ULONG SmallBlockChainStream_GetNextBlockInChain(
4251 SmallBlockChainStream* This,
4252 ULONG blockIndex)
4254 ULARGE_INTEGER offsetOfBlockInDepot;
4255 DWORD buffer;
4256 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4257 ULONG bytesRead;
4258 BOOL32 success;
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,
4269 sizeof(DWORD),
4270 &buffer,
4271 &bytesRead);
4273 if (success)
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
4285 * block depot.
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,
4291 ULONG blockIndex,
4292 ULONG nextBlock)
4294 ULARGE_INTEGER offsetOfBlockInDepot;
4295 DWORD buffer;
4296 ULONG bytesWritten;
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,
4309 sizeof(DWORD),
4310 &buffer,
4311 &bytesWritten);
4314 /******************************************************************************
4315 * SmallBlockChainStream_FreeBlock
4317 * Flag small block 'blockIndex' as free in the small block depot.
4319 void SmallBlockChainStream_FreeBlock(
4320 SmallBlockChainStream* This,
4321 ULONG blockIndex)
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
4331 * necessary.
4333 ULONG SmallBlockChainStream_GetNextFreeBlock(
4334 SmallBlockChainStream* This)
4336 ULARGE_INTEGER offsetOfBlockInDepot;
4337 DWORD buffer;
4338 ULONG bytesRead;
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,
4356 sizeof(DWORD),
4357 &buffer,
4358 &bytesRead);
4361 * If we run out of space for the small block depot, enlarge it
4363 if (success)
4365 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4367 if (nextBlockIndex != BLOCK_UNUSED)
4368 blockIndex++;
4370 else
4372 ULONG count =
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;
4383 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,
4391 sbdIndex,
4392 newsbdIndex);
4394 Storage32Impl_SetNextBlockInChain(
4395 This->parentStorage,
4396 newsbdIndex,
4397 BLOCK_END_OF_CHAIN);
4400 * Initialize all the small blocks to free
4402 smallBlockDepot =
4403 Storage32Impl_GetBigBlock(This->parentStorage, newsbdIndex);
4405 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4406 Storage32Impl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4408 if (count == 0)
4411 * We have just created the small block depot.
4413 StgProperty rootProp;
4414 ULONG sbStartIndex;
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
4425 sbStartIndex =
4426 Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
4428 Storage32Impl_SetNextBlockInChain(
4429 This->parentStorage,
4430 sbStartIndex,
4431 BLOCK_END_OF_CHAIN);
4433 Storage32Impl_ReadProperty(
4434 This->parentStorage,
4435 This->parentStorage->rootPropertySetIndex,
4436 &rootProp);
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,
4445 &rootProp);
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,
4464 &rootProp);
4466 if (rootProp.size.LowPart <
4467 (blocksRequired * This->parentStorage->bigBlockSize))
4469 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4471 BlockChainStream_SetSize(
4472 This->parentStorage->smallBlockRootChain,
4473 rootProp.size);
4475 Storage32Impl_WriteProperty(
4476 This->parentStorage,
4477 This->parentStorage->rootPropertySetIndex,
4478 &rootProp);
4482 return blockIndex;
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,
4495 ULONG size,
4496 void* buffer,
4497 ULONG* bytesRead)
4499 ULARGE_INTEGER offsetInBigBlockFile;
4500 ULONG blockNoInSequence =
4501 offset.LowPart / This->parentStorage->smallBlockSize;
4503 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4504 ULONG bytesToReadInBuffer;
4505 ULONG blockIndex;
4506 ULONG bytesReadFromBigBlockFile;
4507 BYTE* bufferWalker;
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.
4529 *bytesRead = 0;
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,
4555 bufferWalker,
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 */
4570 return (size == 0);
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,
4583 ULONG size,
4584 const void* buffer,
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;
4593 ULONG blockIndex;
4594 ULONG bytesWrittenFromBigBlockFile;
4595 BYTE* bufferWalker;
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.
4620 *bytesWritten = 0;
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,
4645 bufferWalker,
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 */
4660 return (size == 0);
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;
4673 ULONG numBlocks;
4674 ULONG count = 1;
4676 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4678 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4679 numBlocks++;
4681 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4684 * Go to the new end of chain
4686 while (count < numBlocks)
4688 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4689 count++;
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(
4697 This,
4698 blockIndex,
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;
4711 return TRUE;
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;
4724 ULONG newNumBlocks;
4725 ULONG oldNumBlocks = 0;
4727 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4730 * Empty chain
4732 if (blockIndex == BLOCK_END_OF_CHAIN)
4734 StgProperty chainProp;
4736 Storage32Impl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4737 &chainProp);
4739 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4741 Storage32Impl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4742 &chainProp);
4744 blockIndex = chainProp.startingBlock;
4745 SmallBlockChainStream_SetNextBlockInChain(
4746 This,
4747 blockIndex,
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)
4759 newNumBlocks++;
4762 * Go to the current end of chain
4764 while (blockIndex != BLOCK_END_OF_CHAIN)
4766 oldNumBlocks++;
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(
4780 This,
4781 blockIndex,
4782 BLOCK_END_OF_CHAIN);
4784 currentBlock = blockIndex;
4785 oldNumBlocks++;
4788 return TRUE;
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)
4799 ULONG blockIndex;
4800 ULONG count = 0;
4802 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4804 while (blockIndex != BLOCK_END_OF_CHAIN)
4806 count++;
4808 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4811 return count;
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)
4831 return TRUE;
4833 if (newSize.LowPart < size.LowPart)
4835 SmallBlockChainStream_Shrink(This, newSize);
4837 else
4839 SmallBlockChainStream_Enlarge(This, newSize);
4842 return TRUE;
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,
4857 &chainProperty);
4859 return chainProperty.size;
4862 /******************************************************************************
4863 * StgCreateDocfile32 [OLE32.144]
4864 * TODO Validate grfMode (STGM)
4866 HRESULT WINAPI StgCreateDocfile32(
4867 LPCOLESTR32 pwcsName,
4868 DWORD grfMode,
4869 DWORD reserved,
4870 IStorage32 **ppstgOpen)
4872 Storage32Impl* newStorage = 0;
4873 HANDLE32 hFile = INVALID_HANDLE_VALUE32;
4874 HRESULT hr = S_OK;
4875 DWORD shareMode;
4876 DWORD accessMode;
4877 DWORD creationMode;
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;
4901 else
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.
4910 *ppstgOpen = 0;
4912 hFile = CreateFile32W(pwcsName,
4913 accessMode,
4914 shareMode,
4915 NULL,
4916 creationMode,
4917 fileAttributes,
4920 if (hFile == INVALID_HANDLE_VALUE32)
4922 return E_FAIL;
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(
4934 newStorage,
4935 hFile,
4936 grfMode);
4938 if (FAILED(hr))
4939 return hr;
4942 * Get an "out" pointer for the caller.
4944 hr = Storage32BaseImpl_QueryInterface(
4945 (IStorage32*)newStorage,
4946 (REFIID)&IID_IStorage,
4947 (void**)ppstgOpen);
4949 return hr;
4952 /******************************************************************************
4953 * StgOpenStorage32 [OLE32.148]
4955 HRESULT WINAPI StgOpenStorage32(
4956 const OLECHAR32 *pwcsName,
4957 IStorage32 *pstgPriority,
4958 DWORD grfMode,
4959 SNB32 snbExclude,
4960 DWORD reserved,
4961 IStorage32 **ppstgOpen)
4963 Storage32Impl* newStorage = 0;
4964 HRESULT hr = S_OK;
4965 HANDLE32 hFile = 0;
4966 DWORD shareMode;
4967 DWORD accessMode;
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.
4990 *ppstgOpen = 0;
4992 hFile = CreateFile32W( pwcsName,
4993 accessMode,
4994 shareMode,
4995 NULL,
4996 OPEN_EXISTING,
4997 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5001 if (hFile==INVALID_HANDLE_VALUE32)
5003 return E_FAIL;
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(
5015 newStorage,
5016 hFile,
5017 grfMode);
5019 if (FAILED(hr))
5020 return hr;
5023 * Get an "out" pointer for the caller.
5025 hr = Storage32BaseImpl_QueryInterface(
5026 (IStorage32*)newStorage,
5027 (REFIID)&IID_IStorage,
5028 (void**)ppstgOpen);
5030 return hr;
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)
5040 HRESULT hRes;
5042 assert(pStg != 0);
5044 hRes = IStorage32_SetClass(pStg, rclsid);
5046 return hRes;
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 )
5109 return E_FAIL;
5112 * STGM_WRITE | STGM_READWRITE | STGM_READ
5114 if ( ! bSTGM_READ )
5115 if( bSTGM_WRITE && bSTGM_READWRITE )
5116 return E_FAIL;
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)
5126 return E_FAIL;
5129 * STGM_CREATE | STGM_CONVERT
5130 * if both are false, STGM_FAILIFTHERE is set to TRUE
5132 if ( bSTGM_CREATE && bSTGM_CONVERT )
5133 return E_FAIL;
5136 * STGM_NOSCRATCH requires STGM_TRANSACTED
5138 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5139 return E_FAIL;
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)) )
5149 return E_FAIL;
5152 return S_OK;
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))
5177 dwShareMode = 0;
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;
5185 return dwShareMode;
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);
5201 if (bSTGM_READ)
5202 dwDesiredAccess = GENERIC_READ;
5204 if (bSTGM_WRITE)
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);
5226 if (bSTGM_CREATE)
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;