Message translation for WM_WININICHANGE.
[wine/multimedia.git] / ole / storage32.c
blob2a222d15347a586f12c114d8c77c1719d7d9c065
1 /*
2 * Compound Storage (32 bit version)
3 * Storage implementation
5 * This file contains the compound file implementation
6 * of the storage interface.
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Sylvain St-Germain
10 * Copyright 1999 Thuy Nguyen
13 #include <assert.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
18 #include "winbase.h"
19 #include "winerror.h"
20 #include "wine/obj_storage.h"
21 #include "wine/winestring.h"
22 #include "crtdll.h"
23 #include "tchar.h"
24 #include "debug.h"
26 #include "storage32.h"
28 #define FILE_BEGIN 0
30 static const char rootPropertyName[] = "Root Entry";
32 /***********************************************************************
33 * Forward declaration of internal functions used by the method DestroyElement
35 static HRESULT deleteStorageProperty(
36 StorageImpl *parentStorage,
37 OLECHAR *propertyToDeleteName);
39 static HRESULT deleteStreamProperty(
40 StorageImpl *parentStorage,
41 ULONG foundPropertyIndexToDelete,
42 StgProperty propertyToDelete);
44 static HRESULT findPlaceholder(
45 StorageImpl *storage,
46 ULONG propertyIndexToStore,
47 ULONG storagePropertyIndex,
48 INT typeOfRelation);
50 static HRESULT adjustPropertyChain(
51 StorageImpl *This,
52 StgProperty propertyToDelete,
53 StgProperty parentProperty,
54 ULONG parentPropertyId,
55 INT typeOfRelation);
57 /***********************************************************************
58 * Declaration of the functions used to manipulate StgProperty
61 static ULONG getFreeProperty(
62 StorageImpl *storage);
64 static void updatePropertyChain(
65 StorageImpl *storage,
66 ULONG newPropertyIndex,
67 StgProperty newProperty);
69 static LONG propertyNameCmp(
70 OLECHAR *newProperty,
71 OLECHAR *currentProperty);
74 /***********************************************************************
75 * Declaration of miscellaneous functions...
77 static HRESULT validateSTGM(DWORD stgmValue);
79 static DWORD GetShareModeFromSTGM(DWORD stgm);
80 static DWORD GetAccessModeFromSTGM(DWORD stgm);
81 static DWORD GetCreationModeFromSTGM(DWORD stgm);
84 * Virtual function table for the IStorage32Impl class.
86 static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
88 StorageBaseImpl_QueryInterface,
89 StorageBaseImpl_AddRef,
90 StorageBaseImpl_Release,
91 StorageBaseImpl_CreateStream,
92 StorageBaseImpl_OpenStream,
93 StorageImpl_CreateStorage,
94 StorageBaseImpl_OpenStorage,
95 StorageImpl_CopyTo,
96 StorageImpl_MoveElementTo,
97 StorageImpl_Commit,
98 StorageImpl_Revert,
99 StorageBaseImpl_EnumElements,
100 StorageImpl_DestroyElement,
101 StorageBaseImpl_RenameElement,
102 StorageImpl_SetElementTimes,
103 StorageBaseImpl_SetClass,
104 StorageImpl_SetStateBits,
105 StorageBaseImpl_Stat
109 * Virtual function table for the Storage32InternalImpl class.
111 static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
113 StorageBaseImpl_QueryInterface,
114 StorageBaseImpl_AddRef,
115 StorageBaseImpl_Release,
116 StorageBaseImpl_CreateStream,
117 StorageBaseImpl_OpenStream,
118 StorageImpl_CreateStorage,
119 StorageBaseImpl_OpenStorage,
120 StorageImpl_CopyTo,
121 StorageImpl_MoveElementTo,
122 StorageInternalImpl_Commit,
123 StorageInternalImpl_Revert,
124 StorageBaseImpl_EnumElements,
125 StorageImpl_DestroyElement,
126 StorageBaseImpl_RenameElement,
127 StorageImpl_SetElementTimes,
128 StorageBaseImpl_SetClass,
129 StorageImpl_SetStateBits,
130 StorageBaseImpl_Stat
134 * Virtual function table for the IEnumSTATSTGImpl class.
136 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
138 IEnumSTATSTGImpl_QueryInterface,
139 IEnumSTATSTGImpl_AddRef,
140 IEnumSTATSTGImpl_Release,
141 IEnumSTATSTGImpl_Next,
142 IEnumSTATSTGImpl_Skip,
143 IEnumSTATSTGImpl_Reset,
144 IEnumSTATSTGImpl_Clone
151 /************************************************************************
152 ** Storage32BaseImpl implementatiion
155 /************************************************************************
156 * Storage32BaseImpl_QueryInterface (IUnknown)
158 * This method implements the common QueryInterface for all IStorage32
159 * implementations contained in this file.
161 * See Windows documentation for more details on IUnknown methods.
163 HRESULT WINAPI StorageBaseImpl_QueryInterface(
164 IStorage* iface,
165 REFIID riid,
166 void** ppvObject)
168 ICOM_THIS(StorageBaseImpl,iface);
170 * Perform a sanity check on the parameters.
172 if ( (This==0) || (ppvObject==0) )
173 return E_INVALIDARG;
176 * Initialize the return parameter.
178 *ppvObject = 0;
181 * Compare the riid with the interface IDs implemented by this object.
183 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
185 *ppvObject = (IStorage*)This;
187 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
189 *ppvObject = (IStorage*)This;
193 * Check that we obtained an interface.
195 if ((*ppvObject)==0)
196 return E_NOINTERFACE;
199 * Query Interface always increases the reference count by one when it is
200 * successful
202 StorageBaseImpl_AddRef(iface);
204 return S_OK;
207 /************************************************************************
208 * Storage32BaseImpl_AddRef (IUnknown)
210 * This method implements the common AddRef for all IStorage32
211 * implementations contained in this file.
213 * See Windows documentation for more details on IUnknown methods.
215 ULONG WINAPI StorageBaseImpl_AddRef(
216 IStorage* iface)
218 ICOM_THIS(StorageBaseImpl,iface);
219 This->ref++;
221 return This->ref;
224 /************************************************************************
225 * Storage32BaseImpl_Release (IUnknown)
227 * This method implements the common Release for all IStorage32
228 * implementations contained in this file.
230 * See Windows documentation for more details on IUnknown methods.
232 ULONG WINAPI StorageBaseImpl_Release(
233 IStorage* iface)
235 ICOM_THIS(StorageBaseImpl,iface);
237 * Decrease the reference count on this object.
239 This->ref--;
242 * If the reference count goes down to 0, perform suicide.
244 if (This->ref==0)
247 * Since we are using a system of base-classes, we want to call the
248 * destructor of the appropriate derived class. To do this, we are
249 * using virtual functions to implement the destructor.
251 This->v_destructor(This);
253 return 0;
256 return This->ref;
259 /************************************************************************
260 * Storage32BaseImpl_OpenStream (IStorage)
262 * This method will open the specified stream object from the current storage.
264 * See Windows documentation for more details on IStorage methods.
266 HRESULT WINAPI StorageBaseImpl_OpenStream(
267 IStorage* iface,
268 const OLECHAR* pwcsName, /* [string][in] */
269 void* reserved1, /* [unique][in] */
270 DWORD grfMode, /* [in] */
271 DWORD reserved2, /* [in] */
272 IStream** ppstm) /* [out] */
274 ICOM_THIS(StorageBaseImpl,iface);
275 IEnumSTATSTGImpl* propertyEnumeration;
276 StgStreamImpl* newStream;
277 StgProperty currentProperty;
278 ULONG foundPropertyIndex;
281 * Perform a sanity check on the parameters.
283 if ( (pwcsName==NULL) || (ppstm==0) )
284 return E_INVALIDARG;
287 * Initialize the out parameter
289 *ppstm = 0;
292 * Validate the STGM flags
294 if ( FAILED( validateSTGM(grfMode) ))
295 return STG_E_INVALIDFLAG;
298 * As documented.
300 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
301 (grfMode & STGM_DELETEONRELEASE) ||
302 (grfMode & STGM_TRANSACTED) )
303 return STG_E_INVALIDFUNCTION;
306 * Create a property enumeration to search the properties
308 propertyEnumeration = IEnumSTATSTGImpl_Construct(
309 This->ancestorStorage,
310 This->rootPropertySetIndex);
313 * Search the enumeration for the property with the given name
315 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
316 propertyEnumeration,
317 pwcsName,
318 &currentProperty);
321 * Delete the property enumeration since we don't need it anymore
323 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
326 * If it was found, construct the stream object and return a pointer to it.
328 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
329 (currentProperty.propertyType==PROPTYPE_STREAM) )
331 newStream = StgStreamImpl_Construct(This, foundPropertyIndex);
333 if (newStream!=0)
335 *ppstm = (IStream*)newStream;
338 * Since we are returning a pointer to the interface, we have to
339 * nail down the reference.
341 StgStreamImpl_AddRef(*ppstm);
343 return S_OK;
346 return E_OUTOFMEMORY;
349 return STG_E_FILENOTFOUND;
352 /************************************************************************
353 * Storage32BaseImpl_OpenStorage (IStorage)
355 * This method will open a new storage object from the current storage.
357 * See Windows documentation for more details on IStorage methods.
359 HRESULT WINAPI StorageBaseImpl_OpenStorage(
360 IStorage* iface,
361 const OLECHAR* pwcsName, /* [string][unique][in] */
362 IStorage* pstgPriority, /* [unique][in] */
363 DWORD grfMode, /* [in] */
364 SNB snbExclude, /* [unique][in] */
365 DWORD reserved, /* [in] */
366 IStorage** ppstg) /* [out] */
368 ICOM_THIS(StorageBaseImpl,iface);
369 StorageInternalImpl* newStorage;
370 IEnumSTATSTGImpl* propertyEnumeration;
371 StgProperty currentProperty;
372 ULONG foundPropertyIndex;
375 * Perform a sanity check on the parameters.
377 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
378 return E_INVALIDARG;
381 * Validate the STGM flags
383 if ( FAILED( validateSTGM(grfMode) ))
384 return STG_E_INVALIDFLAG;
387 * As documented.
389 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
390 (grfMode & STGM_DELETEONRELEASE) ||
391 (grfMode & STGM_PRIORITY) )
392 return STG_E_INVALIDFUNCTION;
395 * Initialize the out parameter
397 *ppstg = 0;
400 * Create a property enumeration to search the properties
402 propertyEnumeration = IEnumSTATSTGImpl_Construct(
403 This->ancestorStorage,
404 This->rootPropertySetIndex);
407 * Search the enumeration for the property with the given name
409 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
410 propertyEnumeration,
411 pwcsName,
412 &currentProperty);
415 * Delete the property enumeration since we don't need it anymore
417 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
420 * If it was found, construct the stream object and return a pointer to it.
422 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
423 (currentProperty.propertyType==PROPTYPE_STORAGE) )
426 * Construct a new Storage object
428 newStorage = StorageInternalImpl_Construct(
429 This->ancestorStorage,
430 foundPropertyIndex);
432 if (newStorage != 0)
434 *ppstg = (IStorage*)newStorage;
437 * Since we are returning a pointer to the interface,
438 * we have to nail down the reference.
440 StorageBaseImpl_AddRef(*ppstg);
442 return S_OK;
445 return STG_E_INSUFFICIENTMEMORY;
448 return STG_E_FILENOTFOUND;
451 /************************************************************************
452 * Storage32BaseImpl_EnumElements (IStorage)
454 * This method will create an enumerator object that can be used to
455 * retrieve informatino about all the properties in the storage object.
457 * See Windows documentation for more details on IStorage methods.
459 HRESULT WINAPI StorageBaseImpl_EnumElements(
460 IStorage* iface,
461 DWORD reserved1, /* [in] */
462 void* reserved2, /* [size_is][unique][in] */
463 DWORD reserved3, /* [in] */
464 IEnumSTATSTG** ppenum) /* [out] */
466 ICOM_THIS(StorageBaseImpl,iface);
467 IEnumSTATSTGImpl* newEnum;
470 * Perform a sanity check on the parameters.
472 if ( (This==0) || (ppenum==0))
473 return E_INVALIDARG;
476 * Construct the enumerator.
478 newEnum = IEnumSTATSTGImpl_Construct(
479 This->ancestorStorage,
480 This->rootPropertySetIndex);
482 if (newEnum!=0)
484 *ppenum = (IEnumSTATSTG*)newEnum;
487 * Don't forget to nail down a reference to the new object before
488 * returning it.
490 IEnumSTATSTGImpl_AddRef(*ppenum);
492 return S_OK;
495 return E_OUTOFMEMORY;
498 /************************************************************************
499 * Storage32BaseImpl_Stat (IStorage)
501 * This method will retrieve information about this storage object.
503 * See Windows documentation for more details on IStorage methods.
505 HRESULT WINAPI StorageBaseImpl_Stat(
506 IStorage* iface,
507 STATSTG* pstatstg, /* [out] */
508 DWORD grfStatFlag) /* [in] */
510 ICOM_THIS(StorageBaseImpl,iface);
511 StgProperty curProperty;
512 BOOL readSucessful;
515 * Perform a sanity check on the parameters.
517 if ( (This==0) || (pstatstg==0))
518 return E_INVALIDARG;
521 * Read the information from the property.
523 readSucessful = StorageImpl_ReadProperty(
524 This->ancestorStorage,
525 This->rootPropertySetIndex,
526 &curProperty);
528 if (readSucessful)
530 StorageUtl_CopyPropertyToSTATSTG(
531 pstatstg,
532 &curProperty,
533 grfStatFlag);
535 return S_OK;
538 return E_FAIL;
541 /************************************************************************
542 * Storage32BaseImpl_RenameElement (IStorage)
544 * This method will rename the specified element.
546 * See Windows documentation for more details on IStorage methods.
548 * Implementation notes: The method used to rename consists of creating a clone
549 * of the deleted StgProperty object setting it with the new name and to
550 * perform a DestroyElement of the old StgProperty.
552 HRESULT WINAPI StorageBaseImpl_RenameElement(
553 IStorage* iface,
554 const OLECHAR* pwcsOldName, /* [in] */
555 const OLECHAR* pwcsNewName) /* [in] */
557 ICOM_THIS(StorageBaseImpl,iface);
558 IEnumSTATSTGImpl* propertyEnumeration;
559 StgProperty currentProperty;
560 ULONG foundPropertyIndex;
563 * Create a property enumeration to search the properties
565 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
566 This->rootPropertySetIndex);
569 * Search the enumeration for the new property name
571 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
572 pwcsNewName,
573 &currentProperty);
575 if (foundPropertyIndex != PROPERTY_NULL)
578 * There is already a property with the new name
580 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
581 return STG_E_FILEALREADYEXISTS;
584 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
587 * Search the enumeration for the old property name
589 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
590 pwcsOldName,
591 &currentProperty);
594 * Delete the property enumeration since we don't need it anymore
596 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
598 if (foundPropertyIndex != PROPERTY_NULL)
600 StgProperty renamedProperty;
601 ULONG renamedPropertyIndex;
604 * Setup a new property for the renamed property
606 renamedProperty.sizeOfNameString =
607 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
609 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
610 return STG_E_INVALIDNAME;
612 lstrcpyW(renamedProperty.name, pwcsNewName);
614 renamedProperty.propertyType = currentProperty.propertyType;
615 renamedProperty.startingBlock = currentProperty.startingBlock;
616 renamedProperty.size.LowPart = currentProperty.size.LowPart;
617 renamedProperty.size.HighPart = currentProperty.size.HighPart;
619 renamedProperty.previousProperty = PROPERTY_NULL;
620 renamedProperty.nextProperty = PROPERTY_NULL;
623 * Bring the dirProperty link in case it is a storage and in which
624 * case the renamed storage elements don't require to be reorganized.
626 renamedProperty.dirProperty = currentProperty.dirProperty;
628 /* call CoFileTime to get the current time
629 renamedProperty.timeStampS1
630 renamedProperty.timeStampD1
631 renamedProperty.timeStampS2
632 renamedProperty.timeStampD2
633 renamedProperty.propertyUniqueID
637 * Obtain a free property in the property chain
639 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
642 * Save the new property into the new property spot
644 StorageImpl_WriteProperty(
645 This->ancestorStorage,
646 renamedPropertyIndex,
647 &renamedProperty);
650 * Find a spot in the property chain for our newly created property.
652 updatePropertyChain(
653 (StorageImpl*)This,
654 renamedPropertyIndex,
655 renamedProperty);
658 * At this point the renamed property has been inserted in the tree,
659 * now, before to Destroy the old property we must zeroed it's dirProperty
660 * otherwise the DestroyProperty below will zap it all and we do not want
661 * this to happen.
662 * Also, we fake that the old property is a storage so the DestroyProperty
663 * will not do a SetSize(0) on the stream data.
665 * This means that we need to tweek the StgProperty if it is a stream or a
666 * non empty storage.
668 currentProperty.dirProperty = PROPERTY_NULL;
669 currentProperty.propertyType = PROPTYPE_STORAGE;
670 StorageImpl_WriteProperty(
671 This->ancestorStorage,
672 foundPropertyIndex,
673 &currentProperty);
676 * Invoke Destroy to get rid of the ole property and automatically redo
677 * the linking of it's previous and next members...
679 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
682 else
685 * There is no property with the old name
687 return STG_E_FILENOTFOUND;
690 return S_OK;
693 /************************************************************************
694 * Storage32BaseImpl_CreateStream (IStorage)
696 * This method will create a stream object within this storage
698 * See Windows documentation for more details on IStorage methods.
700 HRESULT WINAPI StorageBaseImpl_CreateStream(
701 IStorage* iface,
702 const OLECHAR* pwcsName, /* [string][in] */
703 DWORD grfMode, /* [in] */
704 DWORD reserved1, /* [in] */
705 DWORD reserved2, /* [in] */
706 IStream** ppstm) /* [out] */
708 ICOM_THIS(StorageBaseImpl,iface);
709 IEnumSTATSTGImpl* propertyEnumeration;
710 StgStreamImpl* newStream;
711 StgProperty currentProperty, newStreamProperty;
712 ULONG foundPropertyIndex, newPropertyIndex;
715 * Validate parameters
717 if (ppstm == 0)
718 return STG_E_INVALIDPOINTER;
720 if (pwcsName == 0)
721 return STG_E_INVALIDNAME;
724 * Validate the STGM flags
726 if ( FAILED( validateSTGM(grfMode) ))
727 return STG_E_INVALIDFLAG;
730 * As documented.
732 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
733 (grfMode & STGM_DELETEONRELEASE) ||
734 (grfMode & STGM_TRANSACTED) )
735 return STG_E_INVALIDFUNCTION;
738 * Initialize the out parameter
740 *ppstm = 0;
743 * Create a property enumeration to search the properties
745 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
746 This->rootPropertySetIndex);
748 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
749 pwcsName,
750 &currentProperty);
752 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
754 if (foundPropertyIndex != PROPERTY_NULL)
757 * An element with this name already exists
759 if (grfMode & STGM_CREATE)
760 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
761 else
762 return STG_E_FILEALREADYEXISTS;
766 * memset the empty property
768 memset(&newStreamProperty, 0, sizeof(StgProperty));
770 newStreamProperty.sizeOfNameString =
771 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
773 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
774 return STG_E_INVALIDNAME;
776 lstrcpyW(newStreamProperty.name, pwcsName);
778 newStreamProperty.propertyType = PROPTYPE_STREAM;
779 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
780 newStreamProperty.size.LowPart = 0;
781 newStreamProperty.size.HighPart = 0;
783 newStreamProperty.previousProperty = PROPERTY_NULL;
784 newStreamProperty.nextProperty = PROPERTY_NULL;
785 newStreamProperty.dirProperty = PROPERTY_NULL;
787 /* call CoFileTime to get the current time
788 newStreamProperty.timeStampS1
789 newStreamProperty.timeStampD1
790 newStreamProperty.timeStampS2
791 newStreamProperty.timeStampD2
794 /* newStreamProperty.propertyUniqueID */
797 * Get a free property or create a new one
799 newPropertyIndex = getFreeProperty(This->ancestorStorage);
802 * Save the new property into the new property spot
804 StorageImpl_WriteProperty(
805 This->ancestorStorage,
806 newPropertyIndex,
807 &newStreamProperty);
810 * Find a spot in the property chain for our newly created property.
812 updatePropertyChain(
813 (StorageImpl*)This,
814 newPropertyIndex,
815 newStreamProperty);
818 * Open the stream to return it.
820 newStream = StgStreamImpl_Construct(This, newPropertyIndex);
822 if (newStream != 0)
824 *ppstm = (IStream*)newStream;
827 * Since we are returning a pointer to the interface, we have to nail down
828 * the reference.
830 StgStreamImpl_AddRef(*ppstm);
832 else
834 return STG_E_INSUFFICIENTMEMORY;
837 return S_OK;
840 /************************************************************************
841 * Storage32BaseImpl_SetClass (IStorage)
843 * This method will write the specified CLSID in the property of this
844 * storage.
846 * See Windows documentation for more details on IStorage methods.
848 HRESULT WINAPI StorageBaseImpl_SetClass(
849 IStorage* iface,
850 REFCLSID clsid) /* [in] */
852 ICOM_THIS(StorageBaseImpl,iface);
853 HRESULT hRes = E_FAIL;
854 StgProperty curProperty;
855 BOOL success;
857 success = StorageImpl_ReadProperty(This->ancestorStorage,
858 This->rootPropertySetIndex,
859 &curProperty);
860 if (success)
862 curProperty.propertyUniqueID = *clsid;
864 success = StorageImpl_WriteProperty(This->ancestorStorage,
865 This->rootPropertySetIndex,
866 &curProperty);
867 if (success)
868 hRes = S_OK;
871 return hRes;
874 /************************************************************************
875 ** Storage32Impl implementation
878 /************************************************************************
879 * Storage32Impl_CreateStorage (IStorage)
881 * This method will create the storage object within the provided storage.
883 * See Windows documentation for more details on IStorage methods.
885 HRESULT WINAPI StorageImpl_CreateStorage(
886 IStorage* iface,
887 const OLECHAR *pwcsName, /* [string][in] */
888 DWORD grfMode, /* [in] */
889 DWORD reserved1, /* [in] */
890 DWORD reserved2, /* [in] */
891 IStorage **ppstg) /* [out] */
893 StorageImpl* const This=(StorageImpl*)iface;
895 IEnumSTATSTGImpl *propertyEnumeration;
896 StgProperty currentProperty;
897 StgProperty newProperty;
898 ULONG foundPropertyIndex;
899 ULONG newPropertyIndex;
900 HRESULT hr;
903 * Validate parameters
905 if (ppstg == 0)
906 return STG_E_INVALIDPOINTER;
908 if (pwcsName == 0)
909 return STG_E_INVALIDNAME;
912 * Validate the STGM flags
914 if ( FAILED( validateSTGM(grfMode) ) ||
915 (grfMode & STGM_DELETEONRELEASE) )
916 return STG_E_INVALIDFLAG;
919 * Initialize the out parameter
921 *ppstg = 0;
924 * Create a property enumeration and search the properties
926 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
927 This->rootPropertySetIndex);
929 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
930 pwcsName,
931 &currentProperty);
932 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
934 if (foundPropertyIndex != PROPERTY_NULL)
937 * An element with this name already exists
939 if (grfMode & STGM_CREATE)
940 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
941 else
942 return STG_E_FILEALREADYEXISTS;
946 * memset the empty property
948 memset(&newProperty, 0, sizeof(StgProperty));
950 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
952 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
953 return STG_E_INVALIDNAME;
955 lstrcpyW(newProperty.name, pwcsName);
957 newProperty.propertyType = PROPTYPE_STORAGE;
958 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
959 newProperty.size.LowPart = 0;
960 newProperty.size.HighPart = 0;
962 newProperty.previousProperty = PROPERTY_NULL;
963 newProperty.nextProperty = PROPERTY_NULL;
964 newProperty.dirProperty = PROPERTY_NULL;
966 /* call CoFileTime to get the current time
967 newProperty.timeStampS1
968 newProperty.timeStampD1
969 newProperty.timeStampS2
970 newProperty.timeStampD2
973 /* newStorageProperty.propertyUniqueID */
976 * Obtain a free property in the property chain
978 newPropertyIndex = getFreeProperty(This->ancestorStorage);
981 * Save the new property into the new property spot
983 StorageImpl_WriteProperty(
984 This->ancestorStorage,
985 newPropertyIndex,
986 &newProperty);
989 * Find a spot in the property chain for our newly created property.
991 updatePropertyChain(
992 This,
993 newPropertyIndex,
994 newProperty);
997 * Open it to get a pointer to return.
999 hr = StorageBaseImpl_OpenStorage(
1000 iface,
1001 (OLECHAR*)pwcsName,
1003 grfMode,
1006 ppstg);
1008 if( (hr != S_OK) || (*ppstg == NULL))
1010 return hr;
1013 return S_OK;
1017 /***************************************************************************
1019 * Internal Method
1021 * Get a free property or create a new one.
1023 static ULONG getFreeProperty(
1024 StorageImpl *storage)
1026 ULONG currentPropertyIndex = 0;
1027 ULONG newPropertyIndex = PROPERTY_NULL;
1028 BOOL readSucessful = TRUE;
1029 StgProperty currentProperty;
1034 * Start by reading the root property
1036 readSucessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1037 currentPropertyIndex,
1038 &currentProperty);
1039 if (readSucessful)
1041 if (currentProperty.sizeOfNameString == 0)
1044 * The property existis and is available, we found it.
1046 newPropertyIndex = currentPropertyIndex;
1049 else
1052 * We exhausted the property list, we will create more space below
1054 newPropertyIndex = currentPropertyIndex;
1056 currentPropertyIndex++;
1058 } while (newPropertyIndex == PROPERTY_NULL);
1061 * grow the property chain
1063 if (! readSucessful)
1065 StgProperty emptyProperty;
1066 ULARGE_INTEGER newSize;
1067 ULONG propertyIndex;
1068 ULONG lastProperty = 0;
1069 ULONG blockCount = 0;
1072 * obtain the new count of property blocks
1074 blockCount = BlockChainStream_GetCount(
1075 storage->ancestorStorage->rootBlockChain)+1;
1078 * initialize the size used by the property stream
1080 newSize.HighPart = 0;
1081 newSize.LowPart = storage->bigBlockSize * blockCount;
1084 * add a property block to the property chain
1086 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1089 * memset the empty property in order to initialize the unused newly
1090 * created property
1092 memset(&emptyProperty, 0, sizeof(StgProperty));
1095 * initialize them
1097 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1099 for(
1100 propertyIndex = newPropertyIndex;
1101 propertyIndex < lastProperty;
1102 propertyIndex++)
1104 StorageImpl_WriteProperty(
1105 storage->ancestorStorage,
1106 propertyIndex,
1107 &emptyProperty);
1111 return newPropertyIndex;
1114 /****************************************************************************
1116 * Internal Method
1118 * Case insensitive comparaison of StgProperty.name by first considering
1119 * their size.
1121 * Returns <0 when newPrpoerty < currentProperty
1122 * >0 when newPrpoerty > currentProperty
1123 * 0 when newPrpoerty == currentProperty
1125 static LONG propertyNameCmp(
1126 OLECHAR *newProperty,
1127 OLECHAR *currentProperty)
1129 LONG sizeOfNew = (lstrlenW(newProperty) +1) * sizeof(WCHAR);
1130 LONG sizeOfCur = (lstrlenW(currentProperty)+1) * sizeof(WCHAR);
1131 LONG diff = sizeOfNew - sizeOfCur;
1133 if (diff == 0)
1136 * We compare the string themselves only when they are of the same lenght
1138 WCHAR wsnew[PROPERTY_NAME_MAX_LEN];
1139 WCHAR wscur[PROPERTY_NAME_MAX_LEN];
1141 diff = lstrcmpW( (LPCWSTR)CRTDLL__wcsupr(
1142 lstrcpynW(wsnew, newProperty, sizeOfNew)),
1143 (LPCWSTR)CRTDLL__wcsupr(
1144 lstrcpynW(wscur, currentProperty, sizeOfCur)));
1147 return diff;
1150 /****************************************************************************
1152 * Internal Method
1154 * Properly link this new element in the property chain.
1156 static void updatePropertyChain(
1157 StorageImpl *storage,
1158 ULONG newPropertyIndex,
1159 StgProperty newProperty)
1161 StgProperty currentProperty;
1164 * Read the root property
1166 StorageImpl_ReadProperty(storage->ancestorStorage,
1167 storage->rootPropertySetIndex,
1168 &currentProperty);
1170 if (currentProperty.dirProperty != PROPERTY_NULL)
1173 * The root storage contains some element, therefore, start the research
1174 * for the appropriate location.
1176 BOOL found = 0;
1177 ULONG current, next, previous, currentPropertyId;
1180 * Keep the StgProperty sequence number of the storage first property
1182 currentPropertyId = currentProperty.dirProperty;
1185 * Read
1187 StorageImpl_ReadProperty(storage->ancestorStorage,
1188 currentProperty.dirProperty,
1189 &currentProperty);
1191 previous = currentProperty.previousProperty;
1192 next = currentProperty.nextProperty;
1193 current = currentPropertyId;
1195 while (found == 0)
1197 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1199 if (diff < 0)
1201 if (previous != PROPERTY_NULL)
1203 StorageImpl_ReadProperty(storage->ancestorStorage,
1204 previous,
1205 &currentProperty);
1206 current = previous;
1208 else
1210 currentProperty.previousProperty = newPropertyIndex;
1211 StorageImpl_WriteProperty(storage->ancestorStorage,
1212 current,
1213 &currentProperty);
1214 found = 1;
1217 else
1219 if (next != PROPERTY_NULL)
1221 StorageImpl_ReadProperty(storage->ancestorStorage,
1222 next,
1223 &currentProperty);
1224 current = next;
1226 else
1228 currentProperty.nextProperty = newPropertyIndex;
1229 StorageImpl_WriteProperty(storage->ancestorStorage,
1230 current,
1231 &currentProperty);
1232 found = 1;
1236 previous = currentProperty.previousProperty;
1237 next = currentProperty.nextProperty;
1240 else
1243 * The root storage is empty, link the new property to it's dir property
1245 currentProperty.dirProperty = newPropertyIndex;
1246 StorageImpl_WriteProperty(storage->ancestorStorage,
1247 storage->rootPropertySetIndex,
1248 &currentProperty);
1253 /*************************************************************************
1254 * CopyTo (IStorage)
1256 HRESULT WINAPI StorageImpl_CopyTo(
1257 IStorage* iface,
1258 DWORD ciidExclude, /* [in] */
1259 const IID *rgiidExclude,/* [size_is][unique][in] */
1260 SNB snbExclude, /* [unique][in] */
1261 IStorage *pstgDest) /* [unique][in] */
1263 return E_NOTIMPL;
1266 /*************************************************************************
1267 * MoveElementTo (IStorage)
1269 HRESULT WINAPI StorageImpl_MoveElementTo(
1270 IStorage* iface,
1271 const OLECHAR *pwcsName, /* [string][in] */
1272 IStorage *pstgDest, /* [unique][in] */
1273 const OLECHAR *pwcsNewName,/* [string][in] */
1274 DWORD grfFlags) /* [in] */
1276 return E_NOTIMPL;
1279 /*************************************************************************
1280 * Commit (IStorage)
1282 HRESULT WINAPI StorageImpl_Commit(
1283 IStorage* iface,
1284 DWORD grfCommitFlags)/* [in] */
1286 FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1287 return S_OK;
1290 /*************************************************************************
1291 * Revert (IStorage)
1293 HRESULT WINAPI StorageImpl_Revert(
1294 IStorage* iface)
1296 return E_NOTIMPL;
1299 /*************************************************************************
1300 * DestroyElement (IStorage)
1302 * Stategy: This implementation is build this way for simplicity not for speed.
1303 * I always delete the top most element of the enumeration and adjust
1304 * the deleted element pointer all the time. This takes longer to
1305 * do but allow to reinvoke DestroyElement whenever we encounter a
1306 * storage object. The optimisation reside in the usage of another
1307 * enumeration stategy that would give all the leaves of a storage
1308 * first. (postfix order)
1310 HRESULT WINAPI StorageImpl_DestroyElement(
1311 IStorage* iface,
1312 const OLECHAR *pwcsName)/* [string][in] */
1314 StorageImpl* const This=(StorageImpl*)iface;
1316 IEnumSTATSTGImpl* propertyEnumeration;
1317 HRESULT hr = S_OK;
1318 BOOL res;
1319 StgProperty propertyToDelete;
1320 StgProperty parentProperty;
1321 ULONG foundPropertyIndexToDelete;
1322 ULONG typeOfRelation;
1323 ULONG parentPropertyId;
1326 * Perform a sanity check on the parameters.
1328 if (pwcsName==NULL)
1329 return STG_E_INVALIDPOINTER;
1332 * Create a property enumeration to search the property with the given name
1334 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1335 This->ancestorStorage,
1336 This->rootPropertySetIndex);
1338 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1339 propertyEnumeration,
1340 pwcsName,
1341 &propertyToDelete);
1343 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1345 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1347 return STG_E_FILENOTFOUND;
1351 * Find the parent property of the property to delete (the one that
1352 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1353 * the parent is This. Otherwise, the parent is one of it's sibling...
1357 * First, read This's StgProperty..
1359 res = StorageImpl_ReadProperty(
1360 This->ancestorStorage,
1361 This->rootPropertySetIndex,
1362 &parentProperty);
1364 assert(res==TRUE);
1367 * Second, check to see if by any chance the actual storage (This) is not
1368 * the parent of the property to delete... We never know...
1370 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1373 * Set data as it would have been done in the else part...
1375 typeOfRelation = PROPERTY_RELATION_DIR;
1376 parentPropertyId = This->rootPropertySetIndex;
1378 else
1381 * Create a property enumeration to search the parent properties, and
1382 * delete it once done.
1384 IEnumSTATSTGImpl* propertyEnumeration2;
1386 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1387 This->ancestorStorage,
1388 This->rootPropertySetIndex);
1390 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1391 propertyEnumeration2,
1392 foundPropertyIndexToDelete,
1393 &parentProperty,
1394 &parentPropertyId);
1396 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1399 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1401 hr = deleteStorageProperty(
1402 This,
1403 propertyToDelete.name);
1405 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1407 hr = deleteStreamProperty(
1408 This,
1409 foundPropertyIndexToDelete,
1410 propertyToDelete);
1413 if (hr!=S_OK)
1414 return hr;
1417 * Adjust the property chain
1419 hr = adjustPropertyChain(
1420 This,
1421 propertyToDelete,
1422 parentProperty,
1423 parentPropertyId,
1424 typeOfRelation);
1426 return hr;
1430 /*********************************************************************
1432 * Internal Method
1434 * Perform the deletion of a complete storage node
1437 static HRESULT deleteStorageProperty(
1438 StorageImpl *parentStorage,
1439 OLECHAR *propertyToDeleteName)
1441 IEnumSTATSTG *elements = 0;
1442 IStorage *childStorage = 0;
1443 STATSTG currentElement;
1444 HRESULT hr;
1445 HRESULT destroyHr = S_OK;
1448 * Open the storage and enumerate it
1450 hr = StorageBaseImpl_OpenStorage(
1451 (IStorage*)parentStorage,
1452 propertyToDeleteName,
1454 STGM_SHARE_EXCLUSIVE,
1457 &childStorage);
1459 if (hr != S_OK)
1461 return hr;
1465 * Enumerate the elements
1467 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1472 * Obtain the next element
1474 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1475 if (hr==S_OK)
1477 destroyHr = StorageImpl_DestroyElement(
1478 (IStorage*)childStorage,
1479 (OLECHAR*)currentElement.pwcsName);
1481 CoTaskMemFree(currentElement.pwcsName);
1485 * We need to Reset the enumeration every time because we delete elements
1486 * and the enumeration could be invalid
1488 IEnumSTATSTG_Reset(elements);
1490 } while ((hr == S_OK) && (destroyHr == S_OK));
1492 IStorage_Release(childStorage);
1493 IEnumSTATSTG_Release(elements);
1495 return destroyHr;
1498 /*********************************************************************
1500 * Internal Method
1502 * Perform the deletion of a stream node
1505 static HRESULT deleteStreamProperty(
1506 StorageImpl *parentStorage,
1507 ULONG indexOfPropertyToDelete,
1508 StgProperty propertyToDelete)
1510 IStream *pis;
1511 HRESULT hr;
1512 ULARGE_INTEGER size;
1514 size.HighPart = 0;
1515 size.LowPart = 0;
1517 hr = StorageBaseImpl_OpenStream(
1518 (IStorage*)parentStorage,
1519 (OLECHAR*)propertyToDelete.name,
1520 NULL,
1521 STGM_SHARE_EXCLUSIVE,
1523 &pis);
1525 if (hr!=S_OK)
1527 return(hr);
1531 * Zap the stream
1533 hr = IStream_SetSize(pis, size);
1535 if(hr != S_OK)
1537 return hr;
1541 * Invalidate the property by zeroing it's name member.
1543 propertyToDelete.sizeOfNameString = 0;
1546 * Here we should re-read the property so we get the updated pointer
1547 * but since we are here to zap it, I don't do it...
1550 StorageImpl_WriteProperty(
1551 parentStorage->ancestorStorage,
1552 indexOfPropertyToDelete,
1553 &propertyToDelete);
1555 return S_OK;
1558 /*********************************************************************
1560 * Internal Method
1562 * Finds a placeholder for the StgProperty within the Storage
1565 static HRESULT findPlaceholder(
1566 StorageImpl *storage,
1567 ULONG propertyIndexToStore,
1568 ULONG storePropertyIndex,
1569 INT typeOfRelation)
1571 StgProperty storeProperty;
1572 HRESULT hr = S_OK;
1573 BOOL res = TRUE;
1576 * Read the storage property
1578 res = StorageImpl_ReadProperty(
1579 storage->ancestorStorage,
1580 storePropertyIndex,
1581 &storeProperty);
1583 if(! res)
1585 return E_FAIL;
1588 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1590 if (storeProperty.previousProperty != PROPERTY_NULL)
1592 return findPlaceholder(
1593 storage,
1594 propertyIndexToStore,
1595 storeProperty.previousProperty,
1596 typeOfRelation);
1598 else
1600 storeProperty.previousProperty = propertyIndexToStore;
1603 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1605 if (storeProperty.nextProperty != PROPERTY_NULL)
1607 return findPlaceholder(
1608 storage,
1609 propertyIndexToStore,
1610 storeProperty.nextProperty,
1611 typeOfRelation);
1613 else
1615 storeProperty.nextProperty = propertyIndexToStore;
1618 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1620 if (storeProperty.dirProperty != PROPERTY_NULL)
1622 return findPlaceholder(
1623 storage,
1624 propertyIndexToStore,
1625 storeProperty.dirProperty,
1626 typeOfRelation);
1628 else
1630 storeProperty.dirProperty = propertyIndexToStore;
1634 hr = StorageImpl_WriteProperty(
1635 storage->ancestorStorage,
1636 storePropertyIndex,
1637 &storeProperty);
1639 if(! hr)
1641 return E_FAIL;
1644 return S_OK;
1647 /*************************************************************************
1649 * Internal Method
1651 * This method takes the previous and the next property link of a property
1652 * to be deleted and find them a place in the Storage.
1654 static HRESULT adjustPropertyChain(
1655 StorageImpl *This,
1656 StgProperty propertyToDelete,
1657 StgProperty parentProperty,
1658 ULONG parentPropertyId,
1659 INT typeOfRelation)
1661 ULONG newLinkProperty = PROPERTY_NULL;
1662 BOOL needToFindAPlaceholder = FALSE;
1663 ULONG storeNode = PROPERTY_NULL;
1664 ULONG toStoreNode = PROPERTY_NULL;
1665 INT relationType = 0;
1666 HRESULT hr = S_OK;
1667 BOOL res = TRUE;
1669 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1671 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1674 * Set the parent previous to the property to delete previous
1676 newLinkProperty = propertyToDelete.previousProperty;
1678 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1681 * We also need to find a storage for the other link, setup variables
1682 * to do this at the end...
1684 needToFindAPlaceholder = TRUE;
1685 storeNode = propertyToDelete.previousProperty;
1686 toStoreNode = propertyToDelete.nextProperty;
1687 relationType = PROPERTY_RELATION_NEXT;
1690 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1693 * Set the parent previous to the property to delete next
1695 newLinkProperty = propertyToDelete.nextProperty;
1699 * Link it for real...
1701 parentProperty.previousProperty = newLinkProperty;
1704 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1706 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1709 * Set the parent next to the property to delete next previous
1711 newLinkProperty = propertyToDelete.previousProperty;
1713 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1716 * We also need to find a storage for the other link, setup variables
1717 * to do this at the end...
1719 needToFindAPlaceholder = TRUE;
1720 storeNode = propertyToDelete.previousProperty;
1721 toStoreNode = propertyToDelete.nextProperty;
1722 relationType = PROPERTY_RELATION_NEXT;
1725 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1728 * Set the parent next to the property to delete next
1730 newLinkProperty = propertyToDelete.nextProperty;
1734 * Link it for real...
1736 parentProperty.nextProperty = newLinkProperty;
1738 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1740 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1743 * Set the parent dir to the property to delete previous
1745 newLinkProperty = propertyToDelete.previousProperty;
1747 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1750 * We also need to find a storage for the other link, setup variables
1751 * to do this at the end...
1753 needToFindAPlaceholder = TRUE;
1754 storeNode = propertyToDelete.previousProperty;
1755 toStoreNode = propertyToDelete.nextProperty;
1756 relationType = PROPERTY_RELATION_NEXT;
1759 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1762 * Set the parent dir to the property to delete next
1764 newLinkProperty = propertyToDelete.nextProperty;
1768 * Link it for real...
1770 parentProperty.dirProperty = newLinkProperty;
1774 * Write back the parent property
1776 res = StorageImpl_WriteProperty(
1777 This->ancestorStorage,
1778 parentPropertyId,
1779 &parentProperty);
1780 if(! res)
1782 return E_FAIL;
1786 * If a placeholder is required for the other link, then, find one and
1787 * get out of here...
1789 if (needToFindAPlaceholder)
1791 hr = findPlaceholder(
1792 This,
1793 toStoreNode,
1794 storeNode,
1795 relationType);
1798 return hr;
1802 /******************************************************************************
1803 * SetElementTimes (IStorage)
1805 HRESULT WINAPI StorageImpl_SetElementTimes(
1806 IStorage* iface,
1807 const OLECHAR *pwcsName,/* [string][in] */
1808 const FILETIME *pctime, /* [in] */
1809 const FILETIME *patime, /* [in] */
1810 const FILETIME *pmtime) /* [in] */
1812 return E_NOTIMPL;
1815 /******************************************************************************
1816 * SetStateBits (IStorage)
1818 HRESULT WINAPI StorageImpl_SetStateBits(
1819 IStorage* iface,
1820 DWORD grfStateBits,/* [in] */
1821 DWORD grfMask) /* [in] */
1823 return E_NOTIMPL;
1826 HRESULT StorageImpl_Construct(
1827 StorageImpl* This,
1828 HANDLE hFile,
1829 DWORD openFlags)
1831 HRESULT hr = S_OK;
1832 StgProperty currentProperty;
1833 BOOL readSucessful;
1834 ULONG currentPropertyIndex;
1836 if ( FAILED( validateSTGM(openFlags) ))
1837 return STG_E_INVALIDFLAG;
1839 memset(This, 0, sizeof(StorageImpl));
1842 * Initialize the virtual fgunction table.
1844 This->lpvtbl = &Storage32Impl_Vtbl;
1845 This->v_destructor = &StorageImpl_Destroy;
1848 * This is the top-level storage so initialize the ancester pointer
1849 * to this.
1851 This->ancestorStorage = This;
1854 * Initialize the physical support of the storage.
1856 This->hFile = hFile;
1859 * Initialize the big block cache.
1861 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
1862 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
1863 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
1864 openFlags,
1865 This->bigBlockSize);
1867 if (This->bigBlockFile == 0)
1868 return E_FAIL;
1870 if (openFlags & STGM_CREATE)
1872 ULARGE_INTEGER size;
1873 BYTE* bigBlockBuffer;
1876 * Initialize all header variables:
1877 * - The big block depot consists of one block and it is at block 0
1878 * - The properties start at block 1
1879 * - There is no small block depot
1881 memset( This->bigBlockDepotStart,
1882 BLOCK_UNUSED,
1883 sizeof(This->bigBlockDepotStart));
1885 This->bigBlockDepotCount = 1;
1886 This->bigBlockDepotStart[0] = 0;
1887 This->rootStartBlock = 1;
1888 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
1889 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
1890 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
1891 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
1892 This->extBigBlockDepotCount = 0;
1894 StorageImpl_SaveFileHeader(This);
1897 * Add one block for the big block depot and one block for the properties
1899 size.HighPart = 0;
1900 size.LowPart = This->bigBlockSize * 3;
1901 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
1904 * Initialize the big block depot
1906 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
1907 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
1908 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
1909 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
1910 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
1912 else
1915 * Load the header for the file.
1917 StorageImpl_LoadFileHeader(This);
1921 * There is no block depot cached yet.
1923 This->indexBlockDepotCached = 0xFFFFFFFF;
1926 * Start searching for free blocks with block 0.
1928 This->prevFreeBlock = 0;
1931 * Create the block chain abstractions.
1933 This->rootBlockChain =
1934 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1936 This->smallBlockDepotChain = BlockChainStream_Construct(
1937 This,
1938 &This->smallBlockDepotStart,
1939 PROPERTY_NULL);
1942 * Write the root property
1944 if (openFlags & STGM_CREATE)
1946 StgProperty rootProp;
1948 * Initialize the property chain
1950 memset(&rootProp, 0, sizeof(rootProp));
1951 lstrcpyAtoW(rootProp.name, rootPropertyName);
1953 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
1954 rootProp.propertyType = PROPTYPE_ROOT;
1955 rootProp.previousProperty = PROPERTY_NULL;
1956 rootProp.nextProperty = PROPERTY_NULL;
1957 rootProp.dirProperty = PROPERTY_NULL;
1958 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
1959 rootProp.size.HighPart = 0;
1960 rootProp.size.LowPart = 0;
1962 StorageImpl_WriteProperty(This, 0, &rootProp);
1966 * Find the ID of the root int he property sets.
1968 currentPropertyIndex = 0;
1972 readSucessful = StorageImpl_ReadProperty(
1973 This,
1974 currentPropertyIndex,
1975 &currentProperty);
1977 if (readSucessful)
1979 if ( (currentProperty.sizeOfNameString != 0 ) &&
1980 (currentProperty.propertyType == PROPTYPE_ROOT) )
1982 This->rootPropertySetIndex = currentPropertyIndex;
1986 currentPropertyIndex++;
1988 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1990 if (!readSucessful)
1992 /* TODO CLEANUP */
1993 return E_FAIL;
1997 * Create the block chain abstraction for the small block root chain.
1999 This->smallBlockRootChain = BlockChainStream_Construct(
2000 This,
2001 NULL,
2002 This->rootPropertySetIndex);
2004 return hr;
2007 void StorageImpl_Destroy(
2008 StorageImpl* This)
2010 BlockChainStream_Destroy(This->smallBlockRootChain);
2011 BlockChainStream_Destroy(This->rootBlockChain);
2012 BlockChainStream_Destroy(This->smallBlockDepotChain);
2014 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2015 return;
2018 /******************************************************************************
2019 * Storage32Impl_GetNextFreeBigBlock
2021 * Returns the index of the next free big block.
2022 * If the big block depot is filled, this method will enlarge it.
2025 ULONG StorageImpl_GetNextFreeBigBlock(
2026 StorageImpl* This)
2028 ULONG depotBlockIndexPos;
2029 void *depotBuffer;
2030 ULONG depotBlockOffset;
2031 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2032 ULONG nextBlockIndex = BLOCK_SPECIAL;
2033 int depotIndex = 0;
2034 ULONG freeBlock = BLOCK_UNUSED;
2036 depotIndex = This->prevFreeBlock / blocksPerDepot;
2037 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2040 * Scan the entire big block depot until we find a block marked free
2042 while (nextBlockIndex != BLOCK_UNUSED)
2044 if (depotIndex < COUNT_BBDEPOTINHEADER)
2046 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2049 * Grow the primary depot.
2051 if (depotBlockIndexPos == BLOCK_UNUSED)
2053 depotBlockIndexPos = depotIndex*blocksPerDepot;
2056 * Add a block depot.
2058 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2059 This->bigBlockDepotCount++;
2060 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2063 * Flag it as a block depot.
2065 StorageImpl_SetNextBlockInChain(This,
2066 depotBlockIndexPos,
2067 BLOCK_SPECIAL);
2069 /* Save new header information.
2071 StorageImpl_SaveFileHeader(This);
2074 else
2076 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2078 if (depotBlockIndexPos == BLOCK_UNUSED)
2081 * Grow the extended depot.
2083 ULONG extIndex = BLOCK_UNUSED;
2084 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2085 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2087 if (extBlockOffset == 0)
2089 /* We need an extended block.
2091 extIndex = Storage32Impl_AddExtBlockDepot(This);
2092 This->extBigBlockDepotCount++;
2093 depotBlockIndexPos = extIndex + 1;
2095 else
2096 depotBlockIndexPos = depotIndex * blocksPerDepot;
2099 * Add a block depot and mark it in the extended block.
2101 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2102 This->bigBlockDepotCount++;
2103 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2105 /* Flag the block depot.
2107 StorageImpl_SetNextBlockInChain(This,
2108 depotBlockIndexPos,
2109 BLOCK_SPECIAL);
2111 /* If necessary, flag the extended depot block.
2113 if (extIndex != BLOCK_UNUSED)
2114 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2116 /* Save header information.
2118 StorageImpl_SaveFileHeader(This);
2122 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2124 if (depotBuffer != 0)
2126 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2127 ( nextBlockIndex != BLOCK_UNUSED))
2129 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2131 if (nextBlockIndex == BLOCK_UNUSED)
2133 freeBlock = (depotIndex * blocksPerDepot) +
2134 (depotBlockOffset/sizeof(ULONG));
2137 depotBlockOffset += sizeof(ULONG);
2140 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2143 depotIndex++;
2144 depotBlockOffset = 0;
2147 This->prevFreeBlock = freeBlock;
2149 return freeBlock;
2152 /******************************************************************************
2153 * Storage32Impl_AddBlockDepot
2155 * This will create a depot block, essentially it is a block initialized
2156 * to BLOCK_UNUSEDs.
2158 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2160 BYTE* blockBuffer;
2162 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2165 * Initialize blocks as free
2167 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2169 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2172 /******************************************************************************
2173 * Storage32Impl_GetExtDepotBlock
2175 * Returns the index of the block that corresponds to the specified depot
2176 * index. This method is only for depot indexes equal or greater than
2177 * COUNT_BBDEPOTINHEADER.
2179 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2181 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2182 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2183 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2184 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2185 ULONG blockIndex = BLOCK_UNUSED;
2186 ULONG extBlockIndex = This->extBigBlockDepotStart;
2188 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2190 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2191 return BLOCK_UNUSED;
2193 while (extBlockCount > 0)
2195 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2196 extBlockCount--;
2199 if (extBlockIndex != BLOCK_UNUSED)
2201 BYTE* depotBuffer;
2203 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2205 if (depotBuffer != 0)
2207 StorageUtl_ReadDWord(depotBuffer,
2208 extBlockOffset * sizeof(ULONG),
2209 &blockIndex);
2211 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2215 return blockIndex;
2218 /******************************************************************************
2219 * Storage32Impl_SetExtDepotBlock
2221 * Associates the specified block index to the specified depot index.
2222 * This method is only for depot indexes equal or greater than
2223 * COUNT_BBDEPOTINHEADER.
2225 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2226 ULONG depotIndex,
2227 ULONG blockIndex)
2229 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2230 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2231 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2232 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2233 ULONG extBlockIndex = This->extBigBlockDepotStart;
2235 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2237 while (extBlockCount > 0)
2239 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2240 extBlockCount--;
2243 if (extBlockIndex != BLOCK_UNUSED)
2245 BYTE* depotBuffer;
2247 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2249 if (depotBuffer != 0)
2251 StorageUtl_WriteDWord(depotBuffer,
2252 extBlockOffset * sizeof(ULONG),
2253 blockIndex);
2255 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2260 /******************************************************************************
2261 * Storage32Impl_AddExtBlockDepot
2263 * Creates an extended depot block.
2265 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2267 ULONG numExtBlocks = This->extBigBlockDepotCount;
2268 ULONG nextExtBlock = This->extBigBlockDepotStart;
2269 BYTE* depotBuffer = NULL;
2270 ULONG index = BLOCK_UNUSED;
2271 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2272 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2273 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2275 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2276 blocksPerDepotBlock;
2278 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2281 * The first extended block.
2283 This->extBigBlockDepotStart = index;
2285 else
2287 int i;
2289 * Follow the chain to the last one.
2291 for (i = 0; i < (numExtBlocks - 1); i++)
2293 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2297 * Add the new extended block to the chain.
2299 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2300 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2301 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2305 * Initialize this block.
2307 depotBuffer = StorageImpl_GetBigBlock(This, index);
2308 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2309 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2311 return index;
2314 /******************************************************************************
2315 * Storage32Impl_FreeBigBlock
2317 * This method will flag the specified block as free in the big block depot.
2319 void StorageImpl_FreeBigBlock(
2320 StorageImpl* This,
2321 ULONG blockIndex)
2323 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2325 if (blockIndex < This->prevFreeBlock)
2326 This->prevFreeBlock = blockIndex;
2329 /************************************************************************
2330 * Storage32Impl_GetNextBlockInChain
2332 * This method will retrieve the block index of the next big block in
2333 * in the chain.
2335 * Params: This - Pointer to the Storage object.
2336 * blockIndex - Index of the block to retrieve the chain
2337 * for.
2339 * Returns: This method returns the index of the next block in the chain.
2340 * It will return the constants:
2341 * BLOCK_SPECIAL - If the block given was not part of a
2342 * chain.
2343 * BLOCK_END_OF_CHAIN - If the block given was the last in
2344 * a chain.
2345 * BLOCK_UNUSED - If the block given was not past of a chain
2346 * and is available.
2347 * BLOCK_EXTBBDEPOT - This block is part of the extended
2348 * big block depot.
2350 * See Windows documentation for more details on IStorage methods.
2352 ULONG StorageImpl_GetNextBlockInChain(
2353 StorageImpl* This,
2354 ULONG blockIndex)
2356 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2357 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2358 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2359 ULONG nextBlockIndex = BLOCK_SPECIAL;
2360 void* depotBuffer;
2361 ULONG depotBlockIndexPos;
2363 assert(depotBlockCount < This->bigBlockDepotCount);
2366 * Cache the currently accessed depot block.
2368 if (depotBlockCount != This->indexBlockDepotCached)
2370 This->indexBlockDepotCached = depotBlockCount;
2372 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2374 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2376 else
2379 * We have to look in the extended depot.
2381 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2384 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2386 if (depotBuffer!=0)
2388 int index;
2390 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2392 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2393 This->blockDepotCached[index] = nextBlockIndex;
2396 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2400 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2402 return nextBlockIndex;
2405 /******************************************************************************
2406 * Storage32Impl_GetNextExtendedBlock
2408 * Given an extended block this method will return the next extended block.
2410 * NOTES:
2411 * The last ULONG of an extended block is the block index of the next
2412 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2413 * depot.
2415 * Return values:
2416 * - The index of the next extended block
2417 * - BLOCK_UNUSED: there is no next extended block.
2418 * - Any other return values denotes failure.
2420 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2422 ULONG nextBlockIndex = BLOCK_SPECIAL;
2423 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2424 void* depotBuffer;
2426 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2428 if (depotBuffer!=0)
2430 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2432 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2435 return nextBlockIndex;
2438 /******************************************************************************
2439 * Storage32Impl_SetNextBlockInChain
2441 * This method will write the index of the specified block's next block
2442 * in the big block depot.
2444 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2445 * do the following
2447 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2448 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2449 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2452 void StorageImpl_SetNextBlockInChain(
2453 StorageImpl* This,
2454 ULONG blockIndex,
2455 ULONG nextBlock)
2457 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2458 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2459 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2460 ULONG depotBlockIndexPos;
2461 void* depotBuffer;
2463 assert(depotBlockCount < This->bigBlockDepotCount);
2464 assert(blockIndex != nextBlock);
2466 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2468 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2470 else
2473 * We have to look in the extended depot.
2475 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2478 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2480 if (depotBuffer!=0)
2482 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2483 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2487 * Update the cached block depot, if necessary.
2489 if (depotBlockCount == This->indexBlockDepotCached)
2491 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2495 /******************************************************************************
2496 * Storage32Impl_LoadFileHeader
2498 * This method will read in the file header, i.e. big block index -1.
2500 HRESULT StorageImpl_LoadFileHeader(
2501 StorageImpl* This)
2503 HRESULT hr = STG_E_FILENOTFOUND;
2504 void* headerBigBlock = NULL;
2505 int index;
2508 * Get a pointer to the big block of data containing the header.
2510 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2513 * Extract the information from the header.
2515 if (headerBigBlock!=0)
2518 * Check for the "magic number" signature and return an error if it is not
2519 * found.
2521 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2523 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2524 return STG_E_OLDFORMAT;
2527 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2529 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2530 return STG_E_INVALIDHEADER;
2533 StorageUtl_ReadWord(
2534 headerBigBlock,
2535 OFFSET_BIGBLOCKSIZEBITS,
2536 &This->bigBlockSizeBits);
2538 StorageUtl_ReadWord(
2539 headerBigBlock,
2540 OFFSET_SMALLBLOCKSIZEBITS,
2541 &This->smallBlockSizeBits);
2543 StorageUtl_ReadDWord(
2544 headerBigBlock,
2545 OFFSET_BBDEPOTCOUNT,
2546 &This->bigBlockDepotCount);
2548 StorageUtl_ReadDWord(
2549 headerBigBlock,
2550 OFFSET_ROOTSTARTBLOCK,
2551 &This->rootStartBlock);
2553 StorageUtl_ReadDWord(
2554 headerBigBlock,
2555 OFFSET_SBDEPOTSTART,
2556 &This->smallBlockDepotStart);
2558 StorageUtl_ReadDWord(
2559 headerBigBlock,
2560 OFFSET_EXTBBDEPOTSTART,
2561 &This->extBigBlockDepotStart);
2563 StorageUtl_ReadDWord(
2564 headerBigBlock,
2565 OFFSET_EXTBBDEPOTCOUNT,
2566 &This->extBigBlockDepotCount);
2568 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2570 StorageUtl_ReadDWord(
2571 headerBigBlock,
2572 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2573 &(This->bigBlockDepotStart[index]));
2577 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2579 if ((1 << 2) == 4)
2581 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2582 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2584 else
2586 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2587 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2591 * Right now, the code is making some assumptions about the size of the
2592 * blocks, just make sure they are what we're expecting.
2594 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2595 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2598 * Release the block.
2600 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2603 return hr;
2606 /******************************************************************************
2607 * Storage32Impl_SaveFileHeader
2609 * This method will save to the file the header, i.e. big block -1.
2611 void StorageImpl_SaveFileHeader(
2612 StorageImpl* This)
2614 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2615 int index;
2616 BOOL success;
2619 * Get a pointer to the big block of data containing the header.
2621 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2624 * If the block read failed, the file is probably new.
2626 if (!success)
2629 * Initialize for all unknown fields.
2631 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2634 * Initialize the magic number.
2636 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2639 * And a bunch of things we don't know what they mean
2641 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2642 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2643 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2644 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2645 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2649 * Write the information to the header.
2651 if (headerBigBlock!=0)
2653 StorageUtl_WriteWord(
2654 headerBigBlock,
2655 OFFSET_BIGBLOCKSIZEBITS,
2656 This->bigBlockSizeBits);
2658 StorageUtl_WriteWord(
2659 headerBigBlock,
2660 OFFSET_SMALLBLOCKSIZEBITS,
2661 This->smallBlockSizeBits);
2663 StorageUtl_WriteDWord(
2664 headerBigBlock,
2665 OFFSET_BBDEPOTCOUNT,
2666 This->bigBlockDepotCount);
2668 StorageUtl_WriteDWord(
2669 headerBigBlock,
2670 OFFSET_ROOTSTARTBLOCK,
2671 This->rootStartBlock);
2673 StorageUtl_WriteDWord(
2674 headerBigBlock,
2675 OFFSET_SBDEPOTSTART,
2676 This->smallBlockDepotStart);
2678 StorageUtl_WriteDWord(
2679 headerBigBlock,
2680 OFFSET_EXTBBDEPOTSTART,
2681 This->extBigBlockDepotStart);
2683 StorageUtl_WriteDWord(
2684 headerBigBlock,
2685 OFFSET_EXTBBDEPOTCOUNT,
2686 This->extBigBlockDepotCount);
2688 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2690 StorageUtl_WriteDWord(
2691 headerBigBlock,
2692 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2693 (This->bigBlockDepotStart[index]));
2698 * Write the big block back to the file.
2700 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2703 /******************************************************************************
2704 * Storage32Impl_ReadProperty
2706 * This method will read the specified property from the property chain.
2708 BOOL StorageImpl_ReadProperty(
2709 StorageImpl* This,
2710 ULONG index,
2711 StgProperty* buffer)
2713 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2714 ULARGE_INTEGER offsetInPropSet;
2715 BOOL readSucessful;
2716 ULONG bytesRead;
2718 offsetInPropSet.HighPart = 0;
2719 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2721 readSucessful = BlockChainStream_ReadAt(
2722 This->rootBlockChain,
2723 offsetInPropSet,
2724 PROPSET_BLOCK_SIZE,
2725 currentProperty,
2726 &bytesRead);
2728 if (readSucessful)
2730 memset(buffer->name, 0, sizeof(buffer->name));
2731 memcpy(
2732 buffer->name,
2733 currentProperty+OFFSET_PS_NAME,
2734 PROPERTY_NAME_BUFFER_LEN );
2736 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2738 StorageUtl_ReadWord(
2739 currentProperty,
2740 OFFSET_PS_NAMELENGTH,
2741 &buffer->sizeOfNameString);
2743 StorageUtl_ReadDWord(
2744 currentProperty,
2745 OFFSET_PS_PREVIOUSPROP,
2746 &buffer->previousProperty);
2748 StorageUtl_ReadDWord(
2749 currentProperty,
2750 OFFSET_PS_NEXTPROP,
2751 &buffer->nextProperty);
2753 StorageUtl_ReadDWord(
2754 currentProperty,
2755 OFFSET_PS_DIRPROP,
2756 &buffer->dirProperty);
2758 StorageUtl_ReadGUID(
2759 currentProperty,
2760 OFFSET_PS_GUID,
2761 &buffer->propertyUniqueID);
2763 StorageUtl_ReadDWord(
2764 currentProperty,
2765 OFFSET_PS_TSS1,
2766 &buffer->timeStampS1);
2768 StorageUtl_ReadDWord(
2769 currentProperty,
2770 OFFSET_PS_TSD1,
2771 &buffer->timeStampD1);
2773 StorageUtl_ReadDWord(
2774 currentProperty,
2775 OFFSET_PS_TSS2,
2776 &buffer->timeStampS2);
2778 StorageUtl_ReadDWord(
2779 currentProperty,
2780 OFFSET_PS_TSD2,
2781 &buffer->timeStampD2);
2783 StorageUtl_ReadDWord(
2784 currentProperty,
2785 OFFSET_PS_STARTBLOCK,
2786 &buffer->startingBlock);
2788 StorageUtl_ReadDWord(
2789 currentProperty,
2790 OFFSET_PS_SIZE,
2791 &buffer->size.LowPart);
2793 buffer->size.HighPart = 0;
2796 return readSucessful;
2799 /*********************************************************************
2800 * Write the specified property into the property chain
2802 BOOL StorageImpl_WriteProperty(
2803 StorageImpl* This,
2804 ULONG index,
2805 StgProperty* buffer)
2807 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2808 ULARGE_INTEGER offsetInPropSet;
2809 BOOL writeSucessful;
2810 ULONG bytesWritten;
2812 offsetInPropSet.HighPart = 0;
2813 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2815 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2817 memcpy(
2818 currentProperty + OFFSET_PS_NAME,
2819 buffer->name,
2820 PROPERTY_NAME_BUFFER_LEN );
2822 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2825 * Reassign the size in case of mistake....
2827 buffer->sizeOfNameString = (lstrlenW(buffer->name)+1) * sizeof(WCHAR);
2829 StorageUtl_WriteWord(
2830 currentProperty,
2831 OFFSET_PS_NAMELENGTH,
2832 buffer->sizeOfNameString);
2834 StorageUtl_WriteDWord(
2835 currentProperty,
2836 OFFSET_PS_PREVIOUSPROP,
2837 buffer->previousProperty);
2839 StorageUtl_WriteDWord(
2840 currentProperty,
2841 OFFSET_PS_NEXTPROP,
2842 buffer->nextProperty);
2844 StorageUtl_WriteDWord(
2845 currentProperty,
2846 OFFSET_PS_DIRPROP,
2847 buffer->dirProperty);
2849 StorageUtl_WriteGUID(
2850 currentProperty,
2851 OFFSET_PS_GUID,
2852 &buffer->propertyUniqueID);
2854 StorageUtl_WriteDWord(
2855 currentProperty,
2856 OFFSET_PS_TSS1,
2857 buffer->timeStampS1);
2859 StorageUtl_WriteDWord(
2860 currentProperty,
2861 OFFSET_PS_TSD1,
2862 buffer->timeStampD1);
2864 StorageUtl_WriteDWord(
2865 currentProperty,
2866 OFFSET_PS_TSS2,
2867 buffer->timeStampS2);
2869 StorageUtl_WriteDWord(
2870 currentProperty,
2871 OFFSET_PS_TSD2,
2872 buffer->timeStampD2);
2874 StorageUtl_WriteDWord(
2875 currentProperty,
2876 OFFSET_PS_STARTBLOCK,
2877 buffer->startingBlock);
2879 StorageUtl_WriteDWord(
2880 currentProperty,
2881 OFFSET_PS_SIZE,
2882 buffer->size.LowPart);
2884 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2885 offsetInPropSet,
2886 PROPSET_BLOCK_SIZE,
2887 currentProperty,
2888 &bytesWritten);
2889 return writeSucessful;
2892 BOOL StorageImpl_ReadBigBlock(
2893 StorageImpl* This,
2894 ULONG blockIndex,
2895 void* buffer)
2897 void* bigBlockBuffer;
2899 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2901 if (bigBlockBuffer!=0)
2903 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2905 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2907 return TRUE;
2910 return FALSE;
2913 BOOL StorageImpl_WriteBigBlock(
2914 StorageImpl* This,
2915 ULONG blockIndex,
2916 void* buffer)
2918 void* bigBlockBuffer;
2920 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2922 if (bigBlockBuffer!=0)
2924 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2926 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2928 return TRUE;
2931 return FALSE;
2934 void* StorageImpl_GetROBigBlock(
2935 StorageImpl* This,
2936 ULONG blockIndex)
2938 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2941 void* StorageImpl_GetBigBlock(
2942 StorageImpl* This,
2943 ULONG blockIndex)
2945 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2948 void StorageImpl_ReleaseBigBlock(
2949 StorageImpl* This,
2950 void* pBigBlock)
2952 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2955 /******************************************************************************
2956 * Storage32Impl_SmallBlocksToBigBlocks
2958 * This method will convert a small block chain to a big block chain.
2959 * The small block chain will be destroyed.
2961 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2962 StorageImpl* This,
2963 SmallBlockChainStream** ppsbChain)
2965 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2966 ULARGE_INTEGER size, offset;
2967 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
2968 ULONG propertyIndex;
2969 BOOL successRead, successWrite;
2970 StgProperty chainProperty;
2971 BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2972 BlockChainStream *bbTempChain = NULL;
2973 BlockChainStream *bigBlockChain = NULL;
2976 * Create a temporary big block chain that doesn't have
2977 * an associated property. This temporary chain will be
2978 * used to copy data from small blocks to big blocks.
2980 bbTempChain = BlockChainStream_Construct(This,
2981 &bbHeadOfChain,
2982 PROPERTY_NULL);
2985 * Grow the big block chain.
2987 size = SmallBlockChainStream_GetSize(*ppsbChain);
2988 BlockChainStream_SetSize(bbTempChain, size);
2991 * Copy the contents of the small block chain to the big block chain
2992 * by small block size increments.
2994 offset.LowPart = 0;
2995 offset.HighPart = 0;
2996 cbTotalRead = 0;
2997 cbTotalWritten = 0;
3001 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3002 offset,
3003 sizeof(buffer),
3004 buffer,
3005 &cbRead);
3006 cbTotalRead += cbRead;
3008 successWrite = BlockChainStream_WriteAt(bbTempChain,
3009 offset,
3010 cbRead,
3011 buffer,
3012 &cbWritten);
3013 cbTotalWritten += cbWritten;
3015 offset.LowPart += This->smallBlockSize;
3017 } while (successRead && successWrite);
3019 assert(cbTotalRead == cbTotalWritten);
3022 * Destroy the small block chain.
3024 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3025 size.HighPart = 0;
3026 size.LowPart = 0;
3027 SmallBlockChainStream_SetSize(*ppsbChain, size);
3028 SmallBlockChainStream_Destroy(*ppsbChain);
3029 *ppsbChain = 0;
3032 * Change the property information. This chain is now a big block chain
3033 * and it doesn't reside in the small blocks chain anymore.
3035 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3037 chainProperty.startingBlock = bbHeadOfChain;
3039 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3042 * Destroy the temporary propertyless big block chain.
3043 * Create a new big block chain associated with this property.
3045 BlockChainStream_Destroy(bbTempChain);
3046 bigBlockChain = BlockChainStream_Construct(This,
3047 NULL,
3048 propertyIndex);
3050 return bigBlockChain;
3053 /******************************************************************************
3054 ** Storage32InternalImpl implementation
3057 StorageInternalImpl* StorageInternalImpl_Construct(
3058 StorageImpl* ancestorStorage,
3059 ULONG rootPropertyIndex)
3061 StorageInternalImpl* newStorage;
3064 * Allocate space for the new storage object
3066 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3068 if (newStorage!=0)
3070 memset(newStorage, 0, sizeof(StorageInternalImpl));
3073 * Initialize the virtual function table.
3075 newStorage->lpvtbl = &Storage32InternalImpl_Vtbl;
3076 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3079 * Keep the ancestor storage pointer and nail a reference to it.
3081 newStorage->ancestorStorage = ancestorStorage;
3082 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3085 * Keep the index of the root property set for this storage,
3087 newStorage->rootPropertySetIndex = rootPropertyIndex;
3089 return newStorage;
3092 return 0;
3095 void StorageInternalImpl_Destroy(
3096 StorageInternalImpl* This)
3098 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3099 HeapFree(GetProcessHeap(), 0, This);
3102 /******************************************************************************
3104 ** Storage32InternalImpl_Commit
3106 ** The non-root storages cannot be opened in transacted mode thus this function
3107 ** does nothing.
3109 HRESULT WINAPI StorageInternalImpl_Commit(
3110 IStorage* iface,
3111 DWORD grfCommitFlags) /* [in] */
3113 return S_OK;
3116 /******************************************************************************
3118 ** Storage32InternalImpl_Revert
3120 ** The non-root storages cannot be opened in transacted mode thus this function
3121 ** does nothing.
3123 HRESULT WINAPI StorageInternalImpl_Revert(
3124 IStorage* iface)
3126 return S_OK;
3129 /******************************************************************************
3130 ** IEnumSTATSTGImpl implementation
3133 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3134 StorageImpl* parentStorage,
3135 ULONG firstPropertyNode)
3137 IEnumSTATSTGImpl* newEnumeration;
3139 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3141 if (newEnumeration!=0)
3144 * Set-up the virtual function table and reference count.
3146 newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
3147 newEnumeration->ref = 0;
3150 * We want to nail-down the reference to the storage in case the
3151 * enumeration out-lives the storage in the client application.
3153 newEnumeration->parentStorage = parentStorage;
3154 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3156 newEnumeration->firstPropertyNode = firstPropertyNode;
3159 * Initialize the search stack
3161 newEnumeration->stackSize = 0;
3162 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3163 newEnumeration->stackToVisit =
3164 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3167 * Make sure the current node of the iterator is the first one.
3169 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3172 return newEnumeration;
3175 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3177 IStorage_Release((IStorage*)This->parentStorage);
3178 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3179 HeapFree(GetProcessHeap(), 0, This);
3182 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3183 IEnumSTATSTG* iface,
3184 REFIID riid,
3185 void** ppvObject)
3187 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3190 * Perform a sanity check on the parameters.
3192 if (ppvObject==0)
3193 return E_INVALIDARG;
3196 * Initialize the return parameter.
3198 *ppvObject = 0;
3201 * Compare the riid with the interface IDs implemented by this object.
3203 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3205 *ppvObject = (IEnumSTATSTG*)This;
3207 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3209 *ppvObject = (IEnumSTATSTG*)This;
3213 * Check that we obtained an interface.
3215 if ((*ppvObject)==0)
3216 return E_NOINTERFACE;
3219 * Query Interface always increases the reference count by one when it is
3220 * successful
3222 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3224 return S_OK;
3227 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3228 IEnumSTATSTG* iface)
3230 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3232 This->ref++;
3233 return This->ref;
3236 ULONG WINAPI IEnumSTATSTGImpl_Release(
3237 IEnumSTATSTG* iface)
3239 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3241 ULONG newRef;
3243 This->ref--;
3244 newRef = This->ref;
3247 * If the reference count goes down to 0, perform suicide.
3249 if (newRef==0)
3251 IEnumSTATSTGImpl_Destroy(This);
3254 return newRef;;
3257 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3258 IEnumSTATSTG* iface,
3259 ULONG celt,
3260 STATSTG* rgelt,
3261 ULONG* pceltFetched)
3263 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3265 StgProperty currentProperty;
3266 STATSTG* currentReturnStruct = rgelt;
3267 ULONG objectFetched = 0;
3268 ULONG currentSearchNode;
3271 * Perform a sanity check on the parameters.
3273 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3274 return E_INVALIDARG;
3277 * To avoid the special case, get another pointer to a ULONG value if
3278 * the caller didn't supply one.
3280 if (pceltFetched==0)
3281 pceltFetched = &objectFetched;
3284 * Start the iteration, we will iterate until we hit the end of the
3285 * linked list or until we hit the number of items to iterate through
3287 *pceltFetched = 0;
3290 * Start with the node at the top of the stack.
3292 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3294 while ( ( *pceltFetched < celt) &&
3295 ( currentSearchNode!=PROPERTY_NULL) )
3298 * Remove the top node from the stack
3300 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3303 * Read the property from the storage.
3305 StorageImpl_ReadProperty(This->parentStorage,
3306 currentSearchNode,
3307 &currentProperty);
3310 * Copy the information to the return buffer.
3312 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3313 &currentProperty,
3314 STATFLAG_DEFAULT);
3317 * Step to the next item in the iteration
3319 (*pceltFetched)++;
3320 currentReturnStruct++;
3323 * Push the next search node in the search stack.
3325 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3328 * continue the iteration.
3330 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3333 if (*pceltFetched == celt)
3334 return S_OK;
3336 return S_FALSE;
3340 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3341 IEnumSTATSTG* iface,
3342 ULONG celt)
3344 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3346 StgProperty currentProperty;
3347 ULONG objectFetched = 0;
3348 ULONG currentSearchNode;
3351 * Start with the node at the top of the stack.
3353 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3355 while ( (objectFetched < celt) &&
3356 (currentSearchNode!=PROPERTY_NULL) )
3359 * Remove the top node from the stack
3361 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3364 * Read the property from the storage.
3366 StorageImpl_ReadProperty(This->parentStorage,
3367 currentSearchNode,
3368 &currentProperty);
3371 * Step to the next item in the iteration
3373 objectFetched++;
3376 * Push the next search node in the search stack.
3378 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3381 * continue the iteration.
3383 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3386 if (objectFetched == celt)
3387 return S_OK;
3389 return S_FALSE;
3392 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3393 IEnumSTATSTG* iface)
3395 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3397 StgProperty rootProperty;
3398 BOOL readSucessful;
3401 * Re-initialize the search stack to an empty stack
3403 This->stackSize = 0;
3406 * Read the root property from the storage.
3408 readSucessful = StorageImpl_ReadProperty(
3409 This->parentStorage,
3410 This->firstPropertyNode,
3411 &rootProperty);
3413 if (readSucessful)
3415 assert(rootProperty.sizeOfNameString!=0);
3418 * Push the search node in the search stack.
3420 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3423 return S_OK;
3426 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3427 IEnumSTATSTG* iface,
3428 IEnumSTATSTG** ppenum)
3430 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3432 IEnumSTATSTGImpl* newClone;
3435 * Perform a sanity check on the parameters.
3437 if (ppenum==0)
3438 return E_INVALIDARG;
3440 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3441 This->firstPropertyNode);
3445 * The new clone enumeration must point to the same current node as
3446 * the ole one.
3448 newClone->stackSize = This->stackSize ;
3449 newClone->stackMaxSize = This->stackMaxSize ;
3450 newClone->stackToVisit =
3451 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3453 memcpy(
3454 newClone->stackToVisit,
3455 This->stackToVisit,
3456 sizeof(ULONG) * newClone->stackSize);
3458 *ppenum = (IEnumSTATSTG*)newClone;
3461 * Don't forget to nail down a reference to the clone before
3462 * returning it.
3464 IEnumSTATSTGImpl_AddRef(*ppenum);
3466 return S_OK;
3469 INT IEnumSTATSTGImpl_FindParentProperty(
3470 IEnumSTATSTGImpl *This,
3471 ULONG childProperty,
3472 StgProperty *currentProperty,
3473 ULONG *thisNodeId)
3475 ULONG currentSearchNode;
3476 ULONG foundNode;
3479 * To avoid the special case, get another pointer to a ULONG value if
3480 * the caller didn't supply one.
3482 if (thisNodeId==0)
3483 thisNodeId = &foundNode;
3486 * Start with the node at the top of the stack.
3488 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3491 while (currentSearchNode!=PROPERTY_NULL)
3494 * Store the current node in the returned parameters
3496 *thisNodeId = currentSearchNode;
3499 * Remove the top node from the stack
3501 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3504 * Read the property from the storage.
3506 StorageImpl_ReadProperty(
3507 This->parentStorage,
3508 currentSearchNode,
3509 currentProperty);
3511 if (currentProperty->previousProperty == childProperty)
3512 return PROPERTY_RELATION_PREVIOUS;
3514 else if (currentProperty->nextProperty == childProperty)
3515 return PROPERTY_RELATION_NEXT;
3517 else if (currentProperty->dirProperty == childProperty)
3518 return PROPERTY_RELATION_DIR;
3521 * Push the next search node in the search stack.
3523 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3526 * continue the iteration.
3528 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3531 return PROPERTY_NULL;
3534 ULONG IEnumSTATSTGImpl_FindProperty(
3535 IEnumSTATSTGImpl* This,
3536 const OLECHAR* lpszPropName,
3537 StgProperty* currentProperty)
3539 ULONG currentSearchNode;
3542 * Start with the node at the top of the stack.
3544 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3546 while (currentSearchNode!=PROPERTY_NULL)
3549 * Remove the top node from the stack
3551 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3554 * Read the property from the storage.
3556 StorageImpl_ReadProperty(This->parentStorage,
3557 currentSearchNode,
3558 currentProperty);
3560 if ( propertyNameCmp(
3561 (OLECHAR*)currentProperty->name,
3562 (OLECHAR*)lpszPropName) == 0)
3563 return currentSearchNode;
3566 * Push the next search node in the search stack.
3568 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3571 * continue the iteration.
3573 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3576 return PROPERTY_NULL;
3579 void IEnumSTATSTGImpl_PushSearchNode(
3580 IEnumSTATSTGImpl* This,
3581 ULONG nodeToPush)
3583 StgProperty rootProperty;
3584 BOOL readSucessful;
3587 * First, make sure we're not trying to push an unexisting node.
3589 if (nodeToPush==PROPERTY_NULL)
3590 return;
3593 * First push the node to the stack
3595 if (This->stackSize == This->stackMaxSize)
3597 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3599 This->stackToVisit = HeapReAlloc(
3600 GetProcessHeap(),
3602 This->stackToVisit,
3603 sizeof(ULONG) * This->stackMaxSize);
3606 This->stackToVisit[This->stackSize] = nodeToPush;
3607 This->stackSize++;
3610 * Read the root property from the storage.
3612 readSucessful = StorageImpl_ReadProperty(
3613 This->parentStorage,
3614 nodeToPush,
3615 &rootProperty);
3617 if (readSucessful)
3619 assert(rootProperty.sizeOfNameString!=0);
3622 * Push the previous search node in the search stack.
3624 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3628 ULONG IEnumSTATSTGImpl_PopSearchNode(
3629 IEnumSTATSTGImpl* This,
3630 BOOL remove)
3632 ULONG topNode;
3634 if (This->stackSize == 0)
3635 return PROPERTY_NULL;
3637 topNode = This->stackToVisit[This->stackSize-1];
3639 if (remove)
3640 This->stackSize--;
3642 return topNode;
3645 /******************************************************************************
3646 ** StorageUtl implementation
3649 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3651 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3654 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3656 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3659 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3661 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3664 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3666 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3669 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3671 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3672 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3673 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3675 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3678 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3680 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3681 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3682 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3684 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3687 void StorageUtl_CopyPropertyToSTATSTG(
3688 STATSTG* destination,
3689 StgProperty* source,
3690 int statFlags)
3693 * The copy of the string occurs only when the flag is not set
3695 if ((statFlags & STATFLAG_NONAME) != 0)
3697 destination->pwcsName = 0;
3699 else
3701 destination->pwcsName =
3702 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3704 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3707 switch (source->propertyType)
3709 case PROPTYPE_STORAGE:
3710 case PROPTYPE_ROOT:
3711 destination->type = STGTY_STORAGE;
3712 break;
3713 case PROPTYPE_STREAM:
3714 destination->type = STGTY_STREAM;
3715 break;
3716 default:
3717 destination->type = STGTY_STREAM;
3718 break;
3721 destination->cbSize = source->size;
3723 currentReturnStruct->mtime = {0}; TODO
3724 currentReturnStruct->ctime = {0};
3725 currentReturnStruct->atime = {0};
3727 destination->grfMode = 0;
3728 destination->grfLocksSupported = 0;
3729 destination->clsid = source->propertyUniqueID;
3730 destination->grfStateBits = 0;
3731 destination->reserved = 0;
3734 /******************************************************************************
3735 ** BlockChainStream implementation
3738 BlockChainStream* BlockChainStream_Construct(
3739 StorageImpl* parentStorage,
3740 ULONG* headOfStreamPlaceHolder,
3741 ULONG propertyIndex)
3743 BlockChainStream* newStream;
3744 ULONG blockIndex;
3746 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3748 newStream->parentStorage = parentStorage;
3749 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3750 newStream->ownerPropertyIndex = propertyIndex;
3751 newStream->lastBlockNoInSequence = 0xFFFFFFFF;
3752 newStream->tailIndex = BLOCK_END_OF_CHAIN;
3753 newStream->numBlocks = 0;
3755 blockIndex = BlockChainStream_GetHeadOfChain(newStream);
3757 while (blockIndex != BLOCK_END_OF_CHAIN)
3759 newStream->numBlocks++;
3760 newStream->tailIndex = blockIndex;
3762 blockIndex = StorageImpl_GetNextBlockInChain(
3763 parentStorage,
3764 blockIndex);
3767 return newStream;
3770 void BlockChainStream_Destroy(BlockChainStream* This)
3772 HeapFree(GetProcessHeap(), 0, This);
3775 /******************************************************************************
3776 * BlockChainStream_GetHeadOfChain
3778 * Returns the head of this stream chain.
3779 * Some special chains don't have properties, their heads are kept in
3780 * This->headOfStreamPlaceHolder.
3783 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3785 StgProperty chainProperty;
3786 BOOL readSucessful;
3788 if (This->headOfStreamPlaceHolder != 0)
3789 return *(This->headOfStreamPlaceHolder);
3791 if (This->ownerPropertyIndex != PROPERTY_NULL)
3793 readSucessful = StorageImpl_ReadProperty(
3794 This->parentStorage,
3795 This->ownerPropertyIndex,
3796 &chainProperty);
3798 if (readSucessful)
3800 return chainProperty.startingBlock;
3804 return BLOCK_END_OF_CHAIN;
3807 /******************************************************************************
3808 * BlockChainStream_GetCount
3810 * Returns the number of blocks that comprises this chain.
3811 * This is not the size of the stream as the last block may not be full!
3814 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3816 ULONG blockIndex;
3817 ULONG count = 0;
3819 blockIndex = BlockChainStream_GetHeadOfChain(This);
3821 while (blockIndex != BLOCK_END_OF_CHAIN)
3823 count++;
3825 blockIndex = StorageImpl_GetNextBlockInChain(
3826 This->parentStorage,
3827 blockIndex);
3830 return count;
3833 /******************************************************************************
3834 * BlockChainStream_ReadAt
3836 * Reads a specified number of bytes from this chain at the specified offset.
3837 * bytesRead may be NULL.
3838 * Failure will be returned if the specified number of bytes has not been read.
3840 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
3841 ULARGE_INTEGER offset,
3842 ULONG size,
3843 void* buffer,
3844 ULONG* bytesRead)
3846 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3847 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3848 ULONG bytesToReadInBuffer;
3849 ULONG blockIndex;
3850 BYTE* bufferWalker;
3851 BYTE* bigBlockBuffer;
3853 if (This->lastBlockNoInSequence == 0xFFFFFFFF)
3854 This->lastBlockNoInSequence = blockNoInSequence;
3856 * Find the first block in the stream that contains part of the buffer.
3858 if (blockNoInSequence > This->lastBlockNoInSequence)
3860 ULONG temp = blockNoInSequence;
3862 blockIndex = This->lastBlockNoInSequenceIndex;
3863 blockNoInSequence -= This->lastBlockNoInSequence;
3864 This->lastBlockNoInSequence = temp;
3866 else
3868 blockIndex = BlockChainStream_GetHeadOfChain(This);
3869 This->lastBlockNoInSequence = blockNoInSequence;
3872 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3874 blockIndex =
3875 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3877 blockNoInSequence--;
3880 This->lastBlockNoInSequenceIndex = blockIndex;
3883 * Start reading the buffer.
3885 *bytesRead = 0;
3886 bufferWalker = buffer;
3888 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3891 * Calculate how many bytes we can copy from this big block.
3893 bytesToReadInBuffer =
3894 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3897 * Copy those bytes to the buffer
3899 bigBlockBuffer =
3900 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
3902 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3904 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3907 * Step to the next big block.
3909 blockIndex =
3910 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3912 bufferWalker += bytesToReadInBuffer;
3913 size -= bytesToReadInBuffer;
3914 *bytesRead += bytesToReadInBuffer;
3915 offsetInBlock = 0; /* There is no offset on the next block */
3919 return (size == 0);
3922 /******************************************************************************
3923 * BlockChainStream_WriteAt
3925 * Writes the specified number of bytes to this chain at the specified offset.
3926 * bytesWritten may be NULL.
3927 * Will fail if not all specified number of bytes have been written.
3929 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
3930 ULARGE_INTEGER offset,
3931 ULONG size,
3932 const void* buffer,
3933 ULONG* bytesWritten)
3935 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3936 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3937 ULONG bytesToWrite;
3938 ULONG blockIndex;
3939 BYTE* bufferWalker;
3940 BYTE* bigBlockBuffer;
3942 if (This->lastBlockNoInSequence == 0xFFFFFFFF)
3943 This->lastBlockNoInSequence = blockNoInSequence;
3946 * Find the first block in the stream that contains part of the buffer.
3948 if (blockNoInSequence > This->lastBlockNoInSequence)
3950 ULONG temp = blockNoInSequence;
3952 blockIndex = This->lastBlockNoInSequenceIndex;
3953 blockNoInSequence -= This->lastBlockNoInSequence;
3954 This->lastBlockNoInSequence = temp;
3956 else
3958 blockIndex = BlockChainStream_GetHeadOfChain(This);
3959 This->lastBlockNoInSequence = blockNoInSequence;
3962 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3964 blockIndex =
3965 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3967 blockNoInSequence--;
3970 This->lastBlockNoInSequenceIndex = blockIndex;
3973 * Here, I'm casting away the constness on the buffer variable
3974 * This is OK since we don't intend to modify that buffer.
3976 *bytesWritten = 0;
3977 bufferWalker = (BYTE*)buffer;
3979 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3982 * Calculate how many bytes we can copy from this big block.
3984 bytesToWrite =
3985 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3988 * Copy those bytes to the buffer
3990 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
3992 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
3994 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3997 * Step to the next big block.
3999 blockIndex =
4000 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4002 bufferWalker += bytesToWrite;
4003 size -= bytesToWrite;
4004 *bytesWritten += bytesToWrite;
4005 offsetInBlock = 0; /* There is no offset on the next block */
4008 return (size == 0);
4011 /******************************************************************************
4012 * BlockChainStream_Shrink
4014 * Shrinks this chain in the big block depot.
4016 BOOL BlockChainStream_Shrink(BlockChainStream* This,
4017 ULARGE_INTEGER newSize)
4019 ULONG blockIndex, extraBlock;
4020 ULONG numBlocks;
4021 ULONG count = 1;
4024 * Figure out how many blocks are needed to contain the new size
4026 numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
4028 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
4029 numBlocks++;
4031 blockIndex = BlockChainStream_GetHeadOfChain(This);
4034 * Go to the new end of chain
4036 while (count < numBlocks)
4038 blockIndex =
4039 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4041 count++;
4044 /* Get the next block before marking the new end */
4045 extraBlock =
4046 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4048 /* Mark the new end of chain */
4049 StorageImpl_SetNextBlockInChain(
4050 This->parentStorage,
4051 blockIndex,
4052 BLOCK_END_OF_CHAIN);
4054 This->tailIndex = blockIndex;
4055 This->numBlocks = numBlocks;
4058 * Mark the extra blocks as free
4060 while (extraBlock != BLOCK_END_OF_CHAIN)
4062 blockIndex =
4063 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4065 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4066 extraBlock = blockIndex;
4069 return TRUE;
4072 /******************************************************************************
4073 * BlockChainStream_Enlarge
4075 * Grows this chain in the big block depot.
4077 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4078 ULARGE_INTEGER newSize)
4080 ULONG blockIndex, currentBlock;
4081 ULONG newNumBlocks;
4082 ULONG oldNumBlocks = 0;
4084 blockIndex = BlockChainStream_GetHeadOfChain(This);
4087 * Empty chain. Create the head.
4089 if (blockIndex == BLOCK_END_OF_CHAIN)
4091 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4092 StorageImpl_SetNextBlockInChain(This->parentStorage,
4093 blockIndex,
4094 BLOCK_END_OF_CHAIN);
4096 if (This->headOfStreamPlaceHolder != 0)
4098 *(This->headOfStreamPlaceHolder) = blockIndex;
4100 else
4102 StgProperty chainProp;
4103 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4105 StorageImpl_ReadProperty(
4106 This->parentStorage,
4107 This->ownerPropertyIndex,
4108 &chainProp);
4110 chainProp.startingBlock = blockIndex;
4112 StorageImpl_WriteProperty(
4113 This->parentStorage,
4114 This->ownerPropertyIndex,
4115 &chainProp);
4118 This->tailIndex = blockIndex;
4119 This->numBlocks = 1;
4123 * Figure out how many blocks are needed to contain this stream
4125 newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
4127 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
4128 newNumBlocks++;
4131 * Go to the current end of chain
4133 if (This->tailIndex == BLOCK_END_OF_CHAIN)
4135 currentBlock = blockIndex;
4137 while (blockIndex != BLOCK_END_OF_CHAIN)
4139 This->numBlocks++;
4140 currentBlock = blockIndex;
4142 blockIndex =
4143 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4146 This->tailIndex = currentBlock;
4149 currentBlock = This->tailIndex;
4150 oldNumBlocks = This->numBlocks;
4153 * Add new blocks to the chain
4155 while (oldNumBlocks < newNumBlocks)
4157 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4159 StorageImpl_SetNextBlockInChain(
4160 This->parentStorage,
4161 currentBlock,
4162 blockIndex);
4164 StorageImpl_SetNextBlockInChain(
4165 This->parentStorage,
4166 blockIndex,
4167 BLOCK_END_OF_CHAIN);
4169 currentBlock = blockIndex;
4170 oldNumBlocks++;
4173 This->tailIndex = blockIndex;
4174 This->numBlocks = newNumBlocks;
4176 return TRUE;
4179 /******************************************************************************
4180 * BlockChainStream_SetSize
4182 * Sets the size of this stream. The big block depot will be updated.
4183 * The file will grow if we grow the chain.
4185 * TODO: Free the actual blocks in the file when we shrink the chain.
4186 * Currently, the blocks are still in the file. So the file size
4187 * doesn't shrink even if we shrink streams.
4189 BOOL BlockChainStream_SetSize(
4190 BlockChainStream* This,
4191 ULARGE_INTEGER newSize)
4193 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4195 if (newSize.LowPart == size.LowPart)
4196 return TRUE;
4198 if (newSize.LowPart < size.LowPart)
4200 BlockChainStream_Shrink(This, newSize);
4202 else
4204 ULARGE_INTEGER fileSize =
4205 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4207 ULONG diff = newSize.LowPart - size.LowPart;
4210 * Make sure the file stays a multiple of blocksize
4212 if ((diff % This->parentStorage->bigBlockSize) != 0)
4213 diff += (This->parentStorage->bigBlockSize -
4214 (diff % This->parentStorage->bigBlockSize) );
4216 fileSize.LowPart += diff;
4217 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4219 BlockChainStream_Enlarge(This, newSize);
4222 return TRUE;
4225 /******************************************************************************
4226 * BlockChainStream_GetSize
4228 * Returns the size of this chain.
4229 * Will return the block count if this chain doesn't have a property.
4231 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4233 StgProperty chainProperty;
4235 if(This->headOfStreamPlaceHolder == NULL)
4238 * This chain is a data stream read the property and return
4239 * the appropriate size
4241 StorageImpl_ReadProperty(
4242 This->parentStorage,
4243 This->ownerPropertyIndex,
4244 &chainProperty);
4246 return chainProperty.size;
4248 else
4251 * this chain is a chain that does not have a property, figure out the
4252 * size by making the product number of used blocks times the
4253 * size of them
4255 ULARGE_INTEGER result;
4256 result.HighPart = 0;
4258 result.LowPart =
4259 BlockChainStream_GetCount(This) *
4260 This->parentStorage->bigBlockSize;
4262 return result;
4266 /******************************************************************************
4267 ** SmallBlockChainStream implementation
4270 SmallBlockChainStream* SmallBlockChainStream_Construct(
4271 StorageImpl* parentStorage,
4272 ULONG propertyIndex)
4274 SmallBlockChainStream* newStream;
4276 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4278 newStream->parentStorage = parentStorage;
4279 newStream->ownerPropertyIndex = propertyIndex;
4281 return newStream;
4284 void SmallBlockChainStream_Destroy(
4285 SmallBlockChainStream* This)
4287 HeapFree(GetProcessHeap(), 0, This);
4290 /******************************************************************************
4291 * SmallBlockChainStream_GetHeadOfChain
4293 * Returns the head of this chain of small blocks.
4295 ULONG SmallBlockChainStream_GetHeadOfChain(
4296 SmallBlockChainStream* This)
4298 StgProperty chainProperty;
4299 BOOL readSucessful;
4301 if (This->ownerPropertyIndex)
4303 readSucessful = StorageImpl_ReadProperty(
4304 This->parentStorage,
4305 This->ownerPropertyIndex,
4306 &chainProperty);
4308 if (readSucessful)
4310 return chainProperty.startingBlock;
4315 return BLOCK_END_OF_CHAIN;
4318 /******************************************************************************
4319 * SmallBlockChainStream_GetNextBlockInChain
4321 * Returns the index of the next small block in this chain.
4323 * Return Values:
4324 * - BLOCK_END_OF_CHAIN: end of this chain
4325 * - BLOCK_UNUSED: small block 'blockIndex' is free
4327 ULONG SmallBlockChainStream_GetNextBlockInChain(
4328 SmallBlockChainStream* This,
4329 ULONG blockIndex)
4331 ULARGE_INTEGER offsetOfBlockInDepot;
4332 DWORD buffer;
4333 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4334 ULONG bytesRead;
4335 BOOL success;
4337 offsetOfBlockInDepot.HighPart = 0;
4338 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4341 * Read those bytes in the buffer from the small block file.
4343 success = BlockChainStream_ReadAt(
4344 This->parentStorage->smallBlockDepotChain,
4345 offsetOfBlockInDepot,
4346 sizeof(DWORD),
4347 &buffer,
4348 &bytesRead);
4350 if (success)
4352 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4355 return nextBlockInChain;
4358 /******************************************************************************
4359 * SmallBlockChainStream_SetNextBlockInChain
4361 * Writes the index of the next block of the specified block in the small
4362 * block depot.
4363 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4364 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4366 void SmallBlockChainStream_SetNextBlockInChain(
4367 SmallBlockChainStream* This,
4368 ULONG blockIndex,
4369 ULONG nextBlock)
4371 ULARGE_INTEGER offsetOfBlockInDepot;
4372 DWORD buffer;
4373 ULONG bytesWritten;
4375 offsetOfBlockInDepot.HighPart = 0;
4376 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4378 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4381 * Read those bytes in the buffer from the small block file.
4383 BlockChainStream_WriteAt(
4384 This->parentStorage->smallBlockDepotChain,
4385 offsetOfBlockInDepot,
4386 sizeof(DWORD),
4387 &buffer,
4388 &bytesWritten);
4391 /******************************************************************************
4392 * SmallBlockChainStream_FreeBlock
4394 * Flag small block 'blockIndex' as free in the small block depot.
4396 void SmallBlockChainStream_FreeBlock(
4397 SmallBlockChainStream* This,
4398 ULONG blockIndex)
4400 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4403 /******************************************************************************
4404 * SmallBlockChainStream_GetNextFreeBlock
4406 * Returns the index of a free small block. The small block depot will be
4407 * enlarged if necessary. The small block chain will also be enlarged if
4408 * necessary.
4410 ULONG SmallBlockChainStream_GetNextFreeBlock(
4411 SmallBlockChainStream* This)
4413 ULARGE_INTEGER offsetOfBlockInDepot;
4414 DWORD buffer;
4415 ULONG bytesRead;
4416 ULONG blockIndex = 0;
4417 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4418 BOOL success = TRUE;
4419 ULONG smallBlocksPerBigBlock;
4421 offsetOfBlockInDepot.HighPart = 0;
4424 * Scan the small block depot for a free block
4426 while (nextBlockIndex != BLOCK_UNUSED)
4428 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4430 success = BlockChainStream_ReadAt(
4431 This->parentStorage->smallBlockDepotChain,
4432 offsetOfBlockInDepot,
4433 sizeof(DWORD),
4434 &buffer,
4435 &bytesRead);
4438 * If we run out of space for the small block depot, enlarge it
4440 if (success)
4442 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4444 if (nextBlockIndex != BLOCK_UNUSED)
4445 blockIndex++;
4447 else
4449 ULONG count =
4450 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4452 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4453 ULONG nextBlock, newsbdIndex;
4454 BYTE* smallBlockDepot;
4456 nextBlock = sbdIndex;
4457 while (nextBlock != BLOCK_END_OF_CHAIN)
4459 sbdIndex = nextBlock;
4460 nextBlock =
4461 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4464 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4465 if (sbdIndex != BLOCK_END_OF_CHAIN)
4466 StorageImpl_SetNextBlockInChain(
4467 This->parentStorage,
4468 sbdIndex,
4469 newsbdIndex);
4471 StorageImpl_SetNextBlockInChain(
4472 This->parentStorage,
4473 newsbdIndex,
4474 BLOCK_END_OF_CHAIN);
4477 * Initialize all the small blocks to free
4479 smallBlockDepot =
4480 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4482 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4483 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4485 if (count == 0)
4488 * We have just created the small block depot.
4490 StgProperty rootProp;
4491 ULONG sbStartIndex;
4494 * Save it in the header
4496 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4497 StorageImpl_SaveFileHeader(This->parentStorage);
4500 * And allocate the first big block that will contain small blocks
4502 sbStartIndex =
4503 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4505 StorageImpl_SetNextBlockInChain(
4506 This->parentStorage,
4507 sbStartIndex,
4508 BLOCK_END_OF_CHAIN);
4510 StorageImpl_ReadProperty(
4511 This->parentStorage,
4512 This->parentStorage->rootPropertySetIndex,
4513 &rootProp);
4515 rootProp.startingBlock = sbStartIndex;
4516 rootProp.size.HighPart = 0;
4517 rootProp.size.LowPart = This->parentStorage->bigBlockSize;
4519 StorageImpl_WriteProperty(
4520 This->parentStorage,
4521 This->parentStorage->rootPropertySetIndex,
4522 &rootProp);
4527 smallBlocksPerBigBlock =
4528 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4531 * Verify if we have to allocate big blocks to contain small blocks
4533 if (blockIndex % smallBlocksPerBigBlock == 0)
4535 StgProperty rootProp;
4536 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4538 StorageImpl_ReadProperty(
4539 This->parentStorage,
4540 This->parentStorage->rootPropertySetIndex,
4541 &rootProp);
4543 if (rootProp.size.LowPart <
4544 (blocksRequired * This->parentStorage->bigBlockSize))
4546 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4548 BlockChainStream_SetSize(
4549 This->parentStorage->smallBlockRootChain,
4550 rootProp.size);
4552 StorageImpl_WriteProperty(
4553 This->parentStorage,
4554 This->parentStorage->rootPropertySetIndex,
4555 &rootProp);
4559 return blockIndex;
4562 /******************************************************************************
4563 * SmallBlockChainStream_ReadAt
4565 * Reads a specified number of bytes from this chain at the specified offset.
4566 * bytesRead may be NULL.
4567 * Failure will be returned if the specified number of bytes has not been read.
4569 BOOL SmallBlockChainStream_ReadAt(
4570 SmallBlockChainStream* This,
4571 ULARGE_INTEGER offset,
4572 ULONG size,
4573 void* buffer,
4574 ULONG* bytesRead)
4576 ULARGE_INTEGER offsetInBigBlockFile;
4577 ULONG blockNoInSequence =
4578 offset.LowPart / This->parentStorage->smallBlockSize;
4580 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4581 ULONG bytesToReadInBuffer;
4582 ULONG blockIndex;
4583 ULONG bytesReadFromBigBlockFile;
4584 BYTE* bufferWalker;
4587 * This should never happen on a small block file.
4589 assert(offset.HighPart==0);
4592 * Find the first block in the stream that contains part of the buffer.
4594 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4596 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4598 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4600 blockNoInSequence--;
4604 * Start reading the buffer.
4606 *bytesRead = 0;
4607 bufferWalker = buffer;
4609 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4612 * Calculate how many bytes we can copy from this small block.
4614 bytesToReadInBuffer =
4615 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4618 * Calculate the offset of the small block in the small block file.
4620 offsetInBigBlockFile.HighPart = 0;
4621 offsetInBigBlockFile.LowPart =
4622 blockIndex * This->parentStorage->smallBlockSize;
4624 offsetInBigBlockFile.LowPart += offsetInBlock;
4627 * Read those bytes in the buffer from the small block file.
4629 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4630 offsetInBigBlockFile,
4631 bytesToReadInBuffer,
4632 bufferWalker,
4633 &bytesReadFromBigBlockFile);
4635 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4638 * Step to the next big block.
4640 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4641 bufferWalker += bytesToReadInBuffer;
4642 size -= bytesToReadInBuffer;
4643 *bytesRead += bytesToReadInBuffer;
4644 offsetInBlock = 0; /* There is no offset on the next block */
4647 return (size == 0);
4650 /******************************************************************************
4651 * SmallBlockChainStream_WriteAt
4653 * Writes the specified number of bytes to this chain at the specified offset.
4654 * bytesWritten may be NULL.
4655 * Will fail if not all specified number of bytes have been written.
4657 BOOL SmallBlockChainStream_WriteAt(
4658 SmallBlockChainStream* This,
4659 ULARGE_INTEGER offset,
4660 ULONG size,
4661 const void* buffer,
4662 ULONG* bytesWritten)
4664 ULARGE_INTEGER offsetInBigBlockFile;
4665 ULONG blockNoInSequence =
4666 offset.LowPart / This->parentStorage->smallBlockSize;
4668 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4669 ULONG bytesToWriteInBuffer;
4670 ULONG blockIndex;
4671 ULONG bytesWrittenFromBigBlockFile;
4672 BYTE* bufferWalker;
4675 * This should never happen on a small block file.
4677 assert(offset.HighPart==0);
4680 * Find the first block in the stream that contains part of the buffer.
4682 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4684 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4686 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4688 blockNoInSequence--;
4692 * Start writing the buffer.
4694 * Here, I'm casting away the constness on the buffer variable
4695 * This is OK since we don't intend to modify that buffer.
4697 *bytesWritten = 0;
4698 bufferWalker = (BYTE*)buffer;
4699 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4702 * Calculate how many bytes we can copy to this small block.
4704 bytesToWriteInBuffer =
4705 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4708 * Calculate the offset of the small block in the small block file.
4710 offsetInBigBlockFile.HighPart = 0;
4711 offsetInBigBlockFile.LowPart =
4712 blockIndex * This->parentStorage->smallBlockSize;
4714 offsetInBigBlockFile.LowPart += offsetInBlock;
4717 * Write those bytes in the buffer to the small block file.
4719 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4720 offsetInBigBlockFile,
4721 bytesToWriteInBuffer,
4722 bufferWalker,
4723 &bytesWrittenFromBigBlockFile);
4725 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4728 * Step to the next big block.
4730 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4731 bufferWalker += bytesToWriteInBuffer;
4732 size -= bytesToWriteInBuffer;
4733 *bytesWritten += bytesToWriteInBuffer;
4734 offsetInBlock = 0; /* There is no offset on the next block */
4737 return (size == 0);
4740 /******************************************************************************
4741 * SmallBlockChainStream_Shrink
4743 * Shrinks this chain in the small block depot.
4745 BOOL SmallBlockChainStream_Shrink(
4746 SmallBlockChainStream* This,
4747 ULARGE_INTEGER newSize)
4749 ULONG blockIndex, extraBlock;
4750 ULONG numBlocks;
4751 ULONG count = 1;
4753 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4755 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4756 numBlocks++;
4758 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4761 * Go to the new end of chain
4763 while (count < numBlocks)
4765 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4766 count++;
4769 /* Get the next block before marking the new end */
4770 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4772 /* Mark the new end of chain */
4773 SmallBlockChainStream_SetNextBlockInChain(
4774 This,
4775 blockIndex,
4776 BLOCK_END_OF_CHAIN);
4779 * Mark the extra blocks as free
4781 while (extraBlock != BLOCK_END_OF_CHAIN)
4783 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4784 SmallBlockChainStream_FreeBlock(This, extraBlock);
4785 extraBlock = blockIndex;
4788 return TRUE;
4791 /******************************************************************************
4792 * SmallBlockChainStream_Enlarge
4794 * Grows this chain in the small block depot.
4796 BOOL SmallBlockChainStream_Enlarge(
4797 SmallBlockChainStream* This,
4798 ULARGE_INTEGER newSize)
4800 ULONG blockIndex, currentBlock;
4801 ULONG newNumBlocks;
4802 ULONG oldNumBlocks = 0;
4804 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4807 * Empty chain
4809 if (blockIndex == BLOCK_END_OF_CHAIN)
4811 StgProperty chainProp;
4813 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4814 &chainProp);
4816 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4818 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4819 &chainProp);
4821 blockIndex = chainProp.startingBlock;
4822 SmallBlockChainStream_SetNextBlockInChain(
4823 This,
4824 blockIndex,
4825 BLOCK_END_OF_CHAIN);
4828 currentBlock = blockIndex;
4831 * Figure out how many blocks are needed to contain this stream
4833 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4835 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4836 newNumBlocks++;
4839 * Go to the current end of chain
4841 while (blockIndex != BLOCK_END_OF_CHAIN)
4843 oldNumBlocks++;
4844 currentBlock = blockIndex;
4845 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4849 * Add new blocks to the chain
4851 while (oldNumBlocks < newNumBlocks)
4853 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4854 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4856 SmallBlockChainStream_SetNextBlockInChain(
4857 This,
4858 blockIndex,
4859 BLOCK_END_OF_CHAIN);
4861 currentBlock = blockIndex;
4862 oldNumBlocks++;
4865 return TRUE;
4868 /******************************************************************************
4869 * SmallBlockChainStream_GetCount
4871 * Returns the number of blocks that comprises this chain.
4872 * This is not the size of this chain as the last block may not be full!
4874 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4876 ULONG blockIndex;
4877 ULONG count = 0;
4879 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4881 while (blockIndex != BLOCK_END_OF_CHAIN)
4883 count++;
4885 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4888 return count;
4891 /******************************************************************************
4892 * SmallBlockChainStream_SetSize
4894 * Sets the size of this stream.
4895 * The file will grow if we grow the chain.
4897 * TODO: Free the actual blocks in the file when we shrink the chain.
4898 * Currently, the blocks are still in the file. So the file size
4899 * doesn't shrink even if we shrink streams.
4901 BOOL SmallBlockChainStream_SetSize(
4902 SmallBlockChainStream* This,
4903 ULARGE_INTEGER newSize)
4905 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4907 if (newSize.LowPart == size.LowPart)
4908 return TRUE;
4910 if (newSize.LowPart < size.LowPart)
4912 SmallBlockChainStream_Shrink(This, newSize);
4914 else
4916 SmallBlockChainStream_Enlarge(This, newSize);
4919 return TRUE;
4922 /******************************************************************************
4923 * SmallBlockChainStream_GetSize
4925 * Returns the size of this chain.
4927 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4929 StgProperty chainProperty;
4931 StorageImpl_ReadProperty(
4932 This->parentStorage,
4933 This->ownerPropertyIndex,
4934 &chainProperty);
4936 return chainProperty.size;
4939 /******************************************************************************
4940 * StgCreateDocfile32 [OLE32.144]
4941 * TODO Validate grfMode (STGM)
4943 HRESULT WINAPI StgCreateDocfile(
4944 LPCOLESTR pwcsName,
4945 DWORD grfMode,
4946 DWORD reserved,
4947 IStorage **ppstgOpen)
4949 StorageImpl* newStorage = 0;
4950 HANDLE hFile = INVALID_HANDLE_VALUE;
4951 HRESULT hr = S_OK;
4952 DWORD shareMode;
4953 DWORD accessMode;
4954 DWORD creationMode;
4955 DWORD fileAttributes;
4958 * Validate the parameters
4960 if ((ppstgOpen == 0) || (pwcsName == 0))
4961 return STG_E_INVALIDPOINTER;
4964 * Validate the STGM flags
4966 if ( FAILED( validateSTGM(grfMode) ))
4967 return STG_E_INVALIDFLAG;
4970 * Interpret the STGM value grfMode
4972 shareMode = GetShareModeFromSTGM(grfMode);
4973 accessMode = GetAccessModeFromSTGM(grfMode);
4974 creationMode = GetCreationModeFromSTGM(grfMode);
4976 if (grfMode & STGM_DELETEONRELEASE)
4977 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
4978 else
4979 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
4981 if (grfMode & STGM_TRANSACTED)
4982 FIXME(ole, "Transacted mode not implemented.\n");
4985 * Initialize the "out" parameter.
4987 *ppstgOpen = 0;
4989 hFile = CreateFileW(pwcsName,
4990 accessMode,
4991 shareMode,
4992 NULL,
4993 creationMode,
4994 fileAttributes,
4997 if (hFile == INVALID_HANDLE_VALUE)
4999 return E_FAIL;
5003 * Allocate and initialize the new IStorage32object.
5005 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5007 if (newStorage == 0)
5008 return STG_E_INSUFFICIENTMEMORY;
5010 hr = StorageImpl_Construct(
5011 newStorage,
5012 hFile,
5013 grfMode);
5015 if (FAILED(hr))
5016 return hr;
5019 * Get an "out" pointer for the caller.
5021 hr = StorageBaseImpl_QueryInterface(
5022 (IStorage*)newStorage,
5023 (REFIID)&IID_IStorage,
5024 (void**)ppstgOpen);
5026 return hr;
5029 /******************************************************************************
5030 * StgOpenStorage32 [OLE32.148]
5032 HRESULT WINAPI StgOpenStorage(
5033 const OLECHAR *pwcsName,
5034 IStorage *pstgPriority,
5035 DWORD grfMode,
5036 SNB snbExclude,
5037 DWORD reserved,
5038 IStorage **ppstgOpen)
5040 StorageImpl* newStorage = 0;
5041 HRESULT hr = S_OK;
5042 HANDLE hFile = 0;
5043 DWORD shareMode;
5044 DWORD accessMode;
5047 * Perform a sanity check
5049 if (( pwcsName == 0) || (ppstgOpen == 0) )
5050 return STG_E_INVALIDPOINTER;
5053 * Validate the STGM flags
5055 if ( FAILED( validateSTGM(grfMode) ))
5056 return STG_E_INVALIDFLAG;
5059 * Interpret the STGM value grfMode
5061 shareMode = GetShareModeFromSTGM(grfMode);
5062 accessMode = GetAccessModeFromSTGM(grfMode);
5065 * Initialize the "out" parameter.
5067 *ppstgOpen = 0;
5069 hFile = CreateFileW( pwcsName,
5070 accessMode,
5071 shareMode,
5072 NULL,
5073 OPEN_EXISTING,
5074 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5078 if (hFile==INVALID_HANDLE_VALUE)
5080 return E_FAIL;
5084 * Allocate and initialize the new IStorage32object.
5086 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5088 if (newStorage == 0)
5089 return STG_E_INSUFFICIENTMEMORY;
5091 hr = StorageImpl_Construct(
5092 newStorage,
5093 hFile,
5094 grfMode);
5096 if (FAILED(hr))
5097 return hr;
5100 * Get an "out" pointer for the caller.
5102 hr = StorageBaseImpl_QueryInterface(
5103 (IStorage*)newStorage,
5104 (REFIID)&IID_IStorage,
5105 (void**)ppstgOpen);
5107 return hr;
5110 /******************************************************************************
5111 * WriteClassStg32 [OLE32.148]
5113 * This method will store the specified CLSID in the specified storage object
5115 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5117 HRESULT hRes;
5119 assert(pStg != 0);
5121 hRes = IStorage_SetClass(pStg, rclsid);
5123 return hRes;
5127 /****************************************************************************
5128 * This method validate a STGM parameter that can contain the values below
5130 * STGM_DIRECT 0x00000000
5131 * STGM_TRANSACTED 0x00010000
5132 * STGM_SIMPLE 0x08000000
5134 * STGM_READ 0x00000000
5135 * STGM_WRITE 0x00000001
5136 * STGM_READWRITE 0x00000002
5138 * STGM_SHARE_DENY_NONE 0x00000040
5139 * STGM_SHARE_DENY_READ 0x00000030
5140 * STGM_SHARE_DENY_WRITE 0x00000020
5141 * STGM_SHARE_EXCLUSIVE 0x00000010
5143 * STGM_PRIORITY 0x00040000
5144 * STGM_DELETEONRELEASE 0x04000000
5146 * STGM_CREATE 0x00001000
5147 * STGM_CONVERT 0x00020000
5148 * STGM_FAILIFTHERE 0x00000000
5150 * STGM_NOSCRATCH 0x00100000
5151 * STGM_NOSNAPSHOT 0x00200000
5153 static HRESULT validateSTGM(DWORD stgm)
5155 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5156 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5157 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5159 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5160 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5161 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5163 BOOL bSTGM_SHARE_DENY_NONE =
5164 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5166 BOOL bSTGM_SHARE_DENY_READ =
5167 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5169 BOOL bSTGM_SHARE_DENY_WRITE =
5170 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5172 BOOL bSTGM_SHARE_EXCLUSIVE =
5173 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5175 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5176 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5178 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5179 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5182 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5184 if ( ! bSTGM_DIRECT )
5185 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5186 return E_FAIL;
5189 * STGM_WRITE | STGM_READWRITE | STGM_READ
5191 if ( ! bSTGM_READ )
5192 if( bSTGM_WRITE && bSTGM_READWRITE )
5193 return E_FAIL;
5196 * STGM_SHARE_DENY_NONE | others
5197 * (I assume here that DENY_READ implies DENY_WRITE)
5199 if ( bSTGM_SHARE_DENY_NONE )
5200 if ( bSTGM_SHARE_DENY_READ ||
5201 bSTGM_SHARE_DENY_WRITE ||
5202 bSTGM_SHARE_EXCLUSIVE)
5203 return E_FAIL;
5206 * STGM_CREATE | STGM_CONVERT
5207 * if both are false, STGM_FAILIFTHERE is set to TRUE
5209 if ( bSTGM_CREATE && bSTGM_CONVERT )
5210 return E_FAIL;
5213 * STGM_NOSCRATCH requires STGM_TRANSACTED
5215 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5216 return E_FAIL;
5219 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5220 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5222 if (bSTGM_NOSNAPSHOT)
5224 if ( ! ( bSTGM_TRANSACTED &&
5225 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5226 return E_FAIL;
5229 return S_OK;
5232 /****************************************************************************
5233 * GetShareModeFromSTGM
5235 * This method will return a share mode flag from a STGM value.
5236 * The STGM value is assumed valid.
5238 static DWORD GetShareModeFromSTGM(DWORD stgm)
5240 DWORD dwShareMode = 0;
5241 BOOL bSTGM_SHARE_DENY_NONE =
5242 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5244 BOOL bSTGM_SHARE_DENY_READ =
5245 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5247 BOOL bSTGM_SHARE_DENY_WRITE =
5248 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5250 BOOL bSTGM_SHARE_EXCLUSIVE =
5251 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5253 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5254 dwShareMode = 0;
5256 if (bSTGM_SHARE_DENY_NONE)
5257 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5259 if (bSTGM_SHARE_DENY_WRITE)
5260 dwShareMode = FILE_SHARE_READ;
5262 return dwShareMode;
5265 /****************************************************************************
5266 * GetAccessModeFromSTGM
5268 * This method will return an access mode flag from a STGM value.
5269 * The STGM value is assumed valid.
5271 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5273 DWORD dwDesiredAccess = 0;
5274 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5275 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5276 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5278 if (bSTGM_READ)
5279 dwDesiredAccess = GENERIC_READ;
5281 if (bSTGM_WRITE)
5282 dwDesiredAccess |= GENERIC_WRITE;
5284 if (bSTGM_READWRITE)
5285 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5287 return dwDesiredAccess;
5290 /****************************************************************************
5291 * GetCreationModeFromSTGM
5293 * This method will return a creation mode flag from a STGM value.
5294 * The STGM value is assumed valid.
5296 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5298 if ( stgm & STGM_CREATE)
5299 return CREATE_ALWAYS;
5300 if (stgm & STGM_CONVERT) {
5301 FIXME(ole, "STGM_CONVERT not implemented!\n");
5302 return CREATE_NEW;
5304 /* All other cases */
5305 if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
5306 FIXME(ole,"unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
5307 return CREATE_NEW;