2 * Compound Storage (32 bit version)
3 * Storage implementation
5 * This file contains the compound file implementation
6 * of the storage interface.
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Sylvain St-Germain
10 * Copyright 1999 Thuy Nguyen
18 #include "winbase.h" /* for lstrlenW() and the likes */
20 #include "wine/unicode.h"
21 #include "debugtools.h"
23 #include "storage32.h"
24 #include "ole2.h" /* For Write/ReadClassStm */
27 #include "wine/wingdi16.h"
29 DEFAULT_DEBUG_CHANNEL(storage
);
34 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
35 #define OLESTREAM_ID 0x501
36 #define OLESTREAM_MAX_STR_LEN 255
38 static const char rootPropertyName
[] = "Root Entry";
41 /* OLESTREAM memory structure to use for Get and Put Routines */
42 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
47 DWORD dwOleTypeNameLength
;
48 CHAR strOleTypeName
[OLESTREAM_MAX_STR_LEN
];
49 CHAR
*pstrOleObjFileName
;
50 DWORD dwOleObjFileNameLength
;
51 DWORD dwMetaFileWidth
;
52 DWORD dwMetaFileHeight
;
53 CHAR strUnknown
[8]; /* don't know what is this 8 byts information in OLE stream. */
56 }OLECONVERT_OLESTREAM_DATA
;
58 /* CompObj Stream structure */
59 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
64 DWORD dwCLSIDNameLength
;
65 CHAR strCLSIDName
[OLESTREAM_MAX_STR_LEN
];
66 DWORD dwOleTypeNameLength
;
67 CHAR strOleTypeName
[OLESTREAM_MAX_STR_LEN
];
68 DWORD dwProgIDNameLength
;
69 CHAR strProgIDName
[OLESTREAM_MAX_STR_LEN
];
71 }OLECONVERT_ISTORAGE_COMPOBJ
;
74 /* Ole Presention Stream structure */
75 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
83 }OLECONVERT_ISTORAGE_OLEPRES
;
87 /***********************************************************************
88 * Forward declaration of internal functions used by the method DestroyElement
90 static HRESULT
deleteStorageProperty(
91 StorageImpl
*parentStorage
,
92 ULONG foundPropertyIndexToDelete
,
93 StgProperty propertyToDelete
);
95 static HRESULT
deleteStreamProperty(
96 StorageImpl
*parentStorage
,
97 ULONG foundPropertyIndexToDelete
,
98 StgProperty propertyToDelete
);
100 static HRESULT
findPlaceholder(
101 StorageImpl
*storage
,
102 ULONG propertyIndexToStore
,
103 ULONG storagePropertyIndex
,
106 static HRESULT
adjustPropertyChain(
108 StgProperty propertyToDelete
,
109 StgProperty parentProperty
,
110 ULONG parentPropertyId
,
113 /***********************************************************************
114 * Declaration of the functions used to manipulate StgProperty
117 static ULONG
getFreeProperty(
118 StorageImpl
*storage
);
120 static void updatePropertyChain(
121 StorageImpl
*storage
,
122 ULONG newPropertyIndex
,
123 StgProperty newProperty
);
125 static LONG
propertyNameCmp(
126 OLECHAR
*newProperty
,
127 OLECHAR
*currentProperty
);
130 /***********************************************************************
131 * Declaration of miscellaneous functions...
133 static HRESULT
validateSTGM(DWORD stgmValue
);
135 static DWORD
GetShareModeFromSTGM(DWORD stgm
);
136 static DWORD
GetAccessModeFromSTGM(DWORD stgm
);
137 static DWORD
GetCreationModeFromSTGM(DWORD stgm
);
140 * Virtual function table for the IStorage32Impl class.
142 static ICOM_VTABLE(IStorage
) Storage32Impl_Vtbl
=
144 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
145 StorageBaseImpl_QueryInterface
,
146 StorageBaseImpl_AddRef
,
147 StorageBaseImpl_Release
,
148 StorageBaseImpl_CreateStream
,
149 StorageBaseImpl_OpenStream
,
150 StorageImpl_CreateStorage
,
151 StorageBaseImpl_OpenStorage
,
153 StorageImpl_MoveElementTo
,
156 StorageBaseImpl_EnumElements
,
157 StorageImpl_DestroyElement
,
158 StorageBaseImpl_RenameElement
,
159 StorageImpl_SetElementTimes
,
160 StorageBaseImpl_SetClass
,
161 StorageImpl_SetStateBits
,
166 * Virtual function table for the Storage32InternalImpl class.
168 static ICOM_VTABLE(IStorage
) Storage32InternalImpl_Vtbl
=
170 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
171 StorageBaseImpl_QueryInterface
,
172 StorageBaseImpl_AddRef
,
173 StorageBaseImpl_Release
,
174 StorageBaseImpl_CreateStream
,
175 StorageBaseImpl_OpenStream
,
176 StorageImpl_CreateStorage
,
177 StorageBaseImpl_OpenStorage
,
179 StorageImpl_MoveElementTo
,
180 StorageInternalImpl_Commit
,
181 StorageInternalImpl_Revert
,
182 StorageBaseImpl_EnumElements
,
183 StorageImpl_DestroyElement
,
184 StorageBaseImpl_RenameElement
,
185 StorageImpl_SetElementTimes
,
186 StorageBaseImpl_SetClass
,
187 StorageImpl_SetStateBits
,
192 * Virtual function table for the IEnumSTATSTGImpl class.
194 static ICOM_VTABLE(IEnumSTATSTG
) IEnumSTATSTGImpl_Vtbl
=
196 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
197 IEnumSTATSTGImpl_QueryInterface
,
198 IEnumSTATSTGImpl_AddRef
,
199 IEnumSTATSTGImpl_Release
,
200 IEnumSTATSTGImpl_Next
,
201 IEnumSTATSTGImpl_Skip
,
202 IEnumSTATSTGImpl_Reset
,
203 IEnumSTATSTGImpl_Clone
210 /************************************************************************
211 ** Storage32BaseImpl implementatiion
214 /************************************************************************
215 * Storage32BaseImpl_QueryInterface (IUnknown)
217 * This method implements the common QueryInterface for all IStorage32
218 * implementations contained in this file.
220 * See Windows documentation for more details on IUnknown methods.
222 HRESULT WINAPI
StorageBaseImpl_QueryInterface(
227 ICOM_THIS(StorageBaseImpl
,iface
);
229 * Perform a sanity check on the parameters.
231 if ( (This
==0) || (ppvObject
==0) )
235 * Initialize the return parameter.
240 * Compare the riid with the interface IDs implemented by this object.
242 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
244 *ppvObject
= (IStorage
*)This
;
246 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
248 *ppvObject
= (IStorage
*)This
;
252 * Check that we obtained an interface.
255 return E_NOINTERFACE
;
258 * Query Interface always increases the reference count by one when it is
261 StorageBaseImpl_AddRef(iface
);
266 /************************************************************************
267 * Storage32BaseImpl_AddRef (IUnknown)
269 * This method implements the common AddRef for all IStorage32
270 * implementations contained in this file.
272 * See Windows documentation for more details on IUnknown methods.
274 ULONG WINAPI
StorageBaseImpl_AddRef(
277 ICOM_THIS(StorageBaseImpl
,iface
);
283 /************************************************************************
284 * Storage32BaseImpl_Release (IUnknown)
286 * This method implements the common Release for all IStorage32
287 * implementations contained in this file.
289 * See Windows documentation for more details on IUnknown methods.
291 ULONG WINAPI
StorageBaseImpl_Release(
294 ICOM_THIS(StorageBaseImpl
,iface
);
296 * Decrease the reference count on this object.
301 * If the reference count goes down to 0, perform suicide.
306 * Since we are using a system of base-classes, we want to call the
307 * destructor of the appropriate derived class. To do this, we are
308 * using virtual functions to implement the destructor.
310 This
->v_destructor(This
);
318 /************************************************************************
319 * Storage32BaseImpl_OpenStream (IStorage)
321 * This method will open the specified stream object from the current storage.
323 * See Windows documentation for more details on IStorage methods.
325 HRESULT WINAPI
StorageBaseImpl_OpenStream(
327 const OLECHAR
* pwcsName
, /* [string][in] */
328 void* reserved1
, /* [unique][in] */
329 DWORD grfMode
, /* [in] */
330 DWORD reserved2
, /* [in] */
331 IStream
** ppstm
) /* [out] */
333 ICOM_THIS(StorageBaseImpl
,iface
);
334 IEnumSTATSTGImpl
* propertyEnumeration
;
335 StgStreamImpl
* newStream
;
336 StgProperty currentProperty
;
337 ULONG foundPropertyIndex
;
339 TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
340 iface
, debugstr_w(pwcsName
), reserved1
, grfMode
, reserved2
, ppstm
);
343 * Perform a sanity check on the parameters.
345 if ( (pwcsName
==NULL
) || (ppstm
==0) )
349 * Initialize the out parameter
354 * Validate the STGM flags
356 if ( FAILED( validateSTGM(grfMode
) ))
357 return STG_E_INVALIDFLAG
;
362 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
363 (grfMode
& STGM_DELETEONRELEASE
) ||
364 (grfMode
& STGM_TRANSACTED
) )
365 return STG_E_INVALIDFUNCTION
;
368 * Create a property enumeration to search the properties
370 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
371 This
->ancestorStorage
,
372 This
->rootPropertySetIndex
);
375 * Search the enumeration for the property with the given name
377 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
383 * Delete the property enumeration since we don't need it anymore
385 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
388 * If it was found, construct the stream object and return a pointer to it.
390 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
391 (currentProperty
.propertyType
==PROPTYPE_STREAM
) )
393 newStream
= StgStreamImpl_Construct(This
, grfMode
, foundPropertyIndex
);
397 newStream
->grfMode
= grfMode
;
398 *ppstm
= (IStream
*)newStream
;
401 * Since we are returning a pointer to the interface, we have to
402 * nail down the reference.
404 StgStreamImpl_AddRef(*ppstm
);
409 return E_OUTOFMEMORY
;
412 return STG_E_FILENOTFOUND
;
415 /************************************************************************
416 * Storage32BaseImpl_OpenStorage (IStorage)
418 * This method will open a new storage object from the current storage.
420 * See Windows documentation for more details on IStorage methods.
422 HRESULT WINAPI
StorageBaseImpl_OpenStorage(
424 const OLECHAR
* pwcsName
, /* [string][unique][in] */
425 IStorage
* pstgPriority
, /* [unique][in] */
426 DWORD grfMode
, /* [in] */
427 SNB snbExclude
, /* [unique][in] */
428 DWORD reserved
, /* [in] */
429 IStorage
** ppstg
) /* [out] */
431 ICOM_THIS(StorageBaseImpl
,iface
);
432 StorageInternalImpl
* newStorage
;
433 IEnumSTATSTGImpl
* propertyEnumeration
;
434 StgProperty currentProperty
;
435 ULONG foundPropertyIndex
;
437 TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
438 iface
, debugstr_w(pwcsName
), pstgPriority
,
439 grfMode
, snbExclude
, reserved
, ppstg
);
442 * Perform a sanity check on the parameters.
444 if ( (This
==0) || (pwcsName
==NULL
) || (ppstg
==0) )
448 * Validate the STGM flags
450 if ( FAILED( validateSTGM(grfMode
) ))
451 return STG_E_INVALIDFLAG
;
456 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
457 (grfMode
& STGM_DELETEONRELEASE
) ||
458 (grfMode
& STGM_PRIORITY
) )
459 return STG_E_INVALIDFUNCTION
;
462 * Initialize the out parameter
467 * Create a property enumeration to search the properties
469 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
470 This
->ancestorStorage
,
471 This
->rootPropertySetIndex
);
474 * Search the enumeration for the property with the given name
476 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
482 * Delete the property enumeration since we don't need it anymore
484 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
487 * If it was found, construct the stream object and return a pointer to it.
489 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
490 (currentProperty
.propertyType
==PROPTYPE_STORAGE
) )
493 * Construct a new Storage object
495 newStorage
= StorageInternalImpl_Construct(
496 This
->ancestorStorage
,
501 *ppstg
= (IStorage
*)newStorage
;
504 * Since we are returning a pointer to the interface,
505 * we have to nail down the reference.
507 StorageBaseImpl_AddRef(*ppstg
);
512 return STG_E_INSUFFICIENTMEMORY
;
515 return STG_E_FILENOTFOUND
;
518 /************************************************************************
519 * Storage32BaseImpl_EnumElements (IStorage)
521 * This method will create an enumerator object that can be used to
522 * retrieve informatino about all the properties in the storage object.
524 * See Windows documentation for more details on IStorage methods.
526 HRESULT WINAPI
StorageBaseImpl_EnumElements(
528 DWORD reserved1
, /* [in] */
529 void* reserved2
, /* [size_is][unique][in] */
530 DWORD reserved3
, /* [in] */
531 IEnumSTATSTG
** ppenum
) /* [out] */
533 ICOM_THIS(StorageBaseImpl
,iface
);
534 IEnumSTATSTGImpl
* newEnum
;
536 TRACE("(%p, %ld, %p, %ld, %p)\n",
537 iface
, reserved1
, reserved2
, reserved3
, ppenum
);
540 * Perform a sanity check on the parameters.
542 if ( (This
==0) || (ppenum
==0))
546 * Construct the enumerator.
548 newEnum
= IEnumSTATSTGImpl_Construct(
549 This
->ancestorStorage
,
550 This
->rootPropertySetIndex
);
554 *ppenum
= (IEnumSTATSTG
*)newEnum
;
557 * Don't forget to nail down a reference to the new object before
560 IEnumSTATSTGImpl_AddRef(*ppenum
);
565 return E_OUTOFMEMORY
;
568 /************************************************************************
569 * Storage32BaseImpl_Stat (IStorage)
571 * This method will retrieve information about this storage object.
573 * See Windows documentation for more details on IStorage methods.
575 HRESULT WINAPI
StorageBaseImpl_Stat(
577 STATSTG
* pstatstg
, /* [out] */
578 DWORD grfStatFlag
) /* [in] */
580 ICOM_THIS(StorageBaseImpl
,iface
);
581 StgProperty curProperty
;
584 TRACE("(%p, %p, %lx)\n",
585 iface
, pstatstg
, grfStatFlag
);
588 * Perform a sanity check on the parameters.
590 if ( (This
==0) || (pstatstg
==0))
594 * Read the information from the property.
596 readSuccessful
= StorageImpl_ReadProperty(
597 This
->ancestorStorage
,
598 This
->rootPropertySetIndex
,
603 StorageUtl_CopyPropertyToSTATSTG(
614 /************************************************************************
615 * Storage32BaseImpl_RenameElement (IStorage)
617 * This method will rename the specified element.
619 * See Windows documentation for more details on IStorage methods.
621 * Implementation notes: The method used to rename consists of creating a clone
622 * of the deleted StgProperty object setting it with the new name and to
623 * perform a DestroyElement of the old StgProperty.
625 HRESULT WINAPI
StorageBaseImpl_RenameElement(
627 const OLECHAR
* pwcsOldName
, /* [in] */
628 const OLECHAR
* pwcsNewName
) /* [in] */
630 ICOM_THIS(StorageBaseImpl
,iface
);
631 IEnumSTATSTGImpl
* propertyEnumeration
;
632 StgProperty currentProperty
;
633 ULONG foundPropertyIndex
;
635 TRACE("(%p, %s, %s)\n",
636 iface
, debugstr_w(pwcsOldName
), debugstr_w(pwcsNewName
));
639 * Create a property enumeration to search the properties
641 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
642 This
->rootPropertySetIndex
);
645 * Search the enumeration for the new property name
647 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
651 if (foundPropertyIndex
!= PROPERTY_NULL
)
654 * There is already a property with the new name
656 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
657 return STG_E_FILEALREADYEXISTS
;
660 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)propertyEnumeration
);
663 * Search the enumeration for the old property name
665 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
670 * Delete the property enumeration since we don't need it anymore
672 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
674 if (foundPropertyIndex
!= PROPERTY_NULL
)
676 StgProperty renamedProperty
;
677 ULONG renamedPropertyIndex
;
680 * Setup a new property for the renamed property
682 renamedProperty
.sizeOfNameString
=
683 ( lstrlenW(pwcsNewName
)+1 ) * sizeof(WCHAR
);
685 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
686 return STG_E_INVALIDNAME
;
688 strcpyW(renamedProperty
.name
, pwcsNewName
);
690 renamedProperty
.propertyType
= currentProperty
.propertyType
;
691 renamedProperty
.startingBlock
= currentProperty
.startingBlock
;
692 renamedProperty
.size
.s
.LowPart
= currentProperty
.size
.s
.LowPart
;
693 renamedProperty
.size
.s
.HighPart
= currentProperty
.size
.s
.HighPart
;
695 renamedProperty
.previousProperty
= PROPERTY_NULL
;
696 renamedProperty
.nextProperty
= PROPERTY_NULL
;
699 * Bring the dirProperty link in case it is a storage and in which
700 * case the renamed storage elements don't require to be reorganized.
702 renamedProperty
.dirProperty
= currentProperty
.dirProperty
;
704 /* call CoFileTime to get the current time
705 renamedProperty.timeStampS1
706 renamedProperty.timeStampD1
707 renamedProperty.timeStampS2
708 renamedProperty.timeStampD2
709 renamedProperty.propertyUniqueID
713 * Obtain a free property in the property chain
715 renamedPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
718 * Save the new property into the new property spot
720 StorageImpl_WriteProperty(
721 This
->ancestorStorage
,
722 renamedPropertyIndex
,
726 * Find a spot in the property chain for our newly created property.
730 renamedPropertyIndex
,
734 * At this point the renamed property has been inserted in the tree,
735 * now, before to Destroy the old property we must zeroed it's dirProperty
736 * otherwise the DestroyProperty below will zap it all and we do not want
738 * Also, we fake that the old property is a storage so the DestroyProperty
739 * will not do a SetSize(0) on the stream data.
741 * This means that we need to tweek the StgProperty if it is a stream or a
744 StorageImpl_ReadProperty(This
->ancestorStorage
,
748 currentProperty
.dirProperty
= PROPERTY_NULL
;
749 currentProperty
.propertyType
= PROPTYPE_STORAGE
;
750 StorageImpl_WriteProperty(
751 This
->ancestorStorage
,
756 * Invoke Destroy to get rid of the ole property and automatically redo
757 * the linking of it's previous and next members...
759 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsOldName
);
765 * There is no property with the old name
767 return STG_E_FILENOTFOUND
;
773 /************************************************************************
774 * Storage32BaseImpl_CreateStream (IStorage)
776 * This method will create a stream object within this storage
778 * See Windows documentation for more details on IStorage methods.
780 HRESULT WINAPI
StorageBaseImpl_CreateStream(
782 const OLECHAR
* pwcsName
, /* [string][in] */
783 DWORD grfMode
, /* [in] */
784 DWORD reserved1
, /* [in] */
785 DWORD reserved2
, /* [in] */
786 IStream
** ppstm
) /* [out] */
788 ICOM_THIS(StorageBaseImpl
,iface
);
789 IEnumSTATSTGImpl
* propertyEnumeration
;
790 StgStreamImpl
* newStream
;
791 StgProperty currentProperty
, newStreamProperty
;
792 ULONG foundPropertyIndex
, newPropertyIndex
;
794 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
795 iface
, debugstr_w(pwcsName
), grfMode
,
796 reserved1
, reserved2
, ppstm
);
799 * Validate parameters
802 return STG_E_INVALIDPOINTER
;
805 return STG_E_INVALIDNAME
;
808 * Validate the STGM flags
810 if ( FAILED( validateSTGM(grfMode
) ))
811 return STG_E_INVALIDFLAG
;
816 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
817 (grfMode
& STGM_DELETEONRELEASE
) ||
818 (grfMode
& STGM_TRANSACTED
) )
819 return STG_E_INVALIDFUNCTION
;
822 * Initialize the out parameter
827 * Create a property enumeration to search the properties
829 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
830 This
->rootPropertySetIndex
);
832 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
836 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
838 if (foundPropertyIndex
!= PROPERTY_NULL
)
841 * An element with this name already exists
843 if (grfMode
& STGM_CREATE
)
845 IStorage_DestroyElement(iface
, pwcsName
);
848 return STG_E_FILEALREADYEXISTS
;
852 * memset the empty property
854 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
856 newStreamProperty
.sizeOfNameString
=
857 ( lstrlenW(pwcsName
)+1 ) * sizeof(WCHAR
);
859 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
860 return STG_E_INVALIDNAME
;
862 strcpyW(newStreamProperty
.name
, pwcsName
);
864 newStreamProperty
.propertyType
= PROPTYPE_STREAM
;
865 newStreamProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
866 newStreamProperty
.size
.s
.LowPart
= 0;
867 newStreamProperty
.size
.s
.HighPart
= 0;
869 newStreamProperty
.previousProperty
= PROPERTY_NULL
;
870 newStreamProperty
.nextProperty
= PROPERTY_NULL
;
871 newStreamProperty
.dirProperty
= PROPERTY_NULL
;
873 /* call CoFileTime to get the current time
874 newStreamProperty.timeStampS1
875 newStreamProperty.timeStampD1
876 newStreamProperty.timeStampS2
877 newStreamProperty.timeStampD2
880 /* newStreamProperty.propertyUniqueID */
883 * Get a free property or create a new one
885 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
888 * Save the new property into the new property spot
890 StorageImpl_WriteProperty(
891 This
->ancestorStorage
,
896 * Find a spot in the property chain for our newly created property.
904 * Open the stream to return it.
906 newStream
= StgStreamImpl_Construct(This
, grfMode
, newPropertyIndex
);
910 *ppstm
= (IStream
*)newStream
;
913 * Since we are returning a pointer to the interface, we have to nail down
916 StgStreamImpl_AddRef(*ppstm
);
920 return STG_E_INSUFFICIENTMEMORY
;
926 /************************************************************************
927 * Storage32BaseImpl_SetClass (IStorage)
929 * This method will write the specified CLSID in the property of this
932 * See Windows documentation for more details on IStorage methods.
934 HRESULT WINAPI
StorageBaseImpl_SetClass(
936 REFCLSID clsid
) /* [in] */
938 ICOM_THIS(StorageBaseImpl
,iface
);
939 HRESULT hRes
= E_FAIL
;
940 StgProperty curProperty
;
943 TRACE("(%p, %p)\n", iface
, clsid
);
945 success
= StorageImpl_ReadProperty(This
->ancestorStorage
,
946 This
->rootPropertySetIndex
,
950 curProperty
.propertyUniqueID
= *clsid
;
952 success
= StorageImpl_WriteProperty(This
->ancestorStorage
,
953 This
->rootPropertySetIndex
,
962 /************************************************************************
963 ** Storage32Impl implementation
966 /************************************************************************
967 * Storage32Impl_CreateStorage (IStorage)
969 * This method will create the storage object within the provided storage.
971 * See Windows documentation for more details on IStorage methods.
973 HRESULT WINAPI
StorageImpl_CreateStorage(
975 const OLECHAR
*pwcsName
, /* [string][in] */
976 DWORD grfMode
, /* [in] */
977 DWORD reserved1
, /* [in] */
978 DWORD reserved2
, /* [in] */
979 IStorage
**ppstg
) /* [out] */
981 StorageImpl
* const This
=(StorageImpl
*)iface
;
983 IEnumSTATSTGImpl
*propertyEnumeration
;
984 StgProperty currentProperty
;
985 StgProperty newProperty
;
986 ULONG foundPropertyIndex
;
987 ULONG newPropertyIndex
;
990 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
991 iface
, debugstr_w(pwcsName
), grfMode
,
992 reserved1
, reserved2
, ppstg
);
995 * Validate parameters
998 return STG_E_INVALIDPOINTER
;
1001 return STG_E_INVALIDNAME
;
1004 * Validate the STGM flags
1006 if ( FAILED( validateSTGM(grfMode
) ) ||
1007 (grfMode
& STGM_DELETEONRELEASE
) )
1008 return STG_E_INVALIDFLAG
;
1011 * Initialize the out parameter
1016 * Create a property enumeration and search the properties
1018 propertyEnumeration
= IEnumSTATSTGImpl_Construct( This
->ancestorStorage
,
1019 This
->rootPropertySetIndex
);
1021 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
1024 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1026 if (foundPropertyIndex
!= PROPERTY_NULL
)
1029 * An element with this name already exists
1031 if (grfMode
& STGM_CREATE
)
1032 IStorage_DestroyElement(iface
, pwcsName
);
1034 return STG_E_FILEALREADYEXISTS
;
1038 * memset the empty property
1040 memset(&newProperty
, 0, sizeof(StgProperty
));
1042 newProperty
.sizeOfNameString
= (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
);
1044 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
1045 return STG_E_INVALIDNAME
;
1047 strcpyW(newProperty
.name
, pwcsName
);
1049 newProperty
.propertyType
= PROPTYPE_STORAGE
;
1050 newProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
1051 newProperty
.size
.s
.LowPart
= 0;
1052 newProperty
.size
.s
.HighPart
= 0;
1054 newProperty
.previousProperty
= PROPERTY_NULL
;
1055 newProperty
.nextProperty
= PROPERTY_NULL
;
1056 newProperty
.dirProperty
= PROPERTY_NULL
;
1058 /* call CoFileTime to get the current time
1059 newProperty.timeStampS1
1060 newProperty.timeStampD1
1061 newProperty.timeStampS2
1062 newProperty.timeStampD2
1065 /* newStorageProperty.propertyUniqueID */
1068 * Obtain a free property in the property chain
1070 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
1073 * Save the new property into the new property spot
1075 StorageImpl_WriteProperty(
1076 This
->ancestorStorage
,
1081 * Find a spot in the property chain for our newly created property.
1083 updatePropertyChain(
1089 * Open it to get a pointer to return.
1091 hr
= IStorage_OpenStorage(
1100 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1110 /***************************************************************************
1114 * Get a free property or create a new one.
1116 static ULONG
getFreeProperty(
1117 StorageImpl
*storage
)
1119 ULONG currentPropertyIndex
= 0;
1120 ULONG newPropertyIndex
= PROPERTY_NULL
;
1121 BOOL readSuccessful
= TRUE
;
1122 StgProperty currentProperty
;
1127 * Start by reading the root property
1129 readSuccessful
= StorageImpl_ReadProperty(storage
->ancestorStorage
,
1130 currentPropertyIndex
,
1134 if (currentProperty
.sizeOfNameString
== 0)
1137 * The property existis and is available, we found it.
1139 newPropertyIndex
= currentPropertyIndex
;
1145 * We exhausted the property list, we will create more space below
1147 newPropertyIndex
= currentPropertyIndex
;
1149 currentPropertyIndex
++;
1151 } while (newPropertyIndex
== PROPERTY_NULL
);
1154 * grow the property chain
1156 if (! readSuccessful
)
1158 StgProperty emptyProperty
;
1159 ULARGE_INTEGER newSize
;
1160 ULONG propertyIndex
;
1161 ULONG lastProperty
= 0;
1162 ULONG blockCount
= 0;
1165 * obtain the new count of property blocks
1167 blockCount
= BlockChainStream_GetCount(
1168 storage
->ancestorStorage
->rootBlockChain
)+1;
1171 * initialize the size used by the property stream
1173 newSize
.s
.HighPart
= 0;
1174 newSize
.s
.LowPart
= storage
->bigBlockSize
* blockCount
;
1177 * add a property block to the property chain
1179 BlockChainStream_SetSize(storage
->ancestorStorage
->rootBlockChain
, newSize
);
1182 * memset the empty property in order to initialize the unused newly
1185 memset(&emptyProperty
, 0, sizeof(StgProperty
));
1190 lastProperty
= storage
->bigBlockSize
/ PROPSET_BLOCK_SIZE
* blockCount
;
1193 propertyIndex
= newPropertyIndex
;
1194 propertyIndex
< lastProperty
;
1197 StorageImpl_WriteProperty(
1198 storage
->ancestorStorage
,
1204 return newPropertyIndex
;
1207 /****************************************************************************
1211 * Case insensitive comparaison of StgProperty.name by first considering
1214 * Returns <0 when newPrpoerty < currentProperty
1215 * >0 when newPrpoerty > currentProperty
1216 * 0 when newPrpoerty == currentProperty
1218 static LONG
propertyNameCmp(
1219 OLECHAR
*newProperty
,
1220 OLECHAR
*currentProperty
)
1222 LONG diff
= lstrlenW(newProperty
) - lstrlenW(currentProperty
);
1227 * We compare the string themselves only when they are of the same lenght
1229 diff
= lstrcmpiW( newProperty
, currentProperty
);
1235 /****************************************************************************
1239 * Properly link this new element in the property chain.
1241 static void updatePropertyChain(
1242 StorageImpl
*storage
,
1243 ULONG newPropertyIndex
,
1244 StgProperty newProperty
)
1246 StgProperty currentProperty
;
1249 * Read the root property
1251 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1252 storage
->rootPropertySetIndex
,
1255 if (currentProperty
.dirProperty
!= PROPERTY_NULL
)
1258 * The root storage contains some element, therefore, start the research
1259 * for the appropriate location.
1262 ULONG current
, next
, previous
, currentPropertyId
;
1265 * Keep the StgProperty sequence number of the storage first property
1267 currentPropertyId
= currentProperty
.dirProperty
;
1272 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1273 currentProperty
.dirProperty
,
1276 previous
= currentProperty
.previousProperty
;
1277 next
= currentProperty
.nextProperty
;
1278 current
= currentPropertyId
;
1282 LONG diff
= propertyNameCmp( newProperty
.name
, currentProperty
.name
);
1286 if (previous
!= PROPERTY_NULL
)
1288 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1295 currentProperty
.previousProperty
= newPropertyIndex
;
1296 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1304 if (next
!= PROPERTY_NULL
)
1306 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1313 currentProperty
.nextProperty
= newPropertyIndex
;
1314 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1323 * Trying to insert an item with the same name in the
1324 * subtree structure.
1329 previous
= currentProperty
.previousProperty
;
1330 next
= currentProperty
.nextProperty
;
1336 * The root storage is empty, link the new property to it's dir property
1338 currentProperty
.dirProperty
= newPropertyIndex
;
1339 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1340 storage
->rootPropertySetIndex
,
1346 /*************************************************************************
1349 HRESULT WINAPI
StorageImpl_CopyTo(
1351 DWORD ciidExclude
, /* [in] */
1352 const IID
* rgiidExclude
, /* [size_is][unique][in] */
1353 SNB snbExclude
, /* [unique][in] */
1354 IStorage
* pstgDest
) /* [unique][in] */
1356 IEnumSTATSTG
*elements
= 0;
1357 STATSTG curElement
, strStat
;
1359 IStorage
*pstgTmp
, *pstgChild
;
1360 IStream
*pstrTmp
, *pstrChild
;
1362 if ((ciidExclude
!= 0) || (rgiidExclude
!= NULL
) || (snbExclude
!= NULL
))
1363 FIXME("Exclude option not implemented\n");
1365 TRACE("(%p, %ld, %p, %p, %p)\n",
1366 iface
, ciidExclude
, rgiidExclude
,
1367 snbExclude
, pstgDest
);
1370 * Perform a sanity check
1372 if ( pstgDest
== 0 )
1373 return STG_E_INVALIDPOINTER
;
1376 * Enumerate the elements
1378 hr
= IStorage_EnumElements( iface
, 0, 0, 0, &elements
);
1386 IStorage_Stat( iface
, &curElement
, STATFLAG_NONAME
);
1387 IStorage_SetClass( pstgDest
, &curElement
.clsid
);
1392 * Obtain the next element
1394 hr
= IEnumSTATSTG_Next( elements
, 1, &curElement
, NULL
);
1396 if ( hr
== S_FALSE
)
1398 hr
= S_OK
; /* done, every element has been copied */
1402 if (curElement
.type
== STGTY_STORAGE
)
1405 * open child source storage
1407 hr
= IStorage_OpenStorage( iface
, curElement
.pwcsName
, NULL
,
1408 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1409 NULL
, 0, &pstgChild
);
1415 * Check if destination storage is not a child of the source
1416 * storage, which will cause an infinite loop
1418 if (pstgChild
== pstgDest
)
1420 IEnumSTATSTG_Release(elements
);
1422 return STG_E_ACCESSDENIED
;
1426 * create a new storage in destination storage
1428 hr
= IStorage_CreateStorage( pstgDest
, curElement
.pwcsName
,
1429 STGM_FAILIFTHERE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1433 * if it already exist, don't create a new one use this one
1435 if (hr
== STG_E_FILEALREADYEXISTS
)
1437 hr
= IStorage_OpenStorage( pstgDest
, curElement
.pwcsName
, NULL
,
1438 STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1439 NULL
, 0, &pstgTmp
);
1447 * do the copy recursively
1449 hr
= IStorage_CopyTo( pstgChild
, ciidExclude
, rgiidExclude
,
1450 snbExclude
, pstgTmp
);
1452 IStorage_Release( pstgTmp
);
1453 IStorage_Release( pstgChild
);
1455 else if (curElement
.type
== STGTY_STREAM
)
1458 * create a new stream in destination storage. If the stream already
1459 * exist, it will be deleted and a new one will be created.
1461 hr
= IStorage_CreateStream( pstgDest
, curElement
.pwcsName
,
1462 STGM_CREATE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1469 * open child stream storage
1471 hr
= IStorage_OpenStream( iface
, curElement
.pwcsName
, NULL
,
1472 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1479 * Get the size of the source stream
1481 IStream_Stat( pstrChild
, &strStat
, STATFLAG_NONAME
);
1484 * Set the size of the destination stream.
1486 IStream_SetSize(pstrTmp
, strStat
.cbSize
);
1491 hr
= IStream_CopyTo( pstrChild
, pstrTmp
, strStat
.cbSize
,
1494 IStream_Release( pstrTmp
);
1495 IStream_Release( pstrChild
);
1499 WARN("unknown element type: %ld\n", curElement
.type
);
1502 } while (hr
== S_OK
);
1507 IEnumSTATSTG_Release(elements
);
1512 /*************************************************************************
1513 * MoveElementTo (IStorage)
1515 HRESULT WINAPI
StorageImpl_MoveElementTo(
1517 const OLECHAR
*pwcsName
, /* [string][in] */
1518 IStorage
*pstgDest
, /* [unique][in] */
1519 const OLECHAR
*pwcsNewName
,/* [string][in] */
1520 DWORD grfFlags
) /* [in] */
1522 FIXME("not implemented!\n");
1526 /*************************************************************************
1529 HRESULT WINAPI
StorageImpl_Commit(
1531 DWORD grfCommitFlags
)/* [in] */
1533 FIXME("(%ld): stub!\n", grfCommitFlags
);
1537 /*************************************************************************
1540 HRESULT WINAPI
StorageImpl_Revert(
1543 FIXME("not implemented!\n");
1547 /*************************************************************************
1548 * DestroyElement (IStorage)
1550 * Stategy: This implementation is build this way for simplicity not for speed.
1551 * I always delete the top most element of the enumeration and adjust
1552 * the deleted element pointer all the time. This takes longer to
1553 * do but allow to reinvoke DestroyElement whenever we encounter a
1554 * storage object. The optimisation reside in the usage of another
1555 * enumeration stategy that would give all the leaves of a storage
1556 * first. (postfix order)
1558 HRESULT WINAPI
StorageImpl_DestroyElement(
1560 const OLECHAR
*pwcsName
)/* [string][in] */
1562 StorageImpl
* const This
=(StorageImpl
*)iface
;
1564 IEnumSTATSTGImpl
* propertyEnumeration
;
1567 StgProperty propertyToDelete
;
1568 StgProperty parentProperty
;
1569 ULONG foundPropertyIndexToDelete
;
1570 ULONG typeOfRelation
;
1571 ULONG parentPropertyId
;
1574 iface
, debugstr_w(pwcsName
));
1577 * Perform a sanity check on the parameters.
1580 return STG_E_INVALIDPOINTER
;
1583 * Create a property enumeration to search the property with the given name
1585 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
1586 This
->ancestorStorage
,
1587 This
->rootPropertySetIndex
);
1589 foundPropertyIndexToDelete
= IEnumSTATSTGImpl_FindProperty(
1590 propertyEnumeration
,
1594 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1596 if ( foundPropertyIndexToDelete
== PROPERTY_NULL
)
1598 return STG_E_FILENOTFOUND
;
1602 * Find the parent property of the property to delete (the one that
1603 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1604 * the parent is This. Otherwise, the parent is one of it's sibling...
1608 * First, read This's StgProperty..
1610 res
= StorageImpl_ReadProperty(
1611 This
->ancestorStorage
,
1612 This
->rootPropertySetIndex
,
1618 * Second, check to see if by any chance the actual storage (This) is not
1619 * the parent of the property to delete... We never know...
1621 if ( parentProperty
.dirProperty
== foundPropertyIndexToDelete
)
1624 * Set data as it would have been done in the else part...
1626 typeOfRelation
= PROPERTY_RELATION_DIR
;
1627 parentPropertyId
= This
->rootPropertySetIndex
;
1632 * Create a property enumeration to search the parent properties, and
1633 * delete it once done.
1635 IEnumSTATSTGImpl
* propertyEnumeration2
;
1637 propertyEnumeration2
= IEnumSTATSTGImpl_Construct(
1638 This
->ancestorStorage
,
1639 This
->rootPropertySetIndex
);
1641 typeOfRelation
= IEnumSTATSTGImpl_FindParentProperty(
1642 propertyEnumeration2
,
1643 foundPropertyIndexToDelete
,
1647 IEnumSTATSTGImpl_Destroy(propertyEnumeration2
);
1650 if ( propertyToDelete
.propertyType
== PROPTYPE_STORAGE
)
1652 hr
= deleteStorageProperty(
1654 foundPropertyIndexToDelete
,
1657 else if ( propertyToDelete
.propertyType
== PROPTYPE_STREAM
)
1659 hr
= deleteStreamProperty(
1661 foundPropertyIndexToDelete
,
1669 * Adjust the property chain
1671 hr
= adjustPropertyChain(
1682 /*********************************************************************
1686 * Perform the deletion of a complete storage node
1689 static HRESULT
deleteStorageProperty(
1690 StorageImpl
*parentStorage
,
1691 ULONG indexOfPropertyToDelete
,
1692 StgProperty propertyToDelete
)
1694 IEnumSTATSTG
*elements
= 0;
1695 IStorage
*childStorage
= 0;
1696 STATSTG currentElement
;
1698 HRESULT destroyHr
= S_OK
;
1701 * Open the storage and enumerate it
1703 hr
= StorageBaseImpl_OpenStorage(
1704 (IStorage
*)parentStorage
,
1705 propertyToDelete
.name
,
1707 STGM_SHARE_EXCLUSIVE
,
1718 * Enumerate the elements
1720 IStorage_EnumElements( childStorage
, 0, 0, 0, &elements
);
1725 * Obtain the next element
1727 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1730 destroyHr
= StorageImpl_DestroyElement(
1731 (IStorage
*)childStorage
,
1732 (OLECHAR
*)currentElement
.pwcsName
);
1734 CoTaskMemFree(currentElement
.pwcsName
);
1738 * We need to Reset the enumeration every time because we delete elements
1739 * and the enumeration could be invalid
1741 IEnumSTATSTG_Reset(elements
);
1743 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1746 * Invalidate the property by zeroing it's name member.
1748 propertyToDelete
.sizeOfNameString
= 0;
1750 StorageImpl_WriteProperty(parentStorage
->ancestorStorage
,
1751 indexOfPropertyToDelete
,
1754 IStorage_Release(childStorage
);
1755 IEnumSTATSTG_Release(elements
);
1760 /*********************************************************************
1764 * Perform the deletion of a stream node
1767 static HRESULT
deleteStreamProperty(
1768 StorageImpl
*parentStorage
,
1769 ULONG indexOfPropertyToDelete
,
1770 StgProperty propertyToDelete
)
1774 ULARGE_INTEGER size
;
1776 size
.s
.HighPart
= 0;
1779 hr
= StorageBaseImpl_OpenStream(
1780 (IStorage
*)parentStorage
,
1781 (OLECHAR
*)propertyToDelete
.name
,
1783 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
,
1795 hr
= IStream_SetSize(pis
, size
);
1803 * Release the stream object.
1805 IStream_Release(pis
);
1808 * Invalidate the property by zeroing it's name member.
1810 propertyToDelete
.sizeOfNameString
= 0;
1813 * Here we should re-read the property so we get the updated pointer
1814 * but since we are here to zap it, I don't do it...
1816 StorageImpl_WriteProperty(
1817 parentStorage
->ancestorStorage
,
1818 indexOfPropertyToDelete
,
1824 /*********************************************************************
1828 * Finds a placeholder for the StgProperty within the Storage
1831 static HRESULT
findPlaceholder(
1832 StorageImpl
*storage
,
1833 ULONG propertyIndexToStore
,
1834 ULONG storePropertyIndex
,
1837 StgProperty storeProperty
;
1842 * Read the storage property
1844 res
= StorageImpl_ReadProperty(
1845 storage
->ancestorStorage
,
1854 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1856 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1858 return findPlaceholder(
1860 propertyIndexToStore
,
1861 storeProperty
.previousProperty
,
1866 storeProperty
.previousProperty
= propertyIndexToStore
;
1869 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1871 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1873 return findPlaceholder(
1875 propertyIndexToStore
,
1876 storeProperty
.nextProperty
,
1881 storeProperty
.nextProperty
= propertyIndexToStore
;
1884 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1886 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1888 return findPlaceholder(
1890 propertyIndexToStore
,
1891 storeProperty
.dirProperty
,
1896 storeProperty
.dirProperty
= propertyIndexToStore
;
1900 hr
= StorageImpl_WriteProperty(
1901 storage
->ancestorStorage
,
1913 /*************************************************************************
1917 * This method takes the previous and the next property link of a property
1918 * to be deleted and find them a place in the Storage.
1920 static HRESULT
adjustPropertyChain(
1922 StgProperty propertyToDelete
,
1923 StgProperty parentProperty
,
1924 ULONG parentPropertyId
,
1927 ULONG newLinkProperty
= PROPERTY_NULL
;
1928 BOOL needToFindAPlaceholder
= FALSE
;
1929 ULONG storeNode
= PROPERTY_NULL
;
1930 ULONG toStoreNode
= PROPERTY_NULL
;
1931 INT relationType
= 0;
1935 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1937 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1940 * Set the parent previous to the property to delete previous
1942 newLinkProperty
= propertyToDelete
.previousProperty
;
1944 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1947 * We also need to find a storage for the other link, setup variables
1948 * to do this at the end...
1950 needToFindAPlaceholder
= TRUE
;
1951 storeNode
= propertyToDelete
.previousProperty
;
1952 toStoreNode
= propertyToDelete
.nextProperty
;
1953 relationType
= PROPERTY_RELATION_NEXT
;
1956 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1959 * Set the parent previous to the property to delete next
1961 newLinkProperty
= propertyToDelete
.nextProperty
;
1965 * Link it for real...
1967 parentProperty
.previousProperty
= newLinkProperty
;
1970 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1972 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1975 * Set the parent next to the property to delete next previous
1977 newLinkProperty
= propertyToDelete
.previousProperty
;
1979 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1982 * We also need to find a storage for the other link, setup variables
1983 * to do this at the end...
1985 needToFindAPlaceholder
= TRUE
;
1986 storeNode
= propertyToDelete
.previousProperty
;
1987 toStoreNode
= propertyToDelete
.nextProperty
;
1988 relationType
= PROPERTY_RELATION_NEXT
;
1991 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1994 * Set the parent next to the property to delete next
1996 newLinkProperty
= propertyToDelete
.nextProperty
;
2000 * Link it for real...
2002 parentProperty
.nextProperty
= newLinkProperty
;
2004 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2006 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
2009 * Set the parent dir to the property to delete previous
2011 newLinkProperty
= propertyToDelete
.previousProperty
;
2013 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2016 * We also need to find a storage for the other link, setup variables
2017 * to do this at the end...
2019 needToFindAPlaceholder
= TRUE
;
2020 storeNode
= propertyToDelete
.previousProperty
;
2021 toStoreNode
= propertyToDelete
.nextProperty
;
2022 relationType
= PROPERTY_RELATION_NEXT
;
2025 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2028 * Set the parent dir to the property to delete next
2030 newLinkProperty
= propertyToDelete
.nextProperty
;
2034 * Link it for real...
2036 parentProperty
.dirProperty
= newLinkProperty
;
2040 * Write back the parent property
2042 res
= StorageImpl_WriteProperty(
2043 This
->ancestorStorage
,
2052 * If a placeholder is required for the other link, then, find one and
2053 * get out of here...
2055 if (needToFindAPlaceholder
)
2057 hr
= findPlaceholder(
2068 /******************************************************************************
2069 * SetElementTimes (IStorage)
2071 HRESULT WINAPI
StorageImpl_SetElementTimes(
2073 const OLECHAR
*pwcsName
,/* [string][in] */
2074 const FILETIME
*pctime
, /* [in] */
2075 const FILETIME
*patime
, /* [in] */
2076 const FILETIME
*pmtime
) /* [in] */
2078 FIXME("not implemented!\n");
2082 /******************************************************************************
2083 * SetStateBits (IStorage)
2085 HRESULT WINAPI
StorageImpl_SetStateBits(
2087 DWORD grfStateBits
,/* [in] */
2088 DWORD grfMask
) /* [in] */
2090 FIXME("not implemented!\n");
2094 HRESULT
StorageImpl_Construct(
2103 StgProperty currentProperty
;
2104 BOOL readSuccessful
;
2105 ULONG currentPropertyIndex
;
2107 if ( FAILED( validateSTGM(openFlags
) ))
2108 return STG_E_INVALIDFLAG
;
2110 memset(This
, 0, sizeof(StorageImpl
));
2113 * Initialize the virtual fgunction table.
2115 ICOM_VTBL(This
) = &Storage32Impl_Vtbl
;
2116 This
->v_destructor
= &StorageImpl_Destroy
;
2119 * This is the top-level storage so initialize the ancester pointer
2122 This
->ancestorStorage
= This
;
2125 * Initialize the physical support of the storage.
2127 This
->hFile
= hFile
;
2130 * Initialize the big block cache.
2132 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
2133 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
2134 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
,
2140 if (This
->bigBlockFile
== 0)
2145 ULARGE_INTEGER size
;
2146 BYTE
* bigBlockBuffer
;
2149 * Initialize all header variables:
2150 * - The big block depot consists of one block and it is at block 0
2151 * - The properties start at block 1
2152 * - There is no small block depot
2154 memset( This
->bigBlockDepotStart
,
2156 sizeof(This
->bigBlockDepotStart
));
2158 This
->bigBlockDepotCount
= 1;
2159 This
->bigBlockDepotStart
[0] = 0;
2160 This
->rootStartBlock
= 1;
2161 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2162 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
2163 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
2164 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2165 This
->extBigBlockDepotCount
= 0;
2167 StorageImpl_SaveFileHeader(This
);
2170 * Add one block for the big block depot and one block for the properties
2172 size
.s
.HighPart
= 0;
2173 size
.s
.LowPart
= This
->bigBlockSize
* 3;
2174 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
2177 * Initialize the big block depot
2179 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, 0);
2180 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2181 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
2182 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
2183 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2188 * Load the header for the file.
2190 hr
= StorageImpl_LoadFileHeader(This
);
2194 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2201 * There is no block depot cached yet.
2203 This
->indexBlockDepotCached
= 0xFFFFFFFF;
2206 * Start searching for free blocks with block 0.
2208 This
->prevFreeBlock
= 0;
2211 * Create the block chain abstractions.
2213 This
->rootBlockChain
=
2214 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
2216 This
->smallBlockDepotChain
= BlockChainStream_Construct(
2218 &This
->smallBlockDepotStart
,
2222 * Write the root property
2226 StgProperty rootProp
;
2228 * Initialize the property chain
2230 memset(&rootProp
, 0, sizeof(rootProp
));
2231 lstrcpyAtoW(rootProp
.name
, rootPropertyName
);
2233 rootProp
.sizeOfNameString
= (lstrlenW(rootProp
.name
)+1) * sizeof(WCHAR
);
2234 rootProp
.propertyType
= PROPTYPE_ROOT
;
2235 rootProp
.previousProperty
= PROPERTY_NULL
;
2236 rootProp
.nextProperty
= PROPERTY_NULL
;
2237 rootProp
.dirProperty
= PROPERTY_NULL
;
2238 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
2239 rootProp
.size
.s
.HighPart
= 0;
2240 rootProp
.size
.s
.LowPart
= 0;
2242 StorageImpl_WriteProperty(This
, 0, &rootProp
);
2246 * Find the ID of the root int he property sets.
2248 currentPropertyIndex
= 0;
2252 readSuccessful
= StorageImpl_ReadProperty(
2254 currentPropertyIndex
,
2259 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
2260 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
2262 This
->rootPropertySetIndex
= currentPropertyIndex
;
2266 currentPropertyIndex
++;
2268 } while (readSuccessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
2270 if (!readSuccessful
)
2277 * Create the block chain abstraction for the small block root chain.
2279 This
->smallBlockRootChain
= BlockChainStream_Construct(
2282 This
->rootPropertySetIndex
);
2287 void StorageImpl_Destroy(
2290 TRACE("(%p)\n", This
);
2292 BlockChainStream_Destroy(This
->smallBlockRootChain
);
2293 BlockChainStream_Destroy(This
->rootBlockChain
);
2294 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
2296 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2300 /******************************************************************************
2301 * Storage32Impl_GetNextFreeBigBlock
2303 * Returns the index of the next free big block.
2304 * If the big block depot is filled, this method will enlarge it.
2307 ULONG
StorageImpl_GetNextFreeBigBlock(
2310 ULONG depotBlockIndexPos
;
2312 ULONG depotBlockOffset
;
2313 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
2314 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2316 ULONG freeBlock
= BLOCK_UNUSED
;
2318 depotIndex
= This
->prevFreeBlock
/ blocksPerDepot
;
2319 depotBlockOffset
= (This
->prevFreeBlock
% blocksPerDepot
) * sizeof(ULONG
);
2322 * Scan the entire big block depot until we find a block marked free
2324 while (nextBlockIndex
!= BLOCK_UNUSED
)
2326 if (depotIndex
< COUNT_BBDEPOTINHEADER
)
2328 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2331 * Grow the primary depot.
2333 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2335 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2338 * Add a block depot.
2340 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2341 This
->bigBlockDepotCount
++;
2342 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2345 * Flag it as a block depot.
2347 StorageImpl_SetNextBlockInChain(This
,
2351 /* Save new header information.
2353 StorageImpl_SaveFileHeader(This
);
2358 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotIndex
);
2360 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2363 * Grow the extended depot.
2365 ULONG extIndex
= BLOCK_UNUSED
;
2366 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2367 ULONG extBlockOffset
= numExtBlocks
% (blocksPerDepot
- 1);
2369 if (extBlockOffset
== 0)
2371 /* We need an extended block.
2373 extIndex
= Storage32Impl_AddExtBlockDepot(This
);
2374 This
->extBigBlockDepotCount
++;
2375 depotBlockIndexPos
= extIndex
+ 1;
2378 depotBlockIndexPos
= depotIndex
* blocksPerDepot
;
2381 * Add a block depot and mark it in the extended block.
2383 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2384 This
->bigBlockDepotCount
++;
2385 Storage32Impl_SetExtDepotBlock(This
, depotIndex
, depotBlockIndexPos
);
2387 /* Flag the block depot.
2389 StorageImpl_SetNextBlockInChain(This
,
2393 /* If necessary, flag the extended depot block.
2395 if (extIndex
!= BLOCK_UNUSED
)
2396 StorageImpl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2398 /* Save header information.
2400 StorageImpl_SaveFileHeader(This
);
2404 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2406 if (depotBuffer
!= 0)
2408 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2409 ( nextBlockIndex
!= BLOCK_UNUSED
))
2411 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2413 if (nextBlockIndex
== BLOCK_UNUSED
)
2415 freeBlock
= (depotIndex
* blocksPerDepot
) +
2416 (depotBlockOffset
/sizeof(ULONG
));
2419 depotBlockOffset
+= sizeof(ULONG
);
2422 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2426 depotBlockOffset
= 0;
2429 This
->prevFreeBlock
= freeBlock
;
2434 /******************************************************************************
2435 * Storage32Impl_AddBlockDepot
2437 * This will create a depot block, essentially it is a block initialized
2440 void Storage32Impl_AddBlockDepot(StorageImpl
* This
, ULONG blockIndex
)
2444 blockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2447 * Initialize blocks as free
2449 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2451 StorageImpl_ReleaseBigBlock(This
, blockBuffer
);
2454 /******************************************************************************
2455 * Storage32Impl_GetExtDepotBlock
2457 * Returns the index of the block that corresponds to the specified depot
2458 * index. This method is only for depot indexes equal or greater than
2459 * COUNT_BBDEPOTINHEADER.
2461 ULONG
Storage32Impl_GetExtDepotBlock(StorageImpl
* This
, ULONG depotIndex
)
2463 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2464 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2465 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2466 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2467 ULONG blockIndex
= BLOCK_UNUSED
;
2468 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2470 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2472 if (This
->extBigBlockDepotStart
== BLOCK_END_OF_CHAIN
)
2473 return BLOCK_UNUSED
;
2475 while (extBlockCount
> 0)
2477 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2481 if (extBlockIndex
!= BLOCK_UNUSED
)
2485 depotBuffer
= StorageImpl_GetROBigBlock(This
, extBlockIndex
);
2487 if (depotBuffer
!= 0)
2489 StorageUtl_ReadDWord(depotBuffer
,
2490 extBlockOffset
* sizeof(ULONG
),
2493 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2500 /******************************************************************************
2501 * Storage32Impl_SetExtDepotBlock
2503 * Associates the specified block index to the specified depot index.
2504 * This method is only for depot indexes equal or greater than
2505 * COUNT_BBDEPOTINHEADER.
2507 void Storage32Impl_SetExtDepotBlock(StorageImpl
* This
,
2511 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2512 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2513 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2514 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2515 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2517 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2519 while (extBlockCount
> 0)
2521 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2525 if (extBlockIndex
!= BLOCK_UNUSED
)
2529 depotBuffer
= StorageImpl_GetBigBlock(This
, extBlockIndex
);
2531 if (depotBuffer
!= 0)
2533 StorageUtl_WriteDWord(depotBuffer
,
2534 extBlockOffset
* sizeof(ULONG
),
2537 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2542 /******************************************************************************
2543 * Storage32Impl_AddExtBlockDepot
2545 * Creates an extended depot block.
2547 ULONG
Storage32Impl_AddExtBlockDepot(StorageImpl
* This
)
2549 ULONG numExtBlocks
= This
->extBigBlockDepotCount
;
2550 ULONG nextExtBlock
= This
->extBigBlockDepotStart
;
2551 BYTE
* depotBuffer
= NULL
;
2552 ULONG index
= BLOCK_UNUSED
;
2553 ULONG nextBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2554 ULONG blocksPerDepotBlock
= This
->bigBlockSize
/ sizeof(ULONG
);
2555 ULONG depotBlocksPerExtBlock
= blocksPerDepotBlock
- 1;
2557 index
= (COUNT_BBDEPOTINHEADER
+ (numExtBlocks
* depotBlocksPerExtBlock
)) *
2558 blocksPerDepotBlock
;
2560 if ((numExtBlocks
== 0) && (nextExtBlock
== BLOCK_END_OF_CHAIN
))
2563 * The first extended block.
2565 This
->extBigBlockDepotStart
= index
;
2571 * Follow the chain to the last one.
2573 for (i
= 0; i
< (numExtBlocks
- 1); i
++)
2575 nextExtBlock
= Storage32Impl_GetNextExtendedBlock(This
, nextExtBlock
);
2579 * Add the new extended block to the chain.
2581 depotBuffer
= StorageImpl_GetBigBlock(This
, nextExtBlock
);
2582 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2583 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2587 * Initialize this block.
2589 depotBuffer
= StorageImpl_GetBigBlock(This
, index
);
2590 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2591 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2596 /******************************************************************************
2597 * Storage32Impl_FreeBigBlock
2599 * This method will flag the specified block as free in the big block depot.
2601 void StorageImpl_FreeBigBlock(
2605 StorageImpl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2607 if (blockIndex
< This
->prevFreeBlock
)
2608 This
->prevFreeBlock
= blockIndex
;
2611 /************************************************************************
2612 * Storage32Impl_GetNextBlockInChain
2614 * This method will retrieve the block index of the next big block in
2617 * Params: This - Pointer to the Storage object.
2618 * blockIndex - Index of the block to retrieve the chain
2621 * Returns: This method returns the index of the next block in the chain.
2622 * It will return the constants:
2623 * BLOCK_SPECIAL - If the block given was not part of a
2625 * BLOCK_END_OF_CHAIN - If the block given was the last in
2627 * BLOCK_UNUSED - If the block given was not past of a chain
2629 * BLOCK_EXTBBDEPOT - This block is part of the extended
2632 * See Windows documentation for more details on IStorage methods.
2634 ULONG
StorageImpl_GetNextBlockInChain(
2638 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2639 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2640 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2641 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2643 ULONG depotBlockIndexPos
;
2645 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2648 * Cache the currently accessed depot block.
2650 if (depotBlockCount
!= This
->indexBlockDepotCached
)
2652 This
->indexBlockDepotCached
= depotBlockCount
;
2654 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2656 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2661 * We have to look in the extended depot.
2663 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2666 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2672 for (index
= 0; index
< NUM_BLOCKS_PER_DEPOT_BLOCK
; index
++)
2674 StorageUtl_ReadDWord(depotBuffer
, index
*sizeof(ULONG
), &nextBlockIndex
);
2675 This
->blockDepotCached
[index
] = nextBlockIndex
;
2678 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2682 nextBlockIndex
= This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)];
2684 return nextBlockIndex
;
2687 /******************************************************************************
2688 * Storage32Impl_GetNextExtendedBlock
2690 * Given an extended block this method will return the next extended block.
2693 * The last ULONG of an extended block is the block index of the next
2694 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2698 * - The index of the next extended block
2699 * - BLOCK_UNUSED: there is no next extended block.
2700 * - Any other return values denotes failure.
2702 ULONG
Storage32Impl_GetNextExtendedBlock(StorageImpl
* This
, ULONG blockIndex
)
2704 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2705 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2708 depotBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2712 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2714 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2717 return nextBlockIndex
;
2720 /******************************************************************************
2721 * Storage32Impl_SetNextBlockInChain
2723 * This method will write the index of the specified block's next block
2724 * in the big block depot.
2726 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2729 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2730 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2731 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2734 void StorageImpl_SetNextBlockInChain(
2739 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2740 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2741 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2742 ULONG depotBlockIndexPos
;
2745 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2746 assert(blockIndex
!= nextBlock
);
2748 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2750 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2755 * We have to look in the extended depot.
2757 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2760 depotBuffer
= StorageImpl_GetBigBlock(This
, depotBlockIndexPos
);
2764 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2765 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2769 * Update the cached block depot, if necessary.
2771 if (depotBlockCount
== This
->indexBlockDepotCached
)
2773 This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)] = nextBlock
;
2777 /******************************************************************************
2778 * Storage32Impl_LoadFileHeader
2780 * This method will read in the file header, i.e. big block index -1.
2782 HRESULT
StorageImpl_LoadFileHeader(
2785 HRESULT hr
= STG_E_FILENOTFOUND
;
2786 void* headerBigBlock
= NULL
;
2790 * Get a pointer to the big block of data containing the header.
2792 headerBigBlock
= StorageImpl_GetROBigBlock(This
, -1);
2795 * Extract the information from the header.
2797 if (headerBigBlock
!=0)
2800 * Check for the "magic number" signature and return an error if it is not
2803 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2805 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2806 return STG_E_OLDFORMAT
;
2809 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2811 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2812 return STG_E_INVALIDHEADER
;
2815 StorageUtl_ReadWord(
2817 OFFSET_BIGBLOCKSIZEBITS
,
2818 &This
->bigBlockSizeBits
);
2820 StorageUtl_ReadWord(
2822 OFFSET_SMALLBLOCKSIZEBITS
,
2823 &This
->smallBlockSizeBits
);
2825 StorageUtl_ReadDWord(
2827 OFFSET_BBDEPOTCOUNT
,
2828 &This
->bigBlockDepotCount
);
2830 StorageUtl_ReadDWord(
2832 OFFSET_ROOTSTARTBLOCK
,
2833 &This
->rootStartBlock
);
2835 StorageUtl_ReadDWord(
2837 OFFSET_SBDEPOTSTART
,
2838 &This
->smallBlockDepotStart
);
2840 StorageUtl_ReadDWord(
2842 OFFSET_EXTBBDEPOTSTART
,
2843 &This
->extBigBlockDepotStart
);
2845 StorageUtl_ReadDWord(
2847 OFFSET_EXTBBDEPOTCOUNT
,
2848 &This
->extBigBlockDepotCount
);
2850 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2852 StorageUtl_ReadDWord(
2854 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2855 &(This
->bigBlockDepotStart
[index
]));
2859 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2863 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2864 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2868 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2869 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2873 * Right now, the code is making some assumptions about the size of the
2874 * blocks, just make sure they are what we're expecting.
2876 assert( (This
->bigBlockSize
==DEF_BIG_BLOCK_SIZE
) &&
2877 (This
->smallBlockSize
==DEF_SMALL_BLOCK_SIZE
));
2880 * Release the block.
2882 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2890 /******************************************************************************
2891 * Storage32Impl_SaveFileHeader
2893 * This method will save to the file the header, i.e. big block -1.
2895 void StorageImpl_SaveFileHeader(
2898 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2903 * Get a pointer to the big block of data containing the header.
2905 success
= StorageImpl_ReadBigBlock(This
, -1, headerBigBlock
);
2908 * If the block read failed, the file is probably new.
2913 * Initialize for all unknown fields.
2915 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
2918 * Initialize the magic number.
2920 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
2923 * And a bunch of things we don't know what they mean
2925 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
2926 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
2927 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
2928 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
2929 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
2933 * Write the information to the header.
2935 if (headerBigBlock
!=0)
2937 StorageUtl_WriteWord(
2939 OFFSET_BIGBLOCKSIZEBITS
,
2940 This
->bigBlockSizeBits
);
2942 StorageUtl_WriteWord(
2944 OFFSET_SMALLBLOCKSIZEBITS
,
2945 This
->smallBlockSizeBits
);
2947 StorageUtl_WriteDWord(
2949 OFFSET_BBDEPOTCOUNT
,
2950 This
->bigBlockDepotCount
);
2952 StorageUtl_WriteDWord(
2954 OFFSET_ROOTSTARTBLOCK
,
2955 This
->rootStartBlock
);
2957 StorageUtl_WriteDWord(
2959 OFFSET_SBDEPOTSTART
,
2960 This
->smallBlockDepotStart
);
2962 StorageUtl_WriteDWord(
2964 OFFSET_EXTBBDEPOTSTART
,
2965 This
->extBigBlockDepotStart
);
2967 StorageUtl_WriteDWord(
2969 OFFSET_EXTBBDEPOTCOUNT
,
2970 This
->extBigBlockDepotCount
);
2972 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2974 StorageUtl_WriteDWord(
2976 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2977 (This
->bigBlockDepotStart
[index
]));
2982 * Write the big block back to the file.
2984 StorageImpl_WriteBigBlock(This
, -1, headerBigBlock
);
2987 /******************************************************************************
2988 * Storage32Impl_ReadProperty
2990 * This method will read the specified property from the property chain.
2992 BOOL
StorageImpl_ReadProperty(
2995 StgProperty
* buffer
)
2997 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
2998 ULARGE_INTEGER offsetInPropSet
;
2999 BOOL readSuccessful
;
3002 offsetInPropSet
.s
.HighPart
= 0;
3003 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3005 readSuccessful
= BlockChainStream_ReadAt(
3006 This
->rootBlockChain
,
3014 memset(buffer
->name
, 0, sizeof(buffer
->name
));
3017 currentProperty
+OFFSET_PS_NAME
,
3018 PROPERTY_NAME_BUFFER_LEN
);
3020 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
3022 StorageUtl_ReadWord(
3024 OFFSET_PS_NAMELENGTH
,
3025 &buffer
->sizeOfNameString
);
3027 StorageUtl_ReadDWord(
3029 OFFSET_PS_PREVIOUSPROP
,
3030 &buffer
->previousProperty
);
3032 StorageUtl_ReadDWord(
3035 &buffer
->nextProperty
);
3037 StorageUtl_ReadDWord(
3040 &buffer
->dirProperty
);
3042 StorageUtl_ReadGUID(
3045 &buffer
->propertyUniqueID
);
3047 StorageUtl_ReadDWord(
3050 &buffer
->timeStampS1
);
3052 StorageUtl_ReadDWord(
3055 &buffer
->timeStampD1
);
3057 StorageUtl_ReadDWord(
3060 &buffer
->timeStampS2
);
3062 StorageUtl_ReadDWord(
3065 &buffer
->timeStampD2
);
3067 StorageUtl_ReadDWord(
3069 OFFSET_PS_STARTBLOCK
,
3070 &buffer
->startingBlock
);
3072 StorageUtl_ReadDWord(
3075 &buffer
->size
.s
.LowPart
);
3077 buffer
->size
.s
.HighPart
= 0;
3080 return readSuccessful
;
3083 /*********************************************************************
3084 * Write the specified property into the property chain
3086 BOOL
StorageImpl_WriteProperty(
3089 StgProperty
* buffer
)
3091 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3092 ULARGE_INTEGER offsetInPropSet
;
3093 BOOL writeSuccessful
;
3096 offsetInPropSet
.s
.HighPart
= 0;
3097 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3099 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
3102 currentProperty
+ OFFSET_PS_NAME
,
3104 PROPERTY_NAME_BUFFER_LEN
);
3106 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
3108 StorageUtl_WriteWord(
3110 OFFSET_PS_NAMELENGTH
,
3111 buffer
->sizeOfNameString
);
3113 StorageUtl_WriteDWord(
3115 OFFSET_PS_PREVIOUSPROP
,
3116 buffer
->previousProperty
);
3118 StorageUtl_WriteDWord(
3121 buffer
->nextProperty
);
3123 StorageUtl_WriteDWord(
3126 buffer
->dirProperty
);
3128 StorageUtl_WriteGUID(
3131 &buffer
->propertyUniqueID
);
3133 StorageUtl_WriteDWord(
3136 buffer
->timeStampS1
);
3138 StorageUtl_WriteDWord(
3141 buffer
->timeStampD1
);
3143 StorageUtl_WriteDWord(
3146 buffer
->timeStampS2
);
3148 StorageUtl_WriteDWord(
3151 buffer
->timeStampD2
);
3153 StorageUtl_WriteDWord(
3155 OFFSET_PS_STARTBLOCK
,
3156 buffer
->startingBlock
);
3158 StorageUtl_WriteDWord(
3161 buffer
->size
.s
.LowPart
);
3163 writeSuccessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
3168 return writeSuccessful
;
3171 BOOL
StorageImpl_ReadBigBlock(
3176 void* bigBlockBuffer
;
3178 bigBlockBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
3180 if (bigBlockBuffer
!=0)
3182 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
3184 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3192 BOOL
StorageImpl_WriteBigBlock(
3197 void* bigBlockBuffer
;
3199 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
3201 if (bigBlockBuffer
!=0)
3203 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
3205 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3213 void* StorageImpl_GetROBigBlock(
3217 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
3220 void* StorageImpl_GetBigBlock(
3224 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
3227 void StorageImpl_ReleaseBigBlock(
3231 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
3234 /******************************************************************************
3235 * Storage32Impl_SmallBlocksToBigBlocks
3237 * This method will convert a small block chain to a big block chain.
3238 * The small block chain will be destroyed.
3240 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
3242 SmallBlockChainStream
** ppsbChain
)
3244 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
3245 ULARGE_INTEGER size
, offset
;
3246 ULONG cbRead
, cbWritten
, cbTotalRead
, cbTotalWritten
;
3247 ULONG propertyIndex
;
3248 BOOL successRead
, successWrite
;
3249 StgProperty chainProperty
;
3251 BlockChainStream
*bbTempChain
= NULL
;
3252 BlockChainStream
*bigBlockChain
= NULL
;
3255 * Create a temporary big block chain that doesn't have
3256 * an associated property. This temporary chain will be
3257 * used to copy data from small blocks to big blocks.
3259 bbTempChain
= BlockChainStream_Construct(This
,
3264 * Grow the big block chain.
3266 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
3267 BlockChainStream_SetSize(bbTempChain
, size
);
3270 * Copy the contents of the small block chain to the big block chain
3271 * by small block size increments.
3273 offset
.s
.LowPart
= 0;
3274 offset
.s
.HighPart
= 0;
3278 buffer
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE
);
3281 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
3283 DEF_SMALL_BLOCK_SIZE
,
3286 cbTotalRead
+= cbRead
;
3288 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
3293 cbTotalWritten
+= cbWritten
;
3295 offset
.s
.LowPart
+= This
->smallBlockSize
;
3297 } while (successRead
&& successWrite
);
3298 HeapFree(GetProcessHeap(),0,buffer
);
3300 assert(cbTotalRead
== cbTotalWritten
);
3303 * Destroy the small block chain.
3305 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
3306 size
.s
.HighPart
= 0;
3308 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
3309 SmallBlockChainStream_Destroy(*ppsbChain
);
3313 * Change the property information. This chain is now a big block chain
3314 * and it doesn't reside in the small blocks chain anymore.
3316 StorageImpl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3318 chainProperty
.startingBlock
= bbHeadOfChain
;
3320 StorageImpl_WriteProperty(This
, propertyIndex
, &chainProperty
);
3323 * Destroy the temporary propertyless big block chain.
3324 * Create a new big block chain associated with this property.
3326 BlockChainStream_Destroy(bbTempChain
);
3327 bigBlockChain
= BlockChainStream_Construct(This
,
3331 return bigBlockChain
;
3334 /******************************************************************************
3335 ** Storage32InternalImpl implementation
3338 StorageInternalImpl
* StorageInternalImpl_Construct(
3339 StorageImpl
* ancestorStorage
,
3340 ULONG rootPropertyIndex
)
3342 StorageInternalImpl
* newStorage
;
3345 * Allocate space for the new storage object
3347 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl
));
3351 memset(newStorage
, 0, sizeof(StorageInternalImpl
));
3354 * Initialize the virtual function table.
3356 ICOM_VTBL(newStorage
) = &Storage32InternalImpl_Vtbl
;
3357 newStorage
->v_destructor
= &StorageInternalImpl_Destroy
;
3360 * Keep the ancestor storage pointer and nail a reference to it.
3362 newStorage
->ancestorStorage
= ancestorStorage
;
3363 StorageBaseImpl_AddRef((IStorage
*)(newStorage
->ancestorStorage
));
3366 * Keep the index of the root property set for this storage,
3368 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3376 void StorageInternalImpl_Destroy(
3377 StorageInternalImpl
* This
)
3379 StorageBaseImpl_Release((IStorage
*)This
->ancestorStorage
);
3380 HeapFree(GetProcessHeap(), 0, This
);
3383 /******************************************************************************
3385 ** Storage32InternalImpl_Commit
3387 ** The non-root storages cannot be opened in transacted mode thus this function
3390 HRESULT WINAPI
StorageInternalImpl_Commit(
3392 DWORD grfCommitFlags
) /* [in] */
3397 /******************************************************************************
3399 ** Storage32InternalImpl_Revert
3401 ** The non-root storages cannot be opened in transacted mode thus this function
3404 HRESULT WINAPI
StorageInternalImpl_Revert(
3410 /******************************************************************************
3411 ** IEnumSTATSTGImpl implementation
3414 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3415 StorageImpl
* parentStorage
,
3416 ULONG firstPropertyNode
)
3418 IEnumSTATSTGImpl
* newEnumeration
;
3420 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3422 if (newEnumeration
!=0)
3425 * Set-up the virtual function table and reference count.
3427 ICOM_VTBL(newEnumeration
) = &IEnumSTATSTGImpl_Vtbl
;
3428 newEnumeration
->ref
= 0;
3431 * We want to nail-down the reference to the storage in case the
3432 * enumeration out-lives the storage in the client application.
3434 newEnumeration
->parentStorage
= parentStorage
;
3435 IStorage_AddRef((IStorage
*)newEnumeration
->parentStorage
);
3437 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3440 * Initialize the search stack
3442 newEnumeration
->stackSize
= 0;
3443 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3444 newEnumeration
->stackToVisit
=
3445 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3448 * Make sure the current node of the iterator is the first one.
3450 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3453 return newEnumeration
;
3456 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3458 IStorage_Release((IStorage
*)This
->parentStorage
);
3459 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3460 HeapFree(GetProcessHeap(), 0, This
);
3463 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3464 IEnumSTATSTG
* iface
,
3468 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3471 * Perform a sanity check on the parameters.
3474 return E_INVALIDARG
;
3477 * Initialize the return parameter.
3482 * Compare the riid with the interface IDs implemented by this object.
3484 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3486 *ppvObject
= (IEnumSTATSTG
*)This
;
3488 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3490 *ppvObject
= (IEnumSTATSTG
*)This
;
3494 * Check that we obtained an interface.
3496 if ((*ppvObject
)==0)
3497 return E_NOINTERFACE
;
3500 * Query Interface always increases the reference count by one when it is
3503 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3508 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3509 IEnumSTATSTG
* iface
)
3511 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3517 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3518 IEnumSTATSTG
* iface
)
3520 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3528 * If the reference count goes down to 0, perform suicide.
3532 IEnumSTATSTGImpl_Destroy(This
);
3538 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3539 IEnumSTATSTG
* iface
,
3542 ULONG
* pceltFetched
)
3544 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3546 StgProperty currentProperty
;
3547 STATSTG
* currentReturnStruct
= rgelt
;
3548 ULONG objectFetched
= 0;
3549 ULONG currentSearchNode
;
3552 * Perform a sanity check on the parameters.
3554 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3555 return E_INVALIDARG
;
3558 * To avoid the special case, get another pointer to a ULONG value if
3559 * the caller didn't supply one.
3561 if (pceltFetched
==0)
3562 pceltFetched
= &objectFetched
;
3565 * Start the iteration, we will iterate until we hit the end of the
3566 * linked list or until we hit the number of items to iterate through
3571 * Start with the node at the top of the stack.
3573 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3575 while ( ( *pceltFetched
< celt
) &&
3576 ( currentSearchNode
!=PROPERTY_NULL
) )
3579 * Remove the top node from the stack
3581 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3584 * Read the property from the storage.
3586 StorageImpl_ReadProperty(This
->parentStorage
,
3591 * Copy the information to the return buffer.
3593 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3598 * Step to the next item in the iteration
3601 currentReturnStruct
++;
3604 * Push the next search node in the search stack.
3606 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3609 * continue the iteration.
3611 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3614 if (*pceltFetched
== celt
)
3621 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3622 IEnumSTATSTG
* iface
,
3625 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3627 StgProperty currentProperty
;
3628 ULONG objectFetched
= 0;
3629 ULONG currentSearchNode
;
3632 * Start with the node at the top of the stack.
3634 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3636 while ( (objectFetched
< celt
) &&
3637 (currentSearchNode
!=PROPERTY_NULL
) )
3640 * Remove the top node from the stack
3642 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3645 * Read the property from the storage.
3647 StorageImpl_ReadProperty(This
->parentStorage
,
3652 * Step to the next item in the iteration
3657 * Push the next search node in the search stack.
3659 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3662 * continue the iteration.
3664 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3667 if (objectFetched
== celt
)
3673 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3674 IEnumSTATSTG
* iface
)
3676 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3678 StgProperty rootProperty
;
3679 BOOL readSuccessful
;
3682 * Re-initialize the search stack to an empty stack
3684 This
->stackSize
= 0;
3687 * Read the root property from the storage.
3689 readSuccessful
= StorageImpl_ReadProperty(
3690 This
->parentStorage
,
3691 This
->firstPropertyNode
,
3696 assert(rootProperty
.sizeOfNameString
!=0);
3699 * Push the search node in the search stack.
3701 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3707 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3708 IEnumSTATSTG
* iface
,
3709 IEnumSTATSTG
** ppenum
)
3711 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3713 IEnumSTATSTGImpl
* newClone
;
3716 * Perform a sanity check on the parameters.
3719 return E_INVALIDARG
;
3721 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3722 This
->firstPropertyNode
);
3726 * The new clone enumeration must point to the same current node as
3729 newClone
->stackSize
= This
->stackSize
;
3730 newClone
->stackMaxSize
= This
->stackMaxSize
;
3731 newClone
->stackToVisit
=
3732 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3735 newClone
->stackToVisit
,
3737 sizeof(ULONG
) * newClone
->stackSize
);
3739 *ppenum
= (IEnumSTATSTG
*)newClone
;
3742 * Don't forget to nail down a reference to the clone before
3745 IEnumSTATSTGImpl_AddRef(*ppenum
);
3750 INT
IEnumSTATSTGImpl_FindParentProperty(
3751 IEnumSTATSTGImpl
*This
,
3752 ULONG childProperty
,
3753 StgProperty
*currentProperty
,
3756 ULONG currentSearchNode
;
3760 * To avoid the special case, get another pointer to a ULONG value if
3761 * the caller didn't supply one.
3764 thisNodeId
= &foundNode
;
3767 * Start with the node at the top of the stack.
3769 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3772 while (currentSearchNode
!=PROPERTY_NULL
)
3775 * Store the current node in the returned parameters
3777 *thisNodeId
= currentSearchNode
;
3780 * Remove the top node from the stack
3782 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3785 * Read the property from the storage.
3787 StorageImpl_ReadProperty(
3788 This
->parentStorage
,
3792 if (currentProperty
->previousProperty
== childProperty
)
3793 return PROPERTY_RELATION_PREVIOUS
;
3795 else if (currentProperty
->nextProperty
== childProperty
)
3796 return PROPERTY_RELATION_NEXT
;
3798 else if (currentProperty
->dirProperty
== childProperty
)
3799 return PROPERTY_RELATION_DIR
;
3802 * Push the next search node in the search stack.
3804 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3807 * continue the iteration.
3809 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3812 return PROPERTY_NULL
;
3815 ULONG
IEnumSTATSTGImpl_FindProperty(
3816 IEnumSTATSTGImpl
* This
,
3817 const OLECHAR
* lpszPropName
,
3818 StgProperty
* currentProperty
)
3820 ULONG currentSearchNode
;
3823 * Start with the node at the top of the stack.
3825 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3827 while (currentSearchNode
!=PROPERTY_NULL
)
3830 * Remove the top node from the stack
3832 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3835 * Read the property from the storage.
3837 StorageImpl_ReadProperty(This
->parentStorage
,
3841 if ( propertyNameCmp(
3842 (OLECHAR
*)currentProperty
->name
,
3843 (OLECHAR
*)lpszPropName
) == 0)
3844 return currentSearchNode
;
3847 * Push the next search node in the search stack.
3849 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3852 * continue the iteration.
3854 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3857 return PROPERTY_NULL
;
3860 void IEnumSTATSTGImpl_PushSearchNode(
3861 IEnumSTATSTGImpl
* This
,
3864 StgProperty rootProperty
;
3865 BOOL readSuccessful
;
3868 * First, make sure we're not trying to push an unexisting node.
3870 if (nodeToPush
==PROPERTY_NULL
)
3874 * First push the node to the stack
3876 if (This
->stackSize
== This
->stackMaxSize
)
3878 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3880 This
->stackToVisit
= HeapReAlloc(
3884 sizeof(ULONG
) * This
->stackMaxSize
);
3887 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3891 * Read the root property from the storage.
3893 readSuccessful
= StorageImpl_ReadProperty(
3894 This
->parentStorage
,
3900 assert(rootProperty
.sizeOfNameString
!=0);
3903 * Push the previous search node in the search stack.
3905 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3909 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3910 IEnumSTATSTGImpl
* This
,
3915 if (This
->stackSize
== 0)
3916 return PROPERTY_NULL
;
3918 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3926 /******************************************************************************
3927 ** StorageUtl implementation
3930 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3932 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3935 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3937 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3940 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3942 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3945 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3947 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3950 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3952 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3953 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3954 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3956 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
3959 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
3961 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
3962 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
3963 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
3965 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
3968 void StorageUtl_CopyPropertyToSTATSTG(
3969 STATSTG
* destination
,
3970 StgProperty
* source
,
3974 * The copy of the string occurs only when the flag is not set
3976 if ((statFlags
& STATFLAG_NONAME
) != 0)
3978 destination
->pwcsName
= 0;
3982 destination
->pwcsName
=
3983 CoTaskMemAlloc((lstrlenW(source
->name
)+1)*sizeof(WCHAR
));
3985 strcpyW((LPWSTR
)destination
->pwcsName
, source
->name
);
3988 switch (source
->propertyType
)
3990 case PROPTYPE_STORAGE
:
3992 destination
->type
= STGTY_STORAGE
;
3994 case PROPTYPE_STREAM
:
3995 destination
->type
= STGTY_STREAM
;
3998 destination
->type
= STGTY_STREAM
;
4002 destination
->cbSize
= source
->size
;
4004 currentReturnStruct->mtime = {0}; TODO
4005 currentReturnStruct->ctime = {0};
4006 currentReturnStruct->atime = {0};
4008 destination
->grfMode
= 0;
4009 destination
->grfLocksSupported
= 0;
4010 destination
->clsid
= source
->propertyUniqueID
;
4011 destination
->grfStateBits
= 0;
4012 destination
->reserved
= 0;
4015 /******************************************************************************
4016 ** BlockChainStream implementation
4019 BlockChainStream
* BlockChainStream_Construct(
4020 StorageImpl
* parentStorage
,
4021 ULONG
* headOfStreamPlaceHolder
,
4022 ULONG propertyIndex
)
4024 BlockChainStream
* newStream
;
4027 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
4029 newStream
->parentStorage
= parentStorage
;
4030 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
4031 newStream
->ownerPropertyIndex
= propertyIndex
;
4032 newStream
->lastBlockNoInSequence
= 0xFFFFFFFF;
4033 newStream
->tailIndex
= BLOCK_END_OF_CHAIN
;
4034 newStream
->numBlocks
= 0;
4036 blockIndex
= BlockChainStream_GetHeadOfChain(newStream
);
4038 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4040 newStream
->numBlocks
++;
4041 newStream
->tailIndex
= blockIndex
;
4043 blockIndex
= StorageImpl_GetNextBlockInChain(
4051 void BlockChainStream_Destroy(BlockChainStream
* This
)
4053 HeapFree(GetProcessHeap(), 0, This
);
4056 /******************************************************************************
4057 * BlockChainStream_GetHeadOfChain
4059 * Returns the head of this stream chain.
4060 * Some special chains don't have properties, their heads are kept in
4061 * This->headOfStreamPlaceHolder.
4064 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
4066 StgProperty chainProperty
;
4067 BOOL readSuccessful
;
4069 if (This
->headOfStreamPlaceHolder
!= 0)
4070 return *(This
->headOfStreamPlaceHolder
);
4072 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
4074 readSuccessful
= StorageImpl_ReadProperty(
4075 This
->parentStorage
,
4076 This
->ownerPropertyIndex
,
4081 return chainProperty
.startingBlock
;
4085 return BLOCK_END_OF_CHAIN
;
4088 /******************************************************************************
4089 * BlockChainStream_GetCount
4091 * Returns the number of blocks that comprises this chain.
4092 * This is not the size of the stream as the last block may not be full!
4095 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
4100 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4102 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4106 blockIndex
= StorageImpl_GetNextBlockInChain(
4107 This
->parentStorage
,
4114 /******************************************************************************
4115 * BlockChainStream_ReadAt
4117 * Reads a specified number of bytes from this chain at the specified offset.
4118 * bytesRead may be NULL.
4119 * Failure will be returned if the specified number of bytes has not been read.
4121 BOOL
BlockChainStream_ReadAt(BlockChainStream
* This
,
4122 ULARGE_INTEGER offset
,
4127 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4128 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4129 ULONG bytesToReadInBuffer
;
4132 BYTE
* bigBlockBuffer
;
4135 * Find the first block in the stream that contains part of the buffer.
4137 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4138 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4139 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4141 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4142 This
->lastBlockNoInSequence
= blockNoInSequence
;
4146 ULONG temp
= blockNoInSequence
;
4148 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4149 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4150 This
->lastBlockNoInSequence
= temp
;
4153 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4156 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4158 blockNoInSequence
--;
4161 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4164 * Start reading the buffer.
4167 bufferWalker
= buffer
;
4169 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4172 * Calculate how many bytes we can copy from this big block.
4174 bytesToReadInBuffer
=
4175 min(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4178 * Copy those bytes to the buffer
4181 StorageImpl_GetROBigBlock(This
->parentStorage
, blockIndex
);
4183 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
4185 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4188 * Step to the next big block.
4191 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4193 bufferWalker
+= bytesToReadInBuffer
;
4194 size
-= bytesToReadInBuffer
;
4195 *bytesRead
+= bytesToReadInBuffer
;
4196 offsetInBlock
= 0; /* There is no offset on the next block */
4203 /******************************************************************************
4204 * BlockChainStream_WriteAt
4206 * Writes the specified number of bytes to this chain at the specified offset.
4207 * bytesWritten may be NULL.
4208 * Will fail if not all specified number of bytes have been written.
4210 BOOL
BlockChainStream_WriteAt(BlockChainStream
* This
,
4211 ULARGE_INTEGER offset
,
4214 ULONG
* bytesWritten
)
4216 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4217 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4221 BYTE
* bigBlockBuffer
;
4224 * Find the first block in the stream that contains part of the buffer.
4226 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4227 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4228 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4230 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4231 This
->lastBlockNoInSequence
= blockNoInSequence
;
4235 ULONG temp
= blockNoInSequence
;
4237 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4238 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4239 This
->lastBlockNoInSequence
= temp
;
4242 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4245 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4247 blockNoInSequence
--;
4250 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4253 * Here, I'm casting away the constness on the buffer variable
4254 * This is OK since we don't intend to modify that buffer.
4257 bufferWalker
= (BYTE
*)buffer
;
4259 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4262 * Calculate how many bytes we can copy from this big block.
4265 min(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4268 * Copy those bytes to the buffer
4270 bigBlockBuffer
= StorageImpl_GetBigBlock(This
->parentStorage
, blockIndex
);
4272 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
4274 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4277 * Step to the next big block.
4280 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4282 bufferWalker
+= bytesToWrite
;
4283 size
-= bytesToWrite
;
4284 *bytesWritten
+= bytesToWrite
;
4285 offsetInBlock
= 0; /* There is no offset on the next block */
4291 /******************************************************************************
4292 * BlockChainStream_Shrink
4294 * Shrinks this chain in the big block depot.
4296 BOOL
BlockChainStream_Shrink(BlockChainStream
* This
,
4297 ULARGE_INTEGER newSize
)
4299 ULONG blockIndex
, extraBlock
;
4304 * Reset the last accessed block cache.
4306 This
->lastBlockNoInSequence
= 0xFFFFFFFF;
4307 This
->lastBlockNoInSequenceIndex
= BLOCK_END_OF_CHAIN
;
4310 * Figure out how many blocks are needed to contain the new size
4312 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4314 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4317 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4320 * Go to the new end of chain
4322 while (count
< numBlocks
)
4325 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4330 /* Get the next block before marking the new end */
4332 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4334 /* Mark the new end of chain */
4335 StorageImpl_SetNextBlockInChain(
4336 This
->parentStorage
,
4338 BLOCK_END_OF_CHAIN
);
4340 This
->tailIndex
= blockIndex
;
4341 This
->numBlocks
= numBlocks
;
4344 * Mark the extra blocks as free
4346 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4349 StorageImpl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4351 StorageImpl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4352 extraBlock
= blockIndex
;
4358 /******************************************************************************
4359 * BlockChainStream_Enlarge
4361 * Grows this chain in the big block depot.
4363 BOOL
BlockChainStream_Enlarge(BlockChainStream
* This
,
4364 ULARGE_INTEGER newSize
)
4366 ULONG blockIndex
, currentBlock
;
4368 ULONG oldNumBlocks
= 0;
4370 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4373 * Empty chain. Create the head.
4375 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4377 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4378 StorageImpl_SetNextBlockInChain(This
->parentStorage
,
4380 BLOCK_END_OF_CHAIN
);
4382 if (This
->headOfStreamPlaceHolder
!= 0)
4384 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4388 StgProperty chainProp
;
4389 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4391 StorageImpl_ReadProperty(
4392 This
->parentStorage
,
4393 This
->ownerPropertyIndex
,
4396 chainProp
.startingBlock
= blockIndex
;
4398 StorageImpl_WriteProperty(
4399 This
->parentStorage
,
4400 This
->ownerPropertyIndex
,
4404 This
->tailIndex
= blockIndex
;
4405 This
->numBlocks
= 1;
4409 * Figure out how many blocks are needed to contain this stream
4411 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4413 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4417 * Go to the current end of chain
4419 if (This
->tailIndex
== BLOCK_END_OF_CHAIN
)
4421 currentBlock
= blockIndex
;
4423 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4426 currentBlock
= blockIndex
;
4429 StorageImpl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4432 This
->tailIndex
= currentBlock
;
4435 currentBlock
= This
->tailIndex
;
4436 oldNumBlocks
= This
->numBlocks
;
4439 * Add new blocks to the chain
4441 if (oldNumBlocks
< newNumBlocks
)
4443 while (oldNumBlocks
< newNumBlocks
)
4445 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4447 StorageImpl_SetNextBlockInChain(
4448 This
->parentStorage
,
4452 StorageImpl_SetNextBlockInChain(
4453 This
->parentStorage
,
4455 BLOCK_END_OF_CHAIN
);
4457 currentBlock
= blockIndex
;
4461 This
->tailIndex
= blockIndex
;
4462 This
->numBlocks
= newNumBlocks
;
4468 /******************************************************************************
4469 * BlockChainStream_SetSize
4471 * Sets the size of this stream. The big block depot will be updated.
4472 * The file will grow if we grow the chain.
4474 * TODO: Free the actual blocks in the file when we shrink the chain.
4475 * Currently, the blocks are still in the file. So the file size
4476 * doesn't shrink even if we shrink streams.
4478 BOOL
BlockChainStream_SetSize(
4479 BlockChainStream
* This
,
4480 ULARGE_INTEGER newSize
)
4482 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4484 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
4487 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
4489 BlockChainStream_Shrink(This
, newSize
);
4493 ULARGE_INTEGER fileSize
=
4494 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4496 ULONG diff
= newSize
.s
.LowPart
- size
.s
.LowPart
;
4499 * Make sure the file stays a multiple of blocksize
4501 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4502 diff
+= (This
->parentStorage
->bigBlockSize
-
4503 (diff
% This
->parentStorage
->bigBlockSize
) );
4505 fileSize
.s
.LowPart
+= diff
;
4506 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4508 BlockChainStream_Enlarge(This
, newSize
);
4514 /******************************************************************************
4515 * BlockChainStream_GetSize
4517 * Returns the size of this chain.
4518 * Will return the block count if this chain doesn't have a property.
4520 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4522 StgProperty chainProperty
;
4524 if(This
->headOfStreamPlaceHolder
== NULL
)
4527 * This chain is a data stream read the property and return
4528 * the appropriate size
4530 StorageImpl_ReadProperty(
4531 This
->parentStorage
,
4532 This
->ownerPropertyIndex
,
4535 return chainProperty
.size
;
4540 * this chain is a chain that does not have a property, figure out the
4541 * size by making the product number of used blocks times the
4544 ULARGE_INTEGER result
;
4545 result
.s
.HighPart
= 0;
4548 BlockChainStream_GetCount(This
) *
4549 This
->parentStorage
->bigBlockSize
;
4555 /******************************************************************************
4556 ** SmallBlockChainStream implementation
4559 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4560 StorageImpl
* parentStorage
,
4561 ULONG propertyIndex
)
4563 SmallBlockChainStream
* newStream
;
4565 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4567 newStream
->parentStorage
= parentStorage
;
4568 newStream
->ownerPropertyIndex
= propertyIndex
;
4573 void SmallBlockChainStream_Destroy(
4574 SmallBlockChainStream
* This
)
4576 HeapFree(GetProcessHeap(), 0, This
);
4579 /******************************************************************************
4580 * SmallBlockChainStream_GetHeadOfChain
4582 * Returns the head of this chain of small blocks.
4584 ULONG
SmallBlockChainStream_GetHeadOfChain(
4585 SmallBlockChainStream
* This
)
4587 StgProperty chainProperty
;
4588 BOOL readSuccessful
;
4590 if (This
->ownerPropertyIndex
)
4592 readSuccessful
= StorageImpl_ReadProperty(
4593 This
->parentStorage
,
4594 This
->ownerPropertyIndex
,
4599 return chainProperty
.startingBlock
;
4604 return BLOCK_END_OF_CHAIN
;
4607 /******************************************************************************
4608 * SmallBlockChainStream_GetNextBlockInChain
4610 * Returns the index of the next small block in this chain.
4613 * - BLOCK_END_OF_CHAIN: end of this chain
4614 * - BLOCK_UNUSED: small block 'blockIndex' is free
4616 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4617 SmallBlockChainStream
* This
,
4620 ULARGE_INTEGER offsetOfBlockInDepot
;
4622 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4626 offsetOfBlockInDepot
.s
.HighPart
= 0;
4627 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4630 * Read those bytes in the buffer from the small block file.
4632 success
= BlockChainStream_ReadAt(
4633 This
->parentStorage
->smallBlockDepotChain
,
4634 offsetOfBlockInDepot
,
4641 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4644 return nextBlockInChain
;
4647 /******************************************************************************
4648 * SmallBlockChainStream_SetNextBlockInChain
4650 * Writes the index of the next block of the specified block in the small
4652 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4653 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4655 void SmallBlockChainStream_SetNextBlockInChain(
4656 SmallBlockChainStream
* This
,
4660 ULARGE_INTEGER offsetOfBlockInDepot
;
4664 offsetOfBlockInDepot
.s
.HighPart
= 0;
4665 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4667 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4670 * Read those bytes in the buffer from the small block file.
4672 BlockChainStream_WriteAt(
4673 This
->parentStorage
->smallBlockDepotChain
,
4674 offsetOfBlockInDepot
,
4680 /******************************************************************************
4681 * SmallBlockChainStream_FreeBlock
4683 * Flag small block 'blockIndex' as free in the small block depot.
4685 void SmallBlockChainStream_FreeBlock(
4686 SmallBlockChainStream
* This
,
4689 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4692 /******************************************************************************
4693 * SmallBlockChainStream_GetNextFreeBlock
4695 * Returns the index of a free small block. The small block depot will be
4696 * enlarged if necessary. The small block chain will also be enlarged if
4699 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4700 SmallBlockChainStream
* This
)
4702 ULARGE_INTEGER offsetOfBlockInDepot
;
4705 ULONG blockIndex
= 0;
4706 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4707 BOOL success
= TRUE
;
4708 ULONG smallBlocksPerBigBlock
;
4710 offsetOfBlockInDepot
.s
.HighPart
= 0;
4713 * Scan the small block depot for a free block
4715 while (nextBlockIndex
!= BLOCK_UNUSED
)
4717 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4719 success
= BlockChainStream_ReadAt(
4720 This
->parentStorage
->smallBlockDepotChain
,
4721 offsetOfBlockInDepot
,
4727 * If we run out of space for the small block depot, enlarge it
4731 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4733 if (nextBlockIndex
!= BLOCK_UNUSED
)
4739 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4741 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4742 ULONG nextBlock
, newsbdIndex
;
4743 BYTE
* smallBlockDepot
;
4745 nextBlock
= sbdIndex
;
4746 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4748 sbdIndex
= nextBlock
;
4750 StorageImpl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4753 newsbdIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4754 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4755 StorageImpl_SetNextBlockInChain(
4756 This
->parentStorage
,
4760 StorageImpl_SetNextBlockInChain(
4761 This
->parentStorage
,
4763 BLOCK_END_OF_CHAIN
);
4766 * Initialize all the small blocks to free
4769 StorageImpl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4771 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4772 StorageImpl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4777 * We have just created the small block depot.
4779 StgProperty rootProp
;
4783 * Save it in the header
4785 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4786 StorageImpl_SaveFileHeader(This
->parentStorage
);
4789 * And allocate the first big block that will contain small blocks
4792 StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4794 StorageImpl_SetNextBlockInChain(
4795 This
->parentStorage
,
4797 BLOCK_END_OF_CHAIN
);
4799 StorageImpl_ReadProperty(
4800 This
->parentStorage
,
4801 This
->parentStorage
->rootPropertySetIndex
,
4804 rootProp
.startingBlock
= sbStartIndex
;
4805 rootProp
.size
.s
.HighPart
= 0;
4806 rootProp
.size
.s
.LowPart
= This
->parentStorage
->bigBlockSize
;
4808 StorageImpl_WriteProperty(
4809 This
->parentStorage
,
4810 This
->parentStorage
->rootPropertySetIndex
,
4816 smallBlocksPerBigBlock
=
4817 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4820 * Verify if we have to allocate big blocks to contain small blocks
4822 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4824 StgProperty rootProp
;
4825 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4827 StorageImpl_ReadProperty(
4828 This
->parentStorage
,
4829 This
->parentStorage
->rootPropertySetIndex
,
4832 if (rootProp
.size
.s
.LowPart
<
4833 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4835 rootProp
.size
.s
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4837 BlockChainStream_SetSize(
4838 This
->parentStorage
->smallBlockRootChain
,
4841 StorageImpl_WriteProperty(
4842 This
->parentStorage
,
4843 This
->parentStorage
->rootPropertySetIndex
,
4851 /******************************************************************************
4852 * SmallBlockChainStream_ReadAt
4854 * Reads a specified number of bytes from this chain at the specified offset.
4855 * bytesRead may be NULL.
4856 * Failure will be returned if the specified number of bytes has not been read.
4858 BOOL
SmallBlockChainStream_ReadAt(
4859 SmallBlockChainStream
* This
,
4860 ULARGE_INTEGER offset
,
4865 ULARGE_INTEGER offsetInBigBlockFile
;
4866 ULONG blockNoInSequence
=
4867 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4869 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
4870 ULONG bytesToReadInBuffer
;
4872 ULONG bytesReadFromBigBlockFile
;
4876 * This should never happen on a small block file.
4878 assert(offset
.s
.HighPart
==0);
4881 * Find the first block in the stream that contains part of the buffer.
4883 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4885 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4887 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4889 blockNoInSequence
--;
4893 * Start reading the buffer.
4896 bufferWalker
= buffer
;
4898 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4901 * Calculate how many bytes we can copy from this small block.
4903 bytesToReadInBuffer
=
4904 min(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4907 * Calculate the offset of the small block in the small block file.
4909 offsetInBigBlockFile
.s
.HighPart
= 0;
4910 offsetInBigBlockFile
.s
.LowPart
=
4911 blockIndex
* This
->parentStorage
->smallBlockSize
;
4913 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
4916 * Read those bytes in the buffer from the small block file.
4918 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4919 offsetInBigBlockFile
,
4920 bytesToReadInBuffer
,
4922 &bytesReadFromBigBlockFile
);
4924 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4927 * Step to the next big block.
4929 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4930 bufferWalker
+= bytesToReadInBuffer
;
4931 size
-= bytesToReadInBuffer
;
4932 *bytesRead
+= bytesToReadInBuffer
;
4933 offsetInBlock
= 0; /* There is no offset on the next block */
4939 /******************************************************************************
4940 * SmallBlockChainStream_WriteAt
4942 * Writes the specified number of bytes to this chain at the specified offset.
4943 * bytesWritten may be NULL.
4944 * Will fail if not all specified number of bytes have been written.
4946 BOOL
SmallBlockChainStream_WriteAt(
4947 SmallBlockChainStream
* This
,
4948 ULARGE_INTEGER offset
,
4951 ULONG
* bytesWritten
)
4953 ULARGE_INTEGER offsetInBigBlockFile
;
4954 ULONG blockNoInSequence
=
4955 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4957 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
4958 ULONG bytesToWriteInBuffer
;
4960 ULONG bytesWrittenFromBigBlockFile
;
4964 * This should never happen on a small block file.
4966 assert(offset
.s
.HighPart
==0);
4969 * Find the first block in the stream that contains part of the buffer.
4971 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4973 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4975 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4977 blockNoInSequence
--;
4981 * Start writing the buffer.
4983 * Here, I'm casting away the constness on the buffer variable
4984 * This is OK since we don't intend to modify that buffer.
4987 bufferWalker
= (BYTE
*)buffer
;
4988 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4991 * Calculate how many bytes we can copy to this small block.
4993 bytesToWriteInBuffer
=
4994 min(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4997 * Calculate the offset of the small block in the small block file.
4999 offsetInBigBlockFile
.s
.HighPart
= 0;
5000 offsetInBigBlockFile
.s
.LowPart
=
5001 blockIndex
* This
->parentStorage
->smallBlockSize
;
5003 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
5006 * Write those bytes in the buffer to the small block file.
5008 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
5009 offsetInBigBlockFile
,
5010 bytesToWriteInBuffer
,
5012 &bytesWrittenFromBigBlockFile
);
5014 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
5017 * Step to the next big block.
5019 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5020 bufferWalker
+= bytesToWriteInBuffer
;
5021 size
-= bytesToWriteInBuffer
;
5022 *bytesWritten
+= bytesToWriteInBuffer
;
5023 offsetInBlock
= 0; /* There is no offset on the next block */
5029 /******************************************************************************
5030 * SmallBlockChainStream_Shrink
5032 * Shrinks this chain in the small block depot.
5034 BOOL
SmallBlockChainStream_Shrink(
5035 SmallBlockChainStream
* This
,
5036 ULARGE_INTEGER newSize
)
5038 ULONG blockIndex
, extraBlock
;
5042 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5044 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5047 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5050 * Go to the new end of chain
5052 while (count
< numBlocks
)
5054 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5059 * If the count is 0, we have a special case, the head of the chain was
5064 StgProperty chainProp
;
5066 StorageImpl_ReadProperty(This
->parentStorage
,
5067 This
->ownerPropertyIndex
,
5070 chainProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
5072 StorageImpl_WriteProperty(This
->parentStorage
,
5073 This
->ownerPropertyIndex
,
5077 * We start freeing the chain at the head block.
5079 extraBlock
= blockIndex
;
5083 /* Get the next block before marking the new end */
5084 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5086 /* Mark the new end of chain */
5087 SmallBlockChainStream_SetNextBlockInChain(
5090 BLOCK_END_OF_CHAIN
);
5094 * Mark the extra blocks as free
5096 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
5098 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
5099 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
5100 extraBlock
= blockIndex
;
5106 /******************************************************************************
5107 * SmallBlockChainStream_Enlarge
5109 * Grows this chain in the small block depot.
5111 BOOL
SmallBlockChainStream_Enlarge(
5112 SmallBlockChainStream
* This
,
5113 ULARGE_INTEGER newSize
)
5115 ULONG blockIndex
, currentBlock
;
5117 ULONG oldNumBlocks
= 0;
5119 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5124 if (blockIndex
== BLOCK_END_OF_CHAIN
)
5127 StgProperty chainProp
;
5129 StorageImpl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5132 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
5134 StorageImpl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5137 blockIndex
= chainProp
.startingBlock
;
5138 SmallBlockChainStream_SetNextBlockInChain(
5141 BLOCK_END_OF_CHAIN
);
5144 currentBlock
= blockIndex
;
5147 * Figure out how many blocks are needed to contain this stream
5149 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5151 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5155 * Go to the current end of chain
5157 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5160 currentBlock
= blockIndex
;
5161 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
5165 * Add new blocks to the chain
5167 while (oldNumBlocks
< newNumBlocks
)
5169 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
5170 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
5172 SmallBlockChainStream_SetNextBlockInChain(
5175 BLOCK_END_OF_CHAIN
);
5177 currentBlock
= blockIndex
;
5184 /******************************************************************************
5185 * SmallBlockChainStream_GetCount
5187 * Returns the number of blocks that comprises this chain.
5188 * This is not the size of this chain as the last block may not be full!
5190 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
5195 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5197 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5201 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5207 /******************************************************************************
5208 * SmallBlockChainStream_SetSize
5210 * Sets the size of this stream.
5211 * The file will grow if we grow the chain.
5213 * TODO: Free the actual blocks in the file when we shrink the chain.
5214 * Currently, the blocks are still in the file. So the file size
5215 * doesn't shrink even if we shrink streams.
5217 BOOL
SmallBlockChainStream_SetSize(
5218 SmallBlockChainStream
* This
,
5219 ULARGE_INTEGER newSize
)
5221 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
5223 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
5226 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
5228 SmallBlockChainStream_Shrink(This
, newSize
);
5232 SmallBlockChainStream_Enlarge(This
, newSize
);
5238 /******************************************************************************
5239 * SmallBlockChainStream_GetSize
5241 * Returns the size of this chain.
5243 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
5245 StgProperty chainProperty
;
5247 StorageImpl_ReadProperty(
5248 This
->parentStorage
,
5249 This
->ownerPropertyIndex
,
5252 return chainProperty
.size
;
5255 /******************************************************************************
5256 * StgCreateDocfile [OLE32.144]
5258 HRESULT WINAPI
StgCreateDocfile(
5262 IStorage
**ppstgOpen
)
5264 StorageImpl
* newStorage
= 0;
5265 HANDLE hFile
= INVALID_HANDLE_VALUE
;
5270 DWORD fileAttributes
;
5271 WCHAR tempFileName
[MAX_PATH
];
5273 TRACE("(%s, %lx, %ld, %p)\n",
5274 debugstr_w(pwcsName
), grfMode
,
5275 reserved
, ppstgOpen
);
5278 * Validate the parameters
5281 return STG_E_INVALIDPOINTER
;
5284 * Validate the STGM flags
5286 if ( FAILED( validateSTGM(grfMode
) ))
5287 return STG_E_INVALIDFLAG
;
5290 * Generate a unique name.
5294 WCHAR tempPath
[MAX_PATH
];
5295 WCHAR prefix
[] = { 'S', 'T', 'O', 0 };
5297 memset(tempPath
, 0, sizeof(tempPath
));
5298 memset(tempFileName
, 0, sizeof(tempFileName
));
5300 if ((GetTempPathW(MAX_PATH
, tempPath
)) == 0 )
5303 if (GetTempFileNameW(tempPath
, prefix
, 0, tempFileName
) != 0)
5304 pwcsName
= tempFileName
;
5306 return STG_E_INSUFFICIENTMEMORY
;
5310 * Interpret the STGM value grfMode
5312 shareMode
= GetShareModeFromSTGM(grfMode
);
5313 accessMode
= GetAccessModeFromSTGM(grfMode
);
5314 creationMode
= GetCreationModeFromSTGM(grfMode
);
5316 if (grfMode
& STGM_DELETEONRELEASE
)
5317 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
5319 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
5321 if (grfMode
& STGM_TRANSACTED
)
5322 FIXME("Transacted mode not implemented.\n");
5325 * Initialize the "out" parameter.
5329 hFile
= CreateFileW(pwcsName
,
5337 if (hFile
== INVALID_HANDLE_VALUE
)
5343 * Allocate and initialize the new IStorage32object.
5345 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5347 if (newStorage
== 0)
5348 return STG_E_INSUFFICIENTMEMORY
;
5350 hr
= StorageImpl_Construct(
5360 HeapFree(GetProcessHeap(), 0, newStorage
);
5365 * Get an "out" pointer for the caller.
5367 hr
= StorageBaseImpl_QueryInterface(
5368 (IStorage
*)newStorage
,
5369 (REFIID
)&IID_IStorage
,
5375 /******************************************************************************
5376 * StgOpenStorage [OLE32.148]
5378 HRESULT WINAPI
StgOpenStorage(
5379 const OLECHAR
*pwcsName
,
5380 IStorage
*pstgPriority
,
5384 IStorage
**ppstgOpen
)
5386 StorageImpl
* newStorage
= 0;
5392 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5393 debugstr_w(pwcsName
), pstgPriority
, grfMode
,
5394 snbExclude
, reserved
, ppstgOpen
);
5397 * Perform a sanity check
5399 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
5400 return STG_E_INVALIDPOINTER
;
5403 * Validate the STGM flags
5405 if ( FAILED( validateSTGM(grfMode
) ))
5406 return STG_E_INVALIDFLAG
;
5409 * Interpret the STGM value grfMode
5411 shareMode
= GetShareModeFromSTGM(grfMode
);
5412 accessMode
= GetAccessModeFromSTGM(grfMode
);
5415 * Initialize the "out" parameter.
5419 hFile
= CreateFileW( pwcsName
,
5424 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5428 if (hFile
==INVALID_HANDLE_VALUE
)
5430 HRESULT hr
= E_FAIL
;
5431 DWORD last_error
= GetLastError();
5435 case ERROR_FILE_NOT_FOUND
:
5436 hr
= STG_E_FILENOTFOUND
;
5439 case ERROR_PATH_NOT_FOUND
:
5440 hr
= STG_E_PATHNOTFOUND
;
5443 case ERROR_ACCESS_DENIED
:
5444 case ERROR_WRITE_PROTECT
:
5445 hr
= STG_E_ACCESSDENIED
;
5448 case ERROR_SHARING_VIOLATION
:
5449 hr
= STG_E_SHAREVIOLATION
;
5460 * Allocate and initialize the new IStorage32object.
5462 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5464 if (newStorage
== 0)
5465 return STG_E_INSUFFICIENTMEMORY
;
5467 hr
= StorageImpl_Construct(
5477 HeapFree(GetProcessHeap(), 0, newStorage
);
5482 * Get an "out" pointer for the caller.
5484 hr
= StorageBaseImpl_QueryInterface(
5485 (IStorage
*)newStorage
,
5486 (REFIID
)&IID_IStorage
,
5492 /******************************************************************************
5493 * StgCreateDocfileOnILockBytes [OLE32.145]
5495 HRESULT WINAPI
StgCreateDocfileOnILockBytes(
5499 IStorage
** ppstgOpen
)
5501 StorageImpl
* newStorage
= 0;
5505 * Validate the parameters
5507 if ((ppstgOpen
== 0) || (plkbyt
== 0))
5508 return STG_E_INVALIDPOINTER
;
5511 * Allocate and initialize the new IStorage object.
5513 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5515 if (newStorage
== 0)
5516 return STG_E_INSUFFICIENTMEMORY
;
5518 hr
= StorageImpl_Construct(
5528 HeapFree(GetProcessHeap(), 0, newStorage
);
5533 * Get an "out" pointer for the caller.
5535 hr
= StorageBaseImpl_QueryInterface(
5536 (IStorage
*)newStorage
,
5537 (REFIID
)&IID_IStorage
,
5543 /******************************************************************************
5544 * StgOpenStorageOnILockBytes [OLE32.149]
5546 HRESULT WINAPI
StgOpenStorageOnILockBytes(
5548 IStorage
*pstgPriority
,
5552 IStorage
**ppstgOpen
)
5554 StorageImpl
* newStorage
= 0;
5558 * Perform a sanity check
5560 if ((plkbyt
== 0) || (ppstgOpen
== 0))
5561 return STG_E_INVALIDPOINTER
;
5564 * Validate the STGM flags
5566 if ( FAILED( validateSTGM(grfMode
) ))
5567 return STG_E_INVALIDFLAG
;
5570 * Initialize the "out" parameter.
5575 * Allocate and initialize the new IStorage object.
5577 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5579 if (newStorage
== 0)
5580 return STG_E_INSUFFICIENTMEMORY
;
5582 hr
= StorageImpl_Construct(
5592 HeapFree(GetProcessHeap(), 0, newStorage
);
5597 * Get an "out" pointer for the caller.
5599 hr
= StorageBaseImpl_QueryInterface(
5600 (IStorage
*)newStorage
,
5601 (REFIID
)&IID_IStorage
,
5607 /******************************************************************************
5608 * StgSetTimes [ole32.150]
5612 HRESULT WINAPI
StgSetTimes(WCHAR
* str
, FILETIME
* a
, FILETIME
* b
, FILETIME
*c
)
5615 FIXME("(%p, %p, %p, %p),stub!\n", str
, a
, b
, c
);
5619 /******************************************************************************
5620 * StgIsStorageILockBytes [OLE32.147]
5622 * Determines if the ILockBytes contains a storage object.
5624 HRESULT WINAPI
StgIsStorageILockBytes(ILockBytes
*plkbyt
)
5627 ULARGE_INTEGER offset
;
5629 offset
.s
.HighPart
= 0;
5630 offset
.s
.LowPart
= 0;
5632 ILockBytes_ReadAt(plkbyt
, offset
, sig
, sizeof(sig
), NULL
);
5634 if (memcmp(sig
, STORAGE_magic
, sizeof(STORAGE_magic
)) == 0)
5640 /******************************************************************************
5641 * WriteClassStg [OLE32.158]
5643 * This method will store the specified CLSID in the specified storage object
5645 HRESULT WINAPI
WriteClassStg(IStorage
* pStg
, REFCLSID rclsid
)
5651 hRes
= IStorage_SetClass(pStg
, rclsid
);
5656 /***********************************************************************
5659 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5661 HRESULT WINAPI
ReadClassStg(IStorage
*pstg
,CLSID
*pclsid
){
5671 * read a STATSTG structure (contains the clsid) from the storage
5673 hRes
=IStorage_Stat(pstg
,&pstatstg
,STATFLAG_DEFAULT
);
5676 *pclsid
=pstatstg
.clsid
;
5681 /***********************************************************************
5684 * This function loads an object from stream
5686 HRESULT WINAPI
OleLoadFromStream(IStream
*pStm
,REFIID iidInterface
,void** ppvObj
)
5691 FIXME("(),stub!\n");
5693 res
=ReadClassStm(pStm
,&clsid
);
5695 if (SUCCEEDED(res
)){
5697 res
=CoCreateInstance(&clsid
,NULL
,CLSCTX_INPROC_SERVER
,iidInterface
,ppvObj
);
5701 res
=IPersistStream_Load((IPersistStream
*)ppvObj
,pStm
);
5707 /***********************************************************************
5710 * This function saves an object with the IPersistStream interface on it
5711 * to the specified stream.
5713 HRESULT WINAPI
OleSaveToStream(IPersistStream
*pPStm
,IStream
*pStm
)
5719 TRACE("(%p,%p)\n",pPStm
,pStm
);
5721 res
=IPersistStream_GetClassID(pPStm
,&clsid
);
5723 if (SUCCEEDED(res
)){
5725 res
=WriteClassStm(pStm
,&clsid
);
5729 res
=IPersistStream_Save(pPStm
,pStm
,TRUE
);
5732 TRACE("Finished Save\n");
5736 /****************************************************************************
5737 * This method validate a STGM parameter that can contain the values below
5739 * STGM_DIRECT 0x00000000
5740 * STGM_TRANSACTED 0x00010000
5741 * STGM_SIMPLE 0x08000000
5743 * STGM_READ 0x00000000
5744 * STGM_WRITE 0x00000001
5745 * STGM_READWRITE 0x00000002
5747 * STGM_SHARE_DENY_NONE 0x00000040
5748 * STGM_SHARE_DENY_READ 0x00000030
5749 * STGM_SHARE_DENY_WRITE 0x00000020
5750 * STGM_SHARE_EXCLUSIVE 0x00000010
5752 * STGM_PRIORITY 0x00040000
5753 * STGM_DELETEONRELEASE 0x04000000
5755 * STGM_CREATE 0x00001000
5756 * STGM_CONVERT 0x00020000
5757 * STGM_FAILIFTHERE 0x00000000
5759 * STGM_NOSCRATCH 0x00100000
5760 * STGM_NOSNAPSHOT 0x00200000
5762 static HRESULT
validateSTGM(DWORD stgm
)
5764 BOOL bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5765 BOOL bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5766 BOOL bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5768 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5769 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5770 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5772 BOOL bSTGM_SHARE_DENY_NONE
=
5773 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5775 BOOL bSTGM_SHARE_DENY_READ
=
5776 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5778 BOOL bSTGM_SHARE_DENY_WRITE
=
5779 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5781 BOOL bSTGM_SHARE_EXCLUSIVE
=
5782 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5784 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5785 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5787 BOOL bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5788 BOOL bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5791 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5793 if ( ! bSTGM_DIRECT
)
5794 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5798 * STGM_WRITE | STGM_READWRITE | STGM_READ
5801 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5805 * STGM_SHARE_DENY_NONE | others
5806 * (I assume here that DENY_READ implies DENY_WRITE)
5808 if ( bSTGM_SHARE_DENY_NONE
)
5809 if ( bSTGM_SHARE_DENY_READ
||
5810 bSTGM_SHARE_DENY_WRITE
||
5811 bSTGM_SHARE_EXCLUSIVE
)
5815 * STGM_CREATE | STGM_CONVERT
5816 * if both are false, STGM_FAILIFTHERE is set to TRUE
5818 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5822 * STGM_NOSCRATCH requires STGM_TRANSACTED
5824 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5828 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5829 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5831 if (bSTGM_NOSNAPSHOT
)
5833 if ( ! ( bSTGM_TRANSACTED
&&
5834 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
5841 /****************************************************************************
5842 * GetShareModeFromSTGM
5844 * This method will return a share mode flag from a STGM value.
5845 * The STGM value is assumed valid.
5847 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
5849 DWORD dwShareMode
= 0;
5850 BOOL bSTGM_SHARE_DENY_NONE
=
5851 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5853 BOOL bSTGM_SHARE_DENY_READ
=
5854 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5856 BOOL bSTGM_SHARE_DENY_WRITE
=
5857 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5859 BOOL bSTGM_SHARE_EXCLUSIVE
=
5860 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5862 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
5865 if (bSTGM_SHARE_DENY_NONE
)
5866 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
5868 if (bSTGM_SHARE_DENY_WRITE
)
5869 dwShareMode
= FILE_SHARE_READ
;
5874 /****************************************************************************
5875 * GetAccessModeFromSTGM
5877 * This method will return an access mode flag from a STGM value.
5878 * The STGM value is assumed valid.
5880 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
5882 DWORD dwDesiredAccess
= GENERIC_READ
;
5883 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5884 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5885 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5888 dwDesiredAccess
= GENERIC_READ
;
5891 dwDesiredAccess
|= GENERIC_WRITE
;
5893 if (bSTGM_READWRITE
)
5894 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
5896 return dwDesiredAccess
;
5899 /****************************************************************************
5900 * GetCreationModeFromSTGM
5902 * This method will return a creation mode flag from a STGM value.
5903 * The STGM value is assumed valid.
5905 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
5907 if ( stgm
& STGM_CREATE
)
5908 return CREATE_ALWAYS
;
5909 if (stgm
& STGM_CONVERT
) {
5910 FIXME("STGM_CONVERT not implemented!\n");
5913 /* All other cases */
5914 if (stgm
& ~ (STGM_CREATE
|STGM_CONVERT
))
5915 FIXME("unhandled storage mode : 0x%08lx\n",stgm
& ~ (STGM_CREATE
|STGM_CONVERT
));
5920 /*************************************************************************
5921 * OLECONVERT_LoadOLE10 [Internal]
5923 * Loads the OLE10 STREAM to memory
5926 * pOleStream [I] The OLESTREAM
5927 * pData [I] Data Structure for the OLESTREAM Data
5931 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
5932 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
5935 * This function is used by OleConvertOLESTREAMToIStorage only.
5937 * Memory allocated for pData must be freed by the caller
5939 HRESULT
OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream
, OLECONVERT_OLESTREAM_DATA
*pData
, BOOL bStrem1
)
5942 HRESULT hRes
= S_OK
;
5946 pData
->pData
= NULL
;
5947 pData
->pstrOleObjFileName
= (CHAR
*) NULL
;
5949 for( nTryCnt
=0;nTryCnt
< max_try
; nTryCnt
++)
5952 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwOleID
), sizeof(pData
->dwOleID
));
5953 if(dwSize
!= sizeof(pData
->dwOleID
))
5955 hRes
= CONVERT10_E_OLESTREAM_GET
;
5957 else if(pData
->dwOleID
!= OLESTREAM_ID
)
5959 hRes
= CONVERT10_E_OLESTREAM_FMT
;
5970 /* Get the TypeID...more info needed for this field */
5971 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwTypeID
), sizeof(pData
->dwTypeID
));
5972 if(dwSize
!= sizeof(pData
->dwTypeID
))
5974 hRes
= CONVERT10_E_OLESTREAM_GET
;
5979 if(pData
->dwTypeID
!= 0)
5981 /* Get the lenght of the OleTypeName */
5982 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *) &(pData
->dwOleTypeNameLength
), sizeof(pData
->dwOleTypeNameLength
));
5983 if(dwSize
!= sizeof(pData
->dwOleTypeNameLength
))
5985 hRes
= CONVERT10_E_OLESTREAM_GET
;
5990 if(pData
->dwOleTypeNameLength
> 0)
5992 /* Get the OleTypeName */
5993 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)pData
->strOleTypeName
, pData
->dwOleTypeNameLength
);
5994 if(dwSize
!= pData
->dwOleTypeNameLength
)
5996 hRes
= CONVERT10_E_OLESTREAM_GET
;
6002 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwOleObjFileNameLength
), sizeof(pData
->dwOleObjFileNameLength
));
6003 if(dwSize
!= sizeof(pData
->dwOleObjFileNameLength
))
6005 hRes
= CONVERT10_E_OLESTREAM_GET
;
6009 if(pData
->dwOleObjFileNameLength
< 1) /* there is no file name exist */
6010 pData
->dwOleObjFileNameLength
= sizeof(pData
->dwOleObjFileNameLength
);
6011 pData
->pstrOleObjFileName
= (CHAR
*)malloc(pData
->dwOleObjFileNameLength
);
6012 if(pData
->pstrOleObjFileName
)
6014 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)(pData
->pstrOleObjFileName
),pData
->dwOleObjFileNameLength
);
6015 if(dwSize
!= pData
->dwOleObjFileNameLength
)
6017 hRes
= CONVERT10_E_OLESTREAM_GET
;
6021 hRes
= CONVERT10_E_OLESTREAM_GET
;
6026 /* Get the Width of the Metafile */
6027 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwMetaFileWidth
), sizeof(pData
->dwMetaFileWidth
));
6028 if(dwSize
!= sizeof(pData
->dwMetaFileWidth
))
6030 hRes
= CONVERT10_E_OLESTREAM_GET
;
6034 /* Get the Height of the Metafile */
6035 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwMetaFileHeight
), sizeof(pData
->dwMetaFileHeight
));
6036 if(dwSize
!= sizeof(pData
->dwMetaFileHeight
))
6038 hRes
= CONVERT10_E_OLESTREAM_GET
;
6044 /* Get the Lenght of the Data */
6045 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwDataLength
), sizeof(pData
->dwDataLength
));
6046 if(dwSize
!= sizeof(pData
->dwDataLength
))
6048 hRes
= CONVERT10_E_OLESTREAM_GET
;
6052 if(hRes
== S_OK
) /* I don't know what is this 8 byts information is we have to figure out */
6054 if(!bStrem1
) /* if it is a second OLE stream data */
6056 pData
->dwDataLength
-= 8;
6057 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)(pData
->strUnknown
), sizeof(pData
->strUnknown
));
6058 if(dwSize
!= sizeof(pData
->strUnknown
))
6060 hRes
= CONVERT10_E_OLESTREAM_GET
;
6066 if(pData
->dwDataLength
> 0)
6068 pData
->pData
= (BYTE
*)HeapAlloc(GetProcessHeap(),0,pData
->dwDataLength
);
6070 /* Get Data (ex. IStorage, Metafile, or BMP) */
6073 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)pData
->pData
, pData
->dwDataLength
);
6074 if(dwSize
!= pData
->dwDataLength
)
6076 hRes
= CONVERT10_E_OLESTREAM_GET
;
6081 hRes
= CONVERT10_E_OLESTREAM_GET
;
6090 /*************************************************************************
6091 * OLECONVERT_SaveOLE10 [Internal]
6093 * Saves the OLE10 STREAM From memory
6096 * pData [I] Data Structure for the OLESTREAM Data
6097 * pOleStream [I] The OLESTREAM to save
6101 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6104 * This function is used by OleConvertIStorageToOLESTREAM only.
6107 HRESULT
OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA
*pData
, LPOLESTREAM pOleStream
)
6110 HRESULT hRes
= S_OK
;
6114 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwOleID
), sizeof(pData
->dwOleID
));
6115 if(dwSize
!= sizeof(pData
->dwOleID
))
6117 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6122 /* Set the TypeID */
6123 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwTypeID
), sizeof(pData
->dwTypeID
));
6124 if(dwSize
!= sizeof(pData
->dwTypeID
))
6126 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6130 if(pData
->dwOleID
== OLESTREAM_ID
&& pData
->dwTypeID
!= 0 && hRes
== S_OK
)
6132 /* Set the Lenght of the OleTypeName */
6133 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwOleTypeNameLength
), sizeof(pData
->dwOleTypeNameLength
));
6134 if(dwSize
!= sizeof(pData
->dwOleTypeNameLength
))
6136 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6141 if(pData
->dwOleTypeNameLength
> 0)
6143 /* Set the OleTypeName */
6144 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *) pData
->strOleTypeName
, pData
->dwOleTypeNameLength
);
6145 if(dwSize
!= pData
->dwOleTypeNameLength
)
6147 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6154 /* Set the width of the Metafile */
6155 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwMetaFileWidth
), sizeof(pData
->dwMetaFileWidth
));
6156 if(dwSize
!= sizeof(pData
->dwMetaFileWidth
))
6158 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6164 /* Set the height of the Metafile */
6165 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwMetaFileHeight
), sizeof(pData
->dwMetaFileHeight
));
6166 if(dwSize
!= sizeof(pData
->dwMetaFileHeight
))
6168 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6174 /* Set the lenght of the Data */
6175 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwDataLength
), sizeof(pData
->dwDataLength
));
6176 if(dwSize
!= sizeof(pData
->dwDataLength
))
6178 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6184 if(pData
->dwDataLength
> 0)
6186 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6187 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *) pData
->pData
, pData
->dwDataLength
);
6188 if(dwSize
!= pData
->dwDataLength
)
6190 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6198 /*************************************************************************
6199 * OLECONVERT_GetOLE20FromOLE10[Internal]
6201 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6202 * opens it, and copies the content to the dest IStorage for
6203 * OleConvertOLESTREAMToIStorage
6207 * pDestStorage [I] The IStorage to copy the data to
6208 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
6209 * nBufferLength [I] The size of the buffer
6218 void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage
, BYTE
*pBuffer
, DWORD nBufferLength
)
6222 IStorage
*pTempStorage
;
6223 DWORD dwNumOfBytesWritten
;
6224 WCHAR wstrTempDir
[MAX_PATH
], wstrTempFile
[MAX_PATH
];
6225 WCHAR wstrPrefix
[] = {'s', 'i', 's', 0};
6227 /* Create a temp File */
6228 GetTempPathW(MAX_PATH
, wstrTempDir
);
6229 GetTempFileNameW(wstrTempDir
, wstrPrefix
, 0, wstrTempFile
);
6230 hFile
= CreateFileW(wstrTempFile
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
6232 if(hFile
!= INVALID_HANDLE_VALUE
)
6234 /* Write IStorage Data to File */
6235 WriteFile(hFile
, pBuffer
, nBufferLength
, &dwNumOfBytesWritten
, NULL
);
6238 /* Open and copy temp storage to the Dest Storage */
6239 hRes
= StgOpenStorage(wstrTempFile
, NULL
, STGM_READ
, NULL
, 0, &pTempStorage
);
6242 hRes
= StorageImpl_CopyTo(pTempStorage
, 0, NULL
, NULL
, pDestStorage
);
6243 StorageBaseImpl_Release(pTempStorage
);
6245 DeleteFileW(wstrTempFile
);
6250 /*************************************************************************
6251 * OLECONVERT_WriteOLE20ToBuffer [Internal]
6253 * Saves the OLE10 STREAM From memory
6256 * pStorage [I] The Src IStorage to copy
6257 * pData [I] The Dest Memory to write to.
6260 * The size in bytes allocated for pData
6263 * Memory allocated for pData must be freed by the caller
6265 * Used by OleConvertIStorageToOLESTREAM only.
6268 DWORD
OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage
, BYTE
**pData
)
6272 DWORD nDataLength
= 0;
6273 IStorage
*pTempStorage
;
6274 WCHAR wstrTempDir
[MAX_PATH
], wstrTempFile
[MAX_PATH
];
6275 WCHAR wstrPrefix
[] = {'s', 'i', 's', 0};
6279 /* Create temp Storage */
6280 GetTempPathW(MAX_PATH
, wstrTempDir
);
6281 GetTempFileNameW(wstrTempDir
, wstrPrefix
, 0, wstrTempFile
);
6282 hRes
= StgCreateDocfile(wstrTempFile
, STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
, 0, &pTempStorage
);
6286 /* Copy Src Storage to the Temp Storage */
6287 StorageImpl_CopyTo(pStorage
, 0, NULL
, NULL
, pTempStorage
);
6288 StorageBaseImpl_Release(pTempStorage
);
6290 /* Open Temp Storage as a file and copy to memory */
6291 hFile
= CreateFileW(wstrTempFile
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
6292 if(hFile
!= INVALID_HANDLE_VALUE
)
6294 nDataLength
= GetFileSize(hFile
, NULL
);
6295 *pData
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,nDataLength
);
6296 ReadFile(hFile
, *pData
, nDataLength
, &nDataLength
, 0);
6299 DeleteFileW(wstrTempFile
);
6304 /*************************************************************************
6305 * OLECONVERT_CreateOleStream [Internal]
6307 * Creates the "\001OLE" stream in the IStorage if neccessary.
6310 * pStorage [I] Dest storage to create the stream in
6316 * This function is used by OleConvertOLESTREAMToIStorage only.
6318 * This stream is still unknown, MS Word seems to have extra data
6319 * but since the data is stored in the OLESTREAM there should be
6320 * no need to recreate the stream. If the stream is manually
6321 * deleted it will create it with this default data.
6324 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage
)
6328 WCHAR wstrStreamName
[] = {1,'O', 'l', 'e', 0};
6329 BYTE pOleStreamHeader
[] =
6331 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6333 0x00, 0x00, 0x00, 0x00
6336 /* Create stream if not present */
6337 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6338 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6342 /* Write default Data */
6343 hRes
= IStream_Write(pStream
, pOleStreamHeader
, sizeof(pOleStreamHeader
), NULL
);
6344 IStream_Release(pStream
);
6349 /*************************************************************************
6350 * OLECONVERT_CreateCompObjStream [Internal]
6352 * Creates a "\001CompObj" is the destination IStorage if necessary.
6355 * pStorage [I] The dest IStorage to create the CompObj Stream
6357 * strOleTypeName [I] The ProgID
6361 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6364 * This function is used by OleConvertOLESTREAMToIStorage only.
6366 * The stream data is stored in the OLESTREAM and there should be
6367 * no need to recreate the stream. If the stream is manually
6368 * deleted it will attempt to create it by querying the registry.
6372 HRESULT
OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage
, LPCSTR strOleTypeName
)
6375 HRESULT hStorageRes
, hRes
= S_OK
;
6376 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj
;
6377 WCHAR wstrStreamName
[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6379 BYTE pCompObjUnknown1
[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
6380 BYTE pCompObjUnknown2
[] = {0xF4, 0x39, 0xB2, 0x71};
6382 /* Initialize the CompObj structure */
6383 memset(&IStorageCompObj
, 0, sizeof(IStorageCompObj
));
6384 memcpy(&(IStorageCompObj
.byUnknown1
), pCompObjUnknown1
, sizeof(pCompObjUnknown1
));
6385 memcpy(&(IStorageCompObj
.byUnknown2
), pCompObjUnknown2
, sizeof(pCompObjUnknown2
));
6388 /* Create a CompObj stream if it doesn't exist */
6389 hStorageRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6390 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6391 if(hStorageRes
== S_OK
)
6393 /* copy the OleTypeName to the compobj struct */
6394 IStorageCompObj
.dwOleTypeNameLength
= strlen(strOleTypeName
)+1;
6395 strcpy(IStorageCompObj
.strOleTypeName
, strOleTypeName
);
6397 /* copy the OleTypeName to the compobj struct */
6398 /* Note: in the test made, these where Identical */
6399 IStorageCompObj
.dwProgIDNameLength
= strlen(strOleTypeName
)+1;
6400 strcpy(IStorageCompObj
.strProgIDName
, strOleTypeName
);
6403 hRes
= CLSIDFromProgID16(IStorageCompObj
.strProgIDName
, &(IStorageCompObj
.clsid
));
6409 /* Get the CLSID Default Name from the Registry */
6410 hErr
= RegOpenKeyA(HKEY_CLASSES_ROOT
, IStorageCompObj
.strProgIDName
, &hKey
);
6411 if(hErr
== ERROR_SUCCESS
)
6413 char strTemp
[OLESTREAM_MAX_STR_LEN
];
6414 IStorageCompObj
.dwCLSIDNameLength
= OLESTREAM_MAX_STR_LEN
;
6415 hErr
= RegQueryValueA(hKey
, NULL
, strTemp
, &(IStorageCompObj
.dwCLSIDNameLength
));
6416 if(hErr
== ERROR_SUCCESS
)
6418 strcpy(IStorageCompObj
.strCLSIDName
, strTemp
);
6424 /* Write CompObj Structure to stream */
6425 hRes
= IStream_Write(pStream
, IStorageCompObj
.byUnknown1
, sizeof(IStorageCompObj
.byUnknown1
), NULL
);
6427 WriteClassStm(pStream
,&(IStorageCompObj
.clsid
));
6429 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwCLSIDNameLength
), sizeof(IStorageCompObj
.dwCLSIDNameLength
), NULL
);
6430 if(IStorageCompObj
.dwCLSIDNameLength
> 0)
6432 hRes
= IStream_Write(pStream
, IStorageCompObj
.strCLSIDName
, IStorageCompObj
.dwCLSIDNameLength
, NULL
);
6434 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwOleTypeNameLength
) , sizeof(IStorageCompObj
.dwOleTypeNameLength
), NULL
);
6435 if(IStorageCompObj
.dwOleTypeNameLength
> 0)
6437 hRes
= IStream_Write(pStream
, IStorageCompObj
.strOleTypeName
, IStorageCompObj
.dwOleTypeNameLength
, NULL
);
6439 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwProgIDNameLength
) , sizeof(IStorageCompObj
.dwProgIDNameLength
), NULL
);
6440 if(IStorageCompObj
.dwProgIDNameLength
> 0)
6442 hRes
= IStream_Write(pStream
, IStorageCompObj
.strProgIDName
, IStorageCompObj
.dwProgIDNameLength
, NULL
);
6444 hRes
= IStream_Write(pStream
, IStorageCompObj
.byUnknown2
, sizeof(IStorageCompObj
.byUnknown2
), NULL
);
6445 IStream_Release(pStream
);
6451 /*************************************************************************
6452 * OLECONVERT_CreateOlePresStream[Internal]
6454 * Creates the "\002OlePres000" Stream with the Metafile data
6457 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
6458 * dwExtentX [I] Width of the Metafile
6459 * dwExtentY [I] Height of the Metafile
6460 * pData [I] Metafile data
6461 * dwDataLength [I] Size of the Metafile data
6465 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6468 * This function is used by OleConvertOLESTREAMToIStorage only.
6471 void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage
, DWORD dwExtentX
, DWORD dwExtentY
, BYTE
*pData
, DWORD dwDataLength
)
6475 WCHAR wstrStreamName
[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6476 BYTE pOlePresStreamHeader
[] =
6478 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
6479 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6480 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6481 0x00, 0x00, 0x00, 0x00
6484 BYTE pOlePresStreamHeaderEmpty
[] =
6486 0x00, 0x00, 0x00, 0x00,
6487 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6488 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6489 0x00, 0x00, 0x00, 0x00
6492 /* Create the OlePres000 Stream */
6493 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6494 STGM_CREATE
| STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6499 OLECONVERT_ISTORAGE_OLEPRES OlePres
;
6501 memset(&OlePres
, 0, sizeof(OlePres
));
6502 /* Do we have any metafile data to save */
6503 if(dwDataLength
> 0)
6505 memcpy(OlePres
.byUnknown1
, pOlePresStreamHeader
, sizeof(pOlePresStreamHeader
));
6506 nHeaderSize
= sizeof(pOlePresStreamHeader
);
6510 memcpy(OlePres
.byUnknown1
, pOlePresStreamHeaderEmpty
, sizeof(pOlePresStreamHeaderEmpty
));
6511 nHeaderSize
= sizeof(pOlePresStreamHeaderEmpty
);
6513 /* Set width and height of the metafile */
6514 OlePres
.dwExtentX
= dwExtentX
;
6515 OlePres
.dwExtentY
= -dwExtentY
;
6517 /* Set Data and Lenght */
6518 if(dwDataLength
> sizeof(METAFILEPICT16
))
6520 OlePres
.dwSize
= dwDataLength
- sizeof(METAFILEPICT16
);
6521 OlePres
.pData
= &(pData
[8]);
6523 /* Save OlePres000 Data to Stream */
6524 hRes
= IStream_Write(pStream
, OlePres
.byUnknown1
, nHeaderSize
, NULL
);
6525 hRes
= IStream_Write(pStream
, &(OlePres
.dwExtentX
), sizeof(OlePres
.dwExtentX
), NULL
);
6526 hRes
= IStream_Write(pStream
, &(OlePres
.dwExtentY
), sizeof(OlePres
.dwExtentY
), NULL
);
6527 hRes
= IStream_Write(pStream
, &(OlePres
.dwSize
), sizeof(OlePres
.dwSize
), NULL
);
6528 if(OlePres
.dwSize
> 0)
6530 hRes
= IStream_Write(pStream
, OlePres
.pData
, OlePres
.dwSize
, NULL
);
6532 IStream_Release(pStream
);
6536 /*************************************************************************
6537 * OLECONVERT_CreateOle10NativeStream [Internal]
6539 * Creates the "\001Ole10Native" Stream (should contain a BMP)
6542 * pStorage [I] Dest storage to create the stream in
6543 * pData [I] Ole10 Native Data (ex. bmp)
6544 * dwDataLength [I] Size of the Ole10 Native Data
6550 * This function is used by OleConvertOLESTREAMToIStorage only.
6552 * Might need to verify the data and return appropriate error message
6555 void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage
, BYTE
*pData
, DWORD dwDataLength
)
6559 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6561 /* Create the Ole10Native Stream */
6562 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6563 STGM_CREATE
| STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6567 /* Write info to stream */
6568 hRes
= IStream_Write(pStream
, &dwDataLength
, sizeof(dwDataLength
), NULL
);
6569 hRes
= IStream_Write(pStream
, pData
, dwDataLength
, NULL
);
6570 IStream_Release(pStream
);
6575 /*************************************************************************
6576 * OLECONVERT_GetOLE10ProgID [Internal]
6578 * Finds the ProgID (or OleTypeID) from the IStorage
6581 * pStorage [I] The Src IStorage to get the ProgID
6582 * strProgID [I] the ProgID string to get
6583 * dwSize [I] the size of the string
6587 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6590 * This function is used by OleConvertIStorageToOLESTREAM only.
6594 HRESULT
OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage
, char *strProgID
, DWORD
*dwSize
)
6598 LARGE_INTEGER iSeekPos
;
6599 OLECONVERT_ISTORAGE_COMPOBJ CompObj
;
6600 WCHAR wstrStreamName
[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6602 /* Open the CompObj Stream */
6603 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6604 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6608 /*Get the OleType from the CompObj Stream */
6609 iSeekPos
.s
.LowPart
= sizeof(CompObj
.byUnknown1
) + sizeof(CompObj
.clsid
);
6610 iSeekPos
.s
.HighPart
= 0;
6612 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_SET
, NULL
);
6613 IStream_Read(pStream
, &CompObj
.dwCLSIDNameLength
, sizeof(CompObj
.dwCLSIDNameLength
), NULL
);
6614 iSeekPos
.s
.LowPart
= CompObj
.dwCLSIDNameLength
;
6615 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_CUR
, NULL
);
6616 IStream_Read(pStream
, &CompObj
.dwOleTypeNameLength
, sizeof(CompObj
.dwOleTypeNameLength
), NULL
);
6617 iSeekPos
.s
.LowPart
= CompObj
.dwOleTypeNameLength
;
6618 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_CUR
, NULL
);
6620 IStream_Read(pStream
, dwSize
, sizeof(*dwSize
), NULL
);
6623 IStream_Read(pStream
, strProgID
, *dwSize
, NULL
);
6625 IStream_Release(pStream
);
6630 LPOLESTR wstrProgID
;
6632 /* Get the OleType from the registry */
6633 REFCLSID clsid
= &(stat
.clsid
);
6634 IStorage_Stat(pStorage
, &stat
, STATFLAG_NONAME
);
6635 hRes
= ProgIDFromCLSID(clsid
, &wstrProgID
);
6638 *dwSize
= WideCharToMultiByte(CP_ACP
, 0, wstrProgID
, -1, strProgID
, *dwSize
, NULL
, FALSE
);
6645 /*************************************************************************
6646 * OLECONVERT_GetOle10PresData [Internal]
6648 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
6651 * pStorage [I] Src IStroage
6652 * pOleStream [I] Dest OleStream Mem Struct
6658 * This function is used by OleConvertIStorageToOLESTREAM only.
6660 * Memory allocated for pData must be freed by the caller
6664 void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage
, OLECONVERT_OLESTREAM_DATA
*pOleStreamData
)
6669 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6671 /* Initialize Default data for OLESTREAM */
6672 pOleStreamData
[0].dwOleID
= OLESTREAM_ID
;
6673 pOleStreamData
[0].dwTypeID
= 2;
6674 pOleStreamData
[1].dwOleID
= OLESTREAM_ID
;
6675 pOleStreamData
[1].dwTypeID
= 0;
6676 pOleStreamData
[0].dwMetaFileWidth
= 0;
6677 pOleStreamData
[0].dwMetaFileHeight
= 0;
6678 pOleStreamData
[0].pData
= NULL
;
6679 pOleStreamData
[1].pData
= NULL
;
6681 /* Open Ole10Native Stream */
6682 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6683 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6687 /* Read Size and Data */
6688 IStream_Read(pStream
, &(pOleStreamData
->dwDataLength
), sizeof(pOleStreamData
->dwDataLength
), NULL
);
6689 if(pOleStreamData
->dwDataLength
> 0)
6691 pOleStreamData
->pData
= (LPSTR
) HeapAlloc(GetProcessHeap(),0,pOleStreamData
->dwDataLength
);
6692 IStream_Read(pStream
, pOleStreamData
->pData
, pOleStreamData
->dwDataLength
, NULL
);
6694 IStream_Release(pStream
);
6700 /*************************************************************************
6701 * OLECONVERT_GetOle20PresData[Internal]
6703 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
6706 * pStorage [I] Src IStroage
6707 * pOleStreamData [I] Dest OleStream Mem Struct
6713 * This function is used by OleConvertIStorageToOLESTREAM only.
6715 * Memory allocated for pData must be freed by the caller
6717 void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage
, OLECONVERT_OLESTREAM_DATA
*pOleStreamData
)
6721 OLECONVERT_ISTORAGE_OLEPRES olePress
;
6722 WCHAR wstrStreamName
[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6724 /* Initialize Default data for OLESTREAM */
6725 pOleStreamData
[0].dwOleID
= OLESTREAM_ID
;
6726 pOleStreamData
[0].dwTypeID
= 2;
6727 pOleStreamData
[0].dwMetaFileWidth
= 0;
6728 pOleStreamData
[0].dwMetaFileHeight
= 0;
6729 pOleStreamData
[0].dwDataLength
= OLECONVERT_WriteOLE20ToBuffer(pStorage
, &(pOleStreamData
[0].pData
));
6730 pOleStreamData
[1].dwOleID
= OLESTREAM_ID
;
6731 pOleStreamData
[1].dwTypeID
= 0;
6732 pOleStreamData
[1].dwOleTypeNameLength
= 0;
6733 pOleStreamData
[1].strOleTypeName
[0] = 0;
6734 pOleStreamData
[1].dwMetaFileWidth
= 0;
6735 pOleStreamData
[1].dwMetaFileHeight
= 0;
6736 pOleStreamData
[1].pData
= NULL
;
6737 pOleStreamData
[1].dwDataLength
= 0;
6740 /* Open OlePress000 stream */
6741 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6742 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6745 LARGE_INTEGER iSeekPos
;
6746 METAFILEPICT16 MetaFilePict
;
6747 char strMetafilePictName
[] = "METAFILEPICT";
6749 /* Set the TypeID for a Metafile */
6750 pOleStreamData
[1].dwTypeID
= 5;
6752 /* Set the OleTypeName to Metafile */
6753 pOleStreamData
[1].dwOleTypeNameLength
= strlen(strMetafilePictName
) +1;
6754 strcpy(pOleStreamData
[1].strOleTypeName
, strMetafilePictName
);
6756 iSeekPos
.s
.HighPart
= 0;
6757 iSeekPos
.s
.LowPart
= sizeof(olePress
.byUnknown1
);
6759 /* Get Presentation Data */
6760 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_SET
, NULL
);
6761 IStream_Read(pStream
, &(olePress
.dwExtentX
), sizeof(olePress
.dwExtentX
), NULL
);
6762 IStream_Read(pStream
, &(olePress
.dwExtentY
), sizeof(olePress
.dwExtentY
), NULL
);
6763 IStream_Read(pStream
, &(olePress
.dwSize
), sizeof(olePress
.dwSize
), NULL
);
6765 /*Set width and Height */
6766 pOleStreamData
[1].dwMetaFileWidth
= olePress
.dwExtentX
;
6767 pOleStreamData
[1].dwMetaFileHeight
= -olePress
.dwExtentY
;
6768 if(olePress
.dwSize
> 0)
6771 pOleStreamData
[1].dwDataLength
= olePress
.dwSize
+ sizeof(METAFILEPICT16
);
6773 /* Set MetaFilePict struct */
6774 MetaFilePict
.mm
= 8;
6775 MetaFilePict
.xExt
= olePress
.dwExtentX
;
6776 MetaFilePict
.yExt
= olePress
.dwExtentY
;
6777 MetaFilePict
.hMF
= 0;
6779 /* Get Metafile Data */
6780 pOleStreamData
[1].pData
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,pOleStreamData
[1].dwDataLength
);
6781 memcpy(pOleStreamData
[1].pData
, &MetaFilePict
, sizeof(MetaFilePict
));
6782 IStream_Read(pStream
, &(pOleStreamData
[1].pData
[sizeof(MetaFilePict
)]), pOleStreamData
[1].dwDataLength
-sizeof(METAFILEPICT16
), NULL
);
6784 IStream_Release(pStream
);
6788 /*************************************************************************
6789 * OleConvertOLESTREAMToIStorage [OLE32.87]
6794 * DVTARGETDEVICE paramenter is not handled
6795 * Still unsure of some mem fields for OLE 10 Stream
6796 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6797 * and "\001OLE" streams
6800 HRESULT WINAPI
OleConvertOLESTREAMToIStorage (
6801 LPOLESTREAM pOleStream
,
6803 const DVTARGETDEVICE
* ptd
)
6807 OLECONVERT_OLESTREAM_DATA pOleStreamData
[2];
6809 memset(pOleStreamData
, 0, sizeof(pOleStreamData
));
6813 FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
6816 if(pstg
== NULL
|| pOleStream
== NULL
)
6818 hRes
= E_INVALIDARG
;
6823 /* Load the OLESTREAM to Memory */
6824 hRes
= OLECONVERT_LoadOLE10(pOleStream
, &pOleStreamData
[0], TRUE
);
6829 /* Load the OLESTREAM to Memory (part 2)*/
6830 hRes
= OLECONVERT_LoadOLE10(pOleStream
, &pOleStreamData
[1], FALSE
);
6836 if(pOleStreamData
[0].dwDataLength
> sizeof(STORAGE_magic
))
6838 /* Do we have the IStorage Data in the OLESTREAM */
6839 if(memcmp(pOleStreamData
[0].pData
, STORAGE_magic
, sizeof(STORAGE_magic
)) ==0)
6841 OLECONVERT_GetOLE20FromOLE10(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
6842 OLECONVERT_CreateOlePresStream(pstg
, pOleStreamData
[1].dwMetaFileWidth
, pOleStreamData
[1].dwMetaFileHeight
, pOleStreamData
[1].pData
, pOleStreamData
[1].dwDataLength
);
6846 /* It must be an original OLE 1.0 source */
6847 OLECONVERT_CreateOle10NativeStream(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
6852 /* It must be an original OLE 1.0 source */
6853 OLECONVERT_CreateOle10NativeStream(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
6856 /* Create CompObj Stream if necessary */
6857 hRes
= OLECONVERT_CreateCompObjStream(pstg
, pOleStreamData
[0].strOleTypeName
);
6860 /*Create the Ole Stream if necessary */
6861 OLECONVERT_CreateOleStream(pstg
);
6866 /* Free allocated memory */
6867 for(i
=0; i
< 2; i
++)
6869 if(pOleStreamData
[i
].pData
!= NULL
)
6871 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pData
);
6873 if(pOleStreamData
[i
].pstrOleObjFileName
!= NULL
)
6875 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pstrOleObjFileName
);
6876 pOleStreamData
[i
].pstrOleObjFileName
= NULL
;
6882 /*************************************************************************
6883 * OleConvertIStorageToOLESTREAM [OLE32.85]
6890 * Still unsure of some mem fields for OLE 10 Stream
6891 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6892 * and "\001OLE" streams.
6895 HRESULT WINAPI
OleConvertIStorageToOLESTREAM (
6897 LPOLESTREAM pOleStream
)
6900 HRESULT hRes
= S_OK
;
6902 OLECONVERT_OLESTREAM_DATA pOleStreamData
[2];
6903 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6906 memset(pOleStreamData
, 0, sizeof(pOleStreamData
));
6908 if(pstg
== NULL
|| pOleStream
== NULL
)
6910 hRes
= E_INVALIDARG
;
6914 /* Get the ProgID */
6915 pOleStreamData
[0].dwOleTypeNameLength
= OLESTREAM_MAX_STR_LEN
;
6916 hRes
= OLECONVERT_GetOLE10ProgID(pstg
, pOleStreamData
[0].strOleTypeName
, &(pOleStreamData
[0].dwOleTypeNameLength
));
6920 /*Was it originaly Ole10 */
6921 hRes
= IStorage_OpenStream(pstg
, wstrStreamName
, 0, STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6924 IStream_Release(pStream
);
6925 /*Get Presentation Data for Ole10Native */
6926 OLECONVERT_GetOle10PresData(pstg
, pOleStreamData
);
6930 /*Get Presentation Data (OLE20)*/
6931 OLECONVERT_GetOle20PresData(pstg
, pOleStreamData
);
6934 /* Save OLESTREAM */
6935 hRes
= OLECONVERT_SaveOLE10(&(pOleStreamData
[0]), pOleStream
);
6938 hRes
= OLECONVERT_SaveOLE10(&(pOleStreamData
[1]), pOleStream
);
6943 /* Free allocated memory */
6944 for(i
=0; i
< 2; i
++)
6946 if(pOleStreamData
[i
].pData
!= NULL
)
6948 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pData
);