Changed the button state to "up" as soon as it is known that the
[wine/multimedia.git] / ole / storage32.c
blobbb2b6cc157c117485f7f6f6ec65f761b58bcfca4
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 "winbase.h"
19 #include "winerror.h"
20 #include "wine/obj_storage.h"
21 #include "wine/winestring.h"
22 #include "crtdll.h"
23 #include "tchar.h"
24 #include "debug.h"
26 #include "storage32.h"
28 #define FILE_BEGIN 0
30 static const char rootPropertyName[] = "Root Entry";
32 /***********************************************************************
33 * Forward declaration of internal functions used by the method DestroyElement
35 static HRESULT deleteStorageProperty(
36 StorageImpl *parentStorage,
37 OLECHAR *propertyToDeleteName);
39 static HRESULT deleteStreamProperty(
40 StorageImpl *parentStorage,
41 ULONG foundPropertyIndexToDelete,
42 StgProperty propertyToDelete);
44 static HRESULT findPlaceholder(
45 StorageImpl *storage,
46 ULONG propertyIndexToStore,
47 ULONG storagePropertyIndex,
48 INT typeOfRelation);
50 static HRESULT adjustPropertyChain(
51 StorageImpl *This,
52 StgProperty propertyToDelete,
53 StgProperty parentProperty,
54 ULONG parentPropertyId,
55 INT typeOfRelation);
57 /***********************************************************************
58 * Declaration of the functions used to manipulate StgProperty
61 static ULONG getFreeProperty(
62 StorageImpl *storage);
64 static void updatePropertyChain(
65 StorageImpl *storage,
66 ULONG newPropertyIndex,
67 StgProperty newProperty);
69 static LONG propertyNameCmp(
70 OLECHAR *newProperty,
71 OLECHAR *currentProperty);
74 /***********************************************************************
75 * Declaration of miscellaneous functions...
77 static HRESULT validateSTGM(DWORD stgmValue);
79 static DWORD GetShareModeFromSTGM(DWORD stgm);
80 static DWORD GetAccessModeFromSTGM(DWORD stgm);
81 static DWORD GetCreationModeFromSTGM(DWORD stgm);
84 * Virtual function table for the IStorage32Impl class.
86 static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
88 StorageBaseImpl_QueryInterface,
89 StorageBaseImpl_AddRef,
90 StorageBaseImpl_Release,
91 StorageBaseImpl_CreateStream,
92 StorageBaseImpl_OpenStream,
93 StorageImpl_CreateStorage,
94 StorageBaseImpl_OpenStorage,
95 StorageImpl_CopyTo,
96 StorageImpl_MoveElementTo,
97 StorageImpl_Commit,
98 StorageImpl_Revert,
99 StorageBaseImpl_EnumElements,
100 StorageImpl_DestroyElement,
101 StorageBaseImpl_RenameElement,
102 StorageImpl_SetElementTimes,
103 StorageBaseImpl_SetClass,
104 StorageImpl_SetStateBits,
105 StorageBaseImpl_Stat
109 * Virtual function table for the Storage32InternalImpl class.
111 static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
113 StorageBaseImpl_QueryInterface,
114 StorageBaseImpl_AddRef,
115 StorageBaseImpl_Release,
116 StorageBaseImpl_CreateStream,
117 StorageBaseImpl_OpenStream,
118 StorageImpl_CreateStorage,
119 StorageBaseImpl_OpenStorage,
120 StorageImpl_CopyTo,
121 StorageImpl_MoveElementTo,
122 StorageInternalImpl_Commit,
123 StorageInternalImpl_Revert,
124 StorageBaseImpl_EnumElements,
125 StorageImpl_DestroyElement,
126 StorageBaseImpl_RenameElement,
127 StorageImpl_SetElementTimes,
128 StorageBaseImpl_SetClass,
129 StorageImpl_SetStateBits,
130 StorageBaseImpl_Stat
134 * Virtual function table for the IEnumSTATSTGImpl class.
136 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
138 IEnumSTATSTGImpl_QueryInterface,
139 IEnumSTATSTGImpl_AddRef,
140 IEnumSTATSTGImpl_Release,
141 IEnumSTATSTGImpl_Next,
142 IEnumSTATSTGImpl_Skip,
143 IEnumSTATSTGImpl_Reset,
144 IEnumSTATSTGImpl_Clone
151 /************************************************************************
152 ** Storage32BaseImpl implementatiion
155 /************************************************************************
156 * Storage32BaseImpl_QueryInterface (IUnknown)
158 * This method implements the common QueryInterface for all IStorage32
159 * implementations contained in this file.
161 * See Windows documentation for more details on IUnknown methods.
163 HRESULT WINAPI StorageBaseImpl_QueryInterface(
164 IStorage* iface,
165 REFIID riid,
166 void** ppvObject)
168 ICOM_THIS(StorageBaseImpl,iface);
170 * Perform a sanity check on the parameters.
172 if ( (This==0) || (ppvObject==0) )
173 return E_INVALIDARG;
176 * Initialize the return parameter.
178 *ppvObject = 0;
181 * Compare the riid with the interface IDs implemented by this object.
183 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
185 *ppvObject = (IStorage*)This;
187 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
189 *ppvObject = (IStorage*)This;
193 * Check that we obtained an interface.
195 if ((*ppvObject)==0)
196 return E_NOINTERFACE;
199 * Query Interface always increases the reference count by one when it is
200 * successful
202 StorageBaseImpl_AddRef(iface);
204 return S_OK;
207 /************************************************************************
208 * Storage32BaseImpl_AddRef (IUnknown)
210 * This method implements the common AddRef for all IStorage32
211 * implementations contained in this file.
213 * See Windows documentation for more details on IUnknown methods.
215 ULONG WINAPI StorageBaseImpl_AddRef(
216 IStorage* iface)
218 ICOM_THIS(StorageBaseImpl,iface);
219 This->ref++;
221 return This->ref;
224 /************************************************************************
225 * Storage32BaseImpl_Release (IUnknown)
227 * This method implements the common Release for all IStorage32
228 * implementations contained in this file.
230 * See Windows documentation for more details on IUnknown methods.
232 ULONG WINAPI StorageBaseImpl_Release(
233 IStorage* iface)
235 ICOM_THIS(StorageBaseImpl,iface);
237 * Decrease the reference count on this object.
239 This->ref--;
242 * If the reference count goes down to 0, perform suicide.
244 if (This->ref==0)
247 * Since we are using a system of base-classes, we want to call the
248 * destructor of the appropriate derived class. To do this, we are
249 * using virtual functions to implement the destructor.
251 This->v_destructor(This);
253 return 0;
256 return This->ref;
259 /************************************************************************
260 * Storage32BaseImpl_OpenStream (IStorage)
262 * This method will open the specified stream object from the current storage.
264 * See Windows documentation for more details on IStorage methods.
266 HRESULT WINAPI StorageBaseImpl_OpenStream(
267 IStorage* iface,
268 const OLECHAR* pwcsName, /* [string][in] */
269 void* reserved1, /* [unique][in] */
270 DWORD grfMode, /* [in] */
271 DWORD reserved2, /* [in] */
272 IStream** ppstm) /* [out] */
274 ICOM_THIS(StorageBaseImpl,iface);
275 IEnumSTATSTGImpl* propertyEnumeration;
276 StgStreamImpl* newStream;
277 StgProperty currentProperty;
278 ULONG foundPropertyIndex;
281 * Perform a sanity check on the parameters.
283 if ( (pwcsName==NULL) || (ppstm==0) )
284 return E_INVALIDARG;
287 * Initialize the out parameter
289 *ppstm = 0;
292 * Validate the STGM flags
294 if ( FAILED( validateSTGM(grfMode) ))
295 return STG_E_INVALIDFLAG;
298 * As documented.
300 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
301 (grfMode & STGM_DELETEONRELEASE) ||
302 (grfMode & STGM_TRANSACTED) )
303 return STG_E_INVALIDFUNCTION;
306 * Create a property enumeration to search the properties
308 propertyEnumeration = IEnumSTATSTGImpl_Construct(
309 This->ancestorStorage,
310 This->rootPropertySetIndex);
313 * Search the enumeration for the property with the given name
315 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
316 propertyEnumeration,
317 pwcsName,
318 &currentProperty);
321 * Delete the property enumeration since we don't need it anymore
323 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
326 * If it was found, construct the stream object and return a pointer to it.
328 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
329 (currentProperty.propertyType==PROPTYPE_STREAM) )
331 newStream = StgStreamImpl_Construct(This, foundPropertyIndex);
333 if (newStream!=0)
335 *ppstm = (IStream*)newStream;
338 * Since we are returning a pointer to the interface, we have to
339 * nail down the reference.
341 StgStreamImpl_AddRef(*ppstm);
343 return S_OK;
346 return E_OUTOFMEMORY;
349 return STG_E_FILENOTFOUND;
352 /************************************************************************
353 * Storage32BaseImpl_OpenStorage (IStorage)
355 * This method will open a new storage object from the current storage.
357 * See Windows documentation for more details on IStorage methods.
359 HRESULT WINAPI StorageBaseImpl_OpenStorage(
360 IStorage* iface,
361 const OLECHAR* pwcsName, /* [string][unique][in] */
362 IStorage* pstgPriority, /* [unique][in] */
363 DWORD grfMode, /* [in] */
364 SNB snbExclude, /* [unique][in] */
365 DWORD reserved, /* [in] */
366 IStorage** ppstg) /* [out] */
368 ICOM_THIS(StorageBaseImpl,iface);
369 StorageInternalImpl* newStorage;
370 IEnumSTATSTGImpl* propertyEnumeration;
371 StgProperty currentProperty;
372 ULONG foundPropertyIndex;
375 * Perform a sanity check on the parameters.
377 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
378 return E_INVALIDARG;
381 * Validate the STGM flags
383 if ( FAILED( validateSTGM(grfMode) ))
384 return STG_E_INVALIDFLAG;
387 * As documented.
389 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
390 (grfMode & STGM_DELETEONRELEASE) ||
391 (grfMode & STGM_PRIORITY) )
392 return STG_E_INVALIDFUNCTION;
395 * Initialize the out parameter
397 *ppstg = 0;
400 * Create a property enumeration to search the properties
402 propertyEnumeration = IEnumSTATSTGImpl_Construct(
403 This->ancestorStorage,
404 This->rootPropertySetIndex);
407 * Search the enumeration for the property with the given name
409 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
410 propertyEnumeration,
411 pwcsName,
412 &currentProperty);
415 * Delete the property enumeration since we don't need it anymore
417 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
420 * If it was found, construct the stream object and return a pointer to it.
422 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
423 (currentProperty.propertyType==PROPTYPE_STORAGE) )
426 * Construct a new Storage object
428 newStorage = StorageInternalImpl_Construct(
429 This->ancestorStorage,
430 foundPropertyIndex);
432 if (newStorage != 0)
434 *ppstg = (IStorage*)newStorage;
437 * Since we are returning a pointer to the interface,
438 * we have to nail down the reference.
440 StorageBaseImpl_AddRef(*ppstg);
442 return S_OK;
445 return STG_E_INSUFFICIENTMEMORY;
448 return STG_E_FILENOTFOUND;
451 /************************************************************************
452 * Storage32BaseImpl_EnumElements (IStorage)
454 * This method will create an enumerator object that can be used to
455 * retrieve informatino about all the properties in the storage object.
457 * See Windows documentation for more details on IStorage methods.
459 HRESULT WINAPI StorageBaseImpl_EnumElements(
460 IStorage* iface,
461 DWORD reserved1, /* [in] */
462 void* reserved2, /* [size_is][unique][in] */
463 DWORD reserved3, /* [in] */
464 IEnumSTATSTG** ppenum) /* [out] */
466 ICOM_THIS(StorageBaseImpl,iface);
467 IEnumSTATSTGImpl* newEnum;
470 * Perform a sanity check on the parameters.
472 if ( (This==0) || (ppenum==0))
473 return E_INVALIDARG;
476 * Construct the enumerator.
478 newEnum = IEnumSTATSTGImpl_Construct(
479 This->ancestorStorage,
480 This->rootPropertySetIndex);
482 if (newEnum!=0)
484 *ppenum = (IEnumSTATSTG*)newEnum;
487 * Don't forget to nail down a reference to the new object before
488 * returning it.
490 IEnumSTATSTGImpl_AddRef(*ppenum);
492 return S_OK;
495 return E_OUTOFMEMORY;
498 /************************************************************************
499 * Storage32BaseImpl_Stat (IStorage)
501 * This method will retrieve information about this storage object.
503 * See Windows documentation for more details on IStorage methods.
505 HRESULT WINAPI StorageBaseImpl_Stat(
506 IStorage* iface,
507 STATSTG* pstatstg, /* [out] */
508 DWORD grfStatFlag) /* [in] */
510 ICOM_THIS(StorageBaseImpl,iface);
511 StgProperty curProperty;
512 BOOL readSucessful;
515 * Perform a sanity check on the parameters.
517 if ( (This==0) || (pstatstg==0))
518 return E_INVALIDARG;
521 * Read the information from the property.
523 readSucessful = StorageImpl_ReadProperty(
524 This->ancestorStorage,
525 This->rootPropertySetIndex,
526 &curProperty);
528 if (readSucessful)
530 StorageUtl_CopyPropertyToSTATSTG(
531 pstatstg,
532 &curProperty,
533 grfStatFlag);
535 return S_OK;
538 return E_FAIL;
541 /************************************************************************
542 * Storage32BaseImpl_RenameElement (IStorage)
544 * This method will rename the specified element.
546 * See Windows documentation for more details on IStorage methods.
548 * Implementation notes: The method used to rename consists of creating a clone
549 * of the deleted StgProperty object setting it with the new name and to
550 * perform a DestroyElement of the old StgProperty.
552 HRESULT WINAPI StorageBaseImpl_RenameElement(
553 IStorage* iface,
554 const OLECHAR* pwcsOldName, /* [in] */
555 const OLECHAR* pwcsNewName) /* [in] */
557 ICOM_THIS(StorageBaseImpl,iface);
558 IEnumSTATSTGImpl* propertyEnumeration;
559 StgProperty currentProperty;
560 ULONG foundPropertyIndex;
563 * Create a property enumeration to search the properties
565 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
566 This->rootPropertySetIndex);
569 * Search the enumeration for the new property name
571 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
572 pwcsNewName,
573 &currentProperty);
575 if (foundPropertyIndex != PROPERTY_NULL)
578 * There is already a property with the new name
580 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
581 return STG_E_FILEALREADYEXISTS;
584 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
587 * Search the enumeration for the old property name
589 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
590 pwcsOldName,
591 &currentProperty);
594 * Delete the property enumeration since we don't need it anymore
596 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
598 if (foundPropertyIndex != PROPERTY_NULL)
600 StgProperty renamedProperty;
601 ULONG renamedPropertyIndex;
604 * Setup a new property for the renamed property
606 renamedProperty.sizeOfNameString =
607 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
609 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
610 return STG_E_INVALIDNAME;
612 lstrcpyW(renamedProperty.name, pwcsNewName);
614 renamedProperty.propertyType = currentProperty.propertyType;
615 renamedProperty.startingBlock = currentProperty.startingBlock;
616 renamedProperty.size.LowPart = currentProperty.size.LowPart;
617 renamedProperty.size.HighPart = currentProperty.size.HighPart;
619 renamedProperty.previousProperty = PROPERTY_NULL;
620 renamedProperty.nextProperty = PROPERTY_NULL;
623 * Bring the dirProperty link in case it is a storage and in which
624 * case the renamed storage elements don't require to be reorganized.
626 renamedProperty.dirProperty = currentProperty.dirProperty;
628 /* call CoFileTime to get the current time
629 renamedProperty.timeStampS1
630 renamedProperty.timeStampD1
631 renamedProperty.timeStampS2
632 renamedProperty.timeStampD2
633 renamedProperty.propertyUniqueID
637 * Obtain a free property in the property chain
639 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
642 * Save the new property into the new property spot
644 StorageImpl_WriteProperty(
645 This->ancestorStorage,
646 renamedPropertyIndex,
647 &renamedProperty);
650 * Find a spot in the property chain for our newly created property.
652 updatePropertyChain(
653 (StorageImpl*)This,
654 renamedPropertyIndex,
655 renamedProperty);
658 * At this point the renamed property has been inserted in the tree,
659 * now, before to Destroy the old property we must zeroed it's dirProperty
660 * otherwise the DestroyProperty below will zap it all and we do not want
661 * this to happen.
662 * Also, we fake that the old property is a storage so the DestroyProperty
663 * will not do a SetSize(0) on the stream data.
665 * This means that we need to tweek the StgProperty if it is a stream or a
666 * non empty storage.
668 currentProperty.dirProperty = PROPERTY_NULL;
669 currentProperty.propertyType = PROPTYPE_STORAGE;
670 StorageImpl_WriteProperty(
671 This->ancestorStorage,
672 foundPropertyIndex,
673 &currentProperty);
676 * Invoke Destroy to get rid of the ole property and automatically redo
677 * the linking of it's previous and next members...
679 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
682 else
685 * There is no property with the old name
687 return STG_E_FILENOTFOUND;
690 return S_OK;
693 /************************************************************************
694 * Storage32BaseImpl_CreateStream (IStorage)
696 * This method will create a stream object within this storage
698 * See Windows documentation for more details on IStorage methods.
700 HRESULT WINAPI StorageBaseImpl_CreateStream(
701 IStorage* iface,
702 const OLECHAR* pwcsName, /* [string][in] */
703 DWORD grfMode, /* [in] */
704 DWORD reserved1, /* [in] */
705 DWORD reserved2, /* [in] */
706 IStream** ppstm) /* [out] */
708 ICOM_THIS(StorageBaseImpl,iface);
709 IEnumSTATSTGImpl* propertyEnumeration;
710 StgStreamImpl* newStream;
711 StgProperty currentProperty, newStreamProperty;
712 ULONG foundPropertyIndex, newPropertyIndex;
715 * Validate parameters
717 if (ppstm == 0)
718 return STG_E_INVALIDPOINTER;
720 if (pwcsName == 0)
721 return STG_E_INVALIDNAME;
724 * Validate the STGM flags
726 if ( FAILED( validateSTGM(grfMode) ))
727 return STG_E_INVALIDFLAG;
730 * As documented.
732 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
733 (grfMode & STGM_DELETEONRELEASE) ||
734 (grfMode & STGM_TRANSACTED) )
735 return STG_E_INVALIDFUNCTION;
738 * Initialize the out parameter
740 *ppstm = 0;
743 * Create a property enumeration to search the properties
745 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
746 This->rootPropertySetIndex);
748 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
749 pwcsName,
750 &currentProperty);
752 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
754 if (foundPropertyIndex != PROPERTY_NULL)
757 * An element with this name already exists
759 if (grfMode & STGM_CREATE)
760 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
761 else
762 return STG_E_FILEALREADYEXISTS;
766 * memset the empty property
768 memset(&newStreamProperty, 0, sizeof(StgProperty));
770 newStreamProperty.sizeOfNameString =
771 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
773 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
774 return STG_E_INVALIDNAME;
776 lstrcpyW(newStreamProperty.name, pwcsName);
778 newStreamProperty.propertyType = PROPTYPE_STREAM;
779 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
780 newStreamProperty.size.LowPart = 0;
781 newStreamProperty.size.HighPart = 0;
783 newStreamProperty.previousProperty = PROPERTY_NULL;
784 newStreamProperty.nextProperty = PROPERTY_NULL;
785 newStreamProperty.dirProperty = PROPERTY_NULL;
787 /* call CoFileTime to get the current time
788 newStreamProperty.timeStampS1
789 newStreamProperty.timeStampD1
790 newStreamProperty.timeStampS2
791 newStreamProperty.timeStampD2
794 /* newStreamProperty.propertyUniqueID */
797 * Get a free property or create a new one
799 newPropertyIndex = getFreeProperty(This->ancestorStorage);
802 * Save the new property into the new property spot
804 StorageImpl_WriteProperty(
805 This->ancestorStorage,
806 newPropertyIndex,
807 &newStreamProperty);
810 * Find a spot in the property chain for our newly created property.
812 updatePropertyChain(
813 (StorageImpl*)This,
814 newPropertyIndex,
815 newStreamProperty);
818 * Open the stream to return it.
820 newStream = StgStreamImpl_Construct(This, newPropertyIndex);
822 if (newStream != 0)
824 *ppstm = (IStream*)newStream;
827 * Since we are returning a pointer to the interface, we have to nail down
828 * the reference.
830 StgStreamImpl_AddRef(*ppstm);
832 else
834 return STG_E_INSUFFICIENTMEMORY;
837 return S_OK;
840 /************************************************************************
841 * Storage32BaseImpl_SetClass (IStorage)
843 * This method will write the specified CLSID in the property of this
844 * storage.
846 * See Windows documentation for more details on IStorage methods.
848 HRESULT WINAPI StorageBaseImpl_SetClass(
849 IStorage* iface,
850 REFCLSID clsid) /* [in] */
852 ICOM_THIS(StorageBaseImpl,iface);
853 HRESULT hRes = E_FAIL;
854 StgProperty curProperty;
855 BOOL success;
857 success = StorageImpl_ReadProperty(This->ancestorStorage,
858 This->rootPropertySetIndex,
859 &curProperty);
860 if (success)
862 curProperty.propertyUniqueID = *clsid;
864 success = StorageImpl_WriteProperty(This->ancestorStorage,
865 This->rootPropertySetIndex,
866 &curProperty);
867 if (success)
868 hRes = S_OK;
871 return hRes;
874 /************************************************************************
875 ** Storage32Impl implementation
878 /************************************************************************
879 * Storage32Impl_CreateStorage (IStorage)
881 * This method will create the storage object within the provided storage.
883 * See Windows documentation for more details on IStorage methods.
885 HRESULT WINAPI StorageImpl_CreateStorage(
886 IStorage* iface,
887 const OLECHAR *pwcsName, /* [string][in] */
888 DWORD grfMode, /* [in] */
889 DWORD reserved1, /* [in] */
890 DWORD reserved2, /* [in] */
891 IStorage **ppstg) /* [out] */
893 StorageImpl* const This=(StorageImpl*)iface;
895 IEnumSTATSTGImpl *propertyEnumeration;
896 StgProperty currentProperty;
897 StgProperty newProperty;
898 ULONG foundPropertyIndex;
899 ULONG newPropertyIndex;
900 HRESULT hr;
903 * Validate parameters
905 if (ppstg == 0)
906 return STG_E_INVALIDPOINTER;
908 if (pwcsName == 0)
909 return STG_E_INVALIDNAME;
912 * Validate the STGM flags
914 if ( FAILED( validateSTGM(grfMode) ) ||
915 (grfMode & STGM_DELETEONRELEASE) )
916 return STG_E_INVALIDFLAG;
919 * Initialize the out parameter
921 *ppstg = 0;
924 * Create a property enumeration and search the properties
926 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
927 This->rootPropertySetIndex);
929 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
930 pwcsName,
931 &currentProperty);
932 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
934 if (foundPropertyIndex != PROPERTY_NULL)
937 * An element with this name already exists
939 if (grfMode & STGM_CREATE)
940 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
941 else
942 return STG_E_FILEALREADYEXISTS;
946 * memset the empty property
948 memset(&newProperty, 0, sizeof(StgProperty));
950 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
952 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
953 return STG_E_INVALIDNAME;
955 lstrcpyW(newProperty.name, pwcsName);
957 newProperty.propertyType = PROPTYPE_STORAGE;
958 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
959 newProperty.size.LowPart = 0;
960 newProperty.size.HighPart = 0;
962 newProperty.previousProperty = PROPERTY_NULL;
963 newProperty.nextProperty = PROPERTY_NULL;
964 newProperty.dirProperty = PROPERTY_NULL;
966 /* call CoFileTime to get the current time
967 newProperty.timeStampS1
968 newProperty.timeStampD1
969 newProperty.timeStampS2
970 newProperty.timeStampD2
973 /* newStorageProperty.propertyUniqueID */
976 * Obtain a free property in the property chain
978 newPropertyIndex = getFreeProperty(This->ancestorStorage);
981 * Save the new property into the new property spot
983 StorageImpl_WriteProperty(
984 This->ancestorStorage,
985 newPropertyIndex,
986 &newProperty);
989 * Find a spot in the property chain for our newly created property.
991 updatePropertyChain(
992 This,
993 newPropertyIndex,
994 newProperty);
997 * Open it to get a pointer to return.
999 hr = StorageBaseImpl_OpenStorage(
1000 iface,
1001 (OLECHAR*)pwcsName,
1003 grfMode,
1006 ppstg);
1008 if( (hr != S_OK) || (*ppstg == NULL))
1010 return hr;
1013 return S_OK;
1017 /***************************************************************************
1019 * Internal Method
1021 * Get a free property or create a new one.
1023 static ULONG getFreeProperty(
1024 StorageImpl *storage)
1026 ULONG currentPropertyIndex = 0;
1027 ULONG newPropertyIndex = PROPERTY_NULL;
1028 BOOL readSucessful = TRUE;
1029 StgProperty currentProperty;
1034 * Start by reading the root property
1036 readSucessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1037 currentPropertyIndex,
1038 &currentProperty);
1039 if (readSucessful)
1041 if (currentProperty.sizeOfNameString == 0)
1044 * The property existis and is available, we found it.
1046 newPropertyIndex = currentPropertyIndex;
1049 else
1052 * We exhausted the property list, we will create more space below
1054 newPropertyIndex = currentPropertyIndex;
1056 currentPropertyIndex++;
1058 } while (newPropertyIndex == PROPERTY_NULL);
1061 * grow the property chain
1063 if (! readSucessful)
1065 StgProperty emptyProperty;
1066 ULARGE_INTEGER newSize;
1067 ULONG propertyIndex;
1068 ULONG lastProperty = 0;
1069 ULONG blockCount = 0;
1072 * obtain the new count of property blocks
1074 blockCount = BlockChainStream_GetCount(
1075 storage->ancestorStorage->rootBlockChain)+1;
1078 * initialize the size used by the property stream
1080 newSize.HighPart = 0;
1081 newSize.LowPart = storage->bigBlockSize * blockCount;
1084 * add a property block to the property chain
1086 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1089 * memset the empty property in order to initialize the unused newly
1090 * created property
1092 memset(&emptyProperty, 0, sizeof(StgProperty));
1095 * initialize them
1097 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1099 for(
1100 propertyIndex = newPropertyIndex;
1101 propertyIndex < lastProperty;
1102 propertyIndex++)
1104 StorageImpl_WriteProperty(
1105 storage->ancestorStorage,
1106 propertyIndex,
1107 &emptyProperty);
1111 return newPropertyIndex;
1114 /****************************************************************************
1116 * Internal Method
1118 * Case insensitive comparaison of StgProperty.name by first considering
1119 * their size.
1121 * Returns <0 when newPrpoerty < currentProperty
1122 * >0 when newPrpoerty > currentProperty
1123 * 0 when newPrpoerty == currentProperty
1125 static LONG propertyNameCmp(
1126 OLECHAR *newProperty,
1127 OLECHAR *currentProperty)
1129 LONG sizeOfNew = (lstrlenW(newProperty) +1) * sizeof(WCHAR);
1130 LONG sizeOfCur = (lstrlenW(currentProperty)+1) * sizeof(WCHAR);
1131 LONG diff = sizeOfNew - sizeOfCur;
1133 if (diff == 0)
1136 * We compare the string themselves only when they are of the same lenght
1138 WCHAR wsnew[PROPERTY_NAME_MAX_LEN];
1139 WCHAR wscur[PROPERTY_NAME_MAX_LEN];
1141 diff = lstrcmpW( (LPCWSTR)CRTDLL__wcsupr(
1142 lstrcpynW(wsnew, newProperty, sizeOfNew)),
1143 (LPCWSTR)CRTDLL__wcsupr(
1144 lstrcpynW(wscur, currentProperty, sizeOfCur)));
1147 return diff;
1150 /****************************************************************************
1152 * Internal Method
1154 * Properly link this new element in the property chain.
1156 static void updatePropertyChain(
1157 StorageImpl *storage,
1158 ULONG newPropertyIndex,
1159 StgProperty newProperty)
1161 StgProperty currentProperty;
1164 * Read the root property
1166 StorageImpl_ReadProperty(storage->ancestorStorage,
1167 storage->rootPropertySetIndex,
1168 &currentProperty);
1170 if (currentProperty.dirProperty != PROPERTY_NULL)
1173 * The root storage contains some element, therefore, start the research
1174 * for the appropriate location.
1176 BOOL found = 0;
1177 ULONG current, next, previous, currentPropertyId;
1180 * Keep the StgProperty sequence number of the storage first property
1182 currentPropertyId = currentProperty.dirProperty;
1185 * Read
1187 StorageImpl_ReadProperty(storage->ancestorStorage,
1188 currentProperty.dirProperty,
1189 &currentProperty);
1191 previous = currentProperty.previousProperty;
1192 next = currentProperty.nextProperty;
1193 current = currentPropertyId;
1195 while (found == 0)
1197 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1199 if (diff < 0)
1201 if (previous != PROPERTY_NULL)
1203 StorageImpl_ReadProperty(storage->ancestorStorage,
1204 previous,
1205 &currentProperty);
1206 current = previous;
1208 else
1210 currentProperty.previousProperty = newPropertyIndex;
1211 StorageImpl_WriteProperty(storage->ancestorStorage,
1212 current,
1213 &currentProperty);
1214 found = 1;
1217 else
1219 if (next != PROPERTY_NULL)
1221 StorageImpl_ReadProperty(storage->ancestorStorage,
1222 next,
1223 &currentProperty);
1224 current = next;
1226 else
1228 currentProperty.nextProperty = newPropertyIndex;
1229 StorageImpl_WriteProperty(storage->ancestorStorage,
1230 current,
1231 &currentProperty);
1232 found = 1;
1236 previous = currentProperty.previousProperty;
1237 next = currentProperty.nextProperty;
1240 else
1243 * The root storage is empty, link the new property to it's dir property
1245 currentProperty.dirProperty = newPropertyIndex;
1246 StorageImpl_WriteProperty(storage->ancestorStorage,
1247 storage->rootPropertySetIndex,
1248 &currentProperty);
1253 /*************************************************************************
1254 * CopyTo (IStorage)
1256 HRESULT WINAPI StorageImpl_CopyTo(
1257 IStorage* iface,
1258 DWORD ciidExclude, /* [in] */
1259 const IID *rgiidExclude,/* [size_is][unique][in] */
1260 SNB snbExclude, /* [unique][in] */
1261 IStorage *pstgDest) /* [unique][in] */
1263 return E_NOTIMPL;
1266 /*************************************************************************
1267 * MoveElementTo (IStorage)
1269 HRESULT WINAPI StorageImpl_MoveElementTo(
1270 IStorage* iface,
1271 const OLECHAR *pwcsName, /* [string][in] */
1272 IStorage *pstgDest, /* [unique][in] */
1273 const OLECHAR *pwcsNewName,/* [string][in] */
1274 DWORD grfFlags) /* [in] */
1276 return E_NOTIMPL;
1279 /*************************************************************************
1280 * Commit (IStorage)
1282 HRESULT WINAPI StorageImpl_Commit(
1283 IStorage* iface,
1284 DWORD grfCommitFlags)/* [in] */
1286 FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1287 return S_OK;
1290 /*************************************************************************
1291 * Revert (IStorage)
1293 HRESULT WINAPI StorageImpl_Revert(
1294 IStorage* iface)
1296 return E_NOTIMPL;
1299 /*************************************************************************
1300 * DestroyElement (IStorage)
1302 * Stategy: This implementation is build this way for simplicity not for speed.
1303 * I always delete the top most element of the enumeration and adjust
1304 * the deleted element pointer all the time. This takes longer to
1305 * do but allow to reinvoke DestroyElement whenever we encounter a
1306 * storage object. The optimisation reside in the usage of another
1307 * enumeration stategy that would give all the leaves of a storage
1308 * first. (postfix order)
1310 HRESULT WINAPI StorageImpl_DestroyElement(
1311 IStorage* iface,
1312 const OLECHAR *pwcsName)/* [string][in] */
1314 StorageImpl* const This=(StorageImpl*)iface;
1316 IEnumSTATSTGImpl* propertyEnumeration;
1317 HRESULT hr = S_OK;
1318 BOOL res;
1319 StgProperty propertyToDelete;
1320 StgProperty parentProperty;
1321 ULONG foundPropertyIndexToDelete;
1322 ULONG typeOfRelation;
1323 ULONG parentPropertyId;
1326 * Perform a sanity check on the parameters.
1328 if (pwcsName==NULL)
1329 return STG_E_INVALIDPOINTER;
1332 * Create a property enumeration to search the property with the given name
1334 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1335 This->ancestorStorage,
1336 This->rootPropertySetIndex);
1338 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1339 propertyEnumeration,
1340 pwcsName,
1341 &propertyToDelete);
1343 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1345 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1347 return STG_E_FILENOTFOUND;
1351 * Find the parent property of the property to delete (the one that
1352 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1353 * the parent is This. Otherwise, the parent is one of it's sibling...
1357 * First, read This's StgProperty..
1359 res = StorageImpl_ReadProperty(
1360 This->ancestorStorage,
1361 This->rootPropertySetIndex,
1362 &parentProperty);
1364 assert(res==TRUE);
1367 * Second, check to see if by any chance the actual storage (This) is not
1368 * the parent of the property to delete... We never know...
1370 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1373 * Set data as it would have been done in the else part...
1375 typeOfRelation = PROPERTY_RELATION_DIR;
1376 parentPropertyId = This->rootPropertySetIndex;
1378 else
1381 * Create a property enumeration to search the parent properties, and
1382 * delete it once done.
1384 IEnumSTATSTGImpl* propertyEnumeration2;
1386 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1387 This->ancestorStorage,
1388 This->rootPropertySetIndex);
1390 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1391 propertyEnumeration2,
1392 foundPropertyIndexToDelete,
1393 &parentProperty,
1394 &parentPropertyId);
1396 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1399 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1401 hr = deleteStorageProperty(
1402 This,
1403 propertyToDelete.name);
1405 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1407 hr = deleteStreamProperty(
1408 This,
1409 foundPropertyIndexToDelete,
1410 propertyToDelete);
1413 if (hr!=S_OK)
1414 return hr;
1417 * Adjust the property chain
1419 hr = adjustPropertyChain(
1420 This,
1421 propertyToDelete,
1422 parentProperty,
1423 parentPropertyId,
1424 typeOfRelation);
1426 return hr;
1430 /*********************************************************************
1432 * Internal Method
1434 * Perform the deletion of a complete storage node
1437 static HRESULT deleteStorageProperty(
1438 StorageImpl *parentStorage,
1439 OLECHAR *propertyToDeleteName)
1441 IEnumSTATSTG *elements = 0;
1442 IStorage *childStorage = 0;
1443 STATSTG currentElement;
1444 HRESULT hr;
1445 HRESULT destroyHr = S_OK;
1448 * Open the storage and enumerate it
1450 hr = StorageBaseImpl_OpenStorage(
1451 (IStorage*)parentStorage,
1452 propertyToDeleteName,
1454 STGM_SHARE_EXCLUSIVE,
1457 &childStorage);
1459 if (hr != S_OK)
1461 return hr;
1465 * Enumerate the elements
1467 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1472 * Obtain the next element
1474 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1475 if (hr==S_OK)
1477 destroyHr = StorageImpl_DestroyElement(
1478 (IStorage*)childStorage,
1479 (OLECHAR*)currentElement.pwcsName);
1481 CoTaskMemFree(currentElement.pwcsName);
1485 * We need to Reset the enumeration every time because we delete elements
1486 * and the enumeration could be invalid
1488 IEnumSTATSTG_Reset(elements);
1490 } while ((hr == S_OK) && (destroyHr == S_OK));
1492 IStorage_Release(childStorage);
1493 IEnumSTATSTG_Release(elements);
1495 return destroyHr;
1498 /*********************************************************************
1500 * Internal Method
1502 * Perform the deletion of a stream node
1505 static HRESULT deleteStreamProperty(
1506 StorageImpl *parentStorage,
1507 ULONG indexOfPropertyToDelete,
1508 StgProperty propertyToDelete)
1510 IStream *pis;
1511 HRESULT hr;
1512 ULARGE_INTEGER size;
1514 size.HighPart = 0;
1515 size.LowPart = 0;
1517 hr = StorageBaseImpl_OpenStream(
1518 (IStorage*)parentStorage,
1519 (OLECHAR*)propertyToDelete.name,
1520 NULL,
1521 STGM_SHARE_EXCLUSIVE,
1523 &pis);
1525 if (hr!=S_OK)
1527 return(hr);
1531 * Zap the stream
1533 hr = IStream_SetSize(pis, size);
1535 if(hr != S_OK)
1537 return hr;
1541 * Invalidate the property by zeroing it's name member.
1543 propertyToDelete.sizeOfNameString = 0;
1546 * Here we should re-read the property so we get the updated pointer
1547 * but since we are here to zap it, I don't do it...
1550 StorageImpl_WriteProperty(
1551 parentStorage->ancestorStorage,
1552 indexOfPropertyToDelete,
1553 &propertyToDelete);
1555 return S_OK;
1558 /*********************************************************************
1560 * Internal Method
1562 * Finds a placeholder for the StgProperty within the Storage
1565 static HRESULT findPlaceholder(
1566 StorageImpl *storage,
1567 ULONG propertyIndexToStore,
1568 ULONG storePropertyIndex,
1569 INT typeOfRelation)
1571 StgProperty storeProperty;
1572 HRESULT hr = S_OK;
1573 BOOL res = TRUE;
1576 * Read the storage property
1578 res = StorageImpl_ReadProperty(
1579 storage->ancestorStorage,
1580 storePropertyIndex,
1581 &storeProperty);
1583 if(! res)
1585 return E_FAIL;
1588 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1590 if (storeProperty.previousProperty != PROPERTY_NULL)
1592 return findPlaceholder(
1593 storage,
1594 propertyIndexToStore,
1595 storeProperty.previousProperty,
1596 typeOfRelation);
1598 else
1600 storeProperty.previousProperty = propertyIndexToStore;
1603 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1605 if (storeProperty.nextProperty != PROPERTY_NULL)
1607 return findPlaceholder(
1608 storage,
1609 propertyIndexToStore,
1610 storeProperty.nextProperty,
1611 typeOfRelation);
1613 else
1615 storeProperty.nextProperty = propertyIndexToStore;
1618 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1620 if (storeProperty.dirProperty != PROPERTY_NULL)
1622 return findPlaceholder(
1623 storage,
1624 propertyIndexToStore,
1625 storeProperty.dirProperty,
1626 typeOfRelation);
1628 else
1630 storeProperty.dirProperty = propertyIndexToStore;
1634 hr = StorageImpl_WriteProperty(
1635 storage->ancestorStorage,
1636 storePropertyIndex,
1637 &storeProperty);
1639 if(! hr)
1641 return E_FAIL;
1644 return S_OK;
1647 /*************************************************************************
1649 * Internal Method
1651 * This method takes the previous and the next property link of a property
1652 * to be deleted and find them a place in the Storage.
1654 static HRESULT adjustPropertyChain(
1655 StorageImpl *This,
1656 StgProperty propertyToDelete,
1657 StgProperty parentProperty,
1658 ULONG parentPropertyId,
1659 INT typeOfRelation)
1661 ULONG newLinkProperty = PROPERTY_NULL;
1662 BOOL needToFindAPlaceholder = FALSE;
1663 ULONG storeNode = PROPERTY_NULL;
1664 ULONG toStoreNode = PROPERTY_NULL;
1665 INT relationType = 0;
1666 HRESULT hr = S_OK;
1667 BOOL res = TRUE;
1669 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1671 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1674 * Set the parent previous to the property to delete previous
1676 newLinkProperty = propertyToDelete.previousProperty;
1678 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1681 * We also need to find a storage for the other link, setup variables
1682 * to do this at the end...
1684 needToFindAPlaceholder = TRUE;
1685 storeNode = propertyToDelete.previousProperty;
1686 toStoreNode = propertyToDelete.nextProperty;
1687 relationType = PROPERTY_RELATION_NEXT;
1690 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1693 * Set the parent previous to the property to delete next
1695 newLinkProperty = propertyToDelete.nextProperty;
1699 * Link it for real...
1701 parentProperty.previousProperty = newLinkProperty;
1704 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1706 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1709 * Set the parent next to the property to delete next previous
1711 newLinkProperty = propertyToDelete.previousProperty;
1713 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1716 * We also need to find a storage for the other link, setup variables
1717 * to do this at the end...
1719 needToFindAPlaceholder = TRUE;
1720 storeNode = propertyToDelete.previousProperty;
1721 toStoreNode = propertyToDelete.nextProperty;
1722 relationType = PROPERTY_RELATION_NEXT;
1725 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1728 * Set the parent next to the property to delete next
1730 newLinkProperty = propertyToDelete.nextProperty;
1734 * Link it for real...
1736 parentProperty.nextProperty = newLinkProperty;
1738 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1740 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1743 * Set the parent dir to the property to delete previous
1745 newLinkProperty = propertyToDelete.previousProperty;
1747 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1750 * We also need to find a storage for the other link, setup variables
1751 * to do this at the end...
1753 needToFindAPlaceholder = TRUE;
1754 storeNode = propertyToDelete.previousProperty;
1755 toStoreNode = propertyToDelete.nextProperty;
1756 relationType = PROPERTY_RELATION_NEXT;
1759 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1762 * Set the parent dir to the property to delete next
1764 newLinkProperty = propertyToDelete.nextProperty;
1768 * Link it for real...
1770 parentProperty.dirProperty = newLinkProperty;
1774 * Write back the parent property
1776 res = StorageImpl_WriteProperty(
1777 This->ancestorStorage,
1778 parentPropertyId,
1779 &parentProperty);
1780 if(! res)
1782 return E_FAIL;
1786 * If a placeholder is required for the other link, then, find one and
1787 * get out of here...
1789 if (needToFindAPlaceholder)
1791 hr = findPlaceholder(
1792 This,
1793 toStoreNode,
1794 storeNode,
1795 relationType);
1798 return hr;
1802 /******************************************************************************
1803 * SetElementTimes (IStorage)
1805 HRESULT WINAPI StorageImpl_SetElementTimes(
1806 IStorage* iface,
1807 const OLECHAR *pwcsName,/* [string][in] */
1808 const FILETIME *pctime, /* [in] */
1809 const FILETIME *patime, /* [in] */
1810 const FILETIME *pmtime) /* [in] */
1812 return E_NOTIMPL;
1815 /******************************************************************************
1816 * SetStateBits (IStorage)
1818 HRESULT WINAPI StorageImpl_SetStateBits(
1819 IStorage* iface,
1820 DWORD grfStateBits,/* [in] */
1821 DWORD grfMask) /* [in] */
1823 return E_NOTIMPL;
1826 HRESULT StorageImpl_Construct(
1827 StorageImpl* This,
1828 HANDLE hFile,
1829 DWORD openFlags)
1831 HRESULT hr = S_OK;
1832 StgProperty currentProperty;
1833 BOOL readSucessful;
1834 ULONG currentPropertyIndex;
1836 if ( FAILED( validateSTGM(openFlags) ))
1837 return STG_E_INVALIDFLAG;
1839 memset(This, 0, sizeof(StorageImpl));
1842 * Initialize the virtual fgunction table.
1844 This->lpvtbl = &Storage32Impl_Vtbl;
1845 This->v_destructor = &StorageImpl_Destroy;
1848 * This is the top-level storage so initialize the ancester pointer
1849 * to this.
1851 This->ancestorStorage = This;
1854 * Initialize the physical support of the storage.
1856 This->hFile = hFile;
1859 * Initialize the big block cache.
1861 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
1862 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
1863 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
1864 openFlags,
1865 This->bigBlockSize);
1867 if (This->bigBlockFile == 0)
1868 return E_FAIL;
1870 if (openFlags & STGM_CREATE)
1872 ULARGE_INTEGER size;
1873 BYTE* bigBlockBuffer;
1876 * Initialize all header variables:
1877 * - The big block depot consists of one block and it is at block 0
1878 * - The properties start at block 1
1879 * - There is no small block depot
1881 memset( This->bigBlockDepotStart,
1882 BLOCK_UNUSED,
1883 sizeof(This->bigBlockDepotStart));
1885 This->bigBlockDepotCount = 1;
1886 This->bigBlockDepotStart[0] = 0;
1887 This->rootStartBlock = 1;
1888 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
1889 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
1890 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
1891 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
1892 This->extBigBlockDepotCount = 0;
1894 StorageImpl_SaveFileHeader(This);
1897 * Add one block for the big block depot and one block for the properties
1899 size.HighPart = 0;
1900 size.LowPart = This->bigBlockSize * 3;
1901 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
1904 * Initialize the big block depot
1906 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
1907 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
1908 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
1909 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
1910 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
1912 else
1915 * Load the header for the file.
1917 StorageImpl_LoadFileHeader(This);
1921 * There is no block depot cached yet.
1923 This->indexBlockDepotCached = 0xFFFFFFFF;
1926 * Start searching for free blocks with block 0.
1928 This->prevFreeBlock = 0;
1931 * Create the block chain abstractions.
1933 This->rootBlockChain =
1934 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1936 This->smallBlockDepotChain = BlockChainStream_Construct(
1937 This,
1938 &This->smallBlockDepotStart,
1939 PROPERTY_NULL);
1942 * Write the root property
1944 if (openFlags & STGM_CREATE)
1946 StgProperty rootProp;
1948 * Initialize the property chain
1950 memset(&rootProp, 0, sizeof(rootProp));
1951 lstrcpyAtoW(rootProp.name, rootPropertyName);
1953 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
1954 rootProp.propertyType = PROPTYPE_ROOT;
1955 rootProp.previousProperty = PROPERTY_NULL;
1956 rootProp.nextProperty = PROPERTY_NULL;
1957 rootProp.dirProperty = PROPERTY_NULL;
1958 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
1959 rootProp.size.HighPart = 0;
1960 rootProp.size.LowPart = 0;
1962 StorageImpl_WriteProperty(This, 0, &rootProp);
1966 * Find the ID of the root int he property sets.
1968 currentPropertyIndex = 0;
1972 readSucessful = StorageImpl_ReadProperty(
1973 This,
1974 currentPropertyIndex,
1975 &currentProperty);
1977 if (readSucessful)
1979 if ( (currentProperty.sizeOfNameString != 0 ) &&
1980 (currentProperty.propertyType == PROPTYPE_ROOT) )
1982 This->rootPropertySetIndex = currentPropertyIndex;
1986 currentPropertyIndex++;
1988 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1990 if (!readSucessful)
1992 /* TODO CLEANUP */
1993 return E_FAIL;
1997 * Create the block chain abstraction for the small block root chain.
1999 This->smallBlockRootChain = BlockChainStream_Construct(
2000 This,
2001 NULL,
2002 This->rootPropertySetIndex);
2004 return hr;
2007 void StorageImpl_Destroy(
2008 StorageImpl* This)
2010 BlockChainStream_Destroy(This->smallBlockRootChain);
2011 BlockChainStream_Destroy(This->rootBlockChain);
2012 BlockChainStream_Destroy(This->smallBlockDepotChain);
2014 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2015 return;
2018 /******************************************************************************
2019 * Storage32Impl_GetNextFreeBigBlock
2021 * Returns the index of the next free big block.
2022 * If the big block depot is filled, this method will enlarge it.
2025 ULONG StorageImpl_GetNextFreeBigBlock(
2026 StorageImpl* This)
2028 ULONG depotBlockIndexPos;
2029 void *depotBuffer;
2030 ULONG depotBlockOffset;
2031 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2032 ULONG nextBlockIndex = BLOCK_SPECIAL;
2033 int depotIndex = 0;
2034 ULONG freeBlock = BLOCK_UNUSED;
2036 depotIndex = This->prevFreeBlock / blocksPerDepot;
2037 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2040 * Scan the entire big block depot until we find a block marked free
2042 while (nextBlockIndex != BLOCK_UNUSED)
2044 if (depotIndex < COUNT_BBDEPOTINHEADER)
2046 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2049 * Grow the primary depot.
2051 if (depotBlockIndexPos == BLOCK_UNUSED)
2053 depotBlockIndexPos = depotIndex*blocksPerDepot;
2056 * Add a block depot.
2058 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2059 This->bigBlockDepotCount++;
2060 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2063 * Flag it as a block depot.
2065 StorageImpl_SetNextBlockInChain(This,
2066 depotBlockIndexPos,
2067 BLOCK_SPECIAL);
2069 /* Save new header information.
2071 StorageImpl_SaveFileHeader(This);
2074 else
2076 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2078 if (depotBlockIndexPos == BLOCK_UNUSED)
2081 * Grow the extended depot.
2083 ULONG extIndex = BLOCK_UNUSED;
2084 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2085 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2087 if (extBlockOffset == 0)
2089 /* We need an extended block.
2091 extIndex = Storage32Impl_AddExtBlockDepot(This);
2092 This->extBigBlockDepotCount++;
2093 depotBlockIndexPos = extIndex + 1;
2095 else
2096 depotBlockIndexPos = depotIndex * blocksPerDepot;
2099 * Add a block depot and mark it in the extended block.
2101 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2102 This->bigBlockDepotCount++;
2103 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2105 /* Flag the block depot.
2107 StorageImpl_SetNextBlockInChain(This,
2108 depotBlockIndexPos,
2109 BLOCK_SPECIAL);
2111 /* If necessary, flag the extended depot block.
2113 if (extIndex != BLOCK_UNUSED)
2114 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2116 /* Save header information.
2118 StorageImpl_SaveFileHeader(This);
2122 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2124 if (depotBuffer != 0)
2126 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2127 ( nextBlockIndex != BLOCK_UNUSED))
2129 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2131 if (nextBlockIndex == BLOCK_UNUSED)
2133 freeBlock = (depotIndex * blocksPerDepot) +
2134 (depotBlockOffset/sizeof(ULONG));
2137 depotBlockOffset += sizeof(ULONG);
2140 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2143 depotIndex++;
2144 depotBlockOffset = 0;
2147 This->prevFreeBlock = freeBlock;
2149 return freeBlock;
2152 /******************************************************************************
2153 * Storage32Impl_AddBlockDepot
2155 * This will create a depot block, essentially it is a block initialized
2156 * to BLOCK_UNUSEDs.
2158 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2160 BYTE* blockBuffer;
2162 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2165 * Initialize blocks as free
2167 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2169 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2172 /******************************************************************************
2173 * Storage32Impl_GetExtDepotBlock
2175 * Returns the index of the block that corresponds to the specified depot
2176 * index. This method is only for depot indexes equal or greater than
2177 * COUNT_BBDEPOTINHEADER.
2179 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2181 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2182 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2183 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2184 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2185 ULONG blockIndex = BLOCK_UNUSED;
2186 ULONG extBlockIndex = This->extBigBlockDepotStart;
2188 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2190 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2191 return BLOCK_UNUSED;
2193 while (extBlockCount > 0)
2195 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2196 extBlockCount--;
2199 if (extBlockIndex != BLOCK_UNUSED)
2201 BYTE* depotBuffer;
2203 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2205 if (depotBuffer != 0)
2207 StorageUtl_ReadDWord(depotBuffer,
2208 extBlockOffset * sizeof(ULONG),
2209 &blockIndex);
2211 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2215 return blockIndex;
2218 /******************************************************************************
2219 * Storage32Impl_SetExtDepotBlock
2221 * Associates the specified block index to the specified depot index.
2222 * This method is only for depot indexes equal or greater than
2223 * COUNT_BBDEPOTINHEADER.
2225 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2226 ULONG depotIndex,
2227 ULONG blockIndex)
2229 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2230 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2231 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2232 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2233 ULONG extBlockIndex = This->extBigBlockDepotStart;
2235 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2237 while (extBlockCount > 0)
2239 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2240 extBlockCount--;
2243 if (extBlockIndex != BLOCK_UNUSED)
2245 BYTE* depotBuffer;
2247 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2249 if (depotBuffer != 0)
2251 StorageUtl_WriteDWord(depotBuffer,
2252 extBlockOffset * sizeof(ULONG),
2253 blockIndex);
2255 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2260 /******************************************************************************
2261 * Storage32Impl_AddExtBlockDepot
2263 * Creates an extended depot block.
2265 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2267 ULONG numExtBlocks = This->extBigBlockDepotCount;
2268 ULONG nextExtBlock = This->extBigBlockDepotStart;
2269 BYTE* depotBuffer = NULL;
2270 ULONG index = BLOCK_UNUSED;
2271 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2272 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2273 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2275 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2276 blocksPerDepotBlock;
2278 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2281 * The first extended block.
2283 This->extBigBlockDepotStart = index;
2285 else
2287 int i;
2289 * Follow the chain to the last one.
2291 for (i = 0; i < (numExtBlocks - 1); i++)
2293 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2297 * Add the new extended block to the chain.
2299 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2300 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2301 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2305 * Initialize this block.
2307 depotBuffer = StorageImpl_GetBigBlock(This, index);
2308 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2309 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2311 return index;
2314 /******************************************************************************
2315 * Storage32Impl_FreeBigBlock
2317 * This method will flag the specified block as free in the big block depot.
2319 void StorageImpl_FreeBigBlock(
2320 StorageImpl* This,
2321 ULONG blockIndex)
2323 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2325 if (blockIndex < This->prevFreeBlock)
2326 This->prevFreeBlock = blockIndex;
2329 /************************************************************************
2330 * Storage32Impl_GetNextBlockInChain
2332 * This method will retrieve the block index of the next big block in
2333 * in the chain.
2335 * Params: This - Pointer to the Storage object.
2336 * blockIndex - Index of the block to retrieve the chain
2337 * for.
2339 * Returns: This method returns the index of the next block in the chain.
2340 * It will return the constants:
2341 * BLOCK_SPECIAL - If the block given was not part of a
2342 * chain.
2343 * BLOCK_END_OF_CHAIN - If the block given was the last in
2344 * a chain.
2345 * BLOCK_UNUSED - If the block given was not past of a chain
2346 * and is available.
2347 * BLOCK_EXTBBDEPOT - This block is part of the extended
2348 * big block depot.
2350 * See Windows documentation for more details on IStorage methods.
2352 ULONG StorageImpl_GetNextBlockInChain(
2353 StorageImpl* This,
2354 ULONG blockIndex)
2356 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2357 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2358 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2359 ULONG nextBlockIndex = BLOCK_SPECIAL;
2360 void* depotBuffer;
2361 ULONG depotBlockIndexPos;
2363 assert(depotBlockCount < This->bigBlockDepotCount);
2366 * Cache the currently accessed depot block.
2368 if (depotBlockCount != This->indexBlockDepotCached)
2370 This->indexBlockDepotCached = depotBlockCount;
2372 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2374 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2376 else
2379 * We have to look in the extended depot.
2381 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2384 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2386 if (depotBuffer!=0)
2388 int index;
2390 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2392 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2393 This->blockDepotCached[index] = nextBlockIndex;
2396 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2400 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2402 return nextBlockIndex;
2405 /******************************************************************************
2406 * Storage32Impl_GetNextExtendedBlock
2408 * Given an extended block this method will return the next extended block.
2410 * NOTES:
2411 * The last ULONG of an extended block is the block index of the next
2412 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2413 * depot.
2415 * Return values:
2416 * - The index of the next extended block
2417 * - BLOCK_UNUSED: there is no next extended block.
2418 * - Any other return values denotes failure.
2420 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2422 ULONG nextBlockIndex = BLOCK_SPECIAL;
2423 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2424 void* depotBuffer;
2426 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2428 if (depotBuffer!=0)
2430 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2432 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2435 return nextBlockIndex;
2438 /******************************************************************************
2439 * Storage32Impl_SetNextBlockInChain
2441 * This method will write the index of the specified block's next block
2442 * in the big block depot.
2444 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2445 * do the following
2447 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2448 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2449 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2452 void StorageImpl_SetNextBlockInChain(
2453 StorageImpl* This,
2454 ULONG blockIndex,
2455 ULONG nextBlock)
2457 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2458 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2459 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2460 ULONG depotBlockIndexPos;
2461 void* depotBuffer;
2463 assert(depotBlockCount < This->bigBlockDepotCount);
2465 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2467 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2469 else
2472 * We have to look in the extended depot.
2474 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2477 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2479 if (depotBuffer!=0)
2481 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2482 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2486 * Update the cached block depot, if necessary.
2488 if (depotBlockCount == This->indexBlockDepotCached)
2490 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2494 /******************************************************************************
2495 * Storage32Impl_LoadFileHeader
2497 * This method will read in the file header, i.e. big block index -1.
2499 HRESULT StorageImpl_LoadFileHeader(
2500 StorageImpl* This)
2502 HRESULT hr = STG_E_FILENOTFOUND;
2503 void* headerBigBlock = NULL;
2504 int index;
2507 * Get a pointer to the big block of data containing the header.
2509 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2512 * Extract the information from the header.
2514 if (headerBigBlock!=0)
2517 * Check for the "magic number" signature and return an error if it is not
2518 * found.
2520 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2522 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2523 return STG_E_OLDFORMAT;
2526 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2528 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2529 return STG_E_INVALIDHEADER;
2532 StorageUtl_ReadWord(
2533 headerBigBlock,
2534 OFFSET_BIGBLOCKSIZEBITS,
2535 &This->bigBlockSizeBits);
2537 StorageUtl_ReadWord(
2538 headerBigBlock,
2539 OFFSET_SMALLBLOCKSIZEBITS,
2540 &This->smallBlockSizeBits);
2542 StorageUtl_ReadDWord(
2543 headerBigBlock,
2544 OFFSET_BBDEPOTCOUNT,
2545 &This->bigBlockDepotCount);
2547 StorageUtl_ReadDWord(
2548 headerBigBlock,
2549 OFFSET_ROOTSTARTBLOCK,
2550 &This->rootStartBlock);
2552 StorageUtl_ReadDWord(
2553 headerBigBlock,
2554 OFFSET_SBDEPOTSTART,
2555 &This->smallBlockDepotStart);
2557 StorageUtl_ReadDWord(
2558 headerBigBlock,
2559 OFFSET_EXTBBDEPOTSTART,
2560 &This->extBigBlockDepotStart);
2562 StorageUtl_ReadDWord(
2563 headerBigBlock,
2564 OFFSET_EXTBBDEPOTCOUNT,
2565 &This->extBigBlockDepotCount);
2567 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2569 StorageUtl_ReadDWord(
2570 headerBigBlock,
2571 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2572 &(This->bigBlockDepotStart[index]));
2576 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2578 if ((1 << 2) == 4)
2580 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2581 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2583 else
2585 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2586 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2590 * Right now, the code is making some assumptions about the size of the
2591 * blocks, just make sure they are what we're expecting.
2593 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2594 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2597 * Release the block.
2599 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2602 return hr;
2605 /******************************************************************************
2606 * Storage32Impl_SaveFileHeader
2608 * This method will save to the file the header, i.e. big block -1.
2610 void StorageImpl_SaveFileHeader(
2611 StorageImpl* This)
2613 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2614 int index;
2615 BOOL success;
2618 * Get a pointer to the big block of data containing the header.
2620 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2623 * If the block read failed, the file is probably new.
2625 if (!success)
2628 * Initialize for all unknown fields.
2630 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2633 * Initialize the magic number.
2635 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2638 * And a bunch of things we don't know what they mean
2640 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2641 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2642 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2643 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2644 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2648 * Write the information to the header.
2650 if (headerBigBlock!=0)
2652 StorageUtl_WriteWord(
2653 headerBigBlock,
2654 OFFSET_BIGBLOCKSIZEBITS,
2655 This->bigBlockSizeBits);
2657 StorageUtl_WriteWord(
2658 headerBigBlock,
2659 OFFSET_SMALLBLOCKSIZEBITS,
2660 This->smallBlockSizeBits);
2662 StorageUtl_WriteDWord(
2663 headerBigBlock,
2664 OFFSET_BBDEPOTCOUNT,
2665 This->bigBlockDepotCount);
2667 StorageUtl_WriteDWord(
2668 headerBigBlock,
2669 OFFSET_ROOTSTARTBLOCK,
2670 This->rootStartBlock);
2672 StorageUtl_WriteDWord(
2673 headerBigBlock,
2674 OFFSET_SBDEPOTSTART,
2675 This->smallBlockDepotStart);
2677 StorageUtl_WriteDWord(
2678 headerBigBlock,
2679 OFFSET_EXTBBDEPOTSTART,
2680 This->extBigBlockDepotStart);
2682 StorageUtl_WriteDWord(
2683 headerBigBlock,
2684 OFFSET_EXTBBDEPOTCOUNT,
2685 This->extBigBlockDepotCount);
2687 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2689 StorageUtl_WriteDWord(
2690 headerBigBlock,
2691 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2692 (This->bigBlockDepotStart[index]));
2697 * Write the big block back to the file.
2699 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2702 /******************************************************************************
2703 * Storage32Impl_ReadProperty
2705 * This method will read the specified property from the property chain.
2707 BOOL StorageImpl_ReadProperty(
2708 StorageImpl* This,
2709 ULONG index,
2710 StgProperty* buffer)
2712 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2713 ULARGE_INTEGER offsetInPropSet;
2714 BOOL readSucessful;
2715 ULONG bytesRead;
2717 offsetInPropSet.HighPart = 0;
2718 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2720 readSucessful = BlockChainStream_ReadAt(
2721 This->rootBlockChain,
2722 offsetInPropSet,
2723 PROPSET_BLOCK_SIZE,
2724 currentProperty,
2725 &bytesRead);
2727 if (readSucessful)
2729 memset(buffer->name, 0, sizeof(buffer->name));
2730 memcpy(
2731 buffer->name,
2732 currentProperty+OFFSET_PS_NAME,
2733 PROPERTY_NAME_BUFFER_LEN );
2735 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2737 StorageUtl_ReadWord(
2738 currentProperty,
2739 OFFSET_PS_NAMELENGTH,
2740 &buffer->sizeOfNameString);
2742 StorageUtl_ReadDWord(
2743 currentProperty,
2744 OFFSET_PS_PREVIOUSPROP,
2745 &buffer->previousProperty);
2747 StorageUtl_ReadDWord(
2748 currentProperty,
2749 OFFSET_PS_NEXTPROP,
2750 &buffer->nextProperty);
2752 StorageUtl_ReadDWord(
2753 currentProperty,
2754 OFFSET_PS_DIRPROP,
2755 &buffer->dirProperty);
2757 StorageUtl_ReadGUID(
2758 currentProperty,
2759 OFFSET_PS_GUID,
2760 &buffer->propertyUniqueID);
2762 StorageUtl_ReadDWord(
2763 currentProperty,
2764 OFFSET_PS_TSS1,
2765 &buffer->timeStampS1);
2767 StorageUtl_ReadDWord(
2768 currentProperty,
2769 OFFSET_PS_TSD1,
2770 &buffer->timeStampD1);
2772 StorageUtl_ReadDWord(
2773 currentProperty,
2774 OFFSET_PS_TSS2,
2775 &buffer->timeStampS2);
2777 StorageUtl_ReadDWord(
2778 currentProperty,
2779 OFFSET_PS_TSD2,
2780 &buffer->timeStampD2);
2782 StorageUtl_ReadDWord(
2783 currentProperty,
2784 OFFSET_PS_STARTBLOCK,
2785 &buffer->startingBlock);
2787 StorageUtl_ReadDWord(
2788 currentProperty,
2789 OFFSET_PS_SIZE,
2790 &buffer->size.LowPart);
2792 buffer->size.HighPart = 0;
2795 return readSucessful;
2798 /*********************************************************************
2799 * Write the specified property into the property chain
2801 BOOL StorageImpl_WriteProperty(
2802 StorageImpl* This,
2803 ULONG index,
2804 StgProperty* buffer)
2806 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2807 ULARGE_INTEGER offsetInPropSet;
2808 BOOL writeSucessful;
2809 ULONG bytesWritten;
2811 offsetInPropSet.HighPart = 0;
2812 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2814 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2816 memcpy(
2817 currentProperty + OFFSET_PS_NAME,
2818 buffer->name,
2819 PROPERTY_NAME_BUFFER_LEN );
2821 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2824 * Reassign the size in case of mistake....
2826 buffer->sizeOfNameString = (lstrlenW(buffer->name)+1) * sizeof(WCHAR);
2828 StorageUtl_WriteWord(
2829 currentProperty,
2830 OFFSET_PS_NAMELENGTH,
2831 buffer->sizeOfNameString);
2833 StorageUtl_WriteDWord(
2834 currentProperty,
2835 OFFSET_PS_PREVIOUSPROP,
2836 buffer->previousProperty);
2838 StorageUtl_WriteDWord(
2839 currentProperty,
2840 OFFSET_PS_NEXTPROP,
2841 buffer->nextProperty);
2843 StorageUtl_WriteDWord(
2844 currentProperty,
2845 OFFSET_PS_DIRPROP,
2846 buffer->dirProperty);
2848 StorageUtl_WriteGUID(
2849 currentProperty,
2850 OFFSET_PS_GUID,
2851 &buffer->propertyUniqueID);
2853 StorageUtl_WriteDWord(
2854 currentProperty,
2855 OFFSET_PS_TSS1,
2856 buffer->timeStampS1);
2858 StorageUtl_WriteDWord(
2859 currentProperty,
2860 OFFSET_PS_TSD1,
2861 buffer->timeStampD1);
2863 StorageUtl_WriteDWord(
2864 currentProperty,
2865 OFFSET_PS_TSS2,
2866 buffer->timeStampS2);
2868 StorageUtl_WriteDWord(
2869 currentProperty,
2870 OFFSET_PS_TSD2,
2871 buffer->timeStampD2);
2873 StorageUtl_WriteDWord(
2874 currentProperty,
2875 OFFSET_PS_STARTBLOCK,
2876 buffer->startingBlock);
2878 StorageUtl_WriteDWord(
2879 currentProperty,
2880 OFFSET_PS_SIZE,
2881 buffer->size.LowPart);
2883 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2884 offsetInPropSet,
2885 PROPSET_BLOCK_SIZE,
2886 currentProperty,
2887 &bytesWritten);
2888 return writeSucessful;
2891 BOOL StorageImpl_ReadBigBlock(
2892 StorageImpl* This,
2893 ULONG blockIndex,
2894 void* buffer)
2896 void* bigBlockBuffer;
2898 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2900 if (bigBlockBuffer!=0)
2902 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2904 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2906 return TRUE;
2909 return FALSE;
2912 BOOL StorageImpl_WriteBigBlock(
2913 StorageImpl* This,
2914 ULONG blockIndex,
2915 void* buffer)
2917 void* bigBlockBuffer;
2919 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2921 if (bigBlockBuffer!=0)
2923 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2925 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2927 return TRUE;
2930 return FALSE;
2933 void* StorageImpl_GetROBigBlock(
2934 StorageImpl* This,
2935 ULONG blockIndex)
2937 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2940 void* StorageImpl_GetBigBlock(
2941 StorageImpl* This,
2942 ULONG blockIndex)
2944 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2947 void StorageImpl_ReleaseBigBlock(
2948 StorageImpl* This,
2949 void* pBigBlock)
2951 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2954 /******************************************************************************
2955 * Storage32Impl_SmallBlocksToBigBlocks
2957 * This method will convert a small block chain to a big block chain.
2958 * The small block chain will be destroyed.
2960 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2961 StorageImpl* This,
2962 SmallBlockChainStream** ppsbChain)
2964 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2965 ULARGE_INTEGER size, offset;
2966 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
2967 ULONG propertyIndex;
2968 BOOL successRead, successWrite;
2969 StgProperty chainProperty;
2970 BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2971 BlockChainStream *bbTempChain = NULL;
2972 BlockChainStream *bigBlockChain = NULL;
2975 * Create a temporary big block chain that doesn't have
2976 * an associated property. This temporary chain will be
2977 * used to copy data from small blocks to big blocks.
2979 bbTempChain = BlockChainStream_Construct(This,
2980 &bbHeadOfChain,
2981 PROPERTY_NULL);
2984 * Grow the big block chain.
2986 size = SmallBlockChainStream_GetSize(*ppsbChain);
2987 BlockChainStream_SetSize(bbTempChain, size);
2990 * Copy the contents of the small block chain to the big block chain
2991 * by small block size increments.
2993 offset.LowPart = 0;
2994 offset.HighPart = 0;
2995 cbTotalRead = 0;
2996 cbTotalWritten = 0;
3000 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3001 offset,
3002 sizeof(buffer),
3003 buffer,
3004 &cbRead);
3005 cbTotalRead += cbRead;
3007 successWrite = BlockChainStream_WriteAt(bbTempChain,
3008 offset,
3009 cbRead,
3010 buffer,
3011 &cbWritten);
3012 cbTotalWritten += cbWritten;
3014 offset.LowPart += This->smallBlockSize;
3016 } while (successRead && successWrite);
3018 assert(cbTotalRead == cbTotalWritten);
3021 * Destroy the small block chain.
3023 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3024 size.HighPart = 0;
3025 size.LowPart = 0;
3026 SmallBlockChainStream_SetSize(*ppsbChain, size);
3027 SmallBlockChainStream_Destroy(*ppsbChain);
3028 *ppsbChain = 0;
3031 * Change the property information. This chain is now a big block chain
3032 * and it doesn't reside in the small blocks chain anymore.
3034 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3036 chainProperty.startingBlock = bbHeadOfChain;
3038 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3041 * Destroy the temporary propertyless big block chain.
3042 * Create a new big block chain associated with this property.
3044 BlockChainStream_Destroy(bbTempChain);
3045 bigBlockChain = BlockChainStream_Construct(This,
3046 NULL,
3047 propertyIndex);
3049 return bigBlockChain;
3052 /******************************************************************************
3053 ** Storage32InternalImpl implementation
3056 StorageInternalImpl* StorageInternalImpl_Construct(
3057 StorageImpl* ancestorStorage,
3058 ULONG rootPropertyIndex)
3060 StorageInternalImpl* newStorage;
3063 * Allocate space for the new storage object
3065 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3067 if (newStorage!=0)
3069 memset(newStorage, 0, sizeof(StorageInternalImpl));
3072 * Initialize the virtual function table.
3074 newStorage->lpvtbl = &Storage32InternalImpl_Vtbl;
3075 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3078 * Keep the ancestor storage pointer and nail a reference to it.
3080 newStorage->ancestorStorage = ancestorStorage;
3081 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3084 * Keep the index of the root property set for this storage,
3086 newStorage->rootPropertySetIndex = rootPropertyIndex;
3088 return newStorage;
3091 return 0;
3094 void StorageInternalImpl_Destroy(
3095 StorageInternalImpl* This)
3097 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3098 HeapFree(GetProcessHeap(), 0, This);
3101 /******************************************************************************
3103 ** Storage32InternalImpl_Commit
3105 ** The non-root storages cannot be opened in transacted mode thus this function
3106 ** does nothing.
3108 HRESULT WINAPI StorageInternalImpl_Commit(
3109 IStorage* iface,
3110 DWORD grfCommitFlags) /* [in] */
3112 return S_OK;
3115 /******************************************************************************
3117 ** Storage32InternalImpl_Revert
3119 ** The non-root storages cannot be opened in transacted mode thus this function
3120 ** does nothing.
3122 HRESULT WINAPI StorageInternalImpl_Revert(
3123 IStorage* iface)
3125 return S_OK;
3128 /******************************************************************************
3129 ** IEnumSTATSTGImpl implementation
3132 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3133 StorageImpl* parentStorage,
3134 ULONG firstPropertyNode)
3136 IEnumSTATSTGImpl* newEnumeration;
3138 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3140 if (newEnumeration!=0)
3143 * Set-up the virtual function table and reference count.
3145 newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
3146 newEnumeration->ref = 0;
3149 * We want to nail-down the reference to the storage in case the
3150 * enumeration out-lives the storage in the client application.
3152 newEnumeration->parentStorage = parentStorage;
3153 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3155 newEnumeration->firstPropertyNode = firstPropertyNode;
3158 * Initialize the search stack
3160 newEnumeration->stackSize = 0;
3161 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3162 newEnumeration->stackToVisit =
3163 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3166 * Make sure the current node of the iterator is the first one.
3168 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3171 return newEnumeration;
3174 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3176 IStorage_Release((IStorage*)This->parentStorage);
3177 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3178 HeapFree(GetProcessHeap(), 0, This);
3181 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3182 IEnumSTATSTG* iface,
3183 REFIID riid,
3184 void** ppvObject)
3186 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3189 * Perform a sanity check on the parameters.
3191 if (ppvObject==0)
3192 return E_INVALIDARG;
3195 * Initialize the return parameter.
3197 *ppvObject = 0;
3200 * Compare the riid with the interface IDs implemented by this object.
3202 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3204 *ppvObject = (IEnumSTATSTG*)This;
3206 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3208 *ppvObject = (IEnumSTATSTG*)This;
3212 * Check that we obtained an interface.
3214 if ((*ppvObject)==0)
3215 return E_NOINTERFACE;
3218 * Query Interface always increases the reference count by one when it is
3219 * successful
3221 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3223 return S_OK;
3226 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3227 IEnumSTATSTG* iface)
3229 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3231 This->ref++;
3232 return This->ref;
3235 ULONG WINAPI IEnumSTATSTGImpl_Release(
3236 IEnumSTATSTG* iface)
3238 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3240 ULONG newRef;
3242 This->ref--;
3243 newRef = This->ref;
3246 * If the reference count goes down to 0, perform suicide.
3248 if (newRef==0)
3250 IEnumSTATSTGImpl_Destroy(This);
3253 return newRef;;
3256 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3257 IEnumSTATSTG* iface,
3258 ULONG celt,
3259 STATSTG* rgelt,
3260 ULONG* pceltFetched)
3262 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3264 StgProperty currentProperty;
3265 STATSTG* currentReturnStruct = rgelt;
3266 ULONG objectFetched = 0;
3267 ULONG currentSearchNode;
3270 * Perform a sanity check on the parameters.
3272 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3273 return E_INVALIDARG;
3276 * To avoid the special case, get another pointer to a ULONG value if
3277 * the caller didn't supply one.
3279 if (pceltFetched==0)
3280 pceltFetched = &objectFetched;
3283 * Start the iteration, we will iterate until we hit the end of the
3284 * linked list or until we hit the number of items to iterate through
3286 *pceltFetched = 0;
3289 * Start with the node at the top of the stack.
3291 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3293 while ( ( *pceltFetched < celt) &&
3294 ( currentSearchNode!=PROPERTY_NULL) )
3297 * Remove the top node from the stack
3299 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3302 * Read the property from the storage.
3304 StorageImpl_ReadProperty(This->parentStorage,
3305 currentSearchNode,
3306 &currentProperty);
3309 * Copy the information to the return buffer.
3311 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3312 &currentProperty,
3313 STATFLAG_DEFAULT);
3316 * Step to the next item in the iteration
3318 (*pceltFetched)++;
3319 currentReturnStruct++;
3322 * Push the next search node in the search stack.
3324 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3327 * continue the iteration.
3329 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3332 if (*pceltFetched == celt)
3333 return S_OK;
3335 return S_FALSE;
3339 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3340 IEnumSTATSTG* iface,
3341 ULONG celt)
3343 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3345 StgProperty currentProperty;
3346 ULONG objectFetched = 0;
3347 ULONG currentSearchNode;
3350 * Start with the node at the top of the stack.
3352 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3354 while ( (objectFetched < celt) &&
3355 (currentSearchNode!=PROPERTY_NULL) )
3358 * Remove the top node from the stack
3360 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3363 * Read the property from the storage.
3365 StorageImpl_ReadProperty(This->parentStorage,
3366 currentSearchNode,
3367 &currentProperty);
3370 * Step to the next item in the iteration
3372 objectFetched++;
3375 * Push the next search node in the search stack.
3377 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3380 * continue the iteration.
3382 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3385 if (objectFetched == celt)
3386 return S_OK;
3388 return S_FALSE;
3391 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3392 IEnumSTATSTG* iface)
3394 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3396 StgProperty rootProperty;
3397 BOOL readSucessful;
3400 * Re-initialize the search stack to an empty stack
3402 This->stackSize = 0;
3405 * Read the root property from the storage.
3407 readSucessful = StorageImpl_ReadProperty(
3408 This->parentStorage,
3409 This->firstPropertyNode,
3410 &rootProperty);
3412 if (readSucessful)
3414 assert(rootProperty.sizeOfNameString!=0);
3417 * Push the search node in the search stack.
3419 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3422 return S_OK;
3425 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3426 IEnumSTATSTG* iface,
3427 IEnumSTATSTG** ppenum)
3429 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3431 IEnumSTATSTGImpl* newClone;
3434 * Perform a sanity check on the parameters.
3436 if (ppenum==0)
3437 return E_INVALIDARG;
3439 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3440 This->firstPropertyNode);
3444 * The new clone enumeration must point to the same current node as
3445 * the ole one.
3447 newClone->stackSize = This->stackSize ;
3448 newClone->stackMaxSize = This->stackMaxSize ;
3449 newClone->stackToVisit =
3450 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3452 memcpy(
3453 newClone->stackToVisit,
3454 This->stackToVisit,
3455 sizeof(ULONG) * newClone->stackSize);
3457 *ppenum = (IEnumSTATSTG*)newClone;
3460 * Don't forget to nail down a reference to the clone before
3461 * returning it.
3463 IEnumSTATSTGImpl_AddRef(*ppenum);
3465 return S_OK;
3468 INT IEnumSTATSTGImpl_FindParentProperty(
3469 IEnumSTATSTGImpl *This,
3470 ULONG childProperty,
3471 StgProperty *currentProperty,
3472 ULONG *thisNodeId)
3474 ULONG currentSearchNode;
3475 ULONG foundNode;
3478 * To avoid the special case, get another pointer to a ULONG value if
3479 * the caller didn't supply one.
3481 if (thisNodeId==0)
3482 thisNodeId = &foundNode;
3485 * Start with the node at the top of the stack.
3487 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3490 while (currentSearchNode!=PROPERTY_NULL)
3493 * Store the current node in the returned parameters
3495 *thisNodeId = currentSearchNode;
3498 * Remove the top node from the stack
3500 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3503 * Read the property from the storage.
3505 StorageImpl_ReadProperty(
3506 This->parentStorage,
3507 currentSearchNode,
3508 currentProperty);
3510 if (currentProperty->previousProperty == childProperty)
3511 return PROPERTY_RELATION_PREVIOUS;
3513 else if (currentProperty->nextProperty == childProperty)
3514 return PROPERTY_RELATION_NEXT;
3516 else if (currentProperty->dirProperty == childProperty)
3517 return PROPERTY_RELATION_DIR;
3520 * Push the next search node in the search stack.
3522 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3525 * continue the iteration.
3527 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3530 return PROPERTY_NULL;
3533 ULONG IEnumSTATSTGImpl_FindProperty(
3534 IEnumSTATSTGImpl* This,
3535 const OLECHAR* lpszPropName,
3536 StgProperty* currentProperty)
3538 ULONG currentSearchNode;
3541 * Start with the node at the top of the stack.
3543 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3545 while (currentSearchNode!=PROPERTY_NULL)
3548 * Remove the top node from the stack
3550 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3553 * Read the property from the storage.
3555 StorageImpl_ReadProperty(This->parentStorage,
3556 currentSearchNode,
3557 currentProperty);
3559 if ( propertyNameCmp(
3560 (OLECHAR*)currentProperty->name,
3561 (OLECHAR*)lpszPropName) == 0)
3562 return currentSearchNode;
3565 * Push the next search node in the search stack.
3567 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3570 * continue the iteration.
3572 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3575 return PROPERTY_NULL;
3578 void IEnumSTATSTGImpl_PushSearchNode(
3579 IEnumSTATSTGImpl* This,
3580 ULONG nodeToPush)
3582 StgProperty rootProperty;
3583 BOOL readSucessful;
3586 * First, make sure we're not trying to push an unexisting node.
3588 if (nodeToPush==PROPERTY_NULL)
3589 return;
3592 * First push the node to the stack
3594 if (This->stackSize == This->stackMaxSize)
3596 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3598 This->stackToVisit = HeapReAlloc(
3599 GetProcessHeap(),
3601 This->stackToVisit,
3602 sizeof(ULONG) * This->stackMaxSize);
3605 This->stackToVisit[This->stackSize] = nodeToPush;
3606 This->stackSize++;
3609 * Read the root property from the storage.
3611 readSucessful = StorageImpl_ReadProperty(
3612 This->parentStorage,
3613 nodeToPush,
3614 &rootProperty);
3616 if (readSucessful)
3618 assert(rootProperty.sizeOfNameString!=0);
3621 * Push the previous search node in the search stack.
3623 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3627 ULONG IEnumSTATSTGImpl_PopSearchNode(
3628 IEnumSTATSTGImpl* This,
3629 BOOL remove)
3631 ULONG topNode;
3633 if (This->stackSize == 0)
3634 return PROPERTY_NULL;
3636 topNode = This->stackToVisit[This->stackSize-1];
3638 if (remove)
3639 This->stackSize--;
3641 return topNode;
3644 /******************************************************************************
3645 ** StorageUtl implementation
3648 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3650 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3653 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3655 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3658 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3660 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3663 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3665 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3668 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3670 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3671 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3672 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3674 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3677 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3679 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3680 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3681 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3683 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3686 void StorageUtl_CopyPropertyToSTATSTG(
3687 STATSTG* destination,
3688 StgProperty* source,
3689 int statFlags)
3692 * The copy of the string occurs only when the flag is not set
3694 if ((statFlags & STATFLAG_NONAME) != 0)
3696 destination->pwcsName = 0;
3698 else
3700 destination->pwcsName =
3701 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3703 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3706 switch (source->propertyType)
3708 case PROPTYPE_STORAGE:
3709 case PROPTYPE_ROOT:
3710 destination->type = STGTY_STORAGE;
3711 break;
3712 case PROPTYPE_STREAM:
3713 destination->type = STGTY_STREAM;
3714 break;
3715 default:
3716 destination->type = STGTY_STREAM;
3717 break;
3720 destination->cbSize = source->size;
3722 currentReturnStruct->mtime = {0}; TODO
3723 currentReturnStruct->ctime = {0};
3724 currentReturnStruct->atime = {0};
3726 destination->grfMode = 0;
3727 destination->grfLocksSupported = 0;
3728 destination->clsid = source->propertyUniqueID;
3729 destination->grfStateBits = 0;
3730 destination->reserved = 0;
3733 /******************************************************************************
3734 ** BlockChainStream implementation
3737 BlockChainStream* BlockChainStream_Construct(
3738 StorageImpl* parentStorage,
3739 ULONG* headOfStreamPlaceHolder,
3740 ULONG propertyIndex)
3742 BlockChainStream* newStream;
3744 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3746 newStream->parentStorage = parentStorage;
3747 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3748 newStream->ownerPropertyIndex = propertyIndex;
3750 return newStream;
3753 void BlockChainStream_Destroy(BlockChainStream* This)
3755 HeapFree(GetProcessHeap(), 0, This);
3758 /******************************************************************************
3759 * BlockChainStream_GetHeadOfChain
3761 * Returns the head of this stream chain.
3762 * Some special chains don't have properties, their heads are kept in
3763 * This->headOfStreamPlaceHolder.
3766 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3768 StgProperty chainProperty;
3769 BOOL readSucessful;
3771 if (This->headOfStreamPlaceHolder != 0)
3772 return *(This->headOfStreamPlaceHolder);
3774 if (This->ownerPropertyIndex != PROPERTY_NULL)
3776 readSucessful = StorageImpl_ReadProperty(
3777 This->parentStorage,
3778 This->ownerPropertyIndex,
3779 &chainProperty);
3781 if (readSucessful)
3783 return chainProperty.startingBlock;
3787 return BLOCK_END_OF_CHAIN;
3790 /******************************************************************************
3791 * BlockChainStream_GetCount
3793 * Returns the number of blocks that comprises this chain.
3794 * This is not the size of the stream as the last block may not be full!
3797 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3799 ULONG blockIndex;
3800 ULONG count = 0;
3802 blockIndex = BlockChainStream_GetHeadOfChain(This);
3804 while (blockIndex != BLOCK_END_OF_CHAIN)
3806 count++;
3808 blockIndex = StorageImpl_GetNextBlockInChain(
3809 This->parentStorage,
3810 blockIndex);
3813 return count;
3816 /******************************************************************************
3817 * BlockChainStream_ReadAt
3819 * Reads a specified number of bytes from this chain at the specified offset.
3820 * bytesRead may be NULL.
3821 * Failure will be returned if the specified number of bytes has not been read.
3823 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
3824 ULARGE_INTEGER offset,
3825 ULONG size,
3826 void* buffer,
3827 ULONG* bytesRead)
3829 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3830 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3831 ULONG bytesToReadInBuffer;
3832 ULONG blockIndex;
3833 BYTE* bufferWalker;
3834 BYTE* bigBlockBuffer;
3837 * Find the first block in the stream that contains part of the buffer.
3839 blockIndex = BlockChainStream_GetHeadOfChain(This);
3841 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3843 blockIndex =
3844 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3846 blockNoInSequence--;
3850 * Start reading the buffer.
3852 *bytesRead = 0;
3853 bufferWalker = buffer;
3855 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3858 * Calculate how many bytes we can copy from this big block.
3860 bytesToReadInBuffer =
3861 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3864 * Copy those bytes to the buffer
3866 bigBlockBuffer =
3867 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
3869 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3871 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3874 * Step to the next big block.
3876 blockIndex =
3877 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3879 bufferWalker += bytesToReadInBuffer;
3880 size -= bytesToReadInBuffer;
3881 *bytesRead += bytesToReadInBuffer;
3882 offsetInBlock = 0; /* There is no offset on the next block */
3886 return (size == 0);
3889 /******************************************************************************
3890 * BlockChainStream_WriteAt
3892 * Writes the specified number of bytes to this chain at the specified offset.
3893 * bytesWritten may be NULL.
3894 * Will fail if not all specified number of bytes have been written.
3896 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
3897 ULARGE_INTEGER offset,
3898 ULONG size,
3899 const void* buffer,
3900 ULONG* bytesWritten)
3902 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3903 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3904 ULONG bytesToWrite;
3905 ULONG blockIndex;
3906 BYTE* bufferWalker;
3907 BYTE* bigBlockBuffer;
3910 * Find the first block in the stream that contains part of the buffer.
3912 blockIndex = BlockChainStream_GetHeadOfChain(This);
3914 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3916 blockIndex =
3917 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3919 blockNoInSequence--;
3923 * Here, I'm casting away the constness on the buffer variable
3924 * This is OK since we don't intend to modify that buffer.
3926 *bytesWritten = 0;
3927 bufferWalker = (BYTE*)buffer;
3929 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3932 * Calculate how many bytes we can copy from this big block.
3934 bytesToWrite =
3935 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3938 * Copy those bytes to the buffer
3940 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
3942 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
3944 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3947 * Step to the next big block.
3949 blockIndex =
3950 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3952 bufferWalker += bytesToWrite;
3953 size -= bytesToWrite;
3954 *bytesWritten += bytesToWrite;
3955 offsetInBlock = 0; /* There is no offset on the next block */
3958 return (size == 0);
3961 /******************************************************************************
3962 * BlockChainStream_Shrink
3964 * Shrinks this chain in the big block depot.
3966 BOOL BlockChainStream_Shrink(BlockChainStream* This,
3967 ULARGE_INTEGER newSize)
3969 ULONG blockIndex, extraBlock;
3970 ULONG numBlocks;
3971 ULONG count = 1;
3974 * Figure out how many blocks are needed to contain the new size
3976 numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3978 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3979 numBlocks++;
3981 blockIndex = BlockChainStream_GetHeadOfChain(This);
3984 * Go to the new end of chain
3986 while (count < numBlocks)
3988 blockIndex =
3989 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3991 count++;
3994 /* Get the next block before marking the new end */
3995 extraBlock =
3996 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3998 /* Mark the new end of chain */
3999 StorageImpl_SetNextBlockInChain(
4000 This->parentStorage,
4001 blockIndex,
4002 BLOCK_END_OF_CHAIN);
4005 * Mark the extra blocks as free
4007 while (extraBlock != BLOCK_END_OF_CHAIN)
4009 blockIndex =
4010 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4012 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4013 extraBlock = blockIndex;
4016 return TRUE;
4019 /******************************************************************************
4020 * BlockChainStream_Enlarge
4022 * Grows this chain in the big block depot.
4024 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4025 ULARGE_INTEGER newSize)
4027 ULONG blockIndex, currentBlock;
4028 ULONG newNumBlocks;
4029 ULONG oldNumBlocks = 0;
4031 blockIndex = BlockChainStream_GetHeadOfChain(This);
4034 * Empty chain. Create the head.
4036 if (blockIndex == BLOCK_END_OF_CHAIN)
4038 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4039 StorageImpl_SetNextBlockInChain(This->parentStorage,
4040 blockIndex,
4041 BLOCK_END_OF_CHAIN);
4043 if (This->headOfStreamPlaceHolder != 0)
4045 *(This->headOfStreamPlaceHolder) = blockIndex;
4047 else
4049 StgProperty chainProp;
4050 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4052 StorageImpl_ReadProperty(
4053 This->parentStorage,
4054 This->ownerPropertyIndex,
4055 &chainProp);
4057 chainProp.startingBlock = blockIndex;
4059 StorageImpl_WriteProperty(
4060 This->parentStorage,
4061 This->ownerPropertyIndex,
4062 &chainProp);
4066 currentBlock = blockIndex;
4069 * Figure out how many blocks are needed to contain this stream
4071 newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
4073 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
4074 newNumBlocks++;
4077 * Go to the current end of chain
4079 while (blockIndex != BLOCK_END_OF_CHAIN)
4081 oldNumBlocks++;
4082 currentBlock = blockIndex;
4084 blockIndex =
4085 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4089 * Add new blocks to the chain
4091 while (oldNumBlocks < newNumBlocks)
4093 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4095 StorageImpl_SetNextBlockInChain(
4096 This->parentStorage,
4097 currentBlock,
4098 blockIndex);
4100 StorageImpl_SetNextBlockInChain(
4101 This->parentStorage,
4102 blockIndex,
4103 BLOCK_END_OF_CHAIN);
4105 currentBlock = blockIndex;
4106 oldNumBlocks++;
4109 return TRUE;
4112 /******************************************************************************
4113 * BlockChainStream_SetSize
4115 * Sets the size of this stream. The big block depot will be updated.
4116 * The file will grow if we grow the chain.
4118 * TODO: Free the actual blocks in the file when we shrink the chain.
4119 * Currently, the blocks are still in the file. So the file size
4120 * doesn't shrink even if we shrink streams.
4122 BOOL BlockChainStream_SetSize(
4123 BlockChainStream* This,
4124 ULARGE_INTEGER newSize)
4126 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4128 if (newSize.LowPart == size.LowPart)
4129 return TRUE;
4131 if (newSize.LowPart < size.LowPart)
4133 BlockChainStream_Shrink(This, newSize);
4135 else
4137 ULARGE_INTEGER fileSize =
4138 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4140 ULONG diff = newSize.LowPart - size.LowPart;
4143 * Make sure the file stays a multiple of blocksize
4145 if ((diff % This->parentStorage->bigBlockSize) != 0)
4146 diff += (This->parentStorage->bigBlockSize -
4147 (diff % This->parentStorage->bigBlockSize) );
4149 fileSize.LowPart += diff;
4150 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4152 BlockChainStream_Enlarge(This, newSize);
4155 return TRUE;
4158 /******************************************************************************
4159 * BlockChainStream_GetSize
4161 * Returns the size of this chain.
4162 * Will return the block count if this chain doesn't have a property.
4164 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4166 StgProperty chainProperty;
4168 if(This->headOfStreamPlaceHolder == NULL)
4171 * This chain is a data stream read the property and return
4172 * the appropriate size
4174 StorageImpl_ReadProperty(
4175 This->parentStorage,
4176 This->ownerPropertyIndex,
4177 &chainProperty);
4179 return chainProperty.size;
4181 else
4184 * this chain is a chain that does not have a property, figure out the
4185 * size by making the product number of used blocks times the
4186 * size of them
4188 ULARGE_INTEGER result;
4189 result.HighPart = 0;
4191 result.LowPart =
4192 BlockChainStream_GetCount(This) *
4193 This->parentStorage->bigBlockSize;
4195 return result;
4199 /******************************************************************************
4200 ** SmallBlockChainStream implementation
4203 SmallBlockChainStream* SmallBlockChainStream_Construct(
4204 StorageImpl* parentStorage,
4205 ULONG propertyIndex)
4207 SmallBlockChainStream* newStream;
4209 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4211 newStream->parentStorage = parentStorage;
4212 newStream->ownerPropertyIndex = propertyIndex;
4214 return newStream;
4217 void SmallBlockChainStream_Destroy(
4218 SmallBlockChainStream* This)
4220 HeapFree(GetProcessHeap(), 0, This);
4223 /******************************************************************************
4224 * SmallBlockChainStream_GetHeadOfChain
4226 * Returns the head of this chain of small blocks.
4228 ULONG SmallBlockChainStream_GetHeadOfChain(
4229 SmallBlockChainStream* This)
4231 StgProperty chainProperty;
4232 BOOL readSucessful;
4234 if (This->ownerPropertyIndex)
4236 readSucessful = StorageImpl_ReadProperty(
4237 This->parentStorage,
4238 This->ownerPropertyIndex,
4239 &chainProperty);
4241 if (readSucessful)
4243 return chainProperty.startingBlock;
4248 return BLOCK_END_OF_CHAIN;
4251 /******************************************************************************
4252 * SmallBlockChainStream_GetNextBlockInChain
4254 * Returns the index of the next small block in this chain.
4256 * Return Values:
4257 * - BLOCK_END_OF_CHAIN: end of this chain
4258 * - BLOCK_UNUSED: small block 'blockIndex' is free
4260 ULONG SmallBlockChainStream_GetNextBlockInChain(
4261 SmallBlockChainStream* This,
4262 ULONG blockIndex)
4264 ULARGE_INTEGER offsetOfBlockInDepot;
4265 DWORD buffer;
4266 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4267 ULONG bytesRead;
4268 BOOL success;
4270 offsetOfBlockInDepot.HighPart = 0;
4271 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4274 * Read those bytes in the buffer from the small block file.
4276 success = BlockChainStream_ReadAt(
4277 This->parentStorage->smallBlockDepotChain,
4278 offsetOfBlockInDepot,
4279 sizeof(DWORD),
4280 &buffer,
4281 &bytesRead);
4283 if (success)
4285 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4288 return nextBlockInChain;
4291 /******************************************************************************
4292 * SmallBlockChainStream_SetNextBlockInChain
4294 * Writes the index of the next block of the specified block in the small
4295 * block depot.
4296 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4297 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4299 void SmallBlockChainStream_SetNextBlockInChain(
4300 SmallBlockChainStream* This,
4301 ULONG blockIndex,
4302 ULONG nextBlock)
4304 ULARGE_INTEGER offsetOfBlockInDepot;
4305 DWORD buffer;
4306 ULONG bytesWritten;
4308 offsetOfBlockInDepot.HighPart = 0;
4309 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4311 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4314 * Read those bytes in the buffer from the small block file.
4316 BlockChainStream_WriteAt(
4317 This->parentStorage->smallBlockDepotChain,
4318 offsetOfBlockInDepot,
4319 sizeof(DWORD),
4320 &buffer,
4321 &bytesWritten);
4324 /******************************************************************************
4325 * SmallBlockChainStream_FreeBlock
4327 * Flag small block 'blockIndex' as free in the small block depot.
4329 void SmallBlockChainStream_FreeBlock(
4330 SmallBlockChainStream* This,
4331 ULONG blockIndex)
4333 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4336 /******************************************************************************
4337 * SmallBlockChainStream_GetNextFreeBlock
4339 * Returns the index of a free small block. The small block depot will be
4340 * enlarged if necessary. The small block chain will also be enlarged if
4341 * necessary.
4343 ULONG SmallBlockChainStream_GetNextFreeBlock(
4344 SmallBlockChainStream* This)
4346 ULARGE_INTEGER offsetOfBlockInDepot;
4347 DWORD buffer;
4348 ULONG bytesRead;
4349 ULONG blockIndex = 0;
4350 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4351 BOOL success = TRUE;
4352 ULONG smallBlocksPerBigBlock;
4354 offsetOfBlockInDepot.HighPart = 0;
4357 * Scan the small block depot for a free block
4359 while (nextBlockIndex != BLOCK_UNUSED)
4361 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4363 success = BlockChainStream_ReadAt(
4364 This->parentStorage->smallBlockDepotChain,
4365 offsetOfBlockInDepot,
4366 sizeof(DWORD),
4367 &buffer,
4368 &bytesRead);
4371 * If we run out of space for the small block depot, enlarge it
4373 if (success)
4375 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4377 if (nextBlockIndex != BLOCK_UNUSED)
4378 blockIndex++;
4380 else
4382 ULONG count =
4383 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4385 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4386 ULONG nextBlock, newsbdIndex;
4387 BYTE* smallBlockDepot;
4389 nextBlock = sbdIndex;
4390 while (nextBlock != BLOCK_END_OF_CHAIN)
4392 sbdIndex = nextBlock;
4393 nextBlock =
4394 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4397 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4398 if (sbdIndex != BLOCK_END_OF_CHAIN)
4399 StorageImpl_SetNextBlockInChain(
4400 This->parentStorage,
4401 sbdIndex,
4402 newsbdIndex);
4404 StorageImpl_SetNextBlockInChain(
4405 This->parentStorage,
4406 newsbdIndex,
4407 BLOCK_END_OF_CHAIN);
4410 * Initialize all the small blocks to free
4412 smallBlockDepot =
4413 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4415 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4416 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4418 if (count == 0)
4421 * We have just created the small block depot.
4423 StgProperty rootProp;
4424 ULONG sbStartIndex;
4427 * Save it in the header
4429 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4430 StorageImpl_SaveFileHeader(This->parentStorage);
4433 * And allocate the first big block that will contain small blocks
4435 sbStartIndex =
4436 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4438 StorageImpl_SetNextBlockInChain(
4439 This->parentStorage,
4440 sbStartIndex,
4441 BLOCK_END_OF_CHAIN);
4443 StorageImpl_ReadProperty(
4444 This->parentStorage,
4445 This->parentStorage->rootPropertySetIndex,
4446 &rootProp);
4448 rootProp.startingBlock = sbStartIndex;
4449 rootProp.size.HighPart = 0;
4450 rootProp.size.LowPart = This->parentStorage->bigBlockSize;
4452 StorageImpl_WriteProperty(
4453 This->parentStorage,
4454 This->parentStorage->rootPropertySetIndex,
4455 &rootProp);
4460 smallBlocksPerBigBlock =
4461 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4464 * Verify if we have to allocate big blocks to contain small blocks
4466 if (blockIndex % smallBlocksPerBigBlock == 0)
4468 StgProperty rootProp;
4469 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4471 StorageImpl_ReadProperty(
4472 This->parentStorage,
4473 This->parentStorage->rootPropertySetIndex,
4474 &rootProp);
4476 if (rootProp.size.LowPart <
4477 (blocksRequired * This->parentStorage->bigBlockSize))
4479 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4481 BlockChainStream_SetSize(
4482 This->parentStorage->smallBlockRootChain,
4483 rootProp.size);
4485 StorageImpl_WriteProperty(
4486 This->parentStorage,
4487 This->parentStorage->rootPropertySetIndex,
4488 &rootProp);
4492 return blockIndex;
4495 /******************************************************************************
4496 * SmallBlockChainStream_ReadAt
4498 * Reads a specified number of bytes from this chain at the specified offset.
4499 * bytesRead may be NULL.
4500 * Failure will be returned if the specified number of bytes has not been read.
4502 BOOL SmallBlockChainStream_ReadAt(
4503 SmallBlockChainStream* This,
4504 ULARGE_INTEGER offset,
4505 ULONG size,
4506 void* buffer,
4507 ULONG* bytesRead)
4509 ULARGE_INTEGER offsetInBigBlockFile;
4510 ULONG blockNoInSequence =
4511 offset.LowPart / This->parentStorage->smallBlockSize;
4513 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4514 ULONG bytesToReadInBuffer;
4515 ULONG blockIndex;
4516 ULONG bytesReadFromBigBlockFile;
4517 BYTE* bufferWalker;
4520 * This should never happen on a small block file.
4522 assert(offset.HighPart==0);
4525 * Find the first block in the stream that contains part of the buffer.
4527 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4529 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4531 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4533 blockNoInSequence--;
4537 * Start reading the buffer.
4539 *bytesRead = 0;
4540 bufferWalker = buffer;
4542 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4545 * Calculate how many bytes we can copy from this small block.
4547 bytesToReadInBuffer =
4548 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4551 * Calculate the offset of the small block in the small block file.
4553 offsetInBigBlockFile.HighPart = 0;
4554 offsetInBigBlockFile.LowPart =
4555 blockIndex * This->parentStorage->smallBlockSize;
4557 offsetInBigBlockFile.LowPart += offsetInBlock;
4560 * Read those bytes in the buffer from the small block file.
4562 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4563 offsetInBigBlockFile,
4564 bytesToReadInBuffer,
4565 bufferWalker,
4566 &bytesReadFromBigBlockFile);
4568 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4571 * Step to the next big block.
4573 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4574 bufferWalker += bytesToReadInBuffer;
4575 size -= bytesToReadInBuffer;
4576 *bytesRead += bytesToReadInBuffer;
4577 offsetInBlock = 0; /* There is no offset on the next block */
4580 return (size == 0);
4583 /******************************************************************************
4584 * SmallBlockChainStream_WriteAt
4586 * Writes the specified number of bytes to this chain at the specified offset.
4587 * bytesWritten may be NULL.
4588 * Will fail if not all specified number of bytes have been written.
4590 BOOL SmallBlockChainStream_WriteAt(
4591 SmallBlockChainStream* This,
4592 ULARGE_INTEGER offset,
4593 ULONG size,
4594 const void* buffer,
4595 ULONG* bytesWritten)
4597 ULARGE_INTEGER offsetInBigBlockFile;
4598 ULONG blockNoInSequence =
4599 offset.LowPart / This->parentStorage->smallBlockSize;
4601 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4602 ULONG bytesToWriteInBuffer;
4603 ULONG blockIndex;
4604 ULONG bytesWrittenFromBigBlockFile;
4605 BYTE* bufferWalker;
4608 * This should never happen on a small block file.
4610 assert(offset.HighPart==0);
4613 * Find the first block in the stream that contains part of the buffer.
4615 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4617 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4619 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4621 blockNoInSequence--;
4625 * Start writing the buffer.
4627 * Here, I'm casting away the constness on the buffer variable
4628 * This is OK since we don't intend to modify that buffer.
4630 *bytesWritten = 0;
4631 bufferWalker = (BYTE*)buffer;
4632 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4635 * Calculate how many bytes we can copy to this small block.
4637 bytesToWriteInBuffer =
4638 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4641 * Calculate the offset of the small block in the small block file.
4643 offsetInBigBlockFile.HighPart = 0;
4644 offsetInBigBlockFile.LowPart =
4645 blockIndex * This->parentStorage->smallBlockSize;
4647 offsetInBigBlockFile.LowPart += offsetInBlock;
4650 * Write those bytes in the buffer to the small block file.
4652 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4653 offsetInBigBlockFile,
4654 bytesToWriteInBuffer,
4655 bufferWalker,
4656 &bytesWrittenFromBigBlockFile);
4658 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4661 * Step to the next big block.
4663 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4664 bufferWalker += bytesToWriteInBuffer;
4665 size -= bytesToWriteInBuffer;
4666 *bytesWritten += bytesToWriteInBuffer;
4667 offsetInBlock = 0; /* There is no offset on the next block */
4670 return (size == 0);
4673 /******************************************************************************
4674 * SmallBlockChainStream_Shrink
4676 * Shrinks this chain in the small block depot.
4678 BOOL SmallBlockChainStream_Shrink(
4679 SmallBlockChainStream* This,
4680 ULARGE_INTEGER newSize)
4682 ULONG blockIndex, extraBlock;
4683 ULONG numBlocks;
4684 ULONG count = 1;
4686 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4688 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4689 numBlocks++;
4691 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4694 * Go to the new end of chain
4696 while (count < numBlocks)
4698 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4699 count++;
4702 /* Get the next block before marking the new end */
4703 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4705 /* Mark the new end of chain */
4706 SmallBlockChainStream_SetNextBlockInChain(
4707 This,
4708 blockIndex,
4709 BLOCK_END_OF_CHAIN);
4712 * Mark the extra blocks as free
4714 while (extraBlock != BLOCK_END_OF_CHAIN)
4716 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4717 SmallBlockChainStream_FreeBlock(This, extraBlock);
4718 extraBlock = blockIndex;
4721 return TRUE;
4724 /******************************************************************************
4725 * SmallBlockChainStream_Enlarge
4727 * Grows this chain in the small block depot.
4729 BOOL SmallBlockChainStream_Enlarge(
4730 SmallBlockChainStream* This,
4731 ULARGE_INTEGER newSize)
4733 ULONG blockIndex, currentBlock;
4734 ULONG newNumBlocks;
4735 ULONG oldNumBlocks = 0;
4737 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4740 * Empty chain
4742 if (blockIndex == BLOCK_END_OF_CHAIN)
4744 StgProperty chainProp;
4746 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4747 &chainProp);
4749 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4751 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4752 &chainProp);
4754 blockIndex = chainProp.startingBlock;
4755 SmallBlockChainStream_SetNextBlockInChain(
4756 This,
4757 blockIndex,
4758 BLOCK_END_OF_CHAIN);
4761 currentBlock = blockIndex;
4764 * Figure out how many blocks are needed to contain this stream
4766 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4768 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4769 newNumBlocks++;
4772 * Go to the current end of chain
4774 while (blockIndex != BLOCK_END_OF_CHAIN)
4776 oldNumBlocks++;
4777 currentBlock = blockIndex;
4778 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4782 * Add new blocks to the chain
4784 while (oldNumBlocks < newNumBlocks)
4786 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4787 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4789 SmallBlockChainStream_SetNextBlockInChain(
4790 This,
4791 blockIndex,
4792 BLOCK_END_OF_CHAIN);
4794 currentBlock = blockIndex;
4795 oldNumBlocks++;
4798 return TRUE;
4801 /******************************************************************************
4802 * SmallBlockChainStream_GetCount
4804 * Returns the number of blocks that comprises this chain.
4805 * This is not the size of this chain as the last block may not be full!
4807 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4809 ULONG blockIndex;
4810 ULONG count = 0;
4812 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4814 while (blockIndex != BLOCK_END_OF_CHAIN)
4816 count++;
4818 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4821 return count;
4824 /******************************************************************************
4825 * SmallBlockChainStream_SetSize
4827 * Sets the size of this stream.
4828 * The file will grow if we grow the chain.
4830 * TODO: Free the actual blocks in the file when we shrink the chain.
4831 * Currently, the blocks are still in the file. So the file size
4832 * doesn't shrink even if we shrink streams.
4834 BOOL SmallBlockChainStream_SetSize(
4835 SmallBlockChainStream* This,
4836 ULARGE_INTEGER newSize)
4838 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4840 if (newSize.LowPart == size.LowPart)
4841 return TRUE;
4843 if (newSize.LowPart < size.LowPart)
4845 SmallBlockChainStream_Shrink(This, newSize);
4847 else
4849 SmallBlockChainStream_Enlarge(This, newSize);
4852 return TRUE;
4855 /******************************************************************************
4856 * SmallBlockChainStream_GetSize
4858 * Returns the size of this chain.
4860 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4862 StgProperty chainProperty;
4864 StorageImpl_ReadProperty(
4865 This->parentStorage,
4866 This->ownerPropertyIndex,
4867 &chainProperty);
4869 return chainProperty.size;
4872 /******************************************************************************
4873 * StgCreateDocfile32 [OLE32.144]
4874 * TODO Validate grfMode (STGM)
4876 HRESULT WINAPI StgCreateDocfile(
4877 LPCOLESTR pwcsName,
4878 DWORD grfMode,
4879 DWORD reserved,
4880 IStorage **ppstgOpen)
4882 StorageImpl* newStorage = 0;
4883 HANDLE hFile = INVALID_HANDLE_VALUE;
4884 HRESULT hr = S_OK;
4885 DWORD shareMode;
4886 DWORD accessMode;
4887 DWORD creationMode;
4888 DWORD fileAttributes;
4891 * Validate the parameters
4893 if ((ppstgOpen == 0) || (pwcsName == 0))
4894 return STG_E_INVALIDPOINTER;
4897 * Validate the STGM flags
4899 if ( FAILED( validateSTGM(grfMode) ))
4900 return STG_E_INVALIDFLAG;
4903 * Interpret the STGM value grfMode
4905 shareMode = GetShareModeFromSTGM(grfMode);
4906 accessMode = GetAccessModeFromSTGM(grfMode);
4907 creationMode = GetCreationModeFromSTGM(grfMode);
4909 if (grfMode & STGM_DELETEONRELEASE)
4910 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
4911 else
4912 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
4914 if (grfMode & STGM_TRANSACTED)
4915 FIXME(ole, "Transacted mode not implemented.\n");
4918 * Initialize the "out" parameter.
4920 *ppstgOpen = 0;
4922 hFile = CreateFileW(pwcsName,
4923 accessMode,
4924 shareMode,
4925 NULL,
4926 creationMode,
4927 fileAttributes,
4930 if (hFile == INVALID_HANDLE_VALUE)
4932 return E_FAIL;
4936 * Allocate and initialize the new IStorage32object.
4938 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
4940 if (newStorage == 0)
4941 return STG_E_INSUFFICIENTMEMORY;
4943 hr = StorageImpl_Construct(
4944 newStorage,
4945 hFile,
4946 grfMode);
4948 if (FAILED(hr))
4949 return hr;
4952 * Get an "out" pointer for the caller.
4954 hr = StorageBaseImpl_QueryInterface(
4955 (IStorage*)newStorage,
4956 (REFIID)&IID_IStorage,
4957 (void**)ppstgOpen);
4959 return hr;
4962 /******************************************************************************
4963 * StgOpenStorage32 [OLE32.148]
4965 HRESULT WINAPI StgOpenStorage(
4966 const OLECHAR *pwcsName,
4967 IStorage *pstgPriority,
4968 DWORD grfMode,
4969 SNB snbExclude,
4970 DWORD reserved,
4971 IStorage **ppstgOpen)
4973 StorageImpl* newStorage = 0;
4974 HRESULT hr = S_OK;
4975 HANDLE hFile = 0;
4976 DWORD shareMode;
4977 DWORD accessMode;
4980 * Perform a sanity check
4982 if (( pwcsName == 0) || (ppstgOpen == 0) )
4983 return STG_E_INVALIDPOINTER;
4986 * Validate the STGM flags
4988 if ( FAILED( validateSTGM(grfMode) ))
4989 return STG_E_INVALIDFLAG;
4992 * Interpret the STGM value grfMode
4994 shareMode = GetShareModeFromSTGM(grfMode);
4995 accessMode = GetAccessModeFromSTGM(grfMode);
4998 * Initialize the "out" parameter.
5000 *ppstgOpen = 0;
5002 hFile = CreateFileW( pwcsName,
5003 accessMode,
5004 shareMode,
5005 NULL,
5006 OPEN_EXISTING,
5007 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5011 if (hFile==INVALID_HANDLE_VALUE)
5013 return E_FAIL;
5017 * Allocate and initialize the new IStorage32object.
5019 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5021 if (newStorage == 0)
5022 return STG_E_INSUFFICIENTMEMORY;
5024 hr = StorageImpl_Construct(
5025 newStorage,
5026 hFile,
5027 grfMode);
5029 if (FAILED(hr))
5030 return hr;
5033 * Get an "out" pointer for the caller.
5035 hr = StorageBaseImpl_QueryInterface(
5036 (IStorage*)newStorage,
5037 (REFIID)&IID_IStorage,
5038 (void**)ppstgOpen);
5040 return hr;
5043 /******************************************************************************
5044 * WriteClassStg32 [OLE32.148]
5046 * This method will store the specified CLSID in the specified storage object
5048 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5050 HRESULT hRes;
5052 assert(pStg != 0);
5054 hRes = IStorage_SetClass(pStg, rclsid);
5056 return hRes;
5060 /****************************************************************************
5061 * This method validate a STGM parameter that can contain the values below
5063 * STGM_DIRECT 0x00000000
5064 * STGM_TRANSACTED 0x00010000
5065 * STGM_SIMPLE 0x08000000
5067 * STGM_READ 0x00000000
5068 * STGM_WRITE 0x00000001
5069 * STGM_READWRITE 0x00000002
5071 * STGM_SHARE_DENY_NONE 0x00000040
5072 * STGM_SHARE_DENY_READ 0x00000030
5073 * STGM_SHARE_DENY_WRITE 0x00000020
5074 * STGM_SHARE_EXCLUSIVE 0x00000010
5076 * STGM_PRIORITY 0x00040000
5077 * STGM_DELETEONRELEASE 0x04000000
5079 * STGM_CREATE 0x00001000
5080 * STGM_CONVERT 0x00020000
5081 * STGM_FAILIFTHERE 0x00000000
5083 * STGM_NOSCRATCH 0x00100000
5084 * STGM_NOSNAPSHOT 0x00200000
5086 static HRESULT validateSTGM(DWORD stgm)
5088 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5089 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5090 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5092 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5093 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5094 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5096 BOOL bSTGM_SHARE_DENY_NONE =
5097 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5099 BOOL bSTGM_SHARE_DENY_READ =
5100 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5102 BOOL bSTGM_SHARE_DENY_WRITE =
5103 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5105 BOOL bSTGM_SHARE_EXCLUSIVE =
5106 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5108 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5109 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5111 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5112 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5115 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5117 if ( ! bSTGM_DIRECT )
5118 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5119 return E_FAIL;
5122 * STGM_WRITE | STGM_READWRITE | STGM_READ
5124 if ( ! bSTGM_READ )
5125 if( bSTGM_WRITE && bSTGM_READWRITE )
5126 return E_FAIL;
5129 * STGM_SHARE_DENY_NONE | others
5130 * (I assume here that DENY_READ implies DENY_WRITE)
5132 if ( bSTGM_SHARE_DENY_NONE )
5133 if ( bSTGM_SHARE_DENY_READ ||
5134 bSTGM_SHARE_DENY_WRITE ||
5135 bSTGM_SHARE_EXCLUSIVE)
5136 return E_FAIL;
5139 * STGM_CREATE | STGM_CONVERT
5140 * if both are false, STGM_FAILIFTHERE is set to TRUE
5142 if ( bSTGM_CREATE && bSTGM_CONVERT )
5143 return E_FAIL;
5146 * STGM_NOSCRATCH requires STGM_TRANSACTED
5148 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5149 return E_FAIL;
5152 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5153 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5155 if (bSTGM_NOSNAPSHOT)
5157 if ( ! ( bSTGM_TRANSACTED &&
5158 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5159 return E_FAIL;
5162 return S_OK;
5165 /****************************************************************************
5166 * GetShareModeFromSTGM
5168 * This method will return a share mode flag from a STGM value.
5169 * The STGM value is assumed valid.
5171 static DWORD GetShareModeFromSTGM(DWORD stgm)
5173 DWORD dwShareMode = 0;
5174 BOOL bSTGM_SHARE_DENY_NONE =
5175 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5177 BOOL bSTGM_SHARE_DENY_READ =
5178 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5180 BOOL bSTGM_SHARE_DENY_WRITE =
5181 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5183 BOOL bSTGM_SHARE_EXCLUSIVE =
5184 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5186 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5187 dwShareMode = 0;
5189 if (bSTGM_SHARE_DENY_NONE)
5190 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5192 if (bSTGM_SHARE_DENY_WRITE)
5193 dwShareMode = FILE_SHARE_READ;
5195 return dwShareMode;
5198 /****************************************************************************
5199 * GetAccessModeFromSTGM
5201 * This method will return an access mode flag from a STGM value.
5202 * The STGM value is assumed valid.
5204 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5206 DWORD dwDesiredAccess = 0;
5207 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5208 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5209 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5211 if (bSTGM_READ)
5212 dwDesiredAccess = GENERIC_READ;
5214 if (bSTGM_WRITE)
5215 dwDesiredAccess |= GENERIC_WRITE;
5217 if (bSTGM_READWRITE)
5218 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5220 return dwDesiredAccess;
5223 /****************************************************************************
5224 * GetCreationModeFromSTGM
5226 * This method will return a creation mode flag from a STGM value.
5227 * The STGM value is assumed valid.
5229 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5231 if ( stgm & STGM_CREATE)
5232 return CREATE_ALWAYS;
5233 if (stgm & STGM_CONVERT) {
5234 FIXME(ole, "STGM_CONVERT not implemented!\n");
5235 return CREATE_NEW;
5237 /* All other cases */
5238 if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
5239 FIXME(ole,"unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
5240 return CREATE_NEW;