Fixed typo.
[wine.git] / ole / storage32.c
blobdfecf14dd43e95b9400d4c42fa2462439ddca396
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"
25 #include "windef.h"
27 #include "storage32.h"
29 #define FILE_BEGIN 0
31 static const char rootPropertyName[] = "Root Entry";
33 /***********************************************************************
34 * Forward declaration of internal functions used by the method DestroyElement
36 static HRESULT deleteStorageProperty(
37 StorageImpl *parentStorage,
38 OLECHAR *propertyToDeleteName);
40 static HRESULT deleteStreamProperty(
41 StorageImpl *parentStorage,
42 ULONG foundPropertyIndexToDelete,
43 StgProperty propertyToDelete);
45 static HRESULT findPlaceholder(
46 StorageImpl *storage,
47 ULONG propertyIndexToStore,
48 ULONG storagePropertyIndex,
49 INT typeOfRelation);
51 static HRESULT adjustPropertyChain(
52 StorageImpl *This,
53 StgProperty propertyToDelete,
54 StgProperty parentProperty,
55 ULONG parentPropertyId,
56 INT typeOfRelation);
58 /***********************************************************************
59 * Declaration of the functions used to manipulate StgProperty
62 static ULONG getFreeProperty(
63 StorageImpl *storage);
65 static void updatePropertyChain(
66 StorageImpl *storage,
67 ULONG newPropertyIndex,
68 StgProperty newProperty);
70 static LONG propertyNameCmp(
71 OLECHAR *newProperty,
72 OLECHAR *currentProperty);
75 /***********************************************************************
76 * Declaration of miscellaneous functions...
78 static HRESULT validateSTGM(DWORD stgmValue);
80 static DWORD GetShareModeFromSTGM(DWORD stgm);
81 static DWORD GetAccessModeFromSTGM(DWORD stgm);
82 static DWORD GetCreationModeFromSTGM(DWORD stgm);
85 * Virtual function table for the IStorage32Impl class.
87 static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
89 StorageBaseImpl_QueryInterface,
90 StorageBaseImpl_AddRef,
91 StorageBaseImpl_Release,
92 StorageBaseImpl_CreateStream,
93 StorageBaseImpl_OpenStream,
94 StorageImpl_CreateStorage,
95 StorageBaseImpl_OpenStorage,
96 StorageImpl_CopyTo,
97 StorageImpl_MoveElementTo,
98 StorageImpl_Commit,
99 StorageImpl_Revert,
100 StorageBaseImpl_EnumElements,
101 StorageImpl_DestroyElement,
102 StorageBaseImpl_RenameElement,
103 StorageImpl_SetElementTimes,
104 StorageBaseImpl_SetClass,
105 StorageImpl_SetStateBits,
106 StorageBaseImpl_Stat
110 * Virtual function table for the Storage32InternalImpl class.
112 static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
114 StorageBaseImpl_QueryInterface,
115 StorageBaseImpl_AddRef,
116 StorageBaseImpl_Release,
117 StorageBaseImpl_CreateStream,
118 StorageBaseImpl_OpenStream,
119 StorageImpl_CreateStorage,
120 StorageBaseImpl_OpenStorage,
121 StorageImpl_CopyTo,
122 StorageImpl_MoveElementTo,
123 StorageInternalImpl_Commit,
124 StorageInternalImpl_Revert,
125 StorageBaseImpl_EnumElements,
126 StorageImpl_DestroyElement,
127 StorageBaseImpl_RenameElement,
128 StorageImpl_SetElementTimes,
129 StorageBaseImpl_SetClass,
130 StorageImpl_SetStateBits,
131 StorageBaseImpl_Stat
135 * Virtual function table for the IEnumSTATSTGImpl class.
137 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
139 IEnumSTATSTGImpl_QueryInterface,
140 IEnumSTATSTGImpl_AddRef,
141 IEnumSTATSTGImpl_Release,
142 IEnumSTATSTGImpl_Next,
143 IEnumSTATSTGImpl_Skip,
144 IEnumSTATSTGImpl_Reset,
145 IEnumSTATSTGImpl_Clone
152 /************************************************************************
153 ** Storage32BaseImpl implementatiion
156 /************************************************************************
157 * Storage32BaseImpl_QueryInterface (IUnknown)
159 * This method implements the common QueryInterface for all IStorage32
160 * implementations contained in this file.
162 * See Windows documentation for more details on IUnknown methods.
164 HRESULT WINAPI StorageBaseImpl_QueryInterface(
165 IStorage* iface,
166 REFIID riid,
167 void** ppvObject)
169 ICOM_THIS(StorageBaseImpl,iface);
171 * Perform a sanity check on the parameters.
173 if ( (This==0) || (ppvObject==0) )
174 return E_INVALIDARG;
177 * Initialize the return parameter.
179 *ppvObject = 0;
182 * Compare the riid with the interface IDs implemented by this object.
184 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
186 *ppvObject = (IStorage*)This;
188 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
190 *ppvObject = (IStorage*)This;
194 * Check that we obtained an interface.
196 if ((*ppvObject)==0)
197 return E_NOINTERFACE;
200 * Query Interface always increases the reference count by one when it is
201 * successful
203 StorageBaseImpl_AddRef(iface);
205 return S_OK;
208 /************************************************************************
209 * Storage32BaseImpl_AddRef (IUnknown)
211 * This method implements the common AddRef for all IStorage32
212 * implementations contained in this file.
214 * See Windows documentation for more details on IUnknown methods.
216 ULONG WINAPI StorageBaseImpl_AddRef(
217 IStorage* iface)
219 ICOM_THIS(StorageBaseImpl,iface);
220 This->ref++;
222 return This->ref;
225 /************************************************************************
226 * Storage32BaseImpl_Release (IUnknown)
228 * This method implements the common Release for all IStorage32
229 * implementations contained in this file.
231 * See Windows documentation for more details on IUnknown methods.
233 ULONG WINAPI StorageBaseImpl_Release(
234 IStorage* iface)
236 ICOM_THIS(StorageBaseImpl,iface);
238 * Decrease the reference count on this object.
240 This->ref--;
243 * If the reference count goes down to 0, perform suicide.
245 if (This->ref==0)
248 * Since we are using a system of base-classes, we want to call the
249 * destructor of the appropriate derived class. To do this, we are
250 * using virtual functions to implement the destructor.
252 This->v_destructor(This);
254 return 0;
257 return This->ref;
260 /************************************************************************
261 * Storage32BaseImpl_OpenStream (IStorage)
263 * This method will open the specified stream object from the current storage.
265 * See Windows documentation for more details on IStorage methods.
267 HRESULT WINAPI StorageBaseImpl_OpenStream(
268 IStorage* iface,
269 const OLECHAR* pwcsName, /* [string][in] */
270 void* reserved1, /* [unique][in] */
271 DWORD grfMode, /* [in] */
272 DWORD reserved2, /* [in] */
273 IStream** ppstm) /* [out] */
275 ICOM_THIS(StorageBaseImpl,iface);
276 IEnumSTATSTGImpl* propertyEnumeration;
277 StgStreamImpl* newStream;
278 StgProperty currentProperty;
279 ULONG foundPropertyIndex;
282 * Perform a sanity check on the parameters.
284 if ( (pwcsName==NULL) || (ppstm==0) )
285 return E_INVALIDARG;
288 * Initialize the out parameter
290 *ppstm = 0;
293 * Validate the STGM flags
295 if ( FAILED( validateSTGM(grfMode) ))
296 return STG_E_INVALIDFLAG;
299 * As documented.
301 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
302 (grfMode & STGM_DELETEONRELEASE) ||
303 (grfMode & STGM_TRANSACTED) )
304 return STG_E_INVALIDFUNCTION;
307 * Create a property enumeration to search the properties
309 propertyEnumeration = IEnumSTATSTGImpl_Construct(
310 This->ancestorStorage,
311 This->rootPropertySetIndex);
314 * Search the enumeration for the property with the given name
316 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
317 propertyEnumeration,
318 pwcsName,
319 &currentProperty);
322 * Delete the property enumeration since we don't need it anymore
324 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
327 * If it was found, construct the stream object and return a pointer to it.
329 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
330 (currentProperty.propertyType==PROPTYPE_STREAM) )
332 newStream = StgStreamImpl_Construct(This, foundPropertyIndex);
334 if (newStream!=0)
336 *ppstm = (IStream*)newStream;
339 * Since we are returning a pointer to the interface, we have to
340 * nail down the reference.
342 StgStreamImpl_AddRef(*ppstm);
344 return S_OK;
347 return E_OUTOFMEMORY;
350 return STG_E_FILENOTFOUND;
353 /************************************************************************
354 * Storage32BaseImpl_OpenStorage (IStorage)
356 * This method will open a new storage object from the current storage.
358 * See Windows documentation for more details on IStorage methods.
360 HRESULT WINAPI StorageBaseImpl_OpenStorage(
361 IStorage* iface,
362 const OLECHAR* pwcsName, /* [string][unique][in] */
363 IStorage* pstgPriority, /* [unique][in] */
364 DWORD grfMode, /* [in] */
365 SNB snbExclude, /* [unique][in] */
366 DWORD reserved, /* [in] */
367 IStorage** ppstg) /* [out] */
369 ICOM_THIS(StorageBaseImpl,iface);
370 StorageInternalImpl* newStorage;
371 IEnumSTATSTGImpl* propertyEnumeration;
372 StgProperty currentProperty;
373 ULONG foundPropertyIndex;
376 * Perform a sanity check on the parameters.
378 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
379 return E_INVALIDARG;
382 * Validate the STGM flags
384 if ( FAILED( validateSTGM(grfMode) ))
385 return STG_E_INVALIDFLAG;
388 * As documented.
390 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
391 (grfMode & STGM_DELETEONRELEASE) ||
392 (grfMode & STGM_PRIORITY) )
393 return STG_E_INVALIDFUNCTION;
396 * Initialize the out parameter
398 *ppstg = 0;
401 * Create a property enumeration to search the properties
403 propertyEnumeration = IEnumSTATSTGImpl_Construct(
404 This->ancestorStorage,
405 This->rootPropertySetIndex);
408 * Search the enumeration for the property with the given name
410 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
411 propertyEnumeration,
412 pwcsName,
413 &currentProperty);
416 * Delete the property enumeration since we don't need it anymore
418 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
421 * If it was found, construct the stream object and return a pointer to it.
423 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
424 (currentProperty.propertyType==PROPTYPE_STORAGE) )
427 * Construct a new Storage object
429 newStorage = StorageInternalImpl_Construct(
430 This->ancestorStorage,
431 foundPropertyIndex);
433 if (newStorage != 0)
435 *ppstg = (IStorage*)newStorage;
438 * Since we are returning a pointer to the interface,
439 * we have to nail down the reference.
441 StorageBaseImpl_AddRef(*ppstg);
443 return S_OK;
446 return STG_E_INSUFFICIENTMEMORY;
449 return STG_E_FILENOTFOUND;
452 /************************************************************************
453 * Storage32BaseImpl_EnumElements (IStorage)
455 * This method will create an enumerator object that can be used to
456 * retrieve informatino about all the properties in the storage object.
458 * See Windows documentation for more details on IStorage methods.
460 HRESULT WINAPI StorageBaseImpl_EnumElements(
461 IStorage* iface,
462 DWORD reserved1, /* [in] */
463 void* reserved2, /* [size_is][unique][in] */
464 DWORD reserved3, /* [in] */
465 IEnumSTATSTG** ppenum) /* [out] */
467 ICOM_THIS(StorageBaseImpl,iface);
468 IEnumSTATSTGImpl* newEnum;
471 * Perform a sanity check on the parameters.
473 if ( (This==0) || (ppenum==0))
474 return E_INVALIDARG;
477 * Construct the enumerator.
479 newEnum = IEnumSTATSTGImpl_Construct(
480 This->ancestorStorage,
481 This->rootPropertySetIndex);
483 if (newEnum!=0)
485 *ppenum = (IEnumSTATSTG*)newEnum;
488 * Don't forget to nail down a reference to the new object before
489 * returning it.
491 IEnumSTATSTGImpl_AddRef(*ppenum);
493 return S_OK;
496 return E_OUTOFMEMORY;
499 /************************************************************************
500 * Storage32BaseImpl_Stat (IStorage)
502 * This method will retrieve information about this storage object.
504 * See Windows documentation for more details on IStorage methods.
506 HRESULT WINAPI StorageBaseImpl_Stat(
507 IStorage* iface,
508 STATSTG* pstatstg, /* [out] */
509 DWORD grfStatFlag) /* [in] */
511 ICOM_THIS(StorageBaseImpl,iface);
512 StgProperty curProperty;
513 BOOL readSucessful;
516 * Perform a sanity check on the parameters.
518 if ( (This==0) || (pstatstg==0))
519 return E_INVALIDARG;
522 * Read the information from the property.
524 readSucessful = StorageImpl_ReadProperty(
525 This->ancestorStorage,
526 This->rootPropertySetIndex,
527 &curProperty);
529 if (readSucessful)
531 StorageUtl_CopyPropertyToSTATSTG(
532 pstatstg,
533 &curProperty,
534 grfStatFlag);
536 return S_OK;
539 return E_FAIL;
542 /************************************************************************
543 * Storage32BaseImpl_RenameElement (IStorage)
545 * This method will rename the specified element.
547 * See Windows documentation for more details on IStorage methods.
549 * Implementation notes: The method used to rename consists of creating a clone
550 * of the deleted StgProperty object setting it with the new name and to
551 * perform a DestroyElement of the old StgProperty.
553 HRESULT WINAPI StorageBaseImpl_RenameElement(
554 IStorage* iface,
555 const OLECHAR* pwcsOldName, /* [in] */
556 const OLECHAR* pwcsNewName) /* [in] */
558 ICOM_THIS(StorageBaseImpl,iface);
559 IEnumSTATSTGImpl* propertyEnumeration;
560 StgProperty currentProperty;
561 ULONG foundPropertyIndex;
564 * Create a property enumeration to search the properties
566 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
567 This->rootPropertySetIndex);
570 * Search the enumeration for the new property name
572 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
573 pwcsNewName,
574 &currentProperty);
576 if (foundPropertyIndex != PROPERTY_NULL)
579 * There is already a property with the new name
581 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
582 return STG_E_FILEALREADYEXISTS;
585 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
588 * Search the enumeration for the old property name
590 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
591 pwcsOldName,
592 &currentProperty);
595 * Delete the property enumeration since we don't need it anymore
597 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
599 if (foundPropertyIndex != PROPERTY_NULL)
601 StgProperty renamedProperty;
602 ULONG renamedPropertyIndex;
605 * Setup a new property for the renamed property
607 renamedProperty.sizeOfNameString =
608 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
610 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
611 return STG_E_INVALIDNAME;
613 lstrcpyW(renamedProperty.name, pwcsNewName);
615 renamedProperty.propertyType = currentProperty.propertyType;
616 renamedProperty.startingBlock = currentProperty.startingBlock;
617 renamedProperty.size.LowPart = currentProperty.size.LowPart;
618 renamedProperty.size.HighPart = currentProperty.size.HighPart;
620 renamedProperty.previousProperty = PROPERTY_NULL;
621 renamedProperty.nextProperty = PROPERTY_NULL;
624 * Bring the dirProperty link in case it is a storage and in which
625 * case the renamed storage elements don't require to be reorganized.
627 renamedProperty.dirProperty = currentProperty.dirProperty;
629 /* call CoFileTime to get the current time
630 renamedProperty.timeStampS1
631 renamedProperty.timeStampD1
632 renamedProperty.timeStampS2
633 renamedProperty.timeStampD2
634 renamedProperty.propertyUniqueID
638 * Obtain a free property in the property chain
640 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
643 * Save the new property into the new property spot
645 StorageImpl_WriteProperty(
646 This->ancestorStorage,
647 renamedPropertyIndex,
648 &renamedProperty);
651 * Find a spot in the property chain for our newly created property.
653 updatePropertyChain(
654 (StorageImpl*)This,
655 renamedPropertyIndex,
656 renamedProperty);
659 * At this point the renamed property has been inserted in the tree,
660 * now, before to Destroy the old property we must zeroed it's dirProperty
661 * otherwise the DestroyProperty below will zap it all and we do not want
662 * this to happen.
663 * Also, we fake that the old property is a storage so the DestroyProperty
664 * will not do a SetSize(0) on the stream data.
666 * This means that we need to tweek the StgProperty if it is a stream or a
667 * non empty storage.
669 currentProperty.dirProperty = PROPERTY_NULL;
670 currentProperty.propertyType = PROPTYPE_STORAGE;
671 StorageImpl_WriteProperty(
672 This->ancestorStorage,
673 foundPropertyIndex,
674 &currentProperty);
677 * Invoke Destroy to get rid of the ole property and automatically redo
678 * the linking of it's previous and next members...
680 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
683 else
686 * There is no property with the old name
688 return STG_E_FILENOTFOUND;
691 return S_OK;
694 /************************************************************************
695 * Storage32BaseImpl_CreateStream (IStorage)
697 * This method will create a stream object within this storage
699 * See Windows documentation for more details on IStorage methods.
701 HRESULT WINAPI StorageBaseImpl_CreateStream(
702 IStorage* iface,
703 const OLECHAR* pwcsName, /* [string][in] */
704 DWORD grfMode, /* [in] */
705 DWORD reserved1, /* [in] */
706 DWORD reserved2, /* [in] */
707 IStream** ppstm) /* [out] */
709 ICOM_THIS(StorageBaseImpl,iface);
710 IEnumSTATSTGImpl* propertyEnumeration;
711 StgStreamImpl* newStream;
712 StgProperty currentProperty, newStreamProperty;
713 ULONG foundPropertyIndex, newPropertyIndex;
716 * Validate parameters
718 if (ppstm == 0)
719 return STG_E_INVALIDPOINTER;
721 if (pwcsName == 0)
722 return STG_E_INVALIDNAME;
725 * Validate the STGM flags
727 if ( FAILED( validateSTGM(grfMode) ))
728 return STG_E_INVALIDFLAG;
731 * As documented.
733 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
734 (grfMode & STGM_DELETEONRELEASE) ||
735 (grfMode & STGM_TRANSACTED) )
736 return STG_E_INVALIDFUNCTION;
739 * Initialize the out parameter
741 *ppstm = 0;
744 * Create a property enumeration to search the properties
746 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
747 This->rootPropertySetIndex);
749 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
750 pwcsName,
751 &currentProperty);
753 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
755 if (foundPropertyIndex != PROPERTY_NULL)
758 * An element with this name already exists
760 if (grfMode & STGM_CREATE)
761 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
762 else
763 return STG_E_FILEALREADYEXISTS;
767 * memset the empty property
769 memset(&newStreamProperty, 0, sizeof(StgProperty));
771 newStreamProperty.sizeOfNameString =
772 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
774 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
775 return STG_E_INVALIDNAME;
777 lstrcpyW(newStreamProperty.name, pwcsName);
779 newStreamProperty.propertyType = PROPTYPE_STREAM;
780 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
781 newStreamProperty.size.LowPart = 0;
782 newStreamProperty.size.HighPart = 0;
784 newStreamProperty.previousProperty = PROPERTY_NULL;
785 newStreamProperty.nextProperty = PROPERTY_NULL;
786 newStreamProperty.dirProperty = PROPERTY_NULL;
788 /* call CoFileTime to get the current time
789 newStreamProperty.timeStampS1
790 newStreamProperty.timeStampD1
791 newStreamProperty.timeStampS2
792 newStreamProperty.timeStampD2
795 /* newStreamProperty.propertyUniqueID */
798 * Get a free property or create a new one
800 newPropertyIndex = getFreeProperty(This->ancestorStorage);
803 * Save the new property into the new property spot
805 StorageImpl_WriteProperty(
806 This->ancestorStorage,
807 newPropertyIndex,
808 &newStreamProperty);
811 * Find a spot in the property chain for our newly created property.
813 updatePropertyChain(
814 (StorageImpl*)This,
815 newPropertyIndex,
816 newStreamProperty);
819 * Open the stream to return it.
821 newStream = StgStreamImpl_Construct(This, newPropertyIndex);
823 if (newStream != 0)
825 *ppstm = (IStream*)newStream;
828 * Since we are returning a pointer to the interface, we have to nail down
829 * the reference.
831 StgStreamImpl_AddRef(*ppstm);
833 else
835 return STG_E_INSUFFICIENTMEMORY;
838 return S_OK;
841 /************************************************************************
842 * Storage32BaseImpl_SetClass (IStorage)
844 * This method will write the specified CLSID in the property of this
845 * storage.
847 * See Windows documentation for more details on IStorage methods.
849 HRESULT WINAPI StorageBaseImpl_SetClass(
850 IStorage* iface,
851 REFCLSID clsid) /* [in] */
853 ICOM_THIS(StorageBaseImpl,iface);
854 HRESULT hRes = E_FAIL;
855 StgProperty curProperty;
856 BOOL success;
858 success = StorageImpl_ReadProperty(This->ancestorStorage,
859 This->rootPropertySetIndex,
860 &curProperty);
861 if (success)
863 curProperty.propertyUniqueID = *clsid;
865 success = StorageImpl_WriteProperty(This->ancestorStorage,
866 This->rootPropertySetIndex,
867 &curProperty);
868 if (success)
869 hRes = S_OK;
872 return hRes;
875 /************************************************************************
876 ** Storage32Impl implementation
879 /************************************************************************
880 * Storage32Impl_CreateStorage (IStorage)
882 * This method will create the storage object within the provided storage.
884 * See Windows documentation for more details on IStorage methods.
886 HRESULT WINAPI StorageImpl_CreateStorage(
887 IStorage* iface,
888 const OLECHAR *pwcsName, /* [string][in] */
889 DWORD grfMode, /* [in] */
890 DWORD reserved1, /* [in] */
891 DWORD reserved2, /* [in] */
892 IStorage **ppstg) /* [out] */
894 StorageImpl* const This=(StorageImpl*)iface;
896 IEnumSTATSTGImpl *propertyEnumeration;
897 StgProperty currentProperty;
898 StgProperty newProperty;
899 ULONG foundPropertyIndex;
900 ULONG newPropertyIndex;
901 HRESULT hr;
904 * Validate parameters
906 if (ppstg == 0)
907 return STG_E_INVALIDPOINTER;
909 if (pwcsName == 0)
910 return STG_E_INVALIDNAME;
913 * Validate the STGM flags
915 if ( FAILED( validateSTGM(grfMode) ) ||
916 (grfMode & STGM_DELETEONRELEASE) )
917 return STG_E_INVALIDFLAG;
920 * Initialize the out parameter
922 *ppstg = 0;
925 * Create a property enumeration and search the properties
927 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
928 This->rootPropertySetIndex);
930 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
931 pwcsName,
932 &currentProperty);
933 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
935 if (foundPropertyIndex != PROPERTY_NULL)
938 * An element with this name already exists
940 if (grfMode & STGM_CREATE)
941 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
942 else
943 return STG_E_FILEALREADYEXISTS;
947 * memset the empty property
949 memset(&newProperty, 0, sizeof(StgProperty));
951 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
953 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
954 return STG_E_INVALIDNAME;
956 lstrcpyW(newProperty.name, pwcsName);
958 newProperty.propertyType = PROPTYPE_STORAGE;
959 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
960 newProperty.size.LowPart = 0;
961 newProperty.size.HighPart = 0;
963 newProperty.previousProperty = PROPERTY_NULL;
964 newProperty.nextProperty = PROPERTY_NULL;
965 newProperty.dirProperty = PROPERTY_NULL;
967 /* call CoFileTime to get the current time
968 newProperty.timeStampS1
969 newProperty.timeStampD1
970 newProperty.timeStampS2
971 newProperty.timeStampD2
974 /* newStorageProperty.propertyUniqueID */
977 * Obtain a free property in the property chain
979 newPropertyIndex = getFreeProperty(This->ancestorStorage);
982 * Save the new property into the new property spot
984 StorageImpl_WriteProperty(
985 This->ancestorStorage,
986 newPropertyIndex,
987 &newProperty);
990 * Find a spot in the property chain for our newly created property.
992 updatePropertyChain(
993 This,
994 newPropertyIndex,
995 newProperty);
998 * Open it to get a pointer to return.
1000 hr = StorageBaseImpl_OpenStorage(
1001 iface,
1002 (OLECHAR*)pwcsName,
1004 grfMode,
1007 ppstg);
1009 if( (hr != S_OK) || (*ppstg == NULL))
1011 return hr;
1014 return S_OK;
1018 /***************************************************************************
1020 * Internal Method
1022 * Get a free property or create a new one.
1024 static ULONG getFreeProperty(
1025 StorageImpl *storage)
1027 ULONG currentPropertyIndex = 0;
1028 ULONG newPropertyIndex = PROPERTY_NULL;
1029 BOOL readSucessful = TRUE;
1030 StgProperty currentProperty;
1035 * Start by reading the root property
1037 readSucessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1038 currentPropertyIndex,
1039 &currentProperty);
1040 if (readSucessful)
1042 if (currentProperty.sizeOfNameString == 0)
1045 * The property existis and is available, we found it.
1047 newPropertyIndex = currentPropertyIndex;
1050 else
1053 * We exhausted the property list, we will create more space below
1055 newPropertyIndex = currentPropertyIndex;
1057 currentPropertyIndex++;
1059 } while (newPropertyIndex == PROPERTY_NULL);
1062 * grow the property chain
1064 if (! readSucessful)
1066 StgProperty emptyProperty;
1067 ULARGE_INTEGER newSize;
1068 ULONG propertyIndex;
1069 ULONG lastProperty = 0;
1070 ULONG blockCount = 0;
1073 * obtain the new count of property blocks
1075 blockCount = BlockChainStream_GetCount(
1076 storage->ancestorStorage->rootBlockChain)+1;
1079 * initialize the size used by the property stream
1081 newSize.HighPart = 0;
1082 newSize.LowPart = storage->bigBlockSize * blockCount;
1085 * add a property block to the property chain
1087 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1090 * memset the empty property in order to initialize the unused newly
1091 * created property
1093 memset(&emptyProperty, 0, sizeof(StgProperty));
1096 * initialize them
1098 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1100 for(
1101 propertyIndex = newPropertyIndex;
1102 propertyIndex < lastProperty;
1103 propertyIndex++)
1105 StorageImpl_WriteProperty(
1106 storage->ancestorStorage,
1107 propertyIndex,
1108 &emptyProperty);
1112 return newPropertyIndex;
1115 /****************************************************************************
1117 * Internal Method
1119 * Case insensitive comparaison of StgProperty.name by first considering
1120 * their size.
1122 * Returns <0 when newPrpoerty < currentProperty
1123 * >0 when newPrpoerty > currentProperty
1124 * 0 when newPrpoerty == currentProperty
1126 static LONG propertyNameCmp(
1127 OLECHAR *newProperty,
1128 OLECHAR *currentProperty)
1130 LONG sizeOfNew = (lstrlenW(newProperty) +1) * sizeof(WCHAR);
1131 LONG sizeOfCur = (lstrlenW(currentProperty)+1) * sizeof(WCHAR);
1132 LONG diff = sizeOfNew - sizeOfCur;
1134 if (diff == 0)
1137 * We compare the string themselves only when they are of the same lenght
1139 WCHAR wsnew[PROPERTY_NAME_MAX_LEN];
1140 WCHAR wscur[PROPERTY_NAME_MAX_LEN];
1142 diff = lstrcmpW( (LPCWSTR)CRTDLL__wcsupr(
1143 lstrcpynW(wsnew, newProperty, sizeOfNew)),
1144 (LPCWSTR)CRTDLL__wcsupr(
1145 lstrcpynW(wscur, currentProperty, sizeOfCur)));
1148 return diff;
1151 /****************************************************************************
1153 * Internal Method
1155 * Properly link this new element in the property chain.
1157 static void updatePropertyChain(
1158 StorageImpl *storage,
1159 ULONG newPropertyIndex,
1160 StgProperty newProperty)
1162 StgProperty currentProperty;
1165 * Read the root property
1167 StorageImpl_ReadProperty(storage->ancestorStorage,
1168 storage->rootPropertySetIndex,
1169 &currentProperty);
1171 if (currentProperty.dirProperty != PROPERTY_NULL)
1174 * The root storage contains some element, therefore, start the research
1175 * for the appropriate location.
1177 BOOL found = 0;
1178 ULONG current, next, previous, currentPropertyId;
1181 * Keep the StgProperty sequence number of the storage first property
1183 currentPropertyId = currentProperty.dirProperty;
1186 * Read
1188 StorageImpl_ReadProperty(storage->ancestorStorage,
1189 currentProperty.dirProperty,
1190 &currentProperty);
1192 previous = currentProperty.previousProperty;
1193 next = currentProperty.nextProperty;
1194 current = currentPropertyId;
1196 while (found == 0)
1198 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1200 if (diff < 0)
1202 if (previous != PROPERTY_NULL)
1204 StorageImpl_ReadProperty(storage->ancestorStorage,
1205 previous,
1206 &currentProperty);
1207 current = previous;
1209 else
1211 currentProperty.previousProperty = newPropertyIndex;
1212 StorageImpl_WriteProperty(storage->ancestorStorage,
1213 current,
1214 &currentProperty);
1215 found = 1;
1218 else
1220 if (next != PROPERTY_NULL)
1222 StorageImpl_ReadProperty(storage->ancestorStorage,
1223 next,
1224 &currentProperty);
1225 current = next;
1227 else
1229 currentProperty.nextProperty = newPropertyIndex;
1230 StorageImpl_WriteProperty(storage->ancestorStorage,
1231 current,
1232 &currentProperty);
1233 found = 1;
1237 previous = currentProperty.previousProperty;
1238 next = currentProperty.nextProperty;
1241 else
1244 * The root storage is empty, link the new property to it's dir property
1246 currentProperty.dirProperty = newPropertyIndex;
1247 StorageImpl_WriteProperty(storage->ancestorStorage,
1248 storage->rootPropertySetIndex,
1249 &currentProperty);
1254 /*************************************************************************
1255 * CopyTo (IStorage)
1257 HRESULT WINAPI StorageImpl_CopyTo(
1258 IStorage* iface,
1259 DWORD ciidExclude, /* [in] */
1260 const IID *rgiidExclude,/* [size_is][unique][in] */
1261 SNB snbExclude, /* [unique][in] */
1262 IStorage *pstgDest) /* [unique][in] */
1264 return E_NOTIMPL;
1267 /*************************************************************************
1268 * MoveElementTo (IStorage)
1270 HRESULT WINAPI StorageImpl_MoveElementTo(
1271 IStorage* iface,
1272 const OLECHAR *pwcsName, /* [string][in] */
1273 IStorage *pstgDest, /* [unique][in] */
1274 const OLECHAR *pwcsNewName,/* [string][in] */
1275 DWORD grfFlags) /* [in] */
1277 return E_NOTIMPL;
1280 /*************************************************************************
1281 * Commit (IStorage)
1283 HRESULT WINAPI StorageImpl_Commit(
1284 IStorage* iface,
1285 DWORD grfCommitFlags)/* [in] */
1287 FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1288 return S_OK;
1291 /*************************************************************************
1292 * Revert (IStorage)
1294 HRESULT WINAPI StorageImpl_Revert(
1295 IStorage* iface)
1297 return E_NOTIMPL;
1300 /*************************************************************************
1301 * DestroyElement (IStorage)
1303 * Stategy: This implementation is build this way for simplicity not for speed.
1304 * I always delete the top most element of the enumeration and adjust
1305 * the deleted element pointer all the time. This takes longer to
1306 * do but allow to reinvoke DestroyElement whenever we encounter a
1307 * storage object. The optimisation reside in the usage of another
1308 * enumeration stategy that would give all the leaves of a storage
1309 * first. (postfix order)
1311 HRESULT WINAPI StorageImpl_DestroyElement(
1312 IStorage* iface,
1313 const OLECHAR *pwcsName)/* [string][in] */
1315 StorageImpl* const This=(StorageImpl*)iface;
1317 IEnumSTATSTGImpl* propertyEnumeration;
1318 HRESULT hr = S_OK;
1319 BOOL res;
1320 StgProperty propertyToDelete;
1321 StgProperty parentProperty;
1322 ULONG foundPropertyIndexToDelete;
1323 ULONG typeOfRelation;
1324 ULONG parentPropertyId;
1327 * Perform a sanity check on the parameters.
1329 if (pwcsName==NULL)
1330 return STG_E_INVALIDPOINTER;
1333 * Create a property enumeration to search the property with the given name
1335 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1336 This->ancestorStorage,
1337 This->rootPropertySetIndex);
1339 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1340 propertyEnumeration,
1341 pwcsName,
1342 &propertyToDelete);
1344 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1346 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1348 return STG_E_FILENOTFOUND;
1352 * Find the parent property of the property to delete (the one that
1353 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1354 * the parent is This. Otherwise, the parent is one of it's sibling...
1358 * First, read This's StgProperty..
1360 res = StorageImpl_ReadProperty(
1361 This->ancestorStorage,
1362 This->rootPropertySetIndex,
1363 &parentProperty);
1365 assert(res==TRUE);
1368 * Second, check to see if by any chance the actual storage (This) is not
1369 * the parent of the property to delete... We never know...
1371 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1374 * Set data as it would have been done in the else part...
1376 typeOfRelation = PROPERTY_RELATION_DIR;
1377 parentPropertyId = This->rootPropertySetIndex;
1379 else
1382 * Create a property enumeration to search the parent properties, and
1383 * delete it once done.
1385 IEnumSTATSTGImpl* propertyEnumeration2;
1387 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1388 This->ancestorStorage,
1389 This->rootPropertySetIndex);
1391 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1392 propertyEnumeration2,
1393 foundPropertyIndexToDelete,
1394 &parentProperty,
1395 &parentPropertyId);
1397 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1400 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1402 hr = deleteStorageProperty(
1403 This,
1404 propertyToDelete.name);
1406 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1408 hr = deleteStreamProperty(
1409 This,
1410 foundPropertyIndexToDelete,
1411 propertyToDelete);
1414 if (hr!=S_OK)
1415 return hr;
1418 * Adjust the property chain
1420 hr = adjustPropertyChain(
1421 This,
1422 propertyToDelete,
1423 parentProperty,
1424 parentPropertyId,
1425 typeOfRelation);
1427 return hr;
1431 /*********************************************************************
1433 * Internal Method
1435 * Perform the deletion of a complete storage node
1438 static HRESULT deleteStorageProperty(
1439 StorageImpl *parentStorage,
1440 OLECHAR *propertyToDeleteName)
1442 IEnumSTATSTG *elements = 0;
1443 IStorage *childStorage = 0;
1444 STATSTG currentElement;
1445 HRESULT hr;
1446 HRESULT destroyHr = S_OK;
1449 * Open the storage and enumerate it
1451 hr = StorageBaseImpl_OpenStorage(
1452 (IStorage*)parentStorage,
1453 propertyToDeleteName,
1455 STGM_SHARE_EXCLUSIVE,
1458 &childStorage);
1460 if (hr != S_OK)
1462 return hr;
1466 * Enumerate the elements
1468 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1473 * Obtain the next element
1475 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1476 if (hr==S_OK)
1478 destroyHr = StorageImpl_DestroyElement(
1479 (IStorage*)childStorage,
1480 (OLECHAR*)currentElement.pwcsName);
1482 CoTaskMemFree(currentElement.pwcsName);
1486 * We need to Reset the enumeration every time because we delete elements
1487 * and the enumeration could be invalid
1489 IEnumSTATSTG_Reset(elements);
1491 } while ((hr == S_OK) && (destroyHr == S_OK));
1493 IStorage_Release(childStorage);
1494 IEnumSTATSTG_Release(elements);
1496 return destroyHr;
1499 /*********************************************************************
1501 * Internal Method
1503 * Perform the deletion of a stream node
1506 static HRESULT deleteStreamProperty(
1507 StorageImpl *parentStorage,
1508 ULONG indexOfPropertyToDelete,
1509 StgProperty propertyToDelete)
1511 IStream *pis;
1512 HRESULT hr;
1513 ULARGE_INTEGER size;
1515 size.HighPart = 0;
1516 size.LowPart = 0;
1518 hr = StorageBaseImpl_OpenStream(
1519 (IStorage*)parentStorage,
1520 (OLECHAR*)propertyToDelete.name,
1521 NULL,
1522 STGM_SHARE_EXCLUSIVE,
1524 &pis);
1526 if (hr!=S_OK)
1528 return(hr);
1532 * Zap the stream
1534 hr = IStream_SetSize(pis, size);
1536 if(hr != S_OK)
1538 return hr;
1542 * Invalidate the property by zeroing it's name member.
1544 propertyToDelete.sizeOfNameString = 0;
1547 * Here we should re-read the property so we get the updated pointer
1548 * but since we are here to zap it, I don't do it...
1551 StorageImpl_WriteProperty(
1552 parentStorage->ancestorStorage,
1553 indexOfPropertyToDelete,
1554 &propertyToDelete);
1556 return S_OK;
1559 /*********************************************************************
1561 * Internal Method
1563 * Finds a placeholder for the StgProperty within the Storage
1566 static HRESULT findPlaceholder(
1567 StorageImpl *storage,
1568 ULONG propertyIndexToStore,
1569 ULONG storePropertyIndex,
1570 INT typeOfRelation)
1572 StgProperty storeProperty;
1573 HRESULT hr = S_OK;
1574 BOOL res = TRUE;
1577 * Read the storage property
1579 res = StorageImpl_ReadProperty(
1580 storage->ancestorStorage,
1581 storePropertyIndex,
1582 &storeProperty);
1584 if(! res)
1586 return E_FAIL;
1589 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1591 if (storeProperty.previousProperty != PROPERTY_NULL)
1593 return findPlaceholder(
1594 storage,
1595 propertyIndexToStore,
1596 storeProperty.previousProperty,
1597 typeOfRelation);
1599 else
1601 storeProperty.previousProperty = propertyIndexToStore;
1604 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1606 if (storeProperty.nextProperty != PROPERTY_NULL)
1608 return findPlaceholder(
1609 storage,
1610 propertyIndexToStore,
1611 storeProperty.nextProperty,
1612 typeOfRelation);
1614 else
1616 storeProperty.nextProperty = propertyIndexToStore;
1619 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1621 if (storeProperty.dirProperty != PROPERTY_NULL)
1623 return findPlaceholder(
1624 storage,
1625 propertyIndexToStore,
1626 storeProperty.dirProperty,
1627 typeOfRelation);
1629 else
1631 storeProperty.dirProperty = propertyIndexToStore;
1635 hr = StorageImpl_WriteProperty(
1636 storage->ancestorStorage,
1637 storePropertyIndex,
1638 &storeProperty);
1640 if(! hr)
1642 return E_FAIL;
1645 return S_OK;
1648 /*************************************************************************
1650 * Internal Method
1652 * This method takes the previous and the next property link of a property
1653 * to be deleted and find them a place in the Storage.
1655 static HRESULT adjustPropertyChain(
1656 StorageImpl *This,
1657 StgProperty propertyToDelete,
1658 StgProperty parentProperty,
1659 ULONG parentPropertyId,
1660 INT typeOfRelation)
1662 ULONG newLinkProperty = PROPERTY_NULL;
1663 BOOL needToFindAPlaceholder = FALSE;
1664 ULONG storeNode = PROPERTY_NULL;
1665 ULONG toStoreNode = PROPERTY_NULL;
1666 INT relationType = 0;
1667 HRESULT hr = S_OK;
1668 BOOL res = TRUE;
1670 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1672 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1675 * Set the parent previous to the property to delete previous
1677 newLinkProperty = propertyToDelete.previousProperty;
1679 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1682 * We also need to find a storage for the other link, setup variables
1683 * to do this at the end...
1685 needToFindAPlaceholder = TRUE;
1686 storeNode = propertyToDelete.previousProperty;
1687 toStoreNode = propertyToDelete.nextProperty;
1688 relationType = PROPERTY_RELATION_NEXT;
1691 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1694 * Set the parent previous to the property to delete next
1696 newLinkProperty = propertyToDelete.nextProperty;
1700 * Link it for real...
1702 parentProperty.previousProperty = newLinkProperty;
1705 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1707 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1710 * Set the parent next to the property to delete next previous
1712 newLinkProperty = propertyToDelete.previousProperty;
1714 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1717 * We also need to find a storage for the other link, setup variables
1718 * to do this at the end...
1720 needToFindAPlaceholder = TRUE;
1721 storeNode = propertyToDelete.previousProperty;
1722 toStoreNode = propertyToDelete.nextProperty;
1723 relationType = PROPERTY_RELATION_NEXT;
1726 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1729 * Set the parent next to the property to delete next
1731 newLinkProperty = propertyToDelete.nextProperty;
1735 * Link it for real...
1737 parentProperty.nextProperty = newLinkProperty;
1739 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1741 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1744 * Set the parent dir to the property to delete previous
1746 newLinkProperty = propertyToDelete.previousProperty;
1748 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1751 * We also need to find a storage for the other link, setup variables
1752 * to do this at the end...
1754 needToFindAPlaceholder = TRUE;
1755 storeNode = propertyToDelete.previousProperty;
1756 toStoreNode = propertyToDelete.nextProperty;
1757 relationType = PROPERTY_RELATION_NEXT;
1760 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1763 * Set the parent dir to the property to delete next
1765 newLinkProperty = propertyToDelete.nextProperty;
1769 * Link it for real...
1771 parentProperty.dirProperty = newLinkProperty;
1775 * Write back the parent property
1777 res = StorageImpl_WriteProperty(
1778 This->ancestorStorage,
1779 parentPropertyId,
1780 &parentProperty);
1781 if(! res)
1783 return E_FAIL;
1787 * If a placeholder is required for the other link, then, find one and
1788 * get out of here...
1790 if (needToFindAPlaceholder)
1792 hr = findPlaceholder(
1793 This,
1794 toStoreNode,
1795 storeNode,
1796 relationType);
1799 return hr;
1803 /******************************************************************************
1804 * SetElementTimes (IStorage)
1806 HRESULT WINAPI StorageImpl_SetElementTimes(
1807 IStorage* iface,
1808 const OLECHAR *pwcsName,/* [string][in] */
1809 const FILETIME *pctime, /* [in] */
1810 const FILETIME *patime, /* [in] */
1811 const FILETIME *pmtime) /* [in] */
1813 return E_NOTIMPL;
1816 /******************************************************************************
1817 * SetStateBits (IStorage)
1819 HRESULT WINAPI StorageImpl_SetStateBits(
1820 IStorage* iface,
1821 DWORD grfStateBits,/* [in] */
1822 DWORD grfMask) /* [in] */
1824 return E_NOTIMPL;
1827 HRESULT StorageImpl_Construct(
1828 StorageImpl* This,
1829 HANDLE hFile,
1830 DWORD openFlags)
1832 HRESULT hr = S_OK;
1833 StgProperty currentProperty;
1834 BOOL readSucessful;
1835 ULONG currentPropertyIndex;
1837 if ( FAILED( validateSTGM(openFlags) ))
1838 return STG_E_INVALIDFLAG;
1840 memset(This, 0, sizeof(StorageImpl));
1843 * Initialize the virtual fgunction table.
1845 This->lpvtbl = &Storage32Impl_Vtbl;
1846 This->v_destructor = &StorageImpl_Destroy;
1849 * This is the top-level storage so initialize the ancester pointer
1850 * to this.
1852 This->ancestorStorage = This;
1855 * Initialize the physical support of the storage.
1857 This->hFile = hFile;
1860 * Initialize the big block cache.
1862 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
1863 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
1864 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
1865 openFlags,
1866 This->bigBlockSize);
1868 if (This->bigBlockFile == 0)
1869 return E_FAIL;
1871 if (openFlags & STGM_CREATE)
1873 ULARGE_INTEGER size;
1874 BYTE* bigBlockBuffer;
1877 * Initialize all header variables:
1878 * - The big block depot consists of one block and it is at block 0
1879 * - The properties start at block 1
1880 * - There is no small block depot
1882 memset( This->bigBlockDepotStart,
1883 BLOCK_UNUSED,
1884 sizeof(This->bigBlockDepotStart));
1886 This->bigBlockDepotCount = 1;
1887 This->bigBlockDepotStart[0] = 0;
1888 This->rootStartBlock = 1;
1889 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
1890 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
1891 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
1892 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
1893 This->extBigBlockDepotCount = 0;
1895 StorageImpl_SaveFileHeader(This);
1898 * Add one block for the big block depot and one block for the properties
1900 size.HighPart = 0;
1901 size.LowPart = This->bigBlockSize * 3;
1902 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
1905 * Initialize the big block depot
1907 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
1908 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
1909 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
1910 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
1911 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
1913 else
1916 * Load the header for the file.
1918 hr = StorageImpl_LoadFileHeader(This);
1920 if (FAILED(hr))
1922 BIGBLOCKFILE_Destructor(This->bigBlockFile);
1924 return hr;
1929 * There is no block depot cached yet.
1931 This->indexBlockDepotCached = 0xFFFFFFFF;
1934 * Start searching for free blocks with block 0.
1936 This->prevFreeBlock = 0;
1939 * Create the block chain abstractions.
1941 This->rootBlockChain =
1942 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1944 This->smallBlockDepotChain = BlockChainStream_Construct(
1945 This,
1946 &This->smallBlockDepotStart,
1947 PROPERTY_NULL);
1950 * Write the root property
1952 if (openFlags & STGM_CREATE)
1954 StgProperty rootProp;
1956 * Initialize the property chain
1958 memset(&rootProp, 0, sizeof(rootProp));
1959 lstrcpyAtoW(rootProp.name, rootPropertyName);
1961 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
1962 rootProp.propertyType = PROPTYPE_ROOT;
1963 rootProp.previousProperty = PROPERTY_NULL;
1964 rootProp.nextProperty = PROPERTY_NULL;
1965 rootProp.dirProperty = PROPERTY_NULL;
1966 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
1967 rootProp.size.HighPart = 0;
1968 rootProp.size.LowPart = 0;
1970 StorageImpl_WriteProperty(This, 0, &rootProp);
1974 * Find the ID of the root int he property sets.
1976 currentPropertyIndex = 0;
1980 readSucessful = StorageImpl_ReadProperty(
1981 This,
1982 currentPropertyIndex,
1983 &currentProperty);
1985 if (readSucessful)
1987 if ( (currentProperty.sizeOfNameString != 0 ) &&
1988 (currentProperty.propertyType == PROPTYPE_ROOT) )
1990 This->rootPropertySetIndex = currentPropertyIndex;
1994 currentPropertyIndex++;
1996 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1998 if (!readSucessful)
2000 /* TODO CLEANUP */
2001 return E_FAIL;
2005 * Create the block chain abstraction for the small block root chain.
2007 This->smallBlockRootChain = BlockChainStream_Construct(
2008 This,
2009 NULL,
2010 This->rootPropertySetIndex);
2012 return hr;
2015 void StorageImpl_Destroy(
2016 StorageImpl* This)
2018 BlockChainStream_Destroy(This->smallBlockRootChain);
2019 BlockChainStream_Destroy(This->rootBlockChain);
2020 BlockChainStream_Destroy(This->smallBlockDepotChain);
2022 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2023 return;
2026 /******************************************************************************
2027 * Storage32Impl_GetNextFreeBigBlock
2029 * Returns the index of the next free big block.
2030 * If the big block depot is filled, this method will enlarge it.
2033 ULONG StorageImpl_GetNextFreeBigBlock(
2034 StorageImpl* This)
2036 ULONG depotBlockIndexPos;
2037 void *depotBuffer;
2038 ULONG depotBlockOffset;
2039 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2040 ULONG nextBlockIndex = BLOCK_SPECIAL;
2041 int depotIndex = 0;
2042 ULONG freeBlock = BLOCK_UNUSED;
2044 depotIndex = This->prevFreeBlock / blocksPerDepot;
2045 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2048 * Scan the entire big block depot until we find a block marked free
2050 while (nextBlockIndex != BLOCK_UNUSED)
2052 if (depotIndex < COUNT_BBDEPOTINHEADER)
2054 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2057 * Grow the primary depot.
2059 if (depotBlockIndexPos == BLOCK_UNUSED)
2061 depotBlockIndexPos = depotIndex*blocksPerDepot;
2064 * Add a block depot.
2066 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2067 This->bigBlockDepotCount++;
2068 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2071 * Flag it as a block depot.
2073 StorageImpl_SetNextBlockInChain(This,
2074 depotBlockIndexPos,
2075 BLOCK_SPECIAL);
2077 /* Save new header information.
2079 StorageImpl_SaveFileHeader(This);
2082 else
2084 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2086 if (depotBlockIndexPos == BLOCK_UNUSED)
2089 * Grow the extended depot.
2091 ULONG extIndex = BLOCK_UNUSED;
2092 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2093 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2095 if (extBlockOffset == 0)
2097 /* We need an extended block.
2099 extIndex = Storage32Impl_AddExtBlockDepot(This);
2100 This->extBigBlockDepotCount++;
2101 depotBlockIndexPos = extIndex + 1;
2103 else
2104 depotBlockIndexPos = depotIndex * blocksPerDepot;
2107 * Add a block depot and mark it in the extended block.
2109 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2110 This->bigBlockDepotCount++;
2111 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2113 /* Flag the block depot.
2115 StorageImpl_SetNextBlockInChain(This,
2116 depotBlockIndexPos,
2117 BLOCK_SPECIAL);
2119 /* If necessary, flag the extended depot block.
2121 if (extIndex != BLOCK_UNUSED)
2122 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2124 /* Save header information.
2126 StorageImpl_SaveFileHeader(This);
2130 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2132 if (depotBuffer != 0)
2134 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2135 ( nextBlockIndex != BLOCK_UNUSED))
2137 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2139 if (nextBlockIndex == BLOCK_UNUSED)
2141 freeBlock = (depotIndex * blocksPerDepot) +
2142 (depotBlockOffset/sizeof(ULONG));
2145 depotBlockOffset += sizeof(ULONG);
2148 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2151 depotIndex++;
2152 depotBlockOffset = 0;
2155 This->prevFreeBlock = freeBlock;
2157 return freeBlock;
2160 /******************************************************************************
2161 * Storage32Impl_AddBlockDepot
2163 * This will create a depot block, essentially it is a block initialized
2164 * to BLOCK_UNUSEDs.
2166 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2168 BYTE* blockBuffer;
2170 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2173 * Initialize blocks as free
2175 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2177 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2180 /******************************************************************************
2181 * Storage32Impl_GetExtDepotBlock
2183 * Returns the index of the block that corresponds to the specified depot
2184 * index. This method is only for depot indexes equal or greater than
2185 * COUNT_BBDEPOTINHEADER.
2187 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2189 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2190 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2191 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2192 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2193 ULONG blockIndex = BLOCK_UNUSED;
2194 ULONG extBlockIndex = This->extBigBlockDepotStart;
2196 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2198 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2199 return BLOCK_UNUSED;
2201 while (extBlockCount > 0)
2203 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2204 extBlockCount--;
2207 if (extBlockIndex != BLOCK_UNUSED)
2209 BYTE* depotBuffer;
2211 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2213 if (depotBuffer != 0)
2215 StorageUtl_ReadDWord(depotBuffer,
2216 extBlockOffset * sizeof(ULONG),
2217 &blockIndex);
2219 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2223 return blockIndex;
2226 /******************************************************************************
2227 * Storage32Impl_SetExtDepotBlock
2229 * Associates the specified block index to the specified depot index.
2230 * This method is only for depot indexes equal or greater than
2231 * COUNT_BBDEPOTINHEADER.
2233 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2234 ULONG depotIndex,
2235 ULONG blockIndex)
2237 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2238 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2239 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2240 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2241 ULONG extBlockIndex = This->extBigBlockDepotStart;
2243 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2245 while (extBlockCount > 0)
2247 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2248 extBlockCount--;
2251 if (extBlockIndex != BLOCK_UNUSED)
2253 BYTE* depotBuffer;
2255 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2257 if (depotBuffer != 0)
2259 StorageUtl_WriteDWord(depotBuffer,
2260 extBlockOffset * sizeof(ULONG),
2261 blockIndex);
2263 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2268 /******************************************************************************
2269 * Storage32Impl_AddExtBlockDepot
2271 * Creates an extended depot block.
2273 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2275 ULONG numExtBlocks = This->extBigBlockDepotCount;
2276 ULONG nextExtBlock = This->extBigBlockDepotStart;
2277 BYTE* depotBuffer = NULL;
2278 ULONG index = BLOCK_UNUSED;
2279 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2280 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2281 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2283 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2284 blocksPerDepotBlock;
2286 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2289 * The first extended block.
2291 This->extBigBlockDepotStart = index;
2293 else
2295 int i;
2297 * Follow the chain to the last one.
2299 for (i = 0; i < (numExtBlocks - 1); i++)
2301 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2305 * Add the new extended block to the chain.
2307 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2308 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2309 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2313 * Initialize this block.
2315 depotBuffer = StorageImpl_GetBigBlock(This, index);
2316 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2317 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2319 return index;
2322 /******************************************************************************
2323 * Storage32Impl_FreeBigBlock
2325 * This method will flag the specified block as free in the big block depot.
2327 void StorageImpl_FreeBigBlock(
2328 StorageImpl* This,
2329 ULONG blockIndex)
2331 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2333 if (blockIndex < This->prevFreeBlock)
2334 This->prevFreeBlock = blockIndex;
2337 /************************************************************************
2338 * Storage32Impl_GetNextBlockInChain
2340 * This method will retrieve the block index of the next big block in
2341 * in the chain.
2343 * Params: This - Pointer to the Storage object.
2344 * blockIndex - Index of the block to retrieve the chain
2345 * for.
2347 * Returns: This method returns the index of the next block in the chain.
2348 * It will return the constants:
2349 * BLOCK_SPECIAL - If the block given was not part of a
2350 * chain.
2351 * BLOCK_END_OF_CHAIN - If the block given was the last in
2352 * a chain.
2353 * BLOCK_UNUSED - If the block given was not past of a chain
2354 * and is available.
2355 * BLOCK_EXTBBDEPOT - This block is part of the extended
2356 * big block depot.
2358 * See Windows documentation for more details on IStorage methods.
2360 ULONG StorageImpl_GetNextBlockInChain(
2361 StorageImpl* This,
2362 ULONG blockIndex)
2364 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2365 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2366 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2367 ULONG nextBlockIndex = BLOCK_SPECIAL;
2368 void* depotBuffer;
2369 ULONG depotBlockIndexPos;
2371 assert(depotBlockCount < This->bigBlockDepotCount);
2374 * Cache the currently accessed depot block.
2376 if (depotBlockCount != This->indexBlockDepotCached)
2378 This->indexBlockDepotCached = depotBlockCount;
2380 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2382 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2384 else
2387 * We have to look in the extended depot.
2389 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2392 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2394 if (depotBuffer!=0)
2396 int index;
2398 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2400 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2401 This->blockDepotCached[index] = nextBlockIndex;
2404 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2408 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2410 return nextBlockIndex;
2413 /******************************************************************************
2414 * Storage32Impl_GetNextExtendedBlock
2416 * Given an extended block this method will return the next extended block.
2418 * NOTES:
2419 * The last ULONG of an extended block is the block index of the next
2420 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2421 * depot.
2423 * Return values:
2424 * - The index of the next extended block
2425 * - BLOCK_UNUSED: there is no next extended block.
2426 * - Any other return values denotes failure.
2428 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2430 ULONG nextBlockIndex = BLOCK_SPECIAL;
2431 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2432 void* depotBuffer;
2434 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2436 if (depotBuffer!=0)
2438 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2440 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2443 return nextBlockIndex;
2446 /******************************************************************************
2447 * Storage32Impl_SetNextBlockInChain
2449 * This method will write the index of the specified block's next block
2450 * in the big block depot.
2452 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2453 * do the following
2455 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2456 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2457 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2460 void StorageImpl_SetNextBlockInChain(
2461 StorageImpl* This,
2462 ULONG blockIndex,
2463 ULONG nextBlock)
2465 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2466 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2467 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2468 ULONG depotBlockIndexPos;
2469 void* depotBuffer;
2471 assert(depotBlockCount < This->bigBlockDepotCount);
2472 assert(blockIndex != nextBlock);
2474 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2476 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2478 else
2481 * We have to look in the extended depot.
2483 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2486 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2488 if (depotBuffer!=0)
2490 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2491 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2495 * Update the cached block depot, if necessary.
2497 if (depotBlockCount == This->indexBlockDepotCached)
2499 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2503 /******************************************************************************
2504 * Storage32Impl_LoadFileHeader
2506 * This method will read in the file header, i.e. big block index -1.
2508 HRESULT StorageImpl_LoadFileHeader(
2509 StorageImpl* This)
2511 HRESULT hr = STG_E_FILENOTFOUND;
2512 void* headerBigBlock = NULL;
2513 int index;
2516 * Get a pointer to the big block of data containing the header.
2518 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2521 * Extract the information from the header.
2523 if (headerBigBlock!=0)
2526 * Check for the "magic number" signature and return an error if it is not
2527 * found.
2529 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2531 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2532 return STG_E_OLDFORMAT;
2535 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2537 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2538 return STG_E_INVALIDHEADER;
2541 StorageUtl_ReadWord(
2542 headerBigBlock,
2543 OFFSET_BIGBLOCKSIZEBITS,
2544 &This->bigBlockSizeBits);
2546 StorageUtl_ReadWord(
2547 headerBigBlock,
2548 OFFSET_SMALLBLOCKSIZEBITS,
2549 &This->smallBlockSizeBits);
2551 StorageUtl_ReadDWord(
2552 headerBigBlock,
2553 OFFSET_BBDEPOTCOUNT,
2554 &This->bigBlockDepotCount);
2556 StorageUtl_ReadDWord(
2557 headerBigBlock,
2558 OFFSET_ROOTSTARTBLOCK,
2559 &This->rootStartBlock);
2561 StorageUtl_ReadDWord(
2562 headerBigBlock,
2563 OFFSET_SBDEPOTSTART,
2564 &This->smallBlockDepotStart);
2566 StorageUtl_ReadDWord(
2567 headerBigBlock,
2568 OFFSET_EXTBBDEPOTSTART,
2569 &This->extBigBlockDepotStart);
2571 StorageUtl_ReadDWord(
2572 headerBigBlock,
2573 OFFSET_EXTBBDEPOTCOUNT,
2574 &This->extBigBlockDepotCount);
2576 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2578 StorageUtl_ReadDWord(
2579 headerBigBlock,
2580 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2581 &(This->bigBlockDepotStart[index]));
2585 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2587 if ((1 << 2) == 4)
2589 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2590 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2592 else
2594 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2595 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2599 * Right now, the code is making some assumptions about the size of the
2600 * blocks, just make sure they are what we're expecting.
2602 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2603 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2606 * Release the block.
2608 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2610 hr = S_OK;
2613 return hr;
2616 /******************************************************************************
2617 * Storage32Impl_SaveFileHeader
2619 * This method will save to the file the header, i.e. big block -1.
2621 void StorageImpl_SaveFileHeader(
2622 StorageImpl* This)
2624 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2625 int index;
2626 BOOL success;
2629 * Get a pointer to the big block of data containing the header.
2631 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2634 * If the block read failed, the file is probably new.
2636 if (!success)
2639 * Initialize for all unknown fields.
2641 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2644 * Initialize the magic number.
2646 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2649 * And a bunch of things we don't know what they mean
2651 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2652 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2653 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2654 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2655 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2659 * Write the information to the header.
2661 if (headerBigBlock!=0)
2663 StorageUtl_WriteWord(
2664 headerBigBlock,
2665 OFFSET_BIGBLOCKSIZEBITS,
2666 This->bigBlockSizeBits);
2668 StorageUtl_WriteWord(
2669 headerBigBlock,
2670 OFFSET_SMALLBLOCKSIZEBITS,
2671 This->smallBlockSizeBits);
2673 StorageUtl_WriteDWord(
2674 headerBigBlock,
2675 OFFSET_BBDEPOTCOUNT,
2676 This->bigBlockDepotCount);
2678 StorageUtl_WriteDWord(
2679 headerBigBlock,
2680 OFFSET_ROOTSTARTBLOCK,
2681 This->rootStartBlock);
2683 StorageUtl_WriteDWord(
2684 headerBigBlock,
2685 OFFSET_SBDEPOTSTART,
2686 This->smallBlockDepotStart);
2688 StorageUtl_WriteDWord(
2689 headerBigBlock,
2690 OFFSET_EXTBBDEPOTSTART,
2691 This->extBigBlockDepotStart);
2693 StorageUtl_WriteDWord(
2694 headerBigBlock,
2695 OFFSET_EXTBBDEPOTCOUNT,
2696 This->extBigBlockDepotCount);
2698 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2700 StorageUtl_WriteDWord(
2701 headerBigBlock,
2702 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2703 (This->bigBlockDepotStart[index]));
2708 * Write the big block back to the file.
2710 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2713 /******************************************************************************
2714 * Storage32Impl_ReadProperty
2716 * This method will read the specified property from the property chain.
2718 BOOL StorageImpl_ReadProperty(
2719 StorageImpl* This,
2720 ULONG index,
2721 StgProperty* buffer)
2723 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2724 ULARGE_INTEGER offsetInPropSet;
2725 BOOL readSucessful;
2726 ULONG bytesRead;
2728 offsetInPropSet.HighPart = 0;
2729 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2731 readSucessful = BlockChainStream_ReadAt(
2732 This->rootBlockChain,
2733 offsetInPropSet,
2734 PROPSET_BLOCK_SIZE,
2735 currentProperty,
2736 &bytesRead);
2738 if (readSucessful)
2740 memset(buffer->name, 0, sizeof(buffer->name));
2741 memcpy(
2742 buffer->name,
2743 currentProperty+OFFSET_PS_NAME,
2744 PROPERTY_NAME_BUFFER_LEN );
2746 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2748 StorageUtl_ReadWord(
2749 currentProperty,
2750 OFFSET_PS_NAMELENGTH,
2751 &buffer->sizeOfNameString);
2753 StorageUtl_ReadDWord(
2754 currentProperty,
2755 OFFSET_PS_PREVIOUSPROP,
2756 &buffer->previousProperty);
2758 StorageUtl_ReadDWord(
2759 currentProperty,
2760 OFFSET_PS_NEXTPROP,
2761 &buffer->nextProperty);
2763 StorageUtl_ReadDWord(
2764 currentProperty,
2765 OFFSET_PS_DIRPROP,
2766 &buffer->dirProperty);
2768 StorageUtl_ReadGUID(
2769 currentProperty,
2770 OFFSET_PS_GUID,
2771 &buffer->propertyUniqueID);
2773 StorageUtl_ReadDWord(
2774 currentProperty,
2775 OFFSET_PS_TSS1,
2776 &buffer->timeStampS1);
2778 StorageUtl_ReadDWord(
2779 currentProperty,
2780 OFFSET_PS_TSD1,
2781 &buffer->timeStampD1);
2783 StorageUtl_ReadDWord(
2784 currentProperty,
2785 OFFSET_PS_TSS2,
2786 &buffer->timeStampS2);
2788 StorageUtl_ReadDWord(
2789 currentProperty,
2790 OFFSET_PS_TSD2,
2791 &buffer->timeStampD2);
2793 StorageUtl_ReadDWord(
2794 currentProperty,
2795 OFFSET_PS_STARTBLOCK,
2796 &buffer->startingBlock);
2798 StorageUtl_ReadDWord(
2799 currentProperty,
2800 OFFSET_PS_SIZE,
2801 &buffer->size.LowPart);
2803 buffer->size.HighPart = 0;
2806 return readSucessful;
2809 /*********************************************************************
2810 * Write the specified property into the property chain
2812 BOOL StorageImpl_WriteProperty(
2813 StorageImpl* This,
2814 ULONG index,
2815 StgProperty* buffer)
2817 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2818 ULARGE_INTEGER offsetInPropSet;
2819 BOOL writeSucessful;
2820 ULONG bytesWritten;
2822 offsetInPropSet.HighPart = 0;
2823 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2825 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2827 memcpy(
2828 currentProperty + OFFSET_PS_NAME,
2829 buffer->name,
2830 PROPERTY_NAME_BUFFER_LEN );
2832 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2835 * Reassign the size in case of mistake....
2837 buffer->sizeOfNameString = (lstrlenW(buffer->name)+1) * sizeof(WCHAR);
2839 StorageUtl_WriteWord(
2840 currentProperty,
2841 OFFSET_PS_NAMELENGTH,
2842 buffer->sizeOfNameString);
2844 StorageUtl_WriteDWord(
2845 currentProperty,
2846 OFFSET_PS_PREVIOUSPROP,
2847 buffer->previousProperty);
2849 StorageUtl_WriteDWord(
2850 currentProperty,
2851 OFFSET_PS_NEXTPROP,
2852 buffer->nextProperty);
2854 StorageUtl_WriteDWord(
2855 currentProperty,
2856 OFFSET_PS_DIRPROP,
2857 buffer->dirProperty);
2859 StorageUtl_WriteGUID(
2860 currentProperty,
2861 OFFSET_PS_GUID,
2862 &buffer->propertyUniqueID);
2864 StorageUtl_WriteDWord(
2865 currentProperty,
2866 OFFSET_PS_TSS1,
2867 buffer->timeStampS1);
2869 StorageUtl_WriteDWord(
2870 currentProperty,
2871 OFFSET_PS_TSD1,
2872 buffer->timeStampD1);
2874 StorageUtl_WriteDWord(
2875 currentProperty,
2876 OFFSET_PS_TSS2,
2877 buffer->timeStampS2);
2879 StorageUtl_WriteDWord(
2880 currentProperty,
2881 OFFSET_PS_TSD2,
2882 buffer->timeStampD2);
2884 StorageUtl_WriteDWord(
2885 currentProperty,
2886 OFFSET_PS_STARTBLOCK,
2887 buffer->startingBlock);
2889 StorageUtl_WriteDWord(
2890 currentProperty,
2891 OFFSET_PS_SIZE,
2892 buffer->size.LowPart);
2894 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2895 offsetInPropSet,
2896 PROPSET_BLOCK_SIZE,
2897 currentProperty,
2898 &bytesWritten);
2899 return writeSucessful;
2902 BOOL StorageImpl_ReadBigBlock(
2903 StorageImpl* This,
2904 ULONG blockIndex,
2905 void* buffer)
2907 void* bigBlockBuffer;
2909 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2911 if (bigBlockBuffer!=0)
2913 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2915 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2917 return TRUE;
2920 return FALSE;
2923 BOOL StorageImpl_WriteBigBlock(
2924 StorageImpl* This,
2925 ULONG blockIndex,
2926 void* buffer)
2928 void* bigBlockBuffer;
2930 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2932 if (bigBlockBuffer!=0)
2934 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2936 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2938 return TRUE;
2941 return FALSE;
2944 void* StorageImpl_GetROBigBlock(
2945 StorageImpl* This,
2946 ULONG blockIndex)
2948 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2951 void* StorageImpl_GetBigBlock(
2952 StorageImpl* This,
2953 ULONG blockIndex)
2955 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2958 void StorageImpl_ReleaseBigBlock(
2959 StorageImpl* This,
2960 void* pBigBlock)
2962 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2965 /******************************************************************************
2966 * Storage32Impl_SmallBlocksToBigBlocks
2968 * This method will convert a small block chain to a big block chain.
2969 * The small block chain will be destroyed.
2971 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2972 StorageImpl* This,
2973 SmallBlockChainStream** ppsbChain)
2975 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2976 ULARGE_INTEGER size, offset;
2977 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
2978 ULONG propertyIndex;
2979 BOOL successRead, successWrite;
2980 StgProperty chainProperty;
2981 BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2982 BlockChainStream *bbTempChain = NULL;
2983 BlockChainStream *bigBlockChain = NULL;
2986 * Create a temporary big block chain that doesn't have
2987 * an associated property. This temporary chain will be
2988 * used to copy data from small blocks to big blocks.
2990 bbTempChain = BlockChainStream_Construct(This,
2991 &bbHeadOfChain,
2992 PROPERTY_NULL);
2995 * Grow the big block chain.
2997 size = SmallBlockChainStream_GetSize(*ppsbChain);
2998 BlockChainStream_SetSize(bbTempChain, size);
3001 * Copy the contents of the small block chain to the big block chain
3002 * by small block size increments.
3004 offset.LowPart = 0;
3005 offset.HighPart = 0;
3006 cbTotalRead = 0;
3007 cbTotalWritten = 0;
3011 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3012 offset,
3013 sizeof(buffer),
3014 buffer,
3015 &cbRead);
3016 cbTotalRead += cbRead;
3018 successWrite = BlockChainStream_WriteAt(bbTempChain,
3019 offset,
3020 cbRead,
3021 buffer,
3022 &cbWritten);
3023 cbTotalWritten += cbWritten;
3025 offset.LowPart += This->smallBlockSize;
3027 } while (successRead && successWrite);
3029 assert(cbTotalRead == cbTotalWritten);
3032 * Destroy the small block chain.
3034 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3035 size.HighPart = 0;
3036 size.LowPart = 0;
3037 SmallBlockChainStream_SetSize(*ppsbChain, size);
3038 SmallBlockChainStream_Destroy(*ppsbChain);
3039 *ppsbChain = 0;
3042 * Change the property information. This chain is now a big block chain
3043 * and it doesn't reside in the small blocks chain anymore.
3045 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3047 chainProperty.startingBlock = bbHeadOfChain;
3049 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3052 * Destroy the temporary propertyless big block chain.
3053 * Create a new big block chain associated with this property.
3055 BlockChainStream_Destroy(bbTempChain);
3056 bigBlockChain = BlockChainStream_Construct(This,
3057 NULL,
3058 propertyIndex);
3060 return bigBlockChain;
3063 /******************************************************************************
3064 ** Storage32InternalImpl implementation
3067 StorageInternalImpl* StorageInternalImpl_Construct(
3068 StorageImpl* ancestorStorage,
3069 ULONG rootPropertyIndex)
3071 StorageInternalImpl* newStorage;
3074 * Allocate space for the new storage object
3076 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3078 if (newStorage!=0)
3080 memset(newStorage, 0, sizeof(StorageInternalImpl));
3083 * Initialize the virtual function table.
3085 newStorage->lpvtbl = &Storage32InternalImpl_Vtbl;
3086 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3089 * Keep the ancestor storage pointer and nail a reference to it.
3091 newStorage->ancestorStorage = ancestorStorage;
3092 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3095 * Keep the index of the root property set for this storage,
3097 newStorage->rootPropertySetIndex = rootPropertyIndex;
3099 return newStorage;
3102 return 0;
3105 void StorageInternalImpl_Destroy(
3106 StorageInternalImpl* This)
3108 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3109 HeapFree(GetProcessHeap(), 0, This);
3112 /******************************************************************************
3114 ** Storage32InternalImpl_Commit
3116 ** The non-root storages cannot be opened in transacted mode thus this function
3117 ** does nothing.
3119 HRESULT WINAPI StorageInternalImpl_Commit(
3120 IStorage* iface,
3121 DWORD grfCommitFlags) /* [in] */
3123 return S_OK;
3126 /******************************************************************************
3128 ** Storage32InternalImpl_Revert
3130 ** The non-root storages cannot be opened in transacted mode thus this function
3131 ** does nothing.
3133 HRESULT WINAPI StorageInternalImpl_Revert(
3134 IStorage* iface)
3136 return S_OK;
3139 /******************************************************************************
3140 ** IEnumSTATSTGImpl implementation
3143 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3144 StorageImpl* parentStorage,
3145 ULONG firstPropertyNode)
3147 IEnumSTATSTGImpl* newEnumeration;
3149 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3151 if (newEnumeration!=0)
3154 * Set-up the virtual function table and reference count.
3156 newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
3157 newEnumeration->ref = 0;
3160 * We want to nail-down the reference to the storage in case the
3161 * enumeration out-lives the storage in the client application.
3163 newEnumeration->parentStorage = parentStorage;
3164 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3166 newEnumeration->firstPropertyNode = firstPropertyNode;
3169 * Initialize the search stack
3171 newEnumeration->stackSize = 0;
3172 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3173 newEnumeration->stackToVisit =
3174 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3177 * Make sure the current node of the iterator is the first one.
3179 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3182 return newEnumeration;
3185 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3187 IStorage_Release((IStorage*)This->parentStorage);
3188 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3189 HeapFree(GetProcessHeap(), 0, This);
3192 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3193 IEnumSTATSTG* iface,
3194 REFIID riid,
3195 void** ppvObject)
3197 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3200 * Perform a sanity check on the parameters.
3202 if (ppvObject==0)
3203 return E_INVALIDARG;
3206 * Initialize the return parameter.
3208 *ppvObject = 0;
3211 * Compare the riid with the interface IDs implemented by this object.
3213 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3215 *ppvObject = (IEnumSTATSTG*)This;
3217 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3219 *ppvObject = (IEnumSTATSTG*)This;
3223 * Check that we obtained an interface.
3225 if ((*ppvObject)==0)
3226 return E_NOINTERFACE;
3229 * Query Interface always increases the reference count by one when it is
3230 * successful
3232 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3234 return S_OK;
3237 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3238 IEnumSTATSTG* iface)
3240 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3242 This->ref++;
3243 return This->ref;
3246 ULONG WINAPI IEnumSTATSTGImpl_Release(
3247 IEnumSTATSTG* iface)
3249 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3251 ULONG newRef;
3253 This->ref--;
3254 newRef = This->ref;
3257 * If the reference count goes down to 0, perform suicide.
3259 if (newRef==0)
3261 IEnumSTATSTGImpl_Destroy(This);
3264 return newRef;;
3267 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3268 IEnumSTATSTG* iface,
3269 ULONG celt,
3270 STATSTG* rgelt,
3271 ULONG* pceltFetched)
3273 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3275 StgProperty currentProperty;
3276 STATSTG* currentReturnStruct = rgelt;
3277 ULONG objectFetched = 0;
3278 ULONG currentSearchNode;
3281 * Perform a sanity check on the parameters.
3283 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3284 return E_INVALIDARG;
3287 * To avoid the special case, get another pointer to a ULONG value if
3288 * the caller didn't supply one.
3290 if (pceltFetched==0)
3291 pceltFetched = &objectFetched;
3294 * Start the iteration, we will iterate until we hit the end of the
3295 * linked list or until we hit the number of items to iterate through
3297 *pceltFetched = 0;
3300 * Start with the node at the top of the stack.
3302 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3304 while ( ( *pceltFetched < celt) &&
3305 ( currentSearchNode!=PROPERTY_NULL) )
3308 * Remove the top node from the stack
3310 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3313 * Read the property from the storage.
3315 StorageImpl_ReadProperty(This->parentStorage,
3316 currentSearchNode,
3317 &currentProperty);
3320 * Copy the information to the return buffer.
3322 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3323 &currentProperty,
3324 STATFLAG_DEFAULT);
3327 * Step to the next item in the iteration
3329 (*pceltFetched)++;
3330 currentReturnStruct++;
3333 * Push the next search node in the search stack.
3335 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3338 * continue the iteration.
3340 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3343 if (*pceltFetched == celt)
3344 return S_OK;
3346 return S_FALSE;
3350 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3351 IEnumSTATSTG* iface,
3352 ULONG celt)
3354 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3356 StgProperty currentProperty;
3357 ULONG objectFetched = 0;
3358 ULONG currentSearchNode;
3361 * Start with the node at the top of the stack.
3363 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3365 while ( (objectFetched < celt) &&
3366 (currentSearchNode!=PROPERTY_NULL) )
3369 * Remove the top node from the stack
3371 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3374 * Read the property from the storage.
3376 StorageImpl_ReadProperty(This->parentStorage,
3377 currentSearchNode,
3378 &currentProperty);
3381 * Step to the next item in the iteration
3383 objectFetched++;
3386 * Push the next search node in the search stack.
3388 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3391 * continue the iteration.
3393 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3396 if (objectFetched == celt)
3397 return S_OK;
3399 return S_FALSE;
3402 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3403 IEnumSTATSTG* iface)
3405 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3407 StgProperty rootProperty;
3408 BOOL readSucessful;
3411 * Re-initialize the search stack to an empty stack
3413 This->stackSize = 0;
3416 * Read the root property from the storage.
3418 readSucessful = StorageImpl_ReadProperty(
3419 This->parentStorage,
3420 This->firstPropertyNode,
3421 &rootProperty);
3423 if (readSucessful)
3425 assert(rootProperty.sizeOfNameString!=0);
3428 * Push the search node in the search stack.
3430 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3433 return S_OK;
3436 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3437 IEnumSTATSTG* iface,
3438 IEnumSTATSTG** ppenum)
3440 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3442 IEnumSTATSTGImpl* newClone;
3445 * Perform a sanity check on the parameters.
3447 if (ppenum==0)
3448 return E_INVALIDARG;
3450 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3451 This->firstPropertyNode);
3455 * The new clone enumeration must point to the same current node as
3456 * the ole one.
3458 newClone->stackSize = This->stackSize ;
3459 newClone->stackMaxSize = This->stackMaxSize ;
3460 newClone->stackToVisit =
3461 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3463 memcpy(
3464 newClone->stackToVisit,
3465 This->stackToVisit,
3466 sizeof(ULONG) * newClone->stackSize);
3468 *ppenum = (IEnumSTATSTG*)newClone;
3471 * Don't forget to nail down a reference to the clone before
3472 * returning it.
3474 IEnumSTATSTGImpl_AddRef(*ppenum);
3476 return S_OK;
3479 INT IEnumSTATSTGImpl_FindParentProperty(
3480 IEnumSTATSTGImpl *This,
3481 ULONG childProperty,
3482 StgProperty *currentProperty,
3483 ULONG *thisNodeId)
3485 ULONG currentSearchNode;
3486 ULONG foundNode;
3489 * To avoid the special case, get another pointer to a ULONG value if
3490 * the caller didn't supply one.
3492 if (thisNodeId==0)
3493 thisNodeId = &foundNode;
3496 * Start with the node at the top of the stack.
3498 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3501 while (currentSearchNode!=PROPERTY_NULL)
3504 * Store the current node in the returned parameters
3506 *thisNodeId = currentSearchNode;
3509 * Remove the top node from the stack
3511 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3514 * Read the property from the storage.
3516 StorageImpl_ReadProperty(
3517 This->parentStorage,
3518 currentSearchNode,
3519 currentProperty);
3521 if (currentProperty->previousProperty == childProperty)
3522 return PROPERTY_RELATION_PREVIOUS;
3524 else if (currentProperty->nextProperty == childProperty)
3525 return PROPERTY_RELATION_NEXT;
3527 else if (currentProperty->dirProperty == childProperty)
3528 return PROPERTY_RELATION_DIR;
3531 * Push the next search node in the search stack.
3533 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3536 * continue the iteration.
3538 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3541 return PROPERTY_NULL;
3544 ULONG IEnumSTATSTGImpl_FindProperty(
3545 IEnumSTATSTGImpl* This,
3546 const OLECHAR* lpszPropName,
3547 StgProperty* currentProperty)
3549 ULONG currentSearchNode;
3552 * Start with the node at the top of the stack.
3554 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3556 while (currentSearchNode!=PROPERTY_NULL)
3559 * Remove the top node from the stack
3561 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3564 * Read the property from the storage.
3566 StorageImpl_ReadProperty(This->parentStorage,
3567 currentSearchNode,
3568 currentProperty);
3570 if ( propertyNameCmp(
3571 (OLECHAR*)currentProperty->name,
3572 (OLECHAR*)lpszPropName) == 0)
3573 return currentSearchNode;
3576 * Push the next search node in the search stack.
3578 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3581 * continue the iteration.
3583 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3586 return PROPERTY_NULL;
3589 void IEnumSTATSTGImpl_PushSearchNode(
3590 IEnumSTATSTGImpl* This,
3591 ULONG nodeToPush)
3593 StgProperty rootProperty;
3594 BOOL readSucessful;
3597 * First, make sure we're not trying to push an unexisting node.
3599 if (nodeToPush==PROPERTY_NULL)
3600 return;
3603 * First push the node to the stack
3605 if (This->stackSize == This->stackMaxSize)
3607 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3609 This->stackToVisit = HeapReAlloc(
3610 GetProcessHeap(),
3612 This->stackToVisit,
3613 sizeof(ULONG) * This->stackMaxSize);
3616 This->stackToVisit[This->stackSize] = nodeToPush;
3617 This->stackSize++;
3620 * Read the root property from the storage.
3622 readSucessful = StorageImpl_ReadProperty(
3623 This->parentStorage,
3624 nodeToPush,
3625 &rootProperty);
3627 if (readSucessful)
3629 assert(rootProperty.sizeOfNameString!=0);
3632 * Push the previous search node in the search stack.
3634 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3638 ULONG IEnumSTATSTGImpl_PopSearchNode(
3639 IEnumSTATSTGImpl* This,
3640 BOOL remove)
3642 ULONG topNode;
3644 if (This->stackSize == 0)
3645 return PROPERTY_NULL;
3647 topNode = This->stackToVisit[This->stackSize-1];
3649 if (remove)
3650 This->stackSize--;
3652 return topNode;
3655 /******************************************************************************
3656 ** StorageUtl implementation
3659 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3661 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3664 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3666 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3669 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3671 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3674 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3676 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3679 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3681 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3682 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3683 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3685 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3688 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3690 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3691 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3692 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3694 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3697 void StorageUtl_CopyPropertyToSTATSTG(
3698 STATSTG* destination,
3699 StgProperty* source,
3700 int statFlags)
3703 * The copy of the string occurs only when the flag is not set
3705 if ((statFlags & STATFLAG_NONAME) != 0)
3707 destination->pwcsName = 0;
3709 else
3711 destination->pwcsName =
3712 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3714 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3717 switch (source->propertyType)
3719 case PROPTYPE_STORAGE:
3720 case PROPTYPE_ROOT:
3721 destination->type = STGTY_STORAGE;
3722 break;
3723 case PROPTYPE_STREAM:
3724 destination->type = STGTY_STREAM;
3725 break;
3726 default:
3727 destination->type = STGTY_STREAM;
3728 break;
3731 destination->cbSize = source->size;
3733 currentReturnStruct->mtime = {0}; TODO
3734 currentReturnStruct->ctime = {0};
3735 currentReturnStruct->atime = {0};
3737 destination->grfMode = 0;
3738 destination->grfLocksSupported = 0;
3739 destination->clsid = source->propertyUniqueID;
3740 destination->grfStateBits = 0;
3741 destination->reserved = 0;
3744 /******************************************************************************
3745 ** BlockChainStream implementation
3748 BlockChainStream* BlockChainStream_Construct(
3749 StorageImpl* parentStorage,
3750 ULONG* headOfStreamPlaceHolder,
3751 ULONG propertyIndex)
3753 BlockChainStream* newStream;
3754 ULONG blockIndex;
3756 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3758 newStream->parentStorage = parentStorage;
3759 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3760 newStream->ownerPropertyIndex = propertyIndex;
3761 newStream->lastBlockNoInSequence = 0xFFFFFFFF;
3762 newStream->tailIndex = BLOCK_END_OF_CHAIN;
3763 newStream->numBlocks = 0;
3765 blockIndex = BlockChainStream_GetHeadOfChain(newStream);
3767 while (blockIndex != BLOCK_END_OF_CHAIN)
3769 newStream->numBlocks++;
3770 newStream->tailIndex = blockIndex;
3772 blockIndex = StorageImpl_GetNextBlockInChain(
3773 parentStorage,
3774 blockIndex);
3777 return newStream;
3780 void BlockChainStream_Destroy(BlockChainStream* This)
3782 HeapFree(GetProcessHeap(), 0, This);
3785 /******************************************************************************
3786 * BlockChainStream_GetHeadOfChain
3788 * Returns the head of this stream chain.
3789 * Some special chains don't have properties, their heads are kept in
3790 * This->headOfStreamPlaceHolder.
3793 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3795 StgProperty chainProperty;
3796 BOOL readSucessful;
3798 if (This->headOfStreamPlaceHolder != 0)
3799 return *(This->headOfStreamPlaceHolder);
3801 if (This->ownerPropertyIndex != PROPERTY_NULL)
3803 readSucessful = StorageImpl_ReadProperty(
3804 This->parentStorage,
3805 This->ownerPropertyIndex,
3806 &chainProperty);
3808 if (readSucessful)
3810 return chainProperty.startingBlock;
3814 return BLOCK_END_OF_CHAIN;
3817 /******************************************************************************
3818 * BlockChainStream_GetCount
3820 * Returns the number of blocks that comprises this chain.
3821 * This is not the size of the stream as the last block may not be full!
3824 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3826 ULONG blockIndex;
3827 ULONG count = 0;
3829 blockIndex = BlockChainStream_GetHeadOfChain(This);
3831 while (blockIndex != BLOCK_END_OF_CHAIN)
3833 count++;
3835 blockIndex = StorageImpl_GetNextBlockInChain(
3836 This->parentStorage,
3837 blockIndex);
3840 return count;
3843 /******************************************************************************
3844 * BlockChainStream_ReadAt
3846 * Reads a specified number of bytes from this chain at the specified offset.
3847 * bytesRead may be NULL.
3848 * Failure will be returned if the specified number of bytes has not been read.
3850 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
3851 ULARGE_INTEGER offset,
3852 ULONG size,
3853 void* buffer,
3854 ULONG* bytesRead)
3856 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3857 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3858 ULONG bytesToReadInBuffer;
3859 ULONG blockIndex;
3860 BYTE* bufferWalker;
3861 BYTE* bigBlockBuffer;
3863 if (This->lastBlockNoInSequence == 0xFFFFFFFF)
3864 This->lastBlockNoInSequence = blockNoInSequence;
3866 * Find the first block in the stream that contains part of the buffer.
3868 if (blockNoInSequence > This->lastBlockNoInSequence)
3870 ULONG temp = blockNoInSequence;
3872 blockIndex = This->lastBlockNoInSequenceIndex;
3873 blockNoInSequence -= This->lastBlockNoInSequence;
3874 This->lastBlockNoInSequence = temp;
3876 else
3878 blockIndex = BlockChainStream_GetHeadOfChain(This);
3879 This->lastBlockNoInSequence = blockNoInSequence;
3882 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3884 blockIndex =
3885 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3887 blockNoInSequence--;
3890 This->lastBlockNoInSequenceIndex = blockIndex;
3893 * Start reading the buffer.
3895 *bytesRead = 0;
3896 bufferWalker = buffer;
3898 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3901 * Calculate how many bytes we can copy from this big block.
3903 bytesToReadInBuffer =
3904 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3907 * Copy those bytes to the buffer
3909 bigBlockBuffer =
3910 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
3912 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3914 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3917 * Step to the next big block.
3919 blockIndex =
3920 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3922 bufferWalker += bytesToReadInBuffer;
3923 size -= bytesToReadInBuffer;
3924 *bytesRead += bytesToReadInBuffer;
3925 offsetInBlock = 0; /* There is no offset on the next block */
3929 return (size == 0);
3932 /******************************************************************************
3933 * BlockChainStream_WriteAt
3935 * Writes the specified number of bytes to this chain at the specified offset.
3936 * bytesWritten may be NULL.
3937 * Will fail if not all specified number of bytes have been written.
3939 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
3940 ULARGE_INTEGER offset,
3941 ULONG size,
3942 const void* buffer,
3943 ULONG* bytesWritten)
3945 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3946 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3947 ULONG bytesToWrite;
3948 ULONG blockIndex;
3949 BYTE* bufferWalker;
3950 BYTE* bigBlockBuffer;
3952 if (This->lastBlockNoInSequence == 0xFFFFFFFF)
3953 This->lastBlockNoInSequence = blockNoInSequence;
3956 * Find the first block in the stream that contains part of the buffer.
3958 if (blockNoInSequence > This->lastBlockNoInSequence)
3960 ULONG temp = blockNoInSequence;
3962 blockIndex = This->lastBlockNoInSequenceIndex;
3963 blockNoInSequence -= This->lastBlockNoInSequence;
3964 This->lastBlockNoInSequence = temp;
3966 else
3968 blockIndex = BlockChainStream_GetHeadOfChain(This);
3969 This->lastBlockNoInSequence = blockNoInSequence;
3972 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3974 blockIndex =
3975 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3977 blockNoInSequence--;
3980 This->lastBlockNoInSequenceIndex = blockIndex;
3983 * Here, I'm casting away the constness on the buffer variable
3984 * This is OK since we don't intend to modify that buffer.
3986 *bytesWritten = 0;
3987 bufferWalker = (BYTE*)buffer;
3989 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3992 * Calculate how many bytes we can copy from this big block.
3994 bytesToWrite =
3995 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3998 * Copy those bytes to the buffer
4000 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
4002 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
4004 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4007 * Step to the next big block.
4009 blockIndex =
4010 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4012 bufferWalker += bytesToWrite;
4013 size -= bytesToWrite;
4014 *bytesWritten += bytesToWrite;
4015 offsetInBlock = 0; /* There is no offset on the next block */
4018 return (size == 0);
4021 /******************************************************************************
4022 * BlockChainStream_Shrink
4024 * Shrinks this chain in the big block depot.
4026 BOOL BlockChainStream_Shrink(BlockChainStream* This,
4027 ULARGE_INTEGER newSize)
4029 ULONG blockIndex, extraBlock;
4030 ULONG numBlocks;
4031 ULONG count = 1;
4034 * Figure out how many blocks are needed to contain the new size
4036 numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
4038 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
4039 numBlocks++;
4041 blockIndex = BlockChainStream_GetHeadOfChain(This);
4044 * Go to the new end of chain
4046 while (count < numBlocks)
4048 blockIndex =
4049 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4051 count++;
4054 /* Get the next block before marking the new end */
4055 extraBlock =
4056 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4058 /* Mark the new end of chain */
4059 StorageImpl_SetNextBlockInChain(
4060 This->parentStorage,
4061 blockIndex,
4062 BLOCK_END_OF_CHAIN);
4064 This->tailIndex = blockIndex;
4065 This->numBlocks = numBlocks;
4068 * Mark the extra blocks as free
4070 while (extraBlock != BLOCK_END_OF_CHAIN)
4072 blockIndex =
4073 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4075 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4076 extraBlock = blockIndex;
4079 return TRUE;
4082 /******************************************************************************
4083 * BlockChainStream_Enlarge
4085 * Grows this chain in the big block depot.
4087 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4088 ULARGE_INTEGER newSize)
4090 ULONG blockIndex, currentBlock;
4091 ULONG newNumBlocks;
4092 ULONG oldNumBlocks = 0;
4094 blockIndex = BlockChainStream_GetHeadOfChain(This);
4097 * Empty chain. Create the head.
4099 if (blockIndex == BLOCK_END_OF_CHAIN)
4101 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4102 StorageImpl_SetNextBlockInChain(This->parentStorage,
4103 blockIndex,
4104 BLOCK_END_OF_CHAIN);
4106 if (This->headOfStreamPlaceHolder != 0)
4108 *(This->headOfStreamPlaceHolder) = blockIndex;
4110 else
4112 StgProperty chainProp;
4113 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4115 StorageImpl_ReadProperty(
4116 This->parentStorage,
4117 This->ownerPropertyIndex,
4118 &chainProp);
4120 chainProp.startingBlock = blockIndex;
4122 StorageImpl_WriteProperty(
4123 This->parentStorage,
4124 This->ownerPropertyIndex,
4125 &chainProp);
4128 This->tailIndex = blockIndex;
4129 This->numBlocks = 1;
4133 * Figure out how many blocks are needed to contain this stream
4135 newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
4137 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
4138 newNumBlocks++;
4141 * Go to the current end of chain
4143 if (This->tailIndex == BLOCK_END_OF_CHAIN)
4145 currentBlock = blockIndex;
4147 while (blockIndex != BLOCK_END_OF_CHAIN)
4149 This->numBlocks++;
4150 currentBlock = blockIndex;
4152 blockIndex =
4153 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4156 This->tailIndex = currentBlock;
4159 currentBlock = This->tailIndex;
4160 oldNumBlocks = This->numBlocks;
4163 * Add new blocks to the chain
4165 while (oldNumBlocks < newNumBlocks)
4167 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4169 StorageImpl_SetNextBlockInChain(
4170 This->parentStorage,
4171 currentBlock,
4172 blockIndex);
4174 StorageImpl_SetNextBlockInChain(
4175 This->parentStorage,
4176 blockIndex,
4177 BLOCK_END_OF_CHAIN);
4179 currentBlock = blockIndex;
4180 oldNumBlocks++;
4183 This->tailIndex = blockIndex;
4184 This->numBlocks = newNumBlocks;
4186 return TRUE;
4189 /******************************************************************************
4190 * BlockChainStream_SetSize
4192 * Sets the size of this stream. The big block depot will be updated.
4193 * The file will grow if we grow the chain.
4195 * TODO: Free the actual blocks in the file when we shrink the chain.
4196 * Currently, the blocks are still in the file. So the file size
4197 * doesn't shrink even if we shrink streams.
4199 BOOL BlockChainStream_SetSize(
4200 BlockChainStream* This,
4201 ULARGE_INTEGER newSize)
4203 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4205 if (newSize.LowPart == size.LowPart)
4206 return TRUE;
4208 if (newSize.LowPart < size.LowPart)
4210 BlockChainStream_Shrink(This, newSize);
4212 else
4214 ULARGE_INTEGER fileSize =
4215 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4217 ULONG diff = newSize.LowPart - size.LowPart;
4220 * Make sure the file stays a multiple of blocksize
4222 if ((diff % This->parentStorage->bigBlockSize) != 0)
4223 diff += (This->parentStorage->bigBlockSize -
4224 (diff % This->parentStorage->bigBlockSize) );
4226 fileSize.LowPart += diff;
4227 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4229 BlockChainStream_Enlarge(This, newSize);
4232 return TRUE;
4235 /******************************************************************************
4236 * BlockChainStream_GetSize
4238 * Returns the size of this chain.
4239 * Will return the block count if this chain doesn't have a property.
4241 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4243 StgProperty chainProperty;
4245 if(This->headOfStreamPlaceHolder == NULL)
4248 * This chain is a data stream read the property and return
4249 * the appropriate size
4251 StorageImpl_ReadProperty(
4252 This->parentStorage,
4253 This->ownerPropertyIndex,
4254 &chainProperty);
4256 return chainProperty.size;
4258 else
4261 * this chain is a chain that does not have a property, figure out the
4262 * size by making the product number of used blocks times the
4263 * size of them
4265 ULARGE_INTEGER result;
4266 result.HighPart = 0;
4268 result.LowPart =
4269 BlockChainStream_GetCount(This) *
4270 This->parentStorage->bigBlockSize;
4272 return result;
4276 /******************************************************************************
4277 ** SmallBlockChainStream implementation
4280 SmallBlockChainStream* SmallBlockChainStream_Construct(
4281 StorageImpl* parentStorage,
4282 ULONG propertyIndex)
4284 SmallBlockChainStream* newStream;
4286 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4288 newStream->parentStorage = parentStorage;
4289 newStream->ownerPropertyIndex = propertyIndex;
4291 return newStream;
4294 void SmallBlockChainStream_Destroy(
4295 SmallBlockChainStream* This)
4297 HeapFree(GetProcessHeap(), 0, This);
4300 /******************************************************************************
4301 * SmallBlockChainStream_GetHeadOfChain
4303 * Returns the head of this chain of small blocks.
4305 ULONG SmallBlockChainStream_GetHeadOfChain(
4306 SmallBlockChainStream* This)
4308 StgProperty chainProperty;
4309 BOOL readSucessful;
4311 if (This->ownerPropertyIndex)
4313 readSucessful = StorageImpl_ReadProperty(
4314 This->parentStorage,
4315 This->ownerPropertyIndex,
4316 &chainProperty);
4318 if (readSucessful)
4320 return chainProperty.startingBlock;
4325 return BLOCK_END_OF_CHAIN;
4328 /******************************************************************************
4329 * SmallBlockChainStream_GetNextBlockInChain
4331 * Returns the index of the next small block in this chain.
4333 * Return Values:
4334 * - BLOCK_END_OF_CHAIN: end of this chain
4335 * - BLOCK_UNUSED: small block 'blockIndex' is free
4337 ULONG SmallBlockChainStream_GetNextBlockInChain(
4338 SmallBlockChainStream* This,
4339 ULONG blockIndex)
4341 ULARGE_INTEGER offsetOfBlockInDepot;
4342 DWORD buffer;
4343 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4344 ULONG bytesRead;
4345 BOOL success;
4347 offsetOfBlockInDepot.HighPart = 0;
4348 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4351 * Read those bytes in the buffer from the small block file.
4353 success = BlockChainStream_ReadAt(
4354 This->parentStorage->smallBlockDepotChain,
4355 offsetOfBlockInDepot,
4356 sizeof(DWORD),
4357 &buffer,
4358 &bytesRead);
4360 if (success)
4362 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4365 return nextBlockInChain;
4368 /******************************************************************************
4369 * SmallBlockChainStream_SetNextBlockInChain
4371 * Writes the index of the next block of the specified block in the small
4372 * block depot.
4373 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4374 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4376 void SmallBlockChainStream_SetNextBlockInChain(
4377 SmallBlockChainStream* This,
4378 ULONG blockIndex,
4379 ULONG nextBlock)
4381 ULARGE_INTEGER offsetOfBlockInDepot;
4382 DWORD buffer;
4383 ULONG bytesWritten;
4385 offsetOfBlockInDepot.HighPart = 0;
4386 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4388 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4391 * Read those bytes in the buffer from the small block file.
4393 BlockChainStream_WriteAt(
4394 This->parentStorage->smallBlockDepotChain,
4395 offsetOfBlockInDepot,
4396 sizeof(DWORD),
4397 &buffer,
4398 &bytesWritten);
4401 /******************************************************************************
4402 * SmallBlockChainStream_FreeBlock
4404 * Flag small block 'blockIndex' as free in the small block depot.
4406 void SmallBlockChainStream_FreeBlock(
4407 SmallBlockChainStream* This,
4408 ULONG blockIndex)
4410 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4413 /******************************************************************************
4414 * SmallBlockChainStream_GetNextFreeBlock
4416 * Returns the index of a free small block. The small block depot will be
4417 * enlarged if necessary. The small block chain will also be enlarged if
4418 * necessary.
4420 ULONG SmallBlockChainStream_GetNextFreeBlock(
4421 SmallBlockChainStream* This)
4423 ULARGE_INTEGER offsetOfBlockInDepot;
4424 DWORD buffer;
4425 ULONG bytesRead;
4426 ULONG blockIndex = 0;
4427 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4428 BOOL success = TRUE;
4429 ULONG smallBlocksPerBigBlock;
4431 offsetOfBlockInDepot.HighPart = 0;
4434 * Scan the small block depot for a free block
4436 while (nextBlockIndex != BLOCK_UNUSED)
4438 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4440 success = BlockChainStream_ReadAt(
4441 This->parentStorage->smallBlockDepotChain,
4442 offsetOfBlockInDepot,
4443 sizeof(DWORD),
4444 &buffer,
4445 &bytesRead);
4448 * If we run out of space for the small block depot, enlarge it
4450 if (success)
4452 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4454 if (nextBlockIndex != BLOCK_UNUSED)
4455 blockIndex++;
4457 else
4459 ULONG count =
4460 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4462 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4463 ULONG nextBlock, newsbdIndex;
4464 BYTE* smallBlockDepot;
4466 nextBlock = sbdIndex;
4467 while (nextBlock != BLOCK_END_OF_CHAIN)
4469 sbdIndex = nextBlock;
4470 nextBlock =
4471 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4474 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4475 if (sbdIndex != BLOCK_END_OF_CHAIN)
4476 StorageImpl_SetNextBlockInChain(
4477 This->parentStorage,
4478 sbdIndex,
4479 newsbdIndex);
4481 StorageImpl_SetNextBlockInChain(
4482 This->parentStorage,
4483 newsbdIndex,
4484 BLOCK_END_OF_CHAIN);
4487 * Initialize all the small blocks to free
4489 smallBlockDepot =
4490 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4492 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4493 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4495 if (count == 0)
4498 * We have just created the small block depot.
4500 StgProperty rootProp;
4501 ULONG sbStartIndex;
4504 * Save it in the header
4506 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4507 StorageImpl_SaveFileHeader(This->parentStorage);
4510 * And allocate the first big block that will contain small blocks
4512 sbStartIndex =
4513 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4515 StorageImpl_SetNextBlockInChain(
4516 This->parentStorage,
4517 sbStartIndex,
4518 BLOCK_END_OF_CHAIN);
4520 StorageImpl_ReadProperty(
4521 This->parentStorage,
4522 This->parentStorage->rootPropertySetIndex,
4523 &rootProp);
4525 rootProp.startingBlock = sbStartIndex;
4526 rootProp.size.HighPart = 0;
4527 rootProp.size.LowPart = This->parentStorage->bigBlockSize;
4529 StorageImpl_WriteProperty(
4530 This->parentStorage,
4531 This->parentStorage->rootPropertySetIndex,
4532 &rootProp);
4537 smallBlocksPerBigBlock =
4538 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4541 * Verify if we have to allocate big blocks to contain small blocks
4543 if (blockIndex % smallBlocksPerBigBlock == 0)
4545 StgProperty rootProp;
4546 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4548 StorageImpl_ReadProperty(
4549 This->parentStorage,
4550 This->parentStorage->rootPropertySetIndex,
4551 &rootProp);
4553 if (rootProp.size.LowPart <
4554 (blocksRequired * This->parentStorage->bigBlockSize))
4556 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4558 BlockChainStream_SetSize(
4559 This->parentStorage->smallBlockRootChain,
4560 rootProp.size);
4562 StorageImpl_WriteProperty(
4563 This->parentStorage,
4564 This->parentStorage->rootPropertySetIndex,
4565 &rootProp);
4569 return blockIndex;
4572 /******************************************************************************
4573 * SmallBlockChainStream_ReadAt
4575 * Reads a specified number of bytes from this chain at the specified offset.
4576 * bytesRead may be NULL.
4577 * Failure will be returned if the specified number of bytes has not been read.
4579 BOOL SmallBlockChainStream_ReadAt(
4580 SmallBlockChainStream* This,
4581 ULARGE_INTEGER offset,
4582 ULONG size,
4583 void* buffer,
4584 ULONG* bytesRead)
4586 ULARGE_INTEGER offsetInBigBlockFile;
4587 ULONG blockNoInSequence =
4588 offset.LowPart / This->parentStorage->smallBlockSize;
4590 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4591 ULONG bytesToReadInBuffer;
4592 ULONG blockIndex;
4593 ULONG bytesReadFromBigBlockFile;
4594 BYTE* bufferWalker;
4597 * This should never happen on a small block file.
4599 assert(offset.HighPart==0);
4602 * Find the first block in the stream that contains part of the buffer.
4604 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4606 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4608 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4610 blockNoInSequence--;
4614 * Start reading the buffer.
4616 *bytesRead = 0;
4617 bufferWalker = buffer;
4619 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4622 * Calculate how many bytes we can copy from this small block.
4624 bytesToReadInBuffer =
4625 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4628 * Calculate the offset of the small block in the small block file.
4630 offsetInBigBlockFile.HighPart = 0;
4631 offsetInBigBlockFile.LowPart =
4632 blockIndex * This->parentStorage->smallBlockSize;
4634 offsetInBigBlockFile.LowPart += offsetInBlock;
4637 * Read those bytes in the buffer from the small block file.
4639 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4640 offsetInBigBlockFile,
4641 bytesToReadInBuffer,
4642 bufferWalker,
4643 &bytesReadFromBigBlockFile);
4645 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4648 * Step to the next big block.
4650 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4651 bufferWalker += bytesToReadInBuffer;
4652 size -= bytesToReadInBuffer;
4653 *bytesRead += bytesToReadInBuffer;
4654 offsetInBlock = 0; /* There is no offset on the next block */
4657 return (size == 0);
4660 /******************************************************************************
4661 * SmallBlockChainStream_WriteAt
4663 * Writes the specified number of bytes to this chain at the specified offset.
4664 * bytesWritten may be NULL.
4665 * Will fail if not all specified number of bytes have been written.
4667 BOOL SmallBlockChainStream_WriteAt(
4668 SmallBlockChainStream* This,
4669 ULARGE_INTEGER offset,
4670 ULONG size,
4671 const void* buffer,
4672 ULONG* bytesWritten)
4674 ULARGE_INTEGER offsetInBigBlockFile;
4675 ULONG blockNoInSequence =
4676 offset.LowPart / This->parentStorage->smallBlockSize;
4678 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4679 ULONG bytesToWriteInBuffer;
4680 ULONG blockIndex;
4681 ULONG bytesWrittenFromBigBlockFile;
4682 BYTE* bufferWalker;
4685 * This should never happen on a small block file.
4687 assert(offset.HighPart==0);
4690 * Find the first block in the stream that contains part of the buffer.
4692 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4694 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4696 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4698 blockNoInSequence--;
4702 * Start writing the buffer.
4704 * Here, I'm casting away the constness on the buffer variable
4705 * This is OK since we don't intend to modify that buffer.
4707 *bytesWritten = 0;
4708 bufferWalker = (BYTE*)buffer;
4709 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4712 * Calculate how many bytes we can copy to this small block.
4714 bytesToWriteInBuffer =
4715 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4718 * Calculate the offset of the small block in the small block file.
4720 offsetInBigBlockFile.HighPart = 0;
4721 offsetInBigBlockFile.LowPart =
4722 blockIndex * This->parentStorage->smallBlockSize;
4724 offsetInBigBlockFile.LowPart += offsetInBlock;
4727 * Write those bytes in the buffer to the small block file.
4729 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4730 offsetInBigBlockFile,
4731 bytesToWriteInBuffer,
4732 bufferWalker,
4733 &bytesWrittenFromBigBlockFile);
4735 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4738 * Step to the next big block.
4740 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4741 bufferWalker += bytesToWriteInBuffer;
4742 size -= bytesToWriteInBuffer;
4743 *bytesWritten += bytesToWriteInBuffer;
4744 offsetInBlock = 0; /* There is no offset on the next block */
4747 return (size == 0);
4750 /******************************************************************************
4751 * SmallBlockChainStream_Shrink
4753 * Shrinks this chain in the small block depot.
4755 BOOL SmallBlockChainStream_Shrink(
4756 SmallBlockChainStream* This,
4757 ULARGE_INTEGER newSize)
4759 ULONG blockIndex, extraBlock;
4760 ULONG numBlocks;
4761 ULONG count = 1;
4763 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4765 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4766 numBlocks++;
4768 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4771 * Go to the new end of chain
4773 while (count < numBlocks)
4775 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4776 count++;
4779 /* Get the next block before marking the new end */
4780 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4782 /* Mark the new end of chain */
4783 SmallBlockChainStream_SetNextBlockInChain(
4784 This,
4785 blockIndex,
4786 BLOCK_END_OF_CHAIN);
4789 * Mark the extra blocks as free
4791 while (extraBlock != BLOCK_END_OF_CHAIN)
4793 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4794 SmallBlockChainStream_FreeBlock(This, extraBlock);
4795 extraBlock = blockIndex;
4798 return TRUE;
4801 /******************************************************************************
4802 * SmallBlockChainStream_Enlarge
4804 * Grows this chain in the small block depot.
4806 BOOL SmallBlockChainStream_Enlarge(
4807 SmallBlockChainStream* This,
4808 ULARGE_INTEGER newSize)
4810 ULONG blockIndex, currentBlock;
4811 ULONG newNumBlocks;
4812 ULONG oldNumBlocks = 0;
4814 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4817 * Empty chain
4819 if (blockIndex == BLOCK_END_OF_CHAIN)
4821 StgProperty chainProp;
4823 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4824 &chainProp);
4826 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4828 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4829 &chainProp);
4831 blockIndex = chainProp.startingBlock;
4832 SmallBlockChainStream_SetNextBlockInChain(
4833 This,
4834 blockIndex,
4835 BLOCK_END_OF_CHAIN);
4838 currentBlock = blockIndex;
4841 * Figure out how many blocks are needed to contain this stream
4843 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4845 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4846 newNumBlocks++;
4849 * Go to the current end of chain
4851 while (blockIndex != BLOCK_END_OF_CHAIN)
4853 oldNumBlocks++;
4854 currentBlock = blockIndex;
4855 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4859 * Add new blocks to the chain
4861 while (oldNumBlocks < newNumBlocks)
4863 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4864 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4866 SmallBlockChainStream_SetNextBlockInChain(
4867 This,
4868 blockIndex,
4869 BLOCK_END_OF_CHAIN);
4871 currentBlock = blockIndex;
4872 oldNumBlocks++;
4875 return TRUE;
4878 /******************************************************************************
4879 * SmallBlockChainStream_GetCount
4881 * Returns the number of blocks that comprises this chain.
4882 * This is not the size of this chain as the last block may not be full!
4884 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4886 ULONG blockIndex;
4887 ULONG count = 0;
4889 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4891 while (blockIndex != BLOCK_END_OF_CHAIN)
4893 count++;
4895 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4898 return count;
4901 /******************************************************************************
4902 * SmallBlockChainStream_SetSize
4904 * Sets the size of this stream.
4905 * The file will grow if we grow the chain.
4907 * TODO: Free the actual blocks in the file when we shrink the chain.
4908 * Currently, the blocks are still in the file. So the file size
4909 * doesn't shrink even if we shrink streams.
4911 BOOL SmallBlockChainStream_SetSize(
4912 SmallBlockChainStream* This,
4913 ULARGE_INTEGER newSize)
4915 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4917 if (newSize.LowPart == size.LowPart)
4918 return TRUE;
4920 if (newSize.LowPart < size.LowPart)
4922 SmallBlockChainStream_Shrink(This, newSize);
4924 else
4926 SmallBlockChainStream_Enlarge(This, newSize);
4929 return TRUE;
4932 /******************************************************************************
4933 * SmallBlockChainStream_GetSize
4935 * Returns the size of this chain.
4937 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4939 StgProperty chainProperty;
4941 StorageImpl_ReadProperty(
4942 This->parentStorage,
4943 This->ownerPropertyIndex,
4944 &chainProperty);
4946 return chainProperty.size;
4949 /******************************************************************************
4950 * StgCreateDocfile32 [OLE32.144]
4952 HRESULT WINAPI StgCreateDocfile(
4953 LPCOLESTR pwcsName,
4954 DWORD grfMode,
4955 DWORD reserved,
4956 IStorage **ppstgOpen)
4958 StorageImpl* newStorage = 0;
4959 HANDLE hFile = INVALID_HANDLE_VALUE;
4960 HRESULT hr = S_OK;
4961 DWORD shareMode;
4962 DWORD accessMode;
4963 DWORD creationMode;
4964 DWORD fileAttributes;
4965 WCHAR tempFileName[MAX_PATH];
4968 * Validate the parameters
4970 if (ppstgOpen == 0)
4971 return STG_E_INVALIDPOINTER;
4974 * Validate the STGM flags
4976 if ( FAILED( validateSTGM(grfMode) ))
4977 return STG_E_INVALIDFLAG;
4980 * Generate a unique name.
4982 if (pwcsName == 0)
4984 WCHAR tempPath[MAX_PATH];
4985 WCHAR prefix[] = { 'S', 'T', 'O', 0 };
4987 memset(tempPath, 0, sizeof(tempPath));
4988 memset(tempFileName, 0, sizeof(tempFileName));
4990 if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
4991 tempPath[0] = '.';
4993 if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
4994 pwcsName = tempFileName;
4995 else
4996 return STG_E_INSUFFICIENTMEMORY;
5000 * Interpret the STGM value grfMode
5002 shareMode = GetShareModeFromSTGM(grfMode);
5003 accessMode = GetAccessModeFromSTGM(grfMode);
5004 creationMode = GetCreationModeFromSTGM(grfMode);
5006 if (grfMode & STGM_DELETEONRELEASE)
5007 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5008 else
5009 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5011 if (grfMode & STGM_TRANSACTED)
5012 FIXME(ole, "Transacted mode not implemented.\n");
5015 * Initialize the "out" parameter.
5017 *ppstgOpen = 0;
5019 hFile = CreateFileW(pwcsName,
5020 accessMode,
5021 shareMode,
5022 NULL,
5023 creationMode,
5024 fileAttributes,
5027 if (hFile == INVALID_HANDLE_VALUE)
5029 return E_FAIL;
5033 * Allocate and initialize the new IStorage32object.
5035 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5037 if (newStorage == 0)
5038 return STG_E_INSUFFICIENTMEMORY;
5040 hr = StorageImpl_Construct(
5041 newStorage,
5042 hFile,
5043 grfMode);
5045 if (FAILED(hr))
5047 HeapFree(GetProcessHeap(), 0, newStorage);
5048 return hr;
5052 * Get an "out" pointer for the caller.
5054 hr = StorageBaseImpl_QueryInterface(
5055 (IStorage*)newStorage,
5056 (REFIID)&IID_IStorage,
5057 (void**)ppstgOpen);
5059 return hr;
5062 /******************************************************************************
5063 * StgOpenStorage32 [OLE32.148]
5065 HRESULT WINAPI StgOpenStorage(
5066 const OLECHAR *pwcsName,
5067 IStorage *pstgPriority,
5068 DWORD grfMode,
5069 SNB snbExclude,
5070 DWORD reserved,
5071 IStorage **ppstgOpen)
5073 StorageImpl* newStorage = 0;
5074 HRESULT hr = S_OK;
5075 HANDLE hFile = 0;
5076 DWORD shareMode;
5077 DWORD accessMode;
5080 * Perform a sanity check
5082 if (( pwcsName == 0) || (ppstgOpen == 0) )
5083 return STG_E_INVALIDPOINTER;
5086 * Validate the STGM flags
5088 if ( FAILED( validateSTGM(grfMode) ))
5089 return STG_E_INVALIDFLAG;
5092 * Interpret the STGM value grfMode
5094 shareMode = GetShareModeFromSTGM(grfMode);
5095 accessMode = GetAccessModeFromSTGM(grfMode);
5098 * Initialize the "out" parameter.
5100 *ppstgOpen = 0;
5102 hFile = CreateFileW( pwcsName,
5103 accessMode,
5104 shareMode,
5105 NULL,
5106 OPEN_EXISTING,
5107 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5111 if (hFile==INVALID_HANDLE_VALUE)
5113 return E_FAIL;
5117 * Allocate and initialize the new IStorage32object.
5119 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5121 if (newStorage == 0)
5122 return STG_E_INSUFFICIENTMEMORY;
5124 hr = StorageImpl_Construct(
5125 newStorage,
5126 hFile,
5127 grfMode);
5129 if (FAILED(hr))
5131 HeapFree(GetProcessHeap(), 0, newStorage);
5132 return hr;
5136 * Get an "out" pointer for the caller.
5138 hr = StorageBaseImpl_QueryInterface(
5139 (IStorage*)newStorage,
5140 (REFIID)&IID_IStorage,
5141 (void**)ppstgOpen);
5143 return hr;
5146 /******************************************************************************
5147 * WriteClassStg32 [OLE32.148]
5149 * This method will store the specified CLSID in the specified storage object
5151 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5153 HRESULT hRes;
5155 assert(pStg != 0);
5157 hRes = IStorage_SetClass(pStg, rclsid);
5159 return hRes;
5163 /****************************************************************************
5164 * This method validate a STGM parameter that can contain the values below
5166 * STGM_DIRECT 0x00000000
5167 * STGM_TRANSACTED 0x00010000
5168 * STGM_SIMPLE 0x08000000
5170 * STGM_READ 0x00000000
5171 * STGM_WRITE 0x00000001
5172 * STGM_READWRITE 0x00000002
5174 * STGM_SHARE_DENY_NONE 0x00000040
5175 * STGM_SHARE_DENY_READ 0x00000030
5176 * STGM_SHARE_DENY_WRITE 0x00000020
5177 * STGM_SHARE_EXCLUSIVE 0x00000010
5179 * STGM_PRIORITY 0x00040000
5180 * STGM_DELETEONRELEASE 0x04000000
5182 * STGM_CREATE 0x00001000
5183 * STGM_CONVERT 0x00020000
5184 * STGM_FAILIFTHERE 0x00000000
5186 * STGM_NOSCRATCH 0x00100000
5187 * STGM_NOSNAPSHOT 0x00200000
5189 static HRESULT validateSTGM(DWORD stgm)
5191 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5192 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5193 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5195 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5196 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5197 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5199 BOOL bSTGM_SHARE_DENY_NONE =
5200 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5202 BOOL bSTGM_SHARE_DENY_READ =
5203 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5205 BOOL bSTGM_SHARE_DENY_WRITE =
5206 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5208 BOOL bSTGM_SHARE_EXCLUSIVE =
5209 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5211 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5212 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5214 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5215 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5218 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5220 if ( ! bSTGM_DIRECT )
5221 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5222 return E_FAIL;
5225 * STGM_WRITE | STGM_READWRITE | STGM_READ
5227 if ( ! bSTGM_READ )
5228 if( bSTGM_WRITE && bSTGM_READWRITE )
5229 return E_FAIL;
5232 * STGM_SHARE_DENY_NONE | others
5233 * (I assume here that DENY_READ implies DENY_WRITE)
5235 if ( bSTGM_SHARE_DENY_NONE )
5236 if ( bSTGM_SHARE_DENY_READ ||
5237 bSTGM_SHARE_DENY_WRITE ||
5238 bSTGM_SHARE_EXCLUSIVE)
5239 return E_FAIL;
5242 * STGM_CREATE | STGM_CONVERT
5243 * if both are false, STGM_FAILIFTHERE is set to TRUE
5245 if ( bSTGM_CREATE && bSTGM_CONVERT )
5246 return E_FAIL;
5249 * STGM_NOSCRATCH requires STGM_TRANSACTED
5251 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5252 return E_FAIL;
5255 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5256 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5258 if (bSTGM_NOSNAPSHOT)
5260 if ( ! ( bSTGM_TRANSACTED &&
5261 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5262 return E_FAIL;
5265 return S_OK;
5268 /****************************************************************************
5269 * GetShareModeFromSTGM
5271 * This method will return a share mode flag from a STGM value.
5272 * The STGM value is assumed valid.
5274 static DWORD GetShareModeFromSTGM(DWORD stgm)
5276 DWORD dwShareMode = 0;
5277 BOOL bSTGM_SHARE_DENY_NONE =
5278 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5280 BOOL bSTGM_SHARE_DENY_READ =
5281 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5283 BOOL bSTGM_SHARE_DENY_WRITE =
5284 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5286 BOOL bSTGM_SHARE_EXCLUSIVE =
5287 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5289 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5290 dwShareMode = 0;
5292 if (bSTGM_SHARE_DENY_NONE)
5293 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5295 if (bSTGM_SHARE_DENY_WRITE)
5296 dwShareMode = FILE_SHARE_READ;
5298 return dwShareMode;
5301 /****************************************************************************
5302 * GetAccessModeFromSTGM
5304 * This method will return an access mode flag from a STGM value.
5305 * The STGM value is assumed valid.
5307 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5309 DWORD dwDesiredAccess = 0;
5310 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5311 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5312 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5314 if (bSTGM_READ)
5315 dwDesiredAccess = GENERIC_READ;
5317 if (bSTGM_WRITE)
5318 dwDesiredAccess |= GENERIC_WRITE;
5320 if (bSTGM_READWRITE)
5321 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5323 return dwDesiredAccess;
5326 /****************************************************************************
5327 * GetCreationModeFromSTGM
5329 * This method will return a creation mode flag from a STGM value.
5330 * The STGM value is assumed valid.
5332 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5334 if ( stgm & STGM_CREATE)
5335 return CREATE_ALWAYS;
5336 if (stgm & STGM_CONVERT) {
5337 FIXME(ole, "STGM_CONVERT not implemented!\n");
5338 return CREATE_NEW;
5340 /* All other cases */
5341 if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
5342 FIXME(ole,"unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
5343 return CREATE_NEW;