Process and thread id now use the server-side id instead of an
[wine/multimedia.git] / ole / storage32.c
blob549264e88a61625286272756c371f2106ed448a2
1 /*
2 * Compound Storage (32 bit version)
3 * Storage implementation
5 * This file contains the compound file implementation
6 * of the storage interface.
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Sylvain St-Germain
10 * Copyright 1999 Thuy Nguyen
13 #include <assert.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
18 #include "windows.h"
19 #include "winerror.h"
20 #include "file.h"
21 #include "ole.h"
22 #include "ole2.h"
23 #include "objbase.h"
24 #include "crtdll.h"
25 #include "tchar.h"
26 #include "heap.h"
28 #include "winnt.h"
29 #include "winbase.h"
30 #include "debug.h"
32 #include "storage32.h"
34 #define FILE_BEGIN 0
36 static const char rootPropertyName[] = "Root Entry";
38 /***********************************************************************
39 * Forward declaration of internal functions used by the method DestroyElement
41 static HRESULT deleteStorageProperty(
42 StorageImpl *parentStorage,
43 OLECHAR *propertyToDeleteName);
45 static HRESULT deleteStreamProperty(
46 StorageImpl *parentStorage,
47 ULONG foundPropertyIndexToDelete,
48 StgProperty propertyToDelete);
50 static HRESULT findPlaceholder(
51 StorageImpl *storage,
52 ULONG propertyIndexToStore,
53 ULONG storagePropertyIndex,
54 INT typeOfRelation);
56 static HRESULT adjustPropertyChain(
57 StorageImpl *This,
58 StgProperty propertyToDelete,
59 StgProperty parentProperty,
60 ULONG parentPropertyId,
61 INT typeOfRelation);
63 /***********************************************************************
64 * Declaration of the functions used to manipulate StgProperty
67 static ULONG getFreeProperty(
68 StorageImpl *storage);
70 static void updatePropertyChain(
71 StorageImpl *storage,
72 ULONG newPropertyIndex,
73 StgProperty newProperty);
75 static LONG propertyNameCmp(
76 OLECHAR *newProperty,
77 OLECHAR *currentProperty);
80 /***********************************************************************
81 * Declaration of miscellaneous functions...
83 static HRESULT validateSTGM(DWORD stgmValue);
85 static DWORD GetShareModeFromSTGM(DWORD stgm);
86 static DWORD GetAccessModeFromSTGM(DWORD stgm);
87 static DWORD GetCreationModeFromSTGM(DWORD stgm);
90 * Virtual function table for the IStorage32Impl class.
92 static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
94 StorageBaseImpl_QueryInterface,
95 StorageBaseImpl_AddRef,
96 StorageBaseImpl_Release,
97 StorageBaseImpl_CreateStream,
98 StorageBaseImpl_OpenStream,
99 StorageImpl_CreateStorage,
100 StorageBaseImpl_OpenStorage,
101 StorageImpl_CopyTo,
102 StorageImpl_MoveElementTo,
103 StorageImpl_Commit,
104 StorageImpl_Revert,
105 StorageBaseImpl_EnumElements,
106 StorageImpl_DestroyElement,
107 StorageBaseImpl_RenameElement,
108 StorageImpl_SetElementTimes,
109 StorageBaseImpl_SetClass,
110 StorageImpl_SetStateBits,
111 StorageBaseImpl_Stat
115 * Virtual function table for the Storage32InternalImpl class.
117 static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
119 StorageBaseImpl_QueryInterface,
120 StorageBaseImpl_AddRef,
121 StorageBaseImpl_Release,
122 StorageBaseImpl_CreateStream,
123 StorageBaseImpl_OpenStream,
124 StorageImpl_CreateStorage,
125 StorageBaseImpl_OpenStorage,
126 StorageImpl_CopyTo,
127 StorageImpl_MoveElementTo,
128 StorageInternalImpl_Commit,
129 StorageInternalImpl_Revert,
130 StorageBaseImpl_EnumElements,
131 StorageImpl_DestroyElement,
132 StorageBaseImpl_RenameElement,
133 StorageImpl_SetElementTimes,
134 StorageBaseImpl_SetClass,
135 StorageImpl_SetStateBits,
136 StorageBaseImpl_Stat
140 * Virtual function table for the IEnumSTATSTGImpl class.
142 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
144 IEnumSTATSTGImpl_QueryInterface,
145 IEnumSTATSTGImpl_AddRef,
146 IEnumSTATSTGImpl_Release,
147 IEnumSTATSTGImpl_Next,
148 IEnumSTATSTGImpl_Skip,
149 IEnumSTATSTGImpl_Reset,
150 IEnumSTATSTGImpl_Clone
157 /************************************************************************
158 ** Storage32BaseImpl implementatiion
161 /************************************************************************
162 * Storage32BaseImpl_QueryInterface (IUnknown)
164 * This method implements the common QueryInterface for all IStorage32
165 * implementations contained in this file.
167 * See Windows documentation for more details on IUnknown methods.
169 HRESULT WINAPI StorageBaseImpl_QueryInterface(
170 IStorage* iface,
171 REFIID riid,
172 void** ppvObject)
174 ICOM_THIS(StorageBaseImpl,iface);
176 * Perform a sanity check on the parameters.
178 if ( (This==0) || (ppvObject==0) )
179 return E_INVALIDARG;
182 * Initialize the return parameter.
184 *ppvObject = 0;
187 * Compare the riid with the interface IDs implemented by this object.
189 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
191 *ppvObject = (IStorage*)This;
193 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
195 *ppvObject = (IStorage*)This;
199 * Check that we obtained an interface.
201 if ((*ppvObject)==0)
202 return E_NOINTERFACE;
205 * Query Interface always increases the reference count by one when it is
206 * successful
208 StorageBaseImpl_AddRef(iface);
210 return S_OK;
213 /************************************************************************
214 * Storage32BaseImpl_AddRef (IUnknown)
216 * This method implements the common AddRef for all IStorage32
217 * implementations contained in this file.
219 * See Windows documentation for more details on IUnknown methods.
221 ULONG WINAPI StorageBaseImpl_AddRef(
222 IStorage* iface)
224 ICOM_THIS(StorageBaseImpl,iface);
225 This->ref++;
227 return This->ref;
230 /************************************************************************
231 * Storage32BaseImpl_Release (IUnknown)
233 * This method implements the common Release for all IStorage32
234 * implementations contained in this file.
236 * See Windows documentation for more details on IUnknown methods.
238 ULONG WINAPI StorageBaseImpl_Release(
239 IStorage* iface)
241 ICOM_THIS(StorageBaseImpl,iface);
243 * Decrease the reference count on this object.
245 This->ref--;
248 * If the reference count goes down to 0, perform suicide.
250 if (This->ref==0)
253 * Since we are using a system of base-classes, we want to call the
254 * destructor of the appropriate derived class. To do this, we are
255 * using virtual functions to implement the destructor.
257 This->v_destructor(This);
259 return 0;
262 return This->ref;
265 /************************************************************************
266 * Storage32BaseImpl_OpenStream (IStorage)
268 * This method will open the specified stream object from the current storage.
270 * See Windows documentation for more details on IStorage methods.
272 HRESULT WINAPI StorageBaseImpl_OpenStream(
273 IStorage* iface,
274 const OLECHAR* pwcsName, /* [string][in] */
275 void* reserved1, /* [unique][in] */
276 DWORD grfMode, /* [in] */
277 DWORD reserved2, /* [in] */
278 IStream** ppstm) /* [out] */
280 ICOM_THIS(StorageBaseImpl,iface);
281 IEnumSTATSTGImpl* propertyEnumeration;
282 StgStreamImpl* newStream;
283 StgProperty currentProperty;
284 ULONG foundPropertyIndex;
287 * Perform a sanity check on the parameters.
289 if ( (pwcsName==NULL) || (ppstm==0) )
290 return E_INVALIDARG;
293 * Initialize the out parameter
295 *ppstm = 0;
298 * Validate the STGM flags
300 if ( FAILED( validateSTGM(grfMode) ))
301 return STG_E_INVALIDFLAG;
304 * As documented.
306 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
307 (grfMode & STGM_DELETEONRELEASE) ||
308 (grfMode & STGM_TRANSACTED) )
309 return STG_E_INVALIDFUNCTION;
312 * Create a property enumeration to search the properties
314 propertyEnumeration = IEnumSTATSTGImpl_Construct(
315 This->ancestorStorage,
316 This->rootPropertySetIndex);
319 * Search the enumeration for the property with the given name
321 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
322 propertyEnumeration,
323 pwcsName,
324 &currentProperty);
327 * Delete the property enumeration since we don't need it anymore
329 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
332 * If it was found, construct the stream object and return a pointer to it.
334 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
335 (currentProperty.propertyType==PROPTYPE_STREAM) )
337 newStream = StgStreamImpl_Construct(This, foundPropertyIndex);
339 if (newStream!=0)
341 *ppstm = (IStream*)newStream;
344 * Since we are returning a pointer to the interface, we have to
345 * nail down the reference.
347 StgStreamImpl_AddRef(*ppstm);
349 return S_OK;
352 return E_OUTOFMEMORY;
355 return STG_E_FILENOTFOUND;
358 /************************************************************************
359 * Storage32BaseImpl_OpenStorage (IStorage)
361 * This method will open a new storage object from the current storage.
363 * See Windows documentation for more details on IStorage methods.
365 HRESULT WINAPI StorageBaseImpl_OpenStorage(
366 IStorage* iface,
367 const OLECHAR* pwcsName, /* [string][unique][in] */
368 IStorage* pstgPriority, /* [unique][in] */
369 DWORD grfMode, /* [in] */
370 SNB snbExclude, /* [unique][in] */
371 DWORD reserved, /* [in] */
372 IStorage** ppstg) /* [out] */
374 ICOM_THIS(StorageBaseImpl,iface);
375 StorageInternalImpl* newStorage;
376 IEnumSTATSTGImpl* propertyEnumeration;
377 StgProperty currentProperty;
378 ULONG foundPropertyIndex;
381 * Perform a sanity check on the parameters.
383 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
384 return E_INVALIDARG;
387 * Validate the STGM flags
389 if ( FAILED( validateSTGM(grfMode) ))
390 return STG_E_INVALIDFLAG;
393 * As documented.
395 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
396 (grfMode & STGM_DELETEONRELEASE) ||
397 (grfMode & STGM_PRIORITY) )
398 return STG_E_INVALIDFUNCTION;
401 * Initialize the out parameter
403 *ppstg = 0;
406 * Create a property enumeration to search the properties
408 propertyEnumeration = IEnumSTATSTGImpl_Construct(
409 This->ancestorStorage,
410 This->rootPropertySetIndex);
413 * Search the enumeration for the property with the given name
415 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
416 propertyEnumeration,
417 pwcsName,
418 &currentProperty);
421 * Delete the property enumeration since we don't need it anymore
423 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
426 * If it was found, construct the stream object and return a pointer to it.
428 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
429 (currentProperty.propertyType==PROPTYPE_STORAGE) )
432 * Construct a new Storage object
434 newStorage = StorageInternalImpl_Construct(
435 This->ancestorStorage,
436 foundPropertyIndex);
438 if (newStorage != 0)
440 *ppstg = (IStorage*)newStorage;
443 * Since we are returning a pointer to the interface,
444 * we have to nail down the reference.
446 StorageBaseImpl_AddRef(*ppstg);
448 return S_OK;
451 return STG_E_INSUFFICIENTMEMORY;
454 return STG_E_FILENOTFOUND;
457 /************************************************************************
458 * Storage32BaseImpl_EnumElements (IStorage)
460 * This method will create an enumerator object that can be used to
461 * retrieve informatino about all the properties in the storage object.
463 * See Windows documentation for more details on IStorage methods.
465 HRESULT WINAPI StorageBaseImpl_EnumElements(
466 IStorage* iface,
467 DWORD reserved1, /* [in] */
468 void* reserved2, /* [size_is][unique][in] */
469 DWORD reserved3, /* [in] */
470 IEnumSTATSTG** ppenum) /* [out] */
472 ICOM_THIS(StorageBaseImpl,iface);
473 IEnumSTATSTGImpl* newEnum;
476 * Perform a sanity check on the parameters.
478 if ( (This==0) || (ppenum==0))
479 return E_INVALIDARG;
482 * Construct the enumerator.
484 newEnum = IEnumSTATSTGImpl_Construct(
485 This->ancestorStorage,
486 This->rootPropertySetIndex);
488 if (newEnum!=0)
490 *ppenum = (IEnumSTATSTG*)newEnum;
493 * Don't forget to nail down a reference to the new object before
494 * returning it.
496 IEnumSTATSTGImpl_AddRef(*ppenum);
498 return S_OK;
501 return E_OUTOFMEMORY;
504 /************************************************************************
505 * Storage32BaseImpl_Stat (IStorage)
507 * This method will retrieve information about this storage object.
509 * See Windows documentation for more details on IStorage methods.
511 HRESULT WINAPI StorageBaseImpl_Stat(
512 IStorage* iface,
513 STATSTG* pstatstg, /* [out] */
514 DWORD grfStatFlag) /* [in] */
516 ICOM_THIS(StorageBaseImpl,iface);
517 StgProperty curProperty;
518 BOOL readSucessful;
521 * Perform a sanity check on the parameters.
523 if ( (This==0) || (pstatstg==0))
524 return E_INVALIDARG;
527 * Read the information from the property.
529 readSucessful = StorageImpl_ReadProperty(
530 This->ancestorStorage,
531 This->rootPropertySetIndex,
532 &curProperty);
534 if (readSucessful)
536 StorageUtl_CopyPropertyToSTATSTG(
537 pstatstg,
538 &curProperty,
539 grfStatFlag);
541 return S_OK;
544 return E_FAIL;
547 /************************************************************************
548 * Storage32BaseImpl_RenameElement (IStorage)
550 * This method will rename the specified element.
552 * See Windows documentation for more details on IStorage methods.
554 * Implementation notes: The method used to rename consists of creating a clone
555 * of the deleted StgProperty object setting it with the new name and to
556 * perform a DestroyElement of the old StgProperty.
558 HRESULT WINAPI StorageBaseImpl_RenameElement(
559 IStorage* iface,
560 const OLECHAR* pwcsOldName, /* [in] */
561 const OLECHAR* pwcsNewName) /* [in] */
563 ICOM_THIS(StorageBaseImpl,iface);
564 IEnumSTATSTGImpl* propertyEnumeration;
565 StgProperty currentProperty;
566 ULONG foundPropertyIndex;
569 * Create a property enumeration to search the properties
571 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
572 This->rootPropertySetIndex);
575 * Search the enumeration for the new property name
577 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
578 pwcsNewName,
579 &currentProperty);
581 if (foundPropertyIndex != PROPERTY_NULL)
584 * There is already a property with the new name
586 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
587 return STG_E_FILEALREADYEXISTS;
590 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
593 * Search the enumeration for the old property name
595 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
596 pwcsOldName,
597 &currentProperty);
600 * Delete the property enumeration since we don't need it anymore
602 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
604 if (foundPropertyIndex != PROPERTY_NULL)
606 StgProperty renamedProperty;
607 ULONG renamedPropertyIndex;
610 * Setup a new property for the renamed property
612 renamedProperty.sizeOfNameString =
613 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
615 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
616 return STG_E_INVALIDNAME;
618 lstrcpyW(renamedProperty.name, pwcsNewName);
620 renamedProperty.propertyType = currentProperty.propertyType;
621 renamedProperty.startingBlock = currentProperty.startingBlock;
622 renamedProperty.size.LowPart = currentProperty.size.LowPart;
623 renamedProperty.size.HighPart = currentProperty.size.HighPart;
625 renamedProperty.previousProperty = PROPERTY_NULL;
626 renamedProperty.nextProperty = PROPERTY_NULL;
629 * Bring the dirProperty link in case it is a storage and in which
630 * case the renamed storage elements don't require to be reorganized.
632 renamedProperty.dirProperty = currentProperty.dirProperty;
634 /* call CoFileTime to get the current time
635 renamedProperty.timeStampS1
636 renamedProperty.timeStampD1
637 renamedProperty.timeStampS2
638 renamedProperty.timeStampD2
639 renamedProperty.propertyUniqueID
643 * Obtain a free property in the property chain
645 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
648 * Save the new property into the new property spot
650 StorageImpl_WriteProperty(
651 This->ancestorStorage,
652 renamedPropertyIndex,
653 &renamedProperty);
656 * Find a spot in the property chain for our newly created property.
658 updatePropertyChain(
659 (StorageImpl*)This,
660 renamedPropertyIndex,
661 renamedProperty);
664 * At this point the renamed property has been inserted in the tree,
665 * now, before to Destroy the old property we must zeroed it's dirProperty
666 * otherwise the DestroyProperty below will zap it all and we do not want
667 * this to happen.
668 * Also, we fake that the old property is a storage so the DestroyProperty
669 * will not do a SetSize(0) on the stream data.
671 * This means that we need to tweek the StgProperty if it is a stream or a
672 * non empty storage.
674 currentProperty.dirProperty = PROPERTY_NULL;
675 currentProperty.propertyType = PROPTYPE_STORAGE;
676 StorageImpl_WriteProperty(
677 This->ancestorStorage,
678 foundPropertyIndex,
679 &currentProperty);
682 * Invoke Destroy to get rid of the ole property and automatically redo
683 * the linking of it's previous and next members...
685 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
688 else
691 * There is no property with the old name
693 return STG_E_FILENOTFOUND;
696 return S_OK;
699 /************************************************************************
700 * Storage32BaseImpl_CreateStream (IStorage)
702 * This method will create a stream object within this storage
704 * See Windows documentation for more details on IStorage methods.
706 HRESULT WINAPI StorageBaseImpl_CreateStream(
707 IStorage* iface,
708 const OLECHAR* pwcsName, /* [string][in] */
709 DWORD grfMode, /* [in] */
710 DWORD reserved1, /* [in] */
711 DWORD reserved2, /* [in] */
712 IStream** ppstm) /* [out] */
714 ICOM_THIS(StorageBaseImpl,iface);
715 IEnumSTATSTGImpl* propertyEnumeration;
716 StgStreamImpl* newStream;
717 StgProperty currentProperty, newStreamProperty;
718 ULONG foundPropertyIndex, newPropertyIndex;
721 * Validate parameters
723 if (ppstm == 0)
724 return STG_E_INVALIDPOINTER;
726 if (pwcsName == 0)
727 return STG_E_INVALIDNAME;
730 * Validate the STGM flags
732 if ( FAILED( validateSTGM(grfMode) ))
733 return STG_E_INVALIDFLAG;
736 * As documented.
738 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
739 (grfMode & STGM_DELETEONRELEASE) ||
740 (grfMode & STGM_TRANSACTED) )
741 return STG_E_INVALIDFUNCTION;
744 * Initialize the out parameter
746 *ppstm = 0;
749 * Create a property enumeration to search the properties
751 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
752 This->rootPropertySetIndex);
754 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
755 pwcsName,
756 &currentProperty);
758 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
760 if (foundPropertyIndex != PROPERTY_NULL)
763 * An element with this name already exists
765 if (grfMode & STGM_CREATE)
766 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
767 else
768 return STG_E_FILEALREADYEXISTS;
772 * memset the empty property
774 memset(&newStreamProperty, 0, sizeof(StgProperty));
776 newStreamProperty.sizeOfNameString =
777 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
779 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
780 return STG_E_INVALIDNAME;
782 lstrcpyW(newStreamProperty.name, pwcsName);
784 newStreamProperty.propertyType = PROPTYPE_STREAM;
785 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
786 newStreamProperty.size.LowPart = 0;
787 newStreamProperty.size.HighPart = 0;
789 newStreamProperty.previousProperty = PROPERTY_NULL;
790 newStreamProperty.nextProperty = PROPERTY_NULL;
791 newStreamProperty.dirProperty = PROPERTY_NULL;
793 /* call CoFileTime to get the current time
794 newStreamProperty.timeStampS1
795 newStreamProperty.timeStampD1
796 newStreamProperty.timeStampS2
797 newStreamProperty.timeStampD2
800 /* newStreamProperty.propertyUniqueID */
803 * Get a free property or create a new one
805 newPropertyIndex = getFreeProperty(This->ancestorStorage);
808 * Save the new property into the new property spot
810 StorageImpl_WriteProperty(
811 This->ancestorStorage,
812 newPropertyIndex,
813 &newStreamProperty);
816 * Find a spot in the property chain for our newly created property.
818 updatePropertyChain(
819 (StorageImpl*)This,
820 newPropertyIndex,
821 newStreamProperty);
824 * Open the stream to return it.
826 newStream = StgStreamImpl_Construct(This, newPropertyIndex);
828 if (newStream != 0)
830 *ppstm = (IStream*)newStream;
833 * Since we are returning a pointer to the interface, we have to nail down
834 * the reference.
836 StgStreamImpl_AddRef(*ppstm);
838 else
840 return STG_E_INSUFFICIENTMEMORY;
843 return S_OK;
846 /************************************************************************
847 * Storage32BaseImpl_SetClass (IStorage)
849 * This method will write the specified CLSID in the property of this
850 * storage.
852 * See Windows documentation for more details on IStorage methods.
854 HRESULT WINAPI StorageBaseImpl_SetClass(
855 IStorage* iface,
856 REFCLSID clsid) /* [in] */
858 ICOM_THIS(StorageBaseImpl,iface);
859 HRESULT hRes = E_FAIL;
860 StgProperty curProperty;
861 BOOL success;
863 success = StorageImpl_ReadProperty(This->ancestorStorage,
864 This->rootPropertySetIndex,
865 &curProperty);
866 if (success)
868 curProperty.propertyUniqueID = *clsid;
870 success = StorageImpl_WriteProperty(This->ancestorStorage,
871 This->rootPropertySetIndex,
872 &curProperty);
873 if (success)
874 hRes = S_OK;
877 return hRes;
880 /************************************************************************
881 ** Storage32Impl implementation
884 /************************************************************************
885 * Storage32Impl_CreateStorage (IStorage)
887 * This method will create the storage object within the provided storage.
889 * See Windows documentation for more details on IStorage methods.
891 HRESULT WINAPI StorageImpl_CreateStorage(
892 IStorage* iface,
893 const OLECHAR *pwcsName, /* [string][in] */
894 DWORD grfMode, /* [in] */
895 DWORD reserved1, /* [in] */
896 DWORD reserved2, /* [in] */
897 IStorage **ppstg) /* [out] */
899 StorageImpl* const This=(StorageImpl*)iface;
901 IEnumSTATSTGImpl *propertyEnumeration;
902 StgProperty currentProperty;
903 StgProperty newProperty;
904 ULONG foundPropertyIndex;
905 ULONG newPropertyIndex;
906 HRESULT hr;
909 * Validate parameters
911 if (ppstg == 0)
912 return STG_E_INVALIDPOINTER;
914 if (pwcsName == 0)
915 return STG_E_INVALIDNAME;
918 * Validate the STGM flags
920 if ( FAILED( validateSTGM(grfMode) ) ||
921 (grfMode & STGM_DELETEONRELEASE) )
922 return STG_E_INVALIDFLAG;
925 * Initialize the out parameter
927 *ppstg = 0;
930 * Create a property enumeration and search the properties
932 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
933 This->rootPropertySetIndex);
935 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
936 pwcsName,
937 &currentProperty);
938 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
940 if (foundPropertyIndex != PROPERTY_NULL)
943 * An element with this name already exists
945 if (grfMode & STGM_CREATE)
946 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsName);
947 else
948 return STG_E_FILEALREADYEXISTS;
952 * memset the empty property
954 memset(&newProperty, 0, sizeof(StgProperty));
956 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
958 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
959 return STG_E_INVALIDNAME;
961 lstrcpyW(newProperty.name, pwcsName);
963 newProperty.propertyType = PROPTYPE_STORAGE;
964 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
965 newProperty.size.LowPart = 0;
966 newProperty.size.HighPart = 0;
968 newProperty.previousProperty = PROPERTY_NULL;
969 newProperty.nextProperty = PROPERTY_NULL;
970 newProperty.dirProperty = PROPERTY_NULL;
972 /* call CoFileTime to get the current time
973 newProperty.timeStampS1
974 newProperty.timeStampD1
975 newProperty.timeStampS2
976 newProperty.timeStampD2
979 /* newStorageProperty.propertyUniqueID */
982 * Obtain a free property in the property chain
984 newPropertyIndex = getFreeProperty(This->ancestorStorage);
987 * Save the new property into the new property spot
989 StorageImpl_WriteProperty(
990 This->ancestorStorage,
991 newPropertyIndex,
992 &newProperty);
995 * Find a spot in the property chain for our newly created property.
997 updatePropertyChain(
998 This,
999 newPropertyIndex,
1000 newProperty);
1003 * Open it to get a pointer to return.
1005 hr = StorageBaseImpl_OpenStorage(
1006 iface,
1007 (OLECHAR*)pwcsName,
1009 grfMode,
1012 ppstg);
1014 if( (hr != S_OK) || (*ppstg == NULL))
1016 return hr;
1019 return S_OK;
1023 /***************************************************************************
1025 * Internal Method
1027 * Get a free property or create a new one.
1029 static ULONG getFreeProperty(
1030 StorageImpl *storage)
1032 ULONG currentPropertyIndex = 0;
1033 ULONG newPropertyIndex = PROPERTY_NULL;
1034 BOOL readSucessful = TRUE;
1035 StgProperty currentProperty;
1040 * Start by reading the root property
1042 readSucessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1043 currentPropertyIndex,
1044 &currentProperty);
1045 if (readSucessful)
1047 if (currentProperty.sizeOfNameString == 0)
1050 * The property existis and is available, we found it.
1052 newPropertyIndex = currentPropertyIndex;
1055 else
1058 * We exhausted the property list, we will create more space below
1060 newPropertyIndex = currentPropertyIndex;
1062 currentPropertyIndex++;
1064 } while (newPropertyIndex == PROPERTY_NULL);
1067 * grow the property chain
1069 if (! readSucessful)
1071 StgProperty emptyProperty;
1072 ULARGE_INTEGER newSize;
1073 ULONG propertyIndex;
1074 ULONG lastProperty = 0;
1075 ULONG blockCount = 0;
1078 * obtain the new count of property blocks
1080 blockCount = BlockChainStream_GetCount(
1081 storage->ancestorStorage->rootBlockChain)+1;
1084 * initialize the size used by the property stream
1086 newSize.HighPart = 0;
1087 newSize.LowPart = storage->bigBlockSize * blockCount;
1090 * add a property block to the property chain
1092 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1095 * memset the empty property in order to initialize the unused newly
1096 * created property
1098 memset(&emptyProperty, 0, sizeof(StgProperty));
1101 * initialize them
1103 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1105 for(
1106 propertyIndex = newPropertyIndex;
1107 propertyIndex < lastProperty;
1108 propertyIndex++)
1110 StorageImpl_WriteProperty(
1111 storage->ancestorStorage,
1112 propertyIndex,
1113 &emptyProperty);
1117 return newPropertyIndex;
1120 /****************************************************************************
1122 * Internal Method
1124 * Case insensitive comparaison of StgProperty.name by first considering
1125 * their size.
1127 * Returns <0 when newPrpoerty < currentProperty
1128 * >0 when newPrpoerty > currentProperty
1129 * 0 when newPrpoerty == currentProperty
1131 static LONG propertyNameCmp(
1132 OLECHAR *newProperty,
1133 OLECHAR *currentProperty)
1135 LONG sizeOfNew = (lstrlenW(newProperty) +1) * sizeof(WCHAR);
1136 LONG sizeOfCur = (lstrlenW(currentProperty)+1) * sizeof(WCHAR);
1137 LONG diff = sizeOfNew - sizeOfCur;
1139 if (diff == 0)
1142 * We compare the string themselves only when they are of the same lenght
1144 WCHAR wsnew[PROPERTY_NAME_MAX_LEN];
1145 WCHAR wscur[PROPERTY_NAME_MAX_LEN];
1147 diff = lstrcmpW( (LPCWSTR)CRTDLL__wcsupr(
1148 lstrcpynW(wsnew, newProperty, sizeOfNew)),
1149 (LPCWSTR)CRTDLL__wcsupr(
1150 lstrcpynW(wscur, currentProperty, sizeOfCur)));
1153 return diff;
1156 /****************************************************************************
1158 * Internal Method
1160 * Properly link this new element in the property chain.
1162 static void updatePropertyChain(
1163 StorageImpl *storage,
1164 ULONG newPropertyIndex,
1165 StgProperty newProperty)
1167 StgProperty currentProperty;
1170 * Read the root property
1172 StorageImpl_ReadProperty(storage->ancestorStorage,
1173 storage->rootPropertySetIndex,
1174 &currentProperty);
1176 if (currentProperty.dirProperty != PROPERTY_NULL)
1179 * The root storage contains some element, therefore, start the research
1180 * for the appropriate location.
1182 BOOL found = 0;
1183 ULONG current, next, previous, currentPropertyId;
1186 * Keep the StgProperty sequence number of the storage first property
1188 currentPropertyId = currentProperty.dirProperty;
1191 * Read
1193 StorageImpl_ReadProperty(storage->ancestorStorage,
1194 currentProperty.dirProperty,
1195 &currentProperty);
1197 previous = currentProperty.previousProperty;
1198 next = currentProperty.nextProperty;
1199 current = currentPropertyId;
1201 while (found == 0)
1203 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1205 if (diff < 0)
1207 if (previous != PROPERTY_NULL)
1209 StorageImpl_ReadProperty(storage->ancestorStorage,
1210 previous,
1211 &currentProperty);
1212 current = previous;
1214 else
1216 currentProperty.previousProperty = newPropertyIndex;
1217 StorageImpl_WriteProperty(storage->ancestorStorage,
1218 current,
1219 &currentProperty);
1220 found = 1;
1223 else
1225 if (next != PROPERTY_NULL)
1227 StorageImpl_ReadProperty(storage->ancestorStorage,
1228 next,
1229 &currentProperty);
1230 current = next;
1232 else
1234 currentProperty.nextProperty = newPropertyIndex;
1235 StorageImpl_WriteProperty(storage->ancestorStorage,
1236 current,
1237 &currentProperty);
1238 found = 1;
1242 previous = currentProperty.previousProperty;
1243 next = currentProperty.nextProperty;
1246 else
1249 * The root storage is empty, link the new property to it's dir property
1251 currentProperty.dirProperty = newPropertyIndex;
1252 StorageImpl_WriteProperty(storage->ancestorStorage,
1253 storage->rootPropertySetIndex,
1254 &currentProperty);
1259 /*************************************************************************
1260 * CopyTo (IStorage)
1262 HRESULT WINAPI StorageImpl_CopyTo(
1263 IStorage* iface,
1264 DWORD ciidExclude, /* [in] */
1265 const IID *rgiidExclude,/* [size_is][unique][in] */
1266 SNB snbExclude, /* [unique][in] */
1267 IStorage *pstgDest) /* [unique][in] */
1269 return E_NOTIMPL;
1272 /*************************************************************************
1273 * MoveElementTo (IStorage)
1275 HRESULT WINAPI StorageImpl_MoveElementTo(
1276 IStorage* iface,
1277 const OLECHAR *pwcsName, /* [string][in] */
1278 IStorage *pstgDest, /* [unique][in] */
1279 const OLECHAR *pwcsNewName,/* [string][in] */
1280 DWORD grfFlags) /* [in] */
1282 return E_NOTIMPL;
1285 /*************************************************************************
1286 * Commit (IStorage)
1288 HRESULT WINAPI StorageImpl_Commit(
1289 IStorage* iface,
1290 DWORD grfCommitFlags)/* [in] */
1292 FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1293 return S_OK;
1296 /*************************************************************************
1297 * Revert (IStorage)
1299 HRESULT WINAPI StorageImpl_Revert(
1300 IStorage* iface)
1302 return E_NOTIMPL;
1305 /*************************************************************************
1306 * DestroyElement (IStorage)
1308 * Stategy: This implementation is build this way for simplicity not for speed.
1309 * I always delete the top most element of the enumeration and adjust
1310 * the deleted element pointer all the time. This takes longer to
1311 * do but allow to reinvoke DestroyElement whenever we encounter a
1312 * storage object. The optimisation reside in the usage of another
1313 * enumeration stategy that would give all the leaves of a storage
1314 * first. (postfix order)
1316 HRESULT WINAPI StorageImpl_DestroyElement(
1317 IStorage* iface,
1318 const OLECHAR *pwcsName)/* [string][in] */
1320 StorageImpl* const This=(StorageImpl*)iface;
1322 IEnumSTATSTGImpl* propertyEnumeration;
1323 HRESULT hr = S_OK;
1324 BOOL res;
1325 StgProperty propertyToDelete;
1326 StgProperty parentProperty;
1327 ULONG foundPropertyIndexToDelete;
1328 ULONG typeOfRelation;
1329 ULONG parentPropertyId;
1332 * Perform a sanity check on the parameters.
1334 if (pwcsName==NULL)
1335 return STG_E_INVALIDPOINTER;
1338 * Create a property enumeration to search the property with the given name
1340 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1341 This->ancestorStorage,
1342 This->rootPropertySetIndex);
1344 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1345 propertyEnumeration,
1346 pwcsName,
1347 &propertyToDelete);
1349 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1351 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1353 return STG_E_FILENOTFOUND;
1357 * Find the parent property of the property to delete (the one that
1358 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1359 * the parent is This. Otherwise, the parent is one of it's sibling...
1363 * First, read This's StgProperty..
1365 res = StorageImpl_ReadProperty(
1366 This->ancestorStorage,
1367 This->rootPropertySetIndex,
1368 &parentProperty);
1370 assert(res==TRUE);
1373 * Second, check to see if by any chance the actual storage (This) is not
1374 * the parent of the property to delete... We never know...
1376 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1379 * Set data as it would have been done in the else part...
1381 typeOfRelation = PROPERTY_RELATION_DIR;
1382 parentPropertyId = This->rootPropertySetIndex;
1384 else
1387 * Create a property enumeration to search the parent properties, and
1388 * delete it once done.
1390 IEnumSTATSTGImpl* propertyEnumeration2;
1392 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1393 This->ancestorStorage,
1394 This->rootPropertySetIndex);
1396 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1397 propertyEnumeration2,
1398 foundPropertyIndexToDelete,
1399 &parentProperty,
1400 &parentPropertyId);
1402 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1405 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1407 hr = deleteStorageProperty(
1408 This,
1409 propertyToDelete.name);
1411 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1413 hr = deleteStreamProperty(
1414 This,
1415 foundPropertyIndexToDelete,
1416 propertyToDelete);
1419 if (hr!=S_OK)
1420 return hr;
1423 * Adjust the property chain
1425 hr = adjustPropertyChain(
1426 This,
1427 propertyToDelete,
1428 parentProperty,
1429 parentPropertyId,
1430 typeOfRelation);
1432 return hr;
1436 /*********************************************************************
1438 * Internal Method
1440 * Perform the deletion of a complete storage node
1443 static HRESULT deleteStorageProperty(
1444 StorageImpl *parentStorage,
1445 OLECHAR *propertyToDeleteName)
1447 IEnumSTATSTG *elements = 0;
1448 IStorage *childStorage = 0;
1449 STATSTG currentElement;
1450 HRESULT hr;
1451 HRESULT destroyHr = S_OK;
1454 * Open the storage and enumerate it
1456 hr = StorageBaseImpl_OpenStorage(
1457 (IStorage*)parentStorage,
1458 propertyToDeleteName,
1460 STGM_SHARE_EXCLUSIVE,
1463 &childStorage);
1465 if (hr != S_OK)
1467 return hr;
1471 * Enumerate the elements
1473 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1478 * Obtain the next element
1480 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1481 if (hr==S_OK)
1483 destroyHr = StorageImpl_DestroyElement(
1484 (IStorage*)childStorage,
1485 (OLECHAR*)currentElement.pwcsName);
1487 CoTaskMemFree(currentElement.pwcsName);
1491 * We need to Reset the enumeration every time because we delete elements
1492 * and the enumeration could be invalid
1494 IEnumSTATSTG_Reset(elements);
1496 } while ((hr == S_OK) && (destroyHr == S_OK));
1498 IStorage_Release(childStorage);
1499 IEnumSTATSTG_Release(elements);
1501 return destroyHr;
1504 /*********************************************************************
1506 * Internal Method
1508 * Perform the deletion of a stream node
1511 static HRESULT deleteStreamProperty(
1512 StorageImpl *parentStorage,
1513 ULONG indexOfPropertyToDelete,
1514 StgProperty propertyToDelete)
1516 IStream *pis;
1517 HRESULT hr;
1518 ULARGE_INTEGER size;
1520 size.HighPart = 0;
1521 size.LowPart = 0;
1523 hr = StorageBaseImpl_OpenStream(
1524 (IStorage*)parentStorage,
1525 (OLECHAR*)propertyToDelete.name,
1526 NULL,
1527 STGM_SHARE_EXCLUSIVE,
1529 &pis);
1531 if (hr!=S_OK)
1533 return(hr);
1537 * Zap the stream
1539 hr = IStream_SetSize(pis, size);
1541 if(hr != S_OK)
1543 return hr;
1547 * Invalidate the property by zeroing it's name member.
1549 propertyToDelete.sizeOfNameString = 0;
1552 * Here we should re-read the property so we get the updated pointer
1553 * but since we are here to zap it, I don't do it...
1556 StorageImpl_WriteProperty(
1557 parentStorage->ancestorStorage,
1558 indexOfPropertyToDelete,
1559 &propertyToDelete);
1561 return S_OK;
1564 /*********************************************************************
1566 * Internal Method
1568 * Finds a placeholder for the StgProperty within the Storage
1571 static HRESULT findPlaceholder(
1572 StorageImpl *storage,
1573 ULONG propertyIndexToStore,
1574 ULONG storePropertyIndex,
1575 INT typeOfRelation)
1577 StgProperty storeProperty;
1578 HRESULT hr = S_OK;
1579 BOOL res = TRUE;
1582 * Read the storage property
1584 res = StorageImpl_ReadProperty(
1585 storage->ancestorStorage,
1586 storePropertyIndex,
1587 &storeProperty);
1589 if(! res)
1591 return E_FAIL;
1594 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1596 if (storeProperty.previousProperty != PROPERTY_NULL)
1598 return findPlaceholder(
1599 storage,
1600 propertyIndexToStore,
1601 storeProperty.previousProperty,
1602 typeOfRelation);
1604 else
1606 storeProperty.previousProperty = propertyIndexToStore;
1609 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1611 if (storeProperty.nextProperty != PROPERTY_NULL)
1613 return findPlaceholder(
1614 storage,
1615 propertyIndexToStore,
1616 storeProperty.nextProperty,
1617 typeOfRelation);
1619 else
1621 storeProperty.nextProperty = propertyIndexToStore;
1624 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1626 if (storeProperty.dirProperty != PROPERTY_NULL)
1628 return findPlaceholder(
1629 storage,
1630 propertyIndexToStore,
1631 storeProperty.dirProperty,
1632 typeOfRelation);
1634 else
1636 storeProperty.dirProperty = propertyIndexToStore;
1640 hr = StorageImpl_WriteProperty(
1641 storage->ancestorStorage,
1642 storePropertyIndex,
1643 &storeProperty);
1645 if(! hr)
1647 return E_FAIL;
1650 return S_OK;
1653 /*************************************************************************
1655 * Internal Method
1657 * This method takes the previous and the next property link of a property
1658 * to be deleted and find them a place in the Storage.
1660 static HRESULT adjustPropertyChain(
1661 StorageImpl *This,
1662 StgProperty propertyToDelete,
1663 StgProperty parentProperty,
1664 ULONG parentPropertyId,
1665 INT typeOfRelation)
1667 ULONG newLinkProperty = PROPERTY_NULL;
1668 BOOL needToFindAPlaceholder = FALSE;
1669 ULONG storeNode = PROPERTY_NULL;
1670 ULONG toStoreNode = PROPERTY_NULL;
1671 INT relationType = 0;
1672 HRESULT hr = S_OK;
1673 BOOL res = TRUE;
1675 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1677 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1680 * Set the parent previous to the property to delete previous
1682 newLinkProperty = propertyToDelete.previousProperty;
1684 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1687 * We also need to find a storage for the other link, setup variables
1688 * to do this at the end...
1690 needToFindAPlaceholder = TRUE;
1691 storeNode = propertyToDelete.previousProperty;
1692 toStoreNode = propertyToDelete.nextProperty;
1693 relationType = PROPERTY_RELATION_NEXT;
1696 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1699 * Set the parent previous to the property to delete next
1701 newLinkProperty = propertyToDelete.nextProperty;
1705 * Link it for real...
1707 parentProperty.previousProperty = newLinkProperty;
1710 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1712 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1715 * Set the parent next to the property to delete next previous
1717 newLinkProperty = propertyToDelete.previousProperty;
1719 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1722 * We also need to find a storage for the other link, setup variables
1723 * to do this at the end...
1725 needToFindAPlaceholder = TRUE;
1726 storeNode = propertyToDelete.previousProperty;
1727 toStoreNode = propertyToDelete.nextProperty;
1728 relationType = PROPERTY_RELATION_NEXT;
1731 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1734 * Set the parent next to the property to delete next
1736 newLinkProperty = propertyToDelete.nextProperty;
1740 * Link it for real...
1742 parentProperty.nextProperty = newLinkProperty;
1744 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1746 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1749 * Set the parent dir to the property to delete previous
1751 newLinkProperty = propertyToDelete.previousProperty;
1753 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1756 * We also need to find a storage for the other link, setup variables
1757 * to do this at the end...
1759 needToFindAPlaceholder = TRUE;
1760 storeNode = propertyToDelete.previousProperty;
1761 toStoreNode = propertyToDelete.nextProperty;
1762 relationType = PROPERTY_RELATION_NEXT;
1765 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1768 * Set the parent dir to the property to delete next
1770 newLinkProperty = propertyToDelete.nextProperty;
1774 * Link it for real...
1776 parentProperty.dirProperty = newLinkProperty;
1780 * Write back the parent property
1782 res = StorageImpl_WriteProperty(
1783 This->ancestorStorage,
1784 parentPropertyId,
1785 &parentProperty);
1786 if(! res)
1788 return E_FAIL;
1792 * If a placeholder is required for the other link, then, find one and
1793 * get out of here...
1795 if (needToFindAPlaceholder)
1797 hr = findPlaceholder(
1798 This,
1799 toStoreNode,
1800 storeNode,
1801 relationType);
1804 return hr;
1808 /******************************************************************************
1809 * SetElementTimes (IStorage)
1811 HRESULT WINAPI StorageImpl_SetElementTimes(
1812 IStorage* iface,
1813 const OLECHAR *pwcsName,/* [string][in] */
1814 const FILETIME *pctime, /* [in] */
1815 const FILETIME *patime, /* [in] */
1816 const FILETIME *pmtime) /* [in] */
1818 return E_NOTIMPL;
1821 /******************************************************************************
1822 * SetStateBits (IStorage)
1824 HRESULT WINAPI StorageImpl_SetStateBits(
1825 IStorage* iface,
1826 DWORD grfStateBits,/* [in] */
1827 DWORD grfMask) /* [in] */
1829 return E_NOTIMPL;
1832 HRESULT StorageImpl_Construct(
1833 StorageImpl* This,
1834 HANDLE hFile,
1835 DWORD openFlags)
1837 HRESULT hr = S_OK;
1838 StgProperty currentProperty;
1839 BOOL readSucessful;
1840 ULONG currentPropertyIndex;
1842 if ( FAILED( validateSTGM(openFlags) ))
1843 return STG_E_INVALIDFLAG;
1845 memset(This, 0, sizeof(StorageImpl));
1848 * Initialize the virtual fgunction table.
1850 This->lpvtbl = &Storage32Impl_Vtbl;
1851 This->v_destructor = &StorageImpl_Destroy;
1854 * This is the top-level storage so initialize the ancester pointer
1855 * to this.
1857 This->ancestorStorage = This;
1860 * Initialize the physical support of the storage.
1862 This->hFile = hFile;
1865 * Initialize the big block cache.
1867 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
1868 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
1869 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
1870 openFlags,
1871 This->bigBlockSize);
1873 if (This->bigBlockFile == 0)
1874 return E_FAIL;
1876 if (openFlags & STGM_CREATE)
1878 ULARGE_INTEGER size;
1879 BYTE* bigBlockBuffer;
1882 * Initialize all header variables:
1883 * - The big block depot consists of one block and it is at block 0
1884 * - The properties start at block 1
1885 * - There is no small block depot
1887 memset( This->bigBlockDepotStart,
1888 BLOCK_UNUSED,
1889 sizeof(This->bigBlockDepotStart));
1891 This->bigBlockDepotCount = 1;
1892 This->bigBlockDepotStart[0] = 0;
1893 This->rootStartBlock = 1;
1894 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
1895 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
1896 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
1897 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
1898 This->extBigBlockDepotCount = 0;
1900 StorageImpl_SaveFileHeader(This);
1903 * Add one block for the big block depot and one block for the properties
1905 size.HighPart = 0;
1906 size.LowPart = This->bigBlockSize * 3;
1907 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
1910 * Initialize the big block depot
1912 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
1913 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
1914 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
1915 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
1916 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
1918 else
1921 * Load the header for the file.
1923 StorageImpl_LoadFileHeader(This);
1927 * There is no block depot cached yet.
1929 This->indexBlockDepotCached = 0xFFFFFFFF;
1932 * Create the block chain abstractions.
1934 This->rootBlockChain =
1935 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1937 This->smallBlockDepotChain = BlockChainStream_Construct(
1938 This,
1939 &This->smallBlockDepotStart,
1940 PROPERTY_NULL);
1943 * Write the root property
1945 if (openFlags & STGM_CREATE)
1947 StgProperty rootProp;
1949 * Initialize the property chain
1951 memset(&rootProp, 0, sizeof(rootProp));
1952 lstrcpyAtoW(rootProp.name, rootPropertyName);
1954 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
1955 rootProp.propertyType = PROPTYPE_ROOT;
1956 rootProp.previousProperty = PROPERTY_NULL;
1957 rootProp.nextProperty = PROPERTY_NULL;
1958 rootProp.dirProperty = PROPERTY_NULL;
1959 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
1960 rootProp.size.HighPart = 0;
1961 rootProp.size.LowPart = 0;
1963 StorageImpl_WriteProperty(This, 0, &rootProp);
1967 * Find the ID of the root int he property sets.
1969 currentPropertyIndex = 0;
1973 readSucessful = StorageImpl_ReadProperty(
1974 This,
1975 currentPropertyIndex,
1976 &currentProperty);
1978 if (readSucessful)
1980 if ( (currentProperty.sizeOfNameString != 0 ) &&
1981 (currentProperty.propertyType == PROPTYPE_ROOT) )
1983 This->rootPropertySetIndex = currentPropertyIndex;
1987 currentPropertyIndex++;
1989 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1991 if (!readSucessful)
1993 /* TODO CLEANUP */
1994 return E_FAIL;
1998 * Create the block chain abstraction for the small block root chain.
2000 This->smallBlockRootChain = BlockChainStream_Construct(
2001 This,
2002 NULL,
2003 This->rootPropertySetIndex);
2005 return hr;
2008 void StorageImpl_Destroy(
2009 StorageImpl* This)
2011 BlockChainStream_Destroy(This->smallBlockRootChain);
2012 BlockChainStream_Destroy(This->rootBlockChain);
2013 BlockChainStream_Destroy(This->smallBlockDepotChain);
2015 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2016 return;
2019 /******************************************************************************
2020 * Storage32Impl_GetNextFreeBigBlock
2022 * Returns the index of the next free big block.
2023 * If the big block depot is filled, this method will enlarge it.
2026 ULONG StorageImpl_GetNextFreeBigBlock(
2027 StorageImpl* This)
2029 ULONG depotBlockIndexPos;
2030 void *depotBuffer;
2031 ULONG depotBlockOffset;
2032 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2033 ULONG nextBlockIndex = BLOCK_SPECIAL;
2034 int depotIndex = 0;
2035 ULONG blockNoInSequence = 0;
2038 * Scan the entire big block depot until we find a block marked free
2040 while (nextBlockIndex != BLOCK_UNUSED)
2042 if (depotIndex < COUNT_BBDEPOTINHEADER)
2044 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2047 * Grow the primary depot.
2049 if (depotBlockIndexPos == BLOCK_UNUSED)
2051 depotBlockIndexPos = depotIndex*blocksPerDepot;
2054 * Add a block depot.
2056 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2057 This->bigBlockDepotCount++;
2058 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2061 * Flag it as a block depot.
2063 StorageImpl_SetNextBlockInChain(This,
2064 depotBlockIndexPos,
2065 BLOCK_SPECIAL);
2067 /* Save new header information.
2069 StorageImpl_SaveFileHeader(This);
2072 else
2074 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2076 if (depotBlockIndexPos == BLOCK_UNUSED)
2079 * Grow the extended depot.
2081 ULONG extIndex = BLOCK_UNUSED;
2082 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2083 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2085 if (extBlockOffset == 0)
2087 /* We need an extended block.
2089 extIndex = Storage32Impl_AddExtBlockDepot(This);
2090 This->extBigBlockDepotCount++;
2091 depotBlockIndexPos = extIndex + 1;
2093 else
2094 depotBlockIndexPos = depotIndex * blocksPerDepot;
2097 * Add a block depot and mark it in the extended block.
2099 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2100 This->bigBlockDepotCount++;
2101 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2103 /* Flag the block depot.
2105 StorageImpl_SetNextBlockInChain(This,
2106 depotBlockIndexPos,
2107 BLOCK_SPECIAL);
2109 /* If necessary, flag the extended depot block.
2111 if (extIndex != BLOCK_UNUSED)
2112 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2114 /* Save header information.
2116 StorageImpl_SaveFileHeader(This);
2120 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2122 if (depotBuffer != 0)
2124 depotBlockOffset = 0;
2126 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2127 ( nextBlockIndex != BLOCK_UNUSED))
2129 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2131 if (nextBlockIndex != BLOCK_UNUSED)
2132 blockNoInSequence++;
2134 depotBlockOffset += sizeof(ULONG);
2137 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2140 depotIndex++;
2143 return blockNoInSequence;
2146 /******************************************************************************
2147 * Storage32Impl_AddBlockDepot
2149 * This will create a depot block, essentially it is a block initialized
2150 * to BLOCK_UNUSEDs.
2152 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2154 BYTE* blockBuffer;
2156 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2159 * Initialize blocks as free
2161 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2163 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2166 /******************************************************************************
2167 * Storage32Impl_GetExtDepotBlock
2169 * Returns the index of the block that corresponds to the specified depot
2170 * index. This method is only for depot indexes equal or greater than
2171 * COUNT_BBDEPOTINHEADER.
2173 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2175 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2176 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2177 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2178 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2179 ULONG blockIndex = BLOCK_UNUSED;
2180 ULONG extBlockIndex = This->extBigBlockDepotStart;
2182 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2184 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2185 return BLOCK_UNUSED;
2187 while (extBlockCount > 0)
2189 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2190 extBlockCount--;
2193 if (extBlockIndex != BLOCK_UNUSED)
2195 BYTE* depotBuffer;
2197 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2199 if (depotBuffer != 0)
2201 StorageUtl_ReadDWord(depotBuffer,
2202 extBlockOffset * sizeof(ULONG),
2203 &blockIndex);
2205 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2209 return blockIndex;
2212 /******************************************************************************
2213 * Storage32Impl_SetExtDepotBlock
2215 * Associates the specified block index to the specified depot index.
2216 * This method is only for depot indexes equal or greater than
2217 * COUNT_BBDEPOTINHEADER.
2219 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2220 ULONG depotIndex,
2221 ULONG blockIndex)
2223 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2224 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2225 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2226 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2227 ULONG extBlockIndex = This->extBigBlockDepotStart;
2229 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2231 while (extBlockCount > 0)
2233 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2234 extBlockCount--;
2237 if (extBlockIndex != BLOCK_UNUSED)
2239 BYTE* depotBuffer;
2241 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2243 if (depotBuffer != 0)
2245 StorageUtl_WriteDWord(depotBuffer,
2246 extBlockOffset * sizeof(ULONG),
2247 blockIndex);
2249 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2254 /******************************************************************************
2255 * Storage32Impl_AddExtBlockDepot
2257 * Creates an extended depot block.
2259 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2261 ULONG numExtBlocks = This->extBigBlockDepotCount;
2262 ULONG nextExtBlock = This->extBigBlockDepotStart;
2263 BYTE* depotBuffer = NULL;
2264 ULONG index = BLOCK_UNUSED;
2265 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2266 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2267 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2269 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2270 blocksPerDepotBlock;
2272 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2275 * The first extended block.
2277 This->extBigBlockDepotStart = index;
2279 else
2281 int i;
2283 * Follow the chain to the last one.
2285 for (i = 0; i < (numExtBlocks - 1); i++)
2287 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2291 * Add the new extended block to the chain.
2293 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2294 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2295 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2299 * Initialize this block.
2301 depotBuffer = StorageImpl_GetBigBlock(This, index);
2302 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2303 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2305 return index;
2308 /******************************************************************************
2309 * Storage32Impl_FreeBigBlock
2311 * This method will flag the specified block as free in the big block depot.
2313 void StorageImpl_FreeBigBlock(
2314 StorageImpl* This,
2315 ULONG blockIndex)
2317 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2320 /************************************************************************
2321 * Storage32Impl_GetNextBlockInChain
2323 * This method will retrieve the block index of the next big block in
2324 * in the chain.
2326 * Params: This - Pointer to the Storage object.
2327 * blockIndex - Index of the block to retrieve the chain
2328 * for.
2330 * Returns: This method returns the index of the next block in the chain.
2331 * It will return the constants:
2332 * BLOCK_SPECIAL - If the block given was not part of a
2333 * chain.
2334 * BLOCK_END_OF_CHAIN - If the block given was the last in
2335 * a chain.
2336 * BLOCK_UNUSED - If the block given was not past of a chain
2337 * and is available.
2338 * BLOCK_EXTBBDEPOT - This block is part of the extended
2339 * big block depot.
2341 * See Windows documentation for more details on IStorage methods.
2343 ULONG StorageImpl_GetNextBlockInChain(
2344 StorageImpl* This,
2345 ULONG blockIndex)
2347 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2348 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2349 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2350 ULONG nextBlockIndex = BLOCK_SPECIAL;
2351 void* depotBuffer;
2352 ULONG depotBlockIndexPos;
2354 assert(depotBlockCount < This->bigBlockDepotCount);
2357 * Cache the currently accessed depot block.
2359 if (depotBlockCount != This->indexBlockDepotCached)
2361 This->indexBlockDepotCached = depotBlockCount;
2363 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2365 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2367 else
2370 * We have to look in the extended depot.
2372 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2375 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2377 if (depotBuffer!=0)
2379 int index;
2381 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2383 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2384 This->blockDepotCached[index] = nextBlockIndex;
2387 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2391 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2393 return nextBlockIndex;
2396 /******************************************************************************
2397 * Storage32Impl_GetNextExtendedBlock
2399 * Given an extended block this method will return the next extended block.
2401 * NOTES:
2402 * The last ULONG of an extended block is the block index of the next
2403 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2404 * depot.
2406 * Return values:
2407 * - The index of the next extended block
2408 * - BLOCK_UNUSED: there is no next extended block.
2409 * - Any other return values denotes failure.
2411 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2413 ULONG nextBlockIndex = BLOCK_SPECIAL;
2414 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2415 void* depotBuffer;
2417 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2419 if (depotBuffer!=0)
2421 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2423 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2426 return nextBlockIndex;
2429 /******************************************************************************
2430 * Storage32Impl_SetNextBlockInChain
2432 * This method will write the index of the specified block's next block
2433 * in the big block depot.
2435 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2436 * do the following
2438 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2439 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2440 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2443 void StorageImpl_SetNextBlockInChain(
2444 StorageImpl* This,
2445 ULONG blockIndex,
2446 ULONG nextBlock)
2448 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2449 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2450 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2451 ULONG depotBlockIndexPos;
2452 void* depotBuffer;
2454 assert(depotBlockCount < This->bigBlockDepotCount);
2456 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2458 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2460 else
2463 * We have to look in the extended depot.
2465 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2468 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2470 if (depotBuffer!=0)
2472 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2473 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2477 * Update the cached block depot, if necessary.
2479 if (depotBlockCount == This->indexBlockDepotCached)
2481 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2485 /******************************************************************************
2486 * Storage32Impl_LoadFileHeader
2488 * This method will read in the file header, i.e. big block index -1.
2490 HRESULT StorageImpl_LoadFileHeader(
2491 StorageImpl* This)
2493 HRESULT hr = STG_E_FILENOTFOUND;
2494 void* headerBigBlock = NULL;
2495 int index;
2498 * Get a pointer to the big block of data containing the header.
2500 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2503 * Extract the information from the header.
2505 if (headerBigBlock!=0)
2508 * Check for the "magic number" signature and return an error if it is not
2509 * found.
2511 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2513 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2514 return STG_E_OLDFORMAT;
2517 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2519 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2520 return STG_E_INVALIDHEADER;
2523 StorageUtl_ReadWord(
2524 headerBigBlock,
2525 OFFSET_BIGBLOCKSIZEBITS,
2526 &This->bigBlockSizeBits);
2528 StorageUtl_ReadWord(
2529 headerBigBlock,
2530 OFFSET_SMALLBLOCKSIZEBITS,
2531 &This->smallBlockSizeBits);
2533 StorageUtl_ReadDWord(
2534 headerBigBlock,
2535 OFFSET_BBDEPOTCOUNT,
2536 &This->bigBlockDepotCount);
2538 StorageUtl_ReadDWord(
2539 headerBigBlock,
2540 OFFSET_ROOTSTARTBLOCK,
2541 &This->rootStartBlock);
2543 StorageUtl_ReadDWord(
2544 headerBigBlock,
2545 OFFSET_SBDEPOTSTART,
2546 &This->smallBlockDepotStart);
2548 StorageUtl_ReadDWord(
2549 headerBigBlock,
2550 OFFSET_EXTBBDEPOTSTART,
2551 &This->extBigBlockDepotStart);
2553 StorageUtl_ReadDWord(
2554 headerBigBlock,
2555 OFFSET_EXTBBDEPOTCOUNT,
2556 &This->extBigBlockDepotCount);
2558 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2560 StorageUtl_ReadDWord(
2561 headerBigBlock,
2562 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2563 &(This->bigBlockDepotStart[index]));
2567 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2569 if ((1 << 2) == 4)
2571 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2572 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2574 else
2576 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2577 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2581 * Right now, the code is making some assumptions about the size of the
2582 * blocks, just make sure they are what we're expecting.
2584 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2585 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2588 * Release the block.
2590 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2593 return hr;
2596 /******************************************************************************
2597 * Storage32Impl_SaveFileHeader
2599 * This method will save to the file the header, i.e. big block -1.
2601 void StorageImpl_SaveFileHeader(
2602 StorageImpl* This)
2604 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2605 int index;
2606 BOOL success;
2609 * Get a pointer to the big block of data containing the header.
2611 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2614 * If the block read failed, the file is probably new.
2616 if (!success)
2619 * Initialize for all unknown fields.
2621 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2624 * Initialize the magic number.
2626 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2629 * And a bunch of things we don't know what they mean
2631 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2632 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2633 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2634 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2635 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2639 * Write the information to the header.
2641 if (headerBigBlock!=0)
2643 StorageUtl_WriteWord(
2644 headerBigBlock,
2645 OFFSET_BIGBLOCKSIZEBITS,
2646 This->bigBlockSizeBits);
2648 StorageUtl_WriteWord(
2649 headerBigBlock,
2650 OFFSET_SMALLBLOCKSIZEBITS,
2651 This->smallBlockSizeBits);
2653 StorageUtl_WriteDWord(
2654 headerBigBlock,
2655 OFFSET_BBDEPOTCOUNT,
2656 This->bigBlockDepotCount);
2658 StorageUtl_WriteDWord(
2659 headerBigBlock,
2660 OFFSET_ROOTSTARTBLOCK,
2661 This->rootStartBlock);
2663 StorageUtl_WriteDWord(
2664 headerBigBlock,
2665 OFFSET_SBDEPOTSTART,
2666 This->smallBlockDepotStart);
2668 StorageUtl_WriteDWord(
2669 headerBigBlock,
2670 OFFSET_EXTBBDEPOTSTART,
2671 This->extBigBlockDepotStart);
2673 StorageUtl_WriteDWord(
2674 headerBigBlock,
2675 OFFSET_EXTBBDEPOTCOUNT,
2676 This->extBigBlockDepotCount);
2678 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2680 StorageUtl_WriteDWord(
2681 headerBigBlock,
2682 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2683 (This->bigBlockDepotStart[index]));
2688 * Write the big block back to the file.
2690 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2693 /******************************************************************************
2694 * Storage32Impl_ReadProperty
2696 * This method will read the specified property from the property chain.
2698 BOOL StorageImpl_ReadProperty(
2699 StorageImpl* This,
2700 ULONG index,
2701 StgProperty* buffer)
2703 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2704 ULARGE_INTEGER offsetInPropSet;
2705 BOOL readSucessful;
2706 ULONG bytesRead;
2708 offsetInPropSet.HighPart = 0;
2709 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2711 readSucessful = BlockChainStream_ReadAt(
2712 This->rootBlockChain,
2713 offsetInPropSet,
2714 PROPSET_BLOCK_SIZE,
2715 currentProperty,
2716 &bytesRead);
2718 if (readSucessful)
2720 memset(buffer->name, 0, sizeof(buffer->name));
2721 memcpy(
2722 buffer->name,
2723 currentProperty+OFFSET_PS_NAME,
2724 PROPERTY_NAME_BUFFER_LEN );
2726 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2728 StorageUtl_ReadWord(
2729 currentProperty,
2730 OFFSET_PS_NAMELENGTH,
2731 &buffer->sizeOfNameString);
2733 StorageUtl_ReadDWord(
2734 currentProperty,
2735 OFFSET_PS_PREVIOUSPROP,
2736 &buffer->previousProperty);
2738 StorageUtl_ReadDWord(
2739 currentProperty,
2740 OFFSET_PS_NEXTPROP,
2741 &buffer->nextProperty);
2743 StorageUtl_ReadDWord(
2744 currentProperty,
2745 OFFSET_PS_DIRPROP,
2746 &buffer->dirProperty);
2748 StorageUtl_ReadGUID(
2749 currentProperty,
2750 OFFSET_PS_GUID,
2751 &buffer->propertyUniqueID);
2753 StorageUtl_ReadDWord(
2754 currentProperty,
2755 OFFSET_PS_TSS1,
2756 &buffer->timeStampS1);
2758 StorageUtl_ReadDWord(
2759 currentProperty,
2760 OFFSET_PS_TSD1,
2761 &buffer->timeStampD1);
2763 StorageUtl_ReadDWord(
2764 currentProperty,
2765 OFFSET_PS_TSS2,
2766 &buffer->timeStampS2);
2768 StorageUtl_ReadDWord(
2769 currentProperty,
2770 OFFSET_PS_TSD2,
2771 &buffer->timeStampD2);
2773 StorageUtl_ReadDWord(
2774 currentProperty,
2775 OFFSET_PS_STARTBLOCK,
2776 &buffer->startingBlock);
2778 StorageUtl_ReadDWord(
2779 currentProperty,
2780 OFFSET_PS_SIZE,
2781 &buffer->size.LowPart);
2783 buffer->size.HighPart = 0;
2786 return readSucessful;
2789 /*********************************************************************
2790 * Write the specified property into the property chain
2792 BOOL StorageImpl_WriteProperty(
2793 StorageImpl* This,
2794 ULONG index,
2795 StgProperty* buffer)
2797 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2798 ULARGE_INTEGER offsetInPropSet;
2799 BOOL writeSucessful;
2800 ULONG bytesWritten;
2802 offsetInPropSet.HighPart = 0;
2803 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2805 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2807 memcpy(
2808 currentProperty + OFFSET_PS_NAME,
2809 buffer->name,
2810 PROPERTY_NAME_BUFFER_LEN );
2812 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2815 * Reassign the size in case of mistake....
2817 buffer->sizeOfNameString = (lstrlenW(buffer->name)+1) * sizeof(WCHAR);
2819 StorageUtl_WriteWord(
2820 currentProperty,
2821 OFFSET_PS_NAMELENGTH,
2822 buffer->sizeOfNameString);
2824 StorageUtl_WriteDWord(
2825 currentProperty,
2826 OFFSET_PS_PREVIOUSPROP,
2827 buffer->previousProperty);
2829 StorageUtl_WriteDWord(
2830 currentProperty,
2831 OFFSET_PS_NEXTPROP,
2832 buffer->nextProperty);
2834 StorageUtl_WriteDWord(
2835 currentProperty,
2836 OFFSET_PS_DIRPROP,
2837 buffer->dirProperty);
2839 StorageUtl_WriteGUID(
2840 currentProperty,
2841 OFFSET_PS_GUID,
2842 &buffer->propertyUniqueID);
2844 StorageUtl_WriteDWord(
2845 currentProperty,
2846 OFFSET_PS_TSS1,
2847 buffer->timeStampS1);
2849 StorageUtl_WriteDWord(
2850 currentProperty,
2851 OFFSET_PS_TSD1,
2852 buffer->timeStampD1);
2854 StorageUtl_WriteDWord(
2855 currentProperty,
2856 OFFSET_PS_TSS2,
2857 buffer->timeStampS2);
2859 StorageUtl_WriteDWord(
2860 currentProperty,
2861 OFFSET_PS_TSD2,
2862 buffer->timeStampD2);
2864 StorageUtl_WriteDWord(
2865 currentProperty,
2866 OFFSET_PS_STARTBLOCK,
2867 buffer->startingBlock);
2869 StorageUtl_WriteDWord(
2870 currentProperty,
2871 OFFSET_PS_SIZE,
2872 buffer->size.LowPart);
2874 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2875 offsetInPropSet,
2876 PROPSET_BLOCK_SIZE,
2877 currentProperty,
2878 &bytesWritten);
2879 return writeSucessful;
2882 BOOL StorageImpl_ReadBigBlock(
2883 StorageImpl* This,
2884 ULONG blockIndex,
2885 void* buffer)
2887 void* bigBlockBuffer;
2889 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2891 if (bigBlockBuffer!=0)
2893 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2895 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2897 return TRUE;
2900 return FALSE;
2903 BOOL StorageImpl_WriteBigBlock(
2904 StorageImpl* This,
2905 ULONG blockIndex,
2906 void* buffer)
2908 void* bigBlockBuffer;
2910 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2912 if (bigBlockBuffer!=0)
2914 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2916 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2918 return TRUE;
2921 return FALSE;
2924 void* StorageImpl_GetROBigBlock(
2925 StorageImpl* This,
2926 ULONG blockIndex)
2928 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2931 void* StorageImpl_GetBigBlock(
2932 StorageImpl* This,
2933 ULONG blockIndex)
2935 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2938 void StorageImpl_ReleaseBigBlock(
2939 StorageImpl* This,
2940 void* pBigBlock)
2942 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2945 /******************************************************************************
2946 * Storage32Impl_SmallBlocksToBigBlocks
2948 * This method will convert a small block chain to a big block chain.
2949 * The small block chain will be destroyed.
2951 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2952 StorageImpl* This,
2953 SmallBlockChainStream** ppsbChain)
2955 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2956 ULARGE_INTEGER size, offset;
2957 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
2958 ULONG propertyIndex;
2959 BOOL successRead, successWrite;
2960 StgProperty chainProperty;
2961 BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2962 BlockChainStream *bbTempChain = NULL;
2963 BlockChainStream *bigBlockChain = NULL;
2966 * Create a temporary big block chain that doesn't have
2967 * an associated property. This temporary chain will be
2968 * used to copy data from small blocks to big blocks.
2970 bbTempChain = BlockChainStream_Construct(This,
2971 &bbHeadOfChain,
2972 PROPERTY_NULL);
2975 * Grow the big block chain.
2977 size = SmallBlockChainStream_GetSize(*ppsbChain);
2978 BlockChainStream_SetSize(bbTempChain, size);
2981 * Copy the contents of the small block chain to the big block chain
2982 * by small block size increments.
2984 offset.LowPart = 0;
2985 offset.HighPart = 0;
2986 cbTotalRead = 0;
2987 cbTotalWritten = 0;
2991 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
2992 offset,
2993 sizeof(buffer),
2994 buffer,
2995 &cbRead);
2996 cbTotalRead += cbRead;
2998 successWrite = BlockChainStream_WriteAt(bbTempChain,
2999 offset,
3000 cbRead,
3001 buffer,
3002 &cbWritten);
3003 cbTotalWritten += cbWritten;
3005 offset.LowPart += This->smallBlockSize;
3007 } while (successRead && successWrite);
3009 assert(cbTotalRead == cbTotalWritten);
3012 * Destroy the small block chain.
3014 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3015 size.HighPart = 0;
3016 size.LowPart = 0;
3017 SmallBlockChainStream_SetSize(*ppsbChain, size);
3018 SmallBlockChainStream_Destroy(*ppsbChain);
3019 *ppsbChain = 0;
3022 * Change the property information. This chain is now a big block chain
3023 * and it doesn't reside in the small blocks chain anymore.
3025 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3027 chainProperty.startingBlock = bbHeadOfChain;
3029 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3032 * Destroy the temporary propertyless big block chain.
3033 * Create a new big block chain associated with this property.
3035 BlockChainStream_Destroy(bbTempChain);
3036 bigBlockChain = BlockChainStream_Construct(This,
3037 NULL,
3038 propertyIndex);
3040 return bigBlockChain;
3043 /******************************************************************************
3044 ** Storage32InternalImpl implementation
3047 StorageInternalImpl* StorageInternalImpl_Construct(
3048 StorageImpl* ancestorStorage,
3049 ULONG rootPropertyIndex)
3051 StorageInternalImpl* newStorage;
3054 * Allocate space for the new storage object
3056 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3058 if (newStorage!=0)
3060 memset(newStorage, 0, sizeof(StorageInternalImpl));
3063 * Initialize the virtual function table.
3065 newStorage->lpvtbl = &Storage32InternalImpl_Vtbl;
3066 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3069 * Keep the ancestor storage pointer and nail a reference to it.
3071 newStorage->ancestorStorage = ancestorStorage;
3072 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3075 * Keep the index of the root property set for this storage,
3077 newStorage->rootPropertySetIndex = rootPropertyIndex;
3079 return newStorage;
3082 return 0;
3085 void StorageInternalImpl_Destroy(
3086 StorageInternalImpl* This)
3088 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3089 HeapFree(GetProcessHeap(), 0, This);
3092 /******************************************************************************
3094 ** Storage32InternalImpl_Commit
3096 ** The non-root storages cannot be opened in transacted mode thus this function
3097 ** does nothing.
3099 HRESULT WINAPI StorageInternalImpl_Commit(
3100 IStorage* iface,
3101 DWORD grfCommitFlags) /* [in] */
3103 return S_OK;
3106 /******************************************************************************
3108 ** Storage32InternalImpl_Revert
3110 ** The non-root storages cannot be opened in transacted mode thus this function
3111 ** does nothing.
3113 HRESULT WINAPI StorageInternalImpl_Revert(
3114 IStorage* iface)
3116 return S_OK;
3119 /******************************************************************************
3120 ** IEnumSTATSTGImpl implementation
3123 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3124 StorageImpl* parentStorage,
3125 ULONG firstPropertyNode)
3127 IEnumSTATSTGImpl* newEnumeration;
3129 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3131 if (newEnumeration!=0)
3134 * Set-up the virtual function table and reference count.
3136 newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
3137 newEnumeration->ref = 0;
3140 * We want to nail-down the reference to the storage in case the
3141 * enumeration out-lives the storage in the client application.
3143 newEnumeration->parentStorage = parentStorage;
3144 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3146 newEnumeration->firstPropertyNode = firstPropertyNode;
3149 * Initialize the search stack
3151 newEnumeration->stackSize = 0;
3152 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3153 newEnumeration->stackToVisit =
3154 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3157 * Make sure the current node of the iterator is the first one.
3159 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3162 return newEnumeration;
3165 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3167 IStorage_Release((IStorage*)This->parentStorage);
3168 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3169 HeapFree(GetProcessHeap(), 0, This);
3172 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3173 IEnumSTATSTG* iface,
3174 REFIID riid,
3175 void** ppvObject)
3177 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3180 * Perform a sanity check on the parameters.
3182 if (ppvObject==0)
3183 return E_INVALIDARG;
3186 * Initialize the return parameter.
3188 *ppvObject = 0;
3191 * Compare the riid with the interface IDs implemented by this object.
3193 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3195 *ppvObject = (IEnumSTATSTG*)This;
3197 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3199 *ppvObject = (IEnumSTATSTG*)This;
3203 * Check that we obtained an interface.
3205 if ((*ppvObject)==0)
3206 return E_NOINTERFACE;
3209 * Query Interface always increases the reference count by one when it is
3210 * successful
3212 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3214 return S_OK;
3217 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3218 IEnumSTATSTG* iface)
3220 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3222 This->ref++;
3223 return This->ref;
3226 ULONG WINAPI IEnumSTATSTGImpl_Release(
3227 IEnumSTATSTG* iface)
3229 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3231 ULONG newRef;
3233 This->ref--;
3234 newRef = This->ref;
3237 * If the reference count goes down to 0, perform suicide.
3239 if (newRef==0)
3241 IEnumSTATSTGImpl_Destroy(This);
3244 return newRef;;
3247 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3248 IEnumSTATSTG* iface,
3249 ULONG celt,
3250 STATSTG* rgelt,
3251 ULONG* pceltFetched)
3253 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3255 StgProperty currentProperty;
3256 STATSTG* currentReturnStruct = rgelt;
3257 ULONG objectFetched = 0;
3258 ULONG currentSearchNode;
3261 * Perform a sanity check on the parameters.
3263 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3264 return E_INVALIDARG;
3267 * To avoid the special case, get another pointer to a ULONG value if
3268 * the caller didn't supply one.
3270 if (pceltFetched==0)
3271 pceltFetched = &objectFetched;
3274 * Start the iteration, we will iterate until we hit the end of the
3275 * linked list or until we hit the number of items to iterate through
3277 *pceltFetched = 0;
3280 * Start with the node at the top of the stack.
3282 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3284 while ( ( *pceltFetched < celt) &&
3285 ( currentSearchNode!=PROPERTY_NULL) )
3288 * Remove the top node from the stack
3290 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3293 * Read the property from the storage.
3295 StorageImpl_ReadProperty(This->parentStorage,
3296 currentSearchNode,
3297 &currentProperty);
3300 * Copy the information to the return buffer.
3302 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3303 &currentProperty,
3304 STATFLAG_DEFAULT);
3307 * Step to the next item in the iteration
3309 (*pceltFetched)++;
3310 currentReturnStruct++;
3313 * Push the next search node in the search stack.
3315 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3318 * continue the iteration.
3320 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3323 if (*pceltFetched == celt)
3324 return S_OK;
3326 return S_FALSE;
3330 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3331 IEnumSTATSTG* iface,
3332 ULONG celt)
3334 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3336 StgProperty currentProperty;
3337 ULONG objectFetched = 0;
3338 ULONG currentSearchNode;
3341 * Start with the node at the top of the stack.
3343 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3345 while ( (objectFetched < celt) &&
3346 (currentSearchNode!=PROPERTY_NULL) )
3349 * Remove the top node from the stack
3351 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3354 * Read the property from the storage.
3356 StorageImpl_ReadProperty(This->parentStorage,
3357 currentSearchNode,
3358 &currentProperty);
3361 * Step to the next item in the iteration
3363 objectFetched++;
3366 * Push the next search node in the search stack.
3368 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3371 * continue the iteration.
3373 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3376 if (objectFetched == celt)
3377 return S_OK;
3379 return S_FALSE;
3382 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3383 IEnumSTATSTG* iface)
3385 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3387 StgProperty rootProperty;
3388 BOOL readSucessful;
3391 * Re-initialize the search stack to an empty stack
3393 This->stackSize = 0;
3396 * Read the root property from the storage.
3398 readSucessful = StorageImpl_ReadProperty(
3399 This->parentStorage,
3400 This->firstPropertyNode,
3401 &rootProperty);
3403 if (readSucessful)
3405 assert(rootProperty.sizeOfNameString!=0);
3408 * Push the search node in the search stack.
3410 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3413 return S_OK;
3416 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3417 IEnumSTATSTG* iface,
3418 IEnumSTATSTG** ppenum)
3420 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3422 IEnumSTATSTGImpl* newClone;
3425 * Perform a sanity check on the parameters.
3427 if (ppenum==0)
3428 return E_INVALIDARG;
3430 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3431 This->firstPropertyNode);
3435 * The new clone enumeration must point to the same current node as
3436 * the ole one.
3438 newClone->stackSize = This->stackSize ;
3439 newClone->stackMaxSize = This->stackMaxSize ;
3440 newClone->stackToVisit =
3441 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3443 memcpy(
3444 newClone->stackToVisit,
3445 This->stackToVisit,
3446 sizeof(ULONG) * newClone->stackSize);
3448 *ppenum = (IEnumSTATSTG*)newClone;
3451 * Don't forget to nail down a reference to the clone before
3452 * returning it.
3454 IEnumSTATSTGImpl_AddRef(*ppenum);
3456 return S_OK;
3459 INT IEnumSTATSTGImpl_FindParentProperty(
3460 IEnumSTATSTGImpl *This,
3461 ULONG childProperty,
3462 StgProperty *currentProperty,
3463 ULONG *thisNodeId)
3465 ULONG currentSearchNode;
3466 ULONG foundNode;
3469 * To avoid the special case, get another pointer to a ULONG value if
3470 * the caller didn't supply one.
3472 if (thisNodeId==0)
3473 thisNodeId = &foundNode;
3476 * Start with the node at the top of the stack.
3478 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3481 while (currentSearchNode!=PROPERTY_NULL)
3484 * Store the current node in the returned parameters
3486 *thisNodeId = currentSearchNode;
3489 * Remove the top node from the stack
3491 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3494 * Read the property from the storage.
3496 StorageImpl_ReadProperty(
3497 This->parentStorage,
3498 currentSearchNode,
3499 currentProperty);
3501 if (currentProperty->previousProperty == childProperty)
3502 return PROPERTY_RELATION_PREVIOUS;
3504 else if (currentProperty->nextProperty == childProperty)
3505 return PROPERTY_RELATION_NEXT;
3507 else if (currentProperty->dirProperty == childProperty)
3508 return PROPERTY_RELATION_DIR;
3511 * Push the next search node in the search stack.
3513 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3516 * continue the iteration.
3518 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3521 return PROPERTY_NULL;
3524 ULONG IEnumSTATSTGImpl_FindProperty(
3525 IEnumSTATSTGImpl* This,
3526 const OLECHAR* lpszPropName,
3527 StgProperty* currentProperty)
3529 ULONG currentSearchNode;
3532 * Start with the node at the top of the stack.
3534 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3536 while (currentSearchNode!=PROPERTY_NULL)
3539 * Remove the top node from the stack
3541 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3544 * Read the property from the storage.
3546 StorageImpl_ReadProperty(This->parentStorage,
3547 currentSearchNode,
3548 currentProperty);
3550 if ( propertyNameCmp(
3551 (OLECHAR*)currentProperty->name,
3552 (OLECHAR*)lpszPropName) == 0)
3553 return currentSearchNode;
3556 * Push the next search node in the search stack.
3558 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3561 * continue the iteration.
3563 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3566 return PROPERTY_NULL;
3569 void IEnumSTATSTGImpl_PushSearchNode(
3570 IEnumSTATSTGImpl* This,
3571 ULONG nodeToPush)
3573 StgProperty rootProperty;
3574 BOOL readSucessful;
3577 * First, make sure we're not trying to push an unexisting node.
3579 if (nodeToPush==PROPERTY_NULL)
3580 return;
3583 * First push the node to the stack
3585 if (This->stackSize == This->stackMaxSize)
3587 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3589 This->stackToVisit = HeapReAlloc(
3590 GetProcessHeap(),
3592 This->stackToVisit,
3593 sizeof(ULONG) * This->stackMaxSize);
3596 This->stackToVisit[This->stackSize] = nodeToPush;
3597 This->stackSize++;
3600 * Read the root property from the storage.
3602 readSucessful = StorageImpl_ReadProperty(
3603 This->parentStorage,
3604 nodeToPush,
3605 &rootProperty);
3607 if (readSucessful)
3609 assert(rootProperty.sizeOfNameString!=0);
3612 * Push the previous search node in the search stack.
3614 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3618 ULONG IEnumSTATSTGImpl_PopSearchNode(
3619 IEnumSTATSTGImpl* This,
3620 BOOL remove)
3622 ULONG topNode;
3624 if (This->stackSize == 0)
3625 return PROPERTY_NULL;
3627 topNode = This->stackToVisit[This->stackSize-1];
3629 if (remove)
3630 This->stackSize--;
3632 return topNode;
3635 /******************************************************************************
3636 ** StorageUtl implementation
3639 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3641 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3644 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3646 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3649 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3651 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3654 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3656 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3659 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3661 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3662 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3663 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3665 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3668 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3670 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3671 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3672 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3674 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3677 void StorageUtl_CopyPropertyToSTATSTG(
3678 STATSTG* destination,
3679 StgProperty* source,
3680 int statFlags)
3683 * The copy of the string occurs only when the flag is not set
3685 if ((statFlags & STATFLAG_NONAME) != 0)
3687 destination->pwcsName = 0;
3689 else
3691 destination->pwcsName =
3692 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3694 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3697 switch (source->propertyType)
3699 case PROPTYPE_STORAGE:
3700 case PROPTYPE_ROOT:
3701 destination->type = STGTY_STORAGE;
3702 break;
3703 case PROPTYPE_STREAM:
3704 destination->type = STGTY_STREAM;
3705 break;
3706 default:
3707 destination->type = STGTY_STREAM;
3708 break;
3711 destination->cbSize = source->size;
3713 currentReturnStruct->mtime = {0}; TODO
3714 currentReturnStruct->ctime = {0};
3715 currentReturnStruct->atime = {0};
3717 destination->grfMode = 0;
3718 destination->grfLocksSupported = 0;
3719 destination->clsid = source->propertyUniqueID;
3720 destination->grfStateBits = 0;
3721 destination->reserved = 0;
3724 /******************************************************************************
3725 ** BlockChainStream implementation
3728 BlockChainStream* BlockChainStream_Construct(
3729 StorageImpl* parentStorage,
3730 ULONG* headOfStreamPlaceHolder,
3731 ULONG propertyIndex)
3733 BlockChainStream* newStream;
3735 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3737 newStream->parentStorage = parentStorage;
3738 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3739 newStream->ownerPropertyIndex = propertyIndex;
3741 return newStream;
3744 void BlockChainStream_Destroy(BlockChainStream* This)
3746 HeapFree(GetProcessHeap(), 0, This);
3749 /******************************************************************************
3750 * BlockChainStream_GetHeadOfChain
3752 * Returns the head of this stream chain.
3753 * Some special chains don't have properties, their heads are kept in
3754 * This->headOfStreamPlaceHolder.
3757 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3759 StgProperty chainProperty;
3760 BOOL readSucessful;
3762 if (This->headOfStreamPlaceHolder != 0)
3763 return *(This->headOfStreamPlaceHolder);
3765 if (This->ownerPropertyIndex != PROPERTY_NULL)
3767 readSucessful = StorageImpl_ReadProperty(
3768 This->parentStorage,
3769 This->ownerPropertyIndex,
3770 &chainProperty);
3772 if (readSucessful)
3774 return chainProperty.startingBlock;
3778 return BLOCK_END_OF_CHAIN;
3781 /******************************************************************************
3782 * BlockChainStream_GetCount
3784 * Returns the number of blocks that comprises this chain.
3785 * This is not the size of the stream as the last block may not be full!
3788 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3790 ULONG blockIndex;
3791 ULONG count = 0;
3793 blockIndex = BlockChainStream_GetHeadOfChain(This);
3795 while (blockIndex != BLOCK_END_OF_CHAIN)
3797 count++;
3799 blockIndex = StorageImpl_GetNextBlockInChain(
3800 This->parentStorage,
3801 blockIndex);
3804 return count;
3807 /******************************************************************************
3808 * BlockChainStream_ReadAt
3810 * Reads a specified number of bytes from this chain at the specified offset.
3811 * bytesRead may be NULL.
3812 * Failure will be returned if the specified number of bytes has not been read.
3814 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
3815 ULARGE_INTEGER offset,
3816 ULONG size,
3817 void* buffer,
3818 ULONG* bytesRead)
3820 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3821 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3822 ULONG bytesToReadInBuffer;
3823 ULONG blockIndex;
3824 BYTE* bufferWalker;
3825 BYTE* bigBlockBuffer;
3828 * Find the first block in the stream that contains part of the buffer.
3830 blockIndex = BlockChainStream_GetHeadOfChain(This);
3832 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3834 blockIndex =
3835 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3837 blockNoInSequence--;
3841 * Start reading the buffer.
3843 *bytesRead = 0;
3844 bufferWalker = buffer;
3846 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3849 * Calculate how many bytes we can copy from this big block.
3851 bytesToReadInBuffer =
3852 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3855 * Copy those bytes to the buffer
3857 bigBlockBuffer =
3858 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
3860 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3862 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3865 * Step to the next big block.
3867 blockIndex =
3868 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3870 bufferWalker += bytesToReadInBuffer;
3871 size -= bytesToReadInBuffer;
3872 *bytesRead += bytesToReadInBuffer;
3873 offsetInBlock = 0; /* There is no offset on the next block */
3877 return (size == 0);
3880 /******************************************************************************
3881 * BlockChainStream_WriteAt
3883 * Writes the specified number of bytes to this chain at the specified offset.
3884 * bytesWritten may be NULL.
3885 * Will fail if not all specified number of bytes have been written.
3887 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
3888 ULARGE_INTEGER offset,
3889 ULONG size,
3890 const void* buffer,
3891 ULONG* bytesWritten)
3893 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3894 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3895 ULONG bytesToWrite;
3896 ULONG blockIndex;
3897 BYTE* bufferWalker;
3898 BYTE* bigBlockBuffer;
3901 * Find the first block in the stream that contains part of the buffer.
3903 blockIndex = BlockChainStream_GetHeadOfChain(This);
3905 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3907 blockIndex =
3908 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3910 blockNoInSequence--;
3914 * Here, I'm casting away the constness on the buffer variable
3915 * This is OK since we don't intend to modify that buffer.
3917 *bytesWritten = 0;
3918 bufferWalker = (BYTE*)buffer;
3920 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3923 * Calculate how many bytes we can copy from this big block.
3925 bytesToWrite =
3926 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3929 * Copy those bytes to the buffer
3931 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
3933 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
3935 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3938 * Step to the next big block.
3940 blockIndex =
3941 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3943 bufferWalker += bytesToWrite;
3944 size -= bytesToWrite;
3945 *bytesWritten += bytesToWrite;
3946 offsetInBlock = 0; /* There is no offset on the next block */
3949 return (size == 0);
3952 /******************************************************************************
3953 * BlockChainStream_Shrink
3955 * Shrinks this chain in the big block depot.
3957 BOOL BlockChainStream_Shrink(BlockChainStream* This,
3958 ULARGE_INTEGER newSize)
3960 ULONG blockIndex, extraBlock;
3961 ULONG numBlocks;
3962 ULONG count = 1;
3965 * Figure out how many blocks are needed to contain the new size
3967 numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3969 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3970 numBlocks++;
3972 blockIndex = BlockChainStream_GetHeadOfChain(This);
3975 * Go to the new end of chain
3977 while (count < numBlocks)
3979 blockIndex =
3980 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3982 count++;
3985 /* Get the next block before marking the new end */
3986 extraBlock =
3987 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
3989 /* Mark the new end of chain */
3990 StorageImpl_SetNextBlockInChain(
3991 This->parentStorage,
3992 blockIndex,
3993 BLOCK_END_OF_CHAIN);
3996 * Mark the extra blocks as free
3998 while (extraBlock != BLOCK_END_OF_CHAIN)
4000 blockIndex =
4001 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4003 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4004 extraBlock = blockIndex;
4007 return TRUE;
4010 /******************************************************************************
4011 * BlockChainStream_Enlarge
4013 * Grows this chain in the big block depot.
4015 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4016 ULARGE_INTEGER newSize)
4018 ULONG blockIndex, currentBlock;
4019 ULONG newNumBlocks;
4020 ULONG oldNumBlocks = 0;
4022 blockIndex = BlockChainStream_GetHeadOfChain(This);
4025 * Empty chain. Create the head.
4027 if (blockIndex == BLOCK_END_OF_CHAIN)
4029 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4030 StorageImpl_SetNextBlockInChain(This->parentStorage,
4031 blockIndex,
4032 BLOCK_END_OF_CHAIN);
4034 if (This->headOfStreamPlaceHolder != 0)
4036 *(This->headOfStreamPlaceHolder) = blockIndex;
4038 else
4040 StgProperty chainProp;
4041 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4043 StorageImpl_ReadProperty(
4044 This->parentStorage,
4045 This->ownerPropertyIndex,
4046 &chainProp);
4048 chainProp.startingBlock = blockIndex;
4050 StorageImpl_WriteProperty(
4051 This->parentStorage,
4052 This->ownerPropertyIndex,
4053 &chainProp);
4057 currentBlock = blockIndex;
4060 * Figure out how many blocks are needed to contain this stream
4062 newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
4064 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
4065 newNumBlocks++;
4068 * Go to the current end of chain
4070 while (blockIndex != BLOCK_END_OF_CHAIN)
4072 oldNumBlocks++;
4073 currentBlock = blockIndex;
4075 blockIndex =
4076 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4080 * Add new blocks to the chain
4082 while (oldNumBlocks < newNumBlocks)
4084 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4086 StorageImpl_SetNextBlockInChain(
4087 This->parentStorage,
4088 currentBlock,
4089 blockIndex);
4091 StorageImpl_SetNextBlockInChain(
4092 This->parentStorage,
4093 blockIndex,
4094 BLOCK_END_OF_CHAIN);
4096 currentBlock = blockIndex;
4097 oldNumBlocks++;
4100 return TRUE;
4103 /******************************************************************************
4104 * BlockChainStream_SetSize
4106 * Sets the size of this stream. The big block depot will be updated.
4107 * The file will grow if we grow the chain.
4109 * TODO: Free the actual blocks in the file when we shrink the chain.
4110 * Currently, the blocks are still in the file. So the file size
4111 * doesn't shrink even if we shrink streams.
4113 BOOL BlockChainStream_SetSize(
4114 BlockChainStream* This,
4115 ULARGE_INTEGER newSize)
4117 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4119 if (newSize.LowPart == size.LowPart)
4120 return TRUE;
4122 if (newSize.LowPart < size.LowPart)
4124 BlockChainStream_Shrink(This, newSize);
4126 else
4128 ULARGE_INTEGER fileSize =
4129 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4131 ULONG diff = newSize.LowPart - size.LowPart;
4134 * Make sure the file stays a multiple of blocksize
4136 if ((diff % This->parentStorage->bigBlockSize) != 0)
4137 diff += (This->parentStorage->bigBlockSize -
4138 (diff % This->parentStorage->bigBlockSize) );
4140 fileSize.LowPart += diff;
4141 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4143 BlockChainStream_Enlarge(This, newSize);
4146 return TRUE;
4149 /******************************************************************************
4150 * BlockChainStream_GetSize
4152 * Returns the size of this chain.
4153 * Will return the block count if this chain doesn't have a property.
4155 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4157 StgProperty chainProperty;
4159 if(This->headOfStreamPlaceHolder == NULL)
4162 * This chain is a data stream read the property and return
4163 * the appropriate size
4165 StorageImpl_ReadProperty(
4166 This->parentStorage,
4167 This->ownerPropertyIndex,
4168 &chainProperty);
4170 return chainProperty.size;
4172 else
4175 * this chain is a chain that does not have a property, figure out the
4176 * size by making the product number of used blocks times the
4177 * size of them
4179 ULARGE_INTEGER result;
4180 result.HighPart = 0;
4182 result.LowPart =
4183 BlockChainStream_GetCount(This) *
4184 This->parentStorage->bigBlockSize;
4186 return result;
4190 /******************************************************************************
4191 ** SmallBlockChainStream implementation
4194 SmallBlockChainStream* SmallBlockChainStream_Construct(
4195 StorageImpl* parentStorage,
4196 ULONG propertyIndex)
4198 SmallBlockChainStream* newStream;
4200 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4202 newStream->parentStorage = parentStorage;
4203 newStream->ownerPropertyIndex = propertyIndex;
4205 return newStream;
4208 void SmallBlockChainStream_Destroy(
4209 SmallBlockChainStream* This)
4211 HeapFree(GetProcessHeap(), 0, This);
4214 /******************************************************************************
4215 * SmallBlockChainStream_GetHeadOfChain
4217 * Returns the head of this chain of small blocks.
4219 ULONG SmallBlockChainStream_GetHeadOfChain(
4220 SmallBlockChainStream* This)
4222 StgProperty chainProperty;
4223 BOOL readSucessful;
4225 if (This->ownerPropertyIndex)
4227 readSucessful = StorageImpl_ReadProperty(
4228 This->parentStorage,
4229 This->ownerPropertyIndex,
4230 &chainProperty);
4232 if (readSucessful)
4234 return chainProperty.startingBlock;
4239 return BLOCK_END_OF_CHAIN;
4242 /******************************************************************************
4243 * SmallBlockChainStream_GetNextBlockInChain
4245 * Returns the index of the next small block in this chain.
4247 * Return Values:
4248 * - BLOCK_END_OF_CHAIN: end of this chain
4249 * - BLOCK_UNUSED: small block 'blockIndex' is free
4251 ULONG SmallBlockChainStream_GetNextBlockInChain(
4252 SmallBlockChainStream* This,
4253 ULONG blockIndex)
4255 ULARGE_INTEGER offsetOfBlockInDepot;
4256 DWORD buffer;
4257 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4258 ULONG bytesRead;
4259 BOOL success;
4261 offsetOfBlockInDepot.HighPart = 0;
4262 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4265 * Read those bytes in the buffer from the small block file.
4267 success = BlockChainStream_ReadAt(
4268 This->parentStorage->smallBlockDepotChain,
4269 offsetOfBlockInDepot,
4270 sizeof(DWORD),
4271 &buffer,
4272 &bytesRead);
4274 if (success)
4276 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4279 return nextBlockInChain;
4282 /******************************************************************************
4283 * SmallBlockChainStream_SetNextBlockInChain
4285 * Writes the index of the next block of the specified block in the small
4286 * block depot.
4287 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4288 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4290 void SmallBlockChainStream_SetNextBlockInChain(
4291 SmallBlockChainStream* This,
4292 ULONG blockIndex,
4293 ULONG nextBlock)
4295 ULARGE_INTEGER offsetOfBlockInDepot;
4296 DWORD buffer;
4297 ULONG bytesWritten;
4299 offsetOfBlockInDepot.HighPart = 0;
4300 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4302 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4305 * Read those bytes in the buffer from the small block file.
4307 BlockChainStream_WriteAt(
4308 This->parentStorage->smallBlockDepotChain,
4309 offsetOfBlockInDepot,
4310 sizeof(DWORD),
4311 &buffer,
4312 &bytesWritten);
4315 /******************************************************************************
4316 * SmallBlockChainStream_FreeBlock
4318 * Flag small block 'blockIndex' as free in the small block depot.
4320 void SmallBlockChainStream_FreeBlock(
4321 SmallBlockChainStream* This,
4322 ULONG blockIndex)
4324 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4327 /******************************************************************************
4328 * SmallBlockChainStream_GetNextFreeBlock
4330 * Returns the index of a free small block. The small block depot will be
4331 * enlarged if necessary. The small block chain will also be enlarged if
4332 * necessary.
4334 ULONG SmallBlockChainStream_GetNextFreeBlock(
4335 SmallBlockChainStream* This)
4337 ULARGE_INTEGER offsetOfBlockInDepot;
4338 DWORD buffer;
4339 ULONG bytesRead;
4340 ULONG blockIndex = 0;
4341 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4342 BOOL success = TRUE;
4343 ULONG smallBlocksPerBigBlock;
4345 offsetOfBlockInDepot.HighPart = 0;
4348 * Scan the small block depot for a free block
4350 while (nextBlockIndex != BLOCK_UNUSED)
4352 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4354 success = BlockChainStream_ReadAt(
4355 This->parentStorage->smallBlockDepotChain,
4356 offsetOfBlockInDepot,
4357 sizeof(DWORD),
4358 &buffer,
4359 &bytesRead);
4362 * If we run out of space for the small block depot, enlarge it
4364 if (success)
4366 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4368 if (nextBlockIndex != BLOCK_UNUSED)
4369 blockIndex++;
4371 else
4373 ULONG count =
4374 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4376 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4377 ULONG nextBlock, newsbdIndex;
4378 BYTE* smallBlockDepot;
4380 nextBlock = sbdIndex;
4381 while (nextBlock != BLOCK_END_OF_CHAIN)
4383 sbdIndex = nextBlock;
4384 nextBlock =
4385 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4388 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4389 if (sbdIndex != BLOCK_END_OF_CHAIN)
4390 StorageImpl_SetNextBlockInChain(
4391 This->parentStorage,
4392 sbdIndex,
4393 newsbdIndex);
4395 StorageImpl_SetNextBlockInChain(
4396 This->parentStorage,
4397 newsbdIndex,
4398 BLOCK_END_OF_CHAIN);
4401 * Initialize all the small blocks to free
4403 smallBlockDepot =
4404 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4406 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4407 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4409 if (count == 0)
4412 * We have just created the small block depot.
4414 StgProperty rootProp;
4415 ULONG sbStartIndex;
4418 * Save it in the header
4420 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4421 StorageImpl_SaveFileHeader(This->parentStorage);
4424 * And allocate the first big block that will contain small blocks
4426 sbStartIndex =
4427 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4429 StorageImpl_SetNextBlockInChain(
4430 This->parentStorage,
4431 sbStartIndex,
4432 BLOCK_END_OF_CHAIN);
4434 StorageImpl_ReadProperty(
4435 This->parentStorage,
4436 This->parentStorage->rootPropertySetIndex,
4437 &rootProp);
4439 rootProp.startingBlock = sbStartIndex;
4440 rootProp.size.HighPart = 0;
4441 rootProp.size.LowPart = This->parentStorage->bigBlockSize;
4443 StorageImpl_WriteProperty(
4444 This->parentStorage,
4445 This->parentStorage->rootPropertySetIndex,
4446 &rootProp);
4451 smallBlocksPerBigBlock =
4452 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4455 * Verify if we have to allocate big blocks to contain small blocks
4457 if (blockIndex % smallBlocksPerBigBlock == 0)
4459 StgProperty rootProp;
4460 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4462 StorageImpl_ReadProperty(
4463 This->parentStorage,
4464 This->parentStorage->rootPropertySetIndex,
4465 &rootProp);
4467 if (rootProp.size.LowPart <
4468 (blocksRequired * This->parentStorage->bigBlockSize))
4470 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4472 BlockChainStream_SetSize(
4473 This->parentStorage->smallBlockRootChain,
4474 rootProp.size);
4476 StorageImpl_WriteProperty(
4477 This->parentStorage,
4478 This->parentStorage->rootPropertySetIndex,
4479 &rootProp);
4483 return blockIndex;
4486 /******************************************************************************
4487 * SmallBlockChainStream_ReadAt
4489 * Reads a specified number of bytes from this chain at the specified offset.
4490 * bytesRead may be NULL.
4491 * Failure will be returned if the specified number of bytes has not been read.
4493 BOOL SmallBlockChainStream_ReadAt(
4494 SmallBlockChainStream* This,
4495 ULARGE_INTEGER offset,
4496 ULONG size,
4497 void* buffer,
4498 ULONG* bytesRead)
4500 ULARGE_INTEGER offsetInBigBlockFile;
4501 ULONG blockNoInSequence =
4502 offset.LowPart / This->parentStorage->smallBlockSize;
4504 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4505 ULONG bytesToReadInBuffer;
4506 ULONG blockIndex;
4507 ULONG bytesReadFromBigBlockFile;
4508 BYTE* bufferWalker;
4511 * This should never happen on a small block file.
4513 assert(offset.HighPart==0);
4516 * Find the first block in the stream that contains part of the buffer.
4518 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4520 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4522 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4524 blockNoInSequence--;
4528 * Start reading the buffer.
4530 *bytesRead = 0;
4531 bufferWalker = buffer;
4533 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4536 * Calculate how many bytes we can copy from this small block.
4538 bytesToReadInBuffer =
4539 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4542 * Calculate the offset of the small block in the small block file.
4544 offsetInBigBlockFile.HighPart = 0;
4545 offsetInBigBlockFile.LowPart =
4546 blockIndex * This->parentStorage->smallBlockSize;
4548 offsetInBigBlockFile.LowPart += offsetInBlock;
4551 * Read those bytes in the buffer from the small block file.
4553 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4554 offsetInBigBlockFile,
4555 bytesToReadInBuffer,
4556 bufferWalker,
4557 &bytesReadFromBigBlockFile);
4559 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4562 * Step to the next big block.
4564 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4565 bufferWalker += bytesToReadInBuffer;
4566 size -= bytesToReadInBuffer;
4567 *bytesRead += bytesToReadInBuffer;
4568 offsetInBlock = 0; /* There is no offset on the next block */
4571 return (size == 0);
4574 /******************************************************************************
4575 * SmallBlockChainStream_WriteAt
4577 * Writes the specified number of bytes to this chain at the specified offset.
4578 * bytesWritten may be NULL.
4579 * Will fail if not all specified number of bytes have been written.
4581 BOOL SmallBlockChainStream_WriteAt(
4582 SmallBlockChainStream* This,
4583 ULARGE_INTEGER offset,
4584 ULONG size,
4585 const void* buffer,
4586 ULONG* bytesWritten)
4588 ULARGE_INTEGER offsetInBigBlockFile;
4589 ULONG blockNoInSequence =
4590 offset.LowPart / This->parentStorage->smallBlockSize;
4592 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4593 ULONG bytesToWriteInBuffer;
4594 ULONG blockIndex;
4595 ULONG bytesWrittenFromBigBlockFile;
4596 BYTE* bufferWalker;
4599 * This should never happen on a small block file.
4601 assert(offset.HighPart==0);
4604 * Find the first block in the stream that contains part of the buffer.
4606 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4608 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4610 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4612 blockNoInSequence--;
4616 * Start writing the buffer.
4618 * Here, I'm casting away the constness on the buffer variable
4619 * This is OK since we don't intend to modify that buffer.
4621 *bytesWritten = 0;
4622 bufferWalker = (BYTE*)buffer;
4623 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4626 * Calculate how many bytes we can copy to this small block.
4628 bytesToWriteInBuffer =
4629 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4632 * Calculate the offset of the small block in the small block file.
4634 offsetInBigBlockFile.HighPart = 0;
4635 offsetInBigBlockFile.LowPart =
4636 blockIndex * This->parentStorage->smallBlockSize;
4638 offsetInBigBlockFile.LowPart += offsetInBlock;
4641 * Write those bytes in the buffer to the small block file.
4643 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4644 offsetInBigBlockFile,
4645 bytesToWriteInBuffer,
4646 bufferWalker,
4647 &bytesWrittenFromBigBlockFile);
4649 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4652 * Step to the next big block.
4654 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4655 bufferWalker += bytesToWriteInBuffer;
4656 size -= bytesToWriteInBuffer;
4657 *bytesWritten += bytesToWriteInBuffer;
4658 offsetInBlock = 0; /* There is no offset on the next block */
4661 return (size == 0);
4664 /******************************************************************************
4665 * SmallBlockChainStream_Shrink
4667 * Shrinks this chain in the small block depot.
4669 BOOL SmallBlockChainStream_Shrink(
4670 SmallBlockChainStream* This,
4671 ULARGE_INTEGER newSize)
4673 ULONG blockIndex, extraBlock;
4674 ULONG numBlocks;
4675 ULONG count = 1;
4677 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4679 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4680 numBlocks++;
4682 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4685 * Go to the new end of chain
4687 while (count < numBlocks)
4689 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4690 count++;
4693 /* Get the next block before marking the new end */
4694 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4696 /* Mark the new end of chain */
4697 SmallBlockChainStream_SetNextBlockInChain(
4698 This,
4699 blockIndex,
4700 BLOCK_END_OF_CHAIN);
4703 * Mark the extra blocks as free
4705 while (extraBlock != BLOCK_END_OF_CHAIN)
4707 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4708 SmallBlockChainStream_FreeBlock(This, extraBlock);
4709 extraBlock = blockIndex;
4712 return TRUE;
4715 /******************************************************************************
4716 * SmallBlockChainStream_Enlarge
4718 * Grows this chain in the small block depot.
4720 BOOL SmallBlockChainStream_Enlarge(
4721 SmallBlockChainStream* This,
4722 ULARGE_INTEGER newSize)
4724 ULONG blockIndex, currentBlock;
4725 ULONG newNumBlocks;
4726 ULONG oldNumBlocks = 0;
4728 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4731 * Empty chain
4733 if (blockIndex == BLOCK_END_OF_CHAIN)
4735 StgProperty chainProp;
4737 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4738 &chainProp);
4740 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4742 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4743 &chainProp);
4745 blockIndex = chainProp.startingBlock;
4746 SmallBlockChainStream_SetNextBlockInChain(
4747 This,
4748 blockIndex,
4749 BLOCK_END_OF_CHAIN);
4752 currentBlock = blockIndex;
4755 * Figure out how many blocks are needed to contain this stream
4757 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4759 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4760 newNumBlocks++;
4763 * Go to the current end of chain
4765 while (blockIndex != BLOCK_END_OF_CHAIN)
4767 oldNumBlocks++;
4768 currentBlock = blockIndex;
4769 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4773 * Add new blocks to the chain
4775 while (oldNumBlocks < newNumBlocks)
4777 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4778 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4780 SmallBlockChainStream_SetNextBlockInChain(
4781 This,
4782 blockIndex,
4783 BLOCK_END_OF_CHAIN);
4785 currentBlock = blockIndex;
4786 oldNumBlocks++;
4789 return TRUE;
4792 /******************************************************************************
4793 * SmallBlockChainStream_GetCount
4795 * Returns the number of blocks that comprises this chain.
4796 * This is not the size of this chain as the last block may not be full!
4798 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4800 ULONG blockIndex;
4801 ULONG count = 0;
4803 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4805 while (blockIndex != BLOCK_END_OF_CHAIN)
4807 count++;
4809 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4812 return count;
4815 /******************************************************************************
4816 * SmallBlockChainStream_SetSize
4818 * Sets the size of this stream.
4819 * The file will grow if we grow the chain.
4821 * TODO: Free the actual blocks in the file when we shrink the chain.
4822 * Currently, the blocks are still in the file. So the file size
4823 * doesn't shrink even if we shrink streams.
4825 BOOL SmallBlockChainStream_SetSize(
4826 SmallBlockChainStream* This,
4827 ULARGE_INTEGER newSize)
4829 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4831 if (newSize.LowPart == size.LowPart)
4832 return TRUE;
4834 if (newSize.LowPart < size.LowPart)
4836 SmallBlockChainStream_Shrink(This, newSize);
4838 else
4840 SmallBlockChainStream_Enlarge(This, newSize);
4843 return TRUE;
4846 /******************************************************************************
4847 * SmallBlockChainStream_GetSize
4849 * Returns the size of this chain.
4851 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4853 StgProperty chainProperty;
4855 StorageImpl_ReadProperty(
4856 This->parentStorage,
4857 This->ownerPropertyIndex,
4858 &chainProperty);
4860 return chainProperty.size;
4863 /******************************************************************************
4864 * StgCreateDocfile32 [OLE32.144]
4865 * TODO Validate grfMode (STGM)
4867 HRESULT WINAPI StgCreateDocfile(
4868 LPCOLESTR pwcsName,
4869 DWORD grfMode,
4870 DWORD reserved,
4871 IStorage **ppstgOpen)
4873 StorageImpl* newStorage = 0;
4874 HANDLE hFile = INVALID_HANDLE_VALUE;
4875 HRESULT hr = S_OK;
4876 DWORD shareMode;
4877 DWORD accessMode;
4878 DWORD creationMode;
4879 DWORD fileAttributes;
4882 * Validate the parameters
4884 if ((ppstgOpen == 0) || (pwcsName == 0))
4885 return STG_E_INVALIDPOINTER;
4888 * Validate the STGM flags
4890 if ( FAILED( validateSTGM(grfMode) ))
4891 return STG_E_INVALIDFLAG;
4894 * Interpret the STGM value grfMode
4896 shareMode = GetShareModeFromSTGM(grfMode);
4897 accessMode = GetAccessModeFromSTGM(grfMode);
4898 creationMode = GetCreationModeFromSTGM(grfMode);
4900 if (grfMode & STGM_DELETEONRELEASE)
4901 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
4902 else
4903 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
4905 if (grfMode & STGM_TRANSACTED)
4906 FIXME(ole, "Transacted mode not implemented.\n");
4909 * Initialize the "out" parameter.
4911 *ppstgOpen = 0;
4913 hFile = CreateFileW(pwcsName,
4914 accessMode,
4915 shareMode,
4916 NULL,
4917 creationMode,
4918 fileAttributes,
4921 if (hFile == INVALID_HANDLE_VALUE)
4923 return E_FAIL;
4927 * Allocate and initialize the new IStorage32object.
4929 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
4931 if (newStorage == 0)
4932 return STG_E_INSUFFICIENTMEMORY;
4934 hr = StorageImpl_Construct(
4935 newStorage,
4936 hFile,
4937 grfMode);
4939 if (FAILED(hr))
4940 return hr;
4943 * Get an "out" pointer for the caller.
4945 hr = StorageBaseImpl_QueryInterface(
4946 (IStorage*)newStorage,
4947 (REFIID)&IID_IStorage,
4948 (void**)ppstgOpen);
4950 return hr;
4953 /******************************************************************************
4954 * StgOpenStorage32 [OLE32.148]
4956 HRESULT WINAPI StgOpenStorage(
4957 const OLECHAR *pwcsName,
4958 IStorage *pstgPriority,
4959 DWORD grfMode,
4960 SNB snbExclude,
4961 DWORD reserved,
4962 IStorage **ppstgOpen)
4964 StorageImpl* newStorage = 0;
4965 HRESULT hr = S_OK;
4966 HANDLE hFile = 0;
4967 DWORD shareMode;
4968 DWORD accessMode;
4971 * Perform a sanity check
4973 if (( pwcsName == 0) || (ppstgOpen == 0) )
4974 return STG_E_INVALIDPOINTER;
4977 * Validate the STGM flags
4979 if ( FAILED( validateSTGM(grfMode) ))
4980 return STG_E_INVALIDFLAG;
4983 * Interpret the STGM value grfMode
4985 shareMode = GetShareModeFromSTGM(grfMode);
4986 accessMode = GetAccessModeFromSTGM(grfMode);
4989 * Initialize the "out" parameter.
4991 *ppstgOpen = 0;
4993 hFile = CreateFileW( pwcsName,
4994 accessMode,
4995 shareMode,
4996 NULL,
4997 OPEN_EXISTING,
4998 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5002 if (hFile==INVALID_HANDLE_VALUE)
5004 return E_FAIL;
5008 * Allocate and initialize the new IStorage32object.
5010 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5012 if (newStorage == 0)
5013 return STG_E_INSUFFICIENTMEMORY;
5015 hr = StorageImpl_Construct(
5016 newStorage,
5017 hFile,
5018 grfMode);
5020 if (FAILED(hr))
5021 return hr;
5024 * Get an "out" pointer for the caller.
5026 hr = StorageBaseImpl_QueryInterface(
5027 (IStorage*)newStorage,
5028 (REFIID)&IID_IStorage,
5029 (void**)ppstgOpen);
5031 return hr;
5034 /******************************************************************************
5035 * WriteClassStg32 [OLE32.148]
5037 * This method will store the specified CLSID in the specified storage object
5039 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5041 HRESULT hRes;
5043 assert(pStg != 0);
5045 hRes = IStorage_SetClass(pStg, rclsid);
5047 return hRes;
5051 /****************************************************************************
5052 * This method validate a STGM parameter that can contain the values below
5054 * STGM_DIRECT 0x00000000
5055 * STGM_TRANSACTED 0x00010000
5056 * STGM_SIMPLE 0x08000000
5058 * STGM_READ 0x00000000
5059 * STGM_WRITE 0x00000001
5060 * STGM_READWRITE 0x00000002
5062 * STGM_SHARE_DENY_NONE 0x00000040
5063 * STGM_SHARE_DENY_READ 0x00000030
5064 * STGM_SHARE_DENY_WRITE 0x00000020
5065 * STGM_SHARE_EXCLUSIVE 0x00000010
5067 * STGM_PRIORITY 0x00040000
5068 * STGM_DELETEONRELEASE 0x04000000
5070 * STGM_CREATE 0x00001000
5071 * STGM_CONVERT 0x00020000
5072 * STGM_FAILIFTHERE 0x00000000
5074 * STGM_NOSCRATCH 0x00100000
5075 * STGM_NOSNAPSHOT 0x00200000
5077 static HRESULT validateSTGM(DWORD stgm)
5079 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5080 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5081 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5083 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5084 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5085 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5087 BOOL bSTGM_SHARE_DENY_NONE =
5088 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5090 BOOL bSTGM_SHARE_DENY_READ =
5091 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5093 BOOL bSTGM_SHARE_DENY_WRITE =
5094 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5096 BOOL bSTGM_SHARE_EXCLUSIVE =
5097 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5099 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5100 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5102 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5103 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5106 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5108 if ( ! bSTGM_DIRECT )
5109 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5110 return E_FAIL;
5113 * STGM_WRITE | STGM_READWRITE | STGM_READ
5115 if ( ! bSTGM_READ )
5116 if( bSTGM_WRITE && bSTGM_READWRITE )
5117 return E_FAIL;
5120 * STGM_SHARE_DENY_NONE | others
5121 * (I assume here that DENY_READ implies DENY_WRITE)
5123 if ( bSTGM_SHARE_DENY_NONE )
5124 if ( bSTGM_SHARE_DENY_READ ||
5125 bSTGM_SHARE_DENY_WRITE ||
5126 bSTGM_SHARE_EXCLUSIVE)
5127 return E_FAIL;
5130 * STGM_CREATE | STGM_CONVERT
5131 * if both are false, STGM_FAILIFTHERE is set to TRUE
5133 if ( bSTGM_CREATE && bSTGM_CONVERT )
5134 return E_FAIL;
5137 * STGM_NOSCRATCH requires STGM_TRANSACTED
5139 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5140 return E_FAIL;
5143 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5144 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5146 if (bSTGM_NOSNAPSHOT)
5148 if ( ! ( bSTGM_TRANSACTED &&
5149 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5150 return E_FAIL;
5153 return S_OK;
5156 /****************************************************************************
5157 * GetShareModeFromSTGM
5159 * This method will return a share mode flag from a STGM value.
5160 * The STGM value is assumed valid.
5162 static DWORD GetShareModeFromSTGM(DWORD stgm)
5164 DWORD dwShareMode = 0;
5165 BOOL bSTGM_SHARE_DENY_NONE =
5166 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5168 BOOL bSTGM_SHARE_DENY_READ =
5169 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5171 BOOL bSTGM_SHARE_DENY_WRITE =
5172 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5174 BOOL bSTGM_SHARE_EXCLUSIVE =
5175 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5177 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5178 dwShareMode = 0;
5180 if (bSTGM_SHARE_DENY_NONE)
5181 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5183 if (bSTGM_SHARE_DENY_WRITE)
5184 dwShareMode = FILE_SHARE_READ;
5186 return dwShareMode;
5189 /****************************************************************************
5190 * GetAccessModeFromSTGM
5192 * This method will return an access mode flag from a STGM value.
5193 * The STGM value is assumed valid.
5195 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5197 DWORD dwDesiredAccess = 0;
5198 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5199 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5200 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5202 if (bSTGM_READ)
5203 dwDesiredAccess = GENERIC_READ;
5205 if (bSTGM_WRITE)
5206 dwDesiredAccess |= GENERIC_WRITE;
5208 if (bSTGM_READWRITE)
5209 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5211 return dwDesiredAccess;
5214 /****************************************************************************
5215 * GetCreationModeFromSTGM
5217 * This method will return a creation mode flag from a STGM value.
5218 * The STGM value is assumed valid.
5220 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5222 DWORD dwCreationDistribution;
5223 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5224 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5225 BOOL bSTGM_FAILIFTHERE = ! (bSTGM_CREATE || bSTGM_CONVERT);
5227 if (bSTGM_CREATE)
5228 dwCreationDistribution = CREATE_ALWAYS;
5229 else if (bSTGM_FAILIFTHERE)
5230 dwCreationDistribution = CREATE_NEW;
5231 else if (bSTGM_CONVERT)
5233 FIXME(ole, "STGM_CONVERT not implemented!\n");
5234 dwCreationDistribution = CREATE_NEW;
5237 return dwCreationDistribution;