MCI_OPEN_DRIVER_PARMS - Add win32 version of structure.
[wine.git] / ole / storage32.c
blob7dc0ca2e8f0f5999528474793c4da468c05f26f5
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 * Create the block chain abstractions.
1928 This->rootBlockChain =
1929 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1931 This->smallBlockDepotChain = BlockChainStream_Construct(
1932 This,
1933 &This->smallBlockDepotStart,
1934 PROPERTY_NULL);
1937 * Write the root property
1939 if (openFlags & STGM_CREATE)
1941 StgProperty rootProp;
1943 * Initialize the property chain
1945 memset(&rootProp, 0, sizeof(rootProp));
1946 lstrcpyAtoW(rootProp.name, rootPropertyName);
1948 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
1949 rootProp.propertyType = PROPTYPE_ROOT;
1950 rootProp.previousProperty = PROPERTY_NULL;
1951 rootProp.nextProperty = PROPERTY_NULL;
1952 rootProp.dirProperty = PROPERTY_NULL;
1953 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
1954 rootProp.size.HighPart = 0;
1955 rootProp.size.LowPart = 0;
1957 StorageImpl_WriteProperty(This, 0, &rootProp);
1961 * Find the ID of the root int he property sets.
1963 currentPropertyIndex = 0;
1967 readSucessful = StorageImpl_ReadProperty(
1968 This,
1969 currentPropertyIndex,
1970 &currentProperty);
1972 if (readSucessful)
1974 if ( (currentProperty.sizeOfNameString != 0 ) &&
1975 (currentProperty.propertyType == PROPTYPE_ROOT) )
1977 This->rootPropertySetIndex = currentPropertyIndex;
1981 currentPropertyIndex++;
1983 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1985 if (!readSucessful)
1987 /* TODO CLEANUP */
1988 return E_FAIL;
1992 * Create the block chain abstraction for the small block root chain.
1994 This->smallBlockRootChain = BlockChainStream_Construct(
1995 This,
1996 NULL,
1997 This->rootPropertySetIndex);
1999 return hr;
2002 void StorageImpl_Destroy(
2003 StorageImpl* This)
2005 BlockChainStream_Destroy(This->smallBlockRootChain);
2006 BlockChainStream_Destroy(This->rootBlockChain);
2007 BlockChainStream_Destroy(This->smallBlockDepotChain);
2009 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2010 return;
2013 /******************************************************************************
2014 * Storage32Impl_GetNextFreeBigBlock
2016 * Returns the index of the next free big block.
2017 * If the big block depot is filled, this method will enlarge it.
2020 ULONG StorageImpl_GetNextFreeBigBlock(
2021 StorageImpl* This)
2023 ULONG depotBlockIndexPos;
2024 void *depotBuffer;
2025 ULONG depotBlockOffset;
2026 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2027 ULONG nextBlockIndex = BLOCK_SPECIAL;
2028 int depotIndex = 0;
2029 ULONG blockNoInSequence = 0;
2032 * Scan the entire big block depot until we find a block marked free
2034 while (nextBlockIndex != BLOCK_UNUSED)
2036 if (depotIndex < COUNT_BBDEPOTINHEADER)
2038 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2041 * Grow the primary depot.
2043 if (depotBlockIndexPos == BLOCK_UNUSED)
2045 depotBlockIndexPos = depotIndex*blocksPerDepot;
2048 * Add a block depot.
2050 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2051 This->bigBlockDepotCount++;
2052 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2055 * Flag it as a block depot.
2057 StorageImpl_SetNextBlockInChain(This,
2058 depotBlockIndexPos,
2059 BLOCK_SPECIAL);
2061 /* Save new header information.
2063 StorageImpl_SaveFileHeader(This);
2066 else
2068 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2070 if (depotBlockIndexPos == BLOCK_UNUSED)
2073 * Grow the extended depot.
2075 ULONG extIndex = BLOCK_UNUSED;
2076 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2077 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2079 if (extBlockOffset == 0)
2081 /* We need an extended block.
2083 extIndex = Storage32Impl_AddExtBlockDepot(This);
2084 This->extBigBlockDepotCount++;
2085 depotBlockIndexPos = extIndex + 1;
2087 else
2088 depotBlockIndexPos = depotIndex * blocksPerDepot;
2091 * Add a block depot and mark it in the extended block.
2093 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2094 This->bigBlockDepotCount++;
2095 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2097 /* Flag the block depot.
2099 StorageImpl_SetNextBlockInChain(This,
2100 depotBlockIndexPos,
2101 BLOCK_SPECIAL);
2103 /* If necessary, flag the extended depot block.
2105 if (extIndex != BLOCK_UNUSED)
2106 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2108 /* Save header information.
2110 StorageImpl_SaveFileHeader(This);
2114 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2116 if (depotBuffer != 0)
2118 depotBlockOffset = 0;
2120 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2121 ( nextBlockIndex != BLOCK_UNUSED))
2123 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2125 if (nextBlockIndex != BLOCK_UNUSED)
2126 blockNoInSequence++;
2128 depotBlockOffset += sizeof(ULONG);
2131 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2134 depotIndex++;
2137 return blockNoInSequence;
2140 /******************************************************************************
2141 * Storage32Impl_AddBlockDepot
2143 * This will create a depot block, essentially it is a block initialized
2144 * to BLOCK_UNUSEDs.
2146 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2148 BYTE* blockBuffer;
2150 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2153 * Initialize blocks as free
2155 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2157 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2160 /******************************************************************************
2161 * Storage32Impl_GetExtDepotBlock
2163 * Returns the index of the block that corresponds to the specified depot
2164 * index. This method is only for depot indexes equal or greater than
2165 * COUNT_BBDEPOTINHEADER.
2167 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2169 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2170 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2171 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2172 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2173 ULONG blockIndex = BLOCK_UNUSED;
2174 ULONG extBlockIndex = This->extBigBlockDepotStart;
2176 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2178 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2179 return BLOCK_UNUSED;
2181 while (extBlockCount > 0)
2183 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2184 extBlockCount--;
2187 if (extBlockIndex != BLOCK_UNUSED)
2189 BYTE* depotBuffer;
2191 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2193 if (depotBuffer != 0)
2195 StorageUtl_ReadDWord(depotBuffer,
2196 extBlockOffset * sizeof(ULONG),
2197 &blockIndex);
2199 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2203 return blockIndex;
2206 /******************************************************************************
2207 * Storage32Impl_SetExtDepotBlock
2209 * Associates the specified block index to the specified depot index.
2210 * This method is only for depot indexes equal or greater than
2211 * COUNT_BBDEPOTINHEADER.
2213 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2214 ULONG depotIndex,
2215 ULONG blockIndex)
2217 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2218 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2219 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2220 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2221 ULONG extBlockIndex = This->extBigBlockDepotStart;
2223 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2225 while (extBlockCount > 0)
2227 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2228 extBlockCount--;
2231 if (extBlockIndex != BLOCK_UNUSED)
2233 BYTE* depotBuffer;
2235 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2237 if (depotBuffer != 0)
2239 StorageUtl_WriteDWord(depotBuffer,
2240 extBlockOffset * sizeof(ULONG),
2241 blockIndex);
2243 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2248 /******************************************************************************
2249 * Storage32Impl_AddExtBlockDepot
2251 * Creates an extended depot block.
2253 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2255 ULONG numExtBlocks = This->extBigBlockDepotCount;
2256 ULONG nextExtBlock = This->extBigBlockDepotStart;
2257 BYTE* depotBuffer = NULL;
2258 ULONG index = BLOCK_UNUSED;
2259 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2260 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2261 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2263 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2264 blocksPerDepotBlock;
2266 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2269 * The first extended block.
2271 This->extBigBlockDepotStart = index;
2273 else
2275 int i;
2277 * Follow the chain to the last one.
2279 for (i = 0; i < (numExtBlocks - 1); i++)
2281 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2285 * Add the new extended block to the chain.
2287 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2288 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2289 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2293 * Initialize this block.
2295 depotBuffer = StorageImpl_GetBigBlock(This, index);
2296 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2297 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2299 return index;
2302 /******************************************************************************
2303 * Storage32Impl_FreeBigBlock
2305 * This method will flag the specified block as free in the big block depot.
2307 void StorageImpl_FreeBigBlock(
2308 StorageImpl* This,
2309 ULONG blockIndex)
2311 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2314 /************************************************************************
2315 * Storage32Impl_GetNextBlockInChain
2317 * This method will retrieve the block index of the next big block in
2318 * in the chain.
2320 * Params: This - Pointer to the Storage object.
2321 * blockIndex - Index of the block to retrieve the chain
2322 * for.
2324 * Returns: This method returns the index of the next block in the chain.
2325 * It will return the constants:
2326 * BLOCK_SPECIAL - If the block given was not part of a
2327 * chain.
2328 * BLOCK_END_OF_CHAIN - If the block given was the last in
2329 * a chain.
2330 * BLOCK_UNUSED - If the block given was not past of a chain
2331 * and is available.
2332 * BLOCK_EXTBBDEPOT - This block is part of the extended
2333 * big block depot.
2335 * See Windows documentation for more details on IStorage methods.
2337 ULONG StorageImpl_GetNextBlockInChain(
2338 StorageImpl* This,
2339 ULONG blockIndex)
2341 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2342 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2343 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2344 ULONG nextBlockIndex = BLOCK_SPECIAL;
2345 void* depotBuffer;
2346 ULONG depotBlockIndexPos;
2348 assert(depotBlockCount < This->bigBlockDepotCount);
2351 * Cache the currently accessed depot block.
2353 if (depotBlockCount != This->indexBlockDepotCached)
2355 This->indexBlockDepotCached = depotBlockCount;
2357 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2359 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2361 else
2364 * We have to look in the extended depot.
2366 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2369 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2371 if (depotBuffer!=0)
2373 int index;
2375 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2377 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2378 This->blockDepotCached[index] = nextBlockIndex;
2381 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2385 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2387 return nextBlockIndex;
2390 /******************************************************************************
2391 * Storage32Impl_GetNextExtendedBlock
2393 * Given an extended block this method will return the next extended block.
2395 * NOTES:
2396 * The last ULONG of an extended block is the block index of the next
2397 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2398 * depot.
2400 * Return values:
2401 * - The index of the next extended block
2402 * - BLOCK_UNUSED: there is no next extended block.
2403 * - Any other return values denotes failure.
2405 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2407 ULONG nextBlockIndex = BLOCK_SPECIAL;
2408 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2409 void* depotBuffer;
2411 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2413 if (depotBuffer!=0)
2415 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2417 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2420 return nextBlockIndex;
2423 /******************************************************************************
2424 * Storage32Impl_SetNextBlockInChain
2426 * This method will write the index of the specified block's next block
2427 * in the big block depot.
2429 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2430 * do the following
2432 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2433 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2434 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2437 void StorageImpl_SetNextBlockInChain(
2438 StorageImpl* This,
2439 ULONG blockIndex,
2440 ULONG nextBlock)
2442 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2443 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2444 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2445 ULONG depotBlockIndexPos;
2446 void* depotBuffer;
2448 assert(depotBlockCount < This->bigBlockDepotCount);
2450 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2452 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2454 else
2457 * We have to look in the extended depot.
2459 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2462 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2464 if (depotBuffer!=0)
2466 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2467 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2471 * Update the cached block depot, if necessary.
2473 if (depotBlockCount == This->indexBlockDepotCached)
2475 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2479 /******************************************************************************
2480 * Storage32Impl_LoadFileHeader
2482 * This method will read in the file header, i.e. big block index -1.
2484 HRESULT StorageImpl_LoadFileHeader(
2485 StorageImpl* This)
2487 HRESULT hr = STG_E_FILENOTFOUND;
2488 void* headerBigBlock = NULL;
2489 int index;
2492 * Get a pointer to the big block of data containing the header.
2494 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2497 * Extract the information from the header.
2499 if (headerBigBlock!=0)
2502 * Check for the "magic number" signature and return an error if it is not
2503 * found.
2505 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2507 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2508 return STG_E_OLDFORMAT;
2511 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2513 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2514 return STG_E_INVALIDHEADER;
2517 StorageUtl_ReadWord(
2518 headerBigBlock,
2519 OFFSET_BIGBLOCKSIZEBITS,
2520 &This->bigBlockSizeBits);
2522 StorageUtl_ReadWord(
2523 headerBigBlock,
2524 OFFSET_SMALLBLOCKSIZEBITS,
2525 &This->smallBlockSizeBits);
2527 StorageUtl_ReadDWord(
2528 headerBigBlock,
2529 OFFSET_BBDEPOTCOUNT,
2530 &This->bigBlockDepotCount);
2532 StorageUtl_ReadDWord(
2533 headerBigBlock,
2534 OFFSET_ROOTSTARTBLOCK,
2535 &This->rootStartBlock);
2537 StorageUtl_ReadDWord(
2538 headerBigBlock,
2539 OFFSET_SBDEPOTSTART,
2540 &This->smallBlockDepotStart);
2542 StorageUtl_ReadDWord(
2543 headerBigBlock,
2544 OFFSET_EXTBBDEPOTSTART,
2545 &This->extBigBlockDepotStart);
2547 StorageUtl_ReadDWord(
2548 headerBigBlock,
2549 OFFSET_EXTBBDEPOTCOUNT,
2550 &This->extBigBlockDepotCount);
2552 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2554 StorageUtl_ReadDWord(
2555 headerBigBlock,
2556 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2557 &(This->bigBlockDepotStart[index]));
2561 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2563 if ((1 << 2) == 4)
2565 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2566 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2568 else
2570 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2571 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2575 * Right now, the code is making some assumptions about the size of the
2576 * blocks, just make sure they are what we're expecting.
2578 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2579 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2582 * Release the block.
2584 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2587 return hr;
2590 /******************************************************************************
2591 * Storage32Impl_SaveFileHeader
2593 * This method will save to the file the header, i.e. big block -1.
2595 void StorageImpl_SaveFileHeader(
2596 StorageImpl* This)
2598 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2599 int index;
2600 BOOL success;
2603 * Get a pointer to the big block of data containing the header.
2605 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2608 * If the block read failed, the file is probably new.
2610 if (!success)
2613 * Initialize for all unknown fields.
2615 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2618 * Initialize the magic number.
2620 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2623 * And a bunch of things we don't know what they mean
2625 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2626 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2627 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2628 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2629 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2633 * Write the information to the header.
2635 if (headerBigBlock!=0)
2637 StorageUtl_WriteWord(
2638 headerBigBlock,
2639 OFFSET_BIGBLOCKSIZEBITS,
2640 This->bigBlockSizeBits);
2642 StorageUtl_WriteWord(
2643 headerBigBlock,
2644 OFFSET_SMALLBLOCKSIZEBITS,
2645 This->smallBlockSizeBits);
2647 StorageUtl_WriteDWord(
2648 headerBigBlock,
2649 OFFSET_BBDEPOTCOUNT,
2650 This->bigBlockDepotCount);
2652 StorageUtl_WriteDWord(
2653 headerBigBlock,
2654 OFFSET_ROOTSTARTBLOCK,
2655 This->rootStartBlock);
2657 StorageUtl_WriteDWord(
2658 headerBigBlock,
2659 OFFSET_SBDEPOTSTART,
2660 This->smallBlockDepotStart);
2662 StorageUtl_WriteDWord(
2663 headerBigBlock,
2664 OFFSET_EXTBBDEPOTSTART,
2665 This->extBigBlockDepotStart);
2667 StorageUtl_WriteDWord(
2668 headerBigBlock,
2669 OFFSET_EXTBBDEPOTCOUNT,
2670 This->extBigBlockDepotCount);
2672 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2674 StorageUtl_WriteDWord(
2675 headerBigBlock,
2676 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2677 (This->bigBlockDepotStart[index]));
2682 * Write the big block back to the file.
2684 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2687 /******************************************************************************
2688 * Storage32Impl_ReadProperty
2690 * This method will read the specified property from the property chain.
2692 BOOL StorageImpl_ReadProperty(
2693 StorageImpl* This,
2694 ULONG index,
2695 StgProperty* buffer)
2697 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2698 ULARGE_INTEGER offsetInPropSet;
2699 BOOL readSucessful;
2700 ULONG bytesRead;
2702 offsetInPropSet.HighPart = 0;
2703 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2705 readSucessful = BlockChainStream_ReadAt(
2706 This->rootBlockChain,
2707 offsetInPropSet,
2708 PROPSET_BLOCK_SIZE,
2709 currentProperty,
2710 &bytesRead);
2712 if (readSucessful)
2714 memset(buffer->name, 0, sizeof(buffer->name));
2715 memcpy(
2716 buffer->name,
2717 currentProperty+OFFSET_PS_NAME,
2718 PROPERTY_NAME_BUFFER_LEN );
2720 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2722 StorageUtl_ReadWord(
2723 currentProperty,
2724 OFFSET_PS_NAMELENGTH,
2725 &buffer->sizeOfNameString);
2727 StorageUtl_ReadDWord(
2728 currentProperty,
2729 OFFSET_PS_PREVIOUSPROP,
2730 &buffer->previousProperty);
2732 StorageUtl_ReadDWord(
2733 currentProperty,
2734 OFFSET_PS_NEXTPROP,
2735 &buffer->nextProperty);
2737 StorageUtl_ReadDWord(
2738 currentProperty,
2739 OFFSET_PS_DIRPROP,
2740 &buffer->dirProperty);
2742 StorageUtl_ReadGUID(
2743 currentProperty,
2744 OFFSET_PS_GUID,
2745 &buffer->propertyUniqueID);
2747 StorageUtl_ReadDWord(
2748 currentProperty,
2749 OFFSET_PS_TSS1,
2750 &buffer->timeStampS1);
2752 StorageUtl_ReadDWord(
2753 currentProperty,
2754 OFFSET_PS_TSD1,
2755 &buffer->timeStampD1);
2757 StorageUtl_ReadDWord(
2758 currentProperty,
2759 OFFSET_PS_TSS2,
2760 &buffer->timeStampS2);
2762 StorageUtl_ReadDWord(
2763 currentProperty,
2764 OFFSET_PS_TSD2,
2765 &buffer->timeStampD2);
2767 StorageUtl_ReadDWord(
2768 currentProperty,
2769 OFFSET_PS_STARTBLOCK,
2770 &buffer->startingBlock);
2772 StorageUtl_ReadDWord(
2773 currentProperty,
2774 OFFSET_PS_SIZE,
2775 &buffer->size.LowPart);
2777 buffer->size.HighPart = 0;
2780 return readSucessful;
2783 /*********************************************************************
2784 * Write the specified property into the property chain
2786 BOOL StorageImpl_WriteProperty(
2787 StorageImpl* This,
2788 ULONG index,
2789 StgProperty* buffer)
2791 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2792 ULARGE_INTEGER offsetInPropSet;
2793 BOOL writeSucessful;
2794 ULONG bytesWritten;
2796 offsetInPropSet.HighPart = 0;
2797 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2799 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2801 memcpy(
2802 currentProperty + OFFSET_PS_NAME,
2803 buffer->name,
2804 PROPERTY_NAME_BUFFER_LEN );
2806 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2809 * Reassign the size in case of mistake....
2811 buffer->sizeOfNameString = (lstrlenW(buffer->name)+1) * sizeof(WCHAR);
2813 StorageUtl_WriteWord(
2814 currentProperty,
2815 OFFSET_PS_NAMELENGTH,
2816 buffer->sizeOfNameString);
2818 StorageUtl_WriteDWord(
2819 currentProperty,
2820 OFFSET_PS_PREVIOUSPROP,
2821 buffer->previousProperty);
2823 StorageUtl_WriteDWord(
2824 currentProperty,
2825 OFFSET_PS_NEXTPROP,
2826 buffer->nextProperty);
2828 StorageUtl_WriteDWord(
2829 currentProperty,
2830 OFFSET_PS_DIRPROP,
2831 buffer->dirProperty);
2833 StorageUtl_WriteGUID(
2834 currentProperty,
2835 OFFSET_PS_GUID,
2836 &buffer->propertyUniqueID);
2838 StorageUtl_WriteDWord(
2839 currentProperty,
2840 OFFSET_PS_TSS1,
2841 buffer->timeStampS1);
2843 StorageUtl_WriteDWord(
2844 currentProperty,
2845 OFFSET_PS_TSD1,
2846 buffer->timeStampD1);
2848 StorageUtl_WriteDWord(
2849 currentProperty,
2850 OFFSET_PS_TSS2,
2851 buffer->timeStampS2);
2853 StorageUtl_WriteDWord(
2854 currentProperty,
2855 OFFSET_PS_TSD2,
2856 buffer->timeStampD2);
2858 StorageUtl_WriteDWord(
2859 currentProperty,
2860 OFFSET_PS_STARTBLOCK,
2861 buffer->startingBlock);
2863 StorageUtl_WriteDWord(
2864 currentProperty,
2865 OFFSET_PS_SIZE,
2866 buffer->size.LowPart);
2868 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2869 offsetInPropSet,
2870 PROPSET_BLOCK_SIZE,
2871 currentProperty,
2872 &bytesWritten);
2873 return writeSucessful;
2876 BOOL StorageImpl_ReadBigBlock(
2877 StorageImpl* This,
2878 ULONG blockIndex,
2879 void* buffer)
2881 void* bigBlockBuffer;
2883 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2885 if (bigBlockBuffer!=0)
2887 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2889 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2891 return TRUE;
2894 return FALSE;
2897 BOOL StorageImpl_WriteBigBlock(
2898 StorageImpl* This,
2899 ULONG blockIndex,
2900 void* buffer)
2902 void* bigBlockBuffer;
2904 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2906 if (bigBlockBuffer!=0)
2908 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2910 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2912 return TRUE;
2915 return FALSE;
2918 void* StorageImpl_GetROBigBlock(
2919 StorageImpl* This,
2920 ULONG blockIndex)
2922 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2925 void* StorageImpl_GetBigBlock(
2926 StorageImpl* This,
2927 ULONG blockIndex)
2929 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2932 void StorageImpl_ReleaseBigBlock(
2933 StorageImpl* This,
2934 void* pBigBlock)
2936 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2939 /******************************************************************************
2940 * Storage32Impl_SmallBlocksToBigBlocks
2942 * This method will convert a small block chain to a big block chain.
2943 * The small block chain will be destroyed.
2945 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2946 StorageImpl* This,
2947 SmallBlockChainStream** ppsbChain)
2949 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2950 ULARGE_INTEGER size, offset;
2951 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
2952 ULONG propertyIndex;
2953 BOOL successRead, successWrite;
2954 StgProperty chainProperty;
2955 BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2956 BlockChainStream *bbTempChain = NULL;
2957 BlockChainStream *bigBlockChain = NULL;
2960 * Create a temporary big block chain that doesn't have
2961 * an associated property. This temporary chain will be
2962 * used to copy data from small blocks to big blocks.
2964 bbTempChain = BlockChainStream_Construct(This,
2965 &bbHeadOfChain,
2966 PROPERTY_NULL);
2969 * Grow the big block chain.
2971 size = SmallBlockChainStream_GetSize(*ppsbChain);
2972 BlockChainStream_SetSize(bbTempChain, size);
2975 * Copy the contents of the small block chain to the big block chain
2976 * by small block size increments.
2978 offset.LowPart = 0;
2979 offset.HighPart = 0;
2980 cbTotalRead = 0;
2981 cbTotalWritten = 0;
2985 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
2986 offset,
2987 sizeof(buffer),
2988 buffer,
2989 &cbRead);
2990 cbTotalRead += cbRead;
2992 successWrite = BlockChainStream_WriteAt(bbTempChain,
2993 offset,
2994 cbRead,
2995 buffer,
2996 &cbWritten);
2997 cbTotalWritten += cbWritten;
2999 offset.LowPart += This->smallBlockSize;
3001 } while (successRead && successWrite);
3003 assert(cbTotalRead == cbTotalWritten);
3006 * Destroy the small block chain.
3008 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3009 size.HighPart = 0;
3010 size.LowPart = 0;
3011 SmallBlockChainStream_SetSize(*ppsbChain, size);
3012 SmallBlockChainStream_Destroy(*ppsbChain);
3013 *ppsbChain = 0;
3016 * Change the property information. This chain is now a big block chain
3017 * and it doesn't reside in the small blocks chain anymore.
3019 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3021 chainProperty.startingBlock = bbHeadOfChain;
3023 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3026 * Destroy the temporary propertyless big block chain.
3027 * Create a new big block chain associated with this property.
3029 BlockChainStream_Destroy(bbTempChain);
3030 bigBlockChain = BlockChainStream_Construct(This,
3031 NULL,
3032 propertyIndex);
3034 return bigBlockChain;
3037 /******************************************************************************
3038 ** Storage32InternalImpl implementation
3041 StorageInternalImpl* StorageInternalImpl_Construct(
3042 StorageImpl* ancestorStorage,
3043 ULONG rootPropertyIndex)
3045 StorageInternalImpl* newStorage;
3048 * Allocate space for the new storage object
3050 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3052 if (newStorage!=0)
3054 memset(newStorage, 0, sizeof(StorageInternalImpl));
3057 * Initialize the virtual function table.
3059 newStorage->lpvtbl = &Storage32InternalImpl_Vtbl;
3060 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3063 * Keep the ancestor storage pointer and nail a reference to it.
3065 newStorage->ancestorStorage = ancestorStorage;
3066 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3069 * Keep the index of the root property set for this storage,
3071 newStorage->rootPropertySetIndex = rootPropertyIndex;
3073 return newStorage;
3076 return 0;
3079 void StorageInternalImpl_Destroy(
3080 StorageInternalImpl* This)
3082 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3083 HeapFree(GetProcessHeap(), 0, This);
3086 /******************************************************************************
3088 ** Storage32InternalImpl_Commit
3090 ** The non-root storages cannot be opened in transacted mode thus this function
3091 ** does nothing.
3093 HRESULT WINAPI StorageInternalImpl_Commit(
3094 IStorage* iface,
3095 DWORD grfCommitFlags) /* [in] */
3097 return S_OK;
3100 /******************************************************************************
3102 ** Storage32InternalImpl_Revert
3104 ** The non-root storages cannot be opened in transacted mode thus this function
3105 ** does nothing.
3107 HRESULT WINAPI StorageInternalImpl_Revert(
3108 IStorage* iface)
3110 return S_OK;
3113 /******************************************************************************
3114 ** IEnumSTATSTGImpl implementation
3117 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3118 StorageImpl* parentStorage,
3119 ULONG firstPropertyNode)
3121 IEnumSTATSTGImpl* newEnumeration;
3123 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3125 if (newEnumeration!=0)
3128 * Set-up the virtual function table and reference count.
3130 newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
3131 newEnumeration->ref = 0;
3134 * We want to nail-down the reference to the storage in case the
3135 * enumeration out-lives the storage in the client application.
3137 newEnumeration->parentStorage = parentStorage;
3138 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3140 newEnumeration->firstPropertyNode = firstPropertyNode;
3143 * Initialize the search stack
3145 newEnumeration->stackSize = 0;
3146 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3147 newEnumeration->stackToVisit =
3148 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3151 * Make sure the current node of the iterator is the first one.
3153 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3156 return newEnumeration;
3159 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3161 IStorage_Release((IStorage*)This->parentStorage);
3162 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3163 HeapFree(GetProcessHeap(), 0, This);
3166 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3167 IEnumSTATSTG* iface,
3168 REFIID riid,
3169 void** ppvObject)
3171 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3174 * Perform a sanity check on the parameters.
3176 if (ppvObject==0)
3177 return E_INVALIDARG;
3180 * Initialize the return parameter.
3182 *ppvObject = 0;
3185 * Compare the riid with the interface IDs implemented by this object.
3187 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3189 *ppvObject = (IEnumSTATSTG*)This;
3191 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3193 *ppvObject = (IEnumSTATSTG*)This;
3197 * Check that we obtained an interface.
3199 if ((*ppvObject)==0)
3200 return E_NOINTERFACE;
3203 * Query Interface always increases the reference count by one when it is
3204 * successful
3206 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3208 return S_OK;
3211 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3212 IEnumSTATSTG* iface)
3214 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3216 This->ref++;
3217 return This->ref;
3220 ULONG WINAPI IEnumSTATSTGImpl_Release(
3221 IEnumSTATSTG* iface)
3223 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3225 ULONG newRef;
3227 This->ref--;
3228 newRef = This->ref;
3231 * If the reference count goes down to 0, perform suicide.
3233 if (newRef==0)
3235 IEnumSTATSTGImpl_Destroy(This);
3238 return newRef;;
3241 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3242 IEnumSTATSTG* iface,
3243 ULONG celt,
3244 STATSTG* rgelt,
3245 ULONG* pceltFetched)
3247 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3249 StgProperty currentProperty;
3250 STATSTG* currentReturnStruct = rgelt;
3251 ULONG objectFetched = 0;
3252 ULONG currentSearchNode;
3255 * Perform a sanity check on the parameters.
3257 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3258 return E_INVALIDARG;
3261 * To avoid the special case, get another pointer to a ULONG value if
3262 * the caller didn't supply one.
3264 if (pceltFetched==0)
3265 pceltFetched = &objectFetched;
3268 * Start the iteration, we will iterate until we hit the end of the
3269 * linked list or until we hit the number of items to iterate through
3271 *pceltFetched = 0;
3274 * Start with the node at the top of the stack.
3276 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3278 while ( ( *pceltFetched < celt) &&
3279 ( currentSearchNode!=PROPERTY_NULL) )
3282 * Remove the top node from the stack
3284 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3287 * Read the property from the storage.
3289 StorageImpl_ReadProperty(This->parentStorage,
3290 currentSearchNode,
3291 &currentProperty);
3294 * Copy the information to the return buffer.
3296 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3297 &currentProperty,
3298 STATFLAG_DEFAULT);
3301 * Step to the next item in the iteration
3303 (*pceltFetched)++;
3304 currentReturnStruct++;
3307 * Push the next search node in the search stack.
3309 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3312 * continue the iteration.
3314 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3317 if (*pceltFetched == celt)
3318 return S_OK;
3320 return S_FALSE;
3324 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3325 IEnumSTATSTG* iface,
3326 ULONG celt)
3328 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3330 StgProperty currentProperty;
3331 ULONG objectFetched = 0;
3332 ULONG currentSearchNode;
3335 * Start with the node at the top of the stack.
3337 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3339 while ( (objectFetched < celt) &&
3340 (currentSearchNode!=PROPERTY_NULL) )
3343 * Remove the top node from the stack
3345 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3348 * Read the property from the storage.
3350 StorageImpl_ReadProperty(This->parentStorage,
3351 currentSearchNode,
3352 &currentProperty);
3355 * Step to the next item in the iteration
3357 objectFetched++;
3360 * Push the next search node in the search stack.
3362 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3365 * continue the iteration.
3367 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3370 if (objectFetched == celt)
3371 return S_OK;
3373 return S_FALSE;
3376 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3377 IEnumSTATSTG* iface)
3379 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3381 StgProperty rootProperty;
3382 BOOL readSucessful;
3385 * Re-initialize the search stack to an empty stack
3387 This->stackSize = 0;
3390 * Read the root property from the storage.
3392 readSucessful = StorageImpl_ReadProperty(
3393 This->parentStorage,
3394 This->firstPropertyNode,
3395 &rootProperty);
3397 if (readSucessful)
3399 assert(rootProperty.sizeOfNameString!=0);
3402 * Push the search node in the search stack.
3404 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3407 return S_OK;
3410 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3411 IEnumSTATSTG* iface,
3412 IEnumSTATSTG** ppenum)
3414 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3416 IEnumSTATSTGImpl* newClone;
3419 * Perform a sanity check on the parameters.
3421 if (ppenum==0)
3422 return E_INVALIDARG;
3424 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3425 This->firstPropertyNode);
3429 * The new clone enumeration must point to the same current node as
3430 * the ole one.
3432 newClone->stackSize = This->stackSize ;
3433 newClone->stackMaxSize = This->stackMaxSize ;
3434 newClone->stackToVisit =
3435 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3437 memcpy(
3438 newClone->stackToVisit,
3439 This->stackToVisit,
3440 sizeof(ULONG) * newClone->stackSize);
3442 *ppenum = (IEnumSTATSTG*)newClone;
3445 * Don't forget to nail down a reference to the clone before
3446 * returning it.
3448 IEnumSTATSTGImpl_AddRef(*ppenum);
3450 return S_OK;
3453 INT IEnumSTATSTGImpl_FindParentProperty(
3454 IEnumSTATSTGImpl *This,
3455 ULONG childProperty,
3456 StgProperty *currentProperty,
3457 ULONG *thisNodeId)
3459 ULONG currentSearchNode;
3460 ULONG foundNode;
3463 * To avoid the special case, get another pointer to a ULONG value if
3464 * the caller didn't supply one.
3466 if (thisNodeId==0)
3467 thisNodeId = &foundNode;
3470 * Start with the node at the top of the stack.
3472 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3475 while (currentSearchNode!=PROPERTY_NULL)
3478 * Store the current node in the returned parameters
3480 *thisNodeId = currentSearchNode;
3483 * Remove the top node from the stack
3485 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3488 * Read the property from the storage.
3490 StorageImpl_ReadProperty(
3491 This->parentStorage,
3492 currentSearchNode,
3493 currentProperty);
3495 if (currentProperty->previousProperty == childProperty)
3496 return PROPERTY_RELATION_PREVIOUS;
3498 else if (currentProperty->nextProperty == childProperty)
3499 return PROPERTY_RELATION_NEXT;
3501 else if (currentProperty->dirProperty == childProperty)
3502 return PROPERTY_RELATION_DIR;
3505 * Push the next search node in the search stack.
3507 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3510 * continue the iteration.
3512 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3515 return PROPERTY_NULL;
3518 ULONG IEnumSTATSTGImpl_FindProperty(
3519 IEnumSTATSTGImpl* This,
3520 const OLECHAR* lpszPropName,
3521 StgProperty* currentProperty)
3523 ULONG currentSearchNode;
3526 * Start with the node at the top of the stack.
3528 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3530 while (currentSearchNode!=PROPERTY_NULL)
3533 * Remove the top node from the stack
3535 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3538 * Read the property from the storage.
3540 StorageImpl_ReadProperty(This->parentStorage,
3541 currentSearchNode,
3542 currentProperty);
3544 if ( propertyNameCmp(
3545 (OLECHAR*)currentProperty->name,
3546 (OLECHAR*)lpszPropName) == 0)
3547 return currentSearchNode;
3550 * Push the next search node in the search stack.
3552 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3555 * continue the iteration.
3557 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3560 return PROPERTY_NULL;
3563 void IEnumSTATSTGImpl_PushSearchNode(
3564 IEnumSTATSTGImpl* This,
3565 ULONG nodeToPush)
3567 StgProperty rootProperty;
3568 BOOL readSucessful;
3571 * First, make sure we're not trying to push an unexisting node.
3573 if (nodeToPush==PROPERTY_NULL)
3574 return;
3577 * First push the node to the stack
3579 if (This->stackSize == This->stackMaxSize)
3581 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3583 This->stackToVisit = HeapReAlloc(
3584 GetProcessHeap(),
3586 This->stackToVisit,
3587 sizeof(ULONG) * This->stackMaxSize);
3590 This->stackToVisit[This->stackSize] = nodeToPush;
3591 This->stackSize++;
3594 * Read the root property from the storage.
3596 readSucessful = StorageImpl_ReadProperty(
3597 This->parentStorage,
3598 nodeToPush,
3599 &rootProperty);
3601 if (readSucessful)
3603 assert(rootProperty.sizeOfNameString!=0);
3606 * Push the previous search node in the search stack.
3608 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3612 ULONG IEnumSTATSTGImpl_PopSearchNode(
3613 IEnumSTATSTGImpl* This,
3614 BOOL remove)
3616 ULONG topNode;
3618 if (This->stackSize == 0)
3619 return PROPERTY_NULL;
3621 topNode = This->stackToVisit[This->stackSize-1];
3623 if (remove)
3624 This->stackSize--;
3626 return topNode;
3629 /******************************************************************************
3630 ** StorageUtl implementation
3633 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3635 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3638 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3640 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3643 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3645 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3648 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3650 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3653 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3655 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3656 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3657 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3659 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3662 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3664 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3665 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3666 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3668 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3671 void StorageUtl_CopyPropertyToSTATSTG(
3672 STATSTG* destination,
3673 StgProperty* source,
3674 int statFlags)
3677 * The copy of the string occurs only when the flag is not set
3679 if ((statFlags & STATFLAG_NONAME) != 0)
3681 destination->pwcsName = 0;
3683 else
3685 destination->pwcsName =
3686 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3688 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3691 switch (source->propertyType)
3693 case PROPTYPE_STORAGE:
3694 case PROPTYPE_ROOT:
3695 destination->type = STGTY_STORAGE;
3696 break;
3697 case PROPTYPE_STREAM:
3698 destination->type = STGTY_STREAM;
3699 break;
3700 default:
3701 destination->type = STGTY_STREAM;
3702 break;
3705 destination->cbSize = source->size;
3707 currentReturnStruct->mtime = {0}; TODO
3708 currentReturnStruct->ctime = {0};
3709 currentReturnStruct->atime = {0};
3711 destination->grfMode = 0;
3712 destination->grfLocksSupported = 0;
3713 destination->clsid = source->propertyUniqueID;
3714 destination->grfStateBits = 0;
3715 destination->reserved = 0;
3718 /******************************************************************************
3719 ** BlockChainStream implementation
3722 BlockChainStream* BlockChainStream_Construct(
3723 StorageImpl* parentStorage,
3724 ULONG* headOfStreamPlaceHolder,
3725 ULONG propertyIndex)
3727 BlockChainStream* newStream;
3729 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3731 newStream->parentStorage = parentStorage;
3732 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3733 newStream->ownerPropertyIndex = propertyIndex;
3735 return newStream;
3738 void BlockChainStream_Destroy(BlockChainStream* This)
3740 HeapFree(GetProcessHeap(), 0, This);
3743 /******************************************************************************
3744 * BlockChainStream_GetHeadOfChain
3746 * Returns the head of this stream chain.
3747 * Some special chains don't have properties, their heads are kept in
3748 * This->headOfStreamPlaceHolder.
3751 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3753 StgProperty chainProperty;
3754 BOOL readSucessful;
3756 if (This->headOfStreamPlaceHolder != 0)
3757 return *(This->headOfStreamPlaceHolder);
3759 if (This->ownerPropertyIndex != PROPERTY_NULL)
3761 readSucessful = StorageImpl_ReadProperty(
3762 This->parentStorage,
3763 This->ownerPropertyIndex,
3764 &chainProperty);
3766 if (readSucessful)
3768 return chainProperty.startingBlock;
3772 return BLOCK_END_OF_CHAIN;
3775 /******************************************************************************
3776 * BlockChainStream_GetCount
3778 * Returns the number of blocks that comprises this chain.
3779 * This is not the size of the stream as the last block may not be full!
3782 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3784 ULONG blockIndex;
3785 ULONG count = 0;
3787 blockIndex = BlockChainStream_GetHeadOfChain(This);
3789 while (blockIndex != BLOCK_END_OF_CHAIN)
3791 count++;
3793 blockIndex = StorageImpl_GetNextBlockInChain(
3794 This->parentStorage,
3795 blockIndex);
3798 return count;
3801 /******************************************************************************
3802 * BlockChainStream_ReadAt
3804 * Reads a specified number of bytes from this chain at the specified offset.
3805 * bytesRead may be NULL.
3806 * Failure will be returned if the specified number of bytes has not been read.
3808 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
3809 ULARGE_INTEGER offset,
3810 ULONG size,
3811 void* buffer,
3812 ULONG* bytesRead)
3814 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3815 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3816 ULONG bytesToReadInBuffer;
3817 ULONG blockIndex;
3818 BYTE* bufferWalker;
3819 BYTE* bigBlockBuffer;
3822 * Find the first block in the stream that contains part of the buffer.
3824 blockIndex = BlockChainStream_GetHeadOfChain(This);
3826 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3828 blockIndex =
3829 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3831 blockNoInSequence--;
3835 * Start reading the buffer.
3837 *bytesRead = 0;
3838 bufferWalker = buffer;
3840 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3843 * Calculate how many bytes we can copy from this big block.
3845 bytesToReadInBuffer =
3846 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3849 * Copy those bytes to the buffer
3851 bigBlockBuffer =
3852 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
3854 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3856 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3859 * Step to the next big block.
3861 blockIndex =
3862 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3864 bufferWalker += bytesToReadInBuffer;
3865 size -= bytesToReadInBuffer;
3866 *bytesRead += bytesToReadInBuffer;
3867 offsetInBlock = 0; /* There is no offset on the next block */
3871 return (size == 0);
3874 /******************************************************************************
3875 * BlockChainStream_WriteAt
3877 * Writes the specified number of bytes to this chain at the specified offset.
3878 * bytesWritten may be NULL.
3879 * Will fail if not all specified number of bytes have been written.
3881 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
3882 ULARGE_INTEGER offset,
3883 ULONG size,
3884 const void* buffer,
3885 ULONG* bytesWritten)
3887 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3888 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3889 ULONG bytesToWrite;
3890 ULONG blockIndex;
3891 BYTE* bufferWalker;
3892 BYTE* bigBlockBuffer;
3895 * Find the first block in the stream that contains part of the buffer.
3897 blockIndex = BlockChainStream_GetHeadOfChain(This);
3899 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3901 blockIndex =
3902 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3904 blockNoInSequence--;
3908 * Here, I'm casting away the constness on the buffer variable
3909 * This is OK since we don't intend to modify that buffer.
3911 *bytesWritten = 0;
3912 bufferWalker = (BYTE*)buffer;
3914 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3917 * Calculate how many bytes we can copy from this big block.
3919 bytesToWrite =
3920 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3923 * Copy those bytes to the buffer
3925 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
3927 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
3929 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3932 * Step to the next big block.
3934 blockIndex =
3935 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3937 bufferWalker += bytesToWrite;
3938 size -= bytesToWrite;
3939 *bytesWritten += bytesToWrite;
3940 offsetInBlock = 0; /* There is no offset on the next block */
3943 return (size == 0);
3946 /******************************************************************************
3947 * BlockChainStream_Shrink
3949 * Shrinks this chain in the big block depot.
3951 BOOL BlockChainStream_Shrink(BlockChainStream* This,
3952 ULARGE_INTEGER newSize)
3954 ULONG blockIndex, extraBlock;
3955 ULONG numBlocks;
3956 ULONG count = 1;
3959 * Figure out how many blocks are needed to contain the new size
3961 numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3963 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3964 numBlocks++;
3966 blockIndex = BlockChainStream_GetHeadOfChain(This);
3969 * Go to the new end of chain
3971 while (count < numBlocks)
3973 blockIndex =
3974 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3976 count++;
3979 /* Get the next block before marking the new end */
3980 extraBlock =
3981 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3983 /* Mark the new end of chain */
3984 StorageImpl_SetNextBlockInChain(
3985 This->parentStorage,
3986 blockIndex,
3987 BLOCK_END_OF_CHAIN);
3990 * Mark the extra blocks as free
3992 while (extraBlock != BLOCK_END_OF_CHAIN)
3994 blockIndex =
3995 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
3997 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
3998 extraBlock = blockIndex;
4001 return TRUE;
4004 /******************************************************************************
4005 * BlockChainStream_Enlarge
4007 * Grows this chain in the big block depot.
4009 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4010 ULARGE_INTEGER newSize)
4012 ULONG blockIndex, currentBlock;
4013 ULONG newNumBlocks;
4014 ULONG oldNumBlocks = 0;
4016 blockIndex = BlockChainStream_GetHeadOfChain(This);
4019 * Empty chain. Create the head.
4021 if (blockIndex == BLOCK_END_OF_CHAIN)
4023 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4024 StorageImpl_SetNextBlockInChain(This->parentStorage,
4025 blockIndex,
4026 BLOCK_END_OF_CHAIN);
4028 if (This->headOfStreamPlaceHolder != 0)
4030 *(This->headOfStreamPlaceHolder) = blockIndex;
4032 else
4034 StgProperty chainProp;
4035 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4037 StorageImpl_ReadProperty(
4038 This->parentStorage,
4039 This->ownerPropertyIndex,
4040 &chainProp);
4042 chainProp.startingBlock = blockIndex;
4044 StorageImpl_WriteProperty(
4045 This->parentStorage,
4046 This->ownerPropertyIndex,
4047 &chainProp);
4051 currentBlock = blockIndex;
4054 * Figure out how many blocks are needed to contain this stream
4056 newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
4058 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
4059 newNumBlocks++;
4062 * Go to the current end of chain
4064 while (blockIndex != BLOCK_END_OF_CHAIN)
4066 oldNumBlocks++;
4067 currentBlock = blockIndex;
4069 blockIndex =
4070 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4074 * Add new blocks to the chain
4076 while (oldNumBlocks < newNumBlocks)
4078 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4080 StorageImpl_SetNextBlockInChain(
4081 This->parentStorage,
4082 currentBlock,
4083 blockIndex);
4085 StorageImpl_SetNextBlockInChain(
4086 This->parentStorage,
4087 blockIndex,
4088 BLOCK_END_OF_CHAIN);
4090 currentBlock = blockIndex;
4091 oldNumBlocks++;
4094 return TRUE;
4097 /******************************************************************************
4098 * BlockChainStream_SetSize
4100 * Sets the size of this stream. The big block depot will be updated.
4101 * The file will grow if we grow the chain.
4103 * TODO: Free the actual blocks in the file when we shrink the chain.
4104 * Currently, the blocks are still in the file. So the file size
4105 * doesn't shrink even if we shrink streams.
4107 BOOL BlockChainStream_SetSize(
4108 BlockChainStream* This,
4109 ULARGE_INTEGER newSize)
4111 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4113 if (newSize.LowPart == size.LowPart)
4114 return TRUE;
4116 if (newSize.LowPart < size.LowPart)
4118 BlockChainStream_Shrink(This, newSize);
4120 else
4122 ULARGE_INTEGER fileSize =
4123 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4125 ULONG diff = newSize.LowPart - size.LowPart;
4128 * Make sure the file stays a multiple of blocksize
4130 if ((diff % This->parentStorage->bigBlockSize) != 0)
4131 diff += (This->parentStorage->bigBlockSize -
4132 (diff % This->parentStorage->bigBlockSize) );
4134 fileSize.LowPart += diff;
4135 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4137 BlockChainStream_Enlarge(This, newSize);
4140 return TRUE;
4143 /******************************************************************************
4144 * BlockChainStream_GetSize
4146 * Returns the size of this chain.
4147 * Will return the block count if this chain doesn't have a property.
4149 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4151 StgProperty chainProperty;
4153 if(This->headOfStreamPlaceHolder == NULL)
4156 * This chain is a data stream read the property and return
4157 * the appropriate size
4159 StorageImpl_ReadProperty(
4160 This->parentStorage,
4161 This->ownerPropertyIndex,
4162 &chainProperty);
4164 return chainProperty.size;
4166 else
4169 * this chain is a chain that does not have a property, figure out the
4170 * size by making the product number of used blocks times the
4171 * size of them
4173 ULARGE_INTEGER result;
4174 result.HighPart = 0;
4176 result.LowPart =
4177 BlockChainStream_GetCount(This) *
4178 This->parentStorage->bigBlockSize;
4180 return result;
4184 /******************************************************************************
4185 ** SmallBlockChainStream implementation
4188 SmallBlockChainStream* SmallBlockChainStream_Construct(
4189 StorageImpl* parentStorage,
4190 ULONG propertyIndex)
4192 SmallBlockChainStream* newStream;
4194 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4196 newStream->parentStorage = parentStorage;
4197 newStream->ownerPropertyIndex = propertyIndex;
4199 return newStream;
4202 void SmallBlockChainStream_Destroy(
4203 SmallBlockChainStream* This)
4205 HeapFree(GetProcessHeap(), 0, This);
4208 /******************************************************************************
4209 * SmallBlockChainStream_GetHeadOfChain
4211 * Returns the head of this chain of small blocks.
4213 ULONG SmallBlockChainStream_GetHeadOfChain(
4214 SmallBlockChainStream* This)
4216 StgProperty chainProperty;
4217 BOOL readSucessful;
4219 if (This->ownerPropertyIndex)
4221 readSucessful = StorageImpl_ReadProperty(
4222 This->parentStorage,
4223 This->ownerPropertyIndex,
4224 &chainProperty);
4226 if (readSucessful)
4228 return chainProperty.startingBlock;
4233 return BLOCK_END_OF_CHAIN;
4236 /******************************************************************************
4237 * SmallBlockChainStream_GetNextBlockInChain
4239 * Returns the index of the next small block in this chain.
4241 * Return Values:
4242 * - BLOCK_END_OF_CHAIN: end of this chain
4243 * - BLOCK_UNUSED: small block 'blockIndex' is free
4245 ULONG SmallBlockChainStream_GetNextBlockInChain(
4246 SmallBlockChainStream* This,
4247 ULONG blockIndex)
4249 ULARGE_INTEGER offsetOfBlockInDepot;
4250 DWORD buffer;
4251 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4252 ULONG bytesRead;
4253 BOOL success;
4255 offsetOfBlockInDepot.HighPart = 0;
4256 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4259 * Read those bytes in the buffer from the small block file.
4261 success = BlockChainStream_ReadAt(
4262 This->parentStorage->smallBlockDepotChain,
4263 offsetOfBlockInDepot,
4264 sizeof(DWORD),
4265 &buffer,
4266 &bytesRead);
4268 if (success)
4270 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4273 return nextBlockInChain;
4276 /******************************************************************************
4277 * SmallBlockChainStream_SetNextBlockInChain
4279 * Writes the index of the next block of the specified block in the small
4280 * block depot.
4281 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4282 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4284 void SmallBlockChainStream_SetNextBlockInChain(
4285 SmallBlockChainStream* This,
4286 ULONG blockIndex,
4287 ULONG nextBlock)
4289 ULARGE_INTEGER offsetOfBlockInDepot;
4290 DWORD buffer;
4291 ULONG bytesWritten;
4293 offsetOfBlockInDepot.HighPart = 0;
4294 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4296 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4299 * Read those bytes in the buffer from the small block file.
4301 BlockChainStream_WriteAt(
4302 This->parentStorage->smallBlockDepotChain,
4303 offsetOfBlockInDepot,
4304 sizeof(DWORD),
4305 &buffer,
4306 &bytesWritten);
4309 /******************************************************************************
4310 * SmallBlockChainStream_FreeBlock
4312 * Flag small block 'blockIndex' as free in the small block depot.
4314 void SmallBlockChainStream_FreeBlock(
4315 SmallBlockChainStream* This,
4316 ULONG blockIndex)
4318 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4321 /******************************************************************************
4322 * SmallBlockChainStream_GetNextFreeBlock
4324 * Returns the index of a free small block. The small block depot will be
4325 * enlarged if necessary. The small block chain will also be enlarged if
4326 * necessary.
4328 ULONG SmallBlockChainStream_GetNextFreeBlock(
4329 SmallBlockChainStream* This)
4331 ULARGE_INTEGER offsetOfBlockInDepot;
4332 DWORD buffer;
4333 ULONG bytesRead;
4334 ULONG blockIndex = 0;
4335 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4336 BOOL success = TRUE;
4337 ULONG smallBlocksPerBigBlock;
4339 offsetOfBlockInDepot.HighPart = 0;
4342 * Scan the small block depot for a free block
4344 while (nextBlockIndex != BLOCK_UNUSED)
4346 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4348 success = BlockChainStream_ReadAt(
4349 This->parentStorage->smallBlockDepotChain,
4350 offsetOfBlockInDepot,
4351 sizeof(DWORD),
4352 &buffer,
4353 &bytesRead);
4356 * If we run out of space for the small block depot, enlarge it
4358 if (success)
4360 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4362 if (nextBlockIndex != BLOCK_UNUSED)
4363 blockIndex++;
4365 else
4367 ULONG count =
4368 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4370 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4371 ULONG nextBlock, newsbdIndex;
4372 BYTE* smallBlockDepot;
4374 nextBlock = sbdIndex;
4375 while (nextBlock != BLOCK_END_OF_CHAIN)
4377 sbdIndex = nextBlock;
4378 nextBlock =
4379 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4382 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4383 if (sbdIndex != BLOCK_END_OF_CHAIN)
4384 StorageImpl_SetNextBlockInChain(
4385 This->parentStorage,
4386 sbdIndex,
4387 newsbdIndex);
4389 StorageImpl_SetNextBlockInChain(
4390 This->parentStorage,
4391 newsbdIndex,
4392 BLOCK_END_OF_CHAIN);
4395 * Initialize all the small blocks to free
4397 smallBlockDepot =
4398 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4400 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4401 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4403 if (count == 0)
4406 * We have just created the small block depot.
4408 StgProperty rootProp;
4409 ULONG sbStartIndex;
4412 * Save it in the header
4414 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4415 StorageImpl_SaveFileHeader(This->parentStorage);
4418 * And allocate the first big block that will contain small blocks
4420 sbStartIndex =
4421 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4423 StorageImpl_SetNextBlockInChain(
4424 This->parentStorage,
4425 sbStartIndex,
4426 BLOCK_END_OF_CHAIN);
4428 StorageImpl_ReadProperty(
4429 This->parentStorage,
4430 This->parentStorage->rootPropertySetIndex,
4431 &rootProp);
4433 rootProp.startingBlock = sbStartIndex;
4434 rootProp.size.HighPart = 0;
4435 rootProp.size.LowPart = This->parentStorage->bigBlockSize;
4437 StorageImpl_WriteProperty(
4438 This->parentStorage,
4439 This->parentStorage->rootPropertySetIndex,
4440 &rootProp);
4445 smallBlocksPerBigBlock =
4446 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4449 * Verify if we have to allocate big blocks to contain small blocks
4451 if (blockIndex % smallBlocksPerBigBlock == 0)
4453 StgProperty rootProp;
4454 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4456 StorageImpl_ReadProperty(
4457 This->parentStorage,
4458 This->parentStorage->rootPropertySetIndex,
4459 &rootProp);
4461 if (rootProp.size.LowPart <
4462 (blocksRequired * This->parentStorage->bigBlockSize))
4464 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4466 BlockChainStream_SetSize(
4467 This->parentStorage->smallBlockRootChain,
4468 rootProp.size);
4470 StorageImpl_WriteProperty(
4471 This->parentStorage,
4472 This->parentStorage->rootPropertySetIndex,
4473 &rootProp);
4477 return blockIndex;
4480 /******************************************************************************
4481 * SmallBlockChainStream_ReadAt
4483 * Reads a specified number of bytes from this chain at the specified offset.
4484 * bytesRead may be NULL.
4485 * Failure will be returned if the specified number of bytes has not been read.
4487 BOOL SmallBlockChainStream_ReadAt(
4488 SmallBlockChainStream* This,
4489 ULARGE_INTEGER offset,
4490 ULONG size,
4491 void* buffer,
4492 ULONG* bytesRead)
4494 ULARGE_INTEGER offsetInBigBlockFile;
4495 ULONG blockNoInSequence =
4496 offset.LowPart / This->parentStorage->smallBlockSize;
4498 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4499 ULONG bytesToReadInBuffer;
4500 ULONG blockIndex;
4501 ULONG bytesReadFromBigBlockFile;
4502 BYTE* bufferWalker;
4505 * This should never happen on a small block file.
4507 assert(offset.HighPart==0);
4510 * Find the first block in the stream that contains part of the buffer.
4512 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4514 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4516 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4518 blockNoInSequence--;
4522 * Start reading the buffer.
4524 *bytesRead = 0;
4525 bufferWalker = buffer;
4527 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4530 * Calculate how many bytes we can copy from this small block.
4532 bytesToReadInBuffer =
4533 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4536 * Calculate the offset of the small block in the small block file.
4538 offsetInBigBlockFile.HighPart = 0;
4539 offsetInBigBlockFile.LowPart =
4540 blockIndex * This->parentStorage->smallBlockSize;
4542 offsetInBigBlockFile.LowPart += offsetInBlock;
4545 * Read those bytes in the buffer from the small block file.
4547 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4548 offsetInBigBlockFile,
4549 bytesToReadInBuffer,
4550 bufferWalker,
4551 &bytesReadFromBigBlockFile);
4553 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4556 * Step to the next big block.
4558 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4559 bufferWalker += bytesToReadInBuffer;
4560 size -= bytesToReadInBuffer;
4561 *bytesRead += bytesToReadInBuffer;
4562 offsetInBlock = 0; /* There is no offset on the next block */
4565 return (size == 0);
4568 /******************************************************************************
4569 * SmallBlockChainStream_WriteAt
4571 * Writes the specified number of bytes to this chain at the specified offset.
4572 * bytesWritten may be NULL.
4573 * Will fail if not all specified number of bytes have been written.
4575 BOOL SmallBlockChainStream_WriteAt(
4576 SmallBlockChainStream* This,
4577 ULARGE_INTEGER offset,
4578 ULONG size,
4579 const void* buffer,
4580 ULONG* bytesWritten)
4582 ULARGE_INTEGER offsetInBigBlockFile;
4583 ULONG blockNoInSequence =
4584 offset.LowPart / This->parentStorage->smallBlockSize;
4586 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4587 ULONG bytesToWriteInBuffer;
4588 ULONG blockIndex;
4589 ULONG bytesWrittenFromBigBlockFile;
4590 BYTE* bufferWalker;
4593 * This should never happen on a small block file.
4595 assert(offset.HighPart==0);
4598 * Find the first block in the stream that contains part of the buffer.
4600 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4602 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4604 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4606 blockNoInSequence--;
4610 * Start writing the buffer.
4612 * Here, I'm casting away the constness on the buffer variable
4613 * This is OK since we don't intend to modify that buffer.
4615 *bytesWritten = 0;
4616 bufferWalker = (BYTE*)buffer;
4617 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4620 * Calculate how many bytes we can copy to this small block.
4622 bytesToWriteInBuffer =
4623 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4626 * Calculate the offset of the small block in the small block file.
4628 offsetInBigBlockFile.HighPart = 0;
4629 offsetInBigBlockFile.LowPart =
4630 blockIndex * This->parentStorage->smallBlockSize;
4632 offsetInBigBlockFile.LowPart += offsetInBlock;
4635 * Write those bytes in the buffer to the small block file.
4637 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4638 offsetInBigBlockFile,
4639 bytesToWriteInBuffer,
4640 bufferWalker,
4641 &bytesWrittenFromBigBlockFile);
4643 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4646 * Step to the next big block.
4648 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4649 bufferWalker += bytesToWriteInBuffer;
4650 size -= bytesToWriteInBuffer;
4651 *bytesWritten += bytesToWriteInBuffer;
4652 offsetInBlock = 0; /* There is no offset on the next block */
4655 return (size == 0);
4658 /******************************************************************************
4659 * SmallBlockChainStream_Shrink
4661 * Shrinks this chain in the small block depot.
4663 BOOL SmallBlockChainStream_Shrink(
4664 SmallBlockChainStream* This,
4665 ULARGE_INTEGER newSize)
4667 ULONG blockIndex, extraBlock;
4668 ULONG numBlocks;
4669 ULONG count = 1;
4671 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4673 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4674 numBlocks++;
4676 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4679 * Go to the new end of chain
4681 while (count < numBlocks)
4683 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4684 count++;
4687 /* Get the next block before marking the new end */
4688 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4690 /* Mark the new end of chain */
4691 SmallBlockChainStream_SetNextBlockInChain(
4692 This,
4693 blockIndex,
4694 BLOCK_END_OF_CHAIN);
4697 * Mark the extra blocks as free
4699 while (extraBlock != BLOCK_END_OF_CHAIN)
4701 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4702 SmallBlockChainStream_FreeBlock(This, extraBlock);
4703 extraBlock = blockIndex;
4706 return TRUE;
4709 /******************************************************************************
4710 * SmallBlockChainStream_Enlarge
4712 * Grows this chain in the small block depot.
4714 BOOL SmallBlockChainStream_Enlarge(
4715 SmallBlockChainStream* This,
4716 ULARGE_INTEGER newSize)
4718 ULONG blockIndex, currentBlock;
4719 ULONG newNumBlocks;
4720 ULONG oldNumBlocks = 0;
4722 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4725 * Empty chain
4727 if (blockIndex == BLOCK_END_OF_CHAIN)
4729 StgProperty chainProp;
4731 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4732 &chainProp);
4734 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4736 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4737 &chainProp);
4739 blockIndex = chainProp.startingBlock;
4740 SmallBlockChainStream_SetNextBlockInChain(
4741 This,
4742 blockIndex,
4743 BLOCK_END_OF_CHAIN);
4746 currentBlock = blockIndex;
4749 * Figure out how many blocks are needed to contain this stream
4751 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4753 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4754 newNumBlocks++;
4757 * Go to the current end of chain
4759 while (blockIndex != BLOCK_END_OF_CHAIN)
4761 oldNumBlocks++;
4762 currentBlock = blockIndex;
4763 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4767 * Add new blocks to the chain
4769 while (oldNumBlocks < newNumBlocks)
4771 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4772 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4774 SmallBlockChainStream_SetNextBlockInChain(
4775 This,
4776 blockIndex,
4777 BLOCK_END_OF_CHAIN);
4779 currentBlock = blockIndex;
4780 oldNumBlocks++;
4783 return TRUE;
4786 /******************************************************************************
4787 * SmallBlockChainStream_GetCount
4789 * Returns the number of blocks that comprises this chain.
4790 * This is not the size of this chain as the last block may not be full!
4792 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4794 ULONG blockIndex;
4795 ULONG count = 0;
4797 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4799 while (blockIndex != BLOCK_END_OF_CHAIN)
4801 count++;
4803 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4806 return count;
4809 /******************************************************************************
4810 * SmallBlockChainStream_SetSize
4812 * Sets the size of this stream.
4813 * The file will grow if we grow the chain.
4815 * TODO: Free the actual blocks in the file when we shrink the chain.
4816 * Currently, the blocks are still in the file. So the file size
4817 * doesn't shrink even if we shrink streams.
4819 BOOL SmallBlockChainStream_SetSize(
4820 SmallBlockChainStream* This,
4821 ULARGE_INTEGER newSize)
4823 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4825 if (newSize.LowPart == size.LowPart)
4826 return TRUE;
4828 if (newSize.LowPart < size.LowPart)
4830 SmallBlockChainStream_Shrink(This, newSize);
4832 else
4834 SmallBlockChainStream_Enlarge(This, newSize);
4837 return TRUE;
4840 /******************************************************************************
4841 * SmallBlockChainStream_GetSize
4843 * Returns the size of this chain.
4845 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4847 StgProperty chainProperty;
4849 StorageImpl_ReadProperty(
4850 This->parentStorage,
4851 This->ownerPropertyIndex,
4852 &chainProperty);
4854 return chainProperty.size;
4857 /******************************************************************************
4858 * StgCreateDocfile32 [OLE32.144]
4859 * TODO Validate grfMode (STGM)
4861 HRESULT WINAPI StgCreateDocfile(
4862 LPCOLESTR pwcsName,
4863 DWORD grfMode,
4864 DWORD reserved,
4865 IStorage **ppstgOpen)
4867 StorageImpl* newStorage = 0;
4868 HANDLE hFile = INVALID_HANDLE_VALUE;
4869 HRESULT hr = S_OK;
4870 DWORD shareMode;
4871 DWORD accessMode;
4872 DWORD creationMode;
4873 DWORD fileAttributes;
4876 * Validate the parameters
4878 if ((ppstgOpen == 0) || (pwcsName == 0))
4879 return STG_E_INVALIDPOINTER;
4882 * Validate the STGM flags
4884 if ( FAILED( validateSTGM(grfMode) ))
4885 return STG_E_INVALIDFLAG;
4888 * Interpret the STGM value grfMode
4890 shareMode = GetShareModeFromSTGM(grfMode);
4891 accessMode = GetAccessModeFromSTGM(grfMode);
4892 creationMode = GetCreationModeFromSTGM(grfMode);
4894 if (grfMode & STGM_DELETEONRELEASE)
4895 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
4896 else
4897 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
4899 if (grfMode & STGM_TRANSACTED)
4900 FIXME(ole, "Transacted mode not implemented.\n");
4903 * Initialize the "out" parameter.
4905 *ppstgOpen = 0;
4907 hFile = CreateFileW(pwcsName,
4908 accessMode,
4909 shareMode,
4910 NULL,
4911 creationMode,
4912 fileAttributes,
4915 if (hFile == INVALID_HANDLE_VALUE)
4917 return E_FAIL;
4921 * Allocate and initialize the new IStorage32object.
4923 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
4925 if (newStorage == 0)
4926 return STG_E_INSUFFICIENTMEMORY;
4928 hr = StorageImpl_Construct(
4929 newStorage,
4930 hFile,
4931 grfMode);
4933 if (FAILED(hr))
4934 return hr;
4937 * Get an "out" pointer for the caller.
4939 hr = StorageBaseImpl_QueryInterface(
4940 (IStorage*)newStorage,
4941 (REFIID)&IID_IStorage,
4942 (void**)ppstgOpen);
4944 return hr;
4947 /******************************************************************************
4948 * StgOpenStorage32 [OLE32.148]
4950 HRESULT WINAPI StgOpenStorage(
4951 const OLECHAR *pwcsName,
4952 IStorage *pstgPriority,
4953 DWORD grfMode,
4954 SNB snbExclude,
4955 DWORD reserved,
4956 IStorage **ppstgOpen)
4958 StorageImpl* newStorage = 0;
4959 HRESULT hr = S_OK;
4960 HANDLE hFile = 0;
4961 DWORD shareMode;
4962 DWORD accessMode;
4965 * Perform a sanity check
4967 if (( pwcsName == 0) || (ppstgOpen == 0) )
4968 return STG_E_INVALIDPOINTER;
4971 * Validate the STGM flags
4973 if ( FAILED( validateSTGM(grfMode) ))
4974 return STG_E_INVALIDFLAG;
4977 * Interpret the STGM value grfMode
4979 shareMode = GetShareModeFromSTGM(grfMode);
4980 accessMode = GetAccessModeFromSTGM(grfMode);
4983 * Initialize the "out" parameter.
4985 *ppstgOpen = 0;
4987 hFile = CreateFileW( pwcsName,
4988 accessMode,
4989 shareMode,
4990 NULL,
4991 OPEN_EXISTING,
4992 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
4996 if (hFile==INVALID_HANDLE_VALUE)
4998 return E_FAIL;
5002 * Allocate and initialize the new IStorage32object.
5004 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5006 if (newStorage == 0)
5007 return STG_E_INSUFFICIENTMEMORY;
5009 hr = StorageImpl_Construct(
5010 newStorage,
5011 hFile,
5012 grfMode);
5014 if (FAILED(hr))
5015 return hr;
5018 * Get an "out" pointer for the caller.
5020 hr = StorageBaseImpl_QueryInterface(
5021 (IStorage*)newStorage,
5022 (REFIID)&IID_IStorage,
5023 (void**)ppstgOpen);
5025 return hr;
5028 /******************************************************************************
5029 * WriteClassStg32 [OLE32.148]
5031 * This method will store the specified CLSID in the specified storage object
5033 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5035 HRESULT hRes;
5037 assert(pStg != 0);
5039 hRes = IStorage_SetClass(pStg, rclsid);
5041 return hRes;
5045 /****************************************************************************
5046 * This method validate a STGM parameter that can contain the values below
5048 * STGM_DIRECT 0x00000000
5049 * STGM_TRANSACTED 0x00010000
5050 * STGM_SIMPLE 0x08000000
5052 * STGM_READ 0x00000000
5053 * STGM_WRITE 0x00000001
5054 * STGM_READWRITE 0x00000002
5056 * STGM_SHARE_DENY_NONE 0x00000040
5057 * STGM_SHARE_DENY_READ 0x00000030
5058 * STGM_SHARE_DENY_WRITE 0x00000020
5059 * STGM_SHARE_EXCLUSIVE 0x00000010
5061 * STGM_PRIORITY 0x00040000
5062 * STGM_DELETEONRELEASE 0x04000000
5064 * STGM_CREATE 0x00001000
5065 * STGM_CONVERT 0x00020000
5066 * STGM_FAILIFTHERE 0x00000000
5068 * STGM_NOSCRATCH 0x00100000
5069 * STGM_NOSNAPSHOT 0x00200000
5071 static HRESULT validateSTGM(DWORD stgm)
5073 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5074 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5075 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5077 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5078 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5079 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5081 BOOL bSTGM_SHARE_DENY_NONE =
5082 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5084 BOOL bSTGM_SHARE_DENY_READ =
5085 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5087 BOOL bSTGM_SHARE_DENY_WRITE =
5088 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5090 BOOL bSTGM_SHARE_EXCLUSIVE =
5091 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5093 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5094 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5096 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5097 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5100 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5102 if ( ! bSTGM_DIRECT )
5103 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5104 return E_FAIL;
5107 * STGM_WRITE | STGM_READWRITE | STGM_READ
5109 if ( ! bSTGM_READ )
5110 if( bSTGM_WRITE && bSTGM_READWRITE )
5111 return E_FAIL;
5114 * STGM_SHARE_DENY_NONE | others
5115 * (I assume here that DENY_READ implies DENY_WRITE)
5117 if ( bSTGM_SHARE_DENY_NONE )
5118 if ( bSTGM_SHARE_DENY_READ ||
5119 bSTGM_SHARE_DENY_WRITE ||
5120 bSTGM_SHARE_EXCLUSIVE)
5121 return E_FAIL;
5124 * STGM_CREATE | STGM_CONVERT
5125 * if both are false, STGM_FAILIFTHERE is set to TRUE
5127 if ( bSTGM_CREATE && bSTGM_CONVERT )
5128 return E_FAIL;
5131 * STGM_NOSCRATCH requires STGM_TRANSACTED
5133 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5134 return E_FAIL;
5137 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5138 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5140 if (bSTGM_NOSNAPSHOT)
5142 if ( ! ( bSTGM_TRANSACTED &&
5143 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5144 return E_FAIL;
5147 return S_OK;
5150 /****************************************************************************
5151 * GetShareModeFromSTGM
5153 * This method will return a share mode flag from a STGM value.
5154 * The STGM value is assumed valid.
5156 static DWORD GetShareModeFromSTGM(DWORD stgm)
5158 DWORD dwShareMode = 0;
5159 BOOL bSTGM_SHARE_DENY_NONE =
5160 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5162 BOOL bSTGM_SHARE_DENY_READ =
5163 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5165 BOOL bSTGM_SHARE_DENY_WRITE =
5166 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5168 BOOL bSTGM_SHARE_EXCLUSIVE =
5169 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5171 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5172 dwShareMode = 0;
5174 if (bSTGM_SHARE_DENY_NONE)
5175 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5177 if (bSTGM_SHARE_DENY_WRITE)
5178 dwShareMode = FILE_SHARE_READ;
5180 return dwShareMode;
5183 /****************************************************************************
5184 * GetAccessModeFromSTGM
5186 * This method will return an access mode flag from a STGM value.
5187 * The STGM value is assumed valid.
5189 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5191 DWORD dwDesiredAccess = 0;
5192 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5193 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5194 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5196 if (bSTGM_READ)
5197 dwDesiredAccess = GENERIC_READ;
5199 if (bSTGM_WRITE)
5200 dwDesiredAccess |= GENERIC_WRITE;
5202 if (bSTGM_READWRITE)
5203 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5205 return dwDesiredAccess;
5208 /****************************************************************************
5209 * GetCreationModeFromSTGM
5211 * This method will return a creation mode flag from a STGM value.
5212 * The STGM value is assumed valid.
5214 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5216 DWORD dwCreationDistribution;
5217 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5218 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5219 BOOL bSTGM_FAILIFTHERE = ! (bSTGM_CREATE || bSTGM_CONVERT);
5221 if (bSTGM_CREATE)
5222 dwCreationDistribution = CREATE_ALWAYS;
5223 else if (bSTGM_FAILIFTHERE)
5224 dwCreationDistribution = CREATE_NEW;
5225 else if (bSTGM_CONVERT)
5227 FIXME(ole, "STGM_CONVERT not implemented!\n");
5228 dwCreationDistribution = CREATE_NEW;
5231 return dwCreationDistribution;