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
18 #include "winbase.h" /* for lstrlenW() and the likes */
20 #include "debugtools.h"
22 #include "storage32.h"
23 #include "ole2.h" /* For Write/ReadClassStm */
26 #include "wine/wingdi16.h"
28 DEFAULT_DEBUG_CHANNEL(storage)
33 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
34 #define OLESTREAM_ID 0x501
35 #define OLESTREAM_MAX_STR_LEN 255
37 static const char rootPropertyName[] = "Root Entry";
40 /* OLESTREAM memory structure to use for Get and Put Routines */
41 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
46 DWORD dwOleTypeNameLength;
47 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
48 CHAR *pstrOleObjFileName;
49 DWORD dwOleObjFileNameLength;
50 DWORD dwMetaFileWidth;
51 DWORD dwMetaFileHeight;
52 CHAR strUnknown[8]; //don't know what is this 8 byts information in OLE stream.
55 }OLECONVERT_OLESTREAM_DATA;
57 /* CompObj Stream structure */
58 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
63 DWORD dwCLSIDNameLength;
64 CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
65 DWORD dwOleTypeNameLength;
66 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
67 DWORD dwProgIDNameLength;
68 CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
70 }OLECONVERT_ISTORAGE_COMPOBJ;
73 /* Ole Presention Stream structure */
74 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
82 }OLECONVERT_ISTORAGE_OLEPRES;
86 /***********************************************************************
87 * Forward declaration of internal functions used by the method DestroyElement
89 static HRESULT deleteStorageProperty(
90 StorageImpl *parentStorage,
91 ULONG foundPropertyIndexToDelete,
92 StgProperty propertyToDelete);
94 static HRESULT deleteStreamProperty(
95 StorageImpl *parentStorage,
96 ULONG foundPropertyIndexToDelete,
97 StgProperty propertyToDelete);
99 static HRESULT findPlaceholder(
100 StorageImpl *storage,
101 ULONG propertyIndexToStore,
102 ULONG storagePropertyIndex,
105 static HRESULT adjustPropertyChain(
107 StgProperty propertyToDelete,
108 StgProperty parentProperty,
109 ULONG parentPropertyId,
112 /***********************************************************************
113 * Declaration of the functions used to manipulate StgProperty
116 static ULONG getFreeProperty(
117 StorageImpl *storage);
119 static void updatePropertyChain(
120 StorageImpl *storage,
121 ULONG newPropertyIndex,
122 StgProperty newProperty);
124 static LONG propertyNameCmp(
125 OLECHAR *newProperty,
126 OLECHAR *currentProperty);
129 /***********************************************************************
130 * Declaration of miscellaneous functions...
132 static HRESULT validateSTGM(DWORD stgmValue);
134 static DWORD GetShareModeFromSTGM(DWORD stgm);
135 static DWORD GetAccessModeFromSTGM(DWORD stgm);
136 static DWORD GetCreationModeFromSTGM(DWORD stgm);
139 * Virtual function table for the IStorage32Impl class.
141 static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
143 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
144 StorageBaseImpl_QueryInterface,
145 StorageBaseImpl_AddRef,
146 StorageBaseImpl_Release,
147 StorageBaseImpl_CreateStream,
148 StorageBaseImpl_OpenStream,
149 StorageImpl_CreateStorage,
150 StorageBaseImpl_OpenStorage,
152 StorageImpl_MoveElementTo,
155 StorageBaseImpl_EnumElements,
156 StorageImpl_DestroyElement,
157 StorageBaseImpl_RenameElement,
158 StorageImpl_SetElementTimes,
159 StorageBaseImpl_SetClass,
160 StorageImpl_SetStateBits,
165 * Virtual function table for the Storage32InternalImpl class.
167 static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
169 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
170 StorageBaseImpl_QueryInterface,
171 StorageBaseImpl_AddRef,
172 StorageBaseImpl_Release,
173 StorageBaseImpl_CreateStream,
174 StorageBaseImpl_OpenStream,
175 StorageImpl_CreateStorage,
176 StorageBaseImpl_OpenStorage,
178 StorageImpl_MoveElementTo,
179 StorageInternalImpl_Commit,
180 StorageInternalImpl_Revert,
181 StorageBaseImpl_EnumElements,
182 StorageImpl_DestroyElement,
183 StorageBaseImpl_RenameElement,
184 StorageImpl_SetElementTimes,
185 StorageBaseImpl_SetClass,
186 StorageImpl_SetStateBits,
191 * Virtual function table for the IEnumSTATSTGImpl class.
193 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
195 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
196 IEnumSTATSTGImpl_QueryInterface,
197 IEnumSTATSTGImpl_AddRef,
198 IEnumSTATSTGImpl_Release,
199 IEnumSTATSTGImpl_Next,
200 IEnumSTATSTGImpl_Skip,
201 IEnumSTATSTGImpl_Reset,
202 IEnumSTATSTGImpl_Clone
209 /************************************************************************
210 ** Storage32BaseImpl implementatiion
213 /************************************************************************
214 * Storage32BaseImpl_QueryInterface (IUnknown)
216 * This method implements the common QueryInterface for all IStorage32
217 * implementations contained in this file.
219 * See Windows documentation for more details on IUnknown methods.
221 HRESULT WINAPI StorageBaseImpl_QueryInterface(
226 ICOM_THIS(StorageBaseImpl,iface);
228 * Perform a sanity check on the parameters.
230 if ( (This==0) || (ppvObject==0) )
234 * Initialize the return parameter.
239 * Compare the riid with the interface IDs implemented by this object.
241 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
243 *ppvObject = (IStorage*)This;
245 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
247 *ppvObject = (IStorage*)This;
251 * Check that we obtained an interface.
254 return E_NOINTERFACE;
257 * Query Interface always increases the reference count by one when it is
260 StorageBaseImpl_AddRef(iface);
265 /************************************************************************
266 * Storage32BaseImpl_AddRef (IUnknown)
268 * This method implements the common AddRef for all IStorage32
269 * implementations contained in this file.
271 * See Windows documentation for more details on IUnknown methods.
273 ULONG WINAPI StorageBaseImpl_AddRef(
276 ICOM_THIS(StorageBaseImpl,iface);
282 /************************************************************************
283 * Storage32BaseImpl_Release (IUnknown)
285 * This method implements the common Release for all IStorage32
286 * implementations contained in this file.
288 * See Windows documentation for more details on IUnknown methods.
290 ULONG WINAPI StorageBaseImpl_Release(
293 ICOM_THIS(StorageBaseImpl,iface);
295 * Decrease the reference count on this object.
300 * If the reference count goes down to 0, perform suicide.
305 * Since we are using a system of base-classes, we want to call the
306 * destructor of the appropriate derived class. To do this, we are
307 * using virtual functions to implement the destructor.
309 This->v_destructor(This);
317 /************************************************************************
318 * Storage32BaseImpl_OpenStream (IStorage)
320 * This method will open the specified stream object from the current storage.
322 * See Windows documentation for more details on IStorage methods.
324 HRESULT WINAPI StorageBaseImpl_OpenStream(
326 const OLECHAR* pwcsName, /* [string][in] */
327 void* reserved1, /* [unique][in] */
328 DWORD grfMode, /* [in] */
329 DWORD reserved2, /* [in] */
330 IStream** ppstm) /* [out] */
332 ICOM_THIS(StorageBaseImpl,iface);
333 IEnumSTATSTGImpl* propertyEnumeration;
334 StgStreamImpl* newStream;
335 StgProperty currentProperty;
336 ULONG foundPropertyIndex;
338 TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
339 iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
342 * Perform a sanity check on the parameters.
344 if ( (pwcsName==NULL) || (ppstm==0) )
348 * Initialize the out parameter
353 * Validate the STGM flags
355 if ( FAILED( validateSTGM(grfMode) ))
356 return STG_E_INVALIDFLAG;
361 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
362 (grfMode & STGM_DELETEONRELEASE) ||
363 (grfMode & STGM_TRANSACTED) )
364 return STG_E_INVALIDFUNCTION;
367 * Create a property enumeration to search the properties
369 propertyEnumeration = IEnumSTATSTGImpl_Construct(
370 This->ancestorStorage,
371 This->rootPropertySetIndex);
374 * Search the enumeration for the property with the given name
376 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
382 * Delete the property enumeration since we don't need it anymore
384 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
387 * If it was found, construct the stream object and return a pointer to it.
389 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
390 (currentProperty.propertyType==PROPTYPE_STREAM) )
392 newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
396 newStream->grfMode = grfMode;
397 *ppstm = (IStream*)newStream;
400 * Since we are returning a pointer to the interface, we have to
401 * nail down the reference.
403 StgStreamImpl_AddRef(*ppstm);
408 return E_OUTOFMEMORY;
411 return STG_E_FILENOTFOUND;
414 /************************************************************************
415 * Storage32BaseImpl_OpenStorage (IStorage)
417 * This method will open a new storage object from the current storage.
419 * See Windows documentation for more details on IStorage methods.
421 HRESULT WINAPI StorageBaseImpl_OpenStorage(
423 const OLECHAR* pwcsName, /* [string][unique][in] */
424 IStorage* pstgPriority, /* [unique][in] */
425 DWORD grfMode, /* [in] */
426 SNB snbExclude, /* [unique][in] */
427 DWORD reserved, /* [in] */
428 IStorage** ppstg) /* [out] */
430 ICOM_THIS(StorageBaseImpl,iface);
431 StorageInternalImpl* newStorage;
432 IEnumSTATSTGImpl* propertyEnumeration;
433 StgProperty currentProperty;
434 ULONG foundPropertyIndex;
436 TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
437 iface, debugstr_w(pwcsName), pstgPriority,
438 grfMode, snbExclude, reserved, ppstg);
441 * Perform a sanity check on the parameters.
443 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
447 * Validate the STGM flags
449 if ( FAILED( validateSTGM(grfMode) ))
450 return STG_E_INVALIDFLAG;
455 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
456 (grfMode & STGM_DELETEONRELEASE) ||
457 (grfMode & STGM_PRIORITY) )
458 return STG_E_INVALIDFUNCTION;
461 * Initialize the out parameter
466 * Create a property enumeration to search the properties
468 propertyEnumeration = IEnumSTATSTGImpl_Construct(
469 This->ancestorStorage,
470 This->rootPropertySetIndex);
473 * Search the enumeration for the property with the given name
475 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
481 * Delete the property enumeration since we don't need it anymore
483 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
486 * If it was found, construct the stream object and return a pointer to it.
488 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
489 (currentProperty.propertyType==PROPTYPE_STORAGE) )
492 * Construct a new Storage object
494 newStorage = StorageInternalImpl_Construct(
495 This->ancestorStorage,
500 *ppstg = (IStorage*)newStorage;
503 * Since we are returning a pointer to the interface,
504 * we have to nail down the reference.
506 StorageBaseImpl_AddRef(*ppstg);
511 return STG_E_INSUFFICIENTMEMORY;
514 return STG_E_FILENOTFOUND;
517 /************************************************************************
518 * Storage32BaseImpl_EnumElements (IStorage)
520 * This method will create an enumerator object that can be used to
521 * retrieve informatino about all the properties in the storage object.
523 * See Windows documentation for more details on IStorage methods.
525 HRESULT WINAPI StorageBaseImpl_EnumElements(
527 DWORD reserved1, /* [in] */
528 void* reserved2, /* [size_is][unique][in] */
529 DWORD reserved3, /* [in] */
530 IEnumSTATSTG** ppenum) /* [out] */
532 ICOM_THIS(StorageBaseImpl,iface);
533 IEnumSTATSTGImpl* newEnum;
535 TRACE("(%p, %ld, %p, %ld, %p)\n",
536 iface, reserved1, reserved2, reserved3, ppenum);
539 * Perform a sanity check on the parameters.
541 if ( (This==0) || (ppenum==0))
545 * Construct the enumerator.
547 newEnum = IEnumSTATSTGImpl_Construct(
548 This->ancestorStorage,
549 This->rootPropertySetIndex);
553 *ppenum = (IEnumSTATSTG*)newEnum;
556 * Don't forget to nail down a reference to the new object before
559 IEnumSTATSTGImpl_AddRef(*ppenum);
564 return E_OUTOFMEMORY;
567 /************************************************************************
568 * Storage32BaseImpl_Stat (IStorage)
570 * This method will retrieve information about this storage object.
572 * See Windows documentation for more details on IStorage methods.
574 HRESULT WINAPI StorageBaseImpl_Stat(
576 STATSTG* pstatstg, /* [out] */
577 DWORD grfStatFlag) /* [in] */
579 ICOM_THIS(StorageBaseImpl,iface);
580 StgProperty curProperty;
583 TRACE("(%p, %p, %lx)\n",
584 iface, pstatstg, grfStatFlag);
587 * Perform a sanity check on the parameters.
589 if ( (This==0) || (pstatstg==0))
593 * Read the information from the property.
595 readSuccessful = StorageImpl_ReadProperty(
596 This->ancestorStorage,
597 This->rootPropertySetIndex,
602 StorageUtl_CopyPropertyToSTATSTG(
613 /************************************************************************
614 * Storage32BaseImpl_RenameElement (IStorage)
616 * This method will rename the specified element.
618 * See Windows documentation for more details on IStorage methods.
620 * Implementation notes: The method used to rename consists of creating a clone
621 * of the deleted StgProperty object setting it with the new name and to
622 * perform a DestroyElement of the old StgProperty.
624 HRESULT WINAPI StorageBaseImpl_RenameElement(
626 const OLECHAR* pwcsOldName, /* [in] */
627 const OLECHAR* pwcsNewName) /* [in] */
629 ICOM_THIS(StorageBaseImpl,iface);
630 IEnumSTATSTGImpl* propertyEnumeration;
631 StgProperty currentProperty;
632 ULONG foundPropertyIndex;
634 TRACE("(%p, %s, %s)\n",
635 iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
638 * Create a property enumeration to search the properties
640 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
641 This->rootPropertySetIndex);
644 * Search the enumeration for the new property name
646 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
650 if (foundPropertyIndex != PROPERTY_NULL)
653 * There is already a property with the new name
655 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
656 return STG_E_FILEALREADYEXISTS;
659 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
662 * Search the enumeration for the old property name
664 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
669 * Delete the property enumeration since we don't need it anymore
671 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
673 if (foundPropertyIndex != PROPERTY_NULL)
675 StgProperty renamedProperty;
676 ULONG renamedPropertyIndex;
679 * Setup a new property for the renamed property
681 renamedProperty.sizeOfNameString =
682 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
684 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
685 return STG_E_INVALIDNAME;
687 lstrcpyW(renamedProperty.name, pwcsNewName);
689 renamedProperty.propertyType = currentProperty.propertyType;
690 renamedProperty.startingBlock = currentProperty.startingBlock;
691 renamedProperty.size.s.LowPart = currentProperty.size.s.LowPart;
692 renamedProperty.size.s.HighPart = currentProperty.size.s.HighPart;
694 renamedProperty.previousProperty = PROPERTY_NULL;
695 renamedProperty.nextProperty = PROPERTY_NULL;
698 * Bring the dirProperty link in case it is a storage and in which
699 * case the renamed storage elements don't require to be reorganized.
701 renamedProperty.dirProperty = currentProperty.dirProperty;
703 /* call CoFileTime to get the current time
704 renamedProperty.timeStampS1
705 renamedProperty.timeStampD1
706 renamedProperty.timeStampS2
707 renamedProperty.timeStampD2
708 renamedProperty.propertyUniqueID
712 * Obtain a free property in the property chain
714 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
717 * Save the new property into the new property spot
719 StorageImpl_WriteProperty(
720 This->ancestorStorage,
721 renamedPropertyIndex,
725 * Find a spot in the property chain for our newly created property.
729 renamedPropertyIndex,
733 * At this point the renamed property has been inserted in the tree,
734 * now, before to Destroy the old property we must zeroed it's dirProperty
735 * otherwise the DestroyProperty below will zap it all and we do not want
737 * Also, we fake that the old property is a storage so the DestroyProperty
738 * will not do a SetSize(0) on the stream data.
740 * This means that we need to tweek the StgProperty if it is a stream or a
743 StorageImpl_ReadProperty(This->ancestorStorage,
747 currentProperty.dirProperty = PROPERTY_NULL;
748 currentProperty.propertyType = PROPTYPE_STORAGE;
749 StorageImpl_WriteProperty(
750 This->ancestorStorage,
755 * Invoke Destroy to get rid of the ole property and automatically redo
756 * the linking of it's previous and next members...
758 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
764 * There is no property with the old name
766 return STG_E_FILENOTFOUND;
772 /************************************************************************
773 * Storage32BaseImpl_CreateStream (IStorage)
775 * This method will create a stream object within this storage
777 * See Windows documentation for more details on IStorage methods.
779 HRESULT WINAPI StorageBaseImpl_CreateStream(
781 const OLECHAR* pwcsName, /* [string][in] */
782 DWORD grfMode, /* [in] */
783 DWORD reserved1, /* [in] */
784 DWORD reserved2, /* [in] */
785 IStream** ppstm) /* [out] */
787 ICOM_THIS(StorageBaseImpl,iface);
788 IEnumSTATSTGImpl* propertyEnumeration;
789 StgStreamImpl* newStream;
790 StgProperty currentProperty, newStreamProperty;
791 ULONG foundPropertyIndex, newPropertyIndex;
793 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
794 iface, debugstr_w(pwcsName), grfMode,
795 reserved1, reserved2, ppstm);
798 * Validate parameters
801 return STG_E_INVALIDPOINTER;
804 return STG_E_INVALIDNAME;
807 * Validate the STGM flags
809 if ( FAILED( validateSTGM(grfMode) ))
810 return STG_E_INVALIDFLAG;
815 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
816 (grfMode & STGM_DELETEONRELEASE) ||
817 (grfMode & STGM_TRANSACTED) )
818 return STG_E_INVALIDFUNCTION;
821 * Initialize the out parameter
826 * Create a property enumeration to search the properties
828 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
829 This->rootPropertySetIndex);
831 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
835 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
837 if (foundPropertyIndex != PROPERTY_NULL)
840 * An element with this name already exists
842 if (grfMode & STGM_CREATE)
844 IStorage_DestroyElement(iface, pwcsName);
847 return STG_E_FILEALREADYEXISTS;
851 * memset the empty property
853 memset(&newStreamProperty, 0, sizeof(StgProperty));
855 newStreamProperty.sizeOfNameString =
856 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
858 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
859 return STG_E_INVALIDNAME;
861 lstrcpyW(newStreamProperty.name, pwcsName);
863 newStreamProperty.propertyType = PROPTYPE_STREAM;
864 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
865 newStreamProperty.size.s.LowPart = 0;
866 newStreamProperty.size.s.HighPart = 0;
868 newStreamProperty.previousProperty = PROPERTY_NULL;
869 newStreamProperty.nextProperty = PROPERTY_NULL;
870 newStreamProperty.dirProperty = PROPERTY_NULL;
872 /* call CoFileTime to get the current time
873 newStreamProperty.timeStampS1
874 newStreamProperty.timeStampD1
875 newStreamProperty.timeStampS2
876 newStreamProperty.timeStampD2
879 /* newStreamProperty.propertyUniqueID */
882 * Get a free property or create a new one
884 newPropertyIndex = getFreeProperty(This->ancestorStorage);
887 * Save the new property into the new property spot
889 StorageImpl_WriteProperty(
890 This->ancestorStorage,
895 * Find a spot in the property chain for our newly created property.
903 * Open the stream to return it.
905 newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
909 *ppstm = (IStream*)newStream;
912 * Since we are returning a pointer to the interface, we have to nail down
915 StgStreamImpl_AddRef(*ppstm);
919 return STG_E_INSUFFICIENTMEMORY;
925 /************************************************************************
926 * Storage32BaseImpl_SetClass (IStorage)
928 * This method will write the specified CLSID in the property of this
931 * See Windows documentation for more details on IStorage methods.
933 HRESULT WINAPI StorageBaseImpl_SetClass(
935 REFCLSID clsid) /* [in] */
937 ICOM_THIS(StorageBaseImpl,iface);
938 HRESULT hRes = E_FAIL;
939 StgProperty curProperty;
942 TRACE("(%p, %p)\n", iface, clsid);
944 success = StorageImpl_ReadProperty(This->ancestorStorage,
945 This->rootPropertySetIndex,
949 curProperty.propertyUniqueID = *clsid;
951 success = StorageImpl_WriteProperty(This->ancestorStorage,
952 This->rootPropertySetIndex,
961 /************************************************************************
962 ** Storage32Impl implementation
965 /************************************************************************
966 * Storage32Impl_CreateStorage (IStorage)
968 * This method will create the storage object within the provided storage.
970 * See Windows documentation for more details on IStorage methods.
972 HRESULT WINAPI StorageImpl_CreateStorage(
974 const OLECHAR *pwcsName, /* [string][in] */
975 DWORD grfMode, /* [in] */
976 DWORD reserved1, /* [in] */
977 DWORD reserved2, /* [in] */
978 IStorage **ppstg) /* [out] */
980 StorageImpl* const This=(StorageImpl*)iface;
982 IEnumSTATSTGImpl *propertyEnumeration;
983 StgProperty currentProperty;
984 StgProperty newProperty;
985 ULONG foundPropertyIndex;
986 ULONG newPropertyIndex;
989 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
990 iface, debugstr_w(pwcsName), grfMode,
991 reserved1, reserved2, ppstg);
994 * Validate parameters
997 return STG_E_INVALIDPOINTER;
1000 return STG_E_INVALIDNAME;
1003 * Validate the STGM flags
1005 if ( FAILED( validateSTGM(grfMode) ) ||
1006 (grfMode & STGM_DELETEONRELEASE) )
1007 return STG_E_INVALIDFLAG;
1010 * Initialize the out parameter
1015 * Create a property enumeration and search the properties
1017 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
1018 This->rootPropertySetIndex);
1020 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1023 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1025 if (foundPropertyIndex != PROPERTY_NULL)
1028 * An element with this name already exists
1030 if (grfMode & STGM_CREATE)
1031 IStorage_DestroyElement(iface, pwcsName);
1033 return STG_E_FILEALREADYEXISTS;
1037 * memset the empty property
1039 memset(&newProperty, 0, sizeof(StgProperty));
1041 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1043 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1044 return STG_E_INVALIDNAME;
1046 lstrcpyW(newProperty.name, pwcsName);
1048 newProperty.propertyType = PROPTYPE_STORAGE;
1049 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
1050 newProperty.size.s.LowPart = 0;
1051 newProperty.size.s.HighPart = 0;
1053 newProperty.previousProperty = PROPERTY_NULL;
1054 newProperty.nextProperty = PROPERTY_NULL;
1055 newProperty.dirProperty = PROPERTY_NULL;
1057 /* call CoFileTime to get the current time
1058 newProperty.timeStampS1
1059 newProperty.timeStampD1
1060 newProperty.timeStampS2
1061 newProperty.timeStampD2
1064 /* newStorageProperty.propertyUniqueID */
1067 * Obtain a free property in the property chain
1069 newPropertyIndex = getFreeProperty(This->ancestorStorage);
1072 * Save the new property into the new property spot
1074 StorageImpl_WriteProperty(
1075 This->ancestorStorage,
1080 * Find a spot in the property chain for our newly created property.
1082 updatePropertyChain(
1088 * Open it to get a pointer to return.
1090 hr = IStorage_OpenStorage(
1099 if( (hr != S_OK) || (*ppstg == NULL))
1109 /***************************************************************************
1113 * Get a free property or create a new one.
1115 static ULONG getFreeProperty(
1116 StorageImpl *storage)
1118 ULONG currentPropertyIndex = 0;
1119 ULONG newPropertyIndex = PROPERTY_NULL;
1120 BOOL readSuccessful = TRUE;
1121 StgProperty currentProperty;
1126 * Start by reading the root property
1128 readSuccessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1129 currentPropertyIndex,
1133 if (currentProperty.sizeOfNameString == 0)
1136 * The property existis and is available, we found it.
1138 newPropertyIndex = currentPropertyIndex;
1144 * We exhausted the property list, we will create more space below
1146 newPropertyIndex = currentPropertyIndex;
1148 currentPropertyIndex++;
1150 } while (newPropertyIndex == PROPERTY_NULL);
1153 * grow the property chain
1155 if (! readSuccessful)
1157 StgProperty emptyProperty;
1158 ULARGE_INTEGER newSize;
1159 ULONG propertyIndex;
1160 ULONG lastProperty = 0;
1161 ULONG blockCount = 0;
1164 * obtain the new count of property blocks
1166 blockCount = BlockChainStream_GetCount(
1167 storage->ancestorStorage->rootBlockChain)+1;
1170 * initialize the size used by the property stream
1172 newSize.s.HighPart = 0;
1173 newSize.s.LowPart = storage->bigBlockSize * blockCount;
1176 * add a property block to the property chain
1178 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1181 * memset the empty property in order to initialize the unused newly
1184 memset(&emptyProperty, 0, sizeof(StgProperty));
1189 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1192 propertyIndex = newPropertyIndex;
1193 propertyIndex < lastProperty;
1196 StorageImpl_WriteProperty(
1197 storage->ancestorStorage,
1203 return newPropertyIndex;
1206 /****************************************************************************
1210 * Case insensitive comparaison of StgProperty.name by first considering
1213 * Returns <0 when newPrpoerty < currentProperty
1214 * >0 when newPrpoerty > currentProperty
1215 * 0 when newPrpoerty == currentProperty
1217 static LONG propertyNameCmp(
1218 OLECHAR *newProperty,
1219 OLECHAR *currentProperty)
1221 LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty);
1226 * We compare the string themselves only when they are of the same lenght
1228 diff = lstrcmpiW( newProperty, currentProperty);
1234 /****************************************************************************
1238 * Properly link this new element in the property chain.
1240 static void updatePropertyChain(
1241 StorageImpl *storage,
1242 ULONG newPropertyIndex,
1243 StgProperty newProperty)
1245 StgProperty currentProperty;
1248 * Read the root property
1250 StorageImpl_ReadProperty(storage->ancestorStorage,
1251 storage->rootPropertySetIndex,
1254 if (currentProperty.dirProperty != PROPERTY_NULL)
1257 * The root storage contains some element, therefore, start the research
1258 * for the appropriate location.
1261 ULONG current, next, previous, currentPropertyId;
1264 * Keep the StgProperty sequence number of the storage first property
1266 currentPropertyId = currentProperty.dirProperty;
1271 StorageImpl_ReadProperty(storage->ancestorStorage,
1272 currentProperty.dirProperty,
1275 previous = currentProperty.previousProperty;
1276 next = currentProperty.nextProperty;
1277 current = currentPropertyId;
1281 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1285 if (previous != PROPERTY_NULL)
1287 StorageImpl_ReadProperty(storage->ancestorStorage,
1294 currentProperty.previousProperty = newPropertyIndex;
1295 StorageImpl_WriteProperty(storage->ancestorStorage,
1303 if (next != PROPERTY_NULL)
1305 StorageImpl_ReadProperty(storage->ancestorStorage,
1312 currentProperty.nextProperty = newPropertyIndex;
1313 StorageImpl_WriteProperty(storage->ancestorStorage,
1322 * Trying to insert an item with the same name in the
1323 * subtree structure.
1328 previous = currentProperty.previousProperty;
1329 next = currentProperty.nextProperty;
1335 * The root storage is empty, link the new property to it's dir property
1337 currentProperty.dirProperty = newPropertyIndex;
1338 StorageImpl_WriteProperty(storage->ancestorStorage,
1339 storage->rootPropertySetIndex,
1345 /*************************************************************************
1348 HRESULT WINAPI StorageImpl_CopyTo(
1350 DWORD ciidExclude, /* [in] */
1351 const IID* rgiidExclude, /* [size_is][unique][in] */
1352 SNB snbExclude, /* [unique][in] */
1353 IStorage* pstgDest) /* [unique][in] */
1355 IEnumSTATSTG *elements = 0;
1356 STATSTG curElement, strStat;
1358 IStorage *pstgTmp, *pstgChild;
1359 IStream *pstrTmp, *pstrChild;
1361 if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
1362 FIXME("Exclude option not implemented\n");
1364 TRACE("(%p, %ld, %p, %p, %p)\n",
1365 iface, ciidExclude, rgiidExclude,
1366 snbExclude, pstgDest);
1369 * Perform a sanity check
1371 if ( pstgDest == 0 )
1372 return STG_E_INVALIDPOINTER;
1375 * Enumerate the elements
1377 hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1385 IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1386 IStorage_SetClass( pstgDest, &curElement.clsid );
1391 * Obtain the next element
1393 hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1395 if ( hr == S_FALSE )
1397 hr = S_OK; /* done, every element has been copied */
1401 if (curElement.type == STGTY_STORAGE)
1404 * open child source storage
1406 hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1407 STGM_READ|STGM_SHARE_EXCLUSIVE,
1408 NULL, 0, &pstgChild );
1414 * Check if destination storage is not a child of the source
1415 * storage, which will cause an infinite loop
1417 if (pstgChild == pstgDest)
1419 IEnumSTATSTG_Release(elements);
1421 return STG_E_ACCESSDENIED;
1425 * create a new storage in destination storage
1427 hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1428 STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1432 * if it already exist, don't create a new one use this one
1434 if (hr == STG_E_FILEALREADYEXISTS)
1436 hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1437 STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1438 NULL, 0, &pstgTmp );
1446 * do the copy recursively
1448 hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1449 snbExclude, pstgTmp );
1451 IStorage_Release( pstgTmp );
1452 IStorage_Release( pstgChild );
1454 else if (curElement.type == STGTY_STREAM)
1457 * create a new stream in destination storage. If the stream already
1458 * exist, it will be deleted and a new one will be created.
1460 hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1461 STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1468 * open child stream storage
1470 hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
1471 STGM_READ|STGM_SHARE_EXCLUSIVE,
1478 * Get the size of the source stream
1480 IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1483 * Set the size of the destination stream.
1485 IStream_SetSize(pstrTmp, strStat.cbSize);
1490 hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1493 IStream_Release( pstrTmp );
1494 IStream_Release( pstrChild );
1498 WARN("unknown element type: %ld\n", curElement.type);
1501 } while (hr == S_OK);
1506 IEnumSTATSTG_Release(elements);
1511 /*************************************************************************
1512 * MoveElementTo (IStorage)
1514 HRESULT WINAPI StorageImpl_MoveElementTo(
1516 const OLECHAR *pwcsName, /* [string][in] */
1517 IStorage *pstgDest, /* [unique][in] */
1518 const OLECHAR *pwcsNewName,/* [string][in] */
1519 DWORD grfFlags) /* [in] */
1521 FIXME("not implemented!\n");
1525 /*************************************************************************
1528 HRESULT WINAPI StorageImpl_Commit(
1530 DWORD grfCommitFlags)/* [in] */
1532 FIXME("(%ld): stub!\n", grfCommitFlags);
1536 /*************************************************************************
1539 HRESULT WINAPI StorageImpl_Revert(
1542 FIXME("not implemented!\n");
1546 /*************************************************************************
1547 * DestroyElement (IStorage)
1549 * Stategy: This implementation is build this way for simplicity not for speed.
1550 * I always delete the top most element of the enumeration and adjust
1551 * the deleted element pointer all the time. This takes longer to
1552 * do but allow to reinvoke DestroyElement whenever we encounter a
1553 * storage object. The optimisation reside in the usage of another
1554 * enumeration stategy that would give all the leaves of a storage
1555 * first. (postfix order)
1557 HRESULT WINAPI StorageImpl_DestroyElement(
1559 const OLECHAR *pwcsName)/* [string][in] */
1561 StorageImpl* const This=(StorageImpl*)iface;
1563 IEnumSTATSTGImpl* propertyEnumeration;
1566 StgProperty propertyToDelete;
1567 StgProperty parentProperty;
1568 ULONG foundPropertyIndexToDelete;
1569 ULONG typeOfRelation;
1570 ULONG parentPropertyId;
1573 iface, debugstr_w(pwcsName));
1576 * Perform a sanity check on the parameters.
1579 return STG_E_INVALIDPOINTER;
1582 * Create a property enumeration to search the property with the given name
1584 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1585 This->ancestorStorage,
1586 This->rootPropertySetIndex);
1588 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1589 propertyEnumeration,
1593 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1595 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1597 return STG_E_FILENOTFOUND;
1601 * Find the parent property of the property to delete (the one that
1602 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1603 * the parent is This. Otherwise, the parent is one of it's sibling...
1607 * First, read This's StgProperty..
1609 res = StorageImpl_ReadProperty(
1610 This->ancestorStorage,
1611 This->rootPropertySetIndex,
1617 * Second, check to see if by any chance the actual storage (This) is not
1618 * the parent of the property to delete... We never know...
1620 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1623 * Set data as it would have been done in the else part...
1625 typeOfRelation = PROPERTY_RELATION_DIR;
1626 parentPropertyId = This->rootPropertySetIndex;
1631 * Create a property enumeration to search the parent properties, and
1632 * delete it once done.
1634 IEnumSTATSTGImpl* propertyEnumeration2;
1636 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1637 This->ancestorStorage,
1638 This->rootPropertySetIndex);
1640 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1641 propertyEnumeration2,
1642 foundPropertyIndexToDelete,
1646 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1649 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1651 hr = deleteStorageProperty(
1653 foundPropertyIndexToDelete,
1656 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1658 hr = deleteStreamProperty(
1660 foundPropertyIndexToDelete,
1668 * Adjust the property chain
1670 hr = adjustPropertyChain(
1681 /*********************************************************************
1685 * Perform the deletion of a complete storage node
1688 static HRESULT deleteStorageProperty(
1689 StorageImpl *parentStorage,
1690 ULONG indexOfPropertyToDelete,
1691 StgProperty propertyToDelete)
1693 IEnumSTATSTG *elements = 0;
1694 IStorage *childStorage = 0;
1695 STATSTG currentElement;
1697 HRESULT destroyHr = S_OK;
1700 * Open the storage and enumerate it
1702 hr = StorageBaseImpl_OpenStorage(
1703 (IStorage*)parentStorage,
1704 propertyToDelete.name,
1706 STGM_SHARE_EXCLUSIVE,
1717 * Enumerate the elements
1719 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1724 * Obtain the next element
1726 hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL);
1729 destroyHr = StorageImpl_DestroyElement(
1730 (IStorage*)childStorage,
1731 (OLECHAR*)currentElement.pwcsName);
1733 CoTaskMemFree(currentElement.pwcsName);
1737 * We need to Reset the enumeration every time because we delete elements
1738 * and the enumeration could be invalid
1740 IEnumSTATSTG_Reset(elements);
1742 } while ((hr == S_OK) && (destroyHr == S_OK));
1745 * Invalidate the property by zeroing it's name member.
1747 propertyToDelete.sizeOfNameString = 0;
1749 StorageImpl_WriteProperty(parentStorage->ancestorStorage,
1750 indexOfPropertyToDelete,
1753 IStorage_Release(childStorage);
1754 IEnumSTATSTG_Release(elements);
1759 /*********************************************************************
1763 * Perform the deletion of a stream node
1766 static HRESULT deleteStreamProperty(
1767 StorageImpl *parentStorage,
1768 ULONG indexOfPropertyToDelete,
1769 StgProperty propertyToDelete)
1773 ULARGE_INTEGER size;
1775 size.s.HighPart = 0;
1778 hr = StorageBaseImpl_OpenStream(
1779 (IStorage*)parentStorage,
1780 (OLECHAR*)propertyToDelete.name,
1782 STGM_WRITE | STGM_SHARE_EXCLUSIVE,
1794 hr = IStream_SetSize(pis, size);
1802 * Release the stream object.
1804 IStream_Release(pis);
1807 * Invalidate the property by zeroing it's name member.
1809 propertyToDelete.sizeOfNameString = 0;
1812 * Here we should re-read the property so we get the updated pointer
1813 * but since we are here to zap it, I don't do it...
1815 StorageImpl_WriteProperty(
1816 parentStorage->ancestorStorage,
1817 indexOfPropertyToDelete,
1823 /*********************************************************************
1827 * Finds a placeholder for the StgProperty within the Storage
1830 static HRESULT findPlaceholder(
1831 StorageImpl *storage,
1832 ULONG propertyIndexToStore,
1833 ULONG storePropertyIndex,
1836 StgProperty storeProperty;
1841 * Read the storage property
1843 res = StorageImpl_ReadProperty(
1844 storage->ancestorStorage,
1853 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1855 if (storeProperty.previousProperty != PROPERTY_NULL)
1857 return findPlaceholder(
1859 propertyIndexToStore,
1860 storeProperty.previousProperty,
1865 storeProperty.previousProperty = propertyIndexToStore;
1868 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1870 if (storeProperty.nextProperty != PROPERTY_NULL)
1872 return findPlaceholder(
1874 propertyIndexToStore,
1875 storeProperty.nextProperty,
1880 storeProperty.nextProperty = propertyIndexToStore;
1883 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1885 if (storeProperty.dirProperty != PROPERTY_NULL)
1887 return findPlaceholder(
1889 propertyIndexToStore,
1890 storeProperty.dirProperty,
1895 storeProperty.dirProperty = propertyIndexToStore;
1899 hr = StorageImpl_WriteProperty(
1900 storage->ancestorStorage,
1912 /*************************************************************************
1916 * This method takes the previous and the next property link of a property
1917 * to be deleted and find them a place in the Storage.
1919 static HRESULT adjustPropertyChain(
1921 StgProperty propertyToDelete,
1922 StgProperty parentProperty,
1923 ULONG parentPropertyId,
1926 ULONG newLinkProperty = PROPERTY_NULL;
1927 BOOL needToFindAPlaceholder = FALSE;
1928 ULONG storeNode = PROPERTY_NULL;
1929 ULONG toStoreNode = PROPERTY_NULL;
1930 INT relationType = 0;
1934 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1936 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1939 * Set the parent previous to the property to delete previous
1941 newLinkProperty = propertyToDelete.previousProperty;
1943 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1946 * We also need to find a storage for the other link, setup variables
1947 * to do this at the end...
1949 needToFindAPlaceholder = TRUE;
1950 storeNode = propertyToDelete.previousProperty;
1951 toStoreNode = propertyToDelete.nextProperty;
1952 relationType = PROPERTY_RELATION_NEXT;
1955 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1958 * Set the parent previous to the property to delete next
1960 newLinkProperty = propertyToDelete.nextProperty;
1964 * Link it for real...
1966 parentProperty.previousProperty = newLinkProperty;
1969 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1971 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1974 * Set the parent next to the property to delete next previous
1976 newLinkProperty = propertyToDelete.previousProperty;
1978 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1981 * We also need to find a storage for the other link, setup variables
1982 * to do this at the end...
1984 needToFindAPlaceholder = TRUE;
1985 storeNode = propertyToDelete.previousProperty;
1986 toStoreNode = propertyToDelete.nextProperty;
1987 relationType = PROPERTY_RELATION_NEXT;
1990 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1993 * Set the parent next to the property to delete next
1995 newLinkProperty = propertyToDelete.nextProperty;
1999 * Link it for real...
2001 parentProperty.nextProperty = newLinkProperty;
2003 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2005 if (propertyToDelete.previousProperty != PROPERTY_NULL)
2008 * Set the parent dir to the property to delete previous
2010 newLinkProperty = propertyToDelete.previousProperty;
2012 if (propertyToDelete.nextProperty != PROPERTY_NULL)
2015 * We also need to find a storage for the other link, setup variables
2016 * to do this at the end...
2018 needToFindAPlaceholder = TRUE;
2019 storeNode = propertyToDelete.previousProperty;
2020 toStoreNode = propertyToDelete.nextProperty;
2021 relationType = PROPERTY_RELATION_NEXT;
2024 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2027 * Set the parent dir to the property to delete next
2029 newLinkProperty = propertyToDelete.nextProperty;
2033 * Link it for real...
2035 parentProperty.dirProperty = newLinkProperty;
2039 * Write back the parent property
2041 res = StorageImpl_WriteProperty(
2042 This->ancestorStorage,
2051 * If a placeholder is required for the other link, then, find one and
2052 * get out of here...
2054 if (needToFindAPlaceholder)
2056 hr = findPlaceholder(
2067 /******************************************************************************
2068 * SetElementTimes (IStorage)
2070 HRESULT WINAPI StorageImpl_SetElementTimes(
2072 const OLECHAR *pwcsName,/* [string][in] */
2073 const FILETIME *pctime, /* [in] */
2074 const FILETIME *patime, /* [in] */
2075 const FILETIME *pmtime) /* [in] */
2077 FIXME("not implemented!\n");
2081 /******************************************************************************
2082 * SetStateBits (IStorage)
2084 HRESULT WINAPI StorageImpl_SetStateBits(
2086 DWORD grfStateBits,/* [in] */
2087 DWORD grfMask) /* [in] */
2089 FIXME("not implemented!\n");
2093 HRESULT StorageImpl_Construct(
2102 StgProperty currentProperty;
2103 BOOL readSuccessful;
2104 ULONG currentPropertyIndex;
2106 if ( FAILED( validateSTGM(openFlags) ))
2107 return STG_E_INVALIDFLAG;
2109 memset(This, 0, sizeof(StorageImpl));
2112 * Initialize the virtual fgunction table.
2114 ICOM_VTBL(This) = &Storage32Impl_Vtbl;
2115 This->v_destructor = &StorageImpl_Destroy;
2118 * This is the top-level storage so initialize the ancester pointer
2121 This->ancestorStorage = This;
2124 * Initialize the physical support of the storage.
2126 This->hFile = hFile;
2129 * Initialize the big block cache.
2131 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
2132 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2133 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
2139 if (This->bigBlockFile == 0)
2144 ULARGE_INTEGER size;
2145 BYTE* bigBlockBuffer;
2148 * Initialize all header variables:
2149 * - The big block depot consists of one block and it is at block 0
2150 * - The properties start at block 1
2151 * - There is no small block depot
2153 memset( This->bigBlockDepotStart,
2155 sizeof(This->bigBlockDepotStart));
2157 This->bigBlockDepotCount = 1;
2158 This->bigBlockDepotStart[0] = 0;
2159 This->rootStartBlock = 1;
2160 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
2161 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
2162 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
2163 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2164 This->extBigBlockDepotCount = 0;
2166 StorageImpl_SaveFileHeader(This);
2169 * Add one block for the big block depot and one block for the properties
2171 size.s.HighPart = 0;
2172 size.s.LowPart = This->bigBlockSize * 3;
2173 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
2176 * Initialize the big block depot
2178 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
2179 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2180 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2181 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2182 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2187 * Load the header for the file.
2189 hr = StorageImpl_LoadFileHeader(This);
2193 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2200 * There is no block depot cached yet.
2202 This->indexBlockDepotCached = 0xFFFFFFFF;
2205 * Start searching for free blocks with block 0.
2207 This->prevFreeBlock = 0;
2210 * Create the block chain abstractions.
2212 This->rootBlockChain =
2213 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
2215 This->smallBlockDepotChain = BlockChainStream_Construct(
2217 &This->smallBlockDepotStart,
2221 * Write the root property
2225 StgProperty rootProp;
2227 * Initialize the property chain
2229 memset(&rootProp, 0, sizeof(rootProp));
2230 lstrcpyAtoW(rootProp.name, rootPropertyName);
2232 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
2233 rootProp.propertyType = PROPTYPE_ROOT;
2234 rootProp.previousProperty = PROPERTY_NULL;
2235 rootProp.nextProperty = PROPERTY_NULL;
2236 rootProp.dirProperty = PROPERTY_NULL;
2237 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
2238 rootProp.size.s.HighPart = 0;
2239 rootProp.size.s.LowPart = 0;
2241 StorageImpl_WriteProperty(This, 0, &rootProp);
2245 * Find the ID of the root int he property sets.
2247 currentPropertyIndex = 0;
2251 readSuccessful = StorageImpl_ReadProperty(
2253 currentPropertyIndex,
2258 if ( (currentProperty.sizeOfNameString != 0 ) &&
2259 (currentProperty.propertyType == PROPTYPE_ROOT) )
2261 This->rootPropertySetIndex = currentPropertyIndex;
2265 currentPropertyIndex++;
2267 } while (readSuccessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
2269 if (!readSuccessful)
2276 * Create the block chain abstraction for the small block root chain.
2278 This->smallBlockRootChain = BlockChainStream_Construct(
2281 This->rootPropertySetIndex);
2286 void StorageImpl_Destroy(
2289 TRACE("(%p)\n", This);
2291 BlockChainStream_Destroy(This->smallBlockRootChain);
2292 BlockChainStream_Destroy(This->rootBlockChain);
2293 BlockChainStream_Destroy(This->smallBlockDepotChain);
2295 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2299 /******************************************************************************
2300 * Storage32Impl_GetNextFreeBigBlock
2302 * Returns the index of the next free big block.
2303 * If the big block depot is filled, this method will enlarge it.
2306 ULONG StorageImpl_GetNextFreeBigBlock(
2309 ULONG depotBlockIndexPos;
2311 ULONG depotBlockOffset;
2312 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2313 ULONG nextBlockIndex = BLOCK_SPECIAL;
2315 ULONG freeBlock = BLOCK_UNUSED;
2317 depotIndex = This->prevFreeBlock / blocksPerDepot;
2318 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2321 * Scan the entire big block depot until we find a block marked free
2323 while (nextBlockIndex != BLOCK_UNUSED)
2325 if (depotIndex < COUNT_BBDEPOTINHEADER)
2327 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2330 * Grow the primary depot.
2332 if (depotBlockIndexPos == BLOCK_UNUSED)
2334 depotBlockIndexPos = depotIndex*blocksPerDepot;
2337 * Add a block depot.
2339 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2340 This->bigBlockDepotCount++;
2341 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2344 * Flag it as a block depot.
2346 StorageImpl_SetNextBlockInChain(This,
2350 /* Save new header information.
2352 StorageImpl_SaveFileHeader(This);
2357 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2359 if (depotBlockIndexPos == BLOCK_UNUSED)
2362 * Grow the extended depot.
2364 ULONG extIndex = BLOCK_UNUSED;
2365 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2366 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2368 if (extBlockOffset == 0)
2370 /* We need an extended block.
2372 extIndex = Storage32Impl_AddExtBlockDepot(This);
2373 This->extBigBlockDepotCount++;
2374 depotBlockIndexPos = extIndex + 1;
2377 depotBlockIndexPos = depotIndex * blocksPerDepot;
2380 * Add a block depot and mark it in the extended block.
2382 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2383 This->bigBlockDepotCount++;
2384 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2386 /* Flag the block depot.
2388 StorageImpl_SetNextBlockInChain(This,
2392 /* If necessary, flag the extended depot block.
2394 if (extIndex != BLOCK_UNUSED)
2395 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2397 /* Save header information.
2399 StorageImpl_SaveFileHeader(This);
2403 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2405 if (depotBuffer != 0)
2407 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2408 ( nextBlockIndex != BLOCK_UNUSED))
2410 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2412 if (nextBlockIndex == BLOCK_UNUSED)
2414 freeBlock = (depotIndex * blocksPerDepot) +
2415 (depotBlockOffset/sizeof(ULONG));
2418 depotBlockOffset += sizeof(ULONG);
2421 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2425 depotBlockOffset = 0;
2428 This->prevFreeBlock = freeBlock;
2433 /******************************************************************************
2434 * Storage32Impl_AddBlockDepot
2436 * This will create a depot block, essentially it is a block initialized
2439 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2443 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2446 * Initialize blocks as free
2448 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2450 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2453 /******************************************************************************
2454 * Storage32Impl_GetExtDepotBlock
2456 * Returns the index of the block that corresponds to the specified depot
2457 * index. This method is only for depot indexes equal or greater than
2458 * COUNT_BBDEPOTINHEADER.
2460 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2462 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2463 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2464 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2465 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2466 ULONG blockIndex = BLOCK_UNUSED;
2467 ULONG extBlockIndex = This->extBigBlockDepotStart;
2469 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2471 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2472 return BLOCK_UNUSED;
2474 while (extBlockCount > 0)
2476 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2480 if (extBlockIndex != BLOCK_UNUSED)
2484 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2486 if (depotBuffer != 0)
2488 StorageUtl_ReadDWord(depotBuffer,
2489 extBlockOffset * sizeof(ULONG),
2492 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2499 /******************************************************************************
2500 * Storage32Impl_SetExtDepotBlock
2502 * Associates the specified block index to the specified depot index.
2503 * This method is only for depot indexes equal or greater than
2504 * COUNT_BBDEPOTINHEADER.
2506 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2510 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2511 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2512 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2513 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2514 ULONG extBlockIndex = This->extBigBlockDepotStart;
2516 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2518 while (extBlockCount > 0)
2520 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2524 if (extBlockIndex != BLOCK_UNUSED)
2528 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2530 if (depotBuffer != 0)
2532 StorageUtl_WriteDWord(depotBuffer,
2533 extBlockOffset * sizeof(ULONG),
2536 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2541 /******************************************************************************
2542 * Storage32Impl_AddExtBlockDepot
2544 * Creates an extended depot block.
2546 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2548 ULONG numExtBlocks = This->extBigBlockDepotCount;
2549 ULONG nextExtBlock = This->extBigBlockDepotStart;
2550 BYTE* depotBuffer = NULL;
2551 ULONG index = BLOCK_UNUSED;
2552 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2553 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2554 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2556 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2557 blocksPerDepotBlock;
2559 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2562 * The first extended block.
2564 This->extBigBlockDepotStart = index;
2570 * Follow the chain to the last one.
2572 for (i = 0; i < (numExtBlocks - 1); i++)
2574 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2578 * Add the new extended block to the chain.
2580 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2581 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2582 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2586 * Initialize this block.
2588 depotBuffer = StorageImpl_GetBigBlock(This, index);
2589 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2590 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2595 /******************************************************************************
2596 * Storage32Impl_FreeBigBlock
2598 * This method will flag the specified block as free in the big block depot.
2600 void StorageImpl_FreeBigBlock(
2604 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2606 if (blockIndex < This->prevFreeBlock)
2607 This->prevFreeBlock = blockIndex;
2610 /************************************************************************
2611 * Storage32Impl_GetNextBlockInChain
2613 * This method will retrieve the block index of the next big block in
2616 * Params: This - Pointer to the Storage object.
2617 * blockIndex - Index of the block to retrieve the chain
2620 * Returns: This method returns the index of the next block in the chain.
2621 * It will return the constants:
2622 * BLOCK_SPECIAL - If the block given was not part of a
2624 * BLOCK_END_OF_CHAIN - If the block given was the last in
2626 * BLOCK_UNUSED - If the block given was not past of a chain
2628 * BLOCK_EXTBBDEPOT - This block is part of the extended
2631 * See Windows documentation for more details on IStorage methods.
2633 ULONG StorageImpl_GetNextBlockInChain(
2637 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2638 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2639 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2640 ULONG nextBlockIndex = BLOCK_SPECIAL;
2642 ULONG depotBlockIndexPos;
2644 assert(depotBlockCount < This->bigBlockDepotCount);
2647 * Cache the currently accessed depot block.
2649 if (depotBlockCount != This->indexBlockDepotCached)
2651 This->indexBlockDepotCached = depotBlockCount;
2653 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2655 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2660 * We have to look in the extended depot.
2662 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2665 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2671 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2673 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2674 This->blockDepotCached[index] = nextBlockIndex;
2677 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2681 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2683 return nextBlockIndex;
2686 /******************************************************************************
2687 * Storage32Impl_GetNextExtendedBlock
2689 * Given an extended block this method will return the next extended block.
2692 * The last ULONG of an extended block is the block index of the next
2693 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2697 * - The index of the next extended block
2698 * - BLOCK_UNUSED: there is no next extended block.
2699 * - Any other return values denotes failure.
2701 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2703 ULONG nextBlockIndex = BLOCK_SPECIAL;
2704 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2707 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2711 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2713 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2716 return nextBlockIndex;
2719 /******************************************************************************
2720 * Storage32Impl_SetNextBlockInChain
2722 * This method will write the index of the specified block's next block
2723 * in the big block depot.
2725 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2728 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2729 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2730 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2733 void StorageImpl_SetNextBlockInChain(
2738 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2739 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2740 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2741 ULONG depotBlockIndexPos;
2744 assert(depotBlockCount < This->bigBlockDepotCount);
2745 assert(blockIndex != nextBlock);
2747 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2749 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2754 * We have to look in the extended depot.
2756 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2759 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2763 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2764 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2768 * Update the cached block depot, if necessary.
2770 if (depotBlockCount == This->indexBlockDepotCached)
2772 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2776 /******************************************************************************
2777 * Storage32Impl_LoadFileHeader
2779 * This method will read in the file header, i.e. big block index -1.
2781 HRESULT StorageImpl_LoadFileHeader(
2784 HRESULT hr = STG_E_FILENOTFOUND;
2785 void* headerBigBlock = NULL;
2789 * Get a pointer to the big block of data containing the header.
2791 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2794 * Extract the information from the header.
2796 if (headerBigBlock!=0)
2799 * Check for the "magic number" signature and return an error if it is not
2802 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2804 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2805 return STG_E_OLDFORMAT;
2808 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2810 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2811 return STG_E_INVALIDHEADER;
2814 StorageUtl_ReadWord(
2816 OFFSET_BIGBLOCKSIZEBITS,
2817 &This->bigBlockSizeBits);
2819 StorageUtl_ReadWord(
2821 OFFSET_SMALLBLOCKSIZEBITS,
2822 &This->smallBlockSizeBits);
2824 StorageUtl_ReadDWord(
2826 OFFSET_BBDEPOTCOUNT,
2827 &This->bigBlockDepotCount);
2829 StorageUtl_ReadDWord(
2831 OFFSET_ROOTSTARTBLOCK,
2832 &This->rootStartBlock);
2834 StorageUtl_ReadDWord(
2836 OFFSET_SBDEPOTSTART,
2837 &This->smallBlockDepotStart);
2839 StorageUtl_ReadDWord(
2841 OFFSET_EXTBBDEPOTSTART,
2842 &This->extBigBlockDepotStart);
2844 StorageUtl_ReadDWord(
2846 OFFSET_EXTBBDEPOTCOUNT,
2847 &This->extBigBlockDepotCount);
2849 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2851 StorageUtl_ReadDWord(
2853 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2854 &(This->bigBlockDepotStart[index]));
2858 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2862 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2863 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2867 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2868 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2872 * Right now, the code is making some assumptions about the size of the
2873 * blocks, just make sure they are what we're expecting.
2875 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2876 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2879 * Release the block.
2881 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2889 /******************************************************************************
2890 * Storage32Impl_SaveFileHeader
2892 * This method will save to the file the header, i.e. big block -1.
2894 void StorageImpl_SaveFileHeader(
2897 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2902 * Get a pointer to the big block of data containing the header.
2904 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2907 * If the block read failed, the file is probably new.
2912 * Initialize for all unknown fields.
2914 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2917 * Initialize the magic number.
2919 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2922 * And a bunch of things we don't know what they mean
2924 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2925 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2926 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2927 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2928 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2932 * Write the information to the header.
2934 if (headerBigBlock!=0)
2936 StorageUtl_WriteWord(
2938 OFFSET_BIGBLOCKSIZEBITS,
2939 This->bigBlockSizeBits);
2941 StorageUtl_WriteWord(
2943 OFFSET_SMALLBLOCKSIZEBITS,
2944 This->smallBlockSizeBits);
2946 StorageUtl_WriteDWord(
2948 OFFSET_BBDEPOTCOUNT,
2949 This->bigBlockDepotCount);
2951 StorageUtl_WriteDWord(
2953 OFFSET_ROOTSTARTBLOCK,
2954 This->rootStartBlock);
2956 StorageUtl_WriteDWord(
2958 OFFSET_SBDEPOTSTART,
2959 This->smallBlockDepotStart);
2961 StorageUtl_WriteDWord(
2963 OFFSET_EXTBBDEPOTSTART,
2964 This->extBigBlockDepotStart);
2966 StorageUtl_WriteDWord(
2968 OFFSET_EXTBBDEPOTCOUNT,
2969 This->extBigBlockDepotCount);
2971 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2973 StorageUtl_WriteDWord(
2975 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2976 (This->bigBlockDepotStart[index]));
2981 * Write the big block back to the file.
2983 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2986 /******************************************************************************
2987 * Storage32Impl_ReadProperty
2989 * This method will read the specified property from the property chain.
2991 BOOL StorageImpl_ReadProperty(
2994 StgProperty* buffer)
2996 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2997 ULARGE_INTEGER offsetInPropSet;
2998 BOOL readSuccessful;
3001 offsetInPropSet.s.HighPart = 0;
3002 offsetInPropSet.s.LowPart = index * PROPSET_BLOCK_SIZE;
3004 readSuccessful = BlockChainStream_ReadAt(
3005 This->rootBlockChain,
3013 memset(buffer->name, 0, sizeof(buffer->name));
3016 currentProperty+OFFSET_PS_NAME,
3017 PROPERTY_NAME_BUFFER_LEN );
3019 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3021 StorageUtl_ReadWord(
3023 OFFSET_PS_NAMELENGTH,
3024 &buffer->sizeOfNameString);
3026 StorageUtl_ReadDWord(
3028 OFFSET_PS_PREVIOUSPROP,
3029 &buffer->previousProperty);
3031 StorageUtl_ReadDWord(
3034 &buffer->nextProperty);
3036 StorageUtl_ReadDWord(
3039 &buffer->dirProperty);
3041 StorageUtl_ReadGUID(
3044 &buffer->propertyUniqueID);
3046 StorageUtl_ReadDWord(
3049 &buffer->timeStampS1);
3051 StorageUtl_ReadDWord(
3054 &buffer->timeStampD1);
3056 StorageUtl_ReadDWord(
3059 &buffer->timeStampS2);
3061 StorageUtl_ReadDWord(
3064 &buffer->timeStampD2);
3066 StorageUtl_ReadDWord(
3068 OFFSET_PS_STARTBLOCK,
3069 &buffer->startingBlock);
3071 StorageUtl_ReadDWord(
3074 &buffer->size.s.LowPart);
3076 buffer->size.s.HighPart = 0;
3079 return readSuccessful;
3082 /*********************************************************************
3083 * Write the specified property into the property chain
3085 BOOL StorageImpl_WriteProperty(
3088 StgProperty* buffer)
3090 BYTE currentProperty[PROPSET_BLOCK_SIZE];
3091 ULARGE_INTEGER offsetInPropSet;
3092 BOOL writeSuccessful;
3095 offsetInPropSet.s.HighPart = 0;
3096 offsetInPropSet.s.LowPart = index * PROPSET_BLOCK_SIZE;
3098 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3101 currentProperty + OFFSET_PS_NAME,
3103 PROPERTY_NAME_BUFFER_LEN );
3105 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3107 StorageUtl_WriteWord(
3109 OFFSET_PS_NAMELENGTH,
3110 buffer->sizeOfNameString);
3112 StorageUtl_WriteDWord(
3114 OFFSET_PS_PREVIOUSPROP,
3115 buffer->previousProperty);
3117 StorageUtl_WriteDWord(
3120 buffer->nextProperty);
3122 StorageUtl_WriteDWord(
3125 buffer->dirProperty);
3127 StorageUtl_WriteGUID(
3130 &buffer->propertyUniqueID);
3132 StorageUtl_WriteDWord(
3135 buffer->timeStampS1);
3137 StorageUtl_WriteDWord(
3140 buffer->timeStampD1);
3142 StorageUtl_WriteDWord(
3145 buffer->timeStampS2);
3147 StorageUtl_WriteDWord(
3150 buffer->timeStampD2);
3152 StorageUtl_WriteDWord(
3154 OFFSET_PS_STARTBLOCK,
3155 buffer->startingBlock);
3157 StorageUtl_WriteDWord(
3160 buffer->size.s.LowPart);
3162 writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
3167 return writeSuccessful;
3170 BOOL StorageImpl_ReadBigBlock(
3175 void* bigBlockBuffer;
3177 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
3179 if (bigBlockBuffer!=0)
3181 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
3183 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3191 BOOL StorageImpl_WriteBigBlock(
3196 void* bigBlockBuffer;
3198 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
3200 if (bigBlockBuffer!=0)
3202 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
3204 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3212 void* StorageImpl_GetROBigBlock(
3216 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
3219 void* StorageImpl_GetBigBlock(
3223 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
3226 void StorageImpl_ReleaseBigBlock(
3230 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
3233 /******************************************************************************
3234 * Storage32Impl_SmallBlocksToBigBlocks
3236 * This method will convert a small block chain to a big block chain.
3237 * The small block chain will be destroyed.
3239 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3241 SmallBlockChainStream** ppsbChain)
3243 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3244 ULARGE_INTEGER size, offset;
3245 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
3246 ULONG propertyIndex;
3247 BOOL successRead, successWrite;
3248 StgProperty chainProperty;
3250 BlockChainStream *bbTempChain = NULL;
3251 BlockChainStream *bigBlockChain = NULL;
3254 * Create a temporary big block chain that doesn't have
3255 * an associated property. This temporary chain will be
3256 * used to copy data from small blocks to big blocks.
3258 bbTempChain = BlockChainStream_Construct(This,
3263 * Grow the big block chain.
3265 size = SmallBlockChainStream_GetSize(*ppsbChain);
3266 BlockChainStream_SetSize(bbTempChain, size);
3269 * Copy the contents of the small block chain to the big block chain
3270 * by small block size increments.
3272 offset.s.LowPart = 0;
3273 offset.s.HighPart = 0;
3277 buffer = (BYTE *) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3280 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3282 DEF_SMALL_BLOCK_SIZE,
3285 cbTotalRead += cbRead;
3287 successWrite = BlockChainStream_WriteAt(bbTempChain,
3292 cbTotalWritten += cbWritten;
3294 offset.s.LowPart += This->smallBlockSize;
3296 } while (successRead && successWrite);
3297 HeapFree(GetProcessHeap(),0,buffer);
3299 assert(cbTotalRead == cbTotalWritten);
3302 * Destroy the small block chain.
3304 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3305 size.s.HighPart = 0;
3307 SmallBlockChainStream_SetSize(*ppsbChain, size);
3308 SmallBlockChainStream_Destroy(*ppsbChain);
3312 * Change the property information. This chain is now a big block chain
3313 * and it doesn't reside in the small blocks chain anymore.
3315 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3317 chainProperty.startingBlock = bbHeadOfChain;
3319 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3322 * Destroy the temporary propertyless big block chain.
3323 * Create a new big block chain associated with this property.
3325 BlockChainStream_Destroy(bbTempChain);
3326 bigBlockChain = BlockChainStream_Construct(This,
3330 return bigBlockChain;
3333 /******************************************************************************
3334 ** Storage32InternalImpl implementation
3337 StorageInternalImpl* StorageInternalImpl_Construct(
3338 StorageImpl* ancestorStorage,
3339 ULONG rootPropertyIndex)
3341 StorageInternalImpl* newStorage;
3344 * Allocate space for the new storage object
3346 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3350 memset(newStorage, 0, sizeof(StorageInternalImpl));
3353 * Initialize the virtual function table.
3355 ICOM_VTBL(newStorage) = &Storage32InternalImpl_Vtbl;
3356 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3359 * Keep the ancestor storage pointer and nail a reference to it.
3361 newStorage->ancestorStorage = ancestorStorage;
3362 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3365 * Keep the index of the root property set for this storage,
3367 newStorage->rootPropertySetIndex = rootPropertyIndex;
3375 void StorageInternalImpl_Destroy(
3376 StorageInternalImpl* This)
3378 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3379 HeapFree(GetProcessHeap(), 0, This);
3382 /******************************************************************************
3384 ** Storage32InternalImpl_Commit
3386 ** The non-root storages cannot be opened in transacted mode thus this function
3389 HRESULT WINAPI StorageInternalImpl_Commit(
3391 DWORD grfCommitFlags) /* [in] */
3396 /******************************************************************************
3398 ** Storage32InternalImpl_Revert
3400 ** The non-root storages cannot be opened in transacted mode thus this function
3403 HRESULT WINAPI StorageInternalImpl_Revert(
3409 /******************************************************************************
3410 ** IEnumSTATSTGImpl implementation
3413 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3414 StorageImpl* parentStorage,
3415 ULONG firstPropertyNode)
3417 IEnumSTATSTGImpl* newEnumeration;
3419 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3421 if (newEnumeration!=0)
3424 * Set-up the virtual function table and reference count.
3426 ICOM_VTBL(newEnumeration) = &IEnumSTATSTGImpl_Vtbl;
3427 newEnumeration->ref = 0;
3430 * We want to nail-down the reference to the storage in case the
3431 * enumeration out-lives the storage in the client application.
3433 newEnumeration->parentStorage = parentStorage;
3434 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3436 newEnumeration->firstPropertyNode = firstPropertyNode;
3439 * Initialize the search stack
3441 newEnumeration->stackSize = 0;
3442 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3443 newEnumeration->stackToVisit =
3444 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3447 * Make sure the current node of the iterator is the first one.
3449 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3452 return newEnumeration;
3455 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3457 IStorage_Release((IStorage*)This->parentStorage);
3458 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3459 HeapFree(GetProcessHeap(), 0, This);
3462 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3463 IEnumSTATSTG* iface,
3467 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3470 * Perform a sanity check on the parameters.
3473 return E_INVALIDARG;
3476 * Initialize the return parameter.
3481 * Compare the riid with the interface IDs implemented by this object.
3483 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3485 *ppvObject = (IEnumSTATSTG*)This;
3487 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3489 *ppvObject = (IEnumSTATSTG*)This;
3493 * Check that we obtained an interface.
3495 if ((*ppvObject)==0)
3496 return E_NOINTERFACE;
3499 * Query Interface always increases the reference count by one when it is
3502 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3507 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3508 IEnumSTATSTG* iface)
3510 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3516 ULONG WINAPI IEnumSTATSTGImpl_Release(
3517 IEnumSTATSTG* iface)
3519 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3527 * If the reference count goes down to 0, perform suicide.
3531 IEnumSTATSTGImpl_Destroy(This);
3537 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3538 IEnumSTATSTG* iface,
3541 ULONG* pceltFetched)
3543 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3545 StgProperty currentProperty;
3546 STATSTG* currentReturnStruct = rgelt;
3547 ULONG objectFetched = 0;
3548 ULONG currentSearchNode;
3551 * Perform a sanity check on the parameters.
3553 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3554 return E_INVALIDARG;
3557 * To avoid the special case, get another pointer to a ULONG value if
3558 * the caller didn't supply one.
3560 if (pceltFetched==0)
3561 pceltFetched = &objectFetched;
3564 * Start the iteration, we will iterate until we hit the end of the
3565 * linked list or until we hit the number of items to iterate through
3570 * Start with the node at the top of the stack.
3572 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3574 while ( ( *pceltFetched < celt) &&
3575 ( currentSearchNode!=PROPERTY_NULL) )
3578 * Remove the top node from the stack
3580 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3583 * Read the property from the storage.
3585 StorageImpl_ReadProperty(This->parentStorage,
3590 * Copy the information to the return buffer.
3592 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3597 * Step to the next item in the iteration
3600 currentReturnStruct++;
3603 * Push the next search node in the search stack.
3605 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3608 * continue the iteration.
3610 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3613 if (*pceltFetched == celt)
3620 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3621 IEnumSTATSTG* iface,
3624 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3626 StgProperty currentProperty;
3627 ULONG objectFetched = 0;
3628 ULONG currentSearchNode;
3631 * Start with the node at the top of the stack.
3633 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3635 while ( (objectFetched < celt) &&
3636 (currentSearchNode!=PROPERTY_NULL) )
3639 * Remove the top node from the stack
3641 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3644 * Read the property from the storage.
3646 StorageImpl_ReadProperty(This->parentStorage,
3651 * Step to the next item in the iteration
3656 * Push the next search node in the search stack.
3658 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3661 * continue the iteration.
3663 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3666 if (objectFetched == celt)
3672 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3673 IEnumSTATSTG* iface)
3675 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3677 StgProperty rootProperty;
3678 BOOL readSuccessful;
3681 * Re-initialize the search stack to an empty stack
3683 This->stackSize = 0;
3686 * Read the root property from the storage.
3688 readSuccessful = StorageImpl_ReadProperty(
3689 This->parentStorage,
3690 This->firstPropertyNode,
3695 assert(rootProperty.sizeOfNameString!=0);
3698 * Push the search node in the search stack.
3700 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3706 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3707 IEnumSTATSTG* iface,
3708 IEnumSTATSTG** ppenum)
3710 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3712 IEnumSTATSTGImpl* newClone;
3715 * Perform a sanity check on the parameters.
3718 return E_INVALIDARG;
3720 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3721 This->firstPropertyNode);
3725 * The new clone enumeration must point to the same current node as
3728 newClone->stackSize = This->stackSize ;
3729 newClone->stackMaxSize = This->stackMaxSize ;
3730 newClone->stackToVisit =
3731 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3734 newClone->stackToVisit,
3736 sizeof(ULONG) * newClone->stackSize);
3738 *ppenum = (IEnumSTATSTG*)newClone;
3741 * Don't forget to nail down a reference to the clone before
3744 IEnumSTATSTGImpl_AddRef(*ppenum);
3749 INT IEnumSTATSTGImpl_FindParentProperty(
3750 IEnumSTATSTGImpl *This,
3751 ULONG childProperty,
3752 StgProperty *currentProperty,
3755 ULONG currentSearchNode;
3759 * To avoid the special case, get another pointer to a ULONG value if
3760 * the caller didn't supply one.
3763 thisNodeId = &foundNode;
3766 * Start with the node at the top of the stack.
3768 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3771 while (currentSearchNode!=PROPERTY_NULL)
3774 * Store the current node in the returned parameters
3776 *thisNodeId = currentSearchNode;
3779 * Remove the top node from the stack
3781 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3784 * Read the property from the storage.
3786 StorageImpl_ReadProperty(
3787 This->parentStorage,
3791 if (currentProperty->previousProperty == childProperty)
3792 return PROPERTY_RELATION_PREVIOUS;
3794 else if (currentProperty->nextProperty == childProperty)
3795 return PROPERTY_RELATION_NEXT;
3797 else if (currentProperty->dirProperty == childProperty)
3798 return PROPERTY_RELATION_DIR;
3801 * Push the next search node in the search stack.
3803 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3806 * continue the iteration.
3808 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3811 return PROPERTY_NULL;
3814 ULONG IEnumSTATSTGImpl_FindProperty(
3815 IEnumSTATSTGImpl* This,
3816 const OLECHAR* lpszPropName,
3817 StgProperty* currentProperty)
3819 ULONG currentSearchNode;
3822 * Start with the node at the top of the stack.
3824 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3826 while (currentSearchNode!=PROPERTY_NULL)
3829 * Remove the top node from the stack
3831 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3834 * Read the property from the storage.
3836 StorageImpl_ReadProperty(This->parentStorage,
3840 if ( propertyNameCmp(
3841 (OLECHAR*)currentProperty->name,
3842 (OLECHAR*)lpszPropName) == 0)
3843 return currentSearchNode;
3846 * Push the next search node in the search stack.
3848 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3851 * continue the iteration.
3853 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3856 return PROPERTY_NULL;
3859 void IEnumSTATSTGImpl_PushSearchNode(
3860 IEnumSTATSTGImpl* This,
3863 StgProperty rootProperty;
3864 BOOL readSuccessful;
3867 * First, make sure we're not trying to push an unexisting node.
3869 if (nodeToPush==PROPERTY_NULL)
3873 * First push the node to the stack
3875 if (This->stackSize == This->stackMaxSize)
3877 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3879 This->stackToVisit = HeapReAlloc(
3883 sizeof(ULONG) * This->stackMaxSize);
3886 This->stackToVisit[This->stackSize] = nodeToPush;
3890 * Read the root property from the storage.
3892 readSuccessful = StorageImpl_ReadProperty(
3893 This->parentStorage,
3899 assert(rootProperty.sizeOfNameString!=0);
3902 * Push the previous search node in the search stack.
3904 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3908 ULONG IEnumSTATSTGImpl_PopSearchNode(
3909 IEnumSTATSTGImpl* This,
3914 if (This->stackSize == 0)
3915 return PROPERTY_NULL;
3917 topNode = This->stackToVisit[This->stackSize-1];
3925 /******************************************************************************
3926 ** StorageUtl implementation
3929 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3931 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3934 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3936 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3939 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3941 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3944 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3946 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3949 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3951 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3952 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3953 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3955 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3958 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3960 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3961 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3962 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3964 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3967 void StorageUtl_CopyPropertyToSTATSTG(
3968 STATSTG* destination,
3969 StgProperty* source,
3973 * The copy of the string occurs only when the flag is not set
3975 if ((statFlags & STATFLAG_NONAME) != 0)
3977 destination->pwcsName = 0;
3981 destination->pwcsName =
3982 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3984 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3987 switch (source->propertyType)
3989 case PROPTYPE_STORAGE:
3991 destination->type = STGTY_STORAGE;
3993 case PROPTYPE_STREAM:
3994 destination->type = STGTY_STREAM;
3997 destination->type = STGTY_STREAM;
4001 destination->cbSize = source->size;
4003 currentReturnStruct->mtime = {0}; TODO
4004 currentReturnStruct->ctime = {0};
4005 currentReturnStruct->atime = {0};
4007 destination->grfMode = 0;
4008 destination->grfLocksSupported = 0;
4009 destination->clsid = source->propertyUniqueID;
4010 destination->grfStateBits = 0;
4011 destination->reserved = 0;
4014 /******************************************************************************
4015 ** BlockChainStream implementation
4018 BlockChainStream* BlockChainStream_Construct(
4019 StorageImpl* parentStorage,
4020 ULONG* headOfStreamPlaceHolder,
4021 ULONG propertyIndex)
4023 BlockChainStream* newStream;
4026 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4028 newStream->parentStorage = parentStorage;
4029 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4030 newStream->ownerPropertyIndex = propertyIndex;
4031 newStream->lastBlockNoInSequence = 0xFFFFFFFF;
4032 newStream->tailIndex = BLOCK_END_OF_CHAIN;
4033 newStream->numBlocks = 0;
4035 blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4037 while (blockIndex != BLOCK_END_OF_CHAIN)
4039 newStream->numBlocks++;
4040 newStream->tailIndex = blockIndex;
4042 blockIndex = StorageImpl_GetNextBlockInChain(
4050 void BlockChainStream_Destroy(BlockChainStream* This)
4052 HeapFree(GetProcessHeap(), 0, This);
4055 /******************************************************************************
4056 * BlockChainStream_GetHeadOfChain
4058 * Returns the head of this stream chain.
4059 * Some special chains don't have properties, their heads are kept in
4060 * This->headOfStreamPlaceHolder.
4063 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4065 StgProperty chainProperty;
4066 BOOL readSuccessful;
4068 if (This->headOfStreamPlaceHolder != 0)
4069 return *(This->headOfStreamPlaceHolder);
4071 if (This->ownerPropertyIndex != PROPERTY_NULL)
4073 readSuccessful = StorageImpl_ReadProperty(
4074 This->parentStorage,
4075 This->ownerPropertyIndex,
4080 return chainProperty.startingBlock;
4084 return BLOCK_END_OF_CHAIN;
4087 /******************************************************************************
4088 * BlockChainStream_GetCount
4090 * Returns the number of blocks that comprises this chain.
4091 * This is not the size of the stream as the last block may not be full!
4094 ULONG BlockChainStream_GetCount(BlockChainStream* This)
4099 blockIndex = BlockChainStream_GetHeadOfChain(This);
4101 while (blockIndex != BLOCK_END_OF_CHAIN)
4105 blockIndex = StorageImpl_GetNextBlockInChain(
4106 This->parentStorage,
4113 /******************************************************************************
4114 * BlockChainStream_ReadAt
4116 * Reads a specified number of bytes from this chain at the specified offset.
4117 * bytesRead may be NULL.
4118 * Failure will be returned if the specified number of bytes has not been read.
4120 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
4121 ULARGE_INTEGER offset,
4126 ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
4127 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->bigBlockSize;
4128 ULONG bytesToReadInBuffer;
4131 BYTE* bigBlockBuffer;
4134 * Find the first block in the stream that contains part of the buffer.
4136 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4137 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4138 (blockNoInSequence < This->lastBlockNoInSequence) )
4140 blockIndex = BlockChainStream_GetHeadOfChain(This);
4141 This->lastBlockNoInSequence = blockNoInSequence;
4145 ULONG temp = blockNoInSequence;
4147 blockIndex = This->lastBlockNoInSequenceIndex;
4148 blockNoInSequence -= This->lastBlockNoInSequence;
4149 This->lastBlockNoInSequence = temp;
4152 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4155 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4157 blockNoInSequence--;
4160 This->lastBlockNoInSequenceIndex = blockIndex;
4163 * Start reading the buffer.
4166 bufferWalker = buffer;
4168 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4171 * Calculate how many bytes we can copy from this big block.
4173 bytesToReadInBuffer =
4174 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
4177 * Copy those bytes to the buffer
4180 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
4182 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
4184 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4187 * Step to the next big block.
4190 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4192 bufferWalker += bytesToReadInBuffer;
4193 size -= bytesToReadInBuffer;
4194 *bytesRead += bytesToReadInBuffer;
4195 offsetInBlock = 0; /* There is no offset on the next block */
4202 /******************************************************************************
4203 * BlockChainStream_WriteAt
4205 * Writes the specified number of bytes to this chain at the specified offset.
4206 * bytesWritten may be NULL.
4207 * Will fail if not all specified number of bytes have been written.
4209 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
4210 ULARGE_INTEGER offset,
4213 ULONG* bytesWritten)
4215 ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
4216 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->bigBlockSize;
4220 BYTE* bigBlockBuffer;
4223 * Find the first block in the stream that contains part of the buffer.
4225 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4226 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4227 (blockNoInSequence < This->lastBlockNoInSequence) )
4229 blockIndex = BlockChainStream_GetHeadOfChain(This);
4230 This->lastBlockNoInSequence = blockNoInSequence;
4234 ULONG temp = blockNoInSequence;
4236 blockIndex = This->lastBlockNoInSequenceIndex;
4237 blockNoInSequence -= This->lastBlockNoInSequence;
4238 This->lastBlockNoInSequence = temp;
4241 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4244 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4246 blockNoInSequence--;
4249 This->lastBlockNoInSequenceIndex = blockIndex;
4252 * Here, I'm casting away the constness on the buffer variable
4253 * This is OK since we don't intend to modify that buffer.
4256 bufferWalker = (BYTE*)buffer;
4258 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4261 * Calculate how many bytes we can copy from this big block.
4264 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
4267 * Copy those bytes to the buffer
4269 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
4271 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
4273 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4276 * Step to the next big block.
4279 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4281 bufferWalker += bytesToWrite;
4282 size -= bytesToWrite;
4283 *bytesWritten += bytesToWrite;
4284 offsetInBlock = 0; /* There is no offset on the next block */
4290 /******************************************************************************
4291 * BlockChainStream_Shrink
4293 * Shrinks this chain in the big block depot.
4295 BOOL BlockChainStream_Shrink(BlockChainStream* This,
4296 ULARGE_INTEGER newSize)
4298 ULONG blockIndex, extraBlock;
4303 * Reset the last accessed block cache.
4305 This->lastBlockNoInSequence = 0xFFFFFFFF;
4306 This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4309 * Figure out how many blocks are needed to contain the new size
4311 numBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
4313 if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
4316 blockIndex = BlockChainStream_GetHeadOfChain(This);
4319 * Go to the new end of chain
4321 while (count < numBlocks)
4324 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4329 /* Get the next block before marking the new end */
4331 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4333 /* Mark the new end of chain */
4334 StorageImpl_SetNextBlockInChain(
4335 This->parentStorage,
4337 BLOCK_END_OF_CHAIN);
4339 This->tailIndex = blockIndex;
4340 This->numBlocks = numBlocks;
4343 * Mark the extra blocks as free
4345 while (extraBlock != BLOCK_END_OF_CHAIN)
4348 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4350 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4351 extraBlock = blockIndex;
4357 /******************************************************************************
4358 * BlockChainStream_Enlarge
4360 * Grows this chain in the big block depot.
4362 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4363 ULARGE_INTEGER newSize)
4365 ULONG blockIndex, currentBlock;
4367 ULONG oldNumBlocks = 0;
4369 blockIndex = BlockChainStream_GetHeadOfChain(This);
4372 * Empty chain. Create the head.
4374 if (blockIndex == BLOCK_END_OF_CHAIN)
4376 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4377 StorageImpl_SetNextBlockInChain(This->parentStorage,
4379 BLOCK_END_OF_CHAIN);
4381 if (This->headOfStreamPlaceHolder != 0)
4383 *(This->headOfStreamPlaceHolder) = blockIndex;
4387 StgProperty chainProp;
4388 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4390 StorageImpl_ReadProperty(
4391 This->parentStorage,
4392 This->ownerPropertyIndex,
4395 chainProp.startingBlock = blockIndex;
4397 StorageImpl_WriteProperty(
4398 This->parentStorage,
4399 This->ownerPropertyIndex,
4403 This->tailIndex = blockIndex;
4404 This->numBlocks = 1;
4408 * Figure out how many blocks are needed to contain this stream
4410 newNumBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
4412 if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
4416 * Go to the current end of chain
4418 if (This->tailIndex == BLOCK_END_OF_CHAIN)
4420 currentBlock = blockIndex;
4422 while (blockIndex != BLOCK_END_OF_CHAIN)
4425 currentBlock = blockIndex;
4428 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4431 This->tailIndex = currentBlock;
4434 currentBlock = This->tailIndex;
4435 oldNumBlocks = This->numBlocks;
4438 * Add new blocks to the chain
4440 if (oldNumBlocks < newNumBlocks)
4442 while (oldNumBlocks < newNumBlocks)
4444 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4446 StorageImpl_SetNextBlockInChain(
4447 This->parentStorage,
4451 StorageImpl_SetNextBlockInChain(
4452 This->parentStorage,
4454 BLOCK_END_OF_CHAIN);
4456 currentBlock = blockIndex;
4460 This->tailIndex = blockIndex;
4461 This->numBlocks = newNumBlocks;
4467 /******************************************************************************
4468 * BlockChainStream_SetSize
4470 * Sets the size of this stream. The big block depot will be updated.
4471 * The file will grow if we grow the chain.
4473 * TODO: Free the actual blocks in the file when we shrink the chain.
4474 * Currently, the blocks are still in the file. So the file size
4475 * doesn't shrink even if we shrink streams.
4477 BOOL BlockChainStream_SetSize(
4478 BlockChainStream* This,
4479 ULARGE_INTEGER newSize)
4481 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4483 if (newSize.s.LowPart == size.s.LowPart)
4486 if (newSize.s.LowPart < size.s.LowPart)
4488 BlockChainStream_Shrink(This, newSize);
4492 ULARGE_INTEGER fileSize =
4493 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4495 ULONG diff = newSize.s.LowPart - size.s.LowPart;
4498 * Make sure the file stays a multiple of blocksize
4500 if ((diff % This->parentStorage->bigBlockSize) != 0)
4501 diff += (This->parentStorage->bigBlockSize -
4502 (diff % This->parentStorage->bigBlockSize) );
4504 fileSize.s.LowPart += diff;
4505 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4507 BlockChainStream_Enlarge(This, newSize);
4513 /******************************************************************************
4514 * BlockChainStream_GetSize
4516 * Returns the size of this chain.
4517 * Will return the block count if this chain doesn't have a property.
4519 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4521 StgProperty chainProperty;
4523 if(This->headOfStreamPlaceHolder == NULL)
4526 * This chain is a data stream read the property and return
4527 * the appropriate size
4529 StorageImpl_ReadProperty(
4530 This->parentStorage,
4531 This->ownerPropertyIndex,
4534 return chainProperty.size;
4539 * this chain is a chain that does not have a property, figure out the
4540 * size by making the product number of used blocks times the
4543 ULARGE_INTEGER result;
4544 result.s.HighPart = 0;
4547 BlockChainStream_GetCount(This) *
4548 This->parentStorage->bigBlockSize;
4554 /******************************************************************************
4555 ** SmallBlockChainStream implementation
4558 SmallBlockChainStream* SmallBlockChainStream_Construct(
4559 StorageImpl* parentStorage,
4560 ULONG propertyIndex)
4562 SmallBlockChainStream* newStream;
4564 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4566 newStream->parentStorage = parentStorage;
4567 newStream->ownerPropertyIndex = propertyIndex;
4572 void SmallBlockChainStream_Destroy(
4573 SmallBlockChainStream* This)
4575 HeapFree(GetProcessHeap(), 0, This);
4578 /******************************************************************************
4579 * SmallBlockChainStream_GetHeadOfChain
4581 * Returns the head of this chain of small blocks.
4583 ULONG SmallBlockChainStream_GetHeadOfChain(
4584 SmallBlockChainStream* This)
4586 StgProperty chainProperty;
4587 BOOL readSuccessful;
4589 if (This->ownerPropertyIndex)
4591 readSuccessful = StorageImpl_ReadProperty(
4592 This->parentStorage,
4593 This->ownerPropertyIndex,
4598 return chainProperty.startingBlock;
4603 return BLOCK_END_OF_CHAIN;
4606 /******************************************************************************
4607 * SmallBlockChainStream_GetNextBlockInChain
4609 * Returns the index of the next small block in this chain.
4612 * - BLOCK_END_OF_CHAIN: end of this chain
4613 * - BLOCK_UNUSED: small block 'blockIndex' is free
4615 ULONG SmallBlockChainStream_GetNextBlockInChain(
4616 SmallBlockChainStream* This,
4619 ULARGE_INTEGER offsetOfBlockInDepot;
4621 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4625 offsetOfBlockInDepot.s.HighPart = 0;
4626 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4629 * Read those bytes in the buffer from the small block file.
4631 success = BlockChainStream_ReadAt(
4632 This->parentStorage->smallBlockDepotChain,
4633 offsetOfBlockInDepot,
4640 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4643 return nextBlockInChain;
4646 /******************************************************************************
4647 * SmallBlockChainStream_SetNextBlockInChain
4649 * Writes the index of the next block of the specified block in the small
4651 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4652 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4654 void SmallBlockChainStream_SetNextBlockInChain(
4655 SmallBlockChainStream* This,
4659 ULARGE_INTEGER offsetOfBlockInDepot;
4663 offsetOfBlockInDepot.s.HighPart = 0;
4664 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4666 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4669 * Read those bytes in the buffer from the small block file.
4671 BlockChainStream_WriteAt(
4672 This->parentStorage->smallBlockDepotChain,
4673 offsetOfBlockInDepot,
4679 /******************************************************************************
4680 * SmallBlockChainStream_FreeBlock
4682 * Flag small block 'blockIndex' as free in the small block depot.
4684 void SmallBlockChainStream_FreeBlock(
4685 SmallBlockChainStream* This,
4688 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4691 /******************************************************************************
4692 * SmallBlockChainStream_GetNextFreeBlock
4694 * Returns the index of a free small block. The small block depot will be
4695 * enlarged if necessary. The small block chain will also be enlarged if
4698 ULONG SmallBlockChainStream_GetNextFreeBlock(
4699 SmallBlockChainStream* This)
4701 ULARGE_INTEGER offsetOfBlockInDepot;
4704 ULONG blockIndex = 0;
4705 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4706 BOOL success = TRUE;
4707 ULONG smallBlocksPerBigBlock;
4709 offsetOfBlockInDepot.s.HighPart = 0;
4712 * Scan the small block depot for a free block
4714 while (nextBlockIndex != BLOCK_UNUSED)
4716 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4718 success = BlockChainStream_ReadAt(
4719 This->parentStorage->smallBlockDepotChain,
4720 offsetOfBlockInDepot,
4726 * If we run out of space for the small block depot, enlarge it
4730 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4732 if (nextBlockIndex != BLOCK_UNUSED)
4738 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4740 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4741 ULONG nextBlock, newsbdIndex;
4742 BYTE* smallBlockDepot;
4744 nextBlock = sbdIndex;
4745 while (nextBlock != BLOCK_END_OF_CHAIN)
4747 sbdIndex = nextBlock;
4749 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4752 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4753 if (sbdIndex != BLOCK_END_OF_CHAIN)
4754 StorageImpl_SetNextBlockInChain(
4755 This->parentStorage,
4759 StorageImpl_SetNextBlockInChain(
4760 This->parentStorage,
4762 BLOCK_END_OF_CHAIN);
4765 * Initialize all the small blocks to free
4768 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4770 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4771 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4776 * We have just created the small block depot.
4778 StgProperty rootProp;
4782 * Save it in the header
4784 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4785 StorageImpl_SaveFileHeader(This->parentStorage);
4788 * And allocate the first big block that will contain small blocks
4791 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4793 StorageImpl_SetNextBlockInChain(
4794 This->parentStorage,
4796 BLOCK_END_OF_CHAIN);
4798 StorageImpl_ReadProperty(
4799 This->parentStorage,
4800 This->parentStorage->rootPropertySetIndex,
4803 rootProp.startingBlock = sbStartIndex;
4804 rootProp.size.s.HighPart = 0;
4805 rootProp.size.s.LowPart = This->parentStorage->bigBlockSize;
4807 StorageImpl_WriteProperty(
4808 This->parentStorage,
4809 This->parentStorage->rootPropertySetIndex,
4815 smallBlocksPerBigBlock =
4816 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4819 * Verify if we have to allocate big blocks to contain small blocks
4821 if (blockIndex % smallBlocksPerBigBlock == 0)
4823 StgProperty rootProp;
4824 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4826 StorageImpl_ReadProperty(
4827 This->parentStorage,
4828 This->parentStorage->rootPropertySetIndex,
4831 if (rootProp.size.s.LowPart <
4832 (blocksRequired * This->parentStorage->bigBlockSize))
4834 rootProp.size.s.LowPart += This->parentStorage->bigBlockSize;
4836 BlockChainStream_SetSize(
4837 This->parentStorage->smallBlockRootChain,
4840 StorageImpl_WriteProperty(
4841 This->parentStorage,
4842 This->parentStorage->rootPropertySetIndex,
4850 /******************************************************************************
4851 * SmallBlockChainStream_ReadAt
4853 * Reads a specified number of bytes from this chain at the specified offset.
4854 * bytesRead may be NULL.
4855 * Failure will be returned if the specified number of bytes has not been read.
4857 BOOL SmallBlockChainStream_ReadAt(
4858 SmallBlockChainStream* This,
4859 ULARGE_INTEGER offset,
4864 ULARGE_INTEGER offsetInBigBlockFile;
4865 ULONG blockNoInSequence =
4866 offset.s.LowPart / This->parentStorage->smallBlockSize;
4868 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
4869 ULONG bytesToReadInBuffer;
4871 ULONG bytesReadFromBigBlockFile;
4875 * This should never happen on a small block file.
4877 assert(offset.s.HighPart==0);
4880 * Find the first block in the stream that contains part of the buffer.
4882 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4884 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4886 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4888 blockNoInSequence--;
4892 * Start reading the buffer.
4895 bufferWalker = buffer;
4897 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4900 * Calculate how many bytes we can copy from this small block.
4902 bytesToReadInBuffer =
4903 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4906 * Calculate the offset of the small block in the small block file.
4908 offsetInBigBlockFile.s.HighPart = 0;
4909 offsetInBigBlockFile.s.LowPart =
4910 blockIndex * This->parentStorage->smallBlockSize;
4912 offsetInBigBlockFile.s.LowPart += offsetInBlock;
4915 * Read those bytes in the buffer from the small block file.
4917 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4918 offsetInBigBlockFile,
4919 bytesToReadInBuffer,
4921 &bytesReadFromBigBlockFile);
4923 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4926 * Step to the next big block.
4928 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4929 bufferWalker += bytesToReadInBuffer;
4930 size -= bytesToReadInBuffer;
4931 *bytesRead += bytesToReadInBuffer;
4932 offsetInBlock = 0; /* There is no offset on the next block */
4938 /******************************************************************************
4939 * SmallBlockChainStream_WriteAt
4941 * Writes the specified number of bytes to this chain at the specified offset.
4942 * bytesWritten may be NULL.
4943 * Will fail if not all specified number of bytes have been written.
4945 BOOL SmallBlockChainStream_WriteAt(
4946 SmallBlockChainStream* This,
4947 ULARGE_INTEGER offset,
4950 ULONG* bytesWritten)
4952 ULARGE_INTEGER offsetInBigBlockFile;
4953 ULONG blockNoInSequence =
4954 offset.s.LowPart / This->parentStorage->smallBlockSize;
4956 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
4957 ULONG bytesToWriteInBuffer;
4959 ULONG bytesWrittenFromBigBlockFile;
4963 * This should never happen on a small block file.
4965 assert(offset.s.HighPart==0);
4968 * Find the first block in the stream that contains part of the buffer.
4970 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4972 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4974 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4976 blockNoInSequence--;
4980 * Start writing the buffer.
4982 * Here, I'm casting away the constness on the buffer variable
4983 * This is OK since we don't intend to modify that buffer.
4986 bufferWalker = (BYTE*)buffer;
4987 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4990 * Calculate how many bytes we can copy to this small block.
4992 bytesToWriteInBuffer =
4993 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4996 * Calculate the offset of the small block in the small block file.
4998 offsetInBigBlockFile.s.HighPart = 0;
4999 offsetInBigBlockFile.s.LowPart =
5000 blockIndex * This->parentStorage->smallBlockSize;
5002 offsetInBigBlockFile.s.LowPart += offsetInBlock;
5005 * Write those bytes in the buffer to the small block file.
5007 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
5008 offsetInBigBlockFile,
5009 bytesToWriteInBuffer,
5011 &bytesWrittenFromBigBlockFile);
5013 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
5016 * Step to the next big block.
5018 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5019 bufferWalker += bytesToWriteInBuffer;
5020 size -= bytesToWriteInBuffer;
5021 *bytesWritten += bytesToWriteInBuffer;
5022 offsetInBlock = 0; /* There is no offset on the next block */
5028 /******************************************************************************
5029 * SmallBlockChainStream_Shrink
5031 * Shrinks this chain in the small block depot.
5033 BOOL SmallBlockChainStream_Shrink(
5034 SmallBlockChainStream* This,
5035 ULARGE_INTEGER newSize)
5037 ULONG blockIndex, extraBlock;
5041 numBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
5043 if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
5046 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5049 * Go to the new end of chain
5051 while (count < numBlocks)
5053 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5058 * If the count is 0, we have a special case, the head of the chain was
5063 StgProperty chainProp;
5065 StorageImpl_ReadProperty(This->parentStorage,
5066 This->ownerPropertyIndex,
5069 chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5071 StorageImpl_WriteProperty(This->parentStorage,
5072 This->ownerPropertyIndex,
5076 * We start freeing the chain at the head block.
5078 extraBlock = blockIndex;
5082 /* Get the next block before marking the new end */
5083 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5085 /* Mark the new end of chain */
5086 SmallBlockChainStream_SetNextBlockInChain(
5089 BLOCK_END_OF_CHAIN);
5093 * Mark the extra blocks as free
5095 while (extraBlock != BLOCK_END_OF_CHAIN)
5097 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
5098 SmallBlockChainStream_FreeBlock(This, extraBlock);
5099 extraBlock = blockIndex;
5105 /******************************************************************************
5106 * SmallBlockChainStream_Enlarge
5108 * Grows this chain in the small block depot.
5110 BOOL SmallBlockChainStream_Enlarge(
5111 SmallBlockChainStream* This,
5112 ULARGE_INTEGER newSize)
5114 ULONG blockIndex, currentBlock;
5116 ULONG oldNumBlocks = 0;
5118 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5123 if (blockIndex == BLOCK_END_OF_CHAIN)
5126 StgProperty chainProp;
5128 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5131 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5133 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5136 blockIndex = chainProp.startingBlock;
5137 SmallBlockChainStream_SetNextBlockInChain(
5140 BLOCK_END_OF_CHAIN);
5143 currentBlock = blockIndex;
5146 * Figure out how many blocks are needed to contain this stream
5148 newNumBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
5150 if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
5154 * Go to the current end of chain
5156 while (blockIndex != BLOCK_END_OF_CHAIN)
5159 currentBlock = blockIndex;
5160 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
5164 * Add new blocks to the chain
5166 while (oldNumBlocks < newNumBlocks)
5168 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5169 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5171 SmallBlockChainStream_SetNextBlockInChain(
5174 BLOCK_END_OF_CHAIN);
5176 currentBlock = blockIndex;
5183 /******************************************************************************
5184 * SmallBlockChainStream_GetCount
5186 * Returns the number of blocks that comprises this chain.
5187 * This is not the size of this chain as the last block may not be full!
5189 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5194 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5196 while (blockIndex != BLOCK_END_OF_CHAIN)
5200 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5206 /******************************************************************************
5207 * SmallBlockChainStream_SetSize
5209 * Sets the size of this stream.
5210 * The file will grow if we grow the chain.
5212 * TODO: Free the actual blocks in the file when we shrink the chain.
5213 * Currently, the blocks are still in the file. So the file size
5214 * doesn't shrink even if we shrink streams.
5216 BOOL SmallBlockChainStream_SetSize(
5217 SmallBlockChainStream* This,
5218 ULARGE_INTEGER newSize)
5220 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5222 if (newSize.s.LowPart == size.s.LowPart)
5225 if (newSize.s.LowPart < size.s.LowPart)
5227 SmallBlockChainStream_Shrink(This, newSize);
5231 SmallBlockChainStream_Enlarge(This, newSize);
5237 /******************************************************************************
5238 * SmallBlockChainStream_GetSize
5240 * Returns the size of this chain.
5242 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5244 StgProperty chainProperty;
5246 StorageImpl_ReadProperty(
5247 This->parentStorage,
5248 This->ownerPropertyIndex,
5251 return chainProperty.size;
5254 /******************************************************************************
5255 * StgCreateDocfile32 [OLE32.144]
5257 HRESULT WINAPI StgCreateDocfile(
5261 IStorage **ppstgOpen)
5263 StorageImpl* newStorage = 0;
5264 HANDLE hFile = INVALID_HANDLE_VALUE;
5269 DWORD fileAttributes;
5270 WCHAR tempFileName[MAX_PATH];
5272 TRACE("(%s, %lx, %ld, %p)\n",
5273 debugstr_w(pwcsName), grfMode,
5274 reserved, ppstgOpen);
5277 * Validate the parameters
5280 return STG_E_INVALIDPOINTER;
5283 * Validate the STGM flags
5285 if ( FAILED( validateSTGM(grfMode) ))
5286 return STG_E_INVALIDFLAG;
5289 * Generate a unique name.
5293 WCHAR tempPath[MAX_PATH];
5294 WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5296 memset(tempPath, 0, sizeof(tempPath));
5297 memset(tempFileName, 0, sizeof(tempFileName));
5299 if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5302 if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5303 pwcsName = tempFileName;
5305 return STG_E_INSUFFICIENTMEMORY;
5309 * Interpret the STGM value grfMode
5311 shareMode = GetShareModeFromSTGM(grfMode);
5312 accessMode = GetAccessModeFromSTGM(grfMode);
5313 creationMode = GetCreationModeFromSTGM(grfMode);
5315 if (grfMode & STGM_DELETEONRELEASE)
5316 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5318 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5320 if (grfMode & STGM_TRANSACTED)
5321 FIXME("Transacted mode not implemented.\n");
5324 * Initialize the "out" parameter.
5328 hFile = CreateFileW(pwcsName,
5336 if (hFile == INVALID_HANDLE_VALUE)
5342 * Allocate and initialize the new IStorage32object.
5344 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5346 if (newStorage == 0)
5347 return STG_E_INSUFFICIENTMEMORY;
5349 hr = StorageImpl_Construct(
5359 HeapFree(GetProcessHeap(), 0, newStorage);
5364 * Get an "out" pointer for the caller.
5366 hr = StorageBaseImpl_QueryInterface(
5367 (IStorage*)newStorage,
5368 (REFIID)&IID_IStorage,
5374 /******************************************************************************
5375 * StgOpenStorage32 [OLE32.148]
5377 HRESULT WINAPI StgOpenStorage(
5378 const OLECHAR *pwcsName,
5379 IStorage *pstgPriority,
5383 IStorage **ppstgOpen)
5385 StorageImpl* newStorage = 0;
5391 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5392 debugstr_w(pwcsName), pstgPriority, grfMode,
5393 snbExclude, reserved, ppstgOpen);
5396 * Perform a sanity check
5398 if (( pwcsName == 0) || (ppstgOpen == 0) )
5399 return STG_E_INVALIDPOINTER;
5402 * Validate the STGM flags
5404 if ( FAILED( validateSTGM(grfMode) ))
5405 return STG_E_INVALIDFLAG;
5408 * Interpret the STGM value grfMode
5410 shareMode = GetShareModeFromSTGM(grfMode);
5411 accessMode = GetAccessModeFromSTGM(grfMode);
5414 * Initialize the "out" parameter.
5418 hFile = CreateFileW( pwcsName,
5423 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5427 if (hFile==INVALID_HANDLE_VALUE)
5429 HRESULT hr = E_FAIL;
5430 DWORD last_error = GetLastError();
5434 case ERROR_FILE_NOT_FOUND:
5435 hr = STG_E_FILENOTFOUND;
5438 case ERROR_PATH_NOT_FOUND:
5439 hr = STG_E_PATHNOTFOUND;
5442 case ERROR_ACCESS_DENIED:
5443 case ERROR_WRITE_PROTECT:
5444 hr = STG_E_ACCESSDENIED;
5447 case ERROR_SHARING_VIOLATION:
5448 hr = STG_E_SHAREVIOLATION;
5459 * Allocate and initialize the new IStorage32object.
5461 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5463 if (newStorage == 0)
5464 return STG_E_INSUFFICIENTMEMORY;
5466 hr = StorageImpl_Construct(
5476 HeapFree(GetProcessHeap(), 0, newStorage);
5481 * Get an "out" pointer for the caller.
5483 hr = StorageBaseImpl_QueryInterface(
5484 (IStorage*)newStorage,
5485 (REFIID)&IID_IStorage,
5491 /******************************************************************************
5492 * StgCreateDocfileOnILockBytes [OLE32.145]
5494 HRESULT WINAPI StgCreateDocfileOnILockBytes(
5498 IStorage** ppstgOpen)
5500 StorageImpl* newStorage = 0;
5504 * Validate the parameters
5506 if ((ppstgOpen == 0) || (plkbyt == 0))
5507 return STG_E_INVALIDPOINTER;
5510 * Allocate and initialize the new IStorage object.
5512 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5514 if (newStorage == 0)
5515 return STG_E_INSUFFICIENTMEMORY;
5517 hr = StorageImpl_Construct(
5527 HeapFree(GetProcessHeap(), 0, newStorage);
5532 * Get an "out" pointer for the caller.
5534 hr = StorageBaseImpl_QueryInterface(
5535 (IStorage*)newStorage,
5536 (REFIID)&IID_IStorage,
5542 /******************************************************************************
5543 * StgOpenStorageOnILockBytes [OLE32.149]
5545 HRESULT WINAPI StgOpenStorageOnILockBytes(
5547 IStorage *pstgPriority,
5551 IStorage **ppstgOpen)
5553 StorageImpl* newStorage = 0;
5557 * Perform a sanity check
5559 if ((plkbyt == 0) || (ppstgOpen == 0))
5560 return STG_E_INVALIDPOINTER;
5563 * Validate the STGM flags
5565 if ( FAILED( validateSTGM(grfMode) ))
5566 return STG_E_INVALIDFLAG;
5569 * Initialize the "out" parameter.
5574 * Allocate and initialize the new IStorage object.
5576 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5578 if (newStorage == 0)
5579 return STG_E_INSUFFICIENTMEMORY;
5581 hr = StorageImpl_Construct(
5591 HeapFree(GetProcessHeap(), 0, newStorage);
5596 * Get an "out" pointer for the caller.
5598 hr = StorageBaseImpl_QueryInterface(
5599 (IStorage*)newStorage,
5600 (REFIID)&IID_IStorage,
5606 /******************************************************************************
5607 * StgSetTimes [ole32.150]
5611 HRESULT WINAPI StgSetTimes(WCHAR * str, FILETIME * a, FILETIME * b, FILETIME *c )
5614 FIXME("(%p, %p, %p, %p),stub!\n", str, a, b, c);
5618 /******************************************************************************
5619 * StgIsStorageILockBytes [OLE32.147]
5621 * Determines if the ILockBytes contains a storage object.
5623 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
5626 ULARGE_INTEGER offset;
5628 offset.s.HighPart = 0;
5629 offset.s.LowPart = 0;
5631 ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
5633 if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
5639 /******************************************************************************
5640 * WriteClassStg32 [OLE32.158]
5642 * This method will store the specified CLSID in the specified storage object
5644 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5650 hRes = IStorage_SetClass(pStg, rclsid);
5655 /*******************************************************************************************
5658 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5660 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
5670 * read a STATSTG structure (contains the clsid) from the storage
5672 hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
5675 *pclsid=pstatstg.clsid;
5680 /*************************************************************************************
5683 * This function loads an object from stream
5685 HRESULT WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
5690 FIXME("(),stub!\n");
5692 res=ReadClassStm(pStm,&clsid);
5694 if (SUCCEEDED(res)){
5696 res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
5700 res=IPersistStream_Load((IPersistStream*)ppvObj,pStm);
5706 /************************************************************************************************
5709 * This function saves an object with the IPersistStream interface on it to the specified stream
5711 HRESULT WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
5717 TRACE("(%p,%p)\n",pPStm,pStm);
5719 res=IPersistStream_GetClassID(pPStm,&clsid);
5721 if (SUCCEEDED(res)){
5723 res=WriteClassStm(pStm,&clsid);
5727 res=IPersistStream_Save(pPStm,pStm,FALSE);
5733 /****************************************************************************
5734 * This method validate a STGM parameter that can contain the values below
5736 * STGM_DIRECT 0x00000000
5737 * STGM_TRANSACTED 0x00010000
5738 * STGM_SIMPLE 0x08000000
5740 * STGM_READ 0x00000000
5741 * STGM_WRITE 0x00000001
5742 * STGM_READWRITE 0x00000002
5744 * STGM_SHARE_DENY_NONE 0x00000040
5745 * STGM_SHARE_DENY_READ 0x00000030
5746 * STGM_SHARE_DENY_WRITE 0x00000020
5747 * STGM_SHARE_EXCLUSIVE 0x00000010
5749 * STGM_PRIORITY 0x00040000
5750 * STGM_DELETEONRELEASE 0x04000000
5752 * STGM_CREATE 0x00001000
5753 * STGM_CONVERT 0x00020000
5754 * STGM_FAILIFTHERE 0x00000000
5756 * STGM_NOSCRATCH 0x00100000
5757 * STGM_NOSNAPSHOT 0x00200000
5759 static HRESULT validateSTGM(DWORD stgm)
5761 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5762 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5763 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5765 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5766 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5767 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5769 BOOL bSTGM_SHARE_DENY_NONE =
5770 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5772 BOOL bSTGM_SHARE_DENY_READ =
5773 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5775 BOOL bSTGM_SHARE_DENY_WRITE =
5776 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5778 BOOL bSTGM_SHARE_EXCLUSIVE =
5779 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5781 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5782 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5784 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5785 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5788 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5790 if ( ! bSTGM_DIRECT )
5791 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5795 * STGM_WRITE | STGM_READWRITE | STGM_READ
5798 if( bSTGM_WRITE && bSTGM_READWRITE )
5802 * STGM_SHARE_DENY_NONE | others
5803 * (I assume here that DENY_READ implies DENY_WRITE)
5805 if ( bSTGM_SHARE_DENY_NONE )
5806 if ( bSTGM_SHARE_DENY_READ ||
5807 bSTGM_SHARE_DENY_WRITE ||
5808 bSTGM_SHARE_EXCLUSIVE)
5812 * STGM_CREATE | STGM_CONVERT
5813 * if both are false, STGM_FAILIFTHERE is set to TRUE
5815 if ( bSTGM_CREATE && bSTGM_CONVERT )
5819 * STGM_NOSCRATCH requires STGM_TRANSACTED
5821 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5825 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5826 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5828 if (bSTGM_NOSNAPSHOT)
5830 if ( ! ( bSTGM_TRANSACTED &&
5831 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5838 /****************************************************************************
5839 * GetShareModeFromSTGM
5841 * This method will return a share mode flag from a STGM value.
5842 * The STGM value is assumed valid.
5844 static DWORD GetShareModeFromSTGM(DWORD stgm)
5846 DWORD dwShareMode = 0;
5847 BOOL bSTGM_SHARE_DENY_NONE =
5848 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5850 BOOL bSTGM_SHARE_DENY_READ =
5851 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5853 BOOL bSTGM_SHARE_DENY_WRITE =
5854 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5856 BOOL bSTGM_SHARE_EXCLUSIVE =
5857 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5859 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5862 if (bSTGM_SHARE_DENY_NONE)
5863 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5865 if (bSTGM_SHARE_DENY_WRITE)
5866 dwShareMode = FILE_SHARE_READ;
5871 /****************************************************************************
5872 * GetAccessModeFromSTGM
5874 * This method will return an access mode flag from a STGM value.
5875 * The STGM value is assumed valid.
5877 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5879 DWORD dwDesiredAccess = GENERIC_READ;
5880 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5881 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5882 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5885 dwDesiredAccess = GENERIC_READ;
5888 dwDesiredAccess |= GENERIC_WRITE;
5890 if (bSTGM_READWRITE)
5891 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5893 return dwDesiredAccess;
5896 /****************************************************************************
5897 * GetCreationModeFromSTGM
5899 * This method will return a creation mode flag from a STGM value.
5900 * The STGM value is assumed valid.
5902 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5904 if ( stgm & STGM_CREATE)
5905 return CREATE_ALWAYS;
5906 if (stgm & STGM_CONVERT) {
5907 FIXME("STGM_CONVERT not implemented!\n");
5910 /* All other cases */
5911 if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
5912 FIXME("unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
5917 /*************************************************************************
5918 * OLECONVERT_LoadOLE10 [Internal]
5920 * Loads the OLE10 STREAM to memory
5923 * pOleStream [I] The OLESTREAM
5924 * pData [I] Data Structure for the OLESTREAM Data
5928 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
5929 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
5932 * This function is used by OleConvertOLESTREAMToIStorage only.
5934 * Memory allocated for pData must be freed by the caller
5936 HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
5939 HRESULT hRes = S_OK;
5943 pData->pData = NULL;
5944 pData->pstrOleObjFileName = (CHAR *) NULL;
5946 for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
5949 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
5950 if(dwSize != sizeof(pData->dwOleID))
5952 hRes = CONVERT10_E_OLESTREAM_GET;
5954 else if(pData->dwOleID != OLESTREAM_ID)
5956 hRes = CONVERT10_E_OLESTREAM_FMT;
5967 /* Get the TypeID...more info needed for this field */
5968 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
5969 if(dwSize != sizeof(pData->dwTypeID))
5971 hRes = CONVERT10_E_OLESTREAM_GET;
5976 if(pData->dwTypeID != 0)
5978 /* Get the lenght of the OleTypeName */
5979 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
5980 if(dwSize != sizeof(pData->dwOleTypeNameLength))
5982 hRes = CONVERT10_E_OLESTREAM_GET;
5987 if(pData->dwOleTypeNameLength > 0)
5989 /* Get the OleTypeName */
5990 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
5991 if(dwSize != pData->dwOleTypeNameLength)
5993 hRes = CONVERT10_E_OLESTREAM_GET;
5999 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6000 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6002 hRes = CONVERT10_E_OLESTREAM_GET;
6006 if(pData->dwOleObjFileNameLength < 1) //there is no file name exist
6007 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6008 pData->pstrOleObjFileName = (CHAR *)malloc(pData->dwOleObjFileNameLength);
6009 if(pData->pstrOleObjFileName)
6011 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6012 if(dwSize != pData->dwOleObjFileNameLength)
6014 hRes = CONVERT10_E_OLESTREAM_GET;
6018 hRes = CONVERT10_E_OLESTREAM_GET;
6023 /* Get the Width of the Metafile */
6024 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6025 if(dwSize != sizeof(pData->dwMetaFileWidth))
6027 hRes = CONVERT10_E_OLESTREAM_GET;
6031 /* Get the Height of the Metafile */
6032 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6033 if(dwSize != sizeof(pData->dwMetaFileHeight))
6035 hRes = CONVERT10_E_OLESTREAM_GET;
6041 /* Get the Lenght of the Data */
6042 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6043 if(dwSize != sizeof(pData->dwDataLength))
6045 hRes = CONVERT10_E_OLESTREAM_GET;
6049 if(hRes == S_OK) // I don't know what is this 8 byts information is we have to figure out
6051 if(!bStrem1) //if it is a second OLE stream data
6053 pData->dwDataLength -= 8;
6054 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6055 if(dwSize != sizeof(pData->strUnknown))
6057 hRes = CONVERT10_E_OLESTREAM_GET;
6063 if(pData->dwDataLength > 0)
6065 pData->pData = (BYTE *)HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6067 /* Get Data (ex. IStorage, Metafile, or BMP) */
6070 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6071 if(dwSize != pData->dwDataLength)
6073 hRes = CONVERT10_E_OLESTREAM_GET;
6078 hRes = CONVERT10_E_OLESTREAM_GET;
6087 /*************************************************************************
6088 * OLECONVERT_SaveOLE10 [Internal]
6090 * Saves the OLE10 STREAM From memory
6093 * pData [I] Data Structure for the OLESTREAM Data
6094 * pOleStream [I] The OLESTREAM to save
6098 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6101 * This function is used by OleConvertIStorageToOLESTREAM only.
6104 HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6107 HRESULT hRes = S_OK;
6111 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6112 if(dwSize != sizeof(pData->dwOleID))
6114 hRes = CONVERT10_E_OLESTREAM_PUT;
6119 /* Set the TypeID */
6120 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6121 if(dwSize != sizeof(pData->dwTypeID))
6123 hRes = CONVERT10_E_OLESTREAM_PUT;
6127 if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6129 /* Set the Lenght of the OleTypeName */
6130 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6131 if(dwSize != sizeof(pData->dwOleTypeNameLength))
6133 hRes = CONVERT10_E_OLESTREAM_PUT;
6138 if(pData->dwOleTypeNameLength > 0)
6140 /* Set the OleTypeName */
6141 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->strOleTypeName, pData->dwOleTypeNameLength);
6142 if(dwSize != pData->dwOleTypeNameLength)
6144 hRes = CONVERT10_E_OLESTREAM_PUT;
6151 /* Set the width of the Metafile */
6152 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6153 if(dwSize != sizeof(pData->dwMetaFileWidth))
6155 hRes = CONVERT10_E_OLESTREAM_PUT;
6161 /* Set the height of the Metafile */
6162 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6163 if(dwSize != sizeof(pData->dwMetaFileHeight))
6165 hRes = CONVERT10_E_OLESTREAM_PUT;
6171 /* Set the lenght of the Data */
6172 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6173 if(dwSize != sizeof(pData->dwDataLength))
6175 hRes = CONVERT10_E_OLESTREAM_PUT;
6181 if(pData->dwDataLength > 0)
6183 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6184 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->pData, pData->dwDataLength);
6185 if(dwSize != pData->dwDataLength)
6187 hRes = CONVERT10_E_OLESTREAM_PUT;
6195 /*************************************************************************
6196 * OLECONVERT_GetOLE20FromOLE10[Internal]
6198 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6199 * opens it, and copies the content to the dest IStorage for
6200 * OleConvertOLESTREAMToIStorage
6204 * pDestStorage [I] The IStorage to copy the data to
6205 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
6206 * nBufferLength [I] The size of the buffer
6215 void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6219 IStorage *pTempStorage;
6220 DWORD dwNumOfBytesWritten;
6221 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6222 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6224 /* Create a temp File */
6225 GetTempPathW(MAX_PATH, wstrTempDir);
6226 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6227 hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6229 if(hFile != INVALID_HANDLE_VALUE)
6231 /* Write IStorage Data to File */
6232 WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6235 /* Open and copy temp storage to the Dest Storage */
6236 hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6239 hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6240 StorageBaseImpl_Release(pTempStorage);
6242 DeleteFileW(wstrTempFile);
6247 /*************************************************************************
6248 * OLECONVERT_WriteOLE20ToBuffer [Internal]
6250 * Saves the OLE10 STREAM From memory
6253 * pStorage [I] The Src IStorage to copy
6254 * pData [I] The Dest Memory to write to.
6257 * The size in bytes allocated for pData
6260 * Memory allocated for pData must be freed by the caller
6262 * Used by OleConvertIStorageToOLESTREAM only.
6265 DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6269 DWORD nDataLength = 0;
6270 IStorage *pTempStorage;
6271 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6272 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6276 /* Create temp Storage */
6277 GetTempPathW(MAX_PATH, wstrTempDir);
6278 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6279 hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6283 /* Copy Src Storage to the Temp Storage */
6284 StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6285 StorageBaseImpl_Release(pTempStorage);
6287 /* Open Temp Storage as a file and copy to memory */
6288 hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6289 if(hFile != INVALID_HANDLE_VALUE)
6291 nDataLength = GetFileSize(hFile, NULL);
6292 *pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,nDataLength);
6293 ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6296 DeleteFileW(wstrTempFile);
6301 /*************************************************************************
6302 * OLECONVERT_CreateOleStream [Internal]
6304 * Creates the "\001OLE" stream in the IStorage if neccessary.
6307 * pStorage [I] Dest storage to create the stream in
6313 * This function is used by OleConvertOLESTREAMToIStorage only.
6315 * This stream is still unknown, MS Word seems to have extra data
6316 * but since the data is stored in the OLESTREAM there should be
6317 * no need to recreate the stream. If the stream is manually
6318 * deleted it will create it with this default data.
6321 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6325 WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6326 BYTE pOleStreamHeader [] =
6328 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6330 0x00, 0x00, 0x00, 0x00
6333 /* Create stream if not present */
6334 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6335 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6339 /* Write default Data */
6340 hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6341 IStream_Release(pStream);
6346 /*************************************************************************
6347 * OLECONVERT_CreateCompObjStream [Internal]
6349 * Creates a "\001CompObj" is the destination IStorage if necessary.
6352 * pStorage [I] The dest IStorage to create the CompObj Stream
6354 * strOleTypeName [I] The ProgID
6358 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6361 * This function is used by OleConvertOLESTREAMToIStorage only.
6363 * The stream data is stored in the OLESTREAM and there should be
6364 * no need to recreate the stream. If the stream is manually
6365 * deleted it will attempt to create it by querying the registry.
6369 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
6372 HRESULT hStorageRes, hRes = S_OK;
6373 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
6374 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6376 BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
6377 BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
6379 /* Initialize the CompObj structure */
6380 memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
6381 memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
6382 memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
6385 /* Create a CompObj stream if it doesn't exist */
6386 hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
6387 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6388 if(hStorageRes == S_OK)
6390 /* copy the OleTypeName to the compobj struct */
6391 IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
6392 strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
6394 /* copy the OleTypeName to the compobj struct */
6395 /* Note: in the test made, these where Identical */
6396 IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
6397 strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
6400 hRes = CLSIDFromProgID16(IStorageCompObj.strProgIDName, &(IStorageCompObj.clsid));
6404 hRes = REGDB_E_CLASSNOTREG;
6410 /* Get the CLSID Default Name from the Registry */
6411 hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
6412 if(hErr == ERROR_SUCCESS)
6414 char strTemp[OLESTREAM_MAX_STR_LEN];
6415 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
6416 hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
6417 if(hErr == ERROR_SUCCESS)
6419 strcpy(IStorageCompObj.strCLSIDName, strTemp);
6423 if(hErr != ERROR_SUCCESS)
6425 hRes = REGDB_E_CLASSNOTREG;
6431 /* Write CompObj Structure to stream */
6432 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
6433 hRes = IStream_Write(pStream, &(IStorageCompObj.clsid) , sizeof(IStorageCompObj.clsid ), NULL);
6434 hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
6435 if(IStorageCompObj.dwCLSIDNameLength > 0)
6437 hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
6439 hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
6440 if(IStorageCompObj.dwOleTypeNameLength > 0)
6442 hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
6444 hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
6445 if(IStorageCompObj.dwProgIDNameLength > 0)
6447 hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
6449 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
6451 IStream_Release(pStream);
6457 /*************************************************************************
6458 * OLECONVERT_CreateOlePresStream[Internal]
6460 * Creates the "\002OlePres000" Stream with the Metafile data
6463 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
6464 * dwExtentX [I] Width of the Metafile
6465 * dwExtentY [I] Height of the Metafile
6466 * pData [I] Metafile data
6467 * dwDataLength [I] Size of the Metafile data
6471 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6474 * This function is used by OleConvertOLESTREAMToIStorage only.
6477 void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
6481 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6482 BYTE pOlePresStreamHeader [] =
6484 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
6485 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6486 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6487 0x00, 0x00, 0x00, 0x00
6490 BYTE pOlePresStreamHeaderEmpty [] =
6492 0x00, 0x00, 0x00, 0x00,
6493 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6494 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6495 0x00, 0x00, 0x00, 0x00
6498 /* Create the OlePres000 Stream */
6499 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6500 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6505 OLECONVERT_ISTORAGE_OLEPRES OlePres;
6507 memset(&OlePres, 0, sizeof(OlePres));
6508 /* Do we have any metafile data to save */
6509 if(dwDataLength > 0)
6511 memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
6512 nHeaderSize = sizeof(pOlePresStreamHeader);
6516 memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
6517 nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
6519 /* Set width and height of the metafile */
6520 OlePres.dwExtentX = dwExtentX;
6521 OlePres.dwExtentY = -dwExtentY;
6523 /* Set Data and Lenght */
6524 if(dwDataLength > sizeof(METAFILEPICT16))
6526 OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
6527 OlePres.pData = &(pData[8]);
6529 /* Save OlePres000 Data to Stream */
6530 hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
6531 hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
6532 hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
6533 hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
6534 if(OlePres.dwSize > 0)
6536 hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
6538 IStream_Release(pStream);
6542 /*************************************************************************
6543 * OLECONVERT_CreateOle10NativeStream [Internal]
6545 * Creates the "\001Ole10Native" Stream (should contain a BMP)
6548 * pStorage [I] Dest storage to create the stream in
6549 * pData [I] Ole10 Native Data (ex. bmp)
6550 * dwDataLength [I] Size of the Ole10 Native Data
6556 * This function is used by OleConvertOLESTREAMToIStorage only.
6558 * Might need to verify the data and return appropriate error message
6561 void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
6565 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6567 /* Create the Ole10Native Stream */
6568 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6569 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6573 /* Write info to stream */
6574 hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
6575 hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
6576 IStream_Release(pStream);
6581 /*************************************************************************
6582 * OLECONVERT_GetOLE10ProgID [Internal]
6584 * Finds the ProgID (or OleTypeID) from the IStorage
6587 * pStorage [I] The Src IStorage to get the ProgID
6588 * strProgID [I] the ProgID string to get
6589 * dwSize [I] the size of the string
6593 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6596 * This function is used by OleConvertIStorageToOLESTREAM only.
6600 HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
6604 LARGE_INTEGER iSeekPos;
6605 OLECONVERT_ISTORAGE_COMPOBJ CompObj;
6606 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6608 /* Open the CompObj Stream */
6609 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6610 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6614 /*Get the OleType from the CompObj Stream */
6615 iSeekPos.s.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
6616 iSeekPos.s.HighPart = 0;
6618 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6619 IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
6620 iSeekPos.s.LowPart = CompObj.dwCLSIDNameLength;
6621 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6622 IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
6623 iSeekPos.s.LowPart = CompObj.dwOleTypeNameLength;
6624 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6626 IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
6629 IStream_Read(pStream, strProgID, *dwSize, NULL);
6631 IStream_Release(pStream);
6636 LPOLESTR wstrProgID;
6638 /* Get the OleType from the registry */
6639 REFCLSID clsid = &(stat.clsid);
6640 IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
6641 hRes = ProgIDFromCLSID(clsid, &wstrProgID);
6644 *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
6651 /*************************************************************************
6652 * OLECONVERT_GetOle10PresData [Internal]
6654 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
6657 * pStorage [I] Src IStroage
6658 * pOleStream [I] Dest OleStream Mem Struct
6664 * This function is used by OleConvertIStorageToOLESTREAM only.
6666 * Memory allocated for pData must be freed by the caller
6670 void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6675 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6677 /* Initialize Default data for OLESTREAM */
6678 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6679 pOleStreamData[0].dwTypeID = 2;
6680 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6681 pOleStreamData[1].dwTypeID = 0;
6682 pOleStreamData[0].dwMetaFileWidth = 0;
6683 pOleStreamData[0].dwMetaFileHeight = 0;
6684 pOleStreamData[0].pData = NULL;
6685 pOleStreamData[1].pData = NULL;
6687 /* Open Ole10Native Stream */
6688 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6689 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6693 /* Read Size and Data */
6694 IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
6695 if(pOleStreamData->dwDataLength > 0)
6697 pOleStreamData->pData = (LPSTR) HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
6698 IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
6700 IStream_Release(pStream);
6706 /*************************************************************************
6707 * OLECONVERT_GetOle20PresData[Internal]
6709 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
6712 * pStorage [I] Src IStroage
6713 * pOleStreamData [I] Dest OleStream Mem Struct
6719 * This function is used by OleConvertIStorageToOLESTREAM only.
6721 * Memory allocated for pData must be freed by the caller
6723 void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6727 OLECONVERT_ISTORAGE_OLEPRES olePress;
6728 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6730 /* Initialize Default data for OLESTREAM */
6731 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6732 pOleStreamData[0].dwTypeID = 2;
6733 pOleStreamData[0].dwMetaFileWidth = 0;
6734 pOleStreamData[0].dwMetaFileHeight = 0;
6735 pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
6736 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6737 pOleStreamData[1].dwTypeID = 0;
6738 pOleStreamData[1].dwOleTypeNameLength = 0;
6739 pOleStreamData[1].strOleTypeName[0] = 0;
6740 pOleStreamData[1].dwMetaFileWidth = 0;
6741 pOleStreamData[1].dwMetaFileHeight = 0;
6742 pOleStreamData[1].pData = NULL;
6743 pOleStreamData[1].dwDataLength = 0;
6746 /* Open OlePress000 stream */
6747 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6748 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6751 LARGE_INTEGER iSeekPos;
6752 METAFILEPICT16 MetaFilePict;
6753 char strMetafilePictName[] = "METAFILEPICT";
6755 /* Set the TypeID for a Metafile */
6756 pOleStreamData[1].dwTypeID = 5;
6758 /* Set the OleTypeName to Metafile */
6759 pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
6760 strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
6762 iSeekPos.s.HighPart = 0;
6763 iSeekPos.s.LowPart = sizeof(olePress.byUnknown1);
6765 /* Get Presentation Data */
6766 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6767 IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
6768 IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
6769 IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
6771 /*Set width and Height */
6772 pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
6773 pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
6774 if(olePress.dwSize > 0)
6777 pOleStreamData[1].dwDataLength = olePress.dwSize + sizeof(METAFILEPICT16);
6779 /* Set MetaFilePict struct */
6780 MetaFilePict.mm = 8;
6781 MetaFilePict.xExt = olePress.dwExtentX;
6782 MetaFilePict.yExt = olePress.dwExtentY;
6783 MetaFilePict.hMF = 0;
6785 /* Get Metafile Data */
6786 pOleStreamData[1].pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
6787 memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
6788 IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
6790 IStream_Release(pStream);
6794 /*************************************************************************
6795 * OleConvertOLESTREAMToIStorage [OLE32.87]
6800 * DVTARGETDEVICE paramenter is not handled
6801 * Still unsure of some mem fields for OLE 10 Stream
6802 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6803 * and "\001OLE" streams
6806 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
6807 LPOLESTREAM pOleStream,
6809 const DVTARGETDEVICE* ptd)
6813 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6815 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6819 FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
6822 if(pstg == NULL || pOleStream == NULL)
6824 hRes = E_INVALIDARG;
6829 /* Load the OLESTREAM to Memory */
6830 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
6835 /* Load the OLESTREAM to Memory (part 2)*/
6836 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
6842 if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
6844 /* Do we have the IStorage Data in the OLESTREAM */
6845 if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
6847 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6848 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
6852 /* It must be an original OLE 1.0 source */
6853 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6858 /* It must be an original OLE 1.0 source */
6859 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6862 /* Create CompObj Stream if necessary */
6863 hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
6866 /*Create the Ole Stream if necessary */
6867 OLECONVERT_CreateOleStream(pstg);
6872 /* Free allocated memory */
6873 for(i=0; i < 2; i++)
6875 if(pOleStreamData[i].pData != NULL)
6877 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
6879 if(pOleStreamData[i].pstrOleObjFileName != NULL)
6881 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
6882 pOleStreamData[i].pstrOleObjFileName = NULL;
6888 /*************************************************************************
6889 * OleConvertIStorageToOLESTREAM [OLE32.85]
6896 * Still unsure of some mem fields for OLE 10 Stream
6897 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6898 * and "\001OLE" streams.
6901 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
6903 LPOLESTREAM pOleStream)
6906 HRESULT hRes = S_OK;
6908 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6909 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6912 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6914 if(pstg == NULL || pOleStream == NULL)
6916 hRes = E_INVALIDARG;
6920 /* Get the ProgID */
6921 pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
6922 hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
6926 /*Was it originaly Ole10 */
6927 hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
6930 IStream_Release(pStream);
6931 /*Get Presentation Data for Ole10Native */
6932 OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
6936 /*Get Presentation Data (OLE20)*/
6937 OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
6940 /* Save OLESTREAM */
6941 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
6944 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
6949 /* Free allocated memory */
6950 for(i=0; i < 2; i++)
6952 if(pOleStreamData[i].pData != NULL)
6954 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);