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
32 #include "storage32.h"
36 static const char rootPropertyName[] = "Root Entry";
38 /***********************************************************************
39 * Forward declaration of internal functions used by the method DestroyElement
41 static HRESULT deleteStorageProperty(
42 Storage32Impl *parentStorage,
43 OLECHAR32 *propertyToDeleteName);
45 static HRESULT deleteStreamProperty(
46 Storage32Impl *parentStorage,
47 ULONG foundPropertyIndexToDelete,
48 StgProperty propertyToDelete);
50 static HRESULT findPlaceholder(
51 Storage32Impl *storage,
52 ULONG propertyIndexToStore,
53 ULONG storagePropertyIndex,
54 INT32 typeOfRelation);
56 static HRESULT adjustPropertyChain(
58 StgProperty propertyToDelete,
59 StgProperty parentProperty,
60 ULONG parentPropertyId,
61 INT32 typeOfRelation);
63 /***********************************************************************
64 * Declaration of the functions used to manipulate StgProperty
67 static ULONG getFreeProperty(
68 Storage32Impl *storage);
70 static void updatePropertyChain(
71 Storage32Impl *storage,
72 ULONG newPropertyIndex,
73 StgProperty newProperty);
75 static LONG propertyNameCmp(
76 OLECHAR32 *newProperty,
77 OLECHAR32 *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(IStorage32) Storage32Impl_Vtbl =
94 Storage32BaseImpl_QueryInterface,
95 Storage32BaseImpl_AddRef,
96 Storage32BaseImpl_Release,
97 Storage32BaseImpl_CreateStream,
98 Storage32BaseImpl_OpenStream,
99 Storage32Impl_CreateStorage,
100 Storage32BaseImpl_OpenStorage,
101 Storage32Impl_CopyTo,
102 Storage32Impl_MoveElementTo,
103 Storage32Impl_Commit,
104 Storage32Impl_Revert,
105 Storage32BaseImpl_EnumElements,
106 Storage32Impl_DestroyElement,
107 Storage32BaseImpl_RenameElement,
108 Storage32Impl_SetElementTimes,
109 Storage32BaseImpl_SetClass,
110 Storage32Impl_SetStateBits,
111 Storage32BaseImpl_Stat
115 * Virtual function table for the Storage32InternalImpl class.
117 static ICOM_VTABLE(IStorage32) Storage32InternalImpl_Vtbl =
119 Storage32BaseImpl_QueryInterface,
120 Storage32BaseImpl_AddRef,
121 Storage32BaseImpl_Release,
122 Storage32BaseImpl_CreateStream,
123 Storage32BaseImpl_OpenStream,
124 Storage32Impl_CreateStorage,
125 Storage32BaseImpl_OpenStorage,
126 Storage32Impl_CopyTo,
127 Storage32Impl_MoveElementTo,
128 Storage32InternalImpl_Commit,
129 Storage32InternalImpl_Revert,
130 Storage32BaseImpl_EnumElements,
131 Storage32Impl_DestroyElement,
132 Storage32BaseImpl_RenameElement,
133 Storage32Impl_SetElementTimes,
134 Storage32BaseImpl_SetClass,
135 Storage32Impl_SetStateBits,
136 Storage32BaseImpl_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 Storage32BaseImpl_QueryInterface(
174 ICOM_THIS(Storage32BaseImpl,iface);
176 * Perform a sanity check on the parameters.
178 if ( (This==0) || (ppvObject==0) )
182 * Initialize the return parameter.
187 * Compare the riid with the interface IDs implemented by this object.
189 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
191 *ppvObject = (IStorage32*)This;
193 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
195 *ppvObject = (IStorage32*)This;
199 * Check that we obtained an interface.
202 return E_NOINTERFACE;
205 * Query Interface always increases the reference count by one when it is
208 Storage32BaseImpl_AddRef(iface);
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 Storage32BaseImpl_AddRef(
224 ICOM_THIS(Storage32BaseImpl,iface);
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 Storage32BaseImpl_Release(
241 ICOM_THIS(Storage32BaseImpl,iface);
243 * Decrease the reference count on this object.
248 * If the reference count goes down to 0, perform suicide.
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);
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 Storage32BaseImpl_OpenStream(
274 const OLECHAR32* pwcsName, /* [string][in] */
275 void* reserved1, /* [unique][in] */
276 DWORD grfMode, /* [in] */
277 DWORD reserved2, /* [in] */
278 IStream32** ppstm) /* [out] */
280 ICOM_THIS(Storage32BaseImpl,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) )
293 * Initialize the out parameter
298 * Validate the STGM flags
300 if ( FAILED( validateSTGM(grfMode) ))
301 return STG_E_INVALIDFLAG;
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(
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);
341 *ppstm = (IStream32*)newStream;
344 * Since we are returning a pointer to the interface, we have to
345 * nail down the reference.
347 StgStreamImpl_AddRef(*ppstm);
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 Storage32BaseImpl_OpenStorage(
367 const OLECHAR32* pwcsName, /* [string][unique][in] */
368 IStorage32* pstgPriority, /* [unique][in] */
369 DWORD grfMode, /* [in] */
370 SNB32 snbExclude, /* [unique][in] */
371 DWORD reserved, /* [in] */
372 IStorage32** ppstg) /* [out] */
374 ICOM_THIS(Storage32BaseImpl,iface);
375 Storage32InternalImpl* 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) )
387 * Validate the STGM flags
389 if ( FAILED( validateSTGM(grfMode) ))
390 return STG_E_INVALIDFLAG;
395 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
396 (grfMode & STGM_DELETEONRELEASE) ||
397 (grfMode & STGM_PRIORITY) )
398 return STG_E_INVALIDFUNCTION;
401 * Initialize the out parameter
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(
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 = Storage32InternalImpl_Construct(
435 This->ancestorStorage,
440 *ppstg = (IStorage32*)newStorage;
443 * Since we are returning a pointer to the interface,
444 * we have to nail down the reference.
446 Storage32BaseImpl_AddRef(*ppstg);
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 Storage32BaseImpl_EnumElements(
467 DWORD reserved1, /* [in] */
468 void* reserved2, /* [size_is][unique][in] */
469 DWORD reserved3, /* [in] */
470 IEnumSTATSTG** ppenum) /* [out] */
472 ICOM_THIS(Storage32BaseImpl,iface);
473 IEnumSTATSTGImpl* newEnum;
476 * Perform a sanity check on the parameters.
478 if ( (This==0) || (ppenum==0))
482 * Construct the enumerator.
484 newEnum = IEnumSTATSTGImpl_Construct(
485 This->ancestorStorage,
486 This->rootPropertySetIndex);
490 *ppenum = (IEnumSTATSTG*)newEnum;
493 * Don't forget to nail down a reference to the new object before
496 IEnumSTATSTGImpl_AddRef(*ppenum);
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 Storage32BaseImpl_Stat(
513 STATSTG* pstatstg, /* [out] */
514 DWORD grfStatFlag) /* [in] */
516 ICOM_THIS(Storage32BaseImpl,iface);
517 StgProperty curProperty;
518 BOOL32 readSucessful;
521 * Perform a sanity check on the parameters.
523 if ( (This==0) || (pstatstg==0))
527 * Read the information from the property.
529 readSucessful = Storage32Impl_ReadProperty(
530 This->ancestorStorage,
531 This->rootPropertySetIndex,
536 StorageUtl_CopyPropertyToSTATSTG(
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 Storage32BaseImpl_RenameElement(
560 const OLECHAR32* pwcsOldName, /* [in] */
561 const OLECHAR32* pwcsNewName) /* [in] */
563 ICOM_THIS(Storage32BaseImpl,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,
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,
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 ( lstrlen32W(pwcsNewName)+1 ) * sizeof(WCHAR);
615 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
616 return STG_E_INVALIDNAME;
618 lstrcpy32W(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 Storage32Impl_WriteProperty(
651 This->ancestorStorage,
652 renamedPropertyIndex,
656 * Find a spot in the property chain for our newly created property.
659 (Storage32Impl*)This,
660 renamedPropertyIndex,
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
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
674 currentProperty.dirProperty = PROPERTY_NULL;
675 currentProperty.propertyType = PROPTYPE_STORAGE;
676 Storage32Impl_WriteProperty(
677 This->ancestorStorage,
682 * Invoke Destroy to get rid of the ole property and automatically redo
683 * the linking of it's previous and next members...
685 Storage32Impl_DestroyElement((IStorage32*)This->ancestorStorage, pwcsOldName);
691 * There is no property with the old name
693 return STG_E_FILENOTFOUND;
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 Storage32BaseImpl_CreateStream(
708 const OLECHAR32* pwcsName, /* [string][in] */
709 DWORD grfMode, /* [in] */
710 DWORD reserved1, /* [in] */
711 DWORD reserved2, /* [in] */
712 IStream32** ppstm) /* [out] */
714 ICOM_THIS(Storage32BaseImpl,iface);
715 IEnumSTATSTGImpl* propertyEnumeration;
716 StgStreamImpl* newStream;
717 StgProperty currentProperty, newStreamProperty;
718 ULONG foundPropertyIndex, newPropertyIndex;
721 * Validate parameters
724 return STG_E_INVALIDPOINTER;
727 return STG_E_INVALIDNAME;
730 * Validate the STGM flags
732 if ( FAILED( validateSTGM(grfMode) ))
733 return STG_E_INVALIDFLAG;
738 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
739 (grfMode & STGM_DELETEONRELEASE) ||
740 (grfMode & STGM_TRANSACTED) )
741 return STG_E_INVALIDFUNCTION;
744 * Initialize the out parameter
749 * Create a property enumeration to search the properties
751 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
752 This->rootPropertySetIndex);
754 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
758 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
760 if (foundPropertyIndex != PROPERTY_NULL)
763 * An element with this name already exists
765 if (grfMode & STGM_CREATE)
766 Storage32Impl_DestroyElement((IStorage32*)This->ancestorStorage, pwcsName);
768 return STG_E_FILEALREADYEXISTS;
772 * memset the empty property
774 memset(&newStreamProperty, 0, sizeof(StgProperty));
776 newStreamProperty.sizeOfNameString =
777 ( lstrlen32W(pwcsName)+1 ) * sizeof(WCHAR);
779 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
780 return STG_E_INVALIDNAME;
782 lstrcpy32W(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 Storage32Impl_WriteProperty(
811 This->ancestorStorage,
816 * Find a spot in the property chain for our newly created property.
819 (Storage32Impl*)This,
824 * Open the stream to return it.
826 newStream = StgStreamImpl_Construct(This, newPropertyIndex);
830 *ppstm = (IStream32*)newStream;
833 * Since we are returning a pointer to the interface, we have to nail down
836 StgStreamImpl_AddRef(*ppstm);
840 return STG_E_INSUFFICIENTMEMORY;
846 /************************************************************************
847 * Storage32BaseImpl_SetClass (IStorage)
849 * This method will write the specified CLSID in the property of this
852 * See Windows documentation for more details on IStorage methods.
854 HRESULT WINAPI Storage32BaseImpl_SetClass(
856 REFCLSID clsid) /* [in] */
858 ICOM_THIS(Storage32BaseImpl,iface);
859 HRESULT hRes = E_FAIL;
860 StgProperty curProperty;
863 success = Storage32Impl_ReadProperty(This->ancestorStorage,
864 This->rootPropertySetIndex,
868 curProperty.propertyUniqueID = *clsid;
870 success = Storage32Impl_WriteProperty(This->ancestorStorage,
871 This->rootPropertySetIndex,
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 Storage32Impl_CreateStorage(
893 const OLECHAR32 *pwcsName, /* [string][in] */
894 DWORD grfMode, /* [in] */
895 DWORD reserved1, /* [in] */
896 DWORD reserved2, /* [in] */
897 IStorage32 **ppstg) /* [out] */
899 Storage32Impl* const This=(Storage32Impl*)iface;
901 IEnumSTATSTGImpl *propertyEnumeration;
902 StgProperty currentProperty;
903 StgProperty newProperty;
904 ULONG foundPropertyIndex;
905 ULONG newPropertyIndex;
909 * Validate parameters
912 return STG_E_INVALIDPOINTER;
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
930 * Create a property enumeration and search the properties
932 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
933 This->rootPropertySetIndex);
935 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
938 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
940 if (foundPropertyIndex != PROPERTY_NULL)
943 * An element with this name already exists
945 if (grfMode & STGM_CREATE)
946 Storage32Impl_DestroyElement((IStorage32*)This->ancestorStorage, pwcsName);
948 return STG_E_FILEALREADYEXISTS;
952 * memset the empty property
954 memset(&newProperty, 0, sizeof(StgProperty));
956 newProperty.sizeOfNameString = (lstrlen32W(pwcsName)+1)*sizeof(WCHAR);
958 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
959 return STG_E_INVALIDNAME;
961 lstrcpy32W(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 Storage32Impl_WriteProperty(
990 This->ancestorStorage,
995 * Find a spot in the property chain for our newly created property.
1003 * Open it to get a pointer to return.
1005 hr = Storage32BaseImpl_OpenStorage(
1007 (OLECHAR32*)pwcsName,
1014 if( (hr != S_OK) || (*ppstg == NULL))
1023 /***************************************************************************
1027 * Get a free property or create a new one.
1029 static ULONG getFreeProperty(
1030 Storage32Impl *storage)
1032 ULONG currentPropertyIndex = 0;
1033 ULONG newPropertyIndex = PROPERTY_NULL;
1034 BOOL32 readSucessful = TRUE;
1035 StgProperty currentProperty;
1040 * Start by reading the root property
1042 readSucessful = Storage32Impl_ReadProperty(storage->ancestorStorage,
1043 currentPropertyIndex,
1047 if (currentProperty.sizeOfNameString == 0)
1050 * The property existis and is available, we found it.
1052 newPropertyIndex = currentPropertyIndex;
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
1098 memset(&emptyProperty, 0, sizeof(StgProperty));
1103 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1106 propertyIndex = newPropertyIndex;
1107 propertyIndex < lastProperty;
1110 Storage32Impl_WriteProperty(
1111 storage->ancestorStorage,
1117 return newPropertyIndex;
1120 /****************************************************************************
1124 * Case insensitive comparaison of StgProperty.name by first considering
1127 * Returns <0 when newPrpoerty < currentProperty
1128 * >0 when newPrpoerty > currentProperty
1129 * 0 when newPrpoerty == currentProperty
1131 static LONG propertyNameCmp(
1132 OLECHAR32 *newProperty,
1133 OLECHAR32 *currentProperty)
1135 LONG sizeOfNew = (lstrlen32W(newProperty) +1) * sizeof(WCHAR);
1136 LONG sizeOfCur = (lstrlen32W(currentProperty)+1) * sizeof(WCHAR);
1137 LONG diff = sizeOfNew - sizeOfCur;
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 = lstrcmp32W( (LPCWSTR)CRTDLL__wcsupr(
1148 lstrcpyn32W(wsnew, newProperty, sizeOfNew)),
1149 (LPCWSTR)CRTDLL__wcsupr(
1150 lstrcpyn32W(wscur, currentProperty, sizeOfCur)));
1156 /****************************************************************************
1160 * Properly link this new element in the property chain.
1162 static void updatePropertyChain(
1163 Storage32Impl *storage,
1164 ULONG newPropertyIndex,
1165 StgProperty newProperty)
1167 StgProperty currentProperty;
1170 * Read the root property
1172 Storage32Impl_ReadProperty(storage->ancestorStorage,
1173 storage->rootPropertySetIndex,
1176 if (currentProperty.dirProperty != PROPERTY_NULL)
1179 * The root storage contains some element, therefore, start the research
1180 * for the appropriate location.
1183 ULONG current, next, previous, currentPropertyId;
1186 * Keep the StgProperty sequence number of the storage first property
1188 currentPropertyId = currentProperty.dirProperty;
1193 Storage32Impl_ReadProperty(storage->ancestorStorage,
1194 currentProperty.dirProperty,
1197 previous = currentProperty.previousProperty;
1198 next = currentProperty.nextProperty;
1199 current = currentPropertyId;
1203 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1207 if (previous != PROPERTY_NULL)
1209 Storage32Impl_ReadProperty(storage->ancestorStorage,
1216 currentProperty.previousProperty = newPropertyIndex;
1217 Storage32Impl_WriteProperty(storage->ancestorStorage,
1225 if (next != PROPERTY_NULL)
1227 Storage32Impl_ReadProperty(storage->ancestorStorage,
1234 currentProperty.nextProperty = newPropertyIndex;
1235 Storage32Impl_WriteProperty(storage->ancestorStorage,
1242 previous = currentProperty.previousProperty;
1243 next = currentProperty.nextProperty;
1249 * The root storage is empty, link the new property to it's dir property
1251 currentProperty.dirProperty = newPropertyIndex;
1252 Storage32Impl_WriteProperty(storage->ancestorStorage,
1253 storage->rootPropertySetIndex,
1259 /*************************************************************************
1262 HRESULT WINAPI Storage32Impl_CopyTo(
1264 DWORD ciidExclude, /* [in] */
1265 const IID *rgiidExclude,/* [size_is][unique][in] */
1266 SNB32 snbExclude, /* [unique][in] */
1267 IStorage32 *pstgDest) /* [unique][in] */
1272 /*************************************************************************
1273 * MoveElementTo (IStorage)
1275 HRESULT WINAPI Storage32Impl_MoveElementTo(
1277 const OLECHAR32 *pwcsName, /* [string][in] */
1278 IStorage32 *pstgDest, /* [unique][in] */
1279 const OLECHAR32 *pwcsNewName,/* [string][in] */
1280 DWORD grfFlags) /* [in] */
1285 /*************************************************************************
1288 HRESULT WINAPI Storage32Impl_Commit(
1290 DWORD grfCommitFlags)/* [in] */
1292 FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1296 /*************************************************************************
1299 HRESULT WINAPI Storage32Impl_Revert(
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 Storage32Impl_DestroyElement(
1318 const OLECHAR32 *pwcsName)/* [string][in] */
1320 Storage32Impl* const This=(Storage32Impl*)iface;
1322 IEnumSTATSTGImpl* propertyEnumeration;
1325 StgProperty propertyToDelete;
1326 StgProperty parentProperty;
1327 ULONG foundPropertyIndexToDelete;
1328 ULONG typeOfRelation;
1329 ULONG parentPropertyId;
1332 * Perform a sanity check on the parameters.
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,
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 = Storage32Impl_ReadProperty(
1366 This->ancestorStorage,
1367 This->rootPropertySetIndex,
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;
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,
1402 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1405 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1407 hr = deleteStorageProperty(
1409 propertyToDelete.name);
1411 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1413 hr = deleteStreamProperty(
1415 foundPropertyIndexToDelete,
1423 * Adjust the property chain
1425 hr = adjustPropertyChain(
1436 /*********************************************************************
1440 * Perform the deletion of a complete storage node
1443 static HRESULT deleteStorageProperty(
1444 Storage32Impl *parentStorage,
1445 OLECHAR32 *propertyToDeleteName)
1447 IEnumSTATSTG *elements = 0;
1448 IStorage32 *childStorage = 0;
1449 STATSTG currentElement;
1451 HRESULT destroyHr = S_OK;
1454 * Open the storage and enumerate it
1456 hr = Storage32BaseImpl_OpenStorage(
1457 (IStorage32*)parentStorage,
1458 propertyToDeleteName,
1460 STGM_SHARE_EXCLUSIVE,
1471 * Enumerate the elements
1473 IStorage32_EnumElements( childStorage, 0, 0, 0, &elements);
1478 * Obtain the next element
1480 hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL);
1483 destroyHr = Storage32Impl_DestroyElement(
1484 (IStorage32*)childStorage,
1485 (OLECHAR32*)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 IStorage32_Release(childStorage);
1499 IEnumSTATSTG_Release(elements);
1504 /*********************************************************************
1508 * Perform the deletion of a stream node
1511 static HRESULT deleteStreamProperty(
1512 Storage32Impl *parentStorage,
1513 ULONG indexOfPropertyToDelete,
1514 StgProperty propertyToDelete)
1518 ULARGE_INTEGER size;
1523 hr = Storage32BaseImpl_OpenStream(
1524 (IStorage32*)parentStorage,
1525 (OLECHAR32*)propertyToDelete.name,
1527 STGM_SHARE_EXCLUSIVE,
1539 hr = IStream32_SetSize(pis, size);
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 Storage32Impl_WriteProperty(
1557 parentStorage->ancestorStorage,
1558 indexOfPropertyToDelete,
1564 /*********************************************************************
1568 * Finds a placeholder for the StgProperty within the Storage
1571 static HRESULT findPlaceholder(
1572 Storage32Impl *storage,
1573 ULONG propertyIndexToStore,
1574 ULONG storePropertyIndex,
1575 INT32 typeOfRelation)
1577 StgProperty storeProperty;
1582 * Read the storage property
1584 res = Storage32Impl_ReadProperty(
1585 storage->ancestorStorage,
1594 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1596 if (storeProperty.previousProperty != PROPERTY_NULL)
1598 return findPlaceholder(
1600 propertyIndexToStore,
1601 storeProperty.previousProperty,
1606 storeProperty.previousProperty = propertyIndexToStore;
1609 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1611 if (storeProperty.nextProperty != PROPERTY_NULL)
1613 return findPlaceholder(
1615 propertyIndexToStore,
1616 storeProperty.nextProperty,
1621 storeProperty.nextProperty = propertyIndexToStore;
1624 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1626 if (storeProperty.dirProperty != PROPERTY_NULL)
1628 return findPlaceholder(
1630 propertyIndexToStore,
1631 storeProperty.dirProperty,
1636 storeProperty.dirProperty = propertyIndexToStore;
1640 hr = Storage32Impl_WriteProperty(
1641 storage->ancestorStorage,
1653 /*************************************************************************
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 Storage32Impl *This,
1662 StgProperty propertyToDelete,
1663 StgProperty parentProperty,
1664 ULONG parentPropertyId,
1665 INT32 typeOfRelation)
1667 ULONG newLinkProperty = PROPERTY_NULL;
1668 BOOL32 needToFindAPlaceholder = FALSE;
1669 ULONG storeNode = PROPERTY_NULL;
1670 ULONG toStoreNode = PROPERTY_NULL;
1671 INT32 relationType = 0;
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 = Storage32Impl_WriteProperty(
1783 This->ancestorStorage,
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(
1808 /******************************************************************************
1809 * SetElementTimes (IStorage)
1811 HRESULT WINAPI Storage32Impl_SetElementTimes(
1813 const OLECHAR32 *pwcsName,/* [string][in] */
1814 const FILETIME *pctime, /* [in] */
1815 const FILETIME *patime, /* [in] */
1816 const FILETIME *pmtime) /* [in] */
1821 /******************************************************************************
1822 * SetStateBits (IStorage)
1824 HRESULT WINAPI Storage32Impl_SetStateBits(
1826 DWORD grfStateBits,/* [in] */
1827 DWORD grfMask) /* [in] */
1832 HRESULT Storage32Impl_Construct(
1833 Storage32Impl* This,
1838 StgProperty currentProperty;
1839 BOOL32 readSucessful;
1840 ULONG currentPropertyIndex;
1842 if ( FAILED( validateSTGM(openFlags) ))
1843 return STG_E_INVALIDFLAG;
1845 memset(This, 0, sizeof(Storage32Impl));
1848 * Initialize the virtual fgunction table.
1850 This->lpvtbl = &Storage32Impl_Vtbl;
1851 This->v_destructor = &Storage32Impl_Destroy;
1854 * This is the top-level storage so initialize the ancester pointer
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,
1871 This->bigBlockSize);
1873 if (This->bigBlockFile == 0)
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,
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 Storage32Impl_SaveFileHeader(This);
1903 * Add one block for the big block depot and one block for the properties
1906 size.LowPart = This->bigBlockSize * 3;
1907 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
1910 * Initialize the big block depot
1912 bigBlockBuffer = Storage32Impl_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 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
1921 * Load the header for the file.
1923 Storage32Impl_LoadFileHeader(This);
1927 * Create the block chain abstractions.
1929 This->rootBlockChain =
1930 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1932 This->smallBlockDepotChain = BlockChainStream_Construct(
1934 &This->smallBlockDepotStart,
1938 * Write the root property
1940 if (openFlags & STGM_CREATE)
1942 StgProperty rootProp;
1944 * Initialize the property chain
1946 memset(&rootProp, 0, sizeof(rootProp));
1947 lstrcpyAtoW(rootProp.name, rootPropertyName);
1949 rootProp.sizeOfNameString = (lstrlen32W(rootProp.name)+1) * sizeof(WCHAR);
1950 rootProp.propertyType = PROPTYPE_ROOT;
1951 rootProp.previousProperty = PROPERTY_NULL;
1952 rootProp.nextProperty = PROPERTY_NULL;
1953 rootProp.dirProperty = PROPERTY_NULL;
1954 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
1955 rootProp.size.HighPart = 0;
1956 rootProp.size.LowPart = 0;
1958 Storage32Impl_WriteProperty(This, 0, &rootProp);
1962 * Find the ID of the root int he property sets.
1964 currentPropertyIndex = 0;
1968 readSucessful = Storage32Impl_ReadProperty(
1970 currentPropertyIndex,
1975 if ( (currentProperty.sizeOfNameString != 0 ) &&
1976 (currentProperty.propertyType == PROPTYPE_ROOT) )
1978 This->rootPropertySetIndex = currentPropertyIndex;
1982 currentPropertyIndex++;
1984 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1993 * Create the block chain abstraction for the small block root chain.
1995 This->smallBlockRootChain = BlockChainStream_Construct(
1998 This->rootPropertySetIndex);
2003 void Storage32Impl_Destroy(
2004 Storage32Impl* This)
2006 BlockChainStream_Destroy(This->smallBlockRootChain);
2007 BlockChainStream_Destroy(This->rootBlockChain);
2008 BlockChainStream_Destroy(This->smallBlockDepotChain);
2010 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2014 /******************************************************************************
2015 * Storage32Impl_GetNextFreeBigBlock
2017 * Returns the index of the next free big block.
2018 * If the big block depot is filled, this method will enlarge it.
2020 * TODO: Handle the case when the big block depot becomes bigger
2021 * than COUNT_BBDEPOTINHEADER.
2023 ULONG Storage32Impl_GetNextFreeBigBlock(
2024 Storage32Impl* This)
2026 ULONG depotBlockIndexPos;
2028 ULONG depotBlockOffset;
2029 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2030 ULONG nextBlockIndex = BLOCK_SPECIAL;
2032 ULONG blockNoInSequence = 0;
2035 * Scan the entire big block depot until we find a block marked free
2037 while ( (depotIndex < COUNT_BBDEPOTINHEADER) &&
2038 (nextBlockIndex != BLOCK_UNUSED))
2040 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2042 if (depotBlockIndexPos == BLOCK_UNUSED)
2045 * No more space in the big block depot, we have to enlarge it
2047 depotBlockIndexPos = depotIndex*blocksPerDepot;
2048 depotBuffer = Storage32Impl_GetBigBlock(This, depotBlockIndexPos);
2050 depotBlockOffset = 0;
2052 /* mark this block as being part of the big block depot
2054 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, BLOCK_SPECIAL);
2055 depotBlockOffset += sizeof(ULONG);
2057 /* initialize blocks as free
2059 while ((depotBlockOffset < blocksPerDepot))
2061 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, BLOCK_UNUSED);
2062 depotBlockOffset += sizeof(ULONG);
2065 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2067 /* Save the information to the file header
2069 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2070 This->bigBlockDepotCount++;
2071 Storage32Impl_SaveFileHeader(This);
2074 depotBuffer = Storage32Impl_GetROBigBlock(This, depotBlockIndexPos);
2076 if (depotBuffer != 0)
2078 depotBlockOffset = 0;
2080 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2081 ( nextBlockIndex != BLOCK_UNUSED))
2083 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2085 if (nextBlockIndex != BLOCK_UNUSED)
2086 blockNoInSequence++;
2088 depotBlockOffset += sizeof(ULONG);
2091 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2097 return blockNoInSequence;
2100 /******************************************************************************
2101 * Storage32Impl_FreeBigBlock
2103 * This method will flag the specified block as free in the big block depot.
2105 void Storage32Impl_FreeBigBlock(
2106 Storage32Impl* This,
2109 Storage32Impl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2112 /************************************************************************
2113 * Storage32Impl_GetNextBlockInChain
2115 * This method will retrieve the block index of the next big block in
2118 * Params: This - Pointer to the Storage object.
2119 * blockIndex - Index of the block to retrieve the chain
2122 * Returns: This method returns the index of the next block in the chain.
2123 * It will return the constants:
2124 * BLOCK_SPECIAL - If the block given was not part of a
2126 * BLOCK_END_OF_CHAIN - If the block given was the last in
2128 * BLOCK_UNUSED - If the block given was not past of a chain
2131 * See Windows documentation for more details on IStorage methods.
2133 ULONG Storage32Impl_GetNextBlockInChain(
2134 Storage32Impl* This,
2137 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2138 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2139 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2140 ULONG nextBlockIndex = BLOCK_SPECIAL;
2142 ULONG depotBlockIndexPos;
2144 assert(depotBlockCount < This->bigBlockDepotCount);
2145 assert(depotBlockCount < COUNT_BBDEPOTINHEADER);
2147 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2149 depotBuffer = Storage32Impl_GetROBigBlock(This, depotBlockIndexPos);
2153 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2155 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2158 return nextBlockIndex;
2161 /******************************************************************************
2162 * Storage32Impl_SetNextBlockInChain
2164 * This method will write the index of the specified block's next block
2165 * in the big block depot.
2167 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2170 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2171 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2172 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2175 void Storage32Impl_SetNextBlockInChain(
2176 Storage32Impl* This,
2180 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2181 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2182 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2183 ULONG depotBlockIndexPos;
2186 assert(depotBlockCount < This->bigBlockDepotCount);
2187 assert(depotBlockCount < COUNT_BBDEPOTINHEADER);
2189 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2191 depotBuffer = Storage32Impl_GetBigBlock(This, depotBlockIndexPos);
2195 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2196 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2202 /******************************************************************************
2203 * Storage32Impl_LoadFileHeader
2205 * This method will read in the file header, i.e. big block index -1.
2207 HRESULT Storage32Impl_LoadFileHeader(
2208 Storage32Impl* This)
2210 HRESULT hr = STG_E_FILENOTFOUND;
2211 void* headerBigBlock = NULL;
2215 * Get a pointer to the big block of data containing the header.
2217 headerBigBlock = Storage32Impl_GetROBigBlock(This, -1);
2220 * Extract the information from the header.
2222 if (headerBigBlock!=0)
2225 * Check for the "magic number" signature and return an error if it is not
2228 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2230 Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2231 return STG_E_OLDFORMAT;
2234 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2236 Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2237 return STG_E_INVALIDHEADER;
2240 StorageUtl_ReadWord(
2242 OFFSET_BIGBLOCKSIZEBITS,
2243 &This->bigBlockSizeBits);
2245 StorageUtl_ReadWord(
2247 OFFSET_SMALLBLOCKSIZEBITS,
2248 &This->smallBlockSizeBits);
2250 StorageUtl_ReadDWord(
2252 OFFSET_BBDEPOTCOUNT,
2253 &This->bigBlockDepotCount);
2255 StorageUtl_ReadDWord(
2257 OFFSET_ROOTSTARTBLOCK,
2258 &This->rootStartBlock);
2260 StorageUtl_ReadDWord(
2262 OFFSET_SBDEPOTSTART,
2263 &This->smallBlockDepotStart);
2265 StorageUtl_ReadDWord(
2267 OFFSET_EXTBBDEPOTSTART,
2268 &This->extBigBlockDepotStart);
2270 StorageUtl_ReadDWord(
2272 OFFSET_EXTBBDEPOTCOUNT,
2273 &This->extBigBlockDepotCount);
2275 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2277 StorageUtl_ReadDWord(
2279 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2280 &(This->bigBlockDepotStart[index]));
2284 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2288 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2289 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2293 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2294 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2298 * Right now, the code is making some assumptions about the size of the
2299 * blocks, just make sure they are what we're expecting.
2301 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2302 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2305 * Release the block.
2307 Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2313 /******************************************************************************
2314 * Storage32Impl_SaveFileHeader
2316 * This method will save to the file the header, i.e. big block -1.
2318 void Storage32Impl_SaveFileHeader(
2319 Storage32Impl* This)
2321 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2326 * Get a pointer to the big block of data containing the header.
2328 success = Storage32Impl_ReadBigBlock(This, -1, headerBigBlock);
2331 * If the block read failed, the file is probably new.
2336 * Initialize for all unknown fields.
2338 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2341 * Initialize the magic number.
2343 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2346 * And a bunch of things we don't know what they mean
2348 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2349 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2350 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2351 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2352 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2356 * Write the information to the header.
2358 if (headerBigBlock!=0)
2360 StorageUtl_WriteWord(
2362 OFFSET_BIGBLOCKSIZEBITS,
2363 This->bigBlockSizeBits);
2365 StorageUtl_WriteWord(
2367 OFFSET_SMALLBLOCKSIZEBITS,
2368 This->smallBlockSizeBits);
2370 StorageUtl_WriteDWord(
2372 OFFSET_BBDEPOTCOUNT,
2373 This->bigBlockDepotCount);
2375 StorageUtl_WriteDWord(
2377 OFFSET_ROOTSTARTBLOCK,
2378 This->rootStartBlock);
2380 StorageUtl_WriteDWord(
2382 OFFSET_SBDEPOTSTART,
2383 This->smallBlockDepotStart);
2385 StorageUtl_WriteDWord(
2387 OFFSET_EXTBBDEPOTSTART,
2388 This->extBigBlockDepotStart);
2390 StorageUtl_WriteDWord(
2392 OFFSET_EXTBBDEPOTCOUNT,
2393 This->extBigBlockDepotCount);
2395 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2397 StorageUtl_WriteDWord(
2399 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2400 (This->bigBlockDepotStart[index]));
2405 * Write the big block back to the file.
2407 Storage32Impl_WriteBigBlock(This, -1, headerBigBlock);
2410 /******************************************************************************
2411 * Storage32Impl_ReadProperty
2413 * This method will read the specified property from the property chain.
2415 BOOL32 Storage32Impl_ReadProperty(
2416 Storage32Impl* This,
2418 StgProperty* buffer)
2420 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2421 ULARGE_INTEGER offsetInPropSet;
2422 BOOL32 readSucessful;
2425 offsetInPropSet.HighPart = 0;
2426 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2428 readSucessful = BlockChainStream_ReadAt(
2429 This->rootBlockChain,
2437 memset(buffer->name, 0, sizeof(buffer->name));
2440 currentProperty+OFFSET_PS_NAME,
2441 PROPERTY_NAME_BUFFER_LEN );
2443 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2445 StorageUtl_ReadWord(
2447 OFFSET_PS_NAMELENGTH,
2448 &buffer->sizeOfNameString);
2450 StorageUtl_ReadDWord(
2452 OFFSET_PS_PREVIOUSPROP,
2453 &buffer->previousProperty);
2455 StorageUtl_ReadDWord(
2458 &buffer->nextProperty);
2460 StorageUtl_ReadDWord(
2463 &buffer->dirProperty);
2465 StorageUtl_ReadGUID(
2468 &buffer->propertyUniqueID);
2470 StorageUtl_ReadDWord(
2473 &buffer->timeStampS1);
2475 StorageUtl_ReadDWord(
2478 &buffer->timeStampD1);
2480 StorageUtl_ReadDWord(
2483 &buffer->timeStampS2);
2485 StorageUtl_ReadDWord(
2488 &buffer->timeStampD2);
2490 StorageUtl_ReadDWord(
2492 OFFSET_PS_STARTBLOCK,
2493 &buffer->startingBlock);
2495 StorageUtl_ReadDWord(
2498 &buffer->size.LowPart);
2500 buffer->size.HighPart = 0;
2503 return readSucessful;
2506 /*********************************************************************
2507 * Write the specified property into the property chain
2509 BOOL32 Storage32Impl_WriteProperty(
2510 Storage32Impl* This,
2512 StgProperty* buffer)
2514 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2515 ULARGE_INTEGER offsetInPropSet;
2516 BOOL32 writeSucessful;
2519 offsetInPropSet.HighPart = 0;
2520 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2522 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2525 currentProperty + OFFSET_PS_NAME,
2527 PROPERTY_NAME_BUFFER_LEN );
2529 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2532 * Reassign the size in case of mistake....
2534 buffer->sizeOfNameString = (lstrlen32W(buffer->name)+1) * sizeof(WCHAR);
2536 StorageUtl_WriteWord(
2538 OFFSET_PS_NAMELENGTH,
2539 buffer->sizeOfNameString);
2541 StorageUtl_WriteDWord(
2543 OFFSET_PS_PREVIOUSPROP,
2544 buffer->previousProperty);
2546 StorageUtl_WriteDWord(
2549 buffer->nextProperty);
2551 StorageUtl_WriteDWord(
2554 buffer->dirProperty);
2556 StorageUtl_WriteGUID(
2559 &buffer->propertyUniqueID);
2561 StorageUtl_WriteDWord(
2564 buffer->timeStampS1);
2566 StorageUtl_WriteDWord(
2569 buffer->timeStampD1);
2571 StorageUtl_WriteDWord(
2574 buffer->timeStampS2);
2576 StorageUtl_WriteDWord(
2579 buffer->timeStampD2);
2581 StorageUtl_WriteDWord(
2583 OFFSET_PS_STARTBLOCK,
2584 buffer->startingBlock);
2586 StorageUtl_WriteDWord(
2589 buffer->size.LowPart);
2591 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2596 return writeSucessful;
2599 BOOL32 Storage32Impl_ReadBigBlock(
2600 Storage32Impl* This,
2604 void* bigBlockBuffer;
2606 bigBlockBuffer = Storage32Impl_GetROBigBlock(This, blockIndex);
2608 if (bigBlockBuffer!=0)
2610 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2612 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2620 BOOL32 Storage32Impl_WriteBigBlock(
2621 Storage32Impl* This,
2625 void* bigBlockBuffer;
2627 bigBlockBuffer = Storage32Impl_GetBigBlock(This, blockIndex);
2629 if (bigBlockBuffer!=0)
2631 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2633 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2641 void* Storage32Impl_GetROBigBlock(
2642 Storage32Impl* This,
2645 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2648 void* Storage32Impl_GetBigBlock(
2649 Storage32Impl* This,
2652 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2655 void Storage32Impl_ReleaseBigBlock(
2656 Storage32Impl* This,
2659 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2662 /******************************************************************************
2663 * Storage32Impl_SmallBlocksToBigBlocks
2665 * This method will convert a small block chain to a big block chain.
2666 * The small block chain will be destroyed.
2668 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2669 Storage32Impl* This,
2670 SmallBlockChainStream** ppsbChain)
2672 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2673 ULARGE_INTEGER size, offset;
2674 ULONG cbRead, cbWritten;
2675 ULONG propertyIndex;
2676 BOOL32 successRead, successWrite;
2677 StgProperty chainProperty;
2678 BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2679 BlockChainStream *bbTempChain = NULL;
2680 BlockChainStream *bigBlockChain = NULL;
2683 * Create a temporary big block chain that doesn't have
2684 * an associated property. This temporary chain will be
2685 * used to copy data from small blocks to big blocks.
2687 bbTempChain = BlockChainStream_Construct(This,
2692 * Grow the big block chain.
2694 size = SmallBlockChainStream_GetSize(*ppsbChain);
2695 BlockChainStream_SetSize(bbTempChain, size);
2698 * Copy the contents of the small block chain to the big block chain
2699 * by small block size increments.
2702 offset.HighPart = 0;
2706 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
2712 successWrite = BlockChainStream_WriteAt(bbTempChain,
2717 offset.LowPart += This->smallBlockSize;
2719 } while (successRead && successWrite);
2721 assert(cbRead == cbWritten);
2724 * Destroy the small block chain.
2726 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
2729 SmallBlockChainStream_SetSize(*ppsbChain, size);
2730 SmallBlockChainStream_Destroy(*ppsbChain);
2734 * Change the property information. This chain is now a big block chain
2735 * and it doesn't reside in the small blocks chain anymore.
2737 Storage32Impl_ReadProperty(This, propertyIndex, &chainProperty);
2739 chainProperty.startingBlock = bbHeadOfChain;
2741 Storage32Impl_WriteProperty(This, propertyIndex, &chainProperty);
2744 * Destroy the temporary propertyless big block chain.
2745 * Create a new big block chain associated with this property.
2747 BlockChainStream_Destroy(bbTempChain);
2748 bigBlockChain = BlockChainStream_Construct(This,
2752 return bigBlockChain;
2755 /******************************************************************************
2756 ** Storage32InternalImpl implementation
2759 Storage32InternalImpl* Storage32InternalImpl_Construct(
2760 Storage32Impl* ancestorStorage,
2761 ULONG rootPropertyIndex)
2763 Storage32InternalImpl* newStorage;
2766 * Allocate space for the new storage object
2768 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32InternalImpl));
2772 memset(newStorage, 0, sizeof(Storage32InternalImpl));
2775 * Initialize the virtual function table.
2777 newStorage->lpvtbl = &Storage32InternalImpl_Vtbl;
2778 newStorage->v_destructor = &Storage32InternalImpl_Destroy;
2781 * Keep the ancestor storage pointer and nail a reference to it.
2783 newStorage->ancestorStorage = ancestorStorage;
2784 Storage32BaseImpl_AddRef((IStorage32*)(newStorage->ancestorStorage));
2787 * Keep the index of the root property set for this storage,
2789 newStorage->rootPropertySetIndex = rootPropertyIndex;
2797 void Storage32InternalImpl_Destroy(
2798 Storage32InternalImpl* This)
2800 HeapFree(GetProcessHeap(), 0, This);
2803 /******************************************************************************
2805 ** Storage32InternalImpl_Commit
2807 ** The non-root storages cannot be opened in transacted mode thus this function
2810 HRESULT WINAPI Storage32InternalImpl_Commit(
2812 DWORD grfCommitFlags) /* [in] */
2817 /******************************************************************************
2819 ** Storage32InternalImpl_Revert
2821 ** The non-root storages cannot be opened in transacted mode thus this function
2824 HRESULT WINAPI Storage32InternalImpl_Revert(
2830 /******************************************************************************
2831 ** IEnumSTATSTGImpl implementation
2834 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
2835 Storage32Impl* parentStorage,
2836 ULONG firstPropertyNode)
2838 IEnumSTATSTGImpl* newEnumeration;
2840 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
2842 if (newEnumeration!=0)
2845 * Set-up the virtual function table and reference count.
2847 newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
2848 newEnumeration->ref = 0;
2851 * We want to nail-down the reference to the storage in case the
2852 * enumeration out-lives the storage in the client application.
2854 newEnumeration->parentStorage = parentStorage;
2855 IStorage32_AddRef((IStorage32*)newEnumeration->parentStorage);
2857 newEnumeration->firstPropertyNode = firstPropertyNode;
2860 * Initialize the search stack
2862 newEnumeration->stackSize = 0;
2863 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
2864 newEnumeration->stackToVisit =
2865 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
2868 * Make sure the current node of the iterator is the first one.
2870 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
2873 return newEnumeration;
2876 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
2878 IStorage32_Release((IStorage32*)This->parentStorage);
2879 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
2880 HeapFree(GetProcessHeap(), 0, This);
2883 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
2884 IEnumSTATSTG* iface,
2888 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2891 * Perform a sanity check on the parameters.
2894 return E_INVALIDARG;
2897 * Initialize the return parameter.
2902 * Compare the riid with the interface IDs implemented by this object.
2904 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
2906 *ppvObject = (IEnumSTATSTG*)This;
2908 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
2910 *ppvObject = (IEnumSTATSTG*)This;
2914 * Check that we obtained an interface.
2916 if ((*ppvObject)==0)
2917 return E_NOINTERFACE;
2920 * Query Interface always increases the reference count by one when it is
2923 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
2928 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
2929 IEnumSTATSTG* iface)
2931 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2937 ULONG WINAPI IEnumSTATSTGImpl_Release(
2938 IEnumSTATSTG* iface)
2940 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2948 * If the reference count goes down to 0, perform suicide.
2952 IEnumSTATSTGImpl_Destroy(This);
2958 HRESULT WINAPI IEnumSTATSTGImpl_Next(
2959 IEnumSTATSTG* iface,
2962 ULONG* pceltFetched)
2964 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
2966 StgProperty currentProperty;
2967 STATSTG* currentReturnStruct = rgelt;
2968 ULONG objectFetched = 0;
2969 ULONG currentSearchNode;
2972 * Perform a sanity check on the parameters.
2974 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
2975 return E_INVALIDARG;
2978 * To avoid the special case, get another pointer to a ULONG value if
2979 * the caller didn't supply one.
2981 if (pceltFetched==0)
2982 pceltFetched = &objectFetched;
2985 * Start the iteration, we will iterate until we hit the end of the
2986 * linked list or until we hit the number of items to iterate through
2991 * Start with the node at the top of the stack.
2993 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
2995 while ( ( *pceltFetched < celt) &&
2996 ( currentSearchNode!=PROPERTY_NULL) )
2999 * Remove the top node from the stack
3001 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3004 * Read the property from the storage.
3006 Storage32Impl_ReadProperty(This->parentStorage,
3011 * Copy the information to the return buffer.
3013 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3018 * Step to the next item in the iteration
3021 currentReturnStruct++;
3024 * Push the next search node in the search stack.
3026 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3029 * continue the iteration.
3031 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3034 if (*pceltFetched == celt)
3041 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3042 IEnumSTATSTG* iface,
3045 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3047 StgProperty currentProperty;
3048 ULONG objectFetched = 0;
3049 ULONG currentSearchNode;
3052 * Start with the node at the top of the stack.
3054 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3056 while ( (objectFetched < celt) &&
3057 (currentSearchNode!=PROPERTY_NULL) )
3060 * Remove the top node from the stack
3062 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3065 * Read the property from the storage.
3067 Storage32Impl_ReadProperty(This->parentStorage,
3072 * Step to the next item in the iteration
3077 * Push the next search node in the search stack.
3079 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3082 * continue the iteration.
3084 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3087 if (objectFetched == celt)
3093 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3094 IEnumSTATSTG* iface)
3096 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3098 StgProperty rootProperty;
3099 BOOL32 readSucessful;
3102 * Re-initialize the search stack to an empty stack
3104 This->stackSize = 0;
3107 * Read the root property from the storage.
3109 readSucessful = Storage32Impl_ReadProperty(
3110 This->parentStorage,
3111 This->firstPropertyNode,
3116 assert(rootProperty.sizeOfNameString!=0);
3119 * Push the search node in the search stack.
3121 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3127 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3128 IEnumSTATSTG* iface,
3129 IEnumSTATSTG** ppenum)
3131 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3133 IEnumSTATSTGImpl* newClone;
3136 * Perform a sanity check on the parameters.
3139 return E_INVALIDARG;
3141 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3142 This->firstPropertyNode);
3146 * The new clone enumeration must point to the same current node as
3149 newClone->stackSize = This->stackSize ;
3150 newClone->stackMaxSize = This->stackMaxSize ;
3151 newClone->stackToVisit =
3152 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3155 newClone->stackToVisit,
3157 sizeof(ULONG) * newClone->stackSize);
3159 *ppenum = (IEnumSTATSTG*)newClone;
3162 * Don't forget to nail down a reference to the clone before
3165 IEnumSTATSTGImpl_AddRef(*ppenum);
3170 INT32 IEnumSTATSTGImpl_FindParentProperty(
3171 IEnumSTATSTGImpl *This,
3172 ULONG childProperty,
3173 StgProperty *currentProperty,
3176 ULONG currentSearchNode;
3180 * To avoid the special case, get another pointer to a ULONG value if
3181 * the caller didn't supply one.
3184 thisNodeId = &foundNode;
3187 * Start with the node at the top of the stack.
3189 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3192 while (currentSearchNode!=PROPERTY_NULL)
3195 * Store the current node in the returned parameters
3197 *thisNodeId = currentSearchNode;
3200 * Remove the top node from the stack
3202 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3205 * Read the property from the storage.
3207 Storage32Impl_ReadProperty(
3208 This->parentStorage,
3212 if (currentProperty->previousProperty == childProperty)
3213 return PROPERTY_RELATION_PREVIOUS;
3215 else if (currentProperty->nextProperty == childProperty)
3216 return PROPERTY_RELATION_NEXT;
3218 else if (currentProperty->dirProperty == childProperty)
3219 return PROPERTY_RELATION_DIR;
3222 * Push the next search node in the search stack.
3224 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3227 * continue the iteration.
3229 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3232 return PROPERTY_NULL;
3235 ULONG IEnumSTATSTGImpl_FindProperty(
3236 IEnumSTATSTGImpl* This,
3237 const OLECHAR32* lpszPropName,
3238 StgProperty* currentProperty)
3240 ULONG currentSearchNode;
3243 * Start with the node at the top of the stack.
3245 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3247 while (currentSearchNode!=PROPERTY_NULL)
3250 * Remove the top node from the stack
3252 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3255 * Read the property from the storage.
3257 Storage32Impl_ReadProperty(This->parentStorage,
3261 if ( propertyNameCmp(
3262 (OLECHAR32*)currentProperty->name,
3263 (OLECHAR32*)lpszPropName) == 0)
3264 return currentSearchNode;
3267 * Push the next search node in the search stack.
3269 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3272 * continue the iteration.
3274 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3277 return PROPERTY_NULL;
3280 void IEnumSTATSTGImpl_PushSearchNode(
3281 IEnumSTATSTGImpl* This,
3284 StgProperty rootProperty;
3285 BOOL32 readSucessful;
3288 * First, make sure we're not trying to push an unexisting node.
3290 if (nodeToPush==PROPERTY_NULL)
3294 * First push the node to the stack
3296 if (This->stackSize == This->stackMaxSize)
3298 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3300 This->stackToVisit = HeapReAlloc(
3304 sizeof(ULONG) * This->stackMaxSize);
3307 This->stackToVisit[This->stackSize] = nodeToPush;
3311 * Read the root property from the storage.
3313 readSucessful = Storage32Impl_ReadProperty(
3314 This->parentStorage,
3320 assert(rootProperty.sizeOfNameString!=0);
3323 * Push the previous search node in the search stack.
3325 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3329 ULONG IEnumSTATSTGImpl_PopSearchNode(
3330 IEnumSTATSTGImpl* This,
3335 if (This->stackSize == 0)
3336 return PROPERTY_NULL;
3338 topNode = This->stackToVisit[This->stackSize-1];
3346 /******************************************************************************
3347 ** StorageUtl implementation
3350 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3352 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3355 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3357 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3360 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3362 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3365 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3367 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3370 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3372 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3373 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3374 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3376 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3379 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3381 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3382 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3383 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3385 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3388 void StorageUtl_CopyPropertyToSTATSTG(
3389 STATSTG* destination,
3390 StgProperty* source,
3394 * The copy of the string occurs only when the flag is not set
3396 if ((statFlags & STATFLAG_NONAME) != 0)
3398 destination->pwcsName = 0;
3402 destination->pwcsName =
3403 CoTaskMemAlloc((lstrlen32W(source->name)+1)*sizeof(WCHAR));
3405 lstrcpy32W((LPWSTR)destination->pwcsName, source->name);
3408 switch (source->propertyType)
3410 case PROPTYPE_STORAGE:
3412 destination->type = STGTY_STORAGE;
3414 case PROPTYPE_STREAM:
3415 destination->type = STGTY_STREAM;
3418 destination->type = STGTY_STREAM;
3422 destination->cbSize = source->size;
3424 currentReturnStruct->mtime = {0}; TODO
3425 currentReturnStruct->ctime = {0};
3426 currentReturnStruct->atime = {0};
3428 destination->grfMode = 0;
3429 destination->grfLocksSupported = 0;
3430 destination->clsid = source->propertyUniqueID;
3431 destination->grfStateBits = 0;
3432 destination->reserved = 0;
3435 /******************************************************************************
3436 ** BlockChainStream implementation
3439 BlockChainStream* BlockChainStream_Construct(
3440 Storage32Impl* parentStorage,
3441 ULONG* headOfStreamPlaceHolder,
3442 ULONG propertyIndex)
3444 BlockChainStream* newStream;
3446 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3448 newStream->parentStorage = parentStorage;
3449 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3450 newStream->ownerPropertyIndex = propertyIndex;
3455 void BlockChainStream_Destroy(BlockChainStream* This)
3457 HeapFree(GetProcessHeap(), 0, This);
3460 /******************************************************************************
3461 * BlockChainStream_GetHeadOfChain
3463 * Returns the head of this stream chain.
3464 * Some special chains don't have properties, their heads are kept in
3465 * This->headOfStreamPlaceHolder.
3468 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3470 StgProperty chainProperty;
3471 BOOL32 readSucessful;
3473 if (This->headOfStreamPlaceHolder != 0)
3474 return *(This->headOfStreamPlaceHolder);
3476 if (This->ownerPropertyIndex != PROPERTY_NULL)
3478 readSucessful = Storage32Impl_ReadProperty(
3479 This->parentStorage,
3480 This->ownerPropertyIndex,
3485 return chainProperty.startingBlock;
3489 return BLOCK_END_OF_CHAIN;
3492 /******************************************************************************
3493 * BlockChainStream_GetCount
3495 * Returns the number of blocks that comprises this chain.
3496 * This is not the size of the stream as the last block may not be full!
3499 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3504 blockIndex = BlockChainStream_GetHeadOfChain(This);
3506 while (blockIndex != BLOCK_END_OF_CHAIN)
3510 blockIndex = Storage32Impl_GetNextBlockInChain(
3511 This->parentStorage,
3518 /******************************************************************************
3519 * BlockChainStream_ReadAt
3521 * Reads a specified number of bytes from this chain at the specified offset.
3522 * bytesRead may be NULL.
3523 * Failure will be returned if the specified number of bytes has not been read.
3525 BOOL32 BlockChainStream_ReadAt(BlockChainStream* This,
3526 ULARGE_INTEGER offset,
3531 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3532 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3533 ULONG bytesToReadInBuffer;
3536 BYTE* bigBlockBuffer;
3539 * Find the first block in the stream that contains part of the buffer.
3541 blockIndex = BlockChainStream_GetHeadOfChain(This);
3543 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3546 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3548 blockNoInSequence--;
3552 * Start reading the buffer.
3555 bufferWalker = buffer;
3557 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3560 * Calculate how many bytes we can copy from this big block.
3562 bytesToReadInBuffer =
3563 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3566 * Copy those bytes to the buffer
3569 Storage32Impl_GetROBigBlock(This->parentStorage, blockIndex);
3571 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3573 Storage32Impl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3576 * Step to the next big block.
3579 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3581 bufferWalker += bytesToReadInBuffer;
3582 size -= bytesToReadInBuffer;
3583 *bytesRead += bytesToReadInBuffer;
3584 offsetInBlock = 0; /* There is no offset on the next block */
3591 /******************************************************************************
3592 * BlockChainStream_WriteAt
3594 * Writes the specified number of bytes to this chain at the specified offset.
3595 * bytesWritten may be NULL.
3596 * Will fail if not all specified number of bytes have been written.
3598 BOOL32 BlockChainStream_WriteAt(BlockChainStream* This,
3599 ULARGE_INTEGER offset,
3602 ULONG* bytesWritten)
3604 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3605 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3609 BYTE* bigBlockBuffer;
3612 * Find the first block in the stream that contains part of the buffer.
3614 blockIndex = BlockChainStream_GetHeadOfChain(This);
3616 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3619 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3621 blockNoInSequence--;
3625 * Here, I'm casting away the constness on the buffer variable
3626 * This is OK since we don't intend to modify that buffer.
3629 bufferWalker = (BYTE*)buffer;
3631 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3634 * Calculate how many bytes we can copy from this big block.
3637 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3640 * Copy those bytes to the buffer
3642 bigBlockBuffer = Storage32Impl_GetBigBlock(This->parentStorage, blockIndex);
3644 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
3646 Storage32Impl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3649 * Step to the next big block.
3652 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3654 bufferWalker += bytesToWrite;
3655 size -= bytesToWrite;
3656 *bytesWritten += bytesToWrite;
3657 offsetInBlock = 0; /* There is no offset on the next block */
3663 /******************************************************************************
3664 * BlockChainStream_Shrink
3666 * Shrinks this chain in the big block depot.
3668 BOOL32 BlockChainStream_Shrink(BlockChainStream* This,
3669 ULARGE_INTEGER newSize)
3671 ULONG blockIndex, extraBlock;
3676 * Figure out how many blocks are needed to contain the new size
3678 numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3680 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3683 blockIndex = BlockChainStream_GetHeadOfChain(This);
3686 * Go to the new end of chain
3688 while (count < numBlocks)
3691 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3696 /* Get the next block before marking the new end */
3698 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3700 /* Mark the new end of chain */
3701 Storage32Impl_SetNextBlockInChain(
3702 This->parentStorage,
3704 BLOCK_END_OF_CHAIN);
3707 * Mark the extra blocks as free
3709 while (extraBlock != BLOCK_END_OF_CHAIN)
3712 Storage32Impl_GetNextBlockInChain(This->parentStorage, extraBlock);
3714 Storage32Impl_FreeBigBlock(This->parentStorage, extraBlock);
3715 extraBlock = blockIndex;
3721 /******************************************************************************
3722 * BlockChainStream_Enlarge
3724 * Grows this chain in the big block depot.
3726 BOOL32 BlockChainStream_Enlarge(BlockChainStream* This,
3727 ULARGE_INTEGER newSize)
3729 ULONG blockIndex, currentBlock;
3731 ULONG oldNumBlocks = 0;
3733 blockIndex = BlockChainStream_GetHeadOfChain(This);
3736 * Empty chain. Create the head.
3738 if (blockIndex == BLOCK_END_OF_CHAIN)
3740 blockIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
3741 Storage32Impl_SetNextBlockInChain(This->parentStorage,
3743 BLOCK_END_OF_CHAIN);
3745 if (This->headOfStreamPlaceHolder != 0)
3747 *(This->headOfStreamPlaceHolder) = blockIndex;
3751 StgProperty chainProp;
3752 assert(This->ownerPropertyIndex != PROPERTY_NULL);
3754 Storage32Impl_ReadProperty(
3755 This->parentStorage,
3756 This->ownerPropertyIndex,
3759 chainProp.startingBlock = blockIndex;
3761 Storage32Impl_WriteProperty(
3762 This->parentStorage,
3763 This->ownerPropertyIndex,
3768 currentBlock = blockIndex;
3771 * Figure out how many blocks are needed to contain this stream
3773 newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3775 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3779 * Go to the current end of chain
3781 while (blockIndex != BLOCK_END_OF_CHAIN)
3784 currentBlock = blockIndex;
3787 Storage32Impl_GetNextBlockInChain(This->parentStorage, currentBlock);
3791 * Add new blocks to the chain
3793 while (oldNumBlocks < newNumBlocks)
3795 blockIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
3797 Storage32Impl_SetNextBlockInChain(
3798 This->parentStorage,
3802 Storage32Impl_SetNextBlockInChain(
3803 This->parentStorage,
3805 BLOCK_END_OF_CHAIN);
3807 currentBlock = blockIndex;
3814 /******************************************************************************
3815 * BlockChainStream_SetSize
3817 * Sets the size of this stream. The big block depot will be updated.
3818 * The file will grow if we grow the chain.
3820 * TODO: Free the actual blocks in the file when we shrink the chain.
3821 * Currently, the blocks are still in the file. So the file size
3822 * doesn't shrink even if we shrink streams.
3824 BOOL32 BlockChainStream_SetSize(
3825 BlockChainStream* This,
3826 ULARGE_INTEGER newSize)
3828 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
3830 if (newSize.LowPart == size.LowPart)
3833 if (newSize.LowPart < size.LowPart)
3835 BlockChainStream_Shrink(This, newSize);
3839 ULARGE_INTEGER fileSize =
3840 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
3842 ULONG diff = newSize.LowPart - size.LowPart;
3845 * Make sure the file stays a multiple of blocksize
3847 if ((diff % This->parentStorage->bigBlockSize) != 0)
3848 diff += (This->parentStorage->bigBlockSize -
3849 (diff % This->parentStorage->bigBlockSize) );
3851 fileSize.LowPart += diff;
3852 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
3854 BlockChainStream_Enlarge(This, newSize);
3860 /******************************************************************************
3861 * BlockChainStream_GetSize
3863 * Returns the size of this chain.
3864 * Will return the block count if this chain doesn't have a property.
3866 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
3868 StgProperty chainProperty;
3870 if(This->headOfStreamPlaceHolder == NULL)
3873 * This chain is a data stream read the property and return
3874 * the appropriate size
3876 Storage32Impl_ReadProperty(
3877 This->parentStorage,
3878 This->ownerPropertyIndex,
3881 return chainProperty.size;
3886 * this chain is a chain that does not have a property, figure out the
3887 * size by making the product number of used blocks times the
3890 ULARGE_INTEGER result;
3891 result.HighPart = 0;
3894 BlockChainStream_GetCount(This) *
3895 This->parentStorage->bigBlockSize;
3901 /******************************************************************************
3902 ** SmallBlockChainStream implementation
3905 SmallBlockChainStream* SmallBlockChainStream_Construct(
3906 Storage32Impl* parentStorage,
3907 ULONG propertyIndex)
3909 SmallBlockChainStream* newStream;
3911 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
3913 newStream->parentStorage = parentStorage;
3914 newStream->ownerPropertyIndex = propertyIndex;
3919 void SmallBlockChainStream_Destroy(
3920 SmallBlockChainStream* This)
3922 HeapFree(GetProcessHeap(), 0, This);
3925 /******************************************************************************
3926 * SmallBlockChainStream_GetHeadOfChain
3928 * Returns the head of this chain of small blocks.
3930 ULONG SmallBlockChainStream_GetHeadOfChain(
3931 SmallBlockChainStream* This)
3933 StgProperty chainProperty;
3934 BOOL32 readSucessful;
3936 if (This->ownerPropertyIndex)
3938 readSucessful = Storage32Impl_ReadProperty(
3939 This->parentStorage,
3940 This->ownerPropertyIndex,
3945 return chainProperty.startingBlock;
3950 return BLOCK_END_OF_CHAIN;
3953 /******************************************************************************
3954 * SmallBlockChainStream_GetNextBlockInChain
3956 * Returns the index of the next small block in this chain.
3959 * - BLOCK_END_OF_CHAIN: end of this chain
3960 * - BLOCK_UNUSED: small block 'blockIndex' is free
3962 ULONG SmallBlockChainStream_GetNextBlockInChain(
3963 SmallBlockChainStream* This,
3966 ULARGE_INTEGER offsetOfBlockInDepot;
3968 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
3972 offsetOfBlockInDepot.HighPart = 0;
3973 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
3976 * Read those bytes in the buffer from the small block file.
3978 success = BlockChainStream_ReadAt(
3979 This->parentStorage->smallBlockDepotChain,
3980 offsetOfBlockInDepot,
3987 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
3990 return nextBlockInChain;
3993 /******************************************************************************
3994 * SmallBlockChainStream_SetNextBlockInChain
3996 * Writes the index of the next block of the specified block in the small
3998 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
3999 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4001 void SmallBlockChainStream_SetNextBlockInChain(
4002 SmallBlockChainStream* This,
4006 ULARGE_INTEGER offsetOfBlockInDepot;
4010 offsetOfBlockInDepot.HighPart = 0;
4011 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4013 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4016 * Read those bytes in the buffer from the small block file.
4018 BlockChainStream_WriteAt(
4019 This->parentStorage->smallBlockDepotChain,
4020 offsetOfBlockInDepot,
4026 /******************************************************************************
4027 * SmallBlockChainStream_FreeBlock
4029 * Flag small block 'blockIndex' as free in the small block depot.
4031 void SmallBlockChainStream_FreeBlock(
4032 SmallBlockChainStream* This,
4035 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4038 /******************************************************************************
4039 * SmallBlockChainStream_GetNextFreeBlock
4041 * Returns the index of a free small block. The small block depot will be
4042 * enlarged if necessary. The small block chain will also be enlarged if
4045 ULONG SmallBlockChainStream_GetNextFreeBlock(
4046 SmallBlockChainStream* This)
4048 ULARGE_INTEGER offsetOfBlockInDepot;
4051 ULONG blockIndex = 0;
4052 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4053 BOOL32 success = TRUE;
4054 ULONG smallBlocksPerBigBlock;
4056 offsetOfBlockInDepot.HighPart = 0;
4059 * Scan the small block depot for a free block
4061 while (nextBlockIndex != BLOCK_UNUSED)
4063 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4065 success = BlockChainStream_ReadAt(
4066 This->parentStorage->smallBlockDepotChain,
4067 offsetOfBlockInDepot,
4073 * If we run out of space for the small block depot, enlarge it
4077 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4079 if (nextBlockIndex != BLOCK_UNUSED)
4085 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4087 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4088 ULONG nextBlock, newsbdIndex;
4089 BYTE* smallBlockDepot;
4091 nextBlock = sbdIndex;
4092 while (nextBlock != BLOCK_END_OF_CHAIN)
4094 sbdIndex = nextBlock;
4096 Storage32Impl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4099 newsbdIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
4100 if (sbdIndex != BLOCK_END_OF_CHAIN)
4101 Storage32Impl_SetNextBlockInChain(
4102 This->parentStorage,
4106 Storage32Impl_SetNextBlockInChain(
4107 This->parentStorage,
4109 BLOCK_END_OF_CHAIN);
4112 * Initialize all the small blocks to free
4115 Storage32Impl_GetBigBlock(This->parentStorage, newsbdIndex);
4117 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4118 Storage32Impl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4123 * We have just created the small block depot.
4125 StgProperty rootProp;
4129 * Save it in the header
4131 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4132 Storage32Impl_SaveFileHeader(This->parentStorage);
4135 * And allocate the first big block that will contain small blocks
4138 Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
4140 Storage32Impl_SetNextBlockInChain(
4141 This->parentStorage,
4143 BLOCK_END_OF_CHAIN);
4145 Storage32Impl_ReadProperty(
4146 This->parentStorage,
4147 This->parentStorage->rootPropertySetIndex,
4150 rootProp.startingBlock = sbStartIndex;
4151 rootProp.size.HighPart = 0;
4152 rootProp.size.LowPart = This->parentStorage->bigBlockSize;
4154 Storage32Impl_WriteProperty(
4155 This->parentStorage,
4156 This->parentStorage->rootPropertySetIndex,
4162 smallBlocksPerBigBlock =
4163 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4166 * Verify if we have to allocate big blocks to contain small blocks
4168 if (blockIndex % smallBlocksPerBigBlock == 0)
4170 StgProperty rootProp;
4171 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4173 Storage32Impl_ReadProperty(
4174 This->parentStorage,
4175 This->parentStorage->rootPropertySetIndex,
4178 if (rootProp.size.LowPart <
4179 (blocksRequired * This->parentStorage->bigBlockSize))
4181 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4183 BlockChainStream_SetSize(
4184 This->parentStorage->smallBlockRootChain,
4187 Storage32Impl_WriteProperty(
4188 This->parentStorage,
4189 This->parentStorage->rootPropertySetIndex,
4197 /******************************************************************************
4198 * SmallBlockChainStream_ReadAt
4200 * Reads a specified number of bytes from this chain at the specified offset.
4201 * bytesRead may be NULL.
4202 * Failure will be returned if the specified number of bytes has not been read.
4204 BOOL32 SmallBlockChainStream_ReadAt(
4205 SmallBlockChainStream* This,
4206 ULARGE_INTEGER offset,
4211 ULARGE_INTEGER offsetInBigBlockFile;
4212 ULONG blockNoInSequence =
4213 offset.LowPart / This->parentStorage->smallBlockSize;
4215 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4216 ULONG bytesToReadInBuffer;
4218 ULONG bytesReadFromBigBlockFile;
4222 * This should never happen on a small block file.
4224 assert(offset.HighPart==0);
4227 * Find the first block in the stream that contains part of the buffer.
4229 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4231 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4233 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4235 blockNoInSequence--;
4239 * Start reading the buffer.
4242 bufferWalker = buffer;
4244 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4247 * Calculate how many bytes we can copy from this small block.
4249 bytesToReadInBuffer =
4250 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4253 * Calculate the offset of the small block in the small block file.
4255 offsetInBigBlockFile.HighPart = 0;
4256 offsetInBigBlockFile.LowPart =
4257 blockIndex * This->parentStorage->smallBlockSize;
4259 offsetInBigBlockFile.LowPart += offsetInBlock;
4262 * Read those bytes in the buffer from the small block file.
4264 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4265 offsetInBigBlockFile,
4266 bytesToReadInBuffer,
4268 &bytesReadFromBigBlockFile);
4270 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4273 * Step to the next big block.
4275 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4276 bufferWalker += bytesToReadInBuffer;
4277 size -= bytesToReadInBuffer;
4278 *bytesRead += bytesToReadInBuffer;
4279 offsetInBlock = 0; /* There is no offset on the next block */
4285 /******************************************************************************
4286 * SmallBlockChainStream_WriteAt
4288 * Writes the specified number of bytes to this chain at the specified offset.
4289 * bytesWritten may be NULL.
4290 * Will fail if not all specified number of bytes have been written.
4292 BOOL32 SmallBlockChainStream_WriteAt(
4293 SmallBlockChainStream* This,
4294 ULARGE_INTEGER offset,
4297 ULONG* bytesWritten)
4299 ULARGE_INTEGER offsetInBigBlockFile;
4300 ULONG blockNoInSequence =
4301 offset.LowPart / This->parentStorage->smallBlockSize;
4303 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4304 ULONG bytesToWriteInBuffer;
4306 ULONG bytesWrittenFromBigBlockFile;
4310 * This should never happen on a small block file.
4312 assert(offset.HighPart==0);
4315 * Find the first block in the stream that contains part of the buffer.
4317 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4319 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4321 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4323 blockNoInSequence--;
4327 * Start writing the buffer.
4329 * Here, I'm casting away the constness on the buffer variable
4330 * This is OK since we don't intend to modify that buffer.
4333 bufferWalker = (BYTE*)buffer;
4334 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4337 * Calculate how many bytes we can copy to this small block.
4339 bytesToWriteInBuffer =
4340 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4343 * Calculate the offset of the small block in the small block file.
4345 offsetInBigBlockFile.HighPart = 0;
4346 offsetInBigBlockFile.LowPart =
4347 blockIndex * This->parentStorage->smallBlockSize;
4349 offsetInBigBlockFile.LowPart += offsetInBlock;
4352 * Write those bytes in the buffer to the small block file.
4354 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4355 offsetInBigBlockFile,
4356 bytesToWriteInBuffer,
4358 &bytesWrittenFromBigBlockFile);
4360 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4363 * Step to the next big block.
4365 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4366 bufferWalker += bytesToWriteInBuffer;
4367 size -= bytesToWriteInBuffer;
4368 *bytesWritten += bytesToWriteInBuffer;
4369 offsetInBlock = 0; /* There is no offset on the next block */
4375 /******************************************************************************
4376 * SmallBlockChainStream_Shrink
4378 * Shrinks this chain in the small block depot.
4380 BOOL32 SmallBlockChainStream_Shrink(
4381 SmallBlockChainStream* This,
4382 ULARGE_INTEGER newSize)
4384 ULONG blockIndex, extraBlock;
4388 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4390 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4393 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4396 * Go to the new end of chain
4398 while (count < numBlocks)
4400 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4404 /* Get the next block before marking the new end */
4405 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4407 /* Mark the new end of chain */
4408 SmallBlockChainStream_SetNextBlockInChain(
4411 BLOCK_END_OF_CHAIN);
4414 * Mark the extra blocks as free
4416 while (extraBlock != BLOCK_END_OF_CHAIN)
4418 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4419 SmallBlockChainStream_FreeBlock(This, extraBlock);
4420 extraBlock = blockIndex;
4426 /******************************************************************************
4427 * SmallBlockChainStream_Enlarge
4429 * Grows this chain in the small block depot.
4431 BOOL32 SmallBlockChainStream_Enlarge(
4432 SmallBlockChainStream* This,
4433 ULARGE_INTEGER newSize)
4435 ULONG blockIndex, currentBlock;
4437 ULONG oldNumBlocks = 0;
4439 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4444 if (blockIndex == BLOCK_END_OF_CHAIN)
4446 StgProperty chainProp;
4448 Storage32Impl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4451 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4453 Storage32Impl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4456 blockIndex = chainProp.startingBlock;
4457 SmallBlockChainStream_SetNextBlockInChain(
4460 BLOCK_END_OF_CHAIN);
4463 currentBlock = blockIndex;
4466 * Figure out how many blocks are needed to contain this stream
4468 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4470 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4474 * Go to the current end of chain
4476 while (blockIndex != BLOCK_END_OF_CHAIN)
4479 currentBlock = blockIndex;
4480 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4484 * Add new blocks to the chain
4486 while (oldNumBlocks < newNumBlocks)
4488 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4489 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4491 SmallBlockChainStream_SetNextBlockInChain(
4494 BLOCK_END_OF_CHAIN);
4496 currentBlock = blockIndex;
4503 /******************************************************************************
4504 * SmallBlockChainStream_GetCount
4506 * Returns the number of blocks that comprises this chain.
4507 * This is not the size of this chain as the last block may not be full!
4509 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4514 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4516 while (blockIndex != BLOCK_END_OF_CHAIN)
4520 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4526 /******************************************************************************
4527 * SmallBlockChainStream_SetSize
4529 * Sets the size of this stream.
4530 * The file will grow if we grow the chain.
4532 * TODO: Free the actual blocks in the file when we shrink the chain.
4533 * Currently, the blocks are still in the file. So the file size
4534 * doesn't shrink even if we shrink streams.
4536 BOOL32 SmallBlockChainStream_SetSize(
4537 SmallBlockChainStream* This,
4538 ULARGE_INTEGER newSize)
4540 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4542 if (newSize.LowPart == size.LowPart)
4545 if (newSize.LowPart < size.LowPart)
4547 SmallBlockChainStream_Shrink(This, newSize);
4551 SmallBlockChainStream_Enlarge(This, newSize);
4557 /******************************************************************************
4558 * SmallBlockChainStream_GetSize
4560 * Returns the size of this chain.
4562 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4564 StgProperty chainProperty;
4566 Storage32Impl_ReadProperty(
4567 This->parentStorage,
4568 This->ownerPropertyIndex,
4571 return chainProperty.size;
4574 /******************************************************************************
4575 * StgCreateDocfile32 [OLE32.144]
4576 * TODO Validate grfMode (STGM)
4578 HRESULT WINAPI StgCreateDocfile32(
4579 LPCOLESTR32 pwcsName,
4582 IStorage32 **ppstgOpen)
4584 Storage32Impl* newStorage = 0;
4585 HANDLE32 hFile = INVALID_HANDLE_VALUE32;
4590 DWORD fileAttributes;
4593 * Validate the parameters
4595 if ((ppstgOpen == 0) || (pwcsName == 0))
4596 return STG_E_INVALIDPOINTER;
4599 * Validate the STGM flags
4601 if ( FAILED( validateSTGM(grfMode) ))
4602 return STG_E_INVALIDFLAG;
4605 * Interpret the STGM value grfMode
4607 shareMode = GetShareModeFromSTGM(grfMode);
4608 accessMode = GetAccessModeFromSTGM(grfMode);
4609 creationMode = GetCreationModeFromSTGM(grfMode);
4611 if (grfMode & STGM_DELETEONRELEASE)
4612 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
4614 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
4616 if (grfMode & STGM_TRANSACTED)
4617 FIXME(ole, "Transacted mode not implemented.\n");
4620 * Initialize the "out" parameter.
4624 hFile = CreateFile32W(pwcsName,
4632 if (hFile == INVALID_HANDLE_VALUE32)
4638 * Allocate and initialize the new IStorage32object.
4640 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl));
4642 if (newStorage == 0)
4643 return STG_E_INSUFFICIENTMEMORY;
4645 hr = Storage32Impl_Construct(
4654 * Get an "out" pointer for the caller.
4656 hr = Storage32BaseImpl_QueryInterface(
4657 (IStorage32*)newStorage,
4658 (REFIID)&IID_IStorage,
4664 /******************************************************************************
4665 * StgOpenStorage32 [OLE32.148]
4667 HRESULT WINAPI StgOpenStorage32(
4668 const OLECHAR32 *pwcsName,
4669 IStorage32 *pstgPriority,
4673 IStorage32 **ppstgOpen)
4675 Storage32Impl* newStorage = 0;
4682 * Perform a sanity check
4684 if (( pwcsName == 0) || (ppstgOpen == 0) )
4685 return STG_E_INVALIDPOINTER;
4688 * Validate the STGM flags
4690 if ( FAILED( validateSTGM(grfMode) ))
4691 return STG_E_INVALIDFLAG;
4694 * Interpret the STGM value grfMode
4696 shareMode = GetShareModeFromSTGM(grfMode);
4697 accessMode = GetAccessModeFromSTGM(grfMode);
4700 * Initialize the "out" parameter.
4704 hFile = CreateFile32W( pwcsName,
4709 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
4713 if (hFile==INVALID_HANDLE_VALUE32)
4719 * Allocate and initialize the new IStorage32object.
4721 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl));
4723 if (newStorage == 0)
4724 return STG_E_INSUFFICIENTMEMORY;
4726 hr = Storage32Impl_Construct(
4735 * Get an "out" pointer for the caller.
4737 hr = Storage32BaseImpl_QueryInterface(
4738 (IStorage32*)newStorage,
4739 (REFIID)&IID_IStorage,
4745 /******************************************************************************
4746 * WriteClassStg32 [OLE32.148]
4748 * This method will store the specified CLSID in the specified storage object
4750 HRESULT WINAPI WriteClassStg32(IStorage32* pStg, REFCLSID rclsid)
4756 hRes = IStorage32_SetClass(pStg, rclsid);
4762 /****************************************************************************
4763 * This method validate a STGM parameter that can contain the values below
4765 * STGM_DIRECT 0x00000000
4766 * STGM_TRANSACTED 0x00010000
4767 * STGM_SIMPLE 0x08000000
4769 * STGM_READ 0x00000000
4770 * STGM_WRITE 0x00000001
4771 * STGM_READWRITE 0x00000002
4773 * STGM_SHARE_DENY_NONE 0x00000040
4774 * STGM_SHARE_DENY_READ 0x00000030
4775 * STGM_SHARE_DENY_WRITE 0x00000020
4776 * STGM_SHARE_EXCLUSIVE 0x00000010
4778 * STGM_PRIORITY 0x00040000
4779 * STGM_DELETEONRELEASE 0x04000000
4781 * STGM_CREATE 0x00001000
4782 * STGM_CONVERT 0x00020000
4783 * STGM_FAILIFTHERE 0x00000000
4785 * STGM_NOSCRATCH 0x00100000
4786 * STGM_NOSNAPSHOT 0x00200000
4788 static HRESULT validateSTGM(DWORD stgm)
4790 BOOL32 bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
4791 BOOL32 bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
4792 BOOL32 bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
4794 BOOL32 bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
4795 BOOL32 bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
4796 BOOL32 bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
4798 BOOL32 bSTGM_SHARE_DENY_NONE =
4799 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
4801 BOOL32 bSTGM_SHARE_DENY_READ =
4802 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
4804 BOOL32 bSTGM_SHARE_DENY_WRITE =
4805 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
4807 BOOL32 bSTGM_SHARE_EXCLUSIVE =
4808 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
4810 BOOL32 bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
4811 BOOL32 bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
4813 BOOL32 bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
4814 BOOL32 bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
4817 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
4819 if ( ! bSTGM_DIRECT )
4820 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
4824 * STGM_WRITE | STGM_READWRITE | STGM_READ
4827 if( bSTGM_WRITE && bSTGM_READWRITE )
4831 * STGM_SHARE_DENY_NONE | others
4832 * (I assume here that DENY_READ implies DENY_WRITE)
4834 if ( bSTGM_SHARE_DENY_NONE )
4835 if ( bSTGM_SHARE_DENY_READ ||
4836 bSTGM_SHARE_DENY_WRITE ||
4837 bSTGM_SHARE_EXCLUSIVE)
4841 * STGM_CREATE | STGM_CONVERT
4842 * if both are false, STGM_FAILIFTHERE is set to TRUE
4844 if ( bSTGM_CREATE && bSTGM_CONVERT )
4848 * STGM_NOSCRATCH requires STGM_TRANSACTED
4850 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
4854 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
4855 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
4857 if (bSTGM_NOSNAPSHOT)
4859 if ( ! ( bSTGM_TRANSACTED &&
4860 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
4867 /****************************************************************************
4868 * GetShareModeFromSTGM
4870 * This method will return a share mode flag from a STGM value.
4871 * The STGM value is assumed valid.
4873 static DWORD GetShareModeFromSTGM(DWORD stgm)
4875 DWORD dwShareMode = 0;
4876 BOOL32 bSTGM_SHARE_DENY_NONE =
4877 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
4879 BOOL32 bSTGM_SHARE_DENY_READ =
4880 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
4882 BOOL32 bSTGM_SHARE_DENY_WRITE =
4883 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
4885 BOOL32 bSTGM_SHARE_EXCLUSIVE =
4886 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
4888 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
4891 if (bSTGM_SHARE_DENY_NONE)
4892 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
4894 if (bSTGM_SHARE_DENY_WRITE)
4895 dwShareMode = FILE_SHARE_READ;
4900 /****************************************************************************
4901 * GetAccessModeFromSTGM
4903 * This method will return an access mode flag from a STGM value.
4904 * The STGM value is assumed valid.
4906 static DWORD GetAccessModeFromSTGM(DWORD stgm)
4908 DWORD dwDesiredAccess = 0;
4909 BOOL32 bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
4910 BOOL32 bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
4911 BOOL32 bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
4914 dwDesiredAccess = GENERIC_READ;
4917 dwDesiredAccess |= GENERIC_WRITE;
4919 if (bSTGM_READWRITE)
4920 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
4922 return dwDesiredAccess;
4925 /****************************************************************************
4926 * GetCreationModeFromSTGM
4928 * This method will return a creation mode flag from a STGM value.
4929 * The STGM value is assumed valid.
4931 static DWORD GetCreationModeFromSTGM(DWORD stgm)
4933 DWORD dwCreationDistribution;
4934 BOOL32 bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
4935 BOOL32 bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
4936 BOOL32 bSTGM_FAILIFTHERE = ! (bSTGM_CREATE || bSTGM_CONVERT);
4939 dwCreationDistribution = CREATE_NEW;
4940 else if (bSTGM_FAILIFTHERE)
4941 dwCreationDistribution = CREATE_NEW;
4942 else if (bSTGM_CONVERT)
4944 FIXME(ole, "STGM_CONVERT not implemented!\n");
4945 dwCreationDistribution = CREATE_NEW;
4948 return dwCreationDistribution;