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 <ole32/ole32.h>
19 #include <storage32.h>
25 /* From wingdi16.h of WINE */
27 typedef HANDLE HMETAFILE16;
35 } METAFILEPICT16, *LPMETAFILEPICT16;
39 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
40 #define OLESTREAM_ID 0x501
41 #define OLESTREAM_MAX_STR_LEN 255
43 static const char rootPropertyName[] = "Root Entry";
46 /* OLESTREAM memory structure to use for Get and Put Routines */
47 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
52 DWORD dwOleTypeNameLength;
53 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
54 CHAR *pstrOleObjFileName;
55 DWORD dwOleObjFileNameLength;
56 DWORD dwMetaFileWidth;
57 DWORD dwMetaFileHeight;
58 CHAR strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */
61 }OLECONVERT_OLESTREAM_DATA;
63 /* CompObj Stream structure */
64 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
69 DWORD dwCLSIDNameLength;
70 CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
71 DWORD dwOleTypeNameLength;
72 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
73 DWORD dwProgIDNameLength;
74 CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
76 }OLECONVERT_ISTORAGE_COMPOBJ;
79 /* Ole Presention Stream structure */
80 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
88 }OLECONVERT_ISTORAGE_OLEPRES;
92 /***********************************************************************
93 * Forward declaration of internal functions used by the method DestroyElement
95 static HRESULT deleteStorageProperty(
96 StorageImpl *parentStorage,
97 ULONG foundPropertyIndexToDelete,
98 StgProperty propertyToDelete);
100 static HRESULT deleteStreamProperty(
101 StorageImpl *parentStorage,
102 ULONG foundPropertyIndexToDelete,
103 StgProperty propertyToDelete);
105 static HRESULT findPlaceholder(
106 StorageImpl *storage,
107 ULONG propertyIndexToStore,
108 ULONG storagePropertyIndex,
111 static HRESULT adjustPropertyChain(
113 StgProperty propertyToDelete,
114 StgProperty parentProperty,
115 ULONG parentPropertyId,
118 /***********************************************************************
119 * Declaration of the functions used to manipulate StgProperty
122 static ULONG getFreeProperty(
123 StorageImpl *storage);
125 static void updatePropertyChain(
126 StorageImpl *storage,
127 ULONG newPropertyIndex,
128 StgProperty newProperty);
130 static LONG propertyNameCmp(
131 OLECHAR *newProperty,
132 OLECHAR *currentProperty);
135 /***********************************************************************
136 * Declaration of miscellaneous functions...
138 static HRESULT validateSTGM(DWORD stgmValue);
140 static DWORD GetShareModeFromSTGM(DWORD stgm);
141 static DWORD GetAccessModeFromSTGM(DWORD stgm);
142 static DWORD GetCreationModeFromSTGM(DWORD stgm);
145 * Virtual function table for the IStorage32Impl class.
147 static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
149 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
150 StorageBaseImpl_QueryInterface,
151 StorageBaseImpl_AddRef,
152 StorageBaseImpl_Release,
153 StorageBaseImpl_CreateStream,
154 StorageBaseImpl_OpenStream,
155 StorageImpl_CreateStorage,
156 StorageBaseImpl_OpenStorage,
158 StorageImpl_MoveElementTo,
161 StorageBaseImpl_EnumElements,
162 StorageImpl_DestroyElement,
163 StorageBaseImpl_RenameElement,
164 StorageImpl_SetElementTimes,
165 StorageBaseImpl_SetClass,
166 StorageImpl_SetStateBits,
171 * Virtual function table for the Storage32InternalImpl class.
173 static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
175 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
176 StorageBaseImpl_QueryInterface,
177 StorageBaseImpl_AddRef,
178 StorageBaseImpl_Release,
179 StorageBaseImpl_CreateStream,
180 StorageBaseImpl_OpenStream,
181 StorageImpl_CreateStorage,
182 StorageBaseImpl_OpenStorage,
184 StorageImpl_MoveElementTo,
185 StorageInternalImpl_Commit,
186 StorageInternalImpl_Revert,
187 StorageBaseImpl_EnumElements,
188 StorageImpl_DestroyElement,
189 StorageBaseImpl_RenameElement,
190 StorageImpl_SetElementTimes,
191 StorageBaseImpl_SetClass,
192 StorageImpl_SetStateBits,
197 * Virtual function table for the IEnumSTATSTGImpl class.
199 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
201 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
202 IEnumSTATSTGImpl_QueryInterface,
203 IEnumSTATSTGImpl_AddRef,
204 IEnumSTATSTGImpl_Release,
205 IEnumSTATSTGImpl_Next,
206 IEnumSTATSTGImpl_Skip,
207 IEnumSTATSTGImpl_Reset,
208 IEnumSTATSTGImpl_Clone
215 /************************************************************************
216 ** Storage32BaseImpl implementatiion
219 /************************************************************************
220 * Storage32BaseImpl_QueryInterface (IUnknown)
222 * This method implements the common QueryInterface for all IStorage32
223 * implementations contained in this file.
225 * See Windows documentation for more details on IUnknown methods.
227 HRESULT WINAPI StorageBaseImpl_QueryInterface(
232 ICOM_THIS(StorageBaseImpl,iface);
234 * Perform a sanity check on the parameters.
236 if ( (This==0) || (ppvObject==0) )
240 * Initialize the return parameter.
245 * Compare the riid with the interface IDs implemented by this object.
247 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
249 *ppvObject = (IStorage*)This;
251 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
253 *ppvObject = (IStorage*)This;
257 * Check that we obtained an interface.
260 return E_NOINTERFACE;
263 * Query Interface always increases the reference count by one when it is
266 StorageBaseImpl_AddRef(iface);
271 /************************************************************************
272 * Storage32BaseImpl_AddRef (IUnknown)
274 * This method implements the common AddRef for all IStorage32
275 * implementations contained in this file.
277 * See Windows documentation for more details on IUnknown methods.
279 ULONG WINAPI StorageBaseImpl_AddRef(
282 ICOM_THIS(StorageBaseImpl,iface);
288 /************************************************************************
289 * Storage32BaseImpl_Release (IUnknown)
291 * This method implements the common Release for all IStorage32
292 * implementations contained in this file.
294 * See Windows documentation for more details on IUnknown methods.
296 ULONG WINAPI StorageBaseImpl_Release(
299 ICOM_THIS(StorageBaseImpl,iface);
301 * Decrease the reference count on this object.
306 * If the reference count goes down to 0, perform suicide.
311 * Since we are using a system of base-classes, we want to call the
312 * destructor of the appropriate derived class. To do this, we are
313 * using virtual functions to implement the destructor.
315 This->v_destructor(This);
323 /************************************************************************
324 * Storage32BaseImpl_OpenStream (IStorage)
326 * This method will open the specified stream object from the current storage.
328 * See Windows documentation for more details on IStorage methods.
330 HRESULT WINAPI StorageBaseImpl_OpenStream(
332 const OLECHAR* pwcsName, /* [string][in] */
333 void* reserved1, /* [unique][in] */
334 DWORD grfMode, /* [in] */
335 DWORD reserved2, /* [in] */
336 IStream** ppstm) /* [out] */
338 ICOM_THIS(StorageBaseImpl,iface);
339 IEnumSTATSTGImpl* propertyEnumeration;
340 StgStreamImpl* newStream;
341 StgProperty currentProperty;
342 ULONG foundPropertyIndex;
344 Print(MAX_TRACE, ("(%p, %S, %p, %lx, %ld, %p)\n",
345 iface, pwcsName, reserved1, grfMode, reserved2, ppstm));
348 * Perform a sanity check on the parameters.
350 if ( (pwcsName==NULL) || (ppstm==0) )
354 * Initialize the out parameter
359 * Validate the STGM flags
361 if ( FAILED( validateSTGM(grfMode) ))
362 return STG_E_INVALIDFLAG;
367 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
368 (grfMode & STGM_DELETEONRELEASE) ||
369 (grfMode & STGM_TRANSACTED) )
370 return STG_E_INVALIDFUNCTION;
373 * Create a property enumeration to search the properties
375 propertyEnumeration = IEnumSTATSTGImpl_Construct(
376 This->ancestorStorage,
377 This->rootPropertySetIndex);
380 * Search the enumeration for the property with the given name
382 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
388 * Delete the property enumeration since we don't need it anymore
390 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
393 * If it was found, construct the stream object and return a pointer to it.
395 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
396 (currentProperty.propertyType==PROPTYPE_STREAM) )
398 newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
402 newStream->grfMode = grfMode;
403 *ppstm = (IStream*)newStream;
406 * Since we are returning a pointer to the interface, we have to
407 * nail down the reference.
409 StgStreamImpl_AddRef(*ppstm);
414 return E_OUTOFMEMORY;
417 return STG_E_FILENOTFOUND;
420 /************************************************************************
421 * Storage32BaseImpl_OpenStorage (IStorage)
423 * This method will open a new storage object from the current storage.
425 * See Windows documentation for more details on IStorage methods.
427 HRESULT WINAPI StorageBaseImpl_OpenStorage(
429 const OLECHAR* pwcsName, /* [string][unique][in] */
430 IStorage* pstgPriority, /* [unique][in] */
431 DWORD grfMode, /* [in] */
432 SNB snbExclude, /* [unique][in] */
433 DWORD reserved, /* [in] */
434 IStorage** ppstg) /* [out] */
436 ICOM_THIS(StorageBaseImpl,iface);
437 StorageInternalImpl* newStorage;
438 IEnumSTATSTGImpl* propertyEnumeration;
439 StgProperty currentProperty;
440 ULONG foundPropertyIndex;
442 Print(MAX_TRACE, ("(%p, %S, %p, %lx, %p, %ld, %p)\n",
443 iface, pwcsName, pstgPriority,
444 grfMode, snbExclude, reserved, ppstg));
447 * Perform a sanity check on the parameters.
449 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
453 * Validate the STGM flags
455 if ( FAILED( validateSTGM(grfMode) ))
456 return STG_E_INVALIDFLAG;
461 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
462 (grfMode & STGM_DELETEONRELEASE) ||
463 (grfMode & STGM_PRIORITY) )
464 return STG_E_INVALIDFUNCTION;
467 * Initialize the out parameter
472 * Create a property enumeration to search the properties
474 propertyEnumeration = IEnumSTATSTGImpl_Construct(
475 This->ancestorStorage,
476 This->rootPropertySetIndex);
479 * Search the enumeration for the property with the given name
481 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
487 * Delete the property enumeration since we don't need it anymore
489 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
492 * If it was found, construct the stream object and return a pointer to it.
494 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
495 (currentProperty.propertyType==PROPTYPE_STORAGE) )
498 * Construct a new Storage object
500 newStorage = StorageInternalImpl_Construct(
501 This->ancestorStorage,
506 *ppstg = (IStorage*)newStorage;
509 * Since we are returning a pointer to the interface,
510 * we have to nail down the reference.
512 StorageBaseImpl_AddRef(*ppstg);
517 return STG_E_INSUFFICIENTMEMORY;
520 return STG_E_FILENOTFOUND;
523 /************************************************************************
524 * Storage32BaseImpl_EnumElements (IStorage)
526 * This method will create an enumerator object that can be used to
527 * retrieve informatino about all the properties in the storage object.
529 * See Windows documentation for more details on IStorage methods.
531 HRESULT WINAPI StorageBaseImpl_EnumElements(
533 DWORD reserved1, /* [in] */
534 void* reserved2, /* [size_is][unique][in] */
535 DWORD reserved3, /* [in] */
536 IEnumSTATSTG** ppenum) /* [out] */
538 ICOM_THIS(StorageBaseImpl,iface);
539 IEnumSTATSTGImpl* newEnum;
541 Print(MAX_TRACE, ("(%p, %ld, %p, %ld, %p)\n",
542 iface, reserved1, reserved2, reserved3, ppenum));
545 * Perform a sanity check on the parameters.
547 if ( (This==0) || (ppenum==0))
551 * Construct the enumerator.
553 newEnum = IEnumSTATSTGImpl_Construct(
554 This->ancestorStorage,
555 This->rootPropertySetIndex);
559 *ppenum = (IEnumSTATSTG*)newEnum;
562 * Don't forget to nail down a reference to the new object before
565 IEnumSTATSTGImpl_AddRef(*ppenum);
570 return E_OUTOFMEMORY;
573 /************************************************************************
574 * Storage32BaseImpl_Stat (IStorage)
576 * This method will retrieve information about this storage object.
578 * See Windows documentation for more details on IStorage methods.
580 HRESULT WINAPI StorageBaseImpl_Stat(
582 STATSTG* pstatstg, /* [out] */
583 DWORD grfStatFlag) /* [in] */
585 ICOM_THIS(StorageBaseImpl,iface);
586 StgProperty curProperty;
589 Print(MAX_TRACE, ("(%p, %p, %lx)\n",
590 iface, pstatstg, grfStatFlag));
593 * Perform a sanity check on the parameters.
595 if ( (This==0) || (pstatstg==0))
599 * Read the information from the property.
601 readSuccessful = StorageImpl_ReadProperty(
602 This->ancestorStorage,
603 This->rootPropertySetIndex,
608 StorageUtl_CopyPropertyToSTATSTG(
619 /************************************************************************
620 * Storage32BaseImpl_RenameElement (IStorage)
622 * This method will rename the specified element.
624 * See Windows documentation for more details on IStorage methods.
626 * Implementation notes: The method used to rename consists of creating a clone
627 * of the deleted StgProperty object setting it with the new name and to
628 * perform a DestroyElement of the old StgProperty.
630 HRESULT WINAPI StorageBaseImpl_RenameElement(
632 const OLECHAR* pwcsOldName, /* [in] */
633 const OLECHAR* pwcsNewName) /* [in] */
635 ICOM_THIS(StorageBaseImpl,iface);
636 IEnumSTATSTGImpl* propertyEnumeration;
637 StgProperty currentProperty;
638 ULONG foundPropertyIndex;
640 Print(MAX_TRACE, ("(%p, %S, %S)\n",
641 iface, pwcsOldName, pwcsNewName));
644 * Create a property enumeration to search the properties
646 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
647 This->rootPropertySetIndex);
650 * Search the enumeration for the new property name
652 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
656 if (foundPropertyIndex != PROPERTY_NULL)
659 * There is already a property with the new name
661 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
662 return STG_E_FILEALREADYEXISTS;
665 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
668 * Search the enumeration for the old property name
670 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
675 * Delete the property enumeration since we don't need it anymore
677 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
679 if (foundPropertyIndex != PROPERTY_NULL)
681 StgProperty renamedProperty;
682 ULONG renamedPropertyIndex;
685 * Setup a new property for the renamed property
687 renamedProperty.sizeOfNameString =
688 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
690 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
691 return STG_E_INVALIDNAME;
693 lstrcpyW(renamedProperty.name, pwcsNewName);
695 renamedProperty.propertyType = currentProperty.propertyType;
696 renamedProperty.startingBlock = currentProperty.startingBlock;
697 renamedProperty.size.u.LowPart = currentProperty.size.u.LowPart;
698 renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart;
700 renamedProperty.previousProperty = PROPERTY_NULL;
701 renamedProperty.nextProperty = PROPERTY_NULL;
704 * Bring the dirProperty link in case it is a storage and in which
705 * case the renamed storage elements don't require to be reorganized.
707 renamedProperty.dirProperty = currentProperty.dirProperty;
709 /* call CoFileTime to get the current time
710 renamedProperty.timeStampS1
711 renamedProperty.timeStampD1
712 renamedProperty.timeStampS2
713 renamedProperty.timeStampD2
714 renamedProperty.propertyUniqueID
718 * Obtain a free property in the property chain
720 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
723 * Save the new property into the new property spot
725 StorageImpl_WriteProperty(
726 This->ancestorStorage,
727 renamedPropertyIndex,
731 * Find a spot in the property chain for our newly created property.
735 renamedPropertyIndex,
739 * At this point the renamed property has been inserted in the tree,
740 * now, before to Destroy the old property we must zeroed it's dirProperty
741 * otherwise the DestroyProperty below will zap it all and we do not want
743 * Also, we fake that the old property is a storage so the DestroyProperty
744 * will not do a SetSize(0) on the stream data.
746 * This means that we need to tweek the StgProperty if it is a stream or a
749 StorageImpl_ReadProperty(This->ancestorStorage,
753 currentProperty.dirProperty = PROPERTY_NULL;
754 currentProperty.propertyType = PROPTYPE_STORAGE;
755 StorageImpl_WriteProperty(
756 This->ancestorStorage,
761 * Invoke Destroy to get rid of the ole property and automatically redo
762 * the linking of it's previous and next members...
764 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
770 * There is no property with the old name
772 return STG_E_FILENOTFOUND;
778 /************************************************************************
779 * Storage32BaseImpl_CreateStream (IStorage)
781 * This method will create a stream object within this storage
783 * See Windows documentation for more details on IStorage methods.
785 HRESULT WINAPI StorageBaseImpl_CreateStream(
787 const OLECHAR* pwcsName, /* [string][in] */
788 DWORD grfMode, /* [in] */
789 DWORD reserved1, /* [in] */
790 DWORD reserved2, /* [in] */
791 IStream** ppstm) /* [out] */
793 ICOM_THIS(StorageBaseImpl,iface);
794 IEnumSTATSTGImpl* propertyEnumeration;
795 StgStreamImpl* newStream;
796 StgProperty currentProperty, newStreamProperty;
797 ULONG foundPropertyIndex, newPropertyIndex;
799 Print(MAX_TRACE, ("(%p, %S, %lx, %ld, %ld, %p)\n",
800 iface, pwcsName, grfMode,
801 reserved1, reserved2, ppstm));
804 * Validate parameters
807 return STG_E_INVALIDPOINTER;
810 return STG_E_INVALIDNAME;
813 * Validate the STGM flags
815 if ( FAILED( validateSTGM(grfMode) ))
816 return STG_E_INVALIDFLAG;
821 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
822 (grfMode & STGM_DELETEONRELEASE) ||
823 (grfMode & STGM_TRANSACTED) )
824 return STG_E_INVALIDFUNCTION;
827 * Initialize the out parameter
832 * Create a property enumeration to search the properties
834 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
835 This->rootPropertySetIndex);
837 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
841 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
843 if (foundPropertyIndex != PROPERTY_NULL)
846 * An element with this name already exists
848 if (grfMode & STGM_CREATE)
850 IStorage_DestroyElement(iface, pwcsName);
853 return STG_E_FILEALREADYEXISTS;
857 * memset the empty property
859 memset(&newStreamProperty, 0, sizeof(StgProperty));
861 newStreamProperty.sizeOfNameString =
862 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
864 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
865 return STG_E_INVALIDNAME;
867 lstrcpyW(newStreamProperty.name, pwcsName);
869 newStreamProperty.propertyType = PROPTYPE_STREAM;
870 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
871 newStreamProperty.size.u.LowPart = 0;
872 newStreamProperty.size.u.HighPart = 0;
874 newStreamProperty.previousProperty = PROPERTY_NULL;
875 newStreamProperty.nextProperty = PROPERTY_NULL;
876 newStreamProperty.dirProperty = PROPERTY_NULL;
878 /* call CoFileTime to get the current time
879 newStreamProperty.timeStampS1
880 newStreamProperty.timeStampD1
881 newStreamProperty.timeStampS2
882 newStreamProperty.timeStampD2
885 /* newStreamProperty.propertyUniqueID */
888 * Get a free property or create a new one
890 newPropertyIndex = getFreeProperty(This->ancestorStorage);
893 * Save the new property into the new property spot
895 StorageImpl_WriteProperty(
896 This->ancestorStorage,
901 * Find a spot in the property chain for our newly created property.
909 * Open the stream to return it.
911 newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
915 *ppstm = (IStream*)newStream;
918 * Since we are returning a pointer to the interface, we have to nail down
921 StgStreamImpl_AddRef(*ppstm);
925 return STG_E_INSUFFICIENTMEMORY;
931 /************************************************************************
932 * Storage32BaseImpl_SetClass (IStorage)
934 * This method will write the specified CLSID in the property of this
937 * See Windows documentation for more details on IStorage methods.
939 HRESULT WINAPI StorageBaseImpl_SetClass(
941 REFCLSID clsid) /* [in] */
943 ICOM_THIS(StorageBaseImpl,iface);
944 HRESULT hRes = E_FAIL;
945 StgProperty curProperty;
948 Print(MAX_TRACE, ("(%p, %p)\n", iface, clsid));
950 success = StorageImpl_ReadProperty(This->ancestorStorage,
951 This->rootPropertySetIndex,
955 curProperty.propertyUniqueID = *clsid;
957 success = StorageImpl_WriteProperty(This->ancestorStorage,
958 This->rootPropertySetIndex,
967 /************************************************************************
968 ** Storage32Impl implementation
971 /************************************************************************
972 * Storage32Impl_CreateStorage (IStorage)
974 * This method will create the storage object within the provided storage.
976 * See Windows documentation for more details on IStorage methods.
978 HRESULT WINAPI StorageImpl_CreateStorage(
980 const OLECHAR *pwcsName, /* [string][in] */
981 DWORD grfMode, /* [in] */
982 DWORD reserved1, /* [in] */
983 DWORD reserved2, /* [in] */
984 IStorage **ppstg) /* [out] */
986 StorageImpl* const This=(StorageImpl*)iface;
988 IEnumSTATSTGImpl *propertyEnumeration;
989 StgProperty currentProperty;
990 StgProperty newProperty;
991 ULONG foundPropertyIndex;
992 ULONG newPropertyIndex;
995 Print(MAX_TRACE, ("(%p, %S, %lx, %ld, %ld, %p)\n",
996 iface, pwcsName, grfMode,
997 reserved1, reserved2, ppstg));
1000 * Validate parameters
1003 return STG_E_INVALIDPOINTER;
1006 return STG_E_INVALIDNAME;
1009 * Validate the STGM flags
1011 if ( FAILED( validateSTGM(grfMode) ) ||
1012 (grfMode & STGM_DELETEONRELEASE) )
1013 return STG_E_INVALIDFLAG;
1016 * Initialize the out parameter
1021 * Create a property enumeration and search the properties
1023 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
1024 This->rootPropertySetIndex);
1026 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1029 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1031 if (foundPropertyIndex != PROPERTY_NULL)
1034 * An element with this name already exists
1036 if (grfMode & STGM_CREATE)
1037 IStorage_DestroyElement(iface, pwcsName);
1039 return STG_E_FILEALREADYEXISTS;
1043 * memset the empty property
1045 memset(&newProperty, 0, sizeof(StgProperty));
1047 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1049 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1050 return STG_E_INVALIDNAME;
1052 lstrcpyW(newProperty.name, pwcsName);
1054 newProperty.propertyType = PROPTYPE_STORAGE;
1055 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
1056 newProperty.size.u.LowPart = 0;
1057 newProperty.size.u.HighPart = 0;
1059 newProperty.previousProperty = PROPERTY_NULL;
1060 newProperty.nextProperty = PROPERTY_NULL;
1061 newProperty.dirProperty = PROPERTY_NULL;
1063 /* call CoFileTime to get the current time
1064 newProperty.timeStampS1
1065 newProperty.timeStampD1
1066 newProperty.timeStampS2
1067 newProperty.timeStampD2
1070 /* newStorageProperty.propertyUniqueID */
1073 * Obtain a free property in the property chain
1075 newPropertyIndex = getFreeProperty(This->ancestorStorage);
1078 * Save the new property into the new property spot
1080 StorageImpl_WriteProperty(
1081 This->ancestorStorage,
1086 * Find a spot in the property chain for our newly created property.
1088 updatePropertyChain(
1094 * Open it to get a pointer to return.
1096 hr = IStorage_OpenStorage(
1105 if( (hr != S_OK) || (*ppstg == NULL))
1115 /***************************************************************************
1119 * Get a free property or create a new one.
1121 static ULONG getFreeProperty(
1122 StorageImpl *storage)
1124 ULONG currentPropertyIndex = 0;
1125 ULONG newPropertyIndex = PROPERTY_NULL;
1126 BOOL readSuccessful = TRUE;
1127 StgProperty currentProperty;
1132 * Start by reading the root property
1134 readSuccessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1135 currentPropertyIndex,
1139 if (currentProperty.sizeOfNameString == 0)
1142 * The property existis and is available, we found it.
1144 newPropertyIndex = currentPropertyIndex;
1150 * We exhausted the property list, we will create more space below
1152 newPropertyIndex = currentPropertyIndex;
1154 currentPropertyIndex++;
1156 } while (newPropertyIndex == PROPERTY_NULL);
1159 * grow the property chain
1161 if (! readSuccessful)
1163 StgProperty emptyProperty;
1164 ULARGE_INTEGER newSize;
1165 ULONG propertyIndex;
1166 ULONG lastProperty = 0;
1167 ULONG blockCount = 0;
1170 * obtain the new count of property blocks
1172 blockCount = BlockChainStream_GetCount(
1173 storage->ancestorStorage->rootBlockChain)+1;
1176 * initialize the size used by the property stream
1178 newSize.u.HighPart = 0;
1179 newSize.u.LowPart = storage->bigBlockSize * blockCount;
1182 * add a property block to the property chain
1184 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1187 * memset the empty property in order to initialize the unused newly
1190 memset(&emptyProperty, 0, sizeof(StgProperty));
1195 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1198 propertyIndex = newPropertyIndex;
1199 propertyIndex < lastProperty;
1202 StorageImpl_WriteProperty(
1203 storage->ancestorStorage,
1209 return newPropertyIndex;
1212 /****************************************************************************
1216 * Case insensitive comparaison of StgProperty.name by first considering
1219 * Returns <0 when newPrpoerty < currentProperty
1220 * >0 when newPrpoerty > currentProperty
1221 * 0 when newPrpoerty == currentProperty
1223 static LONG propertyNameCmp(
1224 OLECHAR *newProperty,
1225 OLECHAR *currentProperty)
1227 LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty);
1232 * We compare the string themselves only when they are of the same lenght
1234 diff = lstrcmpiW( newProperty, currentProperty);
1240 /****************************************************************************
1244 * Properly link this new element in the property chain.
1246 static void updatePropertyChain(
1247 StorageImpl *storage,
1248 ULONG newPropertyIndex,
1249 StgProperty newProperty)
1251 StgProperty currentProperty;
1254 * Read the root property
1256 StorageImpl_ReadProperty(storage->ancestorStorage,
1257 storage->rootPropertySetIndex,
1260 if (currentProperty.dirProperty != PROPERTY_NULL)
1263 * The root storage contains some element, therefore, start the research
1264 * for the appropriate location.
1267 ULONG current, next, previous, currentPropertyId;
1270 * Keep the StgProperty sequence number of the storage first property
1272 currentPropertyId = currentProperty.dirProperty;
1277 StorageImpl_ReadProperty(storage->ancestorStorage,
1278 currentProperty.dirProperty,
1281 previous = currentProperty.previousProperty;
1282 next = currentProperty.nextProperty;
1283 current = currentPropertyId;
1287 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1291 if (previous != PROPERTY_NULL)
1293 StorageImpl_ReadProperty(storage->ancestorStorage,
1300 currentProperty.previousProperty = newPropertyIndex;
1301 StorageImpl_WriteProperty(storage->ancestorStorage,
1309 if (next != PROPERTY_NULL)
1311 StorageImpl_ReadProperty(storage->ancestorStorage,
1318 currentProperty.nextProperty = newPropertyIndex;
1319 StorageImpl_WriteProperty(storage->ancestorStorage,
1328 * Trying to insert an item with the same name in the
1329 * subtree structure.
1334 previous = currentProperty.previousProperty;
1335 next = currentProperty.nextProperty;
1341 * The root storage is empty, link the new property to it's dir property
1343 currentProperty.dirProperty = newPropertyIndex;
1344 StorageImpl_WriteProperty(storage->ancestorStorage,
1345 storage->rootPropertySetIndex,
1351 /*************************************************************************
1354 HRESULT WINAPI StorageImpl_CopyTo(
1356 DWORD ciidExclude, /* [in] */
1357 const IID* rgiidExclude, /* [size_is][unique][in] */
1358 SNB snbExclude, /* [unique][in] */
1359 IStorage* pstgDest) /* [unique][in] */
1361 IEnumSTATSTG *elements = 0;
1362 STATSTG curElement, strStat;
1364 IStorage *pstgTmp, *pstgChild;
1365 IStream *pstrTmp, *pstrChild;
1367 if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
1370 Print(MAX_TRACE, ("(%p, %ld, %p, %p, %p)\n",
1371 iface, ciidExclude, rgiidExclude,
1372 snbExclude, pstgDest));
1375 * Perform a sanity check
1377 if ( pstgDest == 0 )
1378 return STG_E_INVALIDPOINTER;
1381 * Enumerate the elements
1383 hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1391 IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1392 IStorage_SetClass( pstgDest, &curElement.clsid );
1397 * Obtain the next element
1399 hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1401 if ( hr == S_FALSE )
1403 hr = S_OK; /* done, every element has been copied */
1407 if (curElement.type == STGTY_STORAGE)
1410 * open child source storage
1412 hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1413 STGM_READ|STGM_SHARE_EXCLUSIVE,
1414 NULL, 0, &pstgChild );
1420 * Check if destination storage is not a child of the source
1421 * storage, which will cause an infinite loop
1423 if (pstgChild == pstgDest)
1425 IEnumSTATSTG_Release(elements);
1427 return STG_E_ACCESSDENIED;
1431 * create a new storage in destination storage
1433 hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1434 STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1438 * if it already exist, don't create a new one use this one
1440 if (hr == STG_E_FILEALREADYEXISTS)
1442 hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1443 STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1444 NULL, 0, &pstgTmp );
1452 * do the copy recursively
1454 hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1455 snbExclude, pstgTmp );
1457 IStorage_Release( pstgTmp );
1458 IStorage_Release( pstgChild );
1460 else if (curElement.type == STGTY_STREAM)
1463 * create a new stream in destination storage. If the stream already
1464 * exist, it will be deleted and a new one will be created.
1466 hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1467 STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1474 * open child stream storage
1476 hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
1477 STGM_READ|STGM_SHARE_EXCLUSIVE,
1484 * Get the size of the source stream
1486 IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1489 * Set the size of the destination stream.
1491 IStream_SetSize(pstrTmp, strStat.cbSize);
1496 hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1499 IStream_Release( pstrTmp );
1500 IStream_Release( pstrChild );
1504 Print(MIN_TRACE, ("unknown element type: %ld\n", curElement.type));
1507 } while (hr == S_OK);
1512 IEnumSTATSTG_Release(elements);
1517 /*************************************************************************
1518 * MoveElementTo (IStorage)
1520 HRESULT WINAPI StorageImpl_MoveElementTo(
1522 const OLECHAR *pwcsName, /* [string][in] */
1523 IStorage *pstgDest, /* [unique][in] */
1524 const OLECHAR *pwcsNewName,/* [string][in] */
1525 DWORD grfFlags) /* [in] */
1531 /*************************************************************************
1534 HRESULT WINAPI StorageImpl_Commit(
1536 DWORD grfCommitFlags)/* [in] */
1542 /*************************************************************************
1545 HRESULT WINAPI StorageImpl_Revert(
1552 /*************************************************************************
1553 * DestroyElement (IStorage)
1555 * Stategy: This implementation is build this way for simplicity not for speed.
1556 * I always delete the top most element of the enumeration and adjust
1557 * the deleted element pointer all the time. This takes longer to
1558 * do but allow to reinvoke DestroyElement whenever we encounter a
1559 * storage object. The optimisation reside in the usage of another
1560 * enumeration stategy that would give all the leaves of a storage
1561 * first. (postfix order)
1563 HRESULT WINAPI StorageImpl_DestroyElement(
1565 const OLECHAR *pwcsName)/* [string][in] */
1567 StorageImpl* const This=(StorageImpl*)iface;
1569 IEnumSTATSTGImpl* propertyEnumeration;
1572 StgProperty propertyToDelete;
1573 StgProperty parentProperty;
1574 ULONG foundPropertyIndexToDelete;
1575 ULONG typeOfRelation;
1576 ULONG parentPropertyId;
1578 Print(MAX_TRACE, ("(%p, %S)\n",
1582 * Perform a sanity check on the parameters.
1585 return STG_E_INVALIDPOINTER;
1588 * Create a property enumeration to search the property with the given name
1590 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1591 This->ancestorStorage,
1592 This->rootPropertySetIndex);
1594 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1595 propertyEnumeration,
1599 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1601 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1603 return STG_E_FILENOTFOUND;
1607 * Find the parent property of the property to delete (the one that
1608 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1609 * the parent is This. Otherwise, the parent is one of it's sibling...
1613 * First, read This's StgProperty..
1615 res = StorageImpl_ReadProperty(
1616 This->ancestorStorage,
1617 This->rootPropertySetIndex,
1623 * Second, check to see if by any chance the actual storage (This) is not
1624 * the parent of the property to delete... We never know...
1626 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1629 * Set data as it would have been done in the else part...
1631 typeOfRelation = PROPERTY_RELATION_DIR;
1632 parentPropertyId = This->rootPropertySetIndex;
1637 * Create a property enumeration to search the parent properties, and
1638 * delete it once done.
1640 IEnumSTATSTGImpl* propertyEnumeration2;
1642 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1643 This->ancestorStorage,
1644 This->rootPropertySetIndex);
1646 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1647 propertyEnumeration2,
1648 foundPropertyIndexToDelete,
1652 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1655 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1657 hr = deleteStorageProperty(
1659 foundPropertyIndexToDelete,
1662 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1664 hr = deleteStreamProperty(
1666 foundPropertyIndexToDelete,
1674 * Adjust the property chain
1676 hr = adjustPropertyChain(
1687 /*********************************************************************
1691 * Perform the deletion of a complete storage node
1694 static HRESULT deleteStorageProperty(
1695 StorageImpl *parentStorage,
1696 ULONG indexOfPropertyToDelete,
1697 StgProperty propertyToDelete)
1699 IEnumSTATSTG *elements = 0;
1700 IStorage *childStorage = 0;
1701 STATSTG currentElement;
1703 HRESULT destroyHr = S_OK;
1706 * Open the storage and enumerate it
1708 hr = StorageBaseImpl_OpenStorage(
1709 (IStorage*)parentStorage,
1710 propertyToDelete.name,
1712 STGM_SHARE_EXCLUSIVE,
1723 * Enumerate the elements
1725 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1730 * Obtain the next element
1732 hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL);
1735 destroyHr = StorageImpl_DestroyElement(
1736 (IStorage*)childStorage,
1737 (OLECHAR*)currentElement.pwcsName);
1739 CoTaskMemFree(currentElement.pwcsName);
1743 * We need to Reset the enumeration every time because we delete elements
1744 * and the enumeration could be invalid
1746 IEnumSTATSTG_Reset(elements);
1748 } while ((hr == S_OK) && (destroyHr == S_OK));
1751 * Invalidate the property by zeroing it's name member.
1753 propertyToDelete.sizeOfNameString = 0;
1755 StorageImpl_WriteProperty(parentStorage->ancestorStorage,
1756 indexOfPropertyToDelete,
1759 IStorage_Release(childStorage);
1760 IEnumSTATSTG_Release(elements);
1765 /*********************************************************************
1769 * Perform the deletion of a stream node
1772 static HRESULT deleteStreamProperty(
1773 StorageImpl *parentStorage,
1774 ULONG indexOfPropertyToDelete,
1775 StgProperty propertyToDelete)
1779 ULARGE_INTEGER size;
1781 size.u.HighPart = 0;
1784 hr = StorageBaseImpl_OpenStream(
1785 (IStorage*)parentStorage,
1786 (OLECHAR*)propertyToDelete.name,
1788 STGM_WRITE | STGM_SHARE_EXCLUSIVE,
1800 hr = IStream_SetSize(pis, size);
1808 * Release the stream object.
1810 IStream_Release(pis);
1813 * Invalidate the property by zeroing it's name member.
1815 propertyToDelete.sizeOfNameString = 0;
1818 * Here we should re-read the property so we get the updated pointer
1819 * but since we are here to zap it, I don't do it...
1821 StorageImpl_WriteProperty(
1822 parentStorage->ancestorStorage,
1823 indexOfPropertyToDelete,
1829 /*********************************************************************
1833 * Finds a placeholder for the StgProperty within the Storage
1836 static HRESULT findPlaceholder(
1837 StorageImpl *storage,
1838 ULONG propertyIndexToStore,
1839 ULONG storePropertyIndex,
1842 StgProperty storeProperty;
1847 * Read the storage property
1849 res = StorageImpl_ReadProperty(
1850 storage->ancestorStorage,
1859 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1861 if (storeProperty.previousProperty != PROPERTY_NULL)
1863 return findPlaceholder(
1865 propertyIndexToStore,
1866 storeProperty.previousProperty,
1871 storeProperty.previousProperty = propertyIndexToStore;
1874 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1876 if (storeProperty.nextProperty != PROPERTY_NULL)
1878 return findPlaceholder(
1880 propertyIndexToStore,
1881 storeProperty.nextProperty,
1886 storeProperty.nextProperty = propertyIndexToStore;
1889 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1891 if (storeProperty.dirProperty != PROPERTY_NULL)
1893 return findPlaceholder(
1895 propertyIndexToStore,
1896 storeProperty.dirProperty,
1901 storeProperty.dirProperty = propertyIndexToStore;
1905 hr = StorageImpl_WriteProperty(
1906 storage->ancestorStorage,
1918 /*************************************************************************
1922 * This method takes the previous and the next property link of a property
1923 * to be deleted and find them a place in the Storage.
1925 static HRESULT adjustPropertyChain(
1927 StgProperty propertyToDelete,
1928 StgProperty parentProperty,
1929 ULONG parentPropertyId,
1932 ULONG newLinkProperty = PROPERTY_NULL;
1933 BOOL needToFindAPlaceholder = FALSE;
1934 ULONG storeNode = PROPERTY_NULL;
1935 ULONG toStoreNode = PROPERTY_NULL;
1936 INT relationType = 0;
1940 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1942 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1945 * Set the parent previous to the property to delete previous
1947 newLinkProperty = propertyToDelete.previousProperty;
1949 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1952 * We also need to find a storage for the other link, setup variables
1953 * to do this at the end...
1955 needToFindAPlaceholder = TRUE;
1956 storeNode = propertyToDelete.previousProperty;
1957 toStoreNode = propertyToDelete.nextProperty;
1958 relationType = PROPERTY_RELATION_NEXT;
1961 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1964 * Set the parent previous to the property to delete next
1966 newLinkProperty = propertyToDelete.nextProperty;
1970 * Link it for real...
1972 parentProperty.previousProperty = newLinkProperty;
1975 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1977 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1980 * Set the parent next to the property to delete next previous
1982 newLinkProperty = propertyToDelete.previousProperty;
1984 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1987 * We also need to find a storage for the other link, setup variables
1988 * to do this at the end...
1990 needToFindAPlaceholder = TRUE;
1991 storeNode = propertyToDelete.previousProperty;
1992 toStoreNode = propertyToDelete.nextProperty;
1993 relationType = PROPERTY_RELATION_NEXT;
1996 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1999 * Set the parent next to the property to delete next
2001 newLinkProperty = propertyToDelete.nextProperty;
2005 * Link it for real...
2007 parentProperty.nextProperty = newLinkProperty;
2009 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2011 if (propertyToDelete.previousProperty != PROPERTY_NULL)
2014 * Set the parent dir to the property to delete previous
2016 newLinkProperty = propertyToDelete.previousProperty;
2018 if (propertyToDelete.nextProperty != PROPERTY_NULL)
2021 * We also need to find a storage for the other link, setup variables
2022 * to do this at the end...
2024 needToFindAPlaceholder = TRUE;
2025 storeNode = propertyToDelete.previousProperty;
2026 toStoreNode = propertyToDelete.nextProperty;
2027 relationType = PROPERTY_RELATION_NEXT;
2030 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2033 * Set the parent dir to the property to delete next
2035 newLinkProperty = propertyToDelete.nextProperty;
2039 * Link it for real...
2041 parentProperty.dirProperty = newLinkProperty;
2045 * Write back the parent property
2047 res = StorageImpl_WriteProperty(
2048 This->ancestorStorage,
2057 * If a placeholder is required for the other link, then, find one and
2058 * get out of here...
2060 if (needToFindAPlaceholder)
2062 hr = findPlaceholder(
2073 /******************************************************************************
2074 * SetElementTimes (IStorage)
2076 HRESULT WINAPI StorageImpl_SetElementTimes(
2078 const OLECHAR *pwcsName,/* [string][in] */
2079 const FILETIME *pctime, /* [in] */
2080 const FILETIME *patime, /* [in] */
2081 const FILETIME *pmtime) /* [in] */
2087 /******************************************************************************
2088 * SetStateBits (IStorage)
2090 HRESULT WINAPI StorageImpl_SetStateBits(
2092 DWORD grfStateBits,/* [in] */
2093 DWORD grfMask) /* [in] */
2099 HRESULT StorageImpl_Construct(
2108 StgProperty currentProperty;
2109 BOOL readSuccessful;
2110 ULONG currentPropertyIndex;
2112 if ( FAILED( validateSTGM(openFlags) ))
2113 return STG_E_INVALIDFLAG;
2115 memset(This, 0, sizeof(StorageImpl));
2118 * Initialize the virtual fgunction table.
2120 ICOM_VTBL(This) = &Storage32Impl_Vtbl;
2121 This->v_destructor = &StorageImpl_Destroy;
2124 * This is the top-level storage so initialize the ancester pointer
2127 This->ancestorStorage = This;
2130 * Initialize the physical support of the storage.
2132 This->hFile = hFile;
2135 * Initialize the big block cache.
2137 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
2138 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2139 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
2145 if (This->bigBlockFile == 0)
2150 ULARGE_INTEGER size;
2151 BYTE* bigBlockBuffer;
2154 * Initialize all header variables:
2155 * - The big block depot consists of one block and it is at block 0
2156 * - The properties start at block 1
2157 * - There is no small block depot
2159 memset( This->bigBlockDepotStart,
2161 sizeof(This->bigBlockDepotStart));
2163 This->bigBlockDepotCount = 1;
2164 This->bigBlockDepotStart[0] = 0;
2165 This->rootStartBlock = 1;
2166 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
2167 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
2168 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
2169 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2170 This->extBigBlockDepotCount = 0;
2172 StorageImpl_SaveFileHeader(This);
2175 * Add one block for the big block depot and one block for the properties
2177 size.u.HighPart = 0;
2178 size.u.LowPart = This->bigBlockSize * 3;
2179 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
2182 * Initialize the big block depot
2184 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
2185 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2186 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2187 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2188 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2193 * Load the header for the file.
2195 hr = StorageImpl_LoadFileHeader(This);
2199 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2206 * There is no block depot cached yet.
2208 This->indexBlockDepotCached = 0xFFFFFFFF;
2211 * Start searching for free blocks with block 0.
2213 This->prevFreeBlock = 0;
2216 * Create the block chain abstractions.
2218 This->rootBlockChain =
2219 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
2221 This->smallBlockDepotChain = BlockChainStream_Construct(
2223 &This->smallBlockDepotStart,
2227 * Write the root property
2231 StgProperty rootProp;
2233 * Initialize the property chain
2235 memset(&rootProp, 0, sizeof(rootProp));
2236 MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,
2237 sizeof(rootProp.name)/sizeof(WCHAR) );
2238 rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
2239 rootProp.propertyType = PROPTYPE_ROOT;
2240 rootProp.previousProperty = PROPERTY_NULL;
2241 rootProp.nextProperty = PROPERTY_NULL;
2242 rootProp.dirProperty = PROPERTY_NULL;
2243 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
2244 rootProp.size.u.HighPart = 0;
2245 rootProp.size.u.LowPart = 0;
2247 StorageImpl_WriteProperty(This, 0, &rootProp);
2251 * Find the ID of the root int he property sets.
2253 currentPropertyIndex = 0;
2257 readSuccessful = StorageImpl_ReadProperty(
2259 currentPropertyIndex,
2264 if ( (currentProperty.sizeOfNameString != 0 ) &&
2265 (currentProperty.propertyType == PROPTYPE_ROOT) )
2267 This->rootPropertySetIndex = currentPropertyIndex;
2271 currentPropertyIndex++;
2273 } while (readSuccessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
2275 if (!readSuccessful)
2282 * Create the block chain abstraction for the small block root chain.
2284 This->smallBlockRootChain = BlockChainStream_Construct(
2287 This->rootPropertySetIndex);
2292 void StorageImpl_Destroy(
2295 Print(MAX_TRACE, ("(%p)\n", This));
2297 BlockChainStream_Destroy(This->smallBlockRootChain);
2298 BlockChainStream_Destroy(This->rootBlockChain);
2299 BlockChainStream_Destroy(This->smallBlockDepotChain);
2301 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2305 /******************************************************************************
2306 * Storage32Impl_GetNextFreeBigBlock
2308 * Returns the index of the next free big block.
2309 * If the big block depot is filled, this method will enlarge it.
2312 ULONG StorageImpl_GetNextFreeBigBlock(
2315 ULONG depotBlockIndexPos;
2317 ULONG depotBlockOffset;
2318 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2319 ULONG nextBlockIndex = BLOCK_SPECIAL;
2321 ULONG freeBlock = BLOCK_UNUSED;
2323 depotIndex = This->prevFreeBlock / blocksPerDepot;
2324 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2327 * Scan the entire big block depot until we find a block marked free
2329 while (nextBlockIndex != BLOCK_UNUSED)
2331 if (depotIndex < COUNT_BBDEPOTINHEADER)
2333 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2336 * Grow the primary depot.
2338 if (depotBlockIndexPos == BLOCK_UNUSED)
2340 depotBlockIndexPos = depotIndex*blocksPerDepot;
2343 * Add a block depot.
2345 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2346 This->bigBlockDepotCount++;
2347 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2350 * Flag it as a block depot.
2352 StorageImpl_SetNextBlockInChain(This,
2356 /* Save new header information.
2358 StorageImpl_SaveFileHeader(This);
2363 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2365 if (depotBlockIndexPos == BLOCK_UNUSED)
2368 * Grow the extended depot.
2370 ULONG extIndex = BLOCK_UNUSED;
2371 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2372 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2374 if (extBlockOffset == 0)
2376 /* We need an extended block.
2378 extIndex = Storage32Impl_AddExtBlockDepot(This);
2379 This->extBigBlockDepotCount++;
2380 depotBlockIndexPos = extIndex + 1;
2383 depotBlockIndexPos = depotIndex * blocksPerDepot;
2386 * Add a block depot and mark it in the extended block.
2388 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2389 This->bigBlockDepotCount++;
2390 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2392 /* Flag the block depot.
2394 StorageImpl_SetNextBlockInChain(This,
2398 /* If necessary, flag the extended depot block.
2400 if (extIndex != BLOCK_UNUSED)
2401 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2403 /* Save header information.
2405 StorageImpl_SaveFileHeader(This);
2409 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2411 if (depotBuffer != 0)
2413 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2414 ( nextBlockIndex != BLOCK_UNUSED))
2416 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2418 if (nextBlockIndex == BLOCK_UNUSED)
2420 freeBlock = (depotIndex * blocksPerDepot) +
2421 (depotBlockOffset/sizeof(ULONG));
2424 depotBlockOffset += sizeof(ULONG);
2427 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2431 depotBlockOffset = 0;
2434 This->prevFreeBlock = freeBlock;
2439 /******************************************************************************
2440 * Storage32Impl_AddBlockDepot
2442 * This will create a depot block, essentially it is a block initialized
2445 void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2449 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2452 * Initialize blocks as free
2454 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2456 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2459 /******************************************************************************
2460 * Storage32Impl_GetExtDepotBlock
2462 * Returns the index of the block that corresponds to the specified depot
2463 * index. This method is only for depot indexes equal or greater than
2464 * COUNT_BBDEPOTINHEADER.
2466 ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2468 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2469 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2470 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2471 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2472 ULONG blockIndex = BLOCK_UNUSED;
2473 ULONG extBlockIndex = This->extBigBlockDepotStart;
2475 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2477 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2478 return BLOCK_UNUSED;
2480 while (extBlockCount > 0)
2482 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2486 if (extBlockIndex != BLOCK_UNUSED)
2490 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2492 if (depotBuffer != 0)
2494 StorageUtl_ReadDWord(depotBuffer,
2495 extBlockOffset * sizeof(ULONG),
2498 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2505 /******************************************************************************
2506 * Storage32Impl_SetExtDepotBlock
2508 * Associates the specified block index to the specified depot index.
2509 * This method is only for depot indexes equal or greater than
2510 * COUNT_BBDEPOTINHEADER.
2512 void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2516 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2517 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2518 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2519 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2520 ULONG extBlockIndex = This->extBigBlockDepotStart;
2522 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2524 while (extBlockCount > 0)
2526 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2530 if (extBlockIndex != BLOCK_UNUSED)
2534 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2536 if (depotBuffer != 0)
2538 StorageUtl_WriteDWord(depotBuffer,
2539 extBlockOffset * sizeof(ULONG),
2542 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2547 /******************************************************************************
2548 * Storage32Impl_AddExtBlockDepot
2550 * Creates an extended depot block.
2552 ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2554 ULONG numExtBlocks = This->extBigBlockDepotCount;
2555 ULONG nextExtBlock = This->extBigBlockDepotStart;
2556 BYTE* depotBuffer = NULL;
2557 ULONG index = BLOCK_UNUSED;
2558 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2559 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2560 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2562 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2563 blocksPerDepotBlock;
2565 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2568 * The first extended block.
2570 This->extBigBlockDepotStart = index;
2576 * Follow the chain to the last one.
2578 for (i = 0; i < (numExtBlocks - 1); i++)
2580 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2584 * Add the new extended block to the chain.
2586 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2587 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2588 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2592 * Initialize this block.
2594 depotBuffer = StorageImpl_GetBigBlock(This, index);
2595 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2596 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2601 /******************************************************************************
2602 * Storage32Impl_FreeBigBlock
2604 * This method will flag the specified block as free in the big block depot.
2606 void StorageImpl_FreeBigBlock(
2610 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2612 if (blockIndex < This->prevFreeBlock)
2613 This->prevFreeBlock = blockIndex;
2616 /************************************************************************
2617 * Storage32Impl_GetNextBlockInChain
2619 * This method will retrieve the block index of the next big block in
2622 * Params: This - Pointer to the Storage object.
2623 * blockIndex - Index of the block to retrieve the chain
2626 * Returns: This method returns the index of the next block in the chain.
2627 * It will return the constants:
2628 * BLOCK_SPECIAL - If the block given was not part of a
2630 * BLOCK_END_OF_CHAIN - If the block given was the last in
2632 * BLOCK_UNUSED - If the block given was not past of a chain
2634 * BLOCK_EXTBBDEPOT - This block is part of the extended
2637 * See Windows documentation for more details on IStorage methods.
2639 ULONG StorageImpl_GetNextBlockInChain(
2643 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2644 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2645 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2646 ULONG nextBlockIndex = BLOCK_SPECIAL;
2648 ULONG depotBlockIndexPos;
2650 assert(depotBlockCount < This->bigBlockDepotCount);
2653 * Cache the currently accessed depot block.
2655 if (depotBlockCount != This->indexBlockDepotCached)
2657 This->indexBlockDepotCached = depotBlockCount;
2659 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2661 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2666 * We have to look in the extended depot.
2668 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2671 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2677 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2679 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2680 This->blockDepotCached[index] = nextBlockIndex;
2683 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2687 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2689 return nextBlockIndex;
2692 /******************************************************************************
2693 * Storage32Impl_GetNextExtendedBlock
2695 * Given an extended block this method will return the next extended block.
2698 * The last ULONG of an extended block is the block index of the next
2699 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2703 * - The index of the next extended block
2704 * - BLOCK_UNUSED: there is no next extended block.
2705 * - Any other return values denotes failure.
2707 ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2709 ULONG nextBlockIndex = BLOCK_SPECIAL;
2710 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2713 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2717 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2719 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2722 return nextBlockIndex;
2725 /******************************************************************************
2726 * Storage32Impl_SetNextBlockInChain
2728 * This method will write the index of the specified block's next block
2729 * in the big block depot.
2731 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2734 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2735 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2736 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2739 void StorageImpl_SetNextBlockInChain(
2744 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2745 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2746 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2747 ULONG depotBlockIndexPos;
2750 assert(depotBlockCount < This->bigBlockDepotCount);
2751 assert(blockIndex != nextBlock);
2753 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2755 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2760 * We have to look in the extended depot.
2762 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2765 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2769 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2770 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2774 * Update the cached block depot, if necessary.
2776 if (depotBlockCount == This->indexBlockDepotCached)
2778 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2782 /******************************************************************************
2783 * Storage32Impl_LoadFileHeader
2785 * This method will read in the file header, i.e. big block index -1.
2787 HRESULT StorageImpl_LoadFileHeader(
2790 HRESULT hr = STG_E_FILENOTFOUND;
2791 void* headerBigBlock = NULL;
2795 * Get a pointer to the big block of data containing the header.
2797 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2800 * Extract the information from the header.
2802 if (headerBigBlock!=0)
2805 * Check for the "magic number" signature and return an error if it is not
2808 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2810 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2811 return STG_E_OLDFORMAT;
2814 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2816 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2817 return STG_E_INVALIDHEADER;
2820 StorageUtl_ReadWord(
2822 OFFSET_BIGBLOCKSIZEBITS,
2823 &This->bigBlockSizeBits);
2825 StorageUtl_ReadWord(
2827 OFFSET_SMALLBLOCKSIZEBITS,
2828 &This->smallBlockSizeBits);
2830 StorageUtl_ReadDWord(
2832 OFFSET_BBDEPOTCOUNT,
2833 &This->bigBlockDepotCount);
2835 StorageUtl_ReadDWord(
2837 OFFSET_ROOTSTARTBLOCK,
2838 &This->rootStartBlock);
2840 StorageUtl_ReadDWord(
2842 OFFSET_SBDEPOTSTART,
2843 &This->smallBlockDepotStart);
2845 StorageUtl_ReadDWord(
2847 OFFSET_EXTBBDEPOTSTART,
2848 &This->extBigBlockDepotStart);
2850 StorageUtl_ReadDWord(
2852 OFFSET_EXTBBDEPOTCOUNT,
2853 &This->extBigBlockDepotCount);
2855 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2857 StorageUtl_ReadDWord(
2859 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2860 &(This->bigBlockDepotStart[index]));
2864 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2868 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2869 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2873 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2874 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2878 * Right now, the code is making some assumptions about the size of the
2879 * blocks, just make sure they are what we're expecting.
2881 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2882 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2885 * Release the block.
2887 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2895 /******************************************************************************
2896 * Storage32Impl_SaveFileHeader
2898 * This method will save to the file the header, i.e. big block -1.
2900 void StorageImpl_SaveFileHeader(
2903 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2908 * Get a pointer to the big block of data containing the header.
2910 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2913 * If the block read failed, the file is probably new.
2918 * Initialize for all unknown fields.
2920 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2923 * Initialize the magic number.
2925 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2928 * And a bunch of things we don't know what they mean
2930 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2931 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2932 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2933 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2934 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2938 * Write the information to the header.
2940 if (headerBigBlock!=0)
2942 StorageUtl_WriteWord(
2944 OFFSET_BIGBLOCKSIZEBITS,
2945 This->bigBlockSizeBits);
2947 StorageUtl_WriteWord(
2949 OFFSET_SMALLBLOCKSIZEBITS,
2950 This->smallBlockSizeBits);
2952 StorageUtl_WriteDWord(
2954 OFFSET_BBDEPOTCOUNT,
2955 This->bigBlockDepotCount);
2957 StorageUtl_WriteDWord(
2959 OFFSET_ROOTSTARTBLOCK,
2960 This->rootStartBlock);
2962 StorageUtl_WriteDWord(
2964 OFFSET_SBDEPOTSTART,
2965 This->smallBlockDepotStart);
2967 StorageUtl_WriteDWord(
2969 OFFSET_EXTBBDEPOTSTART,
2970 This->extBigBlockDepotStart);
2972 StorageUtl_WriteDWord(
2974 OFFSET_EXTBBDEPOTCOUNT,
2975 This->extBigBlockDepotCount);
2977 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2979 StorageUtl_WriteDWord(
2981 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2982 (This->bigBlockDepotStart[index]));
2987 * Write the big block back to the file.
2989 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2992 /******************************************************************************
2993 * Storage32Impl_ReadProperty
2995 * This method will read the specified property from the property chain.
2997 BOOL StorageImpl_ReadProperty(
3000 StgProperty* buffer)
3002 BYTE currentProperty[PROPSET_BLOCK_SIZE];
3003 ULARGE_INTEGER offsetInPropSet;
3004 BOOL readSuccessful;
3007 offsetInPropSet.u.HighPart = 0;
3008 offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE;
3010 readSuccessful = BlockChainStream_ReadAt(
3011 This->rootBlockChain,
3019 memset(buffer->name, 0, sizeof(buffer->name));
3022 currentProperty+OFFSET_PS_NAME,
3023 PROPERTY_NAME_BUFFER_LEN );
3025 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3027 StorageUtl_ReadWord(
3029 OFFSET_PS_NAMELENGTH,
3030 &buffer->sizeOfNameString);
3032 StorageUtl_ReadDWord(
3034 OFFSET_PS_PREVIOUSPROP,
3035 &buffer->previousProperty);
3037 StorageUtl_ReadDWord(
3040 &buffer->nextProperty);
3042 StorageUtl_ReadDWord(
3045 &buffer->dirProperty);
3047 StorageUtl_ReadGUID(
3050 &buffer->propertyUniqueID);
3052 StorageUtl_ReadDWord(
3055 &buffer->timeStampS1);
3057 StorageUtl_ReadDWord(
3060 &buffer->timeStampD1);
3062 StorageUtl_ReadDWord(
3065 &buffer->timeStampS2);
3067 StorageUtl_ReadDWord(
3070 &buffer->timeStampD2);
3072 StorageUtl_ReadDWord(
3074 OFFSET_PS_STARTBLOCK,
3075 &buffer->startingBlock);
3077 StorageUtl_ReadDWord(
3080 &buffer->size.u.LowPart);
3082 buffer->size.u.HighPart = 0;
3085 return readSuccessful;
3088 /*********************************************************************
3089 * Write the specified property into the property chain
3091 BOOL StorageImpl_WriteProperty(
3094 StgProperty* buffer)
3096 BYTE currentProperty[PROPSET_BLOCK_SIZE];
3097 ULARGE_INTEGER offsetInPropSet;
3098 BOOL writeSuccessful;
3101 offsetInPropSet.u.HighPart = 0;
3102 offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE;
3104 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3107 currentProperty + OFFSET_PS_NAME,
3109 PROPERTY_NAME_BUFFER_LEN );
3111 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3113 StorageUtl_WriteWord(
3115 OFFSET_PS_NAMELENGTH,
3116 buffer->sizeOfNameString);
3118 StorageUtl_WriteDWord(
3120 OFFSET_PS_PREVIOUSPROP,
3121 buffer->previousProperty);
3123 StorageUtl_WriteDWord(
3126 buffer->nextProperty);
3128 StorageUtl_WriteDWord(
3131 buffer->dirProperty);
3133 StorageUtl_WriteGUID(
3136 &buffer->propertyUniqueID);
3138 StorageUtl_WriteDWord(
3141 buffer->timeStampS1);
3143 StorageUtl_WriteDWord(
3146 buffer->timeStampD1);
3148 StorageUtl_WriteDWord(
3151 buffer->timeStampS2);
3153 StorageUtl_WriteDWord(
3156 buffer->timeStampD2);
3158 StorageUtl_WriteDWord(
3160 OFFSET_PS_STARTBLOCK,
3161 buffer->startingBlock);
3163 StorageUtl_WriteDWord(
3166 buffer->size.u.LowPart);
3168 writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
3173 return writeSuccessful;
3176 BOOL StorageImpl_ReadBigBlock(
3181 void* bigBlockBuffer;
3183 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
3185 if (bigBlockBuffer!=0)
3187 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
3189 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3197 BOOL StorageImpl_WriteBigBlock(
3202 void* bigBlockBuffer;
3204 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
3206 if (bigBlockBuffer!=0)
3208 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
3210 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3218 void* StorageImpl_GetROBigBlock(
3222 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
3225 void* StorageImpl_GetBigBlock(
3229 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
3232 void StorageImpl_ReleaseBigBlock(
3236 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
3239 /******************************************************************************
3240 * Storage32Impl_SmallBlocksToBigBlocks
3242 * This method will convert a small block chain to a big block chain.
3243 * The small block chain will be destroyed.
3245 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3247 SmallBlockChainStream** ppsbChain)
3249 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3250 ULARGE_INTEGER size, offset;
3251 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
3252 ULONG propertyIndex;
3253 BOOL successRead, successWrite;
3254 StgProperty chainProperty;
3256 BlockChainStream *bbTempChain = NULL;
3257 BlockChainStream *bigBlockChain = NULL;
3260 * Create a temporary big block chain that doesn't have
3261 * an associated property. This temporary chain will be
3262 * used to copy data from small blocks to big blocks.
3264 bbTempChain = BlockChainStream_Construct(This,
3269 * Grow the big block chain.
3271 size = SmallBlockChainStream_GetSize(*ppsbChain);
3272 BlockChainStream_SetSize(bbTempChain, size);
3275 * Copy the contents of the small block chain to the big block chain
3276 * by small block size increments.
3278 offset.u.LowPart = 0;
3279 offset.u.HighPart = 0;
3283 buffer = (BYTE *) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3286 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3288 DEF_SMALL_BLOCK_SIZE,
3291 cbTotalRead += cbRead;
3293 successWrite = BlockChainStream_WriteAt(bbTempChain,
3298 cbTotalWritten += cbWritten;
3300 offset.u.LowPart += This->smallBlockSize;
3302 } while (successRead && successWrite);
3303 HeapFree(GetProcessHeap(),0,buffer);
3305 assert(cbTotalRead == cbTotalWritten);
3308 * Destroy the small block chain.
3310 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3311 size.u.HighPart = 0;
3313 SmallBlockChainStream_SetSize(*ppsbChain, size);
3314 SmallBlockChainStream_Destroy(*ppsbChain);
3318 * Change the property information. This chain is now a big block chain
3319 * and it doesn't reside in the small blocks chain anymore.
3321 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3323 chainProperty.startingBlock = bbHeadOfChain;
3325 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3328 * Destroy the temporary propertyless big block chain.
3329 * Create a new big block chain associated with this property.
3331 BlockChainStream_Destroy(bbTempChain);
3332 bigBlockChain = BlockChainStream_Construct(This,
3336 return bigBlockChain;
3339 /******************************************************************************
3340 ** Storage32InternalImpl implementation
3343 StorageInternalImpl* StorageInternalImpl_Construct(
3344 StorageImpl* ancestorStorage,
3345 ULONG rootPropertyIndex)
3347 StorageInternalImpl* newStorage;
3350 * Allocate space for the new storage object
3352 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3356 memset(newStorage, 0, sizeof(StorageInternalImpl));
3359 * Initialize the virtual function table.
3361 ICOM_VTBL(newStorage) = &Storage32InternalImpl_Vtbl;
3362 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3365 * Keep the ancestor storage pointer and nail a reference to it.
3367 newStorage->ancestorStorage = ancestorStorage;
3368 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3371 * Keep the index of the root property set for this storage,
3373 newStorage->rootPropertySetIndex = rootPropertyIndex;
3381 void StorageInternalImpl_Destroy(
3382 StorageInternalImpl* This)
3384 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3385 HeapFree(GetProcessHeap(), 0, This);
3388 /******************************************************************************
3390 ** Storage32InternalImpl_Commit
3392 ** The non-root storages cannot be opened in transacted mode thus this function
3395 HRESULT WINAPI StorageInternalImpl_Commit(
3397 DWORD grfCommitFlags) /* [in] */
3402 /******************************************************************************
3404 ** Storage32InternalImpl_Revert
3406 ** The non-root storages cannot be opened in transacted mode thus this function
3409 HRESULT WINAPI StorageInternalImpl_Revert(
3415 /******************************************************************************
3416 ** IEnumSTATSTGImpl implementation
3419 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3420 StorageImpl* parentStorage,
3421 ULONG firstPropertyNode)
3423 IEnumSTATSTGImpl* newEnumeration;
3425 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3427 if (newEnumeration!=0)
3430 * Set-up the virtual function table and reference count.
3432 ICOM_VTBL(newEnumeration) = &IEnumSTATSTGImpl_Vtbl;
3433 newEnumeration->ref = 0;
3436 * We want to nail-down the reference to the storage in case the
3437 * enumeration out-lives the storage in the client application.
3439 newEnumeration->parentStorage = parentStorage;
3440 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3442 newEnumeration->firstPropertyNode = firstPropertyNode;
3445 * Initialize the search stack
3447 newEnumeration->stackSize = 0;
3448 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3449 newEnumeration->stackToVisit =
3450 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3453 * Make sure the current node of the iterator is the first one.
3455 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3458 return newEnumeration;
3461 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3463 IStorage_Release((IStorage*)This->parentStorage);
3464 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3465 HeapFree(GetProcessHeap(), 0, This);
3468 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3469 IEnumSTATSTG* iface,
3473 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3476 * Perform a sanity check on the parameters.
3479 return E_INVALIDARG;
3482 * Initialize the return parameter.
3487 * Compare the riid with the interface IDs implemented by this object.
3489 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3491 *ppvObject = (IEnumSTATSTG*)This;
3493 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3495 *ppvObject = (IEnumSTATSTG*)This;
3499 * Check that we obtained an interface.
3501 if ((*ppvObject)==0)
3502 return E_NOINTERFACE;
3505 * Query Interface always increases the reference count by one when it is
3508 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3513 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3514 IEnumSTATSTG* iface)
3516 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3522 ULONG WINAPI IEnumSTATSTGImpl_Release(
3523 IEnumSTATSTG* iface)
3525 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3533 * If the reference count goes down to 0, perform suicide.
3537 IEnumSTATSTGImpl_Destroy(This);
3543 HRESULT WINAPI IEnumSTATSTGImpl_Next(
3544 IEnumSTATSTG* iface,
3547 ULONG* pceltFetched)
3549 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3551 StgProperty currentProperty;
3552 STATSTG* currentReturnStruct = rgelt;
3553 ULONG objectFetched = 0;
3554 ULONG currentSearchNode;
3557 * Perform a sanity check on the parameters.
3559 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3560 return E_INVALIDARG;
3563 * To avoid the special case, get another pointer to a ULONG value if
3564 * the caller didn't supply one.
3566 if (pceltFetched==0)
3567 pceltFetched = &objectFetched;
3570 * Start the iteration, we will iterate until we hit the end of the
3571 * linked list or until we hit the number of items to iterate through
3576 * Start with the node at the top of the stack.
3578 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3580 while ( ( *pceltFetched < celt) &&
3581 ( currentSearchNode!=PROPERTY_NULL) )
3584 * Remove the top node from the stack
3586 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3589 * Read the property from the storage.
3591 StorageImpl_ReadProperty(This->parentStorage,
3596 * Copy the information to the return buffer.
3598 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3603 * Step to the next item in the iteration
3606 currentReturnStruct++;
3609 * Push the next search node in the search stack.
3611 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3614 * continue the iteration.
3616 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3619 if (*pceltFetched == celt)
3626 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3627 IEnumSTATSTG* iface,
3630 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3632 StgProperty currentProperty;
3633 ULONG objectFetched = 0;
3634 ULONG currentSearchNode;
3637 * Start with the node at the top of the stack.
3639 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3641 while ( (objectFetched < celt) &&
3642 (currentSearchNode!=PROPERTY_NULL) )
3645 * Remove the top node from the stack
3647 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3650 * Read the property from the storage.
3652 StorageImpl_ReadProperty(This->parentStorage,
3657 * Step to the next item in the iteration
3662 * Push the next search node in the search stack.
3664 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3667 * continue the iteration.
3669 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3672 if (objectFetched == celt)
3678 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3679 IEnumSTATSTG* iface)
3681 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3683 StgProperty rootProperty;
3684 BOOL readSuccessful;
3687 * Re-initialize the search stack to an empty stack
3689 This->stackSize = 0;
3692 * Read the root property from the storage.
3694 readSuccessful = StorageImpl_ReadProperty(
3695 This->parentStorage,
3696 This->firstPropertyNode,
3701 assert(rootProperty.sizeOfNameString!=0);
3704 * Push the search node in the search stack.
3706 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3712 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3713 IEnumSTATSTG* iface,
3714 IEnumSTATSTG** ppenum)
3716 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3718 IEnumSTATSTGImpl* newClone;
3721 * Perform a sanity check on the parameters.
3724 return E_INVALIDARG;
3726 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3727 This->firstPropertyNode);
3731 * The new clone enumeration must point to the same current node as
3734 newClone->stackSize = This->stackSize ;
3735 newClone->stackMaxSize = This->stackMaxSize ;
3736 newClone->stackToVisit =
3737 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3740 newClone->stackToVisit,
3742 sizeof(ULONG) * newClone->stackSize);
3744 *ppenum = (IEnumSTATSTG*)newClone;
3747 * Don't forget to nail down a reference to the clone before
3750 IEnumSTATSTGImpl_AddRef(*ppenum);
3755 INT IEnumSTATSTGImpl_FindParentProperty(
3756 IEnumSTATSTGImpl *This,
3757 ULONG childProperty,
3758 StgProperty *currentProperty,
3761 ULONG currentSearchNode;
3765 * To avoid the special case, get another pointer to a ULONG value if
3766 * the caller didn't supply one.
3769 thisNodeId = &foundNode;
3772 * Start with the node at the top of the stack.
3774 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3777 while (currentSearchNode!=PROPERTY_NULL)
3780 * Store the current node in the returned parameters
3782 *thisNodeId = currentSearchNode;
3785 * Remove the top node from the stack
3787 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3790 * Read the property from the storage.
3792 StorageImpl_ReadProperty(
3793 This->parentStorage,
3797 if (currentProperty->previousProperty == childProperty)
3798 return PROPERTY_RELATION_PREVIOUS;
3800 else if (currentProperty->nextProperty == childProperty)
3801 return PROPERTY_RELATION_NEXT;
3803 else if (currentProperty->dirProperty == childProperty)
3804 return PROPERTY_RELATION_DIR;
3807 * Push the next search node in the search stack.
3809 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3812 * continue the iteration.
3814 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3817 return PROPERTY_NULL;
3820 ULONG IEnumSTATSTGImpl_FindProperty(
3821 IEnumSTATSTGImpl* This,
3822 const OLECHAR* lpszPropName,
3823 StgProperty* currentProperty)
3825 ULONG currentSearchNode;
3828 * Start with the node at the top of the stack.
3830 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3832 while (currentSearchNode!=PROPERTY_NULL)
3835 * Remove the top node from the stack
3837 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3840 * Read the property from the storage.
3842 StorageImpl_ReadProperty(This->parentStorage,
3846 if ( propertyNameCmp(
3847 (OLECHAR*)currentProperty->name,
3848 (OLECHAR*)lpszPropName) == 0)
3849 return currentSearchNode;
3852 * Push the next search node in the search stack.
3854 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3857 * continue the iteration.
3859 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3862 return PROPERTY_NULL;
3865 void IEnumSTATSTGImpl_PushSearchNode(
3866 IEnumSTATSTGImpl* This,
3869 StgProperty rootProperty;
3870 BOOL readSuccessful;
3873 * First, make sure we're not trying to push an unexisting node.
3875 if (nodeToPush==PROPERTY_NULL)
3879 * First push the node to the stack
3881 if (This->stackSize == This->stackMaxSize)
3883 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3885 This->stackToVisit = HeapReAlloc(
3889 sizeof(ULONG) * This->stackMaxSize);
3892 This->stackToVisit[This->stackSize] = nodeToPush;
3896 * Read the root property from the storage.
3898 readSuccessful = StorageImpl_ReadProperty(
3899 This->parentStorage,
3905 assert(rootProperty.sizeOfNameString!=0);
3908 * Push the previous search node in the search stack.
3910 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3914 ULONG IEnumSTATSTGImpl_PopSearchNode(
3915 IEnumSTATSTGImpl* This,
3920 if (This->stackSize == 0)
3921 return PROPERTY_NULL;
3923 topNode = This->stackToVisit[This->stackSize-1];
3931 /******************************************************************************
3932 ** StorageUtl implementation
3935 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3937 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3940 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3942 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3945 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3947 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3950 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3952 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3955 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3957 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3958 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3959 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3961 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3964 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3966 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3967 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3968 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3970 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3973 void StorageUtl_CopyPropertyToSTATSTG(
3974 STATSTG* destination,
3975 StgProperty* source,
3979 * The copy of the string occurs only when the flag is not set
3981 if ((statFlags & STATFLAG_NONAME) != 0)
3983 destination->pwcsName = 0;
3987 destination->pwcsName =
3988 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3990 lstrcpyW((LPWSTR)destination->pwcsName, source->name);
3993 switch (source->propertyType)
3995 case PROPTYPE_STORAGE:
3997 destination->type = STGTY_STORAGE;
3999 case PROPTYPE_STREAM:
4000 destination->type = STGTY_STREAM;
4003 destination->type = STGTY_STREAM;
4007 destination->cbSize = source->size;
4009 currentReturnStruct->mtime = {0}; TODO
4010 currentReturnStruct->ctime = {0};
4011 currentReturnStruct->atime = {0};
4013 destination->grfMode = 0;
4014 destination->grfLocksSupported = 0;
4015 destination->clsid = source->propertyUniqueID;
4016 destination->grfStateBits = 0;
4017 destination->reserved = 0;
4020 /******************************************************************************
4021 ** BlockChainStream implementation
4024 BlockChainStream* BlockChainStream_Construct(
4025 StorageImpl* parentStorage,
4026 ULONG* headOfStreamPlaceHolder,
4027 ULONG propertyIndex)
4029 BlockChainStream* newStream;
4032 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4034 newStream->parentStorage = parentStorage;
4035 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4036 newStream->ownerPropertyIndex = propertyIndex;
4037 newStream->lastBlockNoInSequence = 0xFFFFFFFF;
4038 newStream->tailIndex = BLOCK_END_OF_CHAIN;
4039 newStream->numBlocks = 0;
4041 blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4043 while (blockIndex != BLOCK_END_OF_CHAIN)
4045 newStream->numBlocks++;
4046 newStream->tailIndex = blockIndex;
4048 blockIndex = StorageImpl_GetNextBlockInChain(
4056 void BlockChainStream_Destroy(BlockChainStream* This)
4058 HeapFree(GetProcessHeap(), 0, This);
4061 /******************************************************************************
4062 * BlockChainStream_GetHeadOfChain
4064 * Returns the head of this stream chain.
4065 * Some special chains don't have properties, their heads are kept in
4066 * This->headOfStreamPlaceHolder.
4069 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4071 StgProperty chainProperty;
4072 BOOL readSuccessful;
4074 if (This->headOfStreamPlaceHolder != 0)
4075 return *(This->headOfStreamPlaceHolder);
4077 if (This->ownerPropertyIndex != PROPERTY_NULL)
4079 readSuccessful = StorageImpl_ReadProperty(
4080 This->parentStorage,
4081 This->ownerPropertyIndex,
4086 return chainProperty.startingBlock;
4090 return BLOCK_END_OF_CHAIN;
4093 /******************************************************************************
4094 * BlockChainStream_GetCount
4096 * Returns the number of blocks that comprises this chain.
4097 * This is not the size of the stream as the last block may not be full!
4100 ULONG BlockChainStream_GetCount(BlockChainStream* This)
4105 blockIndex = BlockChainStream_GetHeadOfChain(This);
4107 while (blockIndex != BLOCK_END_OF_CHAIN)
4111 blockIndex = StorageImpl_GetNextBlockInChain(
4112 This->parentStorage,
4119 /******************************************************************************
4120 * BlockChainStream_ReadAt
4122 * Reads a specified number of bytes from this chain at the specified offset.
4123 * bytesRead may be NULL.
4124 * Failure will be returned if the specified number of bytes has not been read.
4126 BOOL BlockChainStream_ReadAt(BlockChainStream* This,
4127 ULARGE_INTEGER offset,
4132 ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4133 ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize;
4134 ULONG bytesToReadInBuffer;
4137 BYTE* bigBlockBuffer;
4140 * Find the first block in the stream that contains part of the buffer.
4142 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4143 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4144 (blockNoInSequence < This->lastBlockNoInSequence) )
4146 blockIndex = BlockChainStream_GetHeadOfChain(This);
4147 This->lastBlockNoInSequence = blockNoInSequence;
4151 ULONG temp = blockNoInSequence;
4153 blockIndex = This->lastBlockNoInSequenceIndex;
4154 blockNoInSequence -= This->lastBlockNoInSequence;
4155 This->lastBlockNoInSequence = temp;
4158 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4161 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4163 blockNoInSequence--;
4166 This->lastBlockNoInSequenceIndex = blockIndex;
4169 * Start reading the buffer.
4172 bufferWalker = buffer;
4174 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4177 * Calculate how many bytes we can copy from this big block.
4179 bytesToReadInBuffer =
4180 min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4183 * Copy those bytes to the buffer
4186 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
4188 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
4190 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4193 * Step to the next big block.
4196 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4198 bufferWalker += bytesToReadInBuffer;
4199 size -= bytesToReadInBuffer;
4200 *bytesRead += bytesToReadInBuffer;
4201 offsetInBlock = 0; /* There is no offset on the next block */
4208 /******************************************************************************
4209 * BlockChainStream_WriteAt
4211 * Writes the specified number of bytes to this chain at the specified offset.
4212 * bytesWritten may be NULL.
4213 * Will fail if not all specified number of bytes have been written.
4215 BOOL BlockChainStream_WriteAt(BlockChainStream* This,
4216 ULARGE_INTEGER offset,
4219 ULONG* bytesWritten)
4221 ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4222 ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize;
4226 BYTE* bigBlockBuffer;
4229 * Find the first block in the stream that contains part of the buffer.
4231 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4232 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4233 (blockNoInSequence < This->lastBlockNoInSequence) )
4235 blockIndex = BlockChainStream_GetHeadOfChain(This);
4236 This->lastBlockNoInSequence = blockNoInSequence;
4240 ULONG temp = blockNoInSequence;
4242 blockIndex = This->lastBlockNoInSequenceIndex;
4243 blockNoInSequence -= This->lastBlockNoInSequence;
4244 This->lastBlockNoInSequence = temp;
4247 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4250 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4252 blockNoInSequence--;
4255 This->lastBlockNoInSequenceIndex = blockIndex;
4258 * Here, I'm casting away the constness on the buffer variable
4259 * This is OK since we don't intend to modify that buffer.
4262 bufferWalker = (BYTE*)buffer;
4264 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4267 * Calculate how many bytes we can copy from this big block.
4270 min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4273 * Copy those bytes to the buffer
4275 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
4277 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
4279 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4282 * Step to the next big block.
4285 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4287 bufferWalker += bytesToWrite;
4288 size -= bytesToWrite;
4289 *bytesWritten += bytesToWrite;
4290 offsetInBlock = 0; /* There is no offset on the next block */
4296 /******************************************************************************
4297 * BlockChainStream_Shrink
4299 * Shrinks this chain in the big block depot.
4301 BOOL BlockChainStream_Shrink(BlockChainStream* This,
4302 ULARGE_INTEGER newSize)
4304 ULONG blockIndex, extraBlock;
4309 * Reset the last accessed block cache.
4311 This->lastBlockNoInSequence = 0xFFFFFFFF;
4312 This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4315 * Figure out how many blocks are needed to contain the new size
4317 numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4319 if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4322 blockIndex = BlockChainStream_GetHeadOfChain(This);
4325 * Go to the new end of chain
4327 while (count < numBlocks)
4330 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4335 /* Get the next block before marking the new end */
4337 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4339 /* Mark the new end of chain */
4340 StorageImpl_SetNextBlockInChain(
4341 This->parentStorage,
4343 BLOCK_END_OF_CHAIN);
4345 This->tailIndex = blockIndex;
4346 This->numBlocks = numBlocks;
4349 * Mark the extra blocks as free
4351 while (extraBlock != BLOCK_END_OF_CHAIN)
4354 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4356 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4357 extraBlock = blockIndex;
4363 /******************************************************************************
4364 * BlockChainStream_Enlarge
4366 * Grows this chain in the big block depot.
4368 BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4369 ULARGE_INTEGER newSize)
4371 ULONG blockIndex, currentBlock;
4373 ULONG oldNumBlocks = 0;
4375 blockIndex = BlockChainStream_GetHeadOfChain(This);
4378 * Empty chain. Create the head.
4380 if (blockIndex == BLOCK_END_OF_CHAIN)
4382 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4383 StorageImpl_SetNextBlockInChain(This->parentStorage,
4385 BLOCK_END_OF_CHAIN);
4387 if (This->headOfStreamPlaceHolder != 0)
4389 *(This->headOfStreamPlaceHolder) = blockIndex;
4393 StgProperty chainProp;
4394 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4396 StorageImpl_ReadProperty(
4397 This->parentStorage,
4398 This->ownerPropertyIndex,
4401 chainProp.startingBlock = blockIndex;
4403 StorageImpl_WriteProperty(
4404 This->parentStorage,
4405 This->ownerPropertyIndex,
4409 This->tailIndex = blockIndex;
4410 This->numBlocks = 1;
4414 * Figure out how many blocks are needed to contain this stream
4416 newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4418 if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4422 * Go to the current end of chain
4424 if (This->tailIndex == BLOCK_END_OF_CHAIN)
4426 currentBlock = blockIndex;
4428 while (blockIndex != BLOCK_END_OF_CHAIN)
4431 currentBlock = blockIndex;
4434 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4437 This->tailIndex = currentBlock;
4440 currentBlock = This->tailIndex;
4441 oldNumBlocks = This->numBlocks;
4444 * Add new blocks to the chain
4446 if (oldNumBlocks < newNumBlocks)
4448 while (oldNumBlocks < newNumBlocks)
4450 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4452 StorageImpl_SetNextBlockInChain(
4453 This->parentStorage,
4457 StorageImpl_SetNextBlockInChain(
4458 This->parentStorage,
4460 BLOCK_END_OF_CHAIN);
4462 currentBlock = blockIndex;
4466 This->tailIndex = blockIndex;
4467 This->numBlocks = newNumBlocks;
4473 /******************************************************************************
4474 * BlockChainStream_SetSize
4476 * Sets the size of this stream. The big block depot will be updated.
4477 * The file will grow if we grow the chain.
4479 * TODO: Free the actual blocks in the file when we shrink the chain.
4480 * Currently, the blocks are still in the file. So the file size
4481 * doesn't shrink even if we shrink streams.
4483 BOOL BlockChainStream_SetSize(
4484 BlockChainStream* This,
4485 ULARGE_INTEGER newSize)
4487 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4489 if (newSize.u.LowPart == size.u.LowPart)
4492 if (newSize.u.LowPart < size.u.LowPart)
4494 BlockChainStream_Shrink(This, newSize);
4498 ULARGE_INTEGER fileSize =
4499 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4501 ULONG diff = newSize.u.LowPart - size.u.LowPart;
4504 * Make sure the file stays a multiple of blocksize
4506 if ((diff % This->parentStorage->bigBlockSize) != 0)
4507 diff += (This->parentStorage->bigBlockSize -
4508 (diff % This->parentStorage->bigBlockSize) );
4510 fileSize.u.LowPart += diff;
4511 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4513 BlockChainStream_Enlarge(This, newSize);
4519 /******************************************************************************
4520 * BlockChainStream_GetSize
4522 * Returns the size of this chain.
4523 * Will return the block count if this chain doesn't have a property.
4525 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4527 StgProperty chainProperty;
4529 if(This->headOfStreamPlaceHolder == NULL)
4532 * This chain is a data stream read the property and return
4533 * the appropriate size
4535 StorageImpl_ReadProperty(
4536 This->parentStorage,
4537 This->ownerPropertyIndex,
4540 return chainProperty.size;
4545 * this chain is a chain that does not have a property, figure out the
4546 * size by making the product number of used blocks times the
4549 ULARGE_INTEGER result;
4550 result.u.HighPart = 0;
4553 BlockChainStream_GetCount(This) *
4554 This->parentStorage->bigBlockSize;
4560 /******************************************************************************
4561 ** SmallBlockChainStream implementation
4564 SmallBlockChainStream* SmallBlockChainStream_Construct(
4565 StorageImpl* parentStorage,
4566 ULONG propertyIndex)
4568 SmallBlockChainStream* newStream;
4570 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4572 newStream->parentStorage = parentStorage;
4573 newStream->ownerPropertyIndex = propertyIndex;
4578 void SmallBlockChainStream_Destroy(
4579 SmallBlockChainStream* This)
4581 HeapFree(GetProcessHeap(), 0, This);
4584 /******************************************************************************
4585 * SmallBlockChainStream_GetHeadOfChain
4587 * Returns the head of this chain of small blocks.
4589 ULONG SmallBlockChainStream_GetHeadOfChain(
4590 SmallBlockChainStream* This)
4592 StgProperty chainProperty;
4593 BOOL readSuccessful;
4595 if (This->ownerPropertyIndex)
4597 readSuccessful = StorageImpl_ReadProperty(
4598 This->parentStorage,
4599 This->ownerPropertyIndex,
4604 return chainProperty.startingBlock;
4609 return BLOCK_END_OF_CHAIN;
4612 /******************************************************************************
4613 * SmallBlockChainStream_GetNextBlockInChain
4615 * Returns the index of the next small block in this chain.
4618 * - BLOCK_END_OF_CHAIN: end of this chain
4619 * - BLOCK_UNUSED: small block 'blockIndex' is free
4621 ULONG SmallBlockChainStream_GetNextBlockInChain(
4622 SmallBlockChainStream* This,
4625 ULARGE_INTEGER offsetOfBlockInDepot;
4627 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4631 offsetOfBlockInDepot.u.HighPart = 0;
4632 offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
4635 * Read those bytes in the buffer from the small block file.
4637 success = BlockChainStream_ReadAt(
4638 This->parentStorage->smallBlockDepotChain,
4639 offsetOfBlockInDepot,
4646 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4649 return nextBlockInChain;
4652 /******************************************************************************
4653 * SmallBlockChainStream_SetNextBlockInChain
4655 * Writes the index of the next block of the specified block in the small
4657 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4658 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4660 void SmallBlockChainStream_SetNextBlockInChain(
4661 SmallBlockChainStream* This,
4665 ULARGE_INTEGER offsetOfBlockInDepot;
4669 offsetOfBlockInDepot.u.HighPart = 0;
4670 offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
4672 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4675 * Read those bytes in the buffer from the small block file.
4677 BlockChainStream_WriteAt(
4678 This->parentStorage->smallBlockDepotChain,
4679 offsetOfBlockInDepot,
4685 /******************************************************************************
4686 * SmallBlockChainStream_FreeBlock
4688 * Flag small block 'blockIndex' as free in the small block depot.
4690 void SmallBlockChainStream_FreeBlock(
4691 SmallBlockChainStream* This,
4694 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4697 /******************************************************************************
4698 * SmallBlockChainStream_GetNextFreeBlock
4700 * Returns the index of a free small block. The small block depot will be
4701 * enlarged if necessary. The small block chain will also be enlarged if
4704 ULONG SmallBlockChainStream_GetNextFreeBlock(
4705 SmallBlockChainStream* This)
4707 ULARGE_INTEGER offsetOfBlockInDepot;
4710 ULONG blockIndex = 0;
4711 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4712 BOOL success = TRUE;
4713 ULONG smallBlocksPerBigBlock;
4715 offsetOfBlockInDepot.u.HighPart = 0;
4718 * Scan the small block depot for a free block
4720 while (nextBlockIndex != BLOCK_UNUSED)
4722 offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
4724 success = BlockChainStream_ReadAt(
4725 This->parentStorage->smallBlockDepotChain,
4726 offsetOfBlockInDepot,
4732 * If we run out of space for the small block depot, enlarge it
4736 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4738 if (nextBlockIndex != BLOCK_UNUSED)
4744 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4746 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4747 ULONG nextBlock, newsbdIndex;
4748 BYTE* smallBlockDepot;
4750 nextBlock = sbdIndex;
4751 while (nextBlock != BLOCK_END_OF_CHAIN)
4753 sbdIndex = nextBlock;
4755 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4758 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4759 if (sbdIndex != BLOCK_END_OF_CHAIN)
4760 StorageImpl_SetNextBlockInChain(
4761 This->parentStorage,
4765 StorageImpl_SetNextBlockInChain(
4766 This->parentStorage,
4768 BLOCK_END_OF_CHAIN);
4771 * Initialize all the small blocks to free
4774 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4776 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4777 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4782 * We have just created the small block depot.
4784 StgProperty rootProp;
4788 * Save it in the header
4790 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4791 StorageImpl_SaveFileHeader(This->parentStorage);
4794 * And allocate the first big block that will contain small blocks
4797 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4799 StorageImpl_SetNextBlockInChain(
4800 This->parentStorage,
4802 BLOCK_END_OF_CHAIN);
4804 StorageImpl_ReadProperty(
4805 This->parentStorage,
4806 This->parentStorage->rootPropertySetIndex,
4809 rootProp.startingBlock = sbStartIndex;
4810 rootProp.size.u.HighPart = 0;
4811 rootProp.size.u.LowPart = This->parentStorage->bigBlockSize;
4813 StorageImpl_WriteProperty(
4814 This->parentStorage,
4815 This->parentStorage->rootPropertySetIndex,
4821 smallBlocksPerBigBlock =
4822 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4825 * Verify if we have to allocate big blocks to contain small blocks
4827 if (blockIndex % smallBlocksPerBigBlock == 0)
4829 StgProperty rootProp;
4830 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4832 StorageImpl_ReadProperty(
4833 This->parentStorage,
4834 This->parentStorage->rootPropertySetIndex,
4837 if (rootProp.size.u.LowPart <
4838 (blocksRequired * This->parentStorage->bigBlockSize))
4840 rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
4842 BlockChainStream_SetSize(
4843 This->parentStorage->smallBlockRootChain,
4846 StorageImpl_WriteProperty(
4847 This->parentStorage,
4848 This->parentStorage->rootPropertySetIndex,
4856 /******************************************************************************
4857 * SmallBlockChainStream_ReadAt
4859 * Reads a specified number of bytes from this chain at the specified offset.
4860 * bytesRead may be NULL.
4861 * Failure will be returned if the specified number of bytes has not been read.
4863 BOOL SmallBlockChainStream_ReadAt(
4864 SmallBlockChainStream* This,
4865 ULARGE_INTEGER offset,
4870 ULARGE_INTEGER offsetInBigBlockFile;
4871 ULONG blockNoInSequence =
4872 offset.u.LowPart / This->parentStorage->smallBlockSize;
4874 ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
4875 ULONG bytesToReadInBuffer;
4877 ULONG bytesReadFromBigBlockFile;
4881 * This should never happen on a small block file.
4883 assert(offset.u.HighPart==0);
4886 * Find the first block in the stream that contains part of the buffer.
4888 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4890 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4892 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4894 blockNoInSequence--;
4898 * Start reading the buffer.
4901 bufferWalker = buffer;
4903 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4906 * Calculate how many bytes we can copy from this small block.
4908 bytesToReadInBuffer =
4909 min(This->parentStorage->smallBlockSize - offsetInBlock, size);
4912 * Calculate the offset of the small block in the small block file.
4914 offsetInBigBlockFile.u.HighPart = 0;
4915 offsetInBigBlockFile.u.LowPart =
4916 blockIndex * This->parentStorage->smallBlockSize;
4918 offsetInBigBlockFile.u.LowPart += offsetInBlock;
4921 * Read those bytes in the buffer from the small block file.
4923 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4924 offsetInBigBlockFile,
4925 bytesToReadInBuffer,
4927 &bytesReadFromBigBlockFile);
4929 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4932 * Step to the next big block.
4934 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4935 bufferWalker += bytesToReadInBuffer;
4936 size -= bytesToReadInBuffer;
4937 *bytesRead += bytesToReadInBuffer;
4938 offsetInBlock = 0; /* There is no offset on the next block */
4944 /******************************************************************************
4945 * SmallBlockChainStream_WriteAt
4947 * Writes the specified number of bytes to this chain at the specified offset.
4948 * bytesWritten may be NULL.
4949 * Will fail if not all specified number of bytes have been written.
4951 BOOL SmallBlockChainStream_WriteAt(
4952 SmallBlockChainStream* This,
4953 ULARGE_INTEGER offset,
4956 ULONG* bytesWritten)
4958 ULARGE_INTEGER offsetInBigBlockFile;
4959 ULONG blockNoInSequence =
4960 offset.u.LowPart / This->parentStorage->smallBlockSize;
4962 ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
4963 ULONG bytesToWriteInBuffer;
4965 ULONG bytesWrittenFromBigBlockFile;
4969 * This should never happen on a small block file.
4971 assert(offset.u.HighPart==0);
4974 * Find the first block in the stream that contains part of the buffer.
4976 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4978 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4980 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4982 blockNoInSequence--;
4986 * Start writing the buffer.
4988 * Here, I'm casting away the constness on the buffer variable
4989 * This is OK since we don't intend to modify that buffer.
4992 bufferWalker = (BYTE*)buffer;
4993 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4996 * Calculate how many bytes we can copy to this small block.
4998 bytesToWriteInBuffer =
4999 min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5002 * Calculate the offset of the small block in the small block file.
5004 offsetInBigBlockFile.u.HighPart = 0;
5005 offsetInBigBlockFile.u.LowPart =
5006 blockIndex * This->parentStorage->smallBlockSize;
5008 offsetInBigBlockFile.u.LowPart += offsetInBlock;
5011 * Write those bytes in the buffer to the small block file.
5013 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
5014 offsetInBigBlockFile,
5015 bytesToWriteInBuffer,
5017 &bytesWrittenFromBigBlockFile);
5019 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
5022 * Step to the next big block.
5024 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5025 bufferWalker += bytesToWriteInBuffer;
5026 size -= bytesToWriteInBuffer;
5027 *bytesWritten += bytesToWriteInBuffer;
5028 offsetInBlock = 0; /* There is no offset on the next block */
5034 /******************************************************************************
5035 * SmallBlockChainStream_Shrink
5037 * Shrinks this chain in the small block depot.
5039 BOOL SmallBlockChainStream_Shrink(
5040 SmallBlockChainStream* This,
5041 ULARGE_INTEGER newSize)
5043 ULONG blockIndex, extraBlock;
5047 numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5049 if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5052 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5055 * Go to the new end of chain
5057 while (count < numBlocks)
5059 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5064 * If the count is 0, we have a special case, the head of the chain was
5069 StgProperty chainProp;
5071 StorageImpl_ReadProperty(This->parentStorage,
5072 This->ownerPropertyIndex,
5075 chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5077 StorageImpl_WriteProperty(This->parentStorage,
5078 This->ownerPropertyIndex,
5082 * We start freeing the chain at the head block.
5084 extraBlock = blockIndex;
5088 /* Get the next block before marking the new end */
5089 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5091 /* Mark the new end of chain */
5092 SmallBlockChainStream_SetNextBlockInChain(
5095 BLOCK_END_OF_CHAIN);
5099 * Mark the extra blocks as free
5101 while (extraBlock != BLOCK_END_OF_CHAIN)
5103 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
5104 SmallBlockChainStream_FreeBlock(This, extraBlock);
5105 extraBlock = blockIndex;
5111 /******************************************************************************
5112 * SmallBlockChainStream_Enlarge
5114 * Grows this chain in the small block depot.
5116 BOOL SmallBlockChainStream_Enlarge(
5117 SmallBlockChainStream* This,
5118 ULARGE_INTEGER newSize)
5120 ULONG blockIndex, currentBlock;
5122 ULONG oldNumBlocks = 0;
5124 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5129 if (blockIndex == BLOCK_END_OF_CHAIN)
5132 StgProperty chainProp;
5134 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5137 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5139 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5142 blockIndex = chainProp.startingBlock;
5143 SmallBlockChainStream_SetNextBlockInChain(
5146 BLOCK_END_OF_CHAIN);
5149 currentBlock = blockIndex;
5152 * Figure out how many blocks are needed to contain this stream
5154 newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5156 if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5160 * Go to the current end of chain
5162 while (blockIndex != BLOCK_END_OF_CHAIN)
5165 currentBlock = blockIndex;
5166 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
5170 * Add new blocks to the chain
5172 while (oldNumBlocks < newNumBlocks)
5174 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5175 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5177 SmallBlockChainStream_SetNextBlockInChain(
5180 BLOCK_END_OF_CHAIN);
5182 currentBlock = blockIndex;
5189 /******************************************************************************
5190 * SmallBlockChainStream_GetCount
5192 * Returns the number of blocks that comprises this chain.
5193 * This is not the size of this chain as the last block may not be full!
5195 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5200 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5202 while (blockIndex != BLOCK_END_OF_CHAIN)
5206 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5212 /******************************************************************************
5213 * SmallBlockChainStream_SetSize
5215 * Sets the size of this stream.
5216 * The file will grow if we grow the chain.
5218 * TODO: Free the actual blocks in the file when we shrink the chain.
5219 * Currently, the blocks are still in the file. So the file size
5220 * doesn't shrink even if we shrink streams.
5222 BOOL SmallBlockChainStream_SetSize(
5223 SmallBlockChainStream* This,
5224 ULARGE_INTEGER newSize)
5226 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5228 if (newSize.u.LowPart == size.u.LowPart)
5231 if (newSize.u.LowPart < size.u.LowPart)
5233 SmallBlockChainStream_Shrink(This, newSize);
5237 SmallBlockChainStream_Enlarge(This, newSize);
5243 /******************************************************************************
5244 * SmallBlockChainStream_GetSize
5246 * Returns the size of this chain.
5248 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5250 StgProperty chainProperty;
5252 StorageImpl_ReadProperty(
5253 This->parentStorage,
5254 This->ownerPropertyIndex,
5257 return chainProperty.size;
5260 /******************************************************************************
5261 * StgCreateDocfile [OLE32.144]
5263 HRESULT WINAPI StgCreateDocfile(
5267 IStorage **ppstgOpen)
5269 StorageImpl* newStorage = 0;
5270 HANDLE hFile = INVALID_HANDLE_VALUE;
5275 DWORD fileAttributes;
5276 WCHAR tempFileName[MAX_PATH];
5278 Print(MAX_TRACE, ("(%S, %lx, %ld, %p)\n",
5280 reserved, ppstgOpen));
5283 * Validate the parameters
5286 return STG_E_INVALIDPOINTER;
5289 * Validate the STGM flags
5291 if ( FAILED( validateSTGM(grfMode) ))
5292 return STG_E_INVALIDFLAG;
5295 * Generate a unique name.
5299 WCHAR tempPath[MAX_PATH];
5300 WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5302 if (!(grfMode & STGM_SHARE_EXCLUSIVE))
5303 return STG_E_INVALIDFLAG;
5304 if (!(grfMode & (STGM_WRITE|STGM_READWRITE)))
5305 return STG_E_INVALIDFLAG;
5307 memset(tempPath, 0, sizeof(tempPath));
5308 memset(tempFileName, 0, sizeof(tempFileName));
5310 if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5313 if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5314 pwcsName = tempFileName;
5316 return STG_E_INSUFFICIENTMEMORY;
5318 creationMode = TRUNCATE_EXISTING;
5322 creationMode = GetCreationModeFromSTGM(grfMode);
5326 * Interpret the STGM value grfMode
5328 shareMode = GetShareModeFromSTGM(grfMode);
5329 accessMode = GetAccessModeFromSTGM(grfMode);
5331 if (grfMode & STGM_DELETEONRELEASE)
5332 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5334 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5336 if (grfMode & STGM_TRANSACTED)
5340 * Initialize the "out" parameter.
5344 hFile = CreateFileW(pwcsName,
5352 if (hFile == INVALID_HANDLE_VALUE)
5358 * Allocate and initialize the new IStorage32object.
5360 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5362 if (newStorage == 0)
5363 return STG_E_INSUFFICIENTMEMORY;
5365 hr = StorageImpl_Construct(
5375 HeapFree(GetProcessHeap(), 0, newStorage);
5380 * Get an "out" pointer for the caller.
5382 hr = StorageBaseImpl_QueryInterface(
5383 (IStorage*)newStorage,
5384 (REFIID)&IID_IStorage,
5390 /******************************************************************************
5391 * StgOpenStorage [OLE32.148]
5393 HRESULT WINAPI StgOpenStorage(
5394 const OLECHAR *pwcsName,
5395 IStorage *pstgPriority,
5399 IStorage **ppstgOpen)
5401 StorageImpl* newStorage = 0;
5407 Print(MAX_TRACE, ("(%S, %p, %lx, %p, %ld, %p)\n",
5408 pwcsName, pstgPriority, grfMode,
5409 snbExclude, reserved, ppstgOpen));
5412 * Perform a sanity check
5414 if (( pwcsName == 0) || (ppstgOpen == 0) )
5415 return STG_E_INVALIDPOINTER;
5418 * Validate the STGM flags
5420 if ( FAILED( validateSTGM(grfMode) ))
5421 return STG_E_INVALIDFLAG;
5424 * Interpret the STGM value grfMode
5426 shareMode = GetShareModeFromSTGM(grfMode);
5427 accessMode = GetAccessModeFromSTGM(grfMode);
5430 * Initialize the "out" parameter.
5434 hFile = CreateFileW( pwcsName,
5439 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5443 if (hFile==INVALID_HANDLE_VALUE)
5445 HRESULT hr = E_FAIL;
5446 DWORD last_error = GetLastError();
5450 case ERROR_FILE_NOT_FOUND:
5451 hr = STG_E_FILENOTFOUND;
5454 case ERROR_PATH_NOT_FOUND:
5455 hr = STG_E_PATHNOTFOUND;
5458 case ERROR_ACCESS_DENIED:
5459 case ERROR_WRITE_PROTECT:
5460 hr = STG_E_ACCESSDENIED;
5463 case ERROR_SHARING_VIOLATION:
5464 hr = STG_E_SHAREVIOLATION;
5475 * Allocate and initialize the new IStorage32object.
5477 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5479 if (newStorage == 0)
5480 return STG_E_INSUFFICIENTMEMORY;
5482 hr = StorageImpl_Construct(
5492 HeapFree(GetProcessHeap(), 0, newStorage);
5494 * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
5496 if(hr == STG_E_INVALIDHEADER)
5497 return STG_E_FILEALREADYEXISTS;
5502 * Get an "out" pointer for the caller.
5504 hr = StorageBaseImpl_QueryInterface(
5505 (IStorage*)newStorage,
5506 (REFIID)&IID_IStorage,
5512 /******************************************************************************
5513 * StgCreateDocfileOnILockBytes [OLE32.145]
5515 HRESULT WINAPI StgCreateDocfileOnILockBytes(
5519 IStorage** ppstgOpen)
5521 StorageImpl* newStorage = 0;
5525 * Validate the parameters
5527 if ((ppstgOpen == 0) || (plkbyt == 0))
5528 return STG_E_INVALIDPOINTER;
5531 * Allocate and initialize the new IStorage object.
5533 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5535 if (newStorage == 0)
5536 return STG_E_INSUFFICIENTMEMORY;
5538 hr = StorageImpl_Construct(
5548 HeapFree(GetProcessHeap(), 0, newStorage);
5553 * Get an "out" pointer for the caller.
5555 hr = StorageBaseImpl_QueryInterface(
5556 (IStorage*)newStorage,
5557 (REFIID)&IID_IStorage,
5563 /******************************************************************************
5564 * StgOpenStorageOnILockBytes [OLE32.149]
5566 HRESULT WINAPI StgOpenStorageOnILockBytes(
5568 IStorage *pstgPriority,
5572 IStorage **ppstgOpen)
5574 StorageImpl* newStorage = 0;
5578 * Perform a sanity check
5580 if ((plkbyt == 0) || (ppstgOpen == 0))
5581 return STG_E_INVALIDPOINTER;
5584 * Validate the STGM flags
5586 if ( FAILED( validateSTGM(grfMode) ))
5587 return STG_E_INVALIDFLAG;
5590 * Initialize the "out" parameter.
5595 * Allocate and initialize the new IStorage object.
5597 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5599 if (newStorage == 0)
5600 return STG_E_INSUFFICIENTMEMORY;
5602 hr = StorageImpl_Construct(
5612 HeapFree(GetProcessHeap(), 0, newStorage);
5617 * Get an "out" pointer for the caller.
5619 hr = StorageBaseImpl_QueryInterface(
5620 (IStorage*)newStorage,
5621 (REFIID)&IID_IStorage,
5627 /******************************************************************************
5628 * StgSetTimes [ole32.150]
5632 HRESULT WINAPI StgSetTimes(WCHAR * str, FILETIME * a, FILETIME * b, FILETIME *c )
5639 /******************************************************************************
5640 * StgIsStorageILockBytes [OLE32.147]
5642 * Determines if the ILockBytes contains a storage object.
5644 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
5647 ULARGE_INTEGER offset;
5649 offset.u.HighPart = 0;
5650 offset.u.LowPart = 0;
5652 ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
5654 if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
5660 /******************************************************************************
5661 * WriteClassStg [OLE32.158]
5663 * This method will store the specified CLSID in the specified storage object
5665 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5671 hRes = IStorage_SetClass(pStg, rclsid);
5676 /***********************************************************************
5679 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5681 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
5686 Print(MAX_TRACE, ("()\n"));
5691 * read a STATSTG structure (contains the clsid) from the storage
5693 hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
5696 *pclsid=pstatstg.clsid;
5701 /***********************************************************************
5704 * This function loads an object from stream
5706 HRESULT WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
5710 LPPERSISTSTREAM xstm;
5712 Print(MAX_TRACE, ("(%p,%s,%p)\n",pStm,PRINT_GUID(iidInterface),ppvObj));
5714 res=ReadClassStm(pStm,&clsid);
5715 if (!SUCCEEDED(res))
5717 res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
5718 if (!SUCCEEDED(res))
5720 res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
5721 if (!SUCCEEDED(res)) {
5722 IUnknown_Release((IUnknown*)*ppvObj);
5725 res=IPersistStream_Load(xstm,pStm);
5726 IPersistStream_Release(xstm);
5727 /* FIXME: all refcounts ok at this point? I think they should be:
5730 * xstm : 0 (released)
5735 /***********************************************************************
5738 * This function saves an object with the IPersistStream interface on it
5739 * to the specified stream.
5741 HRESULT WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
5747 Print(MAX_TRACE, ("(%p,%p)\n",pPStm,pStm));
5749 res=IPersistStream_GetClassID(pPStm,&clsid);
5751 if (SUCCEEDED(res)){
5753 res=WriteClassStm(pStm,&clsid);
5757 res=IPersistStream_Save(pPStm,pStm,TRUE);
5760 Print(MAX_TRACE, ("Finished Save\n"));
5764 /****************************************************************************
5765 * This method validate a STGM parameter that can contain the values below
5767 * STGM_DIRECT 0x00000000
5768 * STGM_TRANSACTED 0x00010000
5769 * STGM_SIMPLE 0x08000000
5771 * STGM_READ 0x00000000
5772 * STGM_WRITE 0x00000001
5773 * STGM_READWRITE 0x00000002
5775 * STGM_SHARE_DENY_NONE 0x00000040
5776 * STGM_SHARE_DENY_READ 0x00000030
5777 * STGM_SHARE_DENY_WRITE 0x00000020
5778 * STGM_SHARE_EXCLUSIVE 0x00000010
5780 * STGM_PRIORITY 0x00040000
5781 * STGM_DELETEONRELEASE 0x04000000
5783 * STGM_CREATE 0x00001000
5784 * STGM_CONVERT 0x00020000
5785 * STGM_FAILIFTHERE 0x00000000
5787 * STGM_NOSCRATCH 0x00100000
5788 * STGM_NOSNAPSHOT 0x00200000
5790 static HRESULT validateSTGM(DWORD stgm)
5792 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5793 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5794 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5796 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5797 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5798 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5800 BOOL bSTGM_SHARE_DENY_NONE =
5801 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5803 BOOL bSTGM_SHARE_DENY_READ =
5804 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5806 BOOL bSTGM_SHARE_DENY_WRITE =
5807 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5809 BOOL bSTGM_SHARE_EXCLUSIVE =
5810 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5812 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5813 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5815 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5816 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5819 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5821 if ( ! bSTGM_DIRECT )
5822 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5826 * STGM_WRITE | STGM_READWRITE | STGM_READ
5829 if( bSTGM_WRITE && bSTGM_READWRITE )
5833 * STGM_SHARE_DENY_NONE | others
5834 * (I assume here that DENY_READ implies DENY_WRITE)
5836 if ( bSTGM_SHARE_DENY_NONE )
5837 if ( bSTGM_SHARE_DENY_READ ||
5838 bSTGM_SHARE_DENY_WRITE ||
5839 bSTGM_SHARE_EXCLUSIVE)
5843 * STGM_CREATE | STGM_CONVERT
5844 * if both are false, STGM_FAILIFTHERE is set to TRUE
5846 if ( bSTGM_CREATE && bSTGM_CONVERT )
5850 * STGM_NOSCRATCH requires STGM_TRANSACTED
5852 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5856 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5857 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5859 if (bSTGM_NOSNAPSHOT)
5861 if ( ! ( bSTGM_TRANSACTED &&
5862 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5869 /****************************************************************************
5870 * GetShareModeFromSTGM
5872 * This method will return a share mode flag from a STGM value.
5873 * The STGM value is assumed valid.
5875 static DWORD GetShareModeFromSTGM(DWORD stgm)
5877 DWORD dwShareMode = 0;
5878 BOOL bSTGM_SHARE_DENY_NONE =
5879 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5881 BOOL bSTGM_SHARE_DENY_READ =
5882 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5884 BOOL bSTGM_SHARE_DENY_WRITE =
5885 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5887 BOOL bSTGM_SHARE_EXCLUSIVE =
5888 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5890 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5893 if (bSTGM_SHARE_DENY_NONE)
5894 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5896 if (bSTGM_SHARE_DENY_WRITE)
5897 dwShareMode = FILE_SHARE_READ;
5902 /****************************************************************************
5903 * GetAccessModeFromSTGM
5905 * This method will return an access mode flag from a STGM value.
5906 * The STGM value is assumed valid.
5908 static DWORD GetAccessModeFromSTGM(DWORD stgm)
5910 DWORD dwDesiredAccess = GENERIC_READ;
5911 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5912 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5913 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5916 dwDesiredAccess = GENERIC_READ;
5919 dwDesiredAccess |= GENERIC_WRITE;
5921 if (bSTGM_READWRITE)
5922 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5924 return dwDesiredAccess;
5927 /****************************************************************************
5928 * GetCreationModeFromSTGM
5930 * This method will return a creation mode flag from a STGM value.
5931 * The STGM value is assumed valid.
5933 static DWORD GetCreationModeFromSTGM(DWORD stgm)
5935 if ( stgm & STGM_CREATE)
5936 return CREATE_ALWAYS;
5937 if (stgm & STGM_CONVERT) {
5941 /* All other cases */
5942 if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
5943 Print(MIN_TRACE, ("unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT)));
5948 /*************************************************************************
5949 * OLECONVERT_LoadOLE10 [Internal]
5951 * Loads the OLE10 STREAM to memory
5954 * pOleStream [I] The OLESTREAM
5955 * pData [I] Data Structure for the OLESTREAM Data
5959 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
5960 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
5963 * This function is used by OleConvertOLESTREAMToIStorage only.
5965 * Memory allocated for pData must be freed by the caller
5967 HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
5970 HRESULT hRes = S_OK;
5974 pData->pData = NULL;
5975 pData->pstrOleObjFileName = (CHAR *) NULL;
5977 for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
5980 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
5981 if(dwSize != sizeof(pData->dwOleID))
5983 hRes = CONVERT10_E_OLESTREAM_GET;
5985 else if(pData->dwOleID != OLESTREAM_ID)
5987 hRes = CONVERT10_E_OLESTREAM_FMT;
5998 /* Get the TypeID...more info needed for this field */
5999 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6000 if(dwSize != sizeof(pData->dwTypeID))
6002 hRes = CONVERT10_E_OLESTREAM_GET;
6007 if(pData->dwTypeID != 0)
6009 /* Get the lenght of the OleTypeName */
6010 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6011 if(dwSize != sizeof(pData->dwOleTypeNameLength))
6013 hRes = CONVERT10_E_OLESTREAM_GET;
6018 if(pData->dwOleTypeNameLength > 0)
6020 /* Get the OleTypeName */
6021 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6022 if(dwSize != pData->dwOleTypeNameLength)
6024 hRes = CONVERT10_E_OLESTREAM_GET;
6030 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6031 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6033 hRes = CONVERT10_E_OLESTREAM_GET;
6037 if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6038 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6039 pData->pstrOleObjFileName = (CHAR *)malloc(pData->dwOleObjFileNameLength);
6040 if(pData->pstrOleObjFileName)
6042 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6043 if(dwSize != pData->dwOleObjFileNameLength)
6045 hRes = CONVERT10_E_OLESTREAM_GET;
6049 hRes = CONVERT10_E_OLESTREAM_GET;
6054 /* Get the Width of the Metafile */
6055 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6056 if(dwSize != sizeof(pData->dwMetaFileWidth))
6058 hRes = CONVERT10_E_OLESTREAM_GET;
6062 /* Get the Height of the Metafile */
6063 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6064 if(dwSize != sizeof(pData->dwMetaFileHeight))
6066 hRes = CONVERT10_E_OLESTREAM_GET;
6072 /* Get the Lenght of the Data */
6073 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6074 if(dwSize != sizeof(pData->dwDataLength))
6076 hRes = CONVERT10_E_OLESTREAM_GET;
6080 if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6082 if(!bStrem1) /* if it is a second OLE stream data */
6084 pData->dwDataLength -= 8;
6085 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6086 if(dwSize != sizeof(pData->strUnknown))
6088 hRes = CONVERT10_E_OLESTREAM_GET;
6094 if(pData->dwDataLength > 0)
6096 pData->pData = (BYTE *)HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6098 /* Get Data (ex. IStorage, Metafile, or BMP) */
6101 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6102 if(dwSize != pData->dwDataLength)
6104 hRes = CONVERT10_E_OLESTREAM_GET;
6109 hRes = CONVERT10_E_OLESTREAM_GET;
6118 /*************************************************************************
6119 * OLECONVERT_SaveOLE10 [Internal]
6121 * Saves the OLE10 STREAM From memory
6124 * pData [I] Data Structure for the OLESTREAM Data
6125 * pOleStream [I] The OLESTREAM to save
6129 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6132 * This function is used by OleConvertIStorageToOLESTREAM only.
6135 HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6138 HRESULT hRes = S_OK;
6142 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6143 if(dwSize != sizeof(pData->dwOleID))
6145 hRes = CONVERT10_E_OLESTREAM_PUT;
6150 /* Set the TypeID */
6151 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6152 if(dwSize != sizeof(pData->dwTypeID))
6154 hRes = CONVERT10_E_OLESTREAM_PUT;
6158 if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6160 /* Set the Lenght of the OleTypeName */
6161 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6162 if(dwSize != sizeof(pData->dwOleTypeNameLength))
6164 hRes = CONVERT10_E_OLESTREAM_PUT;
6169 if(pData->dwOleTypeNameLength > 0)
6171 /* Set the OleTypeName */
6172 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->strOleTypeName, pData->dwOleTypeNameLength);
6173 if(dwSize != pData->dwOleTypeNameLength)
6175 hRes = CONVERT10_E_OLESTREAM_PUT;
6182 /* Set the width of the Metafile */
6183 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6184 if(dwSize != sizeof(pData->dwMetaFileWidth))
6186 hRes = CONVERT10_E_OLESTREAM_PUT;
6192 /* Set the height of the Metafile */
6193 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6194 if(dwSize != sizeof(pData->dwMetaFileHeight))
6196 hRes = CONVERT10_E_OLESTREAM_PUT;
6202 /* Set the lenght of the Data */
6203 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6204 if(dwSize != sizeof(pData->dwDataLength))
6206 hRes = CONVERT10_E_OLESTREAM_PUT;
6212 if(pData->dwDataLength > 0)
6214 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6215 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->pData, pData->dwDataLength);
6216 if(dwSize != pData->dwDataLength)
6218 hRes = CONVERT10_E_OLESTREAM_PUT;
6226 /*************************************************************************
6227 * OLECONVERT_GetOLE20FromOLE10[Internal]
6229 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6230 * opens it, and copies the content to the dest IStorage for
6231 * OleConvertOLESTREAMToIStorage
6235 * pDestStorage [I] The IStorage to copy the data to
6236 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
6237 * nBufferLength [I] The size of the buffer
6246 void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6250 IStorage *pTempStorage;
6251 DWORD dwNumOfBytesWritten;
6252 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6253 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6255 /* Create a temp File */
6256 GetTempPathW(MAX_PATH, wstrTempDir);
6257 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6258 hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6260 if(hFile != INVALID_HANDLE_VALUE)
6262 /* Write IStorage Data to File */
6263 WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6266 /* Open and copy temp storage to the Dest Storage */
6267 hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6270 hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6271 StorageBaseImpl_Release(pTempStorage);
6273 DeleteFileW(wstrTempFile);
6278 /*************************************************************************
6279 * OLECONVERT_WriteOLE20ToBuffer [Internal]
6281 * Saves the OLE10 STREAM From memory
6284 * pStorage [I] The Src IStorage to copy
6285 * pData [I] The Dest Memory to write to.
6288 * The size in bytes allocated for pData
6291 * Memory allocated for pData must be freed by the caller
6293 * Used by OleConvertIStorageToOLESTREAM only.
6296 DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6300 DWORD nDataLength = 0;
6301 IStorage *pTempStorage;
6302 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6303 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6307 /* Create temp Storage */
6308 GetTempPathW(MAX_PATH, wstrTempDir);
6309 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6310 hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6314 /* Copy Src Storage to the Temp Storage */
6315 StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6316 StorageBaseImpl_Release(pTempStorage);
6318 /* Open Temp Storage as a file and copy to memory */
6319 hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6320 if(hFile != INVALID_HANDLE_VALUE)
6322 nDataLength = GetFileSize(hFile, NULL);
6323 *pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,nDataLength);
6324 ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6327 DeleteFileW(wstrTempFile);
6332 /*************************************************************************
6333 * OLECONVERT_CreateOleStream [Internal]
6335 * Creates the "\001OLE" stream in the IStorage if neccessary.
6338 * pStorage [I] Dest storage to create the stream in
6344 * This function is used by OleConvertOLESTREAMToIStorage only.
6346 * This stream is still unknown, MS Word seems to have extra data
6347 * but since the data is stored in the OLESTREAM there should be
6348 * no need to recreate the stream. If the stream is manually
6349 * deleted it will create it with this default data.
6352 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6356 WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6357 BYTE pOleStreamHeader [] =
6359 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6361 0x00, 0x00, 0x00, 0x00
6364 /* Create stream if not present */
6365 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6366 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6370 /* Write default Data */
6371 hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6372 IStream_Release(pStream);
6377 /*************************************************************************
6378 * OLECONVERT_CreateCompObjStream [Internal]
6380 * Creates a "\001CompObj" is the destination IStorage if necessary.
6383 * pStorage [I] The dest IStorage to create the CompObj Stream
6385 * strOleTypeName [I] The ProgID
6389 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6392 * This function is used by OleConvertOLESTREAMToIStorage only.
6394 * The stream data is stored in the OLESTREAM and there should be
6395 * no need to recreate the stream. If the stream is manually
6396 * deleted it will attempt to create it by querying the registry.
6400 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
6403 HRESULT hStorageRes, hRes = S_OK;
6404 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
6405 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6407 BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
6408 BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
6410 /* Initialize the CompObj structure */
6411 memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
6412 memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
6413 memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
6416 /* Create a CompObj stream if it doesn't exist */
6417 hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
6418 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6419 if(hStorageRes == S_OK)
6421 /* copy the OleTypeName to the compobj struct */
6422 IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
6423 strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
6425 /* copy the OleTypeName to the compobj struct */
6426 /* Note: in the test made, these were Identical */
6427 IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
6428 strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
6431 hRes = CLSIDFromProgID16(IStorageCompObj.strProgIDName, &(IStorageCompObj.clsid));
6437 /* Get the CLSID Default Name from the Registry */
6438 hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
6439 if(hErr == ERROR_SUCCESS)
6441 char strTemp[OLESTREAM_MAX_STR_LEN];
6442 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
6443 hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
6444 if(hErr == ERROR_SUCCESS)
6446 strcpy(IStorageCompObj.strCLSIDName, strTemp);
6452 /* Write CompObj Structure to stream */
6453 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
6455 WriteClassStm(pStream,&(IStorageCompObj.clsid));
6457 hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
6458 if(IStorageCompObj.dwCLSIDNameLength > 0)
6460 hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
6462 hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
6463 if(IStorageCompObj.dwOleTypeNameLength > 0)
6465 hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
6467 hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
6468 if(IStorageCompObj.dwProgIDNameLength > 0)
6470 hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
6472 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
6473 IStream_Release(pStream);
6479 /*************************************************************************
6480 * OLECONVERT_CreateOlePresStream[Internal]
6482 * Creates the "\002OlePres000" Stream with the Metafile data
6485 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
6486 * dwExtentX [I] Width of the Metafile
6487 * dwExtentY [I] Height of the Metafile
6488 * pData [I] Metafile data
6489 * dwDataLength [I] Size of the Metafile data
6493 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6496 * This function is used by OleConvertOLESTREAMToIStorage only.
6499 void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
6503 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6504 BYTE pOlePresStreamHeader [] =
6506 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
6507 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6508 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6509 0x00, 0x00, 0x00, 0x00
6512 BYTE pOlePresStreamHeaderEmpty [] =
6514 0x00, 0x00, 0x00, 0x00,
6515 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6516 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6517 0x00, 0x00, 0x00, 0x00
6520 /* Create the OlePres000 Stream */
6521 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6522 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6527 OLECONVERT_ISTORAGE_OLEPRES OlePres;
6529 memset(&OlePres, 0, sizeof(OlePres));
6530 /* Do we have any metafile data to save */
6531 if(dwDataLength > 0)
6533 memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
6534 nHeaderSize = sizeof(pOlePresStreamHeader);
6538 memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
6539 nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
6541 /* Set width and height of the metafile */
6542 OlePres.dwExtentX = dwExtentX;
6543 OlePres.dwExtentY = -dwExtentY;
6545 /* Set Data and Lenght */
6546 if(dwDataLength > sizeof(METAFILEPICT16))
6548 OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
6549 OlePres.pData = &(pData[8]);
6551 /* Save OlePres000 Data to Stream */
6552 hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
6553 hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
6554 hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
6555 hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
6556 if(OlePres.dwSize > 0)
6558 hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
6560 IStream_Release(pStream);
6564 /*************************************************************************
6565 * OLECONVERT_CreateOle10NativeStream [Internal]
6567 * Creates the "\001Ole10Native" Stream (should contain a BMP)
6570 * pStorage [I] Dest storage to create the stream in
6571 * pData [I] Ole10 Native Data (ex. bmp)
6572 * dwDataLength [I] Size of the Ole10 Native Data
6578 * This function is used by OleConvertOLESTREAMToIStorage only.
6580 * Might need to verify the data and return appropriate error message
6583 void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
6587 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6589 /* Create the Ole10Native Stream */
6590 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6591 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6595 /* Write info to stream */
6596 hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
6597 hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
6598 IStream_Release(pStream);
6603 /*************************************************************************
6604 * OLECONVERT_GetOLE10ProgID [Internal]
6606 * Finds the ProgID (or OleTypeID) from the IStorage
6609 * pStorage [I] The Src IStorage to get the ProgID
6610 * strProgID [I] the ProgID string to get
6611 * dwSize [I] the size of the string
6615 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6618 * This function is used by OleConvertIStorageToOLESTREAM only.
6622 HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
6626 LARGE_INTEGER iSeekPos;
6627 OLECONVERT_ISTORAGE_COMPOBJ CompObj;
6628 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6630 /* Open the CompObj Stream */
6631 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6632 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6636 /*Get the OleType from the CompObj Stream */
6637 iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
6638 iSeekPos.u.HighPart = 0;
6640 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6641 IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
6642 iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
6643 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6644 IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
6645 iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
6646 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6648 IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
6651 IStream_Read(pStream, strProgID, *dwSize, NULL);
6653 IStream_Release(pStream);
6658 LPOLESTR wstrProgID;
6660 /* Get the OleType from the registry */
6661 REFCLSID clsid = &(stat.clsid);
6662 IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
6663 hRes = ProgIDFromCLSID(clsid, &wstrProgID);
6666 *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
6673 /*************************************************************************
6674 * OLECONVERT_GetOle10PresData [Internal]
6676 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
6679 * pStorage [I] Src IStroage
6680 * pOleStream [I] Dest OleStream Mem Struct
6686 * This function is used by OleConvertIStorageToOLESTREAM only.
6688 * Memory allocated for pData must be freed by the caller
6692 void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6697 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6699 /* Initialize Default data for OLESTREAM */
6700 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6701 pOleStreamData[0].dwTypeID = 2;
6702 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6703 pOleStreamData[1].dwTypeID = 0;
6704 pOleStreamData[0].dwMetaFileWidth = 0;
6705 pOleStreamData[0].dwMetaFileHeight = 0;
6706 pOleStreamData[0].pData = NULL;
6707 pOleStreamData[1].pData = NULL;
6709 /* Open Ole10Native Stream */
6710 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6711 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6715 /* Read Size and Data */
6716 IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
6717 if(pOleStreamData->dwDataLength > 0)
6719 pOleStreamData->pData = (LPSTR) HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
6720 IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
6722 IStream_Release(pStream);
6728 /*************************************************************************
6729 * OLECONVERT_GetOle20PresData[Internal]
6731 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
6734 * pStorage [I] Src IStroage
6735 * pOleStreamData [I] Dest OleStream Mem Struct
6741 * This function is used by OleConvertIStorageToOLESTREAM only.
6743 * Memory allocated for pData must be freed by the caller
6745 void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6749 OLECONVERT_ISTORAGE_OLEPRES olePress;
6750 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6752 /* Initialize Default data for OLESTREAM */
6753 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6754 pOleStreamData[0].dwTypeID = 2;
6755 pOleStreamData[0].dwMetaFileWidth = 0;
6756 pOleStreamData[0].dwMetaFileHeight = 0;
6757 pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
6758 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6759 pOleStreamData[1].dwTypeID = 0;
6760 pOleStreamData[1].dwOleTypeNameLength = 0;
6761 pOleStreamData[1].strOleTypeName[0] = 0;
6762 pOleStreamData[1].dwMetaFileWidth = 0;
6763 pOleStreamData[1].dwMetaFileHeight = 0;
6764 pOleStreamData[1].pData = NULL;
6765 pOleStreamData[1].dwDataLength = 0;
6768 /* Open OlePress000 stream */
6769 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6770 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6773 LARGE_INTEGER iSeekPos;
6774 METAFILEPICT16 MetaFilePict;
6775 char strMetafilePictName[] = "METAFILEPICT";
6777 /* Set the TypeID for a Metafile */
6778 pOleStreamData[1].dwTypeID = 5;
6780 /* Set the OleTypeName to Metafile */
6781 pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
6782 strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
6784 iSeekPos.u.HighPart = 0;
6785 iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
6787 /* Get Presentation Data */
6788 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6789 IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
6790 IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
6791 IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
6793 /*Set width and Height */
6794 pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
6795 pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
6796 if(olePress.dwSize > 0)
6799 pOleStreamData[1].dwDataLength = olePress.dwSize + sizeof(METAFILEPICT16);
6801 /* Set MetaFilePict struct */
6802 MetaFilePict.mm = 8;
6803 MetaFilePict.xExt = olePress.dwExtentX;
6804 MetaFilePict.yExt = olePress.dwExtentY;
6805 MetaFilePict.hMF = 0;
6807 /* Get Metafile Data */
6808 pOleStreamData[1].pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
6809 memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
6810 IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
6812 IStream_Release(pStream);
6816 /*************************************************************************
6817 * OleConvertOLESTREAMToIStorage [OLE32.87]
6822 * DVTARGETDEVICE paramenter is not handled
6823 * Still unsure of some mem fields for OLE 10 Stream
6824 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6825 * and "\001OLE" streams
6828 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
6829 LPOLESTREAM pOleStream,
6831 const DVTARGETDEVICE* ptd)
6835 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6837 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6841 Print(MIN_TRACE, ("DVTARGETDEVICE is not NULL, unhandled parameter\n"));
6844 if(pstg == NULL || pOleStream == NULL)
6846 hRes = E_INVALIDARG;
6851 /* Load the OLESTREAM to Memory */
6852 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
6857 /* Load the OLESTREAM to Memory (part 2)*/
6858 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
6864 if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
6866 /* Do we have the IStorage Data in the OLESTREAM */
6867 if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
6869 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6870 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
6874 /* It must be an original OLE 1.0 source */
6875 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6880 /* It must be an original OLE 1.0 source */
6881 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6884 /* Create CompObj Stream if necessary */
6885 hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
6888 /*Create the Ole Stream if necessary */
6889 OLECONVERT_CreateOleStream(pstg);
6894 /* Free allocated memory */
6895 for(i=0; i < 2; i++)
6897 if(pOleStreamData[i].pData != NULL)
6899 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
6901 if(pOleStreamData[i].pstrOleObjFileName != NULL)
6903 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
6904 pOleStreamData[i].pstrOleObjFileName = NULL;
6910 /*************************************************************************
6911 * OleConvertIStorageToOLESTREAM [OLE32.85]
6918 * Still unsure of some mem fields for OLE 10 Stream
6919 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6920 * and "\001OLE" streams.
6923 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
6925 LPOLESTREAM pOleStream)
6928 HRESULT hRes = S_OK;
6930 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6931 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6934 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6936 if(pstg == NULL || pOleStream == NULL)
6938 hRes = E_INVALIDARG;
6942 /* Get the ProgID */
6943 pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
6944 hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
6948 /*Was it originaly Ole10 */
6949 hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
6952 IStream_Release(pStream);
6953 /*Get Presentation Data for Ole10Native */
6954 OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
6958 /*Get Presentation Data (OLE20)*/
6959 OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
6962 /* Save OLESTREAM */
6963 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
6966 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
6971 /* Free allocated memory */
6972 for(i=0; i < 2; i++)
6974 if(pOleStreamData[i].pData != NULL)
6976 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
6983 /***********************************************************************
6984 * GetConvertStg (OLE32.68)
6986 HRESULT WINAPI GetConvertStg(LPGUID guid) {