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
17 #include "winbase.h" /* for lstrlenW() and the likes */
19 #include "debugtools.h"
21 #include "storage32.h"
22 #include "ole2.h" /* For Write/ReadClassStm */
25 #include "wine/wingdi16.h"
27 DEFAULT_DEBUG_CHANNEL(storage)
32 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
33 #define OLESTREAM_ID 0x501
34 #define OLESTREAM_MAX_STR_LEN 255
36 static const char rootPropertyName[] = "Root Entry";
39 /* OLESTREAM memory structure to use for Get and Put Routines */
40 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
45 DWORD dwOleTypeNameLength;
46 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
47 CHAR *pstrOleObjFileName;
48 DWORD dwOleObjFileNameLength;
49 DWORD dwMetaFileWidth;
50 DWORD dwMetaFileHeight;
51 CHAR strUnknown[8]; //don't know what is this 8 byts information in OLE stream.
54 }OLECONVERT_OLESTREAM_DATA;
56 /* CompObj Stream structure */
57 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
62 DWORD dwCLSIDNameLength;
63 CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
64 DWORD dwOleTypeNameLength;
65 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
66 DWORD dwProgIDNameLength;
67 CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
69 }OLECONVERT_ISTORAGE_COMPOBJ;
72 /* Ole Presention Stream structure */
73 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
81 }OLECONVERT_ISTORAGE_OLEPRES;
85 /***********************************************************************
86 * Forward declaration of internal functions used by the method DestroyElement
88 static HRESULT deleteStorageProperty(
89 StorageImpl *parentStorage,
90 ULONG foundPropertyIndexToDelete,
91 StgProperty propertyToDelete);
93 static HRESULT deleteStreamProperty(
94 StorageImpl *parentStorage,
95 ULONG foundPropertyIndexToDelete,
96 StgProperty propertyToDelete);
98 static HRESULT findPlaceholder(
100 ULONG propertyIndexToStore,
101 ULONG storagePropertyIndex,
104 static HRESULT adjustPropertyChain(
106 StgProperty propertyToDelete,
107 StgProperty parentProperty,
108 ULONG parentPropertyId,
111 /***********************************************************************
112 * Declaration of the functions used to manipulate StgProperty
115 static ULONG getFreeProperty(
116 StorageImpl *storage);
118 static void updatePropertyChain(
119 StorageImpl *storage,
120 ULONG newPropertyIndex,
121 StgProperty newProperty);
123 static LONG propertyNameCmp(
124 OLECHAR *newProperty,
125 OLECHAR *currentProperty);
128 /***********************************************************************
129 * Declaration of miscellaneous functions...
131 static HRESULT validateSTGM(DWORD stgmValue);
133 static DWORD GetShareModeFromSTGM(DWORD stgm);
134 static DWORD GetAccessModeFromSTGM(DWORD stgm);
135 static DWORD GetCreationModeFromSTGM(DWORD stgm);
138 * Virtual function table for the IStorage32Impl class.
140 static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
142 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
143 StorageBaseImpl_QueryInterface,
144 StorageBaseImpl_AddRef,
145 StorageBaseImpl_Release,
146 StorageBaseImpl_CreateStream,
147 StorageBaseImpl_OpenStream,
148 StorageImpl_CreateStorage,
149 StorageBaseImpl_OpenStorage,
151 StorageImpl_MoveElementTo,
154 StorageBaseImpl_EnumElements,
155 StorageImpl_DestroyElement,
156 StorageBaseImpl_RenameElement,
157 StorageImpl_SetElementTimes,
158 StorageBaseImpl_SetClass,
159 StorageImpl_SetStateBits,
164 * Virtual function table for the Storage32InternalImpl class.
166 static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
168 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
169 StorageBaseImpl_QueryInterface,
170 StorageBaseImpl_AddRef,
171 StorageBaseImpl_Release,
172 StorageBaseImpl_CreateStream,
173 StorageBaseImpl_OpenStream,
174 StorageImpl_CreateStorage,
175 StorageBaseImpl_OpenStorage,
177 StorageImpl_MoveElementTo,
178 StorageInternalImpl_Commit,
179 StorageInternalImpl_Revert,
180 StorageBaseImpl_EnumElements,
181 StorageImpl_DestroyElement,
182 StorageBaseImpl_RenameElement,
183 StorageImpl_SetElementTimes,
184 StorageBaseImpl_SetClass,
185 StorageImpl_SetStateBits,
190 * Virtual function table for the IEnumSTATSTGImpl class.
192 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
194 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
195 IEnumSTATSTGImpl_QueryInterface,
196 IEnumSTATSTGImpl_AddRef,
197 IEnumSTATSTGImpl_Release,
198 IEnumSTATSTGImpl_Next,
199 IEnumSTATSTGImpl_Skip,
200 IEnumSTATSTGImpl_Reset,
201 IEnumSTATSTGImpl_Clone
208 /************************************************************************
209 ** Storage32BaseImpl implementatiion
212 /************************************************************************
213 * Storage32BaseImpl_QueryInterface (IUnknown)
215 * This method implements the common QueryInterface for all IStorage32
216 * implementations contained in this file.
218 * See Windows documentation for more details on IUnknown methods.
220 HRESULT WINAPI StorageBaseImpl_QueryInterface(
225 ICOM_THIS(StorageBaseImpl,iface);
227 * Perform a sanity check on the parameters.
229 if ( (This==0) || (ppvObject==0) )
233 * Initialize the return parameter.
238 * Compare the riid with the interface IDs implemented by this object.
240 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
242 *ppvObject = (IStorage*)This;
244 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
246 *ppvObject = (IStorage*)This;
250 * Check that we obtained an interface.
253 return E_NOINTERFACE;
256 * Query Interface always increases the reference count by one when it is
259 StorageBaseImpl_AddRef(iface);
264 /************************************************************************
265 * Storage32BaseImpl_AddRef (IUnknown)
267 * This method implements the common AddRef for all IStorage32
268 * implementations contained in this file.
270 * See Windows documentation for more details on IUnknown methods.
272 ULONG WINAPI StorageBaseImpl_AddRef(
275 ICOM_THIS(StorageBaseImpl,iface);
281 /************************************************************************
282 * Storage32BaseImpl_Release (IUnknown)
284 * This method implements the common Release for all IStorage32
285 * implementations contained in this file.
287 * See Windows documentation for more details on IUnknown methods.
289 ULONG WINAPI StorageBaseImpl_Release(
292 ICOM_THIS(StorageBaseImpl,iface);
294 * Decrease the reference count on this object.
299 * If the reference count goes down to 0, perform suicide.
304 * Since we are using a system of base-classes, we want to call the
305 * destructor of the appropriate derived class. To do this, we are
306 * using virtual functions to implement the destructor.
308 This->v_destructor(This);
316 /************************************************************************
317 * Storage32BaseImpl_OpenStream (IStorage)
319 * This method will open the specified stream object from the current storage.
321 * See Windows documentation for more details on IStorage methods.
323 HRESULT WINAPI StorageBaseImpl_OpenStream(
325 const OLECHAR* pwcsName, /* [string][in] */
326 void* reserved1, /* [unique][in] */
327 DWORD grfMode, /* [in] */
328 DWORD reserved2, /* [in] */
329 IStream** ppstm) /* [out] */
331 ICOM_THIS(StorageBaseImpl,iface);
332 IEnumSTATSTGImpl* propertyEnumeration;
333 StgStreamImpl* newStream;
334 StgProperty currentProperty;
335 ULONG foundPropertyIndex;
337 TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
338 iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
341 * Perform a sanity check on the parameters.
343 if ( (pwcsName==NULL) || (ppstm==0) )
347 * Initialize the out parameter
352 * Validate the STGM flags
354 if ( FAILED( validateSTGM(grfMode) ))
355 return STG_E_INVALIDFLAG;
360 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
361 (grfMode & STGM_DELETEONRELEASE) ||
362 (grfMode & STGM_TRANSACTED) )
363 return STG_E_INVALIDFUNCTION;
366 * Create a property enumeration to search the properties
368 propertyEnumeration = IEnumSTATSTGImpl_Construct(
369 This->ancestorStorage,
370 This->rootPropertySetIndex);
373 * Search the enumeration for the property with the given name
375 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
381 * Delete the property enumeration since we don't need it anymore
383 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
386 * If it was found, construct the stream object and return a pointer to it.
388 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
389 (currentProperty.propertyType==PROPTYPE_STREAM) )
391 newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
395 newStream->grfMode = grfMode;
396 *ppstm = (IStream*)newStream;
399 * Since we are returning a pointer to the interface, we have to
400 * nail down the reference.
402 StgStreamImpl_AddRef(*ppstm);
407 return E_OUTOFMEMORY;
410 return STG_E_FILENOTFOUND;
413 /************************************************************************
414 * Storage32BaseImpl_OpenStorage (IStorage)
416 * This method will open a new storage object from the current storage.
418 * See Windows documentation for more details on IStorage methods.
420 HRESULT WINAPI StorageBaseImpl_OpenStorage(
422 const OLECHAR* pwcsName, /* [string][unique][in] */
423 IStorage* pstgPriority, /* [unique][in] */
424 DWORD grfMode, /* [in] */
425 SNB snbExclude, /* [unique][in] */
426 DWORD reserved, /* [in] */
427 IStorage** ppstg) /* [out] */
429 ICOM_THIS(StorageBaseImpl,iface);
430 StorageInternalImpl* newStorage;
431 IEnumSTATSTGImpl* propertyEnumeration;
432 StgProperty currentProperty;
433 ULONG foundPropertyIndex;
435 TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
436 iface, debugstr_w(pwcsName), pstgPriority,
437 grfMode, snbExclude, reserved, ppstg);
440 * Perform a sanity check on the parameters.
442 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
446 * Validate the STGM flags
448 if ( FAILED( validateSTGM(grfMode) ))
449 return STG_E_INVALIDFLAG;
454 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
455 (grfMode & STGM_DELETEONRELEASE) ||
456 (grfMode & STGM_PRIORITY) )
457 return STG_E_INVALIDFUNCTION;
460 * Initialize the out parameter
465 * Create a property enumeration to search the properties
467 propertyEnumeration = IEnumSTATSTGImpl_Construct(
468 This->ancestorStorage,
469 This->rootPropertySetIndex);
472 * Search the enumeration for the property with the given name
474 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
480 * Delete the property enumeration since we don't need it anymore
482 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
485 * If it was found, construct the stream object and return a pointer to it.
487 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
488 (currentProperty.propertyType==PROPTYPE_STORAGE) )
491 * Construct a new Storage object
493 newStorage = StorageInternalImpl_Construct(
494 This->ancestorStorage,
499 *ppstg = (IStorage*)newStorage;
502 * Since we are returning a pointer to the interface,
503 * we have to nail down the reference.
505 StorageBaseImpl_AddRef(*ppstg);
510 return STG_E_INSUFFICIENTMEMORY;
513 return STG_E_FILENOTFOUND;
516 /************************************************************************
517 * Storage32BaseImpl_EnumElements (IStorage)
519 * This method will create an enumerator object that can be used to
520 * retrieve informatino about all the properties in the storage object.
522 * See Windows documentation for more details on IStorage methods.
524 HRESULT WINAPI StorageBaseImpl_EnumElements(
526 DWORD reserved1, /* [in] */
527 void* reserved2, /* [size_is][unique][in] */
528 DWORD reserved3, /* [in] */
529 IEnumSTATSTG** ppenum) /* [out] */
531 ICOM_THIS(StorageBaseImpl,iface);
532 IEnumSTATSTGImpl* newEnum;
534 TRACE("(%p, %ld, %p, %ld, %p)\n",
535 iface, reserved1, reserved2, reserved3, ppenum);
538 * Perform a sanity check on the parameters.
540 if ( (This==0) || (ppenum==0))
544 * Construct the enumerator.
546 newEnum = IEnumSTATSTGImpl_Construct(
547 This->ancestorStorage,
548 This->rootPropertySetIndex);
552 *ppenum = (IEnumSTATSTG*)newEnum;
555 * Don't forget to nail down a reference to the new object before
558 IEnumSTATSTGImpl_AddRef(*ppenum);
563 return E_OUTOFMEMORY;
566 /************************************************************************
567 * Storage32BaseImpl_Stat (IStorage)
569 * This method will retrieve information about this storage object.
571 * See Windows documentation for more details on IStorage methods.
573 HRESULT WINAPI StorageBaseImpl_Stat(
575 STATSTG* pstatstg, /* [out] */
576 DWORD grfStatFlag) /* [in] */
578 ICOM_THIS(StorageBaseImpl,iface);
579 StgProperty curProperty;
582 TRACE("(%p, %p, %lx)\n",
583 iface, pstatstg, grfStatFlag);
586 * Perform a sanity check on the parameters.
588 if ( (This==0) || (pstatstg==0))
592 * Read the information from the property.
594 readSuccessful = StorageImpl_ReadProperty(
595 This->ancestorStorage,
596 This->rootPropertySetIndex,
601 StorageUtl_CopyPropertyToSTATSTG(
612 /************************************************************************
613 * Storage32BaseImpl_RenameElement (IStorage)
615 * This method will rename the specified element.
617 * See Windows documentation for more details on IStorage methods.
619 * Implementation notes: The method used to rename consists of creating a clone
620 * of the deleted StgProperty object setting it with the new name and to
621 * perform a DestroyElement of the old StgProperty.
623 HRESULT WINAPI StorageBaseImpl_RenameElement(
625 const OLECHAR* pwcsOldName, /* [in] */
626 const OLECHAR* pwcsNewName) /* [in] */
628 ICOM_THIS(StorageBaseImpl,iface);
629 IEnumSTATSTGImpl* propertyEnumeration;
630 StgProperty currentProperty;
631 ULONG foundPropertyIndex;
633 TRACE("(%p, %s, %s)\n",
634 iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
637 * Create a property enumeration to search the properties
639 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
640 This->rootPropertySetIndex);
643 * Search the enumeration for the new property name
645 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
649 if (foundPropertyIndex != PROPERTY_NULL)
652 * There is already a property with the new name
654 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
655 return STG_E_FILEALREADYEXISTS;
658 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
661 * Search the enumeration for the old property name
663 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
668 * Delete the property enumeration since we don't need it anymore
670 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
672 if (foundPropertyIndex != PROPERTY_NULL)
674 StgProperty renamedProperty;
675 ULONG renamedPropertyIndex;
678 * Setup a new property for the renamed property
680 renamedProperty.sizeOfNameString =
681 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
683 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
684 return STG_E_INVALIDNAME;
686 lstrcpyW(renamedProperty.name, pwcsNewName);
688 renamedProperty.propertyType = currentProperty.propertyType;
689 renamedProperty.startingBlock = currentProperty.startingBlock;
690 renamedProperty.size.s.LowPart = currentProperty.size.s.LowPart;
691 renamedProperty.size.s.HighPart = currentProperty.size.s.HighPart;
693 renamedProperty.previousProperty = PROPERTY_NULL;
694 renamedProperty.nextProperty = PROPERTY_NULL;
697 * Bring the dirProperty link in case it is a storage and in which
698 * case the renamed storage elements don't require to be reorganized.
700 renamedProperty.dirProperty = currentProperty.dirProperty;
702 /* call CoFileTime to get the current time
703 renamedProperty.timeStampS1
704 renamedProperty.timeStampD1
705 renamedProperty.timeStampS2
706 renamedProperty.timeStampD2
707 renamedProperty.propertyUniqueID
711 * Obtain a free property in the property chain
713 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
716 * Save the new property into the new property spot
718 StorageImpl_WriteProperty(
719 This->ancestorStorage,
720 renamedPropertyIndex,
724 * Find a spot in the property chain for our newly created property.
728 renamedPropertyIndex,
732 * At this point the renamed property has been inserted in the tree,
733 * now, before to Destroy the old property we must zeroed it's dirProperty
734 * otherwise the DestroyProperty below will zap it all and we do not want
736 * Also, we fake that the old property is a storage so the DestroyProperty
737 * will not do a SetSize(0) on the stream data.
739 * This means that we need to tweek the StgProperty if it is a stream or a
742 StorageImpl_ReadProperty(This->ancestorStorage,
746 currentProperty.dirProperty = PROPERTY_NULL;
747 currentProperty.propertyType = PROPTYPE_STORAGE;
748 StorageImpl_WriteProperty(
749 This->ancestorStorage,
754 * Invoke Destroy to get rid of the ole property and automatically redo
755 * the linking of it's previous and next members...
757 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
763 * There is no property with the old name
765 return STG_E_FILENOTFOUND;
771 /************************************************************************
772 * Storage32BaseImpl_CreateStream (IStorage)
774 * This method will create a stream object within this storage
776 * See Windows documentation for more details on IStorage methods.
778 HRESULT WINAPI StorageBaseImpl_CreateStream(
780 const OLECHAR* pwcsName, /* [string][in] */
781 DWORD grfMode, /* [in] */
782 DWORD reserved1, /* [in] */
783 DWORD reserved2, /* [in] */
784 IStream** ppstm) /* [out] */
786 ICOM_THIS(StorageBaseImpl,iface);
787 IEnumSTATSTGImpl* propertyEnumeration;
788 StgStreamImpl* newStream;
789 StgProperty currentProperty, newStreamProperty;
790 ULONG foundPropertyIndex, newPropertyIndex;
792 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
793 iface, debugstr_w(pwcsName), grfMode,
794 reserved1, reserved2, ppstm);
797 * Validate parameters
800 return STG_E_INVALIDPOINTER;
803 return STG_E_INVALIDNAME;
806 * Validate the STGM flags
808 if ( FAILED( validateSTGM(grfMode) ))
809 return STG_E_INVALIDFLAG;
814 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
815 (grfMode & STGM_DELETEONRELEASE) ||
816 (grfMode & STGM_TRANSACTED) )
817 return STG_E_INVALIDFUNCTION;
820 * Initialize the out parameter
825 * Create a property enumeration to search the properties
827 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
828 This->rootPropertySetIndex);
830 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
834 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
836 if (foundPropertyIndex != PROPERTY_NULL)
839 * An element with this name already exists
841 if (grfMode & STGM_CREATE)
843 IStorage_DestroyElement(iface, pwcsName);
846 return STG_E_FILEALREADYEXISTS;
850 * memset the empty property
852 memset(&newStreamProperty, 0, sizeof(StgProperty));
854 newStreamProperty.sizeOfNameString =
855 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
857 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
858 return STG_E_INVALIDNAME;
860 lstrcpyW(newStreamProperty.name, pwcsName);
862 newStreamProperty.propertyType = PROPTYPE_STREAM;
863 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
864 newStreamProperty.size.s.LowPart = 0;
865 newStreamProperty.size.s.HighPart = 0;
867 newStreamProperty.previousProperty = PROPERTY_NULL;
868 newStreamProperty.nextProperty = PROPERTY_NULL;
869 newStreamProperty.dirProperty = PROPERTY_NULL;
871 /* call CoFileTime to get the current time
872 newStreamProperty.timeStampS1
873 newStreamProperty.timeStampD1
874 newStreamProperty.timeStampS2
875 newStreamProperty.timeStampD2
878 /* newStreamProperty.propertyUniqueID */
881 * Get a free property or create a new one
883 newPropertyIndex = getFreeProperty(This->ancestorStorage);
886 * Save the new property into the new property spot
888 StorageImpl_WriteProperty(
889 This->ancestorStorage,
894 * Find a spot in the property chain for our newly created property.
902 * Open the stream to return it.
904 newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
908 *ppstm = (IStream*)newStream;
911 * Since we are returning a pointer to the interface, we have to nail down
914 StgStreamImpl_AddRef(*ppstm);
918 return STG_E_INSUFFICIENTMEMORY;
924 /************************************************************************
925 * Storage32BaseImpl_SetClass (IStorage)
927 * This method will write the specified CLSID in the property of this
930 * See Windows documentation for more details on IStorage methods.
932 HRESULT WINAPI StorageBaseImpl_SetClass(
934 REFCLSID clsid) /* [in] */
936 ICOM_THIS(StorageBaseImpl,iface);
937 HRESULT hRes = E_FAIL;
938 StgProperty curProperty;
941 TRACE("(%p, %p)\n", iface, clsid);
943 success = StorageImpl_ReadProperty(This->ancestorStorage,
944 This->rootPropertySetIndex,
948 curProperty.propertyUniqueID = *clsid;
950 success = StorageImpl_WriteProperty(This->ancestorStorage,
951 This->rootPropertySetIndex,
960 /************************************************************************
961 ** Storage32Impl implementation
964 /************************************************************************
965 * Storage32Impl_CreateStorage (IStorage)
967 * This method will create the storage object within the provided storage.
969 * See Windows documentation for more details on IStorage methods.
971 HRESULT WINAPI StorageImpl_CreateStorage(
973 const OLECHAR *pwcsName, /* [string][in] */
974 DWORD grfMode, /* [in] */
975 DWORD reserved1, /* [in] */
976 DWORD reserved2, /* [in] */
977 IStorage **ppstg) /* [out] */
979 StorageImpl* const This=(StorageImpl*)iface;
981 IEnumSTATSTGImpl *propertyEnumeration;
982 StgProperty currentProperty;
983 StgProperty newProperty;
984 ULONG foundPropertyIndex;
985 ULONG newPropertyIndex;
988 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
989 iface, debugstr_w(pwcsName), grfMode,
990 reserved1, reserved2, ppstg);
993 * Validate parameters
996 return STG_E_INVALIDPOINTER;
999 return STG_E_INVALIDNAME;
1002 * Validate the STGM flags
1004 if ( FAILED( validateSTGM(grfMode) ) ||
1005 (grfMode & STGM_DELETEONRELEASE) )
1006 return STG_E_INVALIDFLAG;
1009 * Initialize the out parameter
1014 * Create a property enumeration and search the properties
1016 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
1017 This->rootPropertySetIndex);
1019 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1022 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1024 if (foundPropertyIndex != PROPERTY_NULL)
1027 * An element with this name already exists
1029 if (grfMode & STGM_CREATE)
1030 IStorage_DestroyElement(iface, pwcsName);
1032 return STG_E_FILEALREADYEXISTS;
1036 * memset the empty property
1038 memset(&newProperty, 0, sizeof(StgProperty));
1040 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1042 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1043 return STG_E_INVALIDNAME;
1045 lstrcpyW(newProperty.name, pwcsName);
1047 newProperty.propertyType = PROPTYPE_STORAGE;
1048 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
1049 newProperty.size.s.LowPart = 0;
1050 newProperty.size.s.HighPart = 0;
1052 newProperty.previousProperty = PROPERTY_NULL;
1053 newProperty.nextProperty = PROPERTY_NULL;
1054 newProperty.dirProperty = PROPERTY_NULL;
1056 /* call CoFileTime to get the current time
1057 newProperty.timeStampS1
1058 newProperty.timeStampD1
1059 newProperty.timeStampS2
1060 newProperty.timeStampD2
1063 /* newStorageProperty.propertyUniqueID */
1066 * Obtain a free property in the property chain
1068 newPropertyIndex = getFreeProperty(This->ancestorStorage);
1071 * Save the new property into the new property spot
1073 StorageImpl_WriteProperty(
1074 This->ancestorStorage,
1079 * Find a spot in the property chain for our newly created property.
1081 updatePropertyChain(
1087 * Open it to get a pointer to return.
1089 hr = IStorage_OpenStorage(
1098 if( (hr != S_OK) || (*ppstg == NULL))
1108 /***************************************************************************
1112 * Get a free property or create a new one.
1114 static ULONG getFreeProperty(
1115 StorageImpl *storage)
1117 ULONG currentPropertyIndex = 0;
1118 ULONG newPropertyIndex = PROPERTY_NULL;
1119 BOOL readSuccessful = TRUE;
1120 StgProperty currentProperty;
1125 * Start by reading the root property
1127 readSuccessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1128 currentPropertyIndex,
1132 if (currentProperty.sizeOfNameString == 0)
1135 * The property existis and is available, we found it.
1137 newPropertyIndex = currentPropertyIndex;
1143 * We exhausted the property list, we will create more space below
1145 newPropertyIndex = currentPropertyIndex;
1147 currentPropertyIndex++;
1149 } while (newPropertyIndex == PROPERTY_NULL);
1152 * grow the property chain
1154 if (! readSuccessful)
1156 StgProperty emptyProperty;
1157 ULARGE_INTEGER newSize;
1158 ULONG propertyIndex;
1159 ULONG lastProperty = 0;
1160 ULONG blockCount = 0;
1163 * obtain the new count of property blocks
1165 blockCount = BlockChainStream_GetCount(
1166 storage->ancestorStorage->rootBlockChain)+1;
1169 * initialize the size used by the property stream
1171 newSize.s.HighPart = 0;
1172 newSize.s.LowPart = storage->bigBlockSize * blockCount;
1175 * add a property block to the property chain
1177 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1180 * memset the empty property in order to initialize the unused newly
1183 memset(&emptyProperty, 0, sizeof(StgProperty));
1188 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1191 propertyIndex = newPropertyIndex;
1192 propertyIndex < lastProperty;
1195 StorageImpl_WriteProperty(
1196 storage->ancestorStorage,
1202 return newPropertyIndex;
1205 /****************************************************************************
1209 * Case insensitive comparaison of StgProperty.name by first considering
1212 * Returns <0 when newPrpoerty < currentProperty
1213 * >0 when newPrpoerty > currentProperty
1214 * 0 when newPrpoerty == currentProperty
1216 static LONG propertyNameCmp(
1217 OLECHAR *newProperty,
1218 OLECHAR *currentProperty)
1220 LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty);
1225 * We compare the string themselves only when they are of the same lenght
1227 diff = lstrcmpiW( newProperty, currentProperty);
1233 /****************************************************************************
1237 * Properly link this new element in the property chain.
1239 static void updatePropertyChain(
1240 StorageImpl *storage,
1241 ULONG newPropertyIndex,
1242 StgProperty newProperty)
1244 StgProperty currentProperty;
1247 * Read the root property
1249 StorageImpl_ReadProperty(storage->ancestorStorage,
1250 storage->rootPropertySetIndex,
1253 if (currentProperty.dirProperty != PROPERTY_NULL)
1256 * The root storage contains some element, therefore, start the research
1257 * for the appropriate location.
1260 ULONG current, next, previous, currentPropertyId;
1263 * Keep the StgProperty sequence number of the storage first property
1265 currentPropertyId = currentProperty.dirProperty;
1270 StorageImpl_ReadProperty(storage->ancestorStorage,
1271 currentProperty.dirProperty,
1274 previous = currentProperty.previousProperty;
1275 next = currentProperty.nextProperty;
1276 current = currentPropertyId;
1280 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1284 if (previous != PROPERTY_NULL)
1286 StorageImpl_ReadProperty(storage->ancestorStorage,
1293 currentProperty.previousProperty = newPropertyIndex;
1294 StorageImpl_WriteProperty(storage->ancestorStorage,
1302 if (next != PROPERTY_NULL)
1304 StorageImpl_ReadProperty(storage->ancestorStorage,
1311 currentProperty.nextProperty = newPropertyIndex;
1312 StorageImpl_WriteProperty(storage->ancestorStorage,
1321 * Trying to insert an item with the same name in the
1322 * subtree structure.
1327 previous = currentProperty.previousProperty;
1328 next = currentProperty.nextProperty;
1334 * The root storage is empty, link the new property to it's dir property
1336 currentProperty.dirProperty = newPropertyIndex;
1337 StorageImpl_WriteProperty(storage->ancestorStorage,
1338 storage->rootPropertySetIndex,
1344 /*************************************************************************
1347 HRESULT WINAPI StorageImpl_CopyTo(
1349 DWORD ciidExclude, /* [in] */
1350 const IID* rgiidExclude, /* [size_is][unique][in] */
1351 SNB snbExclude, /* [unique][in] */
1352 IStorage* pstgDest) /* [unique][in] */
1354 IEnumSTATSTG *elements = 0;
1355 STATSTG curElement, strStat;
1357 IStorage *pstgTmp, *pstgChild;
1358 IStream *pstrTmp, *pstrChild;
1360 if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
1361 FIXME("Exclude option not implemented\n");
1363 TRACE("(%p, %ld, %p, %p, %p)\n",
1364 iface, ciidExclude, rgiidExclude,
1365 snbExclude, pstgDest);
1368 * Perform a sanity check
1370 if ( pstgDest == 0 )
1371 return STG_E_INVALIDPOINTER;
1374 * Enumerate the elements
1376 hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1384 IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1385 IStorage_SetClass( pstgDest, &curElement.clsid );
1390 * Obtain the next element
1392 hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1394 if ( hr == S_FALSE )
1396 hr = S_OK; /* done, every element has been copied */
1400 if (curElement.type == STGTY_STORAGE)
1403 * open child source storage
1405 hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1406 STGM_READ|STGM_SHARE_EXCLUSIVE,
1407 NULL, 0, &pstgChild );
1413 * Check if destination storage is not a child of the source
1414 * storage, which will cause an infinite loop
1416 if (pstgChild == pstgDest)
1418 IEnumSTATSTG_Release(elements);
1420 return STG_E_ACCESSDENIED;
1424 * create a new storage in destination storage
1426 hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1427 STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1431 * if it already exist, don't create a new one use this one
1433 if (hr == STG_E_FILEALREADYEXISTS)
1435 hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1436 STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1437 NULL, 0, &pstgTmp );
1445 * do the copy recursively
1447 hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1448 snbExclude, pstgTmp );
1450 IStorage_Release( pstgTmp );
1451 IStorage_Release( pstgChild );
1453 else if (curElement.type == STGTY_STREAM)
1456 * create a new stream in destination storage. If the stream already
1457 * exist, it will be deleted and a new one will be created.
1459 hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1460 STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1467 * open child stream storage
1469 hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
1470 STGM_READ|STGM_SHARE_EXCLUSIVE,
1477 * Get the size of the source stream
1479 IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1482 * Set the size of the destination stream.
1484 IStream_SetSize(pstrTmp, strStat.cbSize);
1489 hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1492 IStream_Release( pstrTmp );
1493 IStream_Release( pstrChild );
1497 WARN("unknown element type: %ld\n", curElement.type);
1500 } while (hr == S_OK);
1505 IEnumSTATSTG_Release(elements);
1510 /*************************************************************************
1511 * MoveElementTo (IStorage)
1513 HRESULT WINAPI StorageImpl_MoveElementTo(
1515 const OLECHAR *pwcsName, /* [string][in] */
1516 IStorage *pstgDest, /* [unique][in] */
1517 const OLECHAR *pwcsNewName,/* [string][in] */
1518 DWORD grfFlags) /* [in] */
1520 FIXME("not implemented!\n");
1524 /*************************************************************************
1527 HRESULT WINAPI StorageImpl_Commit(
1529 DWORD grfCommitFlags)/* [in] */
1531 FIXME("(%ld): stub!\n", grfCommitFlags);
1535 /*************************************************************************
1538 HRESULT WINAPI StorageImpl_Revert(
1541 FIXME("not implemented!\n");
1545 /*************************************************************************
1546 * DestroyElement (IStorage)
1548 * Stategy: This implementation is build this way for simplicity not for speed.
1549 * I always delete the top most element of the enumeration and adjust
1550 * the deleted element pointer all the time. This takes longer to
1551 * do but allow to reinvoke DestroyElement whenever we encounter a
1552 * storage object. The optimisation reside in the usage of another
1553 * enumeration stategy that would give all the leaves of a storage
1554 * first. (postfix order)
1556 HRESULT WINAPI StorageImpl_DestroyElement(
1558 const OLECHAR *pwcsName)/* [string][in] */
1560 StorageImpl* const This=(StorageImpl*)iface;
1562 IEnumSTATSTGImpl* propertyEnumeration;
1565 StgProperty propertyToDelete;
1566 StgProperty parentProperty;
1567 ULONG foundPropertyIndexToDelete;
1568 ULONG typeOfRelation;
1569 ULONG parentPropertyId;
1572 iface, debugstr_w(pwcsName));
1575 * Perform a sanity check on the parameters.
1578 return STG_E_INVALIDPOINTER;
1581 * Create a property enumeration to search the property with the given name
1583 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1584 This->ancestorStorage,
1585 This->rootPropertySetIndex);
1587 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1588 propertyEnumeration,
1592 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1594 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1596 return STG_E_FILENOTFOUND;
1600 * Find the parent property of the property to delete (the one that
1601 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1602 * the parent is This. Otherwise, the parent is one of it's sibling...
1606 * First, read This's StgProperty..
1608 res = StorageImpl_ReadProperty(
1609 This->ancestorStorage,
1610 This->rootPropertySetIndex,
1616 * Second, check to see if by any chance the actual storage (This) is not
1617 * the parent of the property to delete... We never know...
1619 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1622 * Set data as it would have been done in the else part...
1624 typeOfRelation = PROPERTY_RELATION_DIR;
1625 parentPropertyId = This->rootPropertySetIndex;
1630 * Create a property enumeration to search the parent properties, and
1631 * delete it once done.
1633 IEnumSTATSTGImpl* propertyEnumeration2;
1635 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1636 This->ancestorStorage,
1637 This->rootPropertySetIndex);
1639 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1640 propertyEnumeration2,
1641 foundPropertyIndexToDelete,
1645 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1648 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1650 hr = deleteStorageProperty(
1652 foundPropertyIndexToDelete,
1655 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1657 hr = deleteStreamProperty(
1659 foundPropertyIndexToDelete,
1667 * Adjust the property chain
1669 hr = adjustPropertyChain(
1680 /*********************************************************************
1684 * Perform the deletion of a complete storage node
1687 static HRESULT deleteStorageProperty(
1688 StorageImpl *parentStorage,
1689 ULONG indexOfPropertyToDelete,
1690 StgProperty propertyToDelete)
1692 IEnumSTATSTG *elements = 0;
1693 IStorage *childStorage = 0;
1694 STATSTG currentElement;
1696 HRESULT destroyHr = S_OK;
1699 * Open the storage and enumerate it
1701 hr = StorageBaseImpl_OpenStorage(
1702 (IStorage*)parentStorage,
1703 propertyToDelete.name,
1705 STGM_SHARE_EXCLUSIVE,
1716 * Enumerate the elements
1718 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1723 * Obtain the next element
1725 hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL);
1728 destroyHr = StorageImpl_DestroyElement(
1729 (IStorage*)childStorage,
1730 (OLECHAR*)currentElement.pwcsName);
1732 CoTaskMemFree(currentElement.pwcsName);
1736 * We need to Reset the enumeration every time because we delete elements
1737 * and the enumeration could be invalid
1739 IEnumSTATSTG_Reset(elements);
1741 } while ((hr == S_OK) && (destroyHr == S_OK));
1744 * Invalidate the property by zeroing it's name member.
1746 propertyToDelete.sizeOfNameString = 0;
1748 StorageImpl_WriteProperty(parentStorage->ancestorStorage,
1749 indexOfPropertyToDelete,
1752 IStorage_Release(childStorage);
1753 IEnumSTATSTG_Release(elements);
1758 /*********************************************************************
1762 * Perform the deletion of a stream node
1765 static HRESULT deleteStreamProperty(
1766 StorageImpl *parentStorage,
1767 ULONG indexOfPropertyToDelete,
1768 StgProperty propertyToDelete)
1772 ULARGE_INTEGER size;
1774 size.s.HighPart = 0;
1777 hr = StorageBaseImpl_OpenStream(
1778 (IStorage*)parentStorage,
1779 (OLECHAR*)propertyToDelete.name,
1781 STGM_WRITE | STGM_SHARE_EXCLUSIVE,
1793 hr = IStream_SetSize(pis, size);
1801 * Release the stream object.
1803 IStream_Release(pis);
1806 * Invalidate the property by zeroing it's name member.
1808 propertyToDelete.sizeOfNameString = 0;
1811 * Here we should re-read the property so we get the updated pointer
1812 * but since we are here to zap it, I don't do it...
1814 StorageImpl_WriteProperty(
1815 parentStorage->ancestorStorage,
1816 indexOfPropertyToDelete,
1822 /*********************************************************************
1826 * Finds a placeholder for the StgProperty within the Storage
1829 static HRESULT findPlaceholder(
1830 StorageImpl *storage,
1831 ULONG propertyIndexToStore,
1832 ULONG storePropertyIndex,
1835 StgProperty storeProperty;
1840 * Read the storage property
1842 res = StorageImpl_ReadProperty(
1843 storage->ancestorStorage,
1852 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1854 if (storeProperty.previousProperty != PROPERTY_NULL)
1856 return findPlaceholder(
1858 propertyIndexToStore,
1859 storeProperty.previousProperty,
1864 storeProperty.previousProperty = propertyIndexToStore;
1867 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1869 if (storeProperty.nextProperty != PROPERTY_NULL)
1871 return findPlaceholder(
1873 propertyIndexToStore,
1874 storeProperty.nextProperty,
1879 storeProperty.nextProperty = propertyIndexToStore;
1882 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1884 if (storeProperty.dirProperty != PROPERTY_NULL)
1886 return findPlaceholder(
1888 propertyIndexToStore,
1889 storeProperty.dirProperty,
1894 storeProperty.dirProperty = propertyIndexToStore;
1898 hr = StorageImpl_WriteProperty(
1899 storage->ancestorStorage,
1911 /*************************************************************************
1915 * This method takes the previous and the next property link of a property
1916 * to be deleted and find them a place in the Storage.
1918 static HRESULT adjustPropertyChain(
1920 StgProperty propertyToDelete,
1921 StgProperty parentProperty,
1922 ULONG parentPropertyId,
1925 ULONG newLinkProperty = PROPERTY_NULL;
1926 BOOL needToFindAPlaceholder = FALSE;
1927 ULONG storeNode = PROPERTY_NULL;
1928 ULONG toStoreNode = PROPERTY_NULL;
1929 INT relationType = 0;
1933 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1935 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1938 * Set the parent previous to the property to delete previous
1940 newLinkProperty = propertyToDelete.previousProperty;
1942 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1945 * We also need to find a storage for the other link, setup variables
1946 * to do this at the end...
1948 needToFindAPlaceholder = TRUE;
1949 storeNode = propertyToDelete.previousProperty;
1950 toStoreNode = propertyToDelete.nextProperty;
1951 relationType = PROPERTY_RELATION_NEXT;
1954 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1957 * Set the parent previous to the property to delete next
1959 newLinkProperty = propertyToDelete.nextProperty;
1963 * Link it for real...
1965 parentProperty.previousProperty = newLinkProperty;
1968 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1970 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1973 * Set the parent next to the property to delete next previous
1975 newLinkProperty = propertyToDelete.previousProperty;
1977 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1980 * We also need to find a storage for the other link, setup variables
1981 * to do this at the end...
1983 needToFindAPlaceholder = TRUE;
1984 storeNode = propertyToDelete.previousProperty;
1985 toStoreNode = propertyToDelete.nextProperty;
1986 relationType = PROPERTY_RELATION_NEXT;
1989 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1992 * Set the parent next to the property to delete next
1994 newLinkProperty = propertyToDelete.nextProperty;
1998 * Link it for real...
2000 parentProperty.nextProperty = newLinkProperty;
2002 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2004 if (propertyToDelete.previousProperty != PROPERTY_NULL)
2007 * Set the parent dir to the property to delete previous
2009 newLinkProperty = propertyToDelete.previousProperty;
2011 if (propertyToDelete.nextProperty != PROPERTY_NULL)
2014 * We also need to find a storage for the other link, setup variables
2015 * to do this at the end...
2017 needToFindAPlaceholder = TRUE;
2018 storeNode = propertyToDelete.previousProperty;
2019 toStoreNode = propertyToDelete.nextProperty;
2020 relationType = PROPERTY_RELATION_NEXT;
2023 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2026 * Set the parent dir to the property to delete next
2028 newLinkProperty = propertyToDelete.nextProperty;
2032 * Link it for real...
2034 parentProperty.dirProperty = newLinkProperty;
2038 * Write back the parent property
2040 res = StorageImpl_WriteProperty(
2041 This->ancestorStorage,
2050 * If a placeholder is required for the other link, then, find one and
2051 * get out of here...
2053 if (needToFindAPlaceholder)
2055 hr = findPlaceholder(
2066 /******************************************************************************
2067 * SetElementTimes (IStorage)
2069 HRESULT WINAPI StorageImpl_SetElementTimes(
2071 const OLECHAR *pwcsName,/* [string][in] */
2072 const FILETIME *pctime, /* [in] */
2073 const FILETIME *patime, /* [in] */
2074 const FILETIME *pmtime) /* [in] */
2076 FIXME("not implemented!\n");
2080 /******************************************************************************
2081 * SetStateBits (IStorage)
2083 HRESULT WINAPI StorageImpl_SetStateBits(
2085 DWORD grfStateBits,/* [in] */
2086 DWORD grfMask) /* [in] */
2088 FIXME("not implemented!\n");
2092 HRESULT StorageImpl_Construct(
2101 StgProperty currentProperty;
2102 BOOL readSuccessful;
2103 ULONG currentPropertyIndex;
2105 if ( FAILED( validateSTGM(openFlags) ))
2106 return STG_E_INVALIDFLAG;
2108 memset(This, 0, sizeof(StorageImpl));
2111 * Initialize the virtual fgunction table.
2113 ICOM_VTBL(This) = &Storage32Impl_Vtbl;
2114 This->v_destructor = &StorageImpl_Destroy;
2117 * This is the top-level storage so initialize the ancester pointer
2120 This->ancestorStorage = This;
2123 * Initialize the physical support of the storage.
2125 This->hFile = hFile;
2128 * Initialize the big block cache.
2130 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
2131 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2132 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
2138 if (This->bigBlockFile == 0)
2143 ULARGE_INTEGER size;
2144 BYTE* bigBlockBuffer;
2147 * Initialize all header variables:
2148 * - The big block depot consists of one block and it is at block 0
2149 * - The properties start at block 1
2150 * - There is no small block depot
2152 memset( This->bigBlockDepotStart,
2154 sizeof(This->bigBlockDepotStart));
2156 This->bigBlockDepotCount = 1;
2157 This->bigBlockDepotStart[0] = 0;
2158 This->rootStartBlock = 1;
2159 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
2160 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
2161 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
2162 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2163 This->extBigBlockDepotCount = 0;
2165 StorageImpl_SaveFileHeader(This);
2168 * Add one block for the big block depot and one block for the properties
2170 size.s.HighPart = 0;
2171 size.s.LowPart = This->bigBlockSize * 3;
2172 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
2175 * Initialize the big block depot
2177 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
2178 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2179 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2180 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2181 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2186 * Load the header for the file.
2188 hr = StorageImpl_LoadFileHeader(This);
2192 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2199 * There is no block depot cached yet.
2201 This->indexBlockDepotCached = 0xFFFFFFFF;
2204 * Start searching for free blocks with block 0.
2206 This->prevFreeBlock = 0;
2209 * Create the block chain abstractions.
2211 This->rootBlockChain =
2212 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
2214 This->smallBlockDepotChain = BlockChainStream_Construct(
2216 &This->smallBlockDepotStart,
2220 * Write the root property
2224 StgProperty rootProp;
2226 * Initialize the property chain
2228 memset(&rootProp, 0, sizeof(rootProp));
2229 lstrcpyAtoW(rootProp.name, rootPropertyName);
2231 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
2232 rootProp.propertyType = PROPTYPE_ROOT;
2233 rootProp.previousProperty = PROPERTY_NULL;
2234 rootProp.nextProperty = PROPERTY_NULL;
2235 rootProp.dirProperty = PROPERTY_NULL;
2236 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
2237 rootProp.size.s.HighPart = 0;
2238 rootProp.size.s.LowPart = 0;
2240 StorageImpl_WriteProperty(This, 0, &rootProp);
2244 * Find the ID of the root int he property sets.
2246 currentPropertyIndex = 0;
2250 readSuccessful = StorageImpl_ReadProperty(
2252 currentPropertyIndex,
2257 if ( (currentProperty.sizeOfNameString != 0 ) &&
2258 (currentProperty.propertyType == PROPTYPE_ROOT) )
2260 This->rootPropertySetIndex = currentPropertyIndex;
2264 currentPropertyIndex++;
2266 } while (readSuccessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
2268 if (!readSuccessful)
2275 * Create the block chain abstraction for the small block root chain.
2277 This->smallBlockRootChain = BlockChainStream_Construct(
2280 This->rootPropertySetIndex);
2285 void StorageImpl_Destroy(
2288 TRACE("(%p)\n", This);
2290 BlockChainStream_Destroy(This->smallBlockRootChain);
2291 BlockChainStream_Destroy(This->rootBlockChain);
2292 BlockChainStream_Destroy(This->smallBlockDepotChain);
2294 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2298 /******************************************************************************
2299 * Storage32Impl_GetNextFreeBigBlock
2301 * Returns the index of the next free big block.
2302 * If the big block depot is filled, this method will enlarge it.
2305 ULONG StorageImpl_GetNextFreeBigBlock(
2308 ULONG depotBlockIndexPos;
2310 ULONG depotBlockOffset;
2311 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2312 ULONG nextBlockIndex = BLOCK_SPECIAL;
2314 ULONG freeBlock = BLOCK_UNUSED;
2316 depotIndex = This->prevFreeBlock / blocksPerDepot;
2317 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2320 * Scan the entire big block depot until we find a block marked free
2322 while (nextBlockIndex != BLOCK_UNUSED)
2324 if (depotIndex < COUNT_BBDEPOTINHEADER)
2326 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2329 * Grow the primary depot.
2331 if (depotBlockIndexPos == BLOCK_UNUSED)
2333 depotBlockIndexPos = depotIndex*blocksPerDepot;
2336 * Add a block depot.
2338 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2339 This->bigBlockDepotCount++;
2340 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2343 * Flag it as a block depot.
2345 StorageImpl_SetNextBlockInChain(This,
2349 /* Save new header information.
2351 StorageImpl_SaveFileHeader(This);
2356 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2358 if (depotBlockIndexPos == BLOCK_UNUSED)
2361 * Grow the extended depot.
2363 ULONG extIndex = BLOCK_UNUSED;
2364 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2365 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2367 if (extBlockOffset == 0)
2369 /* We need an extended block.
2371 extIndex = Storage32Impl_AddExtBlockDepot(This);
2372 This->extBigBlockDepotCount++;
2373 depotBlockIndexPos = extIndex + 1;
2376 depotBlockIndexPos = depotIndex * blocksPerDepot;
2379 * Add a block depot and mark it in the extended block.
2381 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2382 This->bigBlockDepotCount++;
2383 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2385 /* Flag the block depot.
2387 StorageImpl_SetNextBlockInChain(This,
2391 /* If necessary, flag the extended depot block.
2393 if (extIndex != BLOCK_UNUSED)
2394 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2396 /* Save header information.
2398 StorageImpl_SaveFileHeader(This);
2402 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2404 if (depotBuffer != 0)
2406 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2407 ( nextBlockIndex != BLOCK_UNUSED))
2409 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2411 if (nextBlockIndex == BLOCK_UNUSED)
2413 freeBlock = (depotIndex * blocksPerDepot) +
2414 (depotBlockOffset/sizeof(ULONG));
2417 depotBlockOffset += sizeof(ULONG);
2420 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2424 depotBlockOffset = 0;
2427 This->prevFreeBlock = freeBlock;
2432 /******************************************************************************
2433 * Storage32Impl_AddBlockDepot
2435 * This will create a depot block, essentially it is a block initialized
2438 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2442 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2445 * Initialize blocks as free
2447 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2449 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2452 /******************************************************************************
2453 * Storage32Impl_GetExtDepotBlock
2455 * Returns the index of the block that corresponds to the specified depot
2456 * index. This method is only for depot indexes equal or greater than
2457 * COUNT_BBDEPOTINHEADER.
2459 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2461 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2462 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2463 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2464 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2465 ULONG blockIndex = BLOCK_UNUSED;
2466 ULONG extBlockIndex = This->extBigBlockDepotStart;
2468 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2470 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2471 return BLOCK_UNUSED;
2473 while (extBlockCount > 0)
2475 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2479 if (extBlockIndex != BLOCK_UNUSED)
2483 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2485 if (depotBuffer != 0)
2487 StorageUtl_ReadDWord(depotBuffer,
2488 extBlockOffset * sizeof(ULONG),
2491 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2498 /******************************************************************************
2499 * Storage32Impl_SetExtDepotBlock
2501 * Associates the specified block index to the specified depot index.
2502 * This method is only for depot indexes equal or greater than
2503 * COUNT_BBDEPOTINHEADER.
2505 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2509 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2510 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2511 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2512 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2513 ULONG extBlockIndex = This->extBigBlockDepotStart;
2515 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2517 while (extBlockCount > 0)
2519 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2523 if (extBlockIndex != BLOCK_UNUSED)
2527 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2529 if (depotBuffer != 0)
2531 StorageUtl_WriteDWord(depotBuffer,
2532 extBlockOffset * sizeof(ULONG),
2535 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2540 /******************************************************************************
2541 * Storage32Impl_AddExtBlockDepot
2543 * Creates an extended depot block.
2545 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2547 ULONG numExtBlocks = This->extBigBlockDepotCount;
2548 ULONG nextExtBlock = This->extBigBlockDepotStart;
2549 BYTE* depotBuffer = NULL;
2550 ULONG index = BLOCK_UNUSED;
2551 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2552 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2553 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2555 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2556 blocksPerDepotBlock;
2558 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2561 * The first extended block.
2563 This->extBigBlockDepotStart = index;
2569 * Follow the chain to the last one.
2571 for (i = 0; i < (numExtBlocks - 1); i++)
2573 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2577 * Add the new extended block to the chain.
2579 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2580 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2581 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2585 * Initialize this block.
2587 depotBuffer = StorageImpl_GetBigBlock(This, index);
2588 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2589 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2594 /******************************************************************************
2595 * Storage32Impl_FreeBigBlock
2597 * This method will flag the specified block as free in the big block depot.
2599 void StorageImpl_FreeBigBlock(
2603 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2605 if (blockIndex < This->prevFreeBlock)
2606 This->prevFreeBlock = blockIndex;
2609 /************************************************************************
2610 * Storage32Impl_GetNextBlockInChain
2612 * This method will retrieve the block index of the next big block in
2615 * Params: This - Pointer to the Storage object.
2616 * blockIndex - Index of the block to retrieve the chain
2619 * Returns: This method returns the index of the next block in the chain.
2620 * It will return the constants:
2621 * BLOCK_SPECIAL - If the block given was not part of a
2623 * BLOCK_END_OF_CHAIN - If the block given was the last in
2625 * BLOCK_UNUSED - If the block given was not past of a chain
2627 * BLOCK_EXTBBDEPOT - This block is part of the extended
2630 * See Windows documentation for more details on IStorage methods.
2632 ULONG StorageImpl_GetNextBlockInChain(
2636 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2637 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2638 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2639 ULONG nextBlockIndex = BLOCK_SPECIAL;
2641 ULONG depotBlockIndexPos;
2643 assert(depotBlockCount < This->bigBlockDepotCount);
2646 * Cache the currently accessed depot block.
2648 if (depotBlockCount != This->indexBlockDepotCached)
2650 This->indexBlockDepotCached = depotBlockCount;
2652 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2654 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2659 * We have to look in the extended depot.
2661 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2664 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2670 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2672 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2673 This->blockDepotCached[index] = nextBlockIndex;
2676 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2680 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2682 return nextBlockIndex;
2685 /******************************************************************************
2686 * Storage32Impl_GetNextExtendedBlock
2688 * Given an extended block this method will return the next extended block.
2691 * The last ULONG of an extended block is the block index of the next
2692 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2696 * - The index of the next extended block
2697 * - BLOCK_UNUSED: there is no next extended block.
2698 * - Any other return values denotes failure.
2700 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2702 ULONG nextBlockIndex = BLOCK_SPECIAL;
2703 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2706 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2710 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2712 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2715 return nextBlockIndex;
2718 /******************************************************************************
2719 * Storage32Impl_SetNextBlockInChain
2721 * This method will write the index of the specified block's next block
2722 * in the big block depot.
2724 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2727 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2728 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2729 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2732 void StorageImpl_SetNextBlockInChain(
2737 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2738 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2739 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2740 ULONG depotBlockIndexPos;
2743 assert(depotBlockCount < This->bigBlockDepotCount);
2744 assert(blockIndex != nextBlock);
2746 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2748 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2753 * We have to look in the extended depot.
2755 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2758 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2762 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2763 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2767 * Update the cached block depot, if necessary.
2769 if (depotBlockCount == This->indexBlockDepotCached)
2771 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2775 /******************************************************************************
2776 * Storage32Impl_LoadFileHeader
2778 * This method will read in the file header, i.e. big block index -1.
2780 HRESULT StorageImpl_LoadFileHeader(
2783 HRESULT hr = STG_E_FILENOTFOUND;
2784 void* headerBigBlock = NULL;
2788 * Get a pointer to the big block of data containing the header.
2790 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2793 * Extract the information from the header.
2795 if (headerBigBlock!=0)
2798 * Check for the "magic number" signature and return an error if it is not
2801 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2803 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2804 return STG_E_OLDFORMAT;
2807 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2809 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2810 return STG_E_INVALIDHEADER;
2813 StorageUtl_ReadWord(
2815 OFFSET_BIGBLOCKSIZEBITS,
2816 &This->bigBlockSizeBits);
2818 StorageUtl_ReadWord(
2820 OFFSET_SMALLBLOCKSIZEBITS,
2821 &This->smallBlockSizeBits);
2823 StorageUtl_ReadDWord(
2825 OFFSET_BBDEPOTCOUNT,
2826 &This->bigBlockDepotCount);
2828 StorageUtl_ReadDWord(
2830 OFFSET_ROOTSTARTBLOCK,
2831 &This->rootStartBlock);
2833 StorageUtl_ReadDWord(
2835 OFFSET_SBDEPOTSTART,
2836 &This->smallBlockDepotStart);
2838 StorageUtl_ReadDWord(
2840 OFFSET_EXTBBDEPOTSTART,
2841 &This->extBigBlockDepotStart);
2843 StorageUtl_ReadDWord(
2845 OFFSET_EXTBBDEPOTCOUNT,
2846 &This->extBigBlockDepotCount);
2848 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2850 StorageUtl_ReadDWord(
2852 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2853 &(This->bigBlockDepotStart[index]));
2857 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2861 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2862 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2866 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2867 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2871 * Right now, the code is making some assumptions about the size of the
2872 * blocks, just make sure they are what we're expecting.
2874 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2875 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2878 * Release the block.
2880 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2888 /******************************************************************************
2889 * Storage32Impl_SaveFileHeader
2891 * This method will save to the file the header, i.e. big block -1.
2893 void StorageImpl_SaveFileHeader(
2896 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2901 * Get a pointer to the big block of data containing the header.
2903 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2906 * If the block read failed, the file is probably new.
2911 * Initialize for all unknown fields.
2913 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2916 * Initialize the magic number.
2918 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2921 * And a bunch of things we don't know what they mean
2923 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2924 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2925 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2926 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2927 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2931 * Write the information to the header.
2933 if (headerBigBlock!=0)
2935 StorageUtl_WriteWord(
2937 OFFSET_BIGBLOCKSIZEBITS,
2938 This->bigBlockSizeBits);
2940 StorageUtl_WriteWord(
2942 OFFSET_SMALLBLOCKSIZEBITS,
2943 This->smallBlockSizeBits);
2945 StorageUtl_WriteDWord(
2947 OFFSET_BBDEPOTCOUNT,
2948 This->bigBlockDepotCount);
2950 StorageUtl_WriteDWord(
2952 OFFSET_ROOTSTARTBLOCK,
2953 This->rootStartBlock);
2955 StorageUtl_WriteDWord(
2957 OFFSET_SBDEPOTSTART,
2958 This->smallBlockDepotStart);
2960 StorageUtl_WriteDWord(
2962 OFFSET_EXTBBDEPOTSTART,
2963 This->extBigBlockDepotStart);
2965 StorageUtl_WriteDWord(
2967 OFFSET_EXTBBDEPOTCOUNT,
2968 This->extBigBlockDepotCount);
2970 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2972 StorageUtl_WriteDWord(
2974 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2975 (This->bigBlockDepotStart[index]));
2980 * Write the big block back to the file.
2982 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2985 /******************************************************************************
2986 * Storage32Impl_ReadProperty
2988 * This method will read the specified property from the property chain.
2990 BOOL StorageImpl_ReadProperty(
2993 StgProperty* buffer)
2995 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2996 ULARGE_INTEGER offsetInPropSet;
2997 BOOL readSuccessful;
3000 offsetInPropSet.s.HighPart = 0;
3001 offsetInPropSet.s.LowPart = index * PROPSET_BLOCK_SIZE;
3003 readSuccessful = BlockChainStream_ReadAt(
3004 This->rootBlockChain,
3012 memset(buffer->name, 0, sizeof(buffer->name));
3015 currentProperty+OFFSET_PS_NAME,
3016 PROPERTY_NAME_BUFFER_LEN );
3018 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3020 StorageUtl_ReadWord(
3022 OFFSET_PS_NAMELENGTH,
3023 &buffer->sizeOfNameString);
3025 StorageUtl_ReadDWord(
3027 OFFSET_PS_PREVIOUSPROP,
3028 &buffer->previousProperty);
3030 StorageUtl_ReadDWord(
3033 &buffer->nextProperty);
3035 StorageUtl_ReadDWord(
3038 &buffer->dirProperty);
3040 StorageUtl_ReadGUID(
3043 &buffer->propertyUniqueID);
3045 StorageUtl_ReadDWord(
3048 &buffer->timeStampS1);
3050 StorageUtl_ReadDWord(
3053 &buffer->timeStampD1);
3055 StorageUtl_ReadDWord(
3058 &buffer->timeStampS2);
3060 StorageUtl_ReadDWord(
3063 &buffer->timeStampD2);
3065 StorageUtl_ReadDWord(
3067 OFFSET_PS_STARTBLOCK,
3068 &buffer->startingBlock);
3070 StorageUtl_ReadDWord(
3073 &buffer->size.s.LowPart);
3075 buffer->size.s.HighPart = 0;
3078 return readSuccessful;
3081 /*********************************************************************
3082 * Write the specified property into the property chain
3084 BOOL StorageImpl_WriteProperty(
3087 StgProperty* buffer)
3089 BYTE currentProperty[PROPSET_BLOCK_SIZE];
3090 ULARGE_INTEGER offsetInPropSet;
3091 BOOL writeSuccessful;
3094 offsetInPropSet.s.HighPart = 0;
3095 offsetInPropSet.s.LowPart = index * PROPSET_BLOCK_SIZE;
3097 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3100 currentProperty + OFFSET_PS_NAME,
3102 PROPERTY_NAME_BUFFER_LEN );
3104 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3106 StorageUtl_WriteWord(
3108 OFFSET_PS_NAMELENGTH,
3109 buffer->sizeOfNameString);
3111 StorageUtl_WriteDWord(
3113 OFFSET_PS_PREVIOUSPROP,
3114 buffer->previousProperty);
3116 StorageUtl_WriteDWord(
3119 buffer->nextProperty);
3121 StorageUtl_WriteDWord(
3124 buffer->dirProperty);
3126 StorageUtl_WriteGUID(
3129 &buffer->propertyUniqueID);
3131 StorageUtl_WriteDWord(
3134 buffer->timeStampS1);
3136 StorageUtl_WriteDWord(
3139 buffer->timeStampD1);
3141 StorageUtl_WriteDWord(
3144 buffer->timeStampS2);
3146 StorageUtl_WriteDWord(
3149 buffer->timeStampD2);
3151 StorageUtl_WriteDWord(
3153 OFFSET_PS_STARTBLOCK,
3154 buffer->startingBlock);
3156 StorageUtl_WriteDWord(
3159 buffer->size.s.LowPart);
3161 writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
3166 return writeSuccessful;
3169 BOOL StorageImpl_ReadBigBlock(
3174 void* bigBlockBuffer;
3176 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
3178 if (bigBlockBuffer!=0)
3180 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
3182 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3190 BOOL StorageImpl_WriteBigBlock(
3195 void* bigBlockBuffer;
3197 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
3199 if (bigBlockBuffer!=0)
3201 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
3203 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3211 void* StorageImpl_GetROBigBlock(
3215 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
3218 void* StorageImpl_GetBigBlock(
3222 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
3225 void StorageImpl_ReleaseBigBlock(
3229 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
3232 /******************************************************************************
3233 * Storage32Impl_SmallBlocksToBigBlocks
3235 * This method will convert a small block chain to a big block chain.
3236 * The small block chain will be destroyed.
3238 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3240 SmallBlockChainStream** ppsbChain)
3242 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3243 ULARGE_INTEGER size, offset;
3244 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
3245 ULONG propertyIndex;
3246 BOOL successRead, successWrite;
3247 StgProperty chainProperty;
3249 BlockChainStream *bbTempChain = NULL;
3250 BlockChainStream *bigBlockChain = NULL;
3253 * Create a temporary big block chain that doesn't have
3254 * an associated property. This temporary chain will be
3255 * used to copy data from small blocks to big blocks.
3257 bbTempChain = BlockChainStream_Construct(This,
3262 * Grow the big block chain.
3264 size = SmallBlockChainStream_GetSize(*ppsbChain);
3265 BlockChainStream_SetSize(bbTempChain, size);
3268 * Copy the contents of the small block chain to the big block chain
3269 * by small block size increments.
3271 offset.s.LowPart = 0;
3272 offset.s.HighPart = 0;
3276 buffer = (BYTE *) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3279 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3281 DEF_SMALL_BLOCK_SIZE,
3284 cbTotalRead += cbRead;
3286 successWrite = BlockChainStream_WriteAt(bbTempChain,
3291 cbTotalWritten += cbWritten;
3293 offset.s.LowPart += This->smallBlockSize;
3295 } while (successRead && successWrite);
3296 HeapFree(GetProcessHeap(),0,buffer);
3298 assert(cbTotalRead == cbTotalWritten);
3301 * Destroy the small block chain.
3303 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3304 size.s.HighPart = 0;
3306 SmallBlockChainStream_SetSize(*ppsbChain, size);
3307 SmallBlockChainStream_Destroy(*ppsbChain);
3311 * Change the property information. This chain is now a big block chain
3312 * and it doesn't reside in the small blocks chain anymore.
3314 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3316 chainProperty.startingBlock = bbHeadOfChain;
3318 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3321 * Destroy the temporary propertyless big block chain.
3322 * Create a new big block chain associated with this property.
3324 BlockChainStream_Destroy(bbTempChain);
3325 bigBlockChain = BlockChainStream_Construct(This,
3329 return bigBlockChain;
3332 /******************************************************************************
3333 ** Storage32InternalImpl implementation
3336 StorageInternalImpl* StorageInternalImpl_Construct(
3337 StorageImpl* ancestorStorage,
3338 ULONG rootPropertyIndex)
3340 StorageInternalImpl* newStorage;
3343 * Allocate space for the new storage object
3345 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3349 memset(newStorage, 0, sizeof(StorageInternalImpl));
3352 * Initialize the virtual function table.
3354 ICOM_VTBL(newStorage) = &Storage32InternalImpl_Vtbl;
3355 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3358 * Keep the ancestor storage pointer and nail a reference to it.
3360 newStorage->ancestorStorage = ancestorStorage;
3361 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3364 * Keep the index of the root property set for this storage,
3366 newStorage->rootPropertySetIndex = rootPropertyIndex;
3374 void StorageInternalImpl_Destroy(
3375 StorageInternalImpl* This)
3377 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3378 HeapFree(GetProcessHeap(), 0, This);
3381 /******************************************************************************
3383 ** Storage32InternalImpl_Commit
3385 ** The non-root storages cannot be opened in transacted mode thus this function
3388 HRESULT WINAPI StorageInternalImpl_Commit(
3390 DWORD grfCommitFlags) /* [in] */
3395 /******************************************************************************
3397 ** Storage32InternalImpl_Revert
3399 ** The non-root storages cannot be opened in transacted mode thus this function
3402 HRESULT WINAPI StorageInternalImpl_Revert(
3408 /******************************************************************************
3409 ** IEnumSTATSTGImpl implementation
3412 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3413 StorageImpl* parentStorage,
3414 ULONG firstPropertyNode)
3416 IEnumSTATSTGImpl* newEnumeration;
3418 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3420 if (newEnumeration!=0)
3423 * Set-up the virtual function table and reference count.
3425 ICOM_VTBL(newEnumeration) = &IEnumSTATSTGImpl_Vtbl;
3426 newEnumeration->ref = 0;
3429 * We want to nail-down the reference to the storage in case the
3430 * enumeration out-lives the storage in the client application.
3432 newEnumeration->parentStorage = parentStorage;
3433 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3435 newEnumeration->firstPropertyNode = firstPropertyNode;
3438 * Initialize the search stack
3440 newEnumeration->stackSize = 0;
3441 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3442 newEnumeration->stackToVisit =
3443 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3446 * Make sure the current node of the iterator is the first one.
3448 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3451 return newEnumeration;
3454 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3456 IStorage_Release((IStorage*)This->parentStorage);
3457 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3458 HeapFree(GetProcessHeap(), 0, This);
3461 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3462 IEnumSTATSTG* iface,
3466 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3469 * Perform a sanity check on the parameters.
3472 return E_INVALIDARG;
3475 * Initialize the return parameter.
3480 * Compare the riid with the interface IDs implemented by this object.
3482 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3484 *ppvObject = (IEnumSTATSTG*)This;
3486 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3488 *ppvObject = (IEnumSTATSTG*)This;
3492 * Check that we obtained an interface.
3494 if ((*ppvObject)==0)
3495 return E_NOINTERFACE;
3498 * Query Interface always increases the reference count by one when it is
3501 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3506 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3507 IEnumSTATSTG* iface)
3509 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3515 ULONG WINAPI IEnumSTATSTGImpl_Release(
3516 IEnumSTATSTG* iface)
3518 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3526 * If the reference count goes down to 0, perform suicide.
3530 IEnumSTATSTGImpl_Destroy(This);
3536 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3537 IEnumSTATSTG* iface,
3540 ULONG* pceltFetched)
3542 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3544 StgProperty currentProperty;
3545 STATSTG* currentReturnStruct = rgelt;
3546 ULONG objectFetched = 0;
3547 ULONG currentSearchNode;
3550 * Perform a sanity check on the parameters.
3552 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3553 return E_INVALIDARG;
3556 * To avoid the special case, get another pointer to a ULONG value if
3557 * the caller didn't supply one.
3559 if (pceltFetched==0)
3560 pceltFetched = &objectFetched;
3563 * Start the iteration, we will iterate until we hit the end of the
3564 * linked list or until we hit the number of items to iterate through
3569 * Start with the node at the top of the stack.
3571 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3573 while ( ( *pceltFetched < celt) &&
3574 ( currentSearchNode!=PROPERTY_NULL) )
3577 * Remove the top node from the stack
3579 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3582 * Read the property from the storage.
3584 StorageImpl_ReadProperty(This->parentStorage,
3589 * Copy the information to the return buffer.
3591 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3596 * Step to the next item in the iteration
3599 currentReturnStruct++;
3602 * Push the next search node in the search stack.
3604 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3607 * continue the iteration.
3609 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3612 if (*pceltFetched == celt)
3619 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3620 IEnumSTATSTG* iface,
3623 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3625 StgProperty currentProperty;
3626 ULONG objectFetched = 0;
3627 ULONG currentSearchNode;
3630 * Start with the node at the top of the stack.
3632 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3634 while ( (objectFetched < celt) &&
3635 (currentSearchNode!=PROPERTY_NULL) )
3638 * Remove the top node from the stack
3640 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3643 * Read the property from the storage.
3645 StorageImpl_ReadProperty(This->parentStorage,
3650 * Step to the next item in the iteration
3655 * Push the next search node in the search stack.
3657 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3660 * continue the iteration.
3662 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3665 if (objectFetched == celt)
3671 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3672 IEnumSTATSTG* iface)
3674 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3676 StgProperty rootProperty;
3677 BOOL readSuccessful;
3680 * Re-initialize the search stack to an empty stack
3682 This->stackSize = 0;
3685 * Read the root property from the storage.
3687 readSuccessful = StorageImpl_ReadProperty(
3688 This->parentStorage,
3689 This->firstPropertyNode,
3694 assert(rootProperty.sizeOfNameString!=0);
3697 * Push the search node in the search stack.
3699 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3705 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3706 IEnumSTATSTG* iface,
3707 IEnumSTATSTG** ppenum)
3709 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3711 IEnumSTATSTGImpl* newClone;
3714 * Perform a sanity check on the parameters.
3717 return E_INVALIDARG;
3719 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3720 This->firstPropertyNode);
3724 * The new clone enumeration must point to the same current node as
3727 newClone->stackSize = This->stackSize ;
3728 newClone->stackMaxSize = This->stackMaxSize ;
3729 newClone->stackToVisit =
3730 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3733 newClone->stackToVisit,
3735 sizeof(ULONG) * newClone->stackSize);
3737 *ppenum = (IEnumSTATSTG*)newClone;
3740 * Don't forget to nail down a reference to the clone before
3743 IEnumSTATSTGImpl_AddRef(*ppenum);
3748 INT IEnumSTATSTGImpl_FindParentProperty(
3749 IEnumSTATSTGImpl *This,
3750 ULONG childProperty,
3751 StgProperty *currentProperty,
3754 ULONG currentSearchNode;
3758 * To avoid the special case, get another pointer to a ULONG value if
3759 * the caller didn't supply one.
3762 thisNodeId = &foundNode;
3765 * Start with the node at the top of the stack.
3767 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3770 while (currentSearchNode!=PROPERTY_NULL)
3773 * Store the current node in the returned parameters
3775 *thisNodeId = currentSearchNode;
3778 * Remove the top node from the stack
3780 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3783 * Read the property from the storage.
3785 StorageImpl_ReadProperty(
3786 This->parentStorage,
3790 if (currentProperty->previousProperty == childProperty)
3791 return PROPERTY_RELATION_PREVIOUS;
3793 else if (currentProperty->nextProperty == childProperty)
3794 return PROPERTY_RELATION_NEXT;
3796 else if (currentProperty->dirProperty == childProperty)
3797 return PROPERTY_RELATION_DIR;
3800 * Push the next search node in the search stack.
3802 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3805 * continue the iteration.
3807 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3810 return PROPERTY_NULL;
3813 ULONG IEnumSTATSTGImpl_FindProperty(
3814 IEnumSTATSTGImpl* This,
3815 const OLECHAR* lpszPropName,
3816 StgProperty* currentProperty)
3818 ULONG currentSearchNode;
3821 * Start with the node at the top of the stack.
3823 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3825 while (currentSearchNode!=PROPERTY_NULL)
3828 * Remove the top node from the stack
3830 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3833 * Read the property from the storage.
3835 StorageImpl_ReadProperty(This->parentStorage,
3839 if ( propertyNameCmp(
3840 (OLECHAR*)currentProperty->name,
3841 (OLECHAR*)lpszPropName) == 0)
3842 return currentSearchNode;
3845 * Push the next search node in the search stack.
3847 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3850 * continue the iteration.
3852 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3855 return PROPERTY_NULL;
3858 void IEnumSTATSTGImpl_PushSearchNode(
3859 IEnumSTATSTGImpl* This,
3862 StgProperty rootProperty;
3863 BOOL readSuccessful;
3866 * First, make sure we're not trying to push an unexisting node.
3868 if (nodeToPush==PROPERTY_NULL)
3872 * First push the node to the stack
3874 if (This->stackSize == This->stackMaxSize)
3876 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3878 This->stackToVisit = HeapReAlloc(
3882 sizeof(ULONG) * This->stackMaxSize);
3885 This->stackToVisit[This->stackSize] = nodeToPush;
3889 * Read the root property from the storage.
3891 readSuccessful = StorageImpl_ReadProperty(
3892 This->parentStorage,
3898 assert(rootProperty.sizeOfNameString!=0);
3901 * Push the previous search node in the search stack.
3903 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3907 ULONG IEnumSTATSTGImpl_PopSearchNode(
3908 IEnumSTATSTGImpl* This,
3913 if (This->stackSize == 0)
3914 return PROPERTY_NULL;
3916 topNode = This->stackToVisit[This->stackSize-1];
3924 /******************************************************************************
3925 ** StorageUtl implementation
3928 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3930 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3933 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3935 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3938 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3940 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3943 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3945 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3948 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3950 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3951 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3952 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3954 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3957 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3959 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3960 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3961 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3963 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3966 void StorageUtl_CopyPropertyToSTATSTG(
3967 STATSTG* destination,
3968 StgProperty* source,
3972 * The copy of the string occurs only when the flag is not set
3974 if ((statFlags & STATFLAG_NONAME) != 0)
3976 destination->pwcsName = 0;
3980 destination->pwcsName =
3981 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3983 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3986 switch (source->propertyType)
3988 case PROPTYPE_STORAGE:
3990 destination->type = STGTY_STORAGE;
3992 case PROPTYPE_STREAM:
3993 destination->type = STGTY_STREAM;
3996 destination->type = STGTY_STREAM;
4000 destination->cbSize = source->size;
4002 currentReturnStruct->mtime = {0}; TODO
4003 currentReturnStruct->ctime = {0};
4004 currentReturnStruct->atime = {0};
4006 destination->grfMode = 0;
4007 destination->grfLocksSupported = 0;
4008 destination->clsid = source->propertyUniqueID;
4009 destination->grfStateBits = 0;
4010 destination->reserved = 0;
4013 /******************************************************************************
4014 ** BlockChainStream implementation
4017 BlockChainStream* BlockChainStream_Construct(
4018 StorageImpl* parentStorage,
4019 ULONG* headOfStreamPlaceHolder,
4020 ULONG propertyIndex)
4022 BlockChainStream* newStream;
4025 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4027 newStream->parentStorage = parentStorage;
4028 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4029 newStream->ownerPropertyIndex = propertyIndex;
4030 newStream->lastBlockNoInSequence = 0xFFFFFFFF;
4031 newStream->tailIndex = BLOCK_END_OF_CHAIN;
4032 newStream->numBlocks = 0;
4034 blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4036 while (blockIndex != BLOCK_END_OF_CHAIN)
4038 newStream->numBlocks++;
4039 newStream->tailIndex = blockIndex;
4041 blockIndex = StorageImpl_GetNextBlockInChain(
4049 void BlockChainStream_Destroy(BlockChainStream* This)
4051 HeapFree(GetProcessHeap(), 0, This);
4054 /******************************************************************************
4055 * BlockChainStream_GetHeadOfChain
4057 * Returns the head of this stream chain.
4058 * Some special chains don't have properties, their heads are kept in
4059 * This->headOfStreamPlaceHolder.
4062 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4064 StgProperty chainProperty;
4065 BOOL readSuccessful;
4067 if (This->headOfStreamPlaceHolder != 0)
4068 return *(This->headOfStreamPlaceHolder);
4070 if (This->ownerPropertyIndex != PROPERTY_NULL)
4072 readSuccessful = StorageImpl_ReadProperty(
4073 This->parentStorage,
4074 This->ownerPropertyIndex,
4079 return chainProperty.startingBlock;
4083 return BLOCK_END_OF_CHAIN;
4086 /******************************************************************************
4087 * BlockChainStream_GetCount
4089 * Returns the number of blocks that comprises this chain.
4090 * This is not the size of the stream as the last block may not be full!
4093 ULONG BlockChainStream_GetCount(BlockChainStream* This)
4098 blockIndex = BlockChainStream_GetHeadOfChain(This);
4100 while (blockIndex != BLOCK_END_OF_CHAIN)
4104 blockIndex = StorageImpl_GetNextBlockInChain(
4105 This->parentStorage,
4112 /******************************************************************************
4113 * BlockChainStream_ReadAt
4115 * Reads a specified number of bytes from this chain at the specified offset.
4116 * bytesRead may be NULL.
4117 * Failure will be returned if the specified number of bytes has not been read.
4119 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
4120 ULARGE_INTEGER offset,
4125 ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
4126 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->bigBlockSize;
4127 ULONG bytesToReadInBuffer;
4130 BYTE* bigBlockBuffer;
4133 * Find the first block in the stream that contains part of the buffer.
4135 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4136 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4137 (blockNoInSequence < This->lastBlockNoInSequence) )
4139 blockIndex = BlockChainStream_GetHeadOfChain(This);
4140 This->lastBlockNoInSequence = blockNoInSequence;
4144 ULONG temp = blockNoInSequence;
4146 blockIndex = This->lastBlockNoInSequenceIndex;
4147 blockNoInSequence -= This->lastBlockNoInSequence;
4148 This->lastBlockNoInSequence = temp;
4151 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4154 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4156 blockNoInSequence--;
4159 This->lastBlockNoInSequenceIndex = blockIndex;
4162 * Start reading the buffer.
4165 bufferWalker = buffer;
4167 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4170 * Calculate how many bytes we can copy from this big block.
4172 bytesToReadInBuffer =
4173 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
4176 * Copy those bytes to the buffer
4179 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
4181 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
4183 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4186 * Step to the next big block.
4189 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4191 bufferWalker += bytesToReadInBuffer;
4192 size -= bytesToReadInBuffer;
4193 *bytesRead += bytesToReadInBuffer;
4194 offsetInBlock = 0; /* There is no offset on the next block */
4201 /******************************************************************************
4202 * BlockChainStream_WriteAt
4204 * Writes the specified number of bytes to this chain at the specified offset.
4205 * bytesWritten may be NULL.
4206 * Will fail if not all specified number of bytes have been written.
4208 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
4209 ULARGE_INTEGER offset,
4212 ULONG* bytesWritten)
4214 ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
4215 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->bigBlockSize;
4219 BYTE* bigBlockBuffer;
4222 * Find the first block in the stream that contains part of the buffer.
4224 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4225 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4226 (blockNoInSequence < This->lastBlockNoInSequence) )
4228 blockIndex = BlockChainStream_GetHeadOfChain(This);
4229 This->lastBlockNoInSequence = blockNoInSequence;
4233 ULONG temp = blockNoInSequence;
4235 blockIndex = This->lastBlockNoInSequenceIndex;
4236 blockNoInSequence -= This->lastBlockNoInSequence;
4237 This->lastBlockNoInSequence = temp;
4240 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4243 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4245 blockNoInSequence--;
4248 This->lastBlockNoInSequenceIndex = blockIndex;
4251 * Here, I'm casting away the constness on the buffer variable
4252 * This is OK since we don't intend to modify that buffer.
4255 bufferWalker = (BYTE*)buffer;
4257 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4260 * Calculate how many bytes we can copy from this big block.
4263 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
4266 * Copy those bytes to the buffer
4268 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
4270 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
4272 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4275 * Step to the next big block.
4278 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4280 bufferWalker += bytesToWrite;
4281 size -= bytesToWrite;
4282 *bytesWritten += bytesToWrite;
4283 offsetInBlock = 0; /* There is no offset on the next block */
4289 /******************************************************************************
4290 * BlockChainStream_Shrink
4292 * Shrinks this chain in the big block depot.
4294 BOOL BlockChainStream_Shrink(BlockChainStream* This,
4295 ULARGE_INTEGER newSize)
4297 ULONG blockIndex, extraBlock;
4302 * Reset the last accessed block cache.
4304 This->lastBlockNoInSequence = 0xFFFFFFFF;
4305 This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4308 * Figure out how many blocks are needed to contain the new size
4310 numBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
4312 if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
4315 blockIndex = BlockChainStream_GetHeadOfChain(This);
4318 * Go to the new end of chain
4320 while (count < numBlocks)
4323 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4328 /* Get the next block before marking the new end */
4330 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4332 /* Mark the new end of chain */
4333 StorageImpl_SetNextBlockInChain(
4334 This->parentStorage,
4336 BLOCK_END_OF_CHAIN);
4338 This->tailIndex = blockIndex;
4339 This->numBlocks = numBlocks;
4342 * Mark the extra blocks as free
4344 while (extraBlock != BLOCK_END_OF_CHAIN)
4347 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4349 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4350 extraBlock = blockIndex;
4356 /******************************************************************************
4357 * BlockChainStream_Enlarge
4359 * Grows this chain in the big block depot.
4361 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4362 ULARGE_INTEGER newSize)
4364 ULONG blockIndex, currentBlock;
4366 ULONG oldNumBlocks = 0;
4368 blockIndex = BlockChainStream_GetHeadOfChain(This);
4371 * Empty chain. Create the head.
4373 if (blockIndex == BLOCK_END_OF_CHAIN)
4375 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4376 StorageImpl_SetNextBlockInChain(This->parentStorage,
4378 BLOCK_END_OF_CHAIN);
4380 if (This->headOfStreamPlaceHolder != 0)
4382 *(This->headOfStreamPlaceHolder) = blockIndex;
4386 StgProperty chainProp;
4387 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4389 StorageImpl_ReadProperty(
4390 This->parentStorage,
4391 This->ownerPropertyIndex,
4394 chainProp.startingBlock = blockIndex;
4396 StorageImpl_WriteProperty(
4397 This->parentStorage,
4398 This->ownerPropertyIndex,
4402 This->tailIndex = blockIndex;
4403 This->numBlocks = 1;
4407 * Figure out how many blocks are needed to contain this stream
4409 newNumBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
4411 if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
4415 * Go to the current end of chain
4417 if (This->tailIndex == BLOCK_END_OF_CHAIN)
4419 currentBlock = blockIndex;
4421 while (blockIndex != BLOCK_END_OF_CHAIN)
4424 currentBlock = blockIndex;
4427 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4430 This->tailIndex = currentBlock;
4433 currentBlock = This->tailIndex;
4434 oldNumBlocks = This->numBlocks;
4437 * Add new blocks to the chain
4439 if (oldNumBlocks < newNumBlocks)
4441 while (oldNumBlocks < newNumBlocks)
4443 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4445 StorageImpl_SetNextBlockInChain(
4446 This->parentStorage,
4450 StorageImpl_SetNextBlockInChain(
4451 This->parentStorage,
4453 BLOCK_END_OF_CHAIN);
4455 currentBlock = blockIndex;
4459 This->tailIndex = blockIndex;
4460 This->numBlocks = newNumBlocks;
4466 /******************************************************************************
4467 * BlockChainStream_SetSize
4469 * Sets the size of this stream. The big block depot will be updated.
4470 * The file will grow if we grow the chain.
4472 * TODO: Free the actual blocks in the file when we shrink the chain.
4473 * Currently, the blocks are still in the file. So the file size
4474 * doesn't shrink even if we shrink streams.
4476 BOOL BlockChainStream_SetSize(
4477 BlockChainStream* This,
4478 ULARGE_INTEGER newSize)
4480 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4482 if (newSize.s.LowPart == size.s.LowPart)
4485 if (newSize.s.LowPart < size.s.LowPart)
4487 BlockChainStream_Shrink(This, newSize);
4491 ULARGE_INTEGER fileSize =
4492 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4494 ULONG diff = newSize.s.LowPart - size.s.LowPart;
4497 * Make sure the file stays a multiple of blocksize
4499 if ((diff % This->parentStorage->bigBlockSize) != 0)
4500 diff += (This->parentStorage->bigBlockSize -
4501 (diff % This->parentStorage->bigBlockSize) );
4503 fileSize.s.LowPart += diff;
4504 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4506 BlockChainStream_Enlarge(This, newSize);
4512 /******************************************************************************
4513 * BlockChainStream_GetSize
4515 * Returns the size of this chain.
4516 * Will return the block count if this chain doesn't have a property.
4518 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4520 StgProperty chainProperty;
4522 if(This->headOfStreamPlaceHolder == NULL)
4525 * This chain is a data stream read the property and return
4526 * the appropriate size
4528 StorageImpl_ReadProperty(
4529 This->parentStorage,
4530 This->ownerPropertyIndex,
4533 return chainProperty.size;
4538 * this chain is a chain that does not have a property, figure out the
4539 * size by making the product number of used blocks times the
4542 ULARGE_INTEGER result;
4543 result.s.HighPart = 0;
4546 BlockChainStream_GetCount(This) *
4547 This->parentStorage->bigBlockSize;
4553 /******************************************************************************
4554 ** SmallBlockChainStream implementation
4557 SmallBlockChainStream* SmallBlockChainStream_Construct(
4558 StorageImpl* parentStorage,
4559 ULONG propertyIndex)
4561 SmallBlockChainStream* newStream;
4563 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4565 newStream->parentStorage = parentStorage;
4566 newStream->ownerPropertyIndex = propertyIndex;
4571 void SmallBlockChainStream_Destroy(
4572 SmallBlockChainStream* This)
4574 HeapFree(GetProcessHeap(), 0, This);
4577 /******************************************************************************
4578 * SmallBlockChainStream_GetHeadOfChain
4580 * Returns the head of this chain of small blocks.
4582 ULONG SmallBlockChainStream_GetHeadOfChain(
4583 SmallBlockChainStream* This)
4585 StgProperty chainProperty;
4586 BOOL readSuccessful;
4588 if (This->ownerPropertyIndex)
4590 readSuccessful = StorageImpl_ReadProperty(
4591 This->parentStorage,
4592 This->ownerPropertyIndex,
4597 return chainProperty.startingBlock;
4602 return BLOCK_END_OF_CHAIN;
4605 /******************************************************************************
4606 * SmallBlockChainStream_GetNextBlockInChain
4608 * Returns the index of the next small block in this chain.
4611 * - BLOCK_END_OF_CHAIN: end of this chain
4612 * - BLOCK_UNUSED: small block 'blockIndex' is free
4614 ULONG SmallBlockChainStream_GetNextBlockInChain(
4615 SmallBlockChainStream* This,
4618 ULARGE_INTEGER offsetOfBlockInDepot;
4620 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4624 offsetOfBlockInDepot.s.HighPart = 0;
4625 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4628 * Read those bytes in the buffer from the small block file.
4630 success = BlockChainStream_ReadAt(
4631 This->parentStorage->smallBlockDepotChain,
4632 offsetOfBlockInDepot,
4639 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4642 return nextBlockInChain;
4645 /******************************************************************************
4646 * SmallBlockChainStream_SetNextBlockInChain
4648 * Writes the index of the next block of the specified block in the small
4650 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4651 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4653 void SmallBlockChainStream_SetNextBlockInChain(
4654 SmallBlockChainStream* This,
4658 ULARGE_INTEGER offsetOfBlockInDepot;
4662 offsetOfBlockInDepot.s.HighPart = 0;
4663 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4665 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4668 * Read those bytes in the buffer from the small block file.
4670 BlockChainStream_WriteAt(
4671 This->parentStorage->smallBlockDepotChain,
4672 offsetOfBlockInDepot,
4678 /******************************************************************************
4679 * SmallBlockChainStream_FreeBlock
4681 * Flag small block 'blockIndex' as free in the small block depot.
4683 void SmallBlockChainStream_FreeBlock(
4684 SmallBlockChainStream* This,
4687 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4690 /******************************************************************************
4691 * SmallBlockChainStream_GetNextFreeBlock
4693 * Returns the index of a free small block. The small block depot will be
4694 * enlarged if necessary. The small block chain will also be enlarged if
4697 ULONG SmallBlockChainStream_GetNextFreeBlock(
4698 SmallBlockChainStream* This)
4700 ULARGE_INTEGER offsetOfBlockInDepot;
4703 ULONG blockIndex = 0;
4704 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4705 BOOL success = TRUE;
4706 ULONG smallBlocksPerBigBlock;
4708 offsetOfBlockInDepot.s.HighPart = 0;
4711 * Scan the small block depot for a free block
4713 while (nextBlockIndex != BLOCK_UNUSED)
4715 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4717 success = BlockChainStream_ReadAt(
4718 This->parentStorage->smallBlockDepotChain,
4719 offsetOfBlockInDepot,
4725 * If we run out of space for the small block depot, enlarge it
4729 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4731 if (nextBlockIndex != BLOCK_UNUSED)
4737 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4739 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4740 ULONG nextBlock, newsbdIndex;
4741 BYTE* smallBlockDepot;
4743 nextBlock = sbdIndex;
4744 while (nextBlock != BLOCK_END_OF_CHAIN)
4746 sbdIndex = nextBlock;
4748 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4751 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4752 if (sbdIndex != BLOCK_END_OF_CHAIN)
4753 StorageImpl_SetNextBlockInChain(
4754 This->parentStorage,
4758 StorageImpl_SetNextBlockInChain(
4759 This->parentStorage,
4761 BLOCK_END_OF_CHAIN);
4764 * Initialize all the small blocks to free
4767 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4769 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4770 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4775 * We have just created the small block depot.
4777 StgProperty rootProp;
4781 * Save it in the header
4783 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4784 StorageImpl_SaveFileHeader(This->parentStorage);
4787 * And allocate the first big block that will contain small blocks
4790 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4792 StorageImpl_SetNextBlockInChain(
4793 This->parentStorage,
4795 BLOCK_END_OF_CHAIN);
4797 StorageImpl_ReadProperty(
4798 This->parentStorage,
4799 This->parentStorage->rootPropertySetIndex,
4802 rootProp.startingBlock = sbStartIndex;
4803 rootProp.size.s.HighPart = 0;
4804 rootProp.size.s.LowPart = This->parentStorage->bigBlockSize;
4806 StorageImpl_WriteProperty(
4807 This->parentStorage,
4808 This->parentStorage->rootPropertySetIndex,
4814 smallBlocksPerBigBlock =
4815 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4818 * Verify if we have to allocate big blocks to contain small blocks
4820 if (blockIndex % smallBlocksPerBigBlock == 0)
4822 StgProperty rootProp;
4823 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4825 StorageImpl_ReadProperty(
4826 This->parentStorage,
4827 This->parentStorage->rootPropertySetIndex,
4830 if (rootProp.size.s.LowPart <
4831 (blocksRequired * This->parentStorage->bigBlockSize))
4833 rootProp.size.s.LowPart += This->parentStorage->bigBlockSize;
4835 BlockChainStream_SetSize(
4836 This->parentStorage->smallBlockRootChain,
4839 StorageImpl_WriteProperty(
4840 This->parentStorage,
4841 This->parentStorage->rootPropertySetIndex,
4849 /******************************************************************************
4850 * SmallBlockChainStream_ReadAt
4852 * Reads a specified number of bytes from this chain at the specified offset.
4853 * bytesRead may be NULL.
4854 * Failure will be returned if the specified number of bytes has not been read.
4856 BOOL SmallBlockChainStream_ReadAt(
4857 SmallBlockChainStream* This,
4858 ULARGE_INTEGER offset,
4863 ULARGE_INTEGER offsetInBigBlockFile;
4864 ULONG blockNoInSequence =
4865 offset.s.LowPart / This->parentStorage->smallBlockSize;
4867 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
4868 ULONG bytesToReadInBuffer;
4870 ULONG bytesReadFromBigBlockFile;
4874 * This should never happen on a small block file.
4876 assert(offset.s.HighPart==0);
4879 * Find the first block in the stream that contains part of the buffer.
4881 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4883 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4885 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4887 blockNoInSequence--;
4891 * Start reading the buffer.
4894 bufferWalker = buffer;
4896 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4899 * Calculate how many bytes we can copy from this small block.
4901 bytesToReadInBuffer =
4902 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4905 * Calculate the offset of the small block in the small block file.
4907 offsetInBigBlockFile.s.HighPart = 0;
4908 offsetInBigBlockFile.s.LowPart =
4909 blockIndex * This->parentStorage->smallBlockSize;
4911 offsetInBigBlockFile.s.LowPart += offsetInBlock;
4914 * Read those bytes in the buffer from the small block file.
4916 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4917 offsetInBigBlockFile,
4918 bytesToReadInBuffer,
4920 &bytesReadFromBigBlockFile);
4922 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4925 * Step to the next big block.
4927 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4928 bufferWalker += bytesToReadInBuffer;
4929 size -= bytesToReadInBuffer;
4930 *bytesRead += bytesToReadInBuffer;
4931 offsetInBlock = 0; /* There is no offset on the next block */
4937 /******************************************************************************
4938 * SmallBlockChainStream_WriteAt
4940 * Writes the specified number of bytes to this chain at the specified offset.
4941 * bytesWritten may be NULL.
4942 * Will fail if not all specified number of bytes have been written.
4944 BOOL SmallBlockChainStream_WriteAt(
4945 SmallBlockChainStream* This,
4946 ULARGE_INTEGER offset,
4949 ULONG* bytesWritten)
4951 ULARGE_INTEGER offsetInBigBlockFile;
4952 ULONG blockNoInSequence =
4953 offset.s.LowPart / This->parentStorage->smallBlockSize;
4955 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
4956 ULONG bytesToWriteInBuffer;
4958 ULONG bytesWrittenFromBigBlockFile;
4962 * This should never happen on a small block file.
4964 assert(offset.s.HighPart==0);
4967 * Find the first block in the stream that contains part of the buffer.
4969 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4971 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4973 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4975 blockNoInSequence--;
4979 * Start writing the buffer.
4981 * Here, I'm casting away the constness on the buffer variable
4982 * This is OK since we don't intend to modify that buffer.
4985 bufferWalker = (BYTE*)buffer;
4986 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4989 * Calculate how many bytes we can copy to this small block.
4991 bytesToWriteInBuffer =
4992 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4995 * Calculate the offset of the small block in the small block file.
4997 offsetInBigBlockFile.s.HighPart = 0;
4998 offsetInBigBlockFile.s.LowPart =
4999 blockIndex * This->parentStorage->smallBlockSize;
5001 offsetInBigBlockFile.s.LowPart += offsetInBlock;
5004 * Write those bytes in the buffer to the small block file.
5006 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
5007 offsetInBigBlockFile,
5008 bytesToWriteInBuffer,
5010 &bytesWrittenFromBigBlockFile);
5012 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
5015 * Step to the next big block.
5017 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5018 bufferWalker += bytesToWriteInBuffer;
5019 size -= bytesToWriteInBuffer;
5020 *bytesWritten += bytesToWriteInBuffer;
5021 offsetInBlock = 0; /* There is no offset on the next block */
5027 /******************************************************************************
5028 * SmallBlockChainStream_Shrink
5030 * Shrinks this chain in the small block depot.
5032 BOOL SmallBlockChainStream_Shrink(
5033 SmallBlockChainStream* This,
5034 ULARGE_INTEGER newSize)
5036 ULONG blockIndex, extraBlock;
5040 numBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
5042 if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
5045 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5048 * Go to the new end of chain
5050 while (count < numBlocks)
5052 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5057 * If the count is 0, we have a special case, the head of the chain was
5062 StgProperty chainProp;
5064 StorageImpl_ReadProperty(This->parentStorage,
5065 This->ownerPropertyIndex,
5068 chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5070 StorageImpl_WriteProperty(This->parentStorage,
5071 This->ownerPropertyIndex,
5075 * We start freeing the chain at the head block.
5077 extraBlock = blockIndex;
5081 /* Get the next block before marking the new end */
5082 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5084 /* Mark the new end of chain */
5085 SmallBlockChainStream_SetNextBlockInChain(
5088 BLOCK_END_OF_CHAIN);
5092 * Mark the extra blocks as free
5094 while (extraBlock != BLOCK_END_OF_CHAIN)
5096 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
5097 SmallBlockChainStream_FreeBlock(This, extraBlock);
5098 extraBlock = blockIndex;
5104 /******************************************************************************
5105 * SmallBlockChainStream_Enlarge
5107 * Grows this chain in the small block depot.
5109 BOOL SmallBlockChainStream_Enlarge(
5110 SmallBlockChainStream* This,
5111 ULARGE_INTEGER newSize)
5113 ULONG blockIndex, currentBlock;
5115 ULONG oldNumBlocks = 0;
5117 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5122 if (blockIndex == BLOCK_END_OF_CHAIN)
5125 StgProperty chainProp;
5127 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5130 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5132 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5135 blockIndex = chainProp.startingBlock;
5136 SmallBlockChainStream_SetNextBlockInChain(
5139 BLOCK_END_OF_CHAIN);
5142 currentBlock = blockIndex;
5145 * Figure out how many blocks are needed to contain this stream
5147 newNumBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
5149 if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
5153 * Go to the current end of chain
5155 while (blockIndex != BLOCK_END_OF_CHAIN)
5158 currentBlock = blockIndex;
5159 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
5163 * Add new blocks to the chain
5165 while (oldNumBlocks < newNumBlocks)
5167 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5168 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5170 SmallBlockChainStream_SetNextBlockInChain(
5173 BLOCK_END_OF_CHAIN);
5175 currentBlock = blockIndex;
5182 /******************************************************************************
5183 * SmallBlockChainStream_GetCount
5185 * Returns the number of blocks that comprises this chain.
5186 * This is not the size of this chain as the last block may not be full!
5188 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5193 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5195 while (blockIndex != BLOCK_END_OF_CHAIN)
5199 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5205 /******************************************************************************
5206 * SmallBlockChainStream_SetSize
5208 * Sets the size of this stream.
5209 * The file will grow if we grow the chain.
5211 * TODO: Free the actual blocks in the file when we shrink the chain.
5212 * Currently, the blocks are still in the file. So the file size
5213 * doesn't shrink even if we shrink streams.
5215 BOOL SmallBlockChainStream_SetSize(
5216 SmallBlockChainStream* This,
5217 ULARGE_INTEGER newSize)
5219 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5221 if (newSize.s.LowPart == size.s.LowPart)
5224 if (newSize.s.LowPart < size.s.LowPart)
5226 SmallBlockChainStream_Shrink(This, newSize);
5230 SmallBlockChainStream_Enlarge(This, newSize);
5236 /******************************************************************************
5237 * SmallBlockChainStream_GetSize
5239 * Returns the size of this chain.
5241 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5243 StgProperty chainProperty;
5245 StorageImpl_ReadProperty(
5246 This->parentStorage,
5247 This->ownerPropertyIndex,
5250 return chainProperty.size;
5253 /******************************************************************************
5254 * StgCreateDocfile32 [OLE32.144]
5256 HRESULT WINAPI StgCreateDocfile(
5260 IStorage **ppstgOpen)
5262 StorageImpl* newStorage = 0;
5263 HANDLE hFile = INVALID_HANDLE_VALUE;
5268 DWORD fileAttributes;
5269 WCHAR tempFileName[MAX_PATH];
5271 TRACE("(%s, %lx, %ld, %p)\n",
5272 debugstr_w(pwcsName), grfMode,
5273 reserved, ppstgOpen);
5276 * Validate the parameters
5279 return STG_E_INVALIDPOINTER;
5282 * Validate the STGM flags
5284 if ( FAILED( validateSTGM(grfMode) ))
5285 return STG_E_INVALIDFLAG;
5288 * Generate a unique name.
5292 WCHAR tempPath[MAX_PATH];
5293 WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5295 memset(tempPath, 0, sizeof(tempPath));
5296 memset(tempFileName, 0, sizeof(tempFileName));
5298 if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5301 if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5302 pwcsName = tempFileName;
5304 return STG_E_INSUFFICIENTMEMORY;
5308 * Interpret the STGM value grfMode
5310 shareMode = GetShareModeFromSTGM(grfMode);
5311 accessMode = GetAccessModeFromSTGM(grfMode);
5312 creationMode = GetCreationModeFromSTGM(grfMode);
5314 if (grfMode & STGM_DELETEONRELEASE)
5315 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5317 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5319 if (grfMode & STGM_TRANSACTED)
5320 FIXME("Transacted mode not implemented.\n");
5323 * Initialize the "out" parameter.
5327 hFile = CreateFileW(pwcsName,
5335 if (hFile == INVALID_HANDLE_VALUE)
5341 * Allocate and initialize the new IStorage32object.
5343 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5345 if (newStorage == 0)
5346 return STG_E_INSUFFICIENTMEMORY;
5348 hr = StorageImpl_Construct(
5358 HeapFree(GetProcessHeap(), 0, newStorage);
5363 * Get an "out" pointer for the caller.
5365 hr = StorageBaseImpl_QueryInterface(
5366 (IStorage*)newStorage,
5367 (REFIID)&IID_IStorage,
5373 /******************************************************************************
5374 * StgOpenStorage32 [OLE32.148]
5376 HRESULT WINAPI StgOpenStorage(
5377 const OLECHAR *pwcsName,
5378 IStorage *pstgPriority,
5382 IStorage **ppstgOpen)
5384 StorageImpl* newStorage = 0;
5390 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5391 debugstr_w(pwcsName), pstgPriority, grfMode,
5392 snbExclude, reserved, ppstgOpen);
5395 * Perform a sanity check
5397 if (( pwcsName == 0) || (ppstgOpen == 0) )
5398 return STG_E_INVALIDPOINTER;
5401 * Validate the STGM flags
5403 if ( FAILED( validateSTGM(grfMode) ))
5404 return STG_E_INVALIDFLAG;
5407 * Interpret the STGM value grfMode
5409 shareMode = GetShareModeFromSTGM(grfMode);
5410 accessMode = GetAccessModeFromSTGM(grfMode);
5413 * Initialize the "out" parameter.
5417 hFile = CreateFileW( pwcsName,
5422 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5426 if (hFile==INVALID_HANDLE_VALUE)
5428 HRESULT hr = E_FAIL;
5429 DWORD last_error = GetLastError();
5433 case ERROR_FILE_NOT_FOUND:
5434 hr = STG_E_FILENOTFOUND;
5437 case ERROR_PATH_NOT_FOUND:
5438 hr = STG_E_PATHNOTFOUND;
5441 case ERROR_ACCESS_DENIED:
5442 case ERROR_WRITE_PROTECT:
5443 hr = STG_E_ACCESSDENIED;
5446 case ERROR_SHARING_VIOLATION:
5447 hr = STG_E_SHAREVIOLATION;
5458 * Allocate and initialize the new IStorage32object.
5460 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5462 if (newStorage == 0)
5463 return STG_E_INSUFFICIENTMEMORY;
5465 hr = StorageImpl_Construct(
5475 HeapFree(GetProcessHeap(), 0, newStorage);
5480 * Get an "out" pointer for the caller.
5482 hr = StorageBaseImpl_QueryInterface(
5483 (IStorage*)newStorage,
5484 (REFIID)&IID_IStorage,
5490 /******************************************************************************
5491 * StgCreateDocfileOnILockBytes [OLE32.145]
5493 HRESULT WINAPI StgCreateDocfileOnILockBytes(
5497 IStorage** ppstgOpen)
5499 StorageImpl* newStorage = 0;
5503 * Validate the parameters
5505 if ((ppstgOpen == 0) || (plkbyt == 0))
5506 return STG_E_INVALIDPOINTER;
5509 * Allocate and initialize the new IStorage object.
5511 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5513 if (newStorage == 0)
5514 return STG_E_INSUFFICIENTMEMORY;
5516 hr = StorageImpl_Construct(
5526 HeapFree(GetProcessHeap(), 0, newStorage);
5531 * Get an "out" pointer for the caller.
5533 hr = StorageBaseImpl_QueryInterface(
5534 (IStorage*)newStorage,
5535 (REFIID)&IID_IStorage,
5541 /******************************************************************************
5542 * StgOpenStorageOnILockBytes [OLE32.149]
5544 HRESULT WINAPI StgOpenStorageOnILockBytes(
5546 IStorage *pstgPriority,
5550 IStorage **ppstgOpen)
5552 StorageImpl* newStorage = 0;
5556 * Perform a sanity check
5558 if ((plkbyt == 0) || (ppstgOpen == 0))
5559 return STG_E_INVALIDPOINTER;
5562 * Validate the STGM flags
5564 if ( FAILED( validateSTGM(grfMode) ))
5565 return STG_E_INVALIDFLAG;
5568 * Initialize the "out" parameter.
5573 * Allocate and initialize the new IStorage object.
5575 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5577 if (newStorage == 0)
5578 return STG_E_INSUFFICIENTMEMORY;
5580 hr = StorageImpl_Construct(
5590 HeapFree(GetProcessHeap(), 0, newStorage);
5595 * Get an "out" pointer for the caller.
5597 hr = StorageBaseImpl_QueryInterface(
5598 (IStorage*)newStorage,
5599 (REFIID)&IID_IStorage,
5605 /******************************************************************************
5606 * StgSetTimes [ole32.150]
5610 HRESULT WINAPI StgSetTimes(WCHAR * str, FILETIME * a, FILETIME * b, FILETIME *c )
5613 FIXME("(%p, %p, %p, %p),stub!\n", str, a, b, c);
5617 /******************************************************************************
5618 * StgIsStorageILockBytes [OLE32.147]
5620 * Determines if the ILockBytes contains a storage object.
5622 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
5625 ULARGE_INTEGER offset;
5627 offset.s.HighPart = 0;
5628 offset.s.LowPart = 0;
5630 ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
5632 if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
5638 /******************************************************************************
5639 * WriteClassStg32 [OLE32.158]
5641 * This method will store the specified CLSID in the specified storage object
5643 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5649 hRes = IStorage_SetClass(pStg, rclsid);
5654 /*******************************************************************************************
5657 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5659 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
5669 * read a STATSTG structure (contains the clsid) from the storage
5671 hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
5674 *pclsid=pstatstg.clsid;
5679 /*************************************************************************************
5682 * This function loads an object from stream
5684 HRESULT WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
5689 FIXME("(),stub!\n");
5691 res=ReadClassStm(pStm,&clsid);
5693 if (SUCCEEDED(res)){
5695 res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
5699 res=IPersistStream_Load((IPersistStream*)ppvObj,pStm);
5705 /************************************************************************************************
5708 * This function saves an object with the IPersistStream interface on it to the specified stream
5710 HRESULT WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
5716 TRACE("(%p,%p)\n",pPStm,pStm);
5718 res=IPersistStream_GetClassID(pPStm,&clsid);
5720 if (SUCCEEDED(res)){
5722 res=WriteClassStm(pStm,&clsid);
5726 res=IPersistStream_Save(pPStm,pStm,FALSE);
5732 /****************************************************************************
5733 * This method validate a STGM parameter that can contain the values below
5735 * STGM_DIRECT 0x00000000
5736 * STGM_TRANSACTED 0x00010000
5737 * STGM_SIMPLE 0x08000000
5739 * STGM_READ 0x00000000
5740 * STGM_WRITE 0x00000001
5741 * STGM_READWRITE 0x00000002
5743 * STGM_SHARE_DENY_NONE 0x00000040
5744 * STGM_SHARE_DENY_READ 0x00000030
5745 * STGM_SHARE_DENY_WRITE 0x00000020
5746 * STGM_SHARE_EXCLUSIVE 0x00000010
5748 * STGM_PRIORITY 0x00040000
5749 * STGM_DELETEONRELEASE 0x04000000
5751 * STGM_CREATE 0x00001000
5752 * STGM_CONVERT 0x00020000
5753 * STGM_FAILIFTHERE 0x00000000
5755 * STGM_NOSCRATCH 0x00100000
5756 * STGM_NOSNAPSHOT 0x00200000
5758 static HRESULT validateSTGM(DWORD stgm)
5760 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5761 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5762 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5764 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5765 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5766 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5768 BOOL bSTGM_SHARE_DENY_NONE =
5769 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5771 BOOL bSTGM_SHARE_DENY_READ =
5772 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5774 BOOL bSTGM_SHARE_DENY_WRITE =
5775 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5777 BOOL bSTGM_SHARE_EXCLUSIVE =
5778 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5780 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5781 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5783 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5784 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5787 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5789 if ( ! bSTGM_DIRECT )
5790 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5794 * STGM_WRITE | STGM_READWRITE | STGM_READ
5797 if( bSTGM_WRITE && bSTGM_READWRITE )
5801 * STGM_SHARE_DENY_NONE | others
5802 * (I assume here that DENY_READ implies DENY_WRITE)
5804 if ( bSTGM_SHARE_DENY_NONE )
5805 if ( bSTGM_SHARE_DENY_READ ||
5806 bSTGM_SHARE_DENY_WRITE ||
5807 bSTGM_SHARE_EXCLUSIVE)
5811 * STGM_CREATE | STGM_CONVERT
5812 * if both are false, STGM_FAILIFTHERE is set to TRUE
5814 if ( bSTGM_CREATE && bSTGM_CONVERT )
5818 * STGM_NOSCRATCH requires STGM_TRANSACTED
5820 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5824 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5825 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5827 if (bSTGM_NOSNAPSHOT)
5829 if ( ! ( bSTGM_TRANSACTED &&
5830 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5837 /****************************************************************************
5838 * GetShareModeFromSTGM
5840 * This method will return a share mode flag from a STGM value.
5841 * The STGM value is assumed valid.
5843 static DWORD GetShareModeFromSTGM(DWORD stgm)
5845 DWORD dwShareMode = 0;
5846 BOOL bSTGM_SHARE_DENY_NONE =
5847 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5849 BOOL bSTGM_SHARE_DENY_READ =
5850 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5852 BOOL bSTGM_SHARE_DENY_WRITE =
5853 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5855 BOOL bSTGM_SHARE_EXCLUSIVE =
5856 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5858 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5861 if (bSTGM_SHARE_DENY_NONE)
5862 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5864 if (bSTGM_SHARE_DENY_WRITE)
5865 dwShareMode = FILE_SHARE_READ;
5870 /****************************************************************************
5871 * GetAccessModeFromSTGM
5873 * This method will return an access mode flag from a STGM value.
5874 * The STGM value is assumed valid.
5876 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5878 DWORD dwDesiredAccess = GENERIC_READ;
5879 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5880 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5881 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5884 dwDesiredAccess = GENERIC_READ;
5887 dwDesiredAccess |= GENERIC_WRITE;
5889 if (bSTGM_READWRITE)
5890 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5892 return dwDesiredAccess;
5895 /****************************************************************************
5896 * GetCreationModeFromSTGM
5898 * This method will return a creation mode flag from a STGM value.
5899 * The STGM value is assumed valid.
5901 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5903 if ( stgm & STGM_CREATE)
5904 return CREATE_ALWAYS;
5905 if (stgm & STGM_CONVERT) {
5906 FIXME("STGM_CONVERT not implemented!\n");
5909 /* All other cases */
5910 if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
5911 FIXME("unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
5916 /*************************************************************************
5917 * OLECONVERT_LoadOLE10 [Internal]
5919 * Loads the OLE10 STREAM to memory
5922 * pOleStream [I] The OLESTREAM
5923 * pData [I] Data Structure for the OLESTREAM Data
5927 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
5928 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
5931 * This function is used by OleConvertOLESTREAMToIStorage only.
5933 * Memory allocated for pData must be freed by the caller
5935 HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
5938 HRESULT hRes = S_OK;
5942 pData->pData = NULL;
5943 pData->pstrOleObjFileName = (CHAR *) NULL;
5945 for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
5948 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
5949 if(dwSize != sizeof(pData->dwOleID))
5951 hRes = CONVERT10_E_OLESTREAM_GET;
5953 else if(pData->dwOleID != OLESTREAM_ID)
5955 hRes = CONVERT10_E_OLESTREAM_FMT;
5966 /* Get the TypeID...more info needed for this field */
5967 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
5968 if(dwSize != sizeof(pData->dwTypeID))
5970 hRes = CONVERT10_E_OLESTREAM_GET;
5975 if(pData->dwTypeID != 0)
5977 /* Get the lenght of the OleTypeName */
5978 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
5979 if(dwSize != sizeof(pData->dwOleTypeNameLength))
5981 hRes = CONVERT10_E_OLESTREAM_GET;
5986 if(pData->dwOleTypeNameLength > 0)
5988 /* Get the OleTypeName */
5989 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
5990 if(dwSize != pData->dwOleTypeNameLength)
5992 hRes = CONVERT10_E_OLESTREAM_GET;
5998 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
5999 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6001 hRes = CONVERT10_E_OLESTREAM_GET;
6005 if(pData->dwOleObjFileNameLength < 1) //there is no file name exist
6006 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6007 pData->pstrOleObjFileName = (CHAR *)malloc(pData->dwOleObjFileNameLength);
6008 if(pData->pstrOleObjFileName)
6010 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6011 if(dwSize != pData->dwOleObjFileNameLength)
6013 hRes = CONVERT10_E_OLESTREAM_GET;
6017 hRes = CONVERT10_E_OLESTREAM_GET;
6022 /* Get the Width of the Metafile */
6023 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6024 if(dwSize != sizeof(pData->dwMetaFileWidth))
6026 hRes = CONVERT10_E_OLESTREAM_GET;
6030 /* Get the Height of the Metafile */
6031 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6032 if(dwSize != sizeof(pData->dwMetaFileHeight))
6034 hRes = CONVERT10_E_OLESTREAM_GET;
6040 /* Get the Lenght of the Data */
6041 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6042 if(dwSize != sizeof(pData->dwDataLength))
6044 hRes = CONVERT10_E_OLESTREAM_GET;
6048 if(hRes == S_OK) // I don't know what is this 8 byts information is we have to figure out
6050 if(!bStrem1) //if it is a second OLE stream data
6052 pData->dwDataLength -= 8;
6053 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6054 if(dwSize != sizeof(pData->strUnknown))
6056 hRes = CONVERT10_E_OLESTREAM_GET;
6062 if(pData->dwDataLength > 0)
6064 pData->pData = (BYTE *)HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6066 /* Get Data (ex. IStorage, Metafile, or BMP) */
6069 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6070 if(dwSize != pData->dwDataLength)
6072 hRes = CONVERT10_E_OLESTREAM_GET;
6077 hRes = CONVERT10_E_OLESTREAM_GET;
6086 /*************************************************************************
6087 * OLECONVERT_SaveOLE10 [Internal]
6089 * Saves the OLE10 STREAM From memory
6092 * pData [I] Data Structure for the OLESTREAM Data
6093 * pOleStream [I] The OLESTREAM to save
6097 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6100 * This function is used by OleConvertIStorageToOLESTREAM only.
6103 HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6106 HRESULT hRes = S_OK;
6110 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6111 if(dwSize != sizeof(pData->dwOleID))
6113 hRes = CONVERT10_E_OLESTREAM_PUT;
6118 /* Set the TypeID */
6119 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6120 if(dwSize != sizeof(pData->dwTypeID))
6122 hRes = CONVERT10_E_OLESTREAM_PUT;
6126 if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6128 /* Set the Lenght of the OleTypeName */
6129 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6130 if(dwSize != sizeof(pData->dwOleTypeNameLength))
6132 hRes = CONVERT10_E_OLESTREAM_PUT;
6137 if(pData->dwOleTypeNameLength > 0)
6139 /* Set the OleTypeName */
6140 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->strOleTypeName, pData->dwOleTypeNameLength);
6141 if(dwSize != pData->dwOleTypeNameLength)
6143 hRes = CONVERT10_E_OLESTREAM_PUT;
6150 /* Set the width of the Metafile */
6151 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6152 if(dwSize != sizeof(pData->dwMetaFileWidth))
6154 hRes = CONVERT10_E_OLESTREAM_PUT;
6160 /* Set the height of the Metafile */
6161 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6162 if(dwSize != sizeof(pData->dwMetaFileHeight))
6164 hRes = CONVERT10_E_OLESTREAM_PUT;
6170 /* Set the lenght of the Data */
6171 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6172 if(dwSize != sizeof(pData->dwDataLength))
6174 hRes = CONVERT10_E_OLESTREAM_PUT;
6180 if(pData->dwDataLength > 0)
6182 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6183 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->pData, pData->dwDataLength);
6184 if(dwSize != pData->dwDataLength)
6186 hRes = CONVERT10_E_OLESTREAM_PUT;
6194 /*************************************************************************
6195 * OLECONVERT_GetOLE20FromOLE10[Internal]
6197 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6198 * opens it, and copies the content to the dest IStorage for
6199 * OleConvertOLESTREAMToIStorage
6203 * pDestStorage [I] The IStorage to copy the data to
6204 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
6205 * nBufferLength [I] The size of the buffer
6214 void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6218 IStorage *pTempStorage;
6219 DWORD dwNumOfBytesWritten;
6220 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6221 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6223 /* Create a temp File */
6224 GetTempPathW(MAX_PATH, wstrTempDir);
6225 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6226 hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6228 if(hFile != INVALID_HANDLE_VALUE)
6230 /* Write IStorage Data to File */
6231 WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6234 /* Open and copy temp storage to the Dest Storage */
6235 hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6238 hRes = StorageImpl_CopyTo(pTempStorage, NULL,NULL,NULL, pDestStorage);
6239 StorageBaseImpl_Release(pTempStorage);
6241 DeleteFileW(wstrTempFile);
6246 /*************************************************************************
6247 * OLECONVERT_WriteOLE20ToBuffer [Internal]
6249 * Saves the OLE10 STREAM From memory
6252 * pStorage [I] The Src IStorage to copy
6253 * pData [I] The Dest Memory to write to.
6256 * The size in bytes allocated for pData
6259 * Memory allocated for pData must be freed by the caller
6261 * Used by OleConvertIStorageToOLESTREAM only.
6264 DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6268 DWORD nDataLength = 0;
6269 IStorage *pTempStorage;
6270 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6271 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6275 /* Create temp Storage */
6276 GetTempPathW(MAX_PATH, wstrTempDir);
6277 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6278 hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, &pTempStorage);
6282 /* Copy Src Storage to the Temp Storage */
6283 StorageImpl_CopyTo(pStorage, NULL,NULL,NULL, pTempStorage);
6284 StorageBaseImpl_Release(pTempStorage);
6286 /* Open Temp Storage as a file and copy to memory */
6287 hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6288 if(hFile != INVALID_HANDLE_VALUE)
6290 nDataLength = GetFileSize(hFile, NULL);
6291 *pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,nDataLength);
6292 ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6295 DeleteFileW(wstrTempFile);
6300 /*************************************************************************
6301 * OLECONVERT_CreateOleStream [Internal]
6303 * Creates the "\001OLE" stream in the IStorage if neccessary.
6306 * pStorage [I] Dest storage to create the stream in
6312 * This function is used by OleConvertOLESTREAMToIStorage only.
6314 * This stream is still unknown, MS Word seems to have extra data
6315 * but since the data is stored in the OLESTREAM there should be
6316 * no need to recreate the stream. If the stream is manually
6317 * deleted it will create it with this default data.
6320 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6324 WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6325 BYTE pOleStreamHeader [] =
6327 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6329 0x00, 0x00, 0x00, 0x00
6332 /* Create stream if not present */
6333 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6334 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6338 /* Write default Data */
6339 hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6340 IStream_Release(pStream);
6345 /*************************************************************************
6346 * OLECONVERT_CreateCompObjStream [Internal]
6348 * Creates a "\001CompObj" is the destination IStorage if necessary.
6351 * pStorage [I] The dest IStorage to create the CompObj Stream
6353 * strOleTypeName [I] The ProgID
6357 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6360 * This function is used by OleConvertOLESTREAMToIStorage only.
6362 * The stream data is stored in the OLESTREAM and there should be
6363 * no need to recreate the stream. If the stream is manually
6364 * deleted it will attempt to create it by querying the registry.
6368 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
6371 HRESULT hStorageRes, hRes = S_OK;
6372 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
6373 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6375 BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
6376 BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
6378 /* Initialize the CompObj structure */
6379 memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
6380 memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
6381 memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
6384 /* Create a CompObj stream if it doesn't exist */
6385 hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
6386 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6387 if(hStorageRes == S_OK)
6389 /* copy the OleTypeName to the compobj struct */
6390 IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
6391 strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
6393 /* copy the OleTypeName to the compobj struct */
6394 /* Note: in the test made, these where Identical */
6395 IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
6396 strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
6399 hRes = CLSIDFromProgID16(IStorageCompObj.strProgIDName, &(IStorageCompObj.clsid));
6403 hRes = REGDB_E_CLASSNOTREG;
6409 /* Get the CLSID Default Name from the Registry */
6410 hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
6411 if(hErr == ERROR_SUCCESS)
6413 char strTemp[OLESTREAM_MAX_STR_LEN];
6414 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
6415 hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
6416 if(hErr == ERROR_SUCCESS)
6418 strcpy(IStorageCompObj.strCLSIDName, strTemp);
6422 if(hErr != ERROR_SUCCESS)
6424 hRes = REGDB_E_CLASSNOTREG;
6430 /* Write CompObj Structure to stream */
6431 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
6432 hRes = IStream_Write(pStream, &(IStorageCompObj.clsid) , sizeof(IStorageCompObj.clsid ), NULL);
6433 hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
6434 if(IStorageCompObj.dwCLSIDNameLength > 0)
6436 hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
6438 hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
6439 if(IStorageCompObj.dwOleTypeNameLength > 0)
6441 hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
6443 hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
6444 if(IStorageCompObj.dwProgIDNameLength > 0)
6446 hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
6448 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
6450 IStream_Release(pStream);
6456 /*************************************************************************
6457 * OLECONVERT_CreateOlePresStream[Internal]
6459 * Creates the "\002OlePres000" Stream with the Metafile data
6462 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
6463 * dwExtentX [I] Width of the Metafile
6464 * dwExtentY [I] Height of the Metafile
6465 * pData [I] Metafile data
6466 * dwDataLength [I] Size of the Metafile data
6470 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6473 * This function is used by OleConvertOLESTREAMToIStorage only.
6476 void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
6480 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6481 BYTE pOlePresStreamHeader [] =
6483 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
6484 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6485 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6486 0x00, 0x00, 0x00, 0x00
6489 BYTE pOlePresStreamHeaderEmpty [] =
6491 0x00, 0x00, 0x00, 0x00,
6492 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6493 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6494 0x00, 0x00, 0x00, 0x00
6497 /* Create the OlePres000 Stream */
6498 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6499 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6504 OLECONVERT_ISTORAGE_OLEPRES OlePres;
6506 memset(&OlePres, 0, sizeof(OlePres));
6507 /* Do we have any metafile data to save */
6508 if(dwDataLength > 0)
6510 memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
6511 nHeaderSize = sizeof(pOlePresStreamHeader);
6515 memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
6516 nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
6518 /* Set width and height of the metafile */
6519 OlePres.dwExtentX = dwExtentX;
6520 OlePres.dwExtentY = -dwExtentY;
6522 /* Set Data and Lenght */
6523 if(dwDataLength > sizeof(METAFILEPICT16))
6525 OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
6526 OlePres.pData = &(pData[8]);
6528 /* Save OlePres000 Data to Stream */
6529 hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
6530 hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
6531 hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
6532 hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
6533 if(OlePres.dwSize > 0)
6535 hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
6537 IStream_Release(pStream);
6541 /*************************************************************************
6542 * OLECONVERT_CreateOle10NativeStream [Internal]
6544 * Creates the "\001Ole10Native" Stream (should contain a BMP)
6547 * pStorage [I] Dest storage to create the stream in
6548 * pData [I] Ole10 Native Data (ex. bmp)
6549 * dwDataLength [I] Size of the Ole10 Native Data
6555 * This function is used by OleConvertOLESTREAMToIStorage only.
6557 * Might need to verify the data and return appropriate error message
6560 void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
6564 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6566 /* Create the Ole10Native Stream */
6567 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6568 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6572 /* Write info to stream */
6573 hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
6574 hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
6575 IStream_Release(pStream);
6580 /*************************************************************************
6581 * OLECONVERT_GetOLE10ProgID [Internal]
6583 * Finds the ProgID (or OleTypeID) from the IStorage
6586 * pStorage [I] The Src IStorage to get the ProgID
6587 * strProgID [I] the ProgID string to get
6588 * dwSize [I] the size of the string
6592 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6595 * This function is used by OleConvertIStorageToOLESTREAM only.
6599 HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
6603 LARGE_INTEGER iSeekPos;
6604 OLECONVERT_ISTORAGE_COMPOBJ CompObj;
6605 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6607 /* Open the CompObj Stream */
6608 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6609 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6613 /*Get the OleType from the CompObj Stream */
6614 iSeekPos.s.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
6615 iSeekPos.s.HighPart = 0;
6617 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6618 IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
6619 iSeekPos.s.LowPart = CompObj.dwCLSIDNameLength;
6620 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6621 IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
6622 iSeekPos.s.LowPart = CompObj.dwOleTypeNameLength;
6623 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6625 IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
6628 IStream_Read(pStream, strProgID, *dwSize, NULL);
6630 IStream_Release(pStream);
6635 LPOLESTR wstrProgID;
6637 /* Get the OleType from the registry */
6638 REFCLSID clsid = &(stat.clsid);
6639 IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
6640 hRes = ProgIDFromCLSID(clsid, &wstrProgID);
6643 *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
6650 /*************************************************************************
6651 * OLECONVERT_GetOle10PresData [Internal]
6653 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
6656 * pStorage [I] Src IStroage
6657 * pOleStream [I] Dest OleStream Mem Struct
6663 * This function is used by OleConvertIStorageToOLESTREAM only.
6665 * Memory allocated for pData must be freed by the caller
6669 void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6674 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6676 /* Initialize Default data for OLESTREAM */
6677 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6678 pOleStreamData[0].dwTypeID = 2;
6679 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6680 pOleStreamData[1].dwTypeID = 0;
6681 pOleStreamData[0].dwMetaFileWidth = 0;
6682 pOleStreamData[0].dwMetaFileHeight = 0;
6683 pOleStreamData[0].pData = NULL;
6684 pOleStreamData[1].pData = NULL;
6686 /* Open Ole10Native Stream */
6687 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6688 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6692 /* Read Size and Data */
6693 IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
6694 if(pOleStreamData->dwDataLength > 0)
6696 pOleStreamData->pData = (LPSTR) HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
6697 IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
6699 IStream_Release(pStream);
6705 /*************************************************************************
6706 * OLECONVERT_GetOle20PresData[Internal]
6708 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
6711 * pStorage [I] Src IStroage
6712 * pOleStreamData [I] Dest OleStream Mem Struct
6718 * This function is used by OleConvertIStorageToOLESTREAM only.
6720 * Memory allocated for pData must be freed by the caller
6722 void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6726 OLECONVERT_ISTORAGE_OLEPRES olePress;
6727 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6729 /* Initialize Default data for OLESTREAM */
6730 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6731 pOleStreamData[0].dwTypeID = 2;
6732 pOleStreamData[0].dwMetaFileWidth = 0;
6733 pOleStreamData[0].dwMetaFileHeight = 0;
6734 pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
6735 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6736 pOleStreamData[1].dwTypeID = 0;
6737 pOleStreamData[1].dwOleTypeNameLength = 0;
6738 pOleStreamData[1].strOleTypeName[0] = 0;
6739 pOleStreamData[1].dwMetaFileWidth = 0;
6740 pOleStreamData[1].dwMetaFileHeight = 0;
6741 pOleStreamData[1].pData = NULL;
6742 pOleStreamData[1].dwDataLength = 0;
6745 /* Open OlePress000 stream */
6746 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6747 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6750 LARGE_INTEGER iSeekPos;
6751 METAFILEPICT16 MetaFilePict;
6752 char strMetafilePictName[] = "METAFILEPICT";
6754 /* Set the TypeID for a Metafile */
6755 pOleStreamData[1].dwTypeID = 5;
6757 /* Set the OleTypeName to Metafile */
6758 pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
6759 strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
6761 iSeekPos.s.HighPart = 0;
6762 iSeekPos.s.LowPart = sizeof(olePress.byUnknown1);
6764 /* Get Presentation Data */
6765 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6766 IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
6767 IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
6768 IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
6770 /*Set width and Height */
6771 pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
6772 pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
6773 if(olePress.dwSize > 0)
6776 pOleStreamData[1].dwDataLength = olePress.dwSize + sizeof(METAFILEPICT16);
6778 /* Set MetaFilePict struct */
6779 MetaFilePict.mm = 8;
6780 MetaFilePict.xExt = olePress.dwExtentX;
6781 MetaFilePict.yExt = olePress.dwExtentY;
6782 MetaFilePict.hMF = 0;
6784 /* Get Metafile Data */
6785 pOleStreamData[1].pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
6786 memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
6787 IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
6789 IStream_Release(pStream);
6793 /*************************************************************************
6794 * OleConvertOLESTREAMToIStorage [OLE32.87]
6799 * DVTARGETDEVICE paramenter is not handled
6800 * Still unsure of some mem fields for OLE 10 Stream
6801 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6802 * and "\001OLE" streams
6805 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
6806 LPOLESTREAM pOleStream,
6808 const DVTARGETDEVICE* ptd)
6812 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6814 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6818 FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
6821 if(pstg == NULL || pOleStream == NULL)
6823 hRes = E_INVALIDARG;
6828 /* Load the OLESTREAM to Memory */
6829 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
6834 /* Load the OLESTREAM to Memory (part 2)*/
6835 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
6841 if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
6843 /* Do we have the IStorage Data in the OLESTREAM */
6844 if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
6846 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6847 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
6851 /* It must be an original OLE 1.0 source */
6852 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6857 /* It must be an original OLE 1.0 source */
6858 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6861 /* Create CompObj Stream if necessary */
6862 hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
6865 /*Create the Ole Stream if necessary */
6866 OLECONVERT_CreateOleStream(pstg);
6871 /* Free allocated memory */
6872 for(i=0; i < 2; i++)
6874 if(pOleStreamData[i].pData != NULL)
6876 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
6878 if(pOleStreamData[i].pstrOleObjFileName != NULL)
6880 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
6881 pOleStreamData[i].pstrOleObjFileName = NULL;
6887 /*************************************************************************
6888 * OleConvertIStorageToOLESTREAM [OLE32.85]
6895 * Still unsure of some mem fields for OLE 10 Stream
6896 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6897 * and "\001OLE" streams.
6900 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
6902 LPOLESTREAM pOleStream)
6905 HRESULT hRes = S_OK;
6907 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6908 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6911 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6913 if(pstg == NULL || pOleStream == NULL)
6915 hRes = E_INVALIDARG;
6919 /* Get the ProgID */
6920 pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
6921 hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
6925 /*Was it originaly Ole10 */
6926 hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
6929 IStream_Release(pStream);
6930 /*Get Presentation Data for Ole10Native */
6931 OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
6935 /*Get Presentation Data (OLE20)*/
6936 OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
6939 /* Save OLESTREAM */
6940 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
6943 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
6948 /* Free allocated memory */
6949 for(i=0; i < 2; i++)
6951 if(pOleStreamData[i].pData != NULL)
6953 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);