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 /************************************************************************
1683 * StorageImpl_Stat (IStorage)
1685 * This method will retrieve information about this storage object.
1687 * See Windows documentation for more details on IStorage methods.
1689 HRESULT WINAPI
StorageImpl_Stat( IStorage
* iface
,
1690 STATSTG
* pstatstg
, /* [out] */
1691 DWORD grfStatFlag
) /* [in] */
1693 StorageImpl
* const This
= (StorageImpl
*)iface
;
1694 HRESULT result
= StorageBaseImpl_Stat( iface
, pstatstg
, grfStatFlag
);
1696 if ( !FAILED(result
) && ((grfStatFlag
& STATFLAG_NONAME
) == 0) && This
->pwcsName
)
1698 CoTaskMemFree(pstatstg
->pwcsName
);
1699 pstatstg
->pwcsName
= CoTaskMemAlloc((lstrlenW(This
->pwcsName
)+1)*sizeof(WCHAR
));
1700 strcpyW(pstatstg
->pwcsName
, This
->pwcsName
);
1708 /*********************************************************************
1712 * Perform the deletion of a complete storage node
1715 static HRESULT
deleteStorageProperty(
1716 StorageImpl
*parentStorage
,
1717 ULONG indexOfPropertyToDelete
,
1718 StgProperty propertyToDelete
)
1720 IEnumSTATSTG
*elements
= 0;
1721 IStorage
*childStorage
= 0;
1722 STATSTG currentElement
;
1724 HRESULT destroyHr
= S_OK
;
1727 * Open the storage and enumerate it
1729 hr
= StorageBaseImpl_OpenStorage(
1730 (IStorage
*)parentStorage
,
1731 propertyToDelete
.name
,
1733 STGM_SHARE_EXCLUSIVE
,
1744 * Enumerate the elements
1746 IStorage_EnumElements( childStorage
, 0, 0, 0, &elements
);
1751 * Obtain the next element
1753 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1756 destroyHr
= StorageImpl_DestroyElement(
1757 (IStorage
*)childStorage
,
1758 (OLECHAR
*)currentElement
.pwcsName
);
1760 CoTaskMemFree(currentElement
.pwcsName
);
1764 * We need to Reset the enumeration every time because we delete elements
1765 * and the enumeration could be invalid
1767 IEnumSTATSTG_Reset(elements
);
1769 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1772 * Invalidate the property by zeroing it's name member.
1774 propertyToDelete
.sizeOfNameString
= 0;
1776 StorageImpl_WriteProperty(parentStorage
->ancestorStorage
,
1777 indexOfPropertyToDelete
,
1780 IStorage_Release(childStorage
);
1781 IEnumSTATSTG_Release(elements
);
1786 /*********************************************************************
1790 * Perform the deletion of a stream node
1793 static HRESULT
deleteStreamProperty(
1794 StorageImpl
*parentStorage
,
1795 ULONG indexOfPropertyToDelete
,
1796 StgProperty propertyToDelete
)
1800 ULARGE_INTEGER size
;
1802 size
.s
.HighPart
= 0;
1805 hr
= StorageBaseImpl_OpenStream(
1806 (IStorage
*)parentStorage
,
1807 (OLECHAR
*)propertyToDelete
.name
,
1809 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
,
1821 hr
= IStream_SetSize(pis
, size
);
1829 * Release the stream object.
1831 IStream_Release(pis
);
1834 * Invalidate the property by zeroing it's name member.
1836 propertyToDelete
.sizeOfNameString
= 0;
1839 * Here we should re-read the property so we get the updated pointer
1840 * but since we are here to zap it, I don't do it...
1842 StorageImpl_WriteProperty(
1843 parentStorage
->ancestorStorage
,
1844 indexOfPropertyToDelete
,
1850 /*********************************************************************
1854 * Finds a placeholder for the StgProperty within the Storage
1857 static HRESULT
findPlaceholder(
1858 StorageImpl
*storage
,
1859 ULONG propertyIndexToStore
,
1860 ULONG storePropertyIndex
,
1863 StgProperty storeProperty
;
1868 * Read the storage property
1870 res
= StorageImpl_ReadProperty(
1871 storage
->ancestorStorage
,
1880 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1882 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1884 return findPlaceholder(
1886 propertyIndexToStore
,
1887 storeProperty
.previousProperty
,
1892 storeProperty
.previousProperty
= propertyIndexToStore
;
1895 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1897 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1899 return findPlaceholder(
1901 propertyIndexToStore
,
1902 storeProperty
.nextProperty
,
1907 storeProperty
.nextProperty
= propertyIndexToStore
;
1910 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1912 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1914 return findPlaceholder(
1916 propertyIndexToStore
,
1917 storeProperty
.dirProperty
,
1922 storeProperty
.dirProperty
= propertyIndexToStore
;
1926 hr
= StorageImpl_WriteProperty(
1927 storage
->ancestorStorage
,
1939 /*************************************************************************
1943 * This method takes the previous and the next property link of a property
1944 * to be deleted and find them a place in the Storage.
1946 static HRESULT
adjustPropertyChain(
1948 StgProperty propertyToDelete
,
1949 StgProperty parentProperty
,
1950 ULONG parentPropertyId
,
1953 ULONG newLinkProperty
= PROPERTY_NULL
;
1954 BOOL needToFindAPlaceholder
= FALSE
;
1955 ULONG storeNode
= PROPERTY_NULL
;
1956 ULONG toStoreNode
= PROPERTY_NULL
;
1957 INT relationType
= 0;
1961 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1963 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
1966 * Set the parent previous to the property to delete previous
1968 newLinkProperty
= propertyToDelete
.previousProperty
;
1970 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1973 * We also need to find a storage for the other link, setup variables
1974 * to do this at the end...
1976 needToFindAPlaceholder
= TRUE
;
1977 storeNode
= propertyToDelete
.previousProperty
;
1978 toStoreNode
= propertyToDelete
.nextProperty
;
1979 relationType
= PROPERTY_RELATION_NEXT
;
1982 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
1985 * Set the parent previous to the property to delete next
1987 newLinkProperty
= propertyToDelete
.nextProperty
;
1991 * Link it for real...
1993 parentProperty
.previousProperty
= newLinkProperty
;
1996 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1998 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
2001 * Set the parent next to the property to delete next previous
2003 newLinkProperty
= propertyToDelete
.previousProperty
;
2005 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2008 * We also need to find a storage for the other link, setup variables
2009 * to do this at the end...
2011 needToFindAPlaceholder
= TRUE
;
2012 storeNode
= propertyToDelete
.previousProperty
;
2013 toStoreNode
= propertyToDelete
.nextProperty
;
2014 relationType
= PROPERTY_RELATION_NEXT
;
2017 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2020 * Set the parent next to the property to delete next
2022 newLinkProperty
= propertyToDelete
.nextProperty
;
2026 * Link it for real...
2028 parentProperty
.nextProperty
= newLinkProperty
;
2030 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2032 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
2035 * Set the parent dir to the property to delete previous
2037 newLinkProperty
= propertyToDelete
.previousProperty
;
2039 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2042 * We also need to find a storage for the other link, setup variables
2043 * to do this at the end...
2045 needToFindAPlaceholder
= TRUE
;
2046 storeNode
= propertyToDelete
.previousProperty
;
2047 toStoreNode
= propertyToDelete
.nextProperty
;
2048 relationType
= PROPERTY_RELATION_NEXT
;
2051 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2054 * Set the parent dir to the property to delete next
2056 newLinkProperty
= propertyToDelete
.nextProperty
;
2060 * Link it for real...
2062 parentProperty
.dirProperty
= newLinkProperty
;
2066 * Write back the parent property
2068 res
= StorageImpl_WriteProperty(
2069 This
->ancestorStorage
,
2078 * If a placeholder is required for the other link, then, find one and
2079 * get out of here...
2081 if (needToFindAPlaceholder
)
2083 hr
= findPlaceholder(
2094 /******************************************************************************
2095 * SetElementTimes (IStorage)
2097 HRESULT WINAPI
StorageImpl_SetElementTimes(
2099 const OLECHAR
*pwcsName
,/* [string][in] */
2100 const FILETIME
*pctime
, /* [in] */
2101 const FILETIME
*patime
, /* [in] */
2102 const FILETIME
*pmtime
) /* [in] */
2104 FIXME("(%s,...), stub!\n",debugstr_w(pwcsName
));
2108 /******************************************************************************
2109 * SetStateBits (IStorage)
2111 HRESULT WINAPI
StorageImpl_SetStateBits(
2113 DWORD grfStateBits
,/* [in] */
2114 DWORD grfMask
) /* [in] */
2116 FIXME("not implemented!\n");
2120 HRESULT
StorageImpl_Construct(
2130 StgProperty currentProperty
;
2131 BOOL readSuccessful
;
2132 ULONG currentPropertyIndex
;
2134 if ( FAILED( validateSTGM(openFlags
) ))
2135 return STG_E_INVALIDFLAG
;
2137 memset(This
, 0, sizeof(StorageImpl
));
2140 * Initialize the virtual fgunction table.
2142 ICOM_VTBL(This
) = &Storage32Impl_Vtbl
;
2143 This
->v_destructor
= &StorageImpl_Destroy
;
2146 * This is the top-level storage so initialize the ancester pointer
2149 This
->ancestorStorage
= This
;
2152 * Initialize the physical support of the storage.
2154 This
->hFile
= hFile
;
2157 * Store copy of file path.
2160 This
->pwcsName
= HeapAlloc(GetProcessHeap(), 0,
2161 (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
));
2162 if (!This
->pwcsName
)
2163 return STG_E_INSUFFICIENTMEMORY
;
2164 strcpyW(This
->pwcsName
, pwcsName
);
2168 * Initialize the big block cache.
2170 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
2171 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
2172 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
,
2178 if (This
->bigBlockFile
== 0)
2183 ULARGE_INTEGER size
;
2184 BYTE
* bigBlockBuffer
;
2187 * Initialize all header variables:
2188 * - The big block depot consists of one block and it is at block 0
2189 * - The properties start at block 1
2190 * - There is no small block depot
2192 memset( This
->bigBlockDepotStart
,
2194 sizeof(This
->bigBlockDepotStart
));
2196 This
->bigBlockDepotCount
= 1;
2197 This
->bigBlockDepotStart
[0] = 0;
2198 This
->rootStartBlock
= 1;
2199 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2200 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
2201 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
2202 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2203 This
->extBigBlockDepotCount
= 0;
2205 StorageImpl_SaveFileHeader(This
);
2208 * Add one block for the big block depot and one block for the properties
2210 size
.s
.HighPart
= 0;
2211 size
.s
.LowPart
= This
->bigBlockSize
* 3;
2212 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
2215 * Initialize the big block depot
2217 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, 0);
2218 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2219 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
2220 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
2221 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2226 * Load the header for the file.
2228 hr
= StorageImpl_LoadFileHeader(This
);
2232 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2239 * There is no block depot cached yet.
2241 This
->indexBlockDepotCached
= 0xFFFFFFFF;
2244 * Start searching for free blocks with block 0.
2246 This
->prevFreeBlock
= 0;
2249 * Create the block chain abstractions.
2251 This
->rootBlockChain
=
2252 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
2254 This
->smallBlockDepotChain
= BlockChainStream_Construct(
2256 &This
->smallBlockDepotStart
,
2260 * Write the root property
2264 StgProperty rootProp
;
2266 * Initialize the property chain
2268 memset(&rootProp
, 0, sizeof(rootProp
));
2269 MultiByteToWideChar( CP_ACP
, 0, rootPropertyName
, -1, rootProp
.name
,
2270 sizeof(rootProp
.name
)/sizeof(WCHAR
) );
2271 rootProp
.sizeOfNameString
= (strlenW(rootProp
.name
)+1) * sizeof(WCHAR
);
2272 rootProp
.propertyType
= PROPTYPE_ROOT
;
2273 rootProp
.previousProperty
= PROPERTY_NULL
;
2274 rootProp
.nextProperty
= PROPERTY_NULL
;
2275 rootProp
.dirProperty
= PROPERTY_NULL
;
2276 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
2277 rootProp
.size
.s
.HighPart
= 0;
2278 rootProp
.size
.s
.LowPart
= 0;
2280 StorageImpl_WriteProperty(This
, 0, &rootProp
);
2284 * Find the ID of the root int he property sets.
2286 currentPropertyIndex
= 0;
2290 readSuccessful
= StorageImpl_ReadProperty(
2292 currentPropertyIndex
,
2297 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
2298 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
2300 This
->rootPropertySetIndex
= currentPropertyIndex
;
2304 currentPropertyIndex
++;
2306 } while (readSuccessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
2308 if (!readSuccessful
)
2315 * Create the block chain abstraction for the small block root chain.
2317 This
->smallBlockRootChain
= BlockChainStream_Construct(
2320 This
->rootPropertySetIndex
);
2325 void StorageImpl_Destroy(
2328 TRACE("(%p)\n", This
);
2331 HeapFree(GetProcessHeap(), 0, This
->pwcsName
);
2333 BlockChainStream_Destroy(This
->smallBlockRootChain
);
2334 BlockChainStream_Destroy(This
->rootBlockChain
);
2335 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
2337 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2341 /******************************************************************************
2342 * Storage32Impl_GetNextFreeBigBlock
2344 * Returns the index of the next free big block.
2345 * If the big block depot is filled, this method will enlarge it.
2348 ULONG
StorageImpl_GetNextFreeBigBlock(
2351 ULONG depotBlockIndexPos
;
2353 ULONG depotBlockOffset
;
2354 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
2355 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2357 ULONG freeBlock
= BLOCK_UNUSED
;
2359 depotIndex
= This
->prevFreeBlock
/ blocksPerDepot
;
2360 depotBlockOffset
= (This
->prevFreeBlock
% blocksPerDepot
) * sizeof(ULONG
);
2363 * Scan the entire big block depot until we find a block marked free
2365 while (nextBlockIndex
!= BLOCK_UNUSED
)
2367 if (depotIndex
< COUNT_BBDEPOTINHEADER
)
2369 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2372 * Grow the primary depot.
2374 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2376 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2379 * Add a block depot.
2381 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2382 This
->bigBlockDepotCount
++;
2383 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2386 * Flag it as a block depot.
2388 StorageImpl_SetNextBlockInChain(This
,
2392 /* Save new header information.
2394 StorageImpl_SaveFileHeader(This
);
2399 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotIndex
);
2401 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2404 * Grow the extended depot.
2406 ULONG extIndex
= BLOCK_UNUSED
;
2407 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2408 ULONG extBlockOffset
= numExtBlocks
% (blocksPerDepot
- 1);
2410 if (extBlockOffset
== 0)
2412 /* We need an extended block.
2414 extIndex
= Storage32Impl_AddExtBlockDepot(This
);
2415 This
->extBigBlockDepotCount
++;
2416 depotBlockIndexPos
= extIndex
+ 1;
2419 depotBlockIndexPos
= depotIndex
* blocksPerDepot
;
2422 * Add a block depot and mark it in the extended block.
2424 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2425 This
->bigBlockDepotCount
++;
2426 Storage32Impl_SetExtDepotBlock(This
, depotIndex
, depotBlockIndexPos
);
2428 /* Flag the block depot.
2430 StorageImpl_SetNextBlockInChain(This
,
2434 /* If necessary, flag the extended depot block.
2436 if (extIndex
!= BLOCK_UNUSED
)
2437 StorageImpl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2439 /* Save header information.
2441 StorageImpl_SaveFileHeader(This
);
2445 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2447 if (depotBuffer
!= 0)
2449 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2450 ( nextBlockIndex
!= BLOCK_UNUSED
))
2452 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2454 if (nextBlockIndex
== BLOCK_UNUSED
)
2456 freeBlock
= (depotIndex
* blocksPerDepot
) +
2457 (depotBlockOffset
/sizeof(ULONG
));
2460 depotBlockOffset
+= sizeof(ULONG
);
2463 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2467 depotBlockOffset
= 0;
2470 This
->prevFreeBlock
= freeBlock
;
2475 /******************************************************************************
2476 * Storage32Impl_AddBlockDepot
2478 * This will create a depot block, essentially it is a block initialized
2481 void Storage32Impl_AddBlockDepot(StorageImpl
* This
, ULONG blockIndex
)
2485 blockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2488 * Initialize blocks as free
2490 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2492 StorageImpl_ReleaseBigBlock(This
, blockBuffer
);
2495 /******************************************************************************
2496 * Storage32Impl_GetExtDepotBlock
2498 * Returns the index of the block that corresponds to the specified depot
2499 * index. This method is only for depot indexes equal or greater than
2500 * COUNT_BBDEPOTINHEADER.
2502 ULONG
Storage32Impl_GetExtDepotBlock(StorageImpl
* This
, ULONG depotIndex
)
2504 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2505 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2506 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2507 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2508 ULONG blockIndex
= BLOCK_UNUSED
;
2509 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2511 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2513 if (This
->extBigBlockDepotStart
== BLOCK_END_OF_CHAIN
)
2514 return BLOCK_UNUSED
;
2516 while (extBlockCount
> 0)
2518 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2522 if (extBlockIndex
!= BLOCK_UNUSED
)
2526 depotBuffer
= StorageImpl_GetROBigBlock(This
, extBlockIndex
);
2528 if (depotBuffer
!= 0)
2530 StorageUtl_ReadDWord(depotBuffer
,
2531 extBlockOffset
* sizeof(ULONG
),
2534 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2541 /******************************************************************************
2542 * Storage32Impl_SetExtDepotBlock
2544 * Associates the specified block index to the specified depot index.
2545 * This method is only for depot indexes equal or greater than
2546 * COUNT_BBDEPOTINHEADER.
2548 void Storage32Impl_SetExtDepotBlock(StorageImpl
* This
,
2552 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2553 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2554 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2555 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2556 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2558 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2560 while (extBlockCount
> 0)
2562 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2566 if (extBlockIndex
!= BLOCK_UNUSED
)
2570 depotBuffer
= StorageImpl_GetBigBlock(This
, extBlockIndex
);
2572 if (depotBuffer
!= 0)
2574 StorageUtl_WriteDWord(depotBuffer
,
2575 extBlockOffset
* sizeof(ULONG
),
2578 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2583 /******************************************************************************
2584 * Storage32Impl_AddExtBlockDepot
2586 * Creates an extended depot block.
2588 ULONG
Storage32Impl_AddExtBlockDepot(StorageImpl
* This
)
2590 ULONG numExtBlocks
= This
->extBigBlockDepotCount
;
2591 ULONG nextExtBlock
= This
->extBigBlockDepotStart
;
2592 BYTE
* depotBuffer
= NULL
;
2593 ULONG index
= BLOCK_UNUSED
;
2594 ULONG nextBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2595 ULONG blocksPerDepotBlock
= This
->bigBlockSize
/ sizeof(ULONG
);
2596 ULONG depotBlocksPerExtBlock
= blocksPerDepotBlock
- 1;
2598 index
= (COUNT_BBDEPOTINHEADER
+ (numExtBlocks
* depotBlocksPerExtBlock
)) *
2599 blocksPerDepotBlock
;
2601 if ((numExtBlocks
== 0) && (nextExtBlock
== BLOCK_END_OF_CHAIN
))
2604 * The first extended block.
2606 This
->extBigBlockDepotStart
= index
;
2612 * Follow the chain to the last one.
2614 for (i
= 0; i
< (numExtBlocks
- 1); i
++)
2616 nextExtBlock
= Storage32Impl_GetNextExtendedBlock(This
, nextExtBlock
);
2620 * Add the new extended block to the chain.
2622 depotBuffer
= StorageImpl_GetBigBlock(This
, nextExtBlock
);
2623 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2624 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2628 * Initialize this block.
2630 depotBuffer
= StorageImpl_GetBigBlock(This
, index
);
2631 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2632 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2637 /******************************************************************************
2638 * Storage32Impl_FreeBigBlock
2640 * This method will flag the specified block as free in the big block depot.
2642 void StorageImpl_FreeBigBlock(
2646 StorageImpl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2648 if (blockIndex
< This
->prevFreeBlock
)
2649 This
->prevFreeBlock
= blockIndex
;
2652 /************************************************************************
2653 * Storage32Impl_GetNextBlockInChain
2655 * This method will retrieve the block index of the next big block in
2658 * Params: This - Pointer to the Storage object.
2659 * blockIndex - Index of the block to retrieve the chain
2662 * Returns: This method returns the index of the next block in the chain.
2663 * It will return the constants:
2664 * BLOCK_SPECIAL - If the block given was not part of a
2666 * BLOCK_END_OF_CHAIN - If the block given was the last in
2668 * BLOCK_UNUSED - If the block given was not past of a chain
2670 * BLOCK_EXTBBDEPOT - This block is part of the extended
2673 * See Windows documentation for more details on IStorage methods.
2675 ULONG
StorageImpl_GetNextBlockInChain(
2679 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2680 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2681 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2682 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2684 ULONG depotBlockIndexPos
;
2686 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2689 * Cache the currently accessed depot block.
2691 if (depotBlockCount
!= This
->indexBlockDepotCached
)
2693 This
->indexBlockDepotCached
= depotBlockCount
;
2695 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2697 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2702 * We have to look in the extended depot.
2704 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2707 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2713 for (index
= 0; index
< NUM_BLOCKS_PER_DEPOT_BLOCK
; index
++)
2715 StorageUtl_ReadDWord(depotBuffer
, index
*sizeof(ULONG
), &nextBlockIndex
);
2716 This
->blockDepotCached
[index
] = nextBlockIndex
;
2719 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2723 nextBlockIndex
= This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)];
2725 return nextBlockIndex
;
2728 /******************************************************************************
2729 * Storage32Impl_GetNextExtendedBlock
2731 * Given an extended block this method will return the next extended block.
2734 * The last ULONG of an extended block is the block index of the next
2735 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2739 * - The index of the next extended block
2740 * - BLOCK_UNUSED: there is no next extended block.
2741 * - Any other return values denotes failure.
2743 ULONG
Storage32Impl_GetNextExtendedBlock(StorageImpl
* This
, ULONG blockIndex
)
2745 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2746 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2749 depotBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2753 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2755 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2758 return nextBlockIndex
;
2761 /******************************************************************************
2762 * Storage32Impl_SetNextBlockInChain
2764 * This method will write the index of the specified block's next block
2765 * in the big block depot.
2767 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2770 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2771 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2772 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2775 void StorageImpl_SetNextBlockInChain(
2780 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2781 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2782 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2783 ULONG depotBlockIndexPos
;
2786 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2787 assert(blockIndex
!= nextBlock
);
2789 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2791 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2796 * We have to look in the extended depot.
2798 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2801 depotBuffer
= StorageImpl_GetBigBlock(This
, depotBlockIndexPos
);
2805 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2806 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2810 * Update the cached block depot, if necessary.
2812 if (depotBlockCount
== This
->indexBlockDepotCached
)
2814 This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)] = nextBlock
;
2818 /******************************************************************************
2819 * Storage32Impl_LoadFileHeader
2821 * This method will read in the file header, i.e. big block index -1.
2823 HRESULT
StorageImpl_LoadFileHeader(
2826 HRESULT hr
= STG_E_FILENOTFOUND
;
2827 void* headerBigBlock
= NULL
;
2831 * Get a pointer to the big block of data containing the header.
2833 headerBigBlock
= StorageImpl_GetROBigBlock(This
, -1);
2836 * Extract the information from the header.
2838 if (headerBigBlock
!=0)
2841 * Check for the "magic number" signature and return an error if it is not
2844 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2846 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2847 return STG_E_OLDFORMAT
;
2850 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2852 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2853 return STG_E_INVALIDHEADER
;
2856 StorageUtl_ReadWord(
2858 OFFSET_BIGBLOCKSIZEBITS
,
2859 &This
->bigBlockSizeBits
);
2861 StorageUtl_ReadWord(
2863 OFFSET_SMALLBLOCKSIZEBITS
,
2864 &This
->smallBlockSizeBits
);
2866 StorageUtl_ReadDWord(
2868 OFFSET_BBDEPOTCOUNT
,
2869 &This
->bigBlockDepotCount
);
2871 StorageUtl_ReadDWord(
2873 OFFSET_ROOTSTARTBLOCK
,
2874 &This
->rootStartBlock
);
2876 StorageUtl_ReadDWord(
2878 OFFSET_SBDEPOTSTART
,
2879 &This
->smallBlockDepotStart
);
2881 StorageUtl_ReadDWord(
2883 OFFSET_EXTBBDEPOTSTART
,
2884 &This
->extBigBlockDepotStart
);
2886 StorageUtl_ReadDWord(
2888 OFFSET_EXTBBDEPOTCOUNT
,
2889 &This
->extBigBlockDepotCount
);
2891 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2893 StorageUtl_ReadDWord(
2895 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2896 &(This
->bigBlockDepotStart
[index
]));
2900 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2904 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2905 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2909 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2910 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2914 * Right now, the code is making some assumptions about the size of the
2915 * blocks, just make sure they are what we're expecting.
2917 assert( (This
->bigBlockSize
==DEF_BIG_BLOCK_SIZE
) &&
2918 (This
->smallBlockSize
==DEF_SMALL_BLOCK_SIZE
));
2921 * Release the block.
2923 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2931 /******************************************************************************
2932 * Storage32Impl_SaveFileHeader
2934 * This method will save to the file the header, i.e. big block -1.
2936 void StorageImpl_SaveFileHeader(
2939 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
2944 * Get a pointer to the big block of data containing the header.
2946 success
= StorageImpl_ReadBigBlock(This
, -1, headerBigBlock
);
2949 * If the block read failed, the file is probably new.
2954 * Initialize for all unknown fields.
2956 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
2959 * Initialize the magic number.
2961 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
2964 * And a bunch of things we don't know what they mean
2966 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
2967 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
2968 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
2969 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
2970 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
2974 * Write the information to the header.
2976 if (headerBigBlock
!=0)
2978 StorageUtl_WriteWord(
2980 OFFSET_BIGBLOCKSIZEBITS
,
2981 This
->bigBlockSizeBits
);
2983 StorageUtl_WriteWord(
2985 OFFSET_SMALLBLOCKSIZEBITS
,
2986 This
->smallBlockSizeBits
);
2988 StorageUtl_WriteDWord(
2990 OFFSET_BBDEPOTCOUNT
,
2991 This
->bigBlockDepotCount
);
2993 StorageUtl_WriteDWord(
2995 OFFSET_ROOTSTARTBLOCK
,
2996 This
->rootStartBlock
);
2998 StorageUtl_WriteDWord(
3000 OFFSET_SBDEPOTSTART
,
3001 This
->smallBlockDepotStart
);
3003 StorageUtl_WriteDWord(
3005 OFFSET_EXTBBDEPOTSTART
,
3006 This
->extBigBlockDepotStart
);
3008 StorageUtl_WriteDWord(
3010 OFFSET_EXTBBDEPOTCOUNT
,
3011 This
->extBigBlockDepotCount
);
3013 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
3015 StorageUtl_WriteDWord(
3017 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
3018 (This
->bigBlockDepotStart
[index
]));
3023 * Write the big block back to the file.
3025 StorageImpl_WriteBigBlock(This
, -1, headerBigBlock
);
3028 /******************************************************************************
3029 * Storage32Impl_ReadProperty
3031 * This method will read the specified property from the property chain.
3033 BOOL
StorageImpl_ReadProperty(
3036 StgProperty
* buffer
)
3038 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3039 ULARGE_INTEGER offsetInPropSet
;
3040 BOOL readSuccessful
;
3043 offsetInPropSet
.s
.HighPart
= 0;
3044 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3046 readSuccessful
= BlockChainStream_ReadAt(
3047 This
->rootBlockChain
,
3055 memset(buffer
->name
, 0, sizeof(buffer
->name
));
3058 currentProperty
+OFFSET_PS_NAME
,
3059 PROPERTY_NAME_BUFFER_LEN
);
3061 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
3063 StorageUtl_ReadWord(
3065 OFFSET_PS_NAMELENGTH
,
3066 &buffer
->sizeOfNameString
);
3068 StorageUtl_ReadDWord(
3070 OFFSET_PS_PREVIOUSPROP
,
3071 &buffer
->previousProperty
);
3073 StorageUtl_ReadDWord(
3076 &buffer
->nextProperty
);
3078 StorageUtl_ReadDWord(
3081 &buffer
->dirProperty
);
3083 StorageUtl_ReadGUID(
3086 &buffer
->propertyUniqueID
);
3088 StorageUtl_ReadDWord(
3091 &buffer
->timeStampS1
);
3093 StorageUtl_ReadDWord(
3096 &buffer
->timeStampD1
);
3098 StorageUtl_ReadDWord(
3101 &buffer
->timeStampS2
);
3103 StorageUtl_ReadDWord(
3106 &buffer
->timeStampD2
);
3108 StorageUtl_ReadDWord(
3110 OFFSET_PS_STARTBLOCK
,
3111 &buffer
->startingBlock
);
3113 StorageUtl_ReadDWord(
3116 &buffer
->size
.s
.LowPart
);
3118 buffer
->size
.s
.HighPart
= 0;
3121 return readSuccessful
;
3124 /*********************************************************************
3125 * Write the specified property into the property chain
3127 BOOL
StorageImpl_WriteProperty(
3130 StgProperty
* buffer
)
3132 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3133 ULARGE_INTEGER offsetInPropSet
;
3134 BOOL writeSuccessful
;
3137 offsetInPropSet
.s
.HighPart
= 0;
3138 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3140 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
3143 currentProperty
+ OFFSET_PS_NAME
,
3145 PROPERTY_NAME_BUFFER_LEN
);
3147 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
3149 StorageUtl_WriteWord(
3151 OFFSET_PS_NAMELENGTH
,
3152 buffer
->sizeOfNameString
);
3154 StorageUtl_WriteDWord(
3156 OFFSET_PS_PREVIOUSPROP
,
3157 buffer
->previousProperty
);
3159 StorageUtl_WriteDWord(
3162 buffer
->nextProperty
);
3164 StorageUtl_WriteDWord(
3167 buffer
->dirProperty
);
3169 StorageUtl_WriteGUID(
3172 &buffer
->propertyUniqueID
);
3174 StorageUtl_WriteDWord(
3177 buffer
->timeStampS1
);
3179 StorageUtl_WriteDWord(
3182 buffer
->timeStampD1
);
3184 StorageUtl_WriteDWord(
3187 buffer
->timeStampS2
);
3189 StorageUtl_WriteDWord(
3192 buffer
->timeStampD2
);
3194 StorageUtl_WriteDWord(
3196 OFFSET_PS_STARTBLOCK
,
3197 buffer
->startingBlock
);
3199 StorageUtl_WriteDWord(
3202 buffer
->size
.s
.LowPart
);
3204 writeSuccessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
3209 return writeSuccessful
;
3212 BOOL
StorageImpl_ReadBigBlock(
3217 void* bigBlockBuffer
;
3219 bigBlockBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
3221 if (bigBlockBuffer
!=0)
3223 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
3225 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3233 BOOL
StorageImpl_WriteBigBlock(
3238 void* bigBlockBuffer
;
3240 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
3242 if (bigBlockBuffer
!=0)
3244 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
3246 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3254 void* StorageImpl_GetROBigBlock(
3258 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
3261 void* StorageImpl_GetBigBlock(
3265 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
3268 void StorageImpl_ReleaseBigBlock(
3272 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
3275 /******************************************************************************
3276 * Storage32Impl_SmallBlocksToBigBlocks
3278 * This method will convert a small block chain to a big block chain.
3279 * The small block chain will be destroyed.
3281 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
3283 SmallBlockChainStream
** ppsbChain
)
3285 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
3286 ULARGE_INTEGER size
, offset
;
3287 ULONG cbRead
, cbWritten
, cbTotalRead
, cbTotalWritten
;
3288 ULONG propertyIndex
;
3289 BOOL successRead
, successWrite
;
3290 StgProperty chainProperty
;
3292 BlockChainStream
*bbTempChain
= NULL
;
3293 BlockChainStream
*bigBlockChain
= NULL
;
3296 * Create a temporary big block chain that doesn't have
3297 * an associated property. This temporary chain will be
3298 * used to copy data from small blocks to big blocks.
3300 bbTempChain
= BlockChainStream_Construct(This
,
3305 * Grow the big block chain.
3307 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
3308 BlockChainStream_SetSize(bbTempChain
, size
);
3311 * Copy the contents of the small block chain to the big block chain
3312 * by small block size increments.
3314 offset
.s
.LowPart
= 0;
3315 offset
.s
.HighPart
= 0;
3319 buffer
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE
);
3322 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
3324 DEF_SMALL_BLOCK_SIZE
,
3327 cbTotalRead
+= cbRead
;
3329 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
3334 cbTotalWritten
+= cbWritten
;
3336 offset
.s
.LowPart
+= This
->smallBlockSize
;
3338 } while (successRead
&& successWrite
);
3339 HeapFree(GetProcessHeap(),0,buffer
);
3341 assert(cbTotalRead
== cbTotalWritten
);
3344 * Destroy the small block chain.
3346 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
3347 size
.s
.HighPart
= 0;
3349 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
3350 SmallBlockChainStream_Destroy(*ppsbChain
);
3354 * Change the property information. This chain is now a big block chain
3355 * and it doesn't reside in the small blocks chain anymore.
3357 StorageImpl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3359 chainProperty
.startingBlock
= bbHeadOfChain
;
3361 StorageImpl_WriteProperty(This
, propertyIndex
, &chainProperty
);
3364 * Destroy the temporary propertyless big block chain.
3365 * Create a new big block chain associated with this property.
3367 BlockChainStream_Destroy(bbTempChain
);
3368 bigBlockChain
= BlockChainStream_Construct(This
,
3372 return bigBlockChain
;
3375 /******************************************************************************
3376 ** Storage32InternalImpl implementation
3379 StorageInternalImpl
* StorageInternalImpl_Construct(
3380 StorageImpl
* ancestorStorage
,
3381 ULONG rootPropertyIndex
)
3383 StorageInternalImpl
* newStorage
;
3386 * Allocate space for the new storage object
3388 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl
));
3392 memset(newStorage
, 0, sizeof(StorageInternalImpl
));
3395 * Initialize the virtual function table.
3397 ICOM_VTBL(newStorage
) = &Storage32InternalImpl_Vtbl
;
3398 newStorage
->v_destructor
= &StorageInternalImpl_Destroy
;
3401 * Keep the ancestor storage pointer and nail a reference to it.
3403 newStorage
->ancestorStorage
= ancestorStorage
;
3404 StorageBaseImpl_AddRef((IStorage
*)(newStorage
->ancestorStorage
));
3407 * Keep the index of the root property set for this storage,
3409 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3417 void StorageInternalImpl_Destroy(
3418 StorageInternalImpl
* This
)
3420 StorageBaseImpl_Release((IStorage
*)This
->ancestorStorage
);
3421 HeapFree(GetProcessHeap(), 0, This
);
3424 /******************************************************************************
3426 ** Storage32InternalImpl_Commit
3428 ** The non-root storages cannot be opened in transacted mode thus this function
3431 HRESULT WINAPI
StorageInternalImpl_Commit(
3433 DWORD grfCommitFlags
) /* [in] */
3438 /******************************************************************************
3440 ** Storage32InternalImpl_Revert
3442 ** The non-root storages cannot be opened in transacted mode thus this function
3445 HRESULT WINAPI
StorageInternalImpl_Revert(
3451 /******************************************************************************
3452 ** IEnumSTATSTGImpl implementation
3455 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3456 StorageImpl
* parentStorage
,
3457 ULONG firstPropertyNode
)
3459 IEnumSTATSTGImpl
* newEnumeration
;
3461 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3463 if (newEnumeration
!=0)
3466 * Set-up the virtual function table and reference count.
3468 ICOM_VTBL(newEnumeration
) = &IEnumSTATSTGImpl_Vtbl
;
3469 newEnumeration
->ref
= 0;
3472 * We want to nail-down the reference to the storage in case the
3473 * enumeration out-lives the storage in the client application.
3475 newEnumeration
->parentStorage
= parentStorage
;
3476 IStorage_AddRef((IStorage
*)newEnumeration
->parentStorage
);
3478 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3481 * Initialize the search stack
3483 newEnumeration
->stackSize
= 0;
3484 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3485 newEnumeration
->stackToVisit
=
3486 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3489 * Make sure the current node of the iterator is the first one.
3491 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3494 return newEnumeration
;
3497 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3499 IStorage_Release((IStorage
*)This
->parentStorage
);
3500 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3501 HeapFree(GetProcessHeap(), 0, This
);
3504 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3505 IEnumSTATSTG
* iface
,
3509 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3512 * Perform a sanity check on the parameters.
3515 return E_INVALIDARG
;
3518 * Initialize the return parameter.
3523 * Compare the riid with the interface IDs implemented by this object.
3525 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3527 *ppvObject
= (IEnumSTATSTG
*)This
;
3529 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3531 *ppvObject
= (IEnumSTATSTG
*)This
;
3535 * Check that we obtained an interface.
3537 if ((*ppvObject
)==0)
3538 return E_NOINTERFACE
;
3541 * Query Interface always increases the reference count by one when it is
3544 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3549 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3550 IEnumSTATSTG
* iface
)
3552 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3558 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3559 IEnumSTATSTG
* iface
)
3561 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3569 * If the reference count goes down to 0, perform suicide.
3573 IEnumSTATSTGImpl_Destroy(This
);
3579 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3580 IEnumSTATSTG
* iface
,
3583 ULONG
* pceltFetched
)
3585 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3587 StgProperty currentProperty
;
3588 STATSTG
* currentReturnStruct
= rgelt
;
3589 ULONG objectFetched
= 0;
3590 ULONG currentSearchNode
;
3593 * Perform a sanity check on the parameters.
3595 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3596 return E_INVALIDARG
;
3599 * To avoid the special case, get another pointer to a ULONG value if
3600 * the caller didn't supply one.
3602 if (pceltFetched
==0)
3603 pceltFetched
= &objectFetched
;
3606 * Start the iteration, we will iterate until we hit the end of the
3607 * linked list or until we hit the number of items to iterate through
3612 * Start with the node at the top of the stack.
3614 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3616 while ( ( *pceltFetched
< celt
) &&
3617 ( currentSearchNode
!=PROPERTY_NULL
) )
3620 * Remove the top node from the stack
3622 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3625 * Read the property from the storage.
3627 StorageImpl_ReadProperty(This
->parentStorage
,
3632 * Copy the information to the return buffer.
3634 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3639 * Step to the next item in the iteration
3642 currentReturnStruct
++;
3645 * Push the next search node in the search stack.
3647 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3650 * continue the iteration.
3652 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3655 if (*pceltFetched
== celt
)
3662 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3663 IEnumSTATSTG
* iface
,
3666 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3668 StgProperty currentProperty
;
3669 ULONG objectFetched
= 0;
3670 ULONG currentSearchNode
;
3673 * Start with the node at the top of the stack.
3675 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3677 while ( (objectFetched
< celt
) &&
3678 (currentSearchNode
!=PROPERTY_NULL
) )
3681 * Remove the top node from the stack
3683 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3686 * Read the property from the storage.
3688 StorageImpl_ReadProperty(This
->parentStorage
,
3693 * Step to the next item in the iteration
3698 * Push the next search node in the search stack.
3700 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3703 * continue the iteration.
3705 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3708 if (objectFetched
== celt
)
3714 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3715 IEnumSTATSTG
* iface
)
3717 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3719 StgProperty rootProperty
;
3720 BOOL readSuccessful
;
3723 * Re-initialize the search stack to an empty stack
3725 This
->stackSize
= 0;
3728 * Read the root property from the storage.
3730 readSuccessful
= StorageImpl_ReadProperty(
3731 This
->parentStorage
,
3732 This
->firstPropertyNode
,
3737 assert(rootProperty
.sizeOfNameString
!=0);
3740 * Push the search node in the search stack.
3742 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3748 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3749 IEnumSTATSTG
* iface
,
3750 IEnumSTATSTG
** ppenum
)
3752 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3754 IEnumSTATSTGImpl
* newClone
;
3757 * Perform a sanity check on the parameters.
3760 return E_INVALIDARG
;
3762 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3763 This
->firstPropertyNode
);
3767 * The new clone enumeration must point to the same current node as
3770 newClone
->stackSize
= This
->stackSize
;
3771 newClone
->stackMaxSize
= This
->stackMaxSize
;
3772 newClone
->stackToVisit
=
3773 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3776 newClone
->stackToVisit
,
3778 sizeof(ULONG
) * newClone
->stackSize
);
3780 *ppenum
= (IEnumSTATSTG
*)newClone
;
3783 * Don't forget to nail down a reference to the clone before
3786 IEnumSTATSTGImpl_AddRef(*ppenum
);
3791 INT
IEnumSTATSTGImpl_FindParentProperty(
3792 IEnumSTATSTGImpl
*This
,
3793 ULONG childProperty
,
3794 StgProperty
*currentProperty
,
3797 ULONG currentSearchNode
;
3801 * To avoid the special case, get another pointer to a ULONG value if
3802 * the caller didn't supply one.
3805 thisNodeId
= &foundNode
;
3808 * Start with the node at the top of the stack.
3810 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3813 while (currentSearchNode
!=PROPERTY_NULL
)
3816 * Store the current node in the returned parameters
3818 *thisNodeId
= currentSearchNode
;
3821 * Remove the top node from the stack
3823 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3826 * Read the property from the storage.
3828 StorageImpl_ReadProperty(
3829 This
->parentStorage
,
3833 if (currentProperty
->previousProperty
== childProperty
)
3834 return PROPERTY_RELATION_PREVIOUS
;
3836 else if (currentProperty
->nextProperty
== childProperty
)
3837 return PROPERTY_RELATION_NEXT
;
3839 else if (currentProperty
->dirProperty
== childProperty
)
3840 return PROPERTY_RELATION_DIR
;
3843 * Push the next search node in the search stack.
3845 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3848 * continue the iteration.
3850 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3853 return PROPERTY_NULL
;
3856 ULONG
IEnumSTATSTGImpl_FindProperty(
3857 IEnumSTATSTGImpl
* This
,
3858 const OLECHAR
* lpszPropName
,
3859 StgProperty
* currentProperty
)
3861 ULONG currentSearchNode
;
3864 * Start with the node at the top of the stack.
3866 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3868 while (currentSearchNode
!=PROPERTY_NULL
)
3871 * Remove the top node from the stack
3873 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3876 * Read the property from the storage.
3878 StorageImpl_ReadProperty(This
->parentStorage
,
3882 if ( propertyNameCmp(
3883 (OLECHAR
*)currentProperty
->name
,
3884 (OLECHAR
*)lpszPropName
) == 0)
3885 return currentSearchNode
;
3888 * Push the next search node in the search stack.
3890 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3893 * continue the iteration.
3895 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3898 return PROPERTY_NULL
;
3901 void IEnumSTATSTGImpl_PushSearchNode(
3902 IEnumSTATSTGImpl
* This
,
3905 StgProperty rootProperty
;
3906 BOOL readSuccessful
;
3909 * First, make sure we're not trying to push an unexisting node.
3911 if (nodeToPush
==PROPERTY_NULL
)
3915 * First push the node to the stack
3917 if (This
->stackSize
== This
->stackMaxSize
)
3919 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3921 This
->stackToVisit
= HeapReAlloc(
3925 sizeof(ULONG
) * This
->stackMaxSize
);
3928 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
3932 * Read the root property from the storage.
3934 readSuccessful
= StorageImpl_ReadProperty(
3935 This
->parentStorage
,
3941 assert(rootProperty
.sizeOfNameString
!=0);
3944 * Push the previous search node in the search stack.
3946 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
3950 ULONG
IEnumSTATSTGImpl_PopSearchNode(
3951 IEnumSTATSTGImpl
* This
,
3956 if (This
->stackSize
== 0)
3957 return PROPERTY_NULL
;
3959 topNode
= This
->stackToVisit
[This
->stackSize
-1];
3967 /******************************************************************************
3968 ** StorageUtl implementation
3971 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
3973 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
3976 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
3978 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
3981 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
3983 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
3986 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
3988 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
3991 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
3993 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
3994 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
3995 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
3997 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
4000 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
4002 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
4003 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
4004 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
4006 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
4009 void StorageUtl_CopyPropertyToSTATSTG(
4010 STATSTG
* destination
,
4011 StgProperty
* source
,
4015 * The copy of the string occurs only when the flag is not set
4017 if ((statFlags
& STATFLAG_NONAME
) != 0)
4019 destination
->pwcsName
= 0;
4023 destination
->pwcsName
=
4024 CoTaskMemAlloc((lstrlenW(source
->name
)+1)*sizeof(WCHAR
));
4026 strcpyW((LPWSTR
)destination
->pwcsName
, source
->name
);
4029 switch (source
->propertyType
)
4031 case PROPTYPE_STORAGE
:
4033 destination
->type
= STGTY_STORAGE
;
4035 case PROPTYPE_STREAM
:
4036 destination
->type
= STGTY_STREAM
;
4039 destination
->type
= STGTY_STREAM
;
4043 destination
->cbSize
= source
->size
;
4045 currentReturnStruct->mtime = {0}; TODO
4046 currentReturnStruct->ctime = {0};
4047 currentReturnStruct->atime = {0};
4049 destination
->grfMode
= 0;
4050 destination
->grfLocksSupported
= 0;
4051 destination
->clsid
= source
->propertyUniqueID
;
4052 destination
->grfStateBits
= 0;
4053 destination
->reserved
= 0;
4056 /******************************************************************************
4057 ** BlockChainStream implementation
4060 BlockChainStream
* BlockChainStream_Construct(
4061 StorageImpl
* parentStorage
,
4062 ULONG
* headOfStreamPlaceHolder
,
4063 ULONG propertyIndex
)
4065 BlockChainStream
* newStream
;
4068 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
4070 newStream
->parentStorage
= parentStorage
;
4071 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
4072 newStream
->ownerPropertyIndex
= propertyIndex
;
4073 newStream
->lastBlockNoInSequence
= 0xFFFFFFFF;
4074 newStream
->tailIndex
= BLOCK_END_OF_CHAIN
;
4075 newStream
->numBlocks
= 0;
4077 blockIndex
= BlockChainStream_GetHeadOfChain(newStream
);
4079 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4081 newStream
->numBlocks
++;
4082 newStream
->tailIndex
= blockIndex
;
4084 blockIndex
= StorageImpl_GetNextBlockInChain(
4092 void BlockChainStream_Destroy(BlockChainStream
* This
)
4094 HeapFree(GetProcessHeap(), 0, This
);
4097 /******************************************************************************
4098 * BlockChainStream_GetHeadOfChain
4100 * Returns the head of this stream chain.
4101 * Some special chains don't have properties, their heads are kept in
4102 * This->headOfStreamPlaceHolder.
4105 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
4107 StgProperty chainProperty
;
4108 BOOL readSuccessful
;
4110 if (This
->headOfStreamPlaceHolder
!= 0)
4111 return *(This
->headOfStreamPlaceHolder
);
4113 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
4115 readSuccessful
= StorageImpl_ReadProperty(
4116 This
->parentStorage
,
4117 This
->ownerPropertyIndex
,
4122 return chainProperty
.startingBlock
;
4126 return BLOCK_END_OF_CHAIN
;
4129 /******************************************************************************
4130 * BlockChainStream_GetCount
4132 * Returns the number of blocks that comprises this chain.
4133 * This is not the size of the stream as the last block may not be full!
4136 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
4141 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4143 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4147 blockIndex
= StorageImpl_GetNextBlockInChain(
4148 This
->parentStorage
,
4155 /******************************************************************************
4156 * BlockChainStream_ReadAt
4158 * Reads a specified number of bytes from this chain at the specified offset.
4159 * bytesRead may be NULL.
4160 * Failure will be returned if the specified number of bytes has not been read.
4162 BOOL
BlockChainStream_ReadAt(BlockChainStream
* This
,
4163 ULARGE_INTEGER offset
,
4168 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4169 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4170 ULONG bytesToReadInBuffer
;
4173 BYTE
* bigBlockBuffer
;
4176 * Find the first block in the stream that contains part of the buffer.
4178 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4179 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4180 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4182 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4183 This
->lastBlockNoInSequence
= blockNoInSequence
;
4187 ULONG temp
= blockNoInSequence
;
4189 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4190 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4191 This
->lastBlockNoInSequence
= temp
;
4194 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4197 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4199 blockNoInSequence
--;
4202 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4205 * Start reading the buffer.
4208 bufferWalker
= buffer
;
4210 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4213 * Calculate how many bytes we can copy from this big block.
4215 bytesToReadInBuffer
=
4216 min(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4219 * Copy those bytes to the buffer
4222 StorageImpl_GetROBigBlock(This
->parentStorage
, blockIndex
);
4224 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
4226 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4229 * Step to the next big block.
4232 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4234 bufferWalker
+= bytesToReadInBuffer
;
4235 size
-= bytesToReadInBuffer
;
4236 *bytesRead
+= bytesToReadInBuffer
;
4237 offsetInBlock
= 0; /* There is no offset on the next block */
4244 /******************************************************************************
4245 * BlockChainStream_WriteAt
4247 * Writes the specified number of bytes to this chain at the specified offset.
4248 * bytesWritten may be NULL.
4249 * Will fail if not all specified number of bytes have been written.
4251 BOOL
BlockChainStream_WriteAt(BlockChainStream
* This
,
4252 ULARGE_INTEGER offset
,
4255 ULONG
* bytesWritten
)
4257 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4258 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4262 BYTE
* bigBlockBuffer
;
4265 * Find the first block in the stream that contains part of the buffer.
4267 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4268 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4269 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4271 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4272 This
->lastBlockNoInSequence
= blockNoInSequence
;
4276 ULONG temp
= blockNoInSequence
;
4278 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4279 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4280 This
->lastBlockNoInSequence
= temp
;
4283 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4286 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4288 blockNoInSequence
--;
4291 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4294 * Here, I'm casting away the constness on the buffer variable
4295 * This is OK since we don't intend to modify that buffer.
4298 bufferWalker
= (BYTE
*)buffer
;
4300 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4303 * Calculate how many bytes we can copy from this big block.
4306 min(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4309 * Copy those bytes to the buffer
4311 bigBlockBuffer
= StorageImpl_GetBigBlock(This
->parentStorage
, blockIndex
);
4313 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
4315 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4318 * Step to the next big block.
4321 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4323 bufferWalker
+= bytesToWrite
;
4324 size
-= bytesToWrite
;
4325 *bytesWritten
+= bytesToWrite
;
4326 offsetInBlock
= 0; /* There is no offset on the next block */
4332 /******************************************************************************
4333 * BlockChainStream_Shrink
4335 * Shrinks this chain in the big block depot.
4337 BOOL
BlockChainStream_Shrink(BlockChainStream
* This
,
4338 ULARGE_INTEGER newSize
)
4340 ULONG blockIndex
, extraBlock
;
4345 * Reset the last accessed block cache.
4347 This
->lastBlockNoInSequence
= 0xFFFFFFFF;
4348 This
->lastBlockNoInSequenceIndex
= BLOCK_END_OF_CHAIN
;
4351 * Figure out how many blocks are needed to contain the new size
4353 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4355 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4358 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4361 * Go to the new end of chain
4363 while (count
< numBlocks
)
4366 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4371 /* Get the next block before marking the new end */
4373 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4375 /* Mark the new end of chain */
4376 StorageImpl_SetNextBlockInChain(
4377 This
->parentStorage
,
4379 BLOCK_END_OF_CHAIN
);
4381 This
->tailIndex
= blockIndex
;
4382 This
->numBlocks
= numBlocks
;
4385 * Mark the extra blocks as free
4387 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4390 StorageImpl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4392 StorageImpl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4393 extraBlock
= blockIndex
;
4399 /******************************************************************************
4400 * BlockChainStream_Enlarge
4402 * Grows this chain in the big block depot.
4404 BOOL
BlockChainStream_Enlarge(BlockChainStream
* This
,
4405 ULARGE_INTEGER newSize
)
4407 ULONG blockIndex
, currentBlock
;
4409 ULONG oldNumBlocks
= 0;
4411 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4414 * Empty chain. Create the head.
4416 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4418 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4419 StorageImpl_SetNextBlockInChain(This
->parentStorage
,
4421 BLOCK_END_OF_CHAIN
);
4423 if (This
->headOfStreamPlaceHolder
!= 0)
4425 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4429 StgProperty chainProp
;
4430 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4432 StorageImpl_ReadProperty(
4433 This
->parentStorage
,
4434 This
->ownerPropertyIndex
,
4437 chainProp
.startingBlock
= blockIndex
;
4439 StorageImpl_WriteProperty(
4440 This
->parentStorage
,
4441 This
->ownerPropertyIndex
,
4445 This
->tailIndex
= blockIndex
;
4446 This
->numBlocks
= 1;
4450 * Figure out how many blocks are needed to contain this stream
4452 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4454 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4458 * Go to the current end of chain
4460 if (This
->tailIndex
== BLOCK_END_OF_CHAIN
)
4462 currentBlock
= blockIndex
;
4464 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4467 currentBlock
= blockIndex
;
4470 StorageImpl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4473 This
->tailIndex
= currentBlock
;
4476 currentBlock
= This
->tailIndex
;
4477 oldNumBlocks
= This
->numBlocks
;
4480 * Add new blocks to the chain
4482 if (oldNumBlocks
< newNumBlocks
)
4484 while (oldNumBlocks
< newNumBlocks
)
4486 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4488 StorageImpl_SetNextBlockInChain(
4489 This
->parentStorage
,
4493 StorageImpl_SetNextBlockInChain(
4494 This
->parentStorage
,
4496 BLOCK_END_OF_CHAIN
);
4498 currentBlock
= blockIndex
;
4502 This
->tailIndex
= blockIndex
;
4503 This
->numBlocks
= newNumBlocks
;
4509 /******************************************************************************
4510 * BlockChainStream_SetSize
4512 * Sets the size of this stream. The big block depot will be updated.
4513 * The file will grow if we grow the chain.
4515 * TODO: Free the actual blocks in the file when we shrink the chain.
4516 * Currently, the blocks are still in the file. So the file size
4517 * doesn't shrink even if we shrink streams.
4519 BOOL
BlockChainStream_SetSize(
4520 BlockChainStream
* This
,
4521 ULARGE_INTEGER newSize
)
4523 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4525 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
4528 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
4530 BlockChainStream_Shrink(This
, newSize
);
4534 ULARGE_INTEGER fileSize
=
4535 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4537 ULONG diff
= newSize
.s
.LowPart
- size
.s
.LowPart
;
4540 * Make sure the file stays a multiple of blocksize
4542 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4543 diff
+= (This
->parentStorage
->bigBlockSize
-
4544 (diff
% This
->parentStorage
->bigBlockSize
) );
4546 fileSize
.s
.LowPart
+= diff
;
4547 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4549 BlockChainStream_Enlarge(This
, newSize
);
4555 /******************************************************************************
4556 * BlockChainStream_GetSize
4558 * Returns the size of this chain.
4559 * Will return the block count if this chain doesn't have a property.
4561 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4563 StgProperty chainProperty
;
4565 if(This
->headOfStreamPlaceHolder
== NULL
)
4568 * This chain is a data stream read the property and return
4569 * the appropriate size
4571 StorageImpl_ReadProperty(
4572 This
->parentStorage
,
4573 This
->ownerPropertyIndex
,
4576 return chainProperty
.size
;
4581 * this chain is a chain that does not have a property, figure out the
4582 * size by making the product number of used blocks times the
4585 ULARGE_INTEGER result
;
4586 result
.s
.HighPart
= 0;
4589 BlockChainStream_GetCount(This
) *
4590 This
->parentStorage
->bigBlockSize
;
4596 /******************************************************************************
4597 ** SmallBlockChainStream implementation
4600 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4601 StorageImpl
* parentStorage
,
4602 ULONG propertyIndex
)
4604 SmallBlockChainStream
* newStream
;
4606 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4608 newStream
->parentStorage
= parentStorage
;
4609 newStream
->ownerPropertyIndex
= propertyIndex
;
4614 void SmallBlockChainStream_Destroy(
4615 SmallBlockChainStream
* This
)
4617 HeapFree(GetProcessHeap(), 0, This
);
4620 /******************************************************************************
4621 * SmallBlockChainStream_GetHeadOfChain
4623 * Returns the head of this chain of small blocks.
4625 ULONG
SmallBlockChainStream_GetHeadOfChain(
4626 SmallBlockChainStream
* This
)
4628 StgProperty chainProperty
;
4629 BOOL readSuccessful
;
4631 if (This
->ownerPropertyIndex
)
4633 readSuccessful
= StorageImpl_ReadProperty(
4634 This
->parentStorage
,
4635 This
->ownerPropertyIndex
,
4640 return chainProperty
.startingBlock
;
4645 return BLOCK_END_OF_CHAIN
;
4648 /******************************************************************************
4649 * SmallBlockChainStream_GetNextBlockInChain
4651 * Returns the index of the next small block in this chain.
4654 * - BLOCK_END_OF_CHAIN: end of this chain
4655 * - BLOCK_UNUSED: small block 'blockIndex' is free
4657 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4658 SmallBlockChainStream
* This
,
4661 ULARGE_INTEGER offsetOfBlockInDepot
;
4663 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4667 offsetOfBlockInDepot
.s
.HighPart
= 0;
4668 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4671 * Read those bytes in the buffer from the small block file.
4673 success
= BlockChainStream_ReadAt(
4674 This
->parentStorage
->smallBlockDepotChain
,
4675 offsetOfBlockInDepot
,
4682 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4685 return nextBlockInChain
;
4688 /******************************************************************************
4689 * SmallBlockChainStream_SetNextBlockInChain
4691 * Writes the index of the next block of the specified block in the small
4693 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4694 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4696 void SmallBlockChainStream_SetNextBlockInChain(
4697 SmallBlockChainStream
* This
,
4701 ULARGE_INTEGER offsetOfBlockInDepot
;
4705 offsetOfBlockInDepot
.s
.HighPart
= 0;
4706 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4708 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4711 * Read those bytes in the buffer from the small block file.
4713 BlockChainStream_WriteAt(
4714 This
->parentStorage
->smallBlockDepotChain
,
4715 offsetOfBlockInDepot
,
4721 /******************************************************************************
4722 * SmallBlockChainStream_FreeBlock
4724 * Flag small block 'blockIndex' as free in the small block depot.
4726 void SmallBlockChainStream_FreeBlock(
4727 SmallBlockChainStream
* This
,
4730 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4733 /******************************************************************************
4734 * SmallBlockChainStream_GetNextFreeBlock
4736 * Returns the index of a free small block. The small block depot will be
4737 * enlarged if necessary. The small block chain will also be enlarged if
4740 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4741 SmallBlockChainStream
* This
)
4743 ULARGE_INTEGER offsetOfBlockInDepot
;
4746 ULONG blockIndex
= 0;
4747 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4748 BOOL success
= TRUE
;
4749 ULONG smallBlocksPerBigBlock
;
4751 offsetOfBlockInDepot
.s
.HighPart
= 0;
4754 * Scan the small block depot for a free block
4756 while (nextBlockIndex
!= BLOCK_UNUSED
)
4758 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4760 success
= BlockChainStream_ReadAt(
4761 This
->parentStorage
->smallBlockDepotChain
,
4762 offsetOfBlockInDepot
,
4768 * If we run out of space for the small block depot, enlarge it
4772 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4774 if (nextBlockIndex
!= BLOCK_UNUSED
)
4780 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4782 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4783 ULONG nextBlock
, newsbdIndex
;
4784 BYTE
* smallBlockDepot
;
4786 nextBlock
= sbdIndex
;
4787 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4789 sbdIndex
= nextBlock
;
4791 StorageImpl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4794 newsbdIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4795 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4796 StorageImpl_SetNextBlockInChain(
4797 This
->parentStorage
,
4801 StorageImpl_SetNextBlockInChain(
4802 This
->parentStorage
,
4804 BLOCK_END_OF_CHAIN
);
4807 * Initialize all the small blocks to free
4810 StorageImpl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4812 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4813 StorageImpl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4818 * We have just created the small block depot.
4820 StgProperty rootProp
;
4824 * Save it in the header
4826 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4827 StorageImpl_SaveFileHeader(This
->parentStorage
);
4830 * And allocate the first big block that will contain small blocks
4833 StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4835 StorageImpl_SetNextBlockInChain(
4836 This
->parentStorage
,
4838 BLOCK_END_OF_CHAIN
);
4840 StorageImpl_ReadProperty(
4841 This
->parentStorage
,
4842 This
->parentStorage
->rootPropertySetIndex
,
4845 rootProp
.startingBlock
= sbStartIndex
;
4846 rootProp
.size
.s
.HighPart
= 0;
4847 rootProp
.size
.s
.LowPart
= This
->parentStorage
->bigBlockSize
;
4849 StorageImpl_WriteProperty(
4850 This
->parentStorage
,
4851 This
->parentStorage
->rootPropertySetIndex
,
4857 smallBlocksPerBigBlock
=
4858 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4861 * Verify if we have to allocate big blocks to contain small blocks
4863 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4865 StgProperty rootProp
;
4866 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4868 StorageImpl_ReadProperty(
4869 This
->parentStorage
,
4870 This
->parentStorage
->rootPropertySetIndex
,
4873 if (rootProp
.size
.s
.LowPart
<
4874 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4876 rootProp
.size
.s
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4878 BlockChainStream_SetSize(
4879 This
->parentStorage
->smallBlockRootChain
,
4882 StorageImpl_WriteProperty(
4883 This
->parentStorage
,
4884 This
->parentStorage
->rootPropertySetIndex
,
4892 /******************************************************************************
4893 * SmallBlockChainStream_ReadAt
4895 * Reads a specified number of bytes from this chain at the specified offset.
4896 * bytesRead may be NULL.
4897 * Failure will be returned if the specified number of bytes has not been read.
4899 BOOL
SmallBlockChainStream_ReadAt(
4900 SmallBlockChainStream
* This
,
4901 ULARGE_INTEGER offset
,
4906 ULARGE_INTEGER offsetInBigBlockFile
;
4907 ULONG blockNoInSequence
=
4908 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4910 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
4911 ULONG bytesToReadInBuffer
;
4913 ULONG bytesReadFromBigBlockFile
;
4917 * This should never happen on a small block file.
4919 assert(offset
.s
.HighPart
==0);
4922 * Find the first block in the stream that contains part of the buffer.
4924 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
4926 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4928 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4930 blockNoInSequence
--;
4934 * Start reading the buffer.
4937 bufferWalker
= buffer
;
4939 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4942 * Calculate how many bytes we can copy from this small block.
4944 bytesToReadInBuffer
=
4945 min(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
4948 * Calculate the offset of the small block in the small block file.
4950 offsetInBigBlockFile
.s
.HighPart
= 0;
4951 offsetInBigBlockFile
.s
.LowPart
=
4952 blockIndex
* This
->parentStorage
->smallBlockSize
;
4954 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
4957 * Read those bytes in the buffer from the small block file.
4959 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
4960 offsetInBigBlockFile
,
4961 bytesToReadInBuffer
,
4963 &bytesReadFromBigBlockFile
);
4965 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
4968 * Step to the next big block.
4970 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
4971 bufferWalker
+= bytesToReadInBuffer
;
4972 size
-= bytesToReadInBuffer
;
4973 *bytesRead
+= bytesToReadInBuffer
;
4974 offsetInBlock
= 0; /* There is no offset on the next block */
4980 /******************************************************************************
4981 * SmallBlockChainStream_WriteAt
4983 * Writes the specified number of bytes to this chain at the specified offset.
4984 * bytesWritten may be NULL.
4985 * Will fail if not all specified number of bytes have been written.
4987 BOOL
SmallBlockChainStream_WriteAt(
4988 SmallBlockChainStream
* This
,
4989 ULARGE_INTEGER offset
,
4992 ULONG
* bytesWritten
)
4994 ULARGE_INTEGER offsetInBigBlockFile
;
4995 ULONG blockNoInSequence
=
4996 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4998 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
4999 ULONG bytesToWriteInBuffer
;
5001 ULONG bytesWrittenFromBigBlockFile
;
5005 * This should never happen on a small block file.
5007 assert(offset
.s
.HighPart
==0);
5010 * Find the first block in the stream that contains part of the buffer.
5012 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5014 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
5016 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5018 blockNoInSequence
--;
5022 * Start writing the buffer.
5024 * Here, I'm casting away the constness on the buffer variable
5025 * This is OK since we don't intend to modify that buffer.
5028 bufferWalker
= (BYTE
*)buffer
;
5029 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
5032 * Calculate how many bytes we can copy to this small block.
5034 bytesToWriteInBuffer
=
5035 min(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
5038 * Calculate the offset of the small block in the small block file.
5040 offsetInBigBlockFile
.s
.HighPart
= 0;
5041 offsetInBigBlockFile
.s
.LowPart
=
5042 blockIndex
* This
->parentStorage
->smallBlockSize
;
5044 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
5047 * Write those bytes in the buffer to the small block file.
5049 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
5050 offsetInBigBlockFile
,
5051 bytesToWriteInBuffer
,
5053 &bytesWrittenFromBigBlockFile
);
5055 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
5058 * Step to the next big block.
5060 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5061 bufferWalker
+= bytesToWriteInBuffer
;
5062 size
-= bytesToWriteInBuffer
;
5063 *bytesWritten
+= bytesToWriteInBuffer
;
5064 offsetInBlock
= 0; /* There is no offset on the next block */
5070 /******************************************************************************
5071 * SmallBlockChainStream_Shrink
5073 * Shrinks this chain in the small block depot.
5075 BOOL
SmallBlockChainStream_Shrink(
5076 SmallBlockChainStream
* This
,
5077 ULARGE_INTEGER newSize
)
5079 ULONG blockIndex
, extraBlock
;
5083 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5085 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5088 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5091 * Go to the new end of chain
5093 while (count
< numBlocks
)
5095 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5100 * If the count is 0, we have a special case, the head of the chain was
5105 StgProperty chainProp
;
5107 StorageImpl_ReadProperty(This
->parentStorage
,
5108 This
->ownerPropertyIndex
,
5111 chainProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
5113 StorageImpl_WriteProperty(This
->parentStorage
,
5114 This
->ownerPropertyIndex
,
5118 * We start freeing the chain at the head block.
5120 extraBlock
= blockIndex
;
5124 /* Get the next block before marking the new end */
5125 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5127 /* Mark the new end of chain */
5128 SmallBlockChainStream_SetNextBlockInChain(
5131 BLOCK_END_OF_CHAIN
);
5135 * Mark the extra blocks as free
5137 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
5139 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
5140 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
5141 extraBlock
= blockIndex
;
5147 /******************************************************************************
5148 * SmallBlockChainStream_Enlarge
5150 * Grows this chain in the small block depot.
5152 BOOL
SmallBlockChainStream_Enlarge(
5153 SmallBlockChainStream
* This
,
5154 ULARGE_INTEGER newSize
)
5156 ULONG blockIndex
, currentBlock
;
5158 ULONG oldNumBlocks
= 0;
5160 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5165 if (blockIndex
== BLOCK_END_OF_CHAIN
)
5168 StgProperty chainProp
;
5170 StorageImpl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5173 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
5175 StorageImpl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5178 blockIndex
= chainProp
.startingBlock
;
5179 SmallBlockChainStream_SetNextBlockInChain(
5182 BLOCK_END_OF_CHAIN
);
5185 currentBlock
= blockIndex
;
5188 * Figure out how many blocks are needed to contain this stream
5190 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5192 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5196 * Go to the current end of chain
5198 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5201 currentBlock
= blockIndex
;
5202 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
5206 * Add new blocks to the chain
5208 while (oldNumBlocks
< newNumBlocks
)
5210 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
5211 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
5213 SmallBlockChainStream_SetNextBlockInChain(
5216 BLOCK_END_OF_CHAIN
);
5218 currentBlock
= blockIndex
;
5225 /******************************************************************************
5226 * SmallBlockChainStream_GetCount
5228 * Returns the number of blocks that comprises this chain.
5229 * This is not the size of this chain as the last block may not be full!
5231 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
5236 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5238 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5242 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5248 /******************************************************************************
5249 * SmallBlockChainStream_SetSize
5251 * Sets the size of this stream.
5252 * The file will grow if we grow the chain.
5254 * TODO: Free the actual blocks in the file when we shrink the chain.
5255 * Currently, the blocks are still in the file. So the file size
5256 * doesn't shrink even if we shrink streams.
5258 BOOL
SmallBlockChainStream_SetSize(
5259 SmallBlockChainStream
* This
,
5260 ULARGE_INTEGER newSize
)
5262 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
5264 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
5267 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
5269 SmallBlockChainStream_Shrink(This
, newSize
);
5273 SmallBlockChainStream_Enlarge(This
, newSize
);
5279 /******************************************************************************
5280 * SmallBlockChainStream_GetSize
5282 * Returns the size of this chain.
5284 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
5286 StgProperty chainProperty
;
5288 StorageImpl_ReadProperty(
5289 This
->parentStorage
,
5290 This
->ownerPropertyIndex
,
5293 return chainProperty
.size
;
5296 /******************************************************************************
5297 * StgCreateDocfile [OLE32.144]
5299 HRESULT WINAPI
StgCreateDocfile(
5303 IStorage
**ppstgOpen
)
5305 StorageImpl
* newStorage
= 0;
5306 HANDLE hFile
= INVALID_HANDLE_VALUE
;
5311 DWORD fileAttributes
;
5312 WCHAR tempFileName
[MAX_PATH
];
5314 TRACE("(%s, %lx, %ld, %p)\n",
5315 debugstr_w(pwcsName
), grfMode
,
5316 reserved
, ppstgOpen
);
5319 * Validate the parameters
5322 return STG_E_INVALIDPOINTER
;
5325 * Validate the STGM flags
5327 if ( FAILED( validateSTGM(grfMode
) ))
5328 return STG_E_INVALIDFLAG
;
5331 * Generate a unique name.
5335 WCHAR tempPath
[MAX_PATH
];
5336 WCHAR prefix
[] = { 'S', 'T', 'O', 0 };
5338 if (!(grfMode
& STGM_SHARE_EXCLUSIVE
))
5339 return STG_E_INVALIDFLAG
;
5340 if (!(grfMode
& (STGM_WRITE
|STGM_READWRITE
)))
5341 return STG_E_INVALIDFLAG
;
5343 memset(tempPath
, 0, sizeof(tempPath
));
5344 memset(tempFileName
, 0, sizeof(tempFileName
));
5346 if ((GetTempPathW(MAX_PATH
, tempPath
)) == 0 )
5349 if (GetTempFileNameW(tempPath
, prefix
, 0, tempFileName
) != 0)
5350 pwcsName
= tempFileName
;
5352 return STG_E_INSUFFICIENTMEMORY
;
5354 creationMode
= TRUNCATE_EXISTING
;
5358 creationMode
= GetCreationModeFromSTGM(grfMode
);
5362 * Interpret the STGM value grfMode
5364 shareMode
= GetShareModeFromSTGM(grfMode
);
5365 accessMode
= GetAccessModeFromSTGM(grfMode
);
5367 if (grfMode
& STGM_DELETEONRELEASE
)
5368 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
5370 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
5372 if (grfMode
& STGM_TRANSACTED
)
5373 FIXME("Transacted mode not implemented.\n");
5376 * Initialize the "out" parameter.
5380 hFile
= CreateFileW(pwcsName
,
5388 if (hFile
== INVALID_HANDLE_VALUE
)
5394 * Allocate and initialize the new IStorage32object.
5396 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5398 if (newStorage
== 0)
5399 return STG_E_INSUFFICIENTMEMORY
;
5401 hr
= StorageImpl_Construct(
5412 HeapFree(GetProcessHeap(), 0, newStorage
);
5417 * Get an "out" pointer for the caller.
5419 hr
= StorageBaseImpl_QueryInterface(
5420 (IStorage
*)newStorage
,
5421 (REFIID
)&IID_IStorage
,
5427 /******************************************************************************
5428 * StgOpenStorage [OLE32.148]
5430 HRESULT WINAPI
StgOpenStorage(
5431 const OLECHAR
*pwcsName
,
5432 IStorage
*pstgPriority
,
5436 IStorage
**ppstgOpen
)
5438 StorageImpl
* newStorage
= 0;
5444 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5445 debugstr_w(pwcsName
), pstgPriority
, grfMode
,
5446 snbExclude
, reserved
, ppstgOpen
);
5449 * Perform a sanity check
5451 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
5452 return STG_E_INVALIDPOINTER
;
5455 * Validate the STGM flags
5457 if ( FAILED( validateSTGM(grfMode
) ))
5458 return STG_E_INVALIDFLAG
;
5461 * Interpret the STGM value grfMode
5463 shareMode
= GetShareModeFromSTGM(grfMode
);
5464 accessMode
= GetAccessModeFromSTGM(grfMode
);
5467 * Initialize the "out" parameter.
5471 hFile
= CreateFileW( pwcsName
,
5476 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5480 if (hFile
==INVALID_HANDLE_VALUE
)
5482 HRESULT hr
= E_FAIL
;
5483 DWORD last_error
= GetLastError();
5487 case ERROR_FILE_NOT_FOUND
:
5488 hr
= STG_E_FILENOTFOUND
;
5491 case ERROR_PATH_NOT_FOUND
:
5492 hr
= STG_E_PATHNOTFOUND
;
5495 case ERROR_ACCESS_DENIED
:
5496 case ERROR_WRITE_PROTECT
:
5497 hr
= STG_E_ACCESSDENIED
;
5500 case ERROR_SHARING_VIOLATION
:
5501 hr
= STG_E_SHAREVIOLATION
;
5512 * Allocate and initialize the new IStorage32object.
5514 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5516 if (newStorage
== 0)
5517 return STG_E_INSUFFICIENTMEMORY
;
5519 hr
= StorageImpl_Construct(
5530 HeapFree(GetProcessHeap(), 0, newStorage
);
5532 * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
5534 if(hr
== STG_E_INVALIDHEADER
)
5535 return STG_E_FILEALREADYEXISTS
;
5540 * Get an "out" pointer for the caller.
5542 hr
= StorageBaseImpl_QueryInterface(
5543 (IStorage
*)newStorage
,
5544 (REFIID
)&IID_IStorage
,
5550 /******************************************************************************
5551 * StgCreateDocfileOnILockBytes [OLE32.145]
5553 HRESULT WINAPI
StgCreateDocfileOnILockBytes(
5557 IStorage
** ppstgOpen
)
5559 StorageImpl
* newStorage
= 0;
5563 * Validate the parameters
5565 if ((ppstgOpen
== 0) || (plkbyt
== 0))
5566 return STG_E_INVALIDPOINTER
;
5569 * Allocate and initialize the new IStorage object.
5571 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5573 if (newStorage
== 0)
5574 return STG_E_INSUFFICIENTMEMORY
;
5576 hr
= StorageImpl_Construct(
5587 HeapFree(GetProcessHeap(), 0, newStorage
);
5592 * Get an "out" pointer for the caller.
5594 hr
= StorageBaseImpl_QueryInterface(
5595 (IStorage
*)newStorage
,
5596 (REFIID
)&IID_IStorage
,
5602 /******************************************************************************
5603 * StgOpenStorageOnILockBytes [OLE32.149]
5605 HRESULT WINAPI
StgOpenStorageOnILockBytes(
5607 IStorage
*pstgPriority
,
5611 IStorage
**ppstgOpen
)
5613 StorageImpl
* newStorage
= 0;
5617 * Perform a sanity check
5619 if ((plkbyt
== 0) || (ppstgOpen
== 0))
5620 return STG_E_INVALIDPOINTER
;
5623 * Validate the STGM flags
5625 if ( FAILED( validateSTGM(grfMode
) ))
5626 return STG_E_INVALIDFLAG
;
5629 * Initialize the "out" parameter.
5634 * Allocate and initialize the new IStorage object.
5636 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5638 if (newStorage
== 0)
5639 return STG_E_INSUFFICIENTMEMORY
;
5641 hr
= StorageImpl_Construct(
5652 HeapFree(GetProcessHeap(), 0, newStorage
);
5657 * Get an "out" pointer for the caller.
5659 hr
= StorageBaseImpl_QueryInterface(
5660 (IStorage
*)newStorage
,
5661 (REFIID
)&IID_IStorage
,
5667 /******************************************************************************
5668 * StgSetTimes [ole32.150]
5669 * StgSetTimes [OLE32.150]
5673 HRESULT WINAPI
StgSetTimes(OLECHAR
*str
, FILETIME
*a
, FILETIME
*b
, FILETIME
*c
)
5675 FIXME("(%s, %p, %p, %p),stub!\n", debugstr_w(str
), a
, b
, c
);
5679 /******************************************************************************
5680 * StgIsStorageILockBytes [OLE32.147]
5682 * Determines if the ILockBytes contains a storage object.
5684 HRESULT WINAPI
StgIsStorageILockBytes(ILockBytes
*plkbyt
)
5687 ULARGE_INTEGER offset
;
5689 offset
.s
.HighPart
= 0;
5690 offset
.s
.LowPart
= 0;
5692 ILockBytes_ReadAt(plkbyt
, offset
, sig
, sizeof(sig
), NULL
);
5694 if (memcmp(sig
, STORAGE_magic
, sizeof(STORAGE_magic
)) == 0)
5700 /******************************************************************************
5701 * WriteClassStg [OLE32.158]
5703 * This method will store the specified CLSID in the specified storage object
5705 HRESULT WINAPI
WriteClassStg(IStorage
* pStg
, REFCLSID rclsid
)
5711 hRes
= IStorage_SetClass(pStg
, rclsid
);
5716 /***********************************************************************
5717 * ReadClassStg (OLE32.134)
5719 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5721 HRESULT WINAPI
ReadClassStg(IStorage
*pstg
,CLSID
*pclsid
){
5731 * read a STATSTG structure (contains the clsid) from the storage
5733 hRes
=IStorage_Stat(pstg
,&pstatstg
,STATFLAG_DEFAULT
);
5736 *pclsid
=pstatstg
.clsid
;
5741 /***********************************************************************
5742 * OleLoadFromStream (OLE32.113)
5744 * This function loads an object from stream
5746 HRESULT WINAPI
OleLoadFromStream(IStream
*pStm
,REFIID iidInterface
,void** ppvObj
)
5750 LPPERSISTSTREAM xstm
;
5752 TRACE("(%p,%s,%p)\n",pStm
,debugstr_guid(iidInterface
),ppvObj
);
5754 res
=ReadClassStm(pStm
,&clsid
);
5755 if (!SUCCEEDED(res
))
5757 res
=CoCreateInstance(&clsid
,NULL
,CLSCTX_INPROC_SERVER
,iidInterface
,ppvObj
);
5758 if (!SUCCEEDED(res
))
5760 res
=IUnknown_QueryInterface((IUnknown
*)*ppvObj
,&IID_IPersistStream
,(LPVOID
*)&xstm
);
5761 if (!SUCCEEDED(res
)) {
5762 IUnknown_Release((IUnknown
*)*ppvObj
);
5765 res
=IPersistStream_Load(xstm
,pStm
);
5766 IPersistStream_Release(xstm
);
5767 /* FIXME: all refcounts ok at this point? I think they should be:
5770 * xstm : 0 (released)
5775 /***********************************************************************
5776 * OleSaveToStream (OLE32.125)
5778 * This function saves an object with the IPersistStream interface on it
5779 * to the specified stream.
5781 HRESULT WINAPI
OleSaveToStream(IPersistStream
*pPStm
,IStream
*pStm
)
5787 TRACE("(%p,%p)\n",pPStm
,pStm
);
5789 res
=IPersistStream_GetClassID(pPStm
,&clsid
);
5791 if (SUCCEEDED(res
)){
5793 res
=WriteClassStm(pStm
,&clsid
);
5797 res
=IPersistStream_Save(pPStm
,pStm
,TRUE
);
5800 TRACE("Finished Save\n");
5804 /****************************************************************************
5805 * This method validate a STGM parameter that can contain the values below
5807 * STGM_DIRECT 0x00000000
5808 * STGM_TRANSACTED 0x00010000
5809 * STGM_SIMPLE 0x08000000
5811 * STGM_READ 0x00000000
5812 * STGM_WRITE 0x00000001
5813 * STGM_READWRITE 0x00000002
5815 * STGM_SHARE_DENY_NONE 0x00000040
5816 * STGM_SHARE_DENY_READ 0x00000030
5817 * STGM_SHARE_DENY_WRITE 0x00000020
5818 * STGM_SHARE_EXCLUSIVE 0x00000010
5820 * STGM_PRIORITY 0x00040000
5821 * STGM_DELETEONRELEASE 0x04000000
5823 * STGM_CREATE 0x00001000
5824 * STGM_CONVERT 0x00020000
5825 * STGM_FAILIFTHERE 0x00000000
5827 * STGM_NOSCRATCH 0x00100000
5828 * STGM_NOSNAPSHOT 0x00200000
5830 static HRESULT
validateSTGM(DWORD stgm
)
5832 BOOL bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5833 BOOL bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5834 BOOL bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5836 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5837 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5838 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5840 BOOL bSTGM_SHARE_DENY_NONE
=
5841 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5843 BOOL bSTGM_SHARE_DENY_READ
=
5844 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5846 BOOL bSTGM_SHARE_DENY_WRITE
=
5847 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5849 BOOL bSTGM_SHARE_EXCLUSIVE
=
5850 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5852 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5853 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5855 BOOL bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5856 BOOL bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5859 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5861 if ( ! bSTGM_DIRECT
)
5862 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5866 * STGM_WRITE | STGM_READWRITE | STGM_READ
5869 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5873 * STGM_SHARE_DENY_NONE | others
5874 * (I assume here that DENY_READ implies DENY_WRITE)
5876 if ( bSTGM_SHARE_DENY_NONE
)
5877 if ( bSTGM_SHARE_DENY_READ
||
5878 bSTGM_SHARE_DENY_WRITE
||
5879 bSTGM_SHARE_EXCLUSIVE
)
5883 * STGM_CREATE | STGM_CONVERT
5884 * if both are false, STGM_FAILIFTHERE is set to TRUE
5886 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5890 * STGM_NOSCRATCH requires STGM_TRANSACTED
5892 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5896 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5897 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5899 if (bSTGM_NOSNAPSHOT
)
5901 if ( ! ( bSTGM_TRANSACTED
&&
5902 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
5909 /****************************************************************************
5910 * GetShareModeFromSTGM
5912 * This method will return a share mode flag from a STGM value.
5913 * The STGM value is assumed valid.
5915 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
5917 DWORD dwShareMode
= 0;
5918 BOOL bSTGM_SHARE_DENY_NONE
=
5919 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5921 BOOL bSTGM_SHARE_DENY_READ
=
5922 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5924 BOOL bSTGM_SHARE_DENY_WRITE
=
5925 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5927 BOOL bSTGM_SHARE_EXCLUSIVE
=
5928 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5930 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
5933 if (bSTGM_SHARE_DENY_NONE
)
5934 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
5936 if (bSTGM_SHARE_DENY_WRITE
)
5937 dwShareMode
= FILE_SHARE_READ
;
5942 /****************************************************************************
5943 * GetAccessModeFromSTGM
5945 * This method will return an access mode flag from a STGM value.
5946 * The STGM value is assumed valid.
5948 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
5950 DWORD dwDesiredAccess
= GENERIC_READ
;
5951 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5952 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5953 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5956 dwDesiredAccess
= GENERIC_READ
;
5959 dwDesiredAccess
|= GENERIC_WRITE
;
5961 if (bSTGM_READWRITE
)
5962 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
5964 return dwDesiredAccess
;
5967 /****************************************************************************
5968 * GetCreationModeFromSTGM
5970 * This method will return a creation mode flag from a STGM value.
5971 * The STGM value is assumed valid.
5973 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
5975 if ( stgm
& STGM_CREATE
)
5976 return CREATE_ALWAYS
;
5977 if (stgm
& STGM_CONVERT
) {
5978 FIXME("STGM_CONVERT not implemented!\n");
5981 /* All other cases */
5982 if (stgm
& ~ (STGM_CREATE
|STGM_CONVERT
))
5983 FIXME("unhandled storage mode : 0x%08lx\n",stgm
& ~ (STGM_CREATE
|STGM_CONVERT
));
5988 /*************************************************************************
5989 * OLECONVERT_LoadOLE10 [Internal]
5991 * Loads the OLE10 STREAM to memory
5994 * pOleStream [I] The OLESTREAM
5995 * pData [I] Data Structure for the OLESTREAM Data
5999 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
6000 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6003 * This function is used by OleConvertOLESTREAMToIStorage only.
6005 * Memory allocated for pData must be freed by the caller
6007 HRESULT
OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream
, OLECONVERT_OLESTREAM_DATA
*pData
, BOOL bStrem1
)
6010 HRESULT hRes
= S_OK
;
6014 pData
->pData
= NULL
;
6015 pData
->pstrOleObjFileName
= (CHAR
*) NULL
;
6017 for( nTryCnt
=0;nTryCnt
< max_try
; nTryCnt
++)
6020 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwOleID
), sizeof(pData
->dwOleID
));
6021 if(dwSize
!= sizeof(pData
->dwOleID
))
6023 hRes
= CONVERT10_E_OLESTREAM_GET
;
6025 else if(pData
->dwOleID
!= OLESTREAM_ID
)
6027 hRes
= CONVERT10_E_OLESTREAM_FMT
;
6038 /* Get the TypeID...more info needed for this field */
6039 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwTypeID
), sizeof(pData
->dwTypeID
));
6040 if(dwSize
!= sizeof(pData
->dwTypeID
))
6042 hRes
= CONVERT10_E_OLESTREAM_GET
;
6047 if(pData
->dwTypeID
!= 0)
6049 /* Get the lenght of the OleTypeName */
6050 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *) &(pData
->dwOleTypeNameLength
), sizeof(pData
->dwOleTypeNameLength
));
6051 if(dwSize
!= sizeof(pData
->dwOleTypeNameLength
))
6053 hRes
= CONVERT10_E_OLESTREAM_GET
;
6058 if(pData
->dwOleTypeNameLength
> 0)
6060 /* Get the OleTypeName */
6061 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)pData
->strOleTypeName
, pData
->dwOleTypeNameLength
);
6062 if(dwSize
!= pData
->dwOleTypeNameLength
)
6064 hRes
= CONVERT10_E_OLESTREAM_GET
;
6070 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwOleObjFileNameLength
), sizeof(pData
->dwOleObjFileNameLength
));
6071 if(dwSize
!= sizeof(pData
->dwOleObjFileNameLength
))
6073 hRes
= CONVERT10_E_OLESTREAM_GET
;
6077 if(pData
->dwOleObjFileNameLength
< 1) /* there is no file name exist */
6078 pData
->dwOleObjFileNameLength
= sizeof(pData
->dwOleObjFileNameLength
);
6079 pData
->pstrOleObjFileName
= (CHAR
*)malloc(pData
->dwOleObjFileNameLength
);
6080 if(pData
->pstrOleObjFileName
)
6082 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)(pData
->pstrOleObjFileName
),pData
->dwOleObjFileNameLength
);
6083 if(dwSize
!= pData
->dwOleObjFileNameLength
)
6085 hRes
= CONVERT10_E_OLESTREAM_GET
;
6089 hRes
= CONVERT10_E_OLESTREAM_GET
;
6094 /* Get the Width of the Metafile */
6095 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwMetaFileWidth
), sizeof(pData
->dwMetaFileWidth
));
6096 if(dwSize
!= sizeof(pData
->dwMetaFileWidth
))
6098 hRes
= CONVERT10_E_OLESTREAM_GET
;
6102 /* Get the Height of the Metafile */
6103 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwMetaFileHeight
), sizeof(pData
->dwMetaFileHeight
));
6104 if(dwSize
!= sizeof(pData
->dwMetaFileHeight
))
6106 hRes
= CONVERT10_E_OLESTREAM_GET
;
6112 /* Get the Lenght of the Data */
6113 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwDataLength
), sizeof(pData
->dwDataLength
));
6114 if(dwSize
!= sizeof(pData
->dwDataLength
))
6116 hRes
= CONVERT10_E_OLESTREAM_GET
;
6120 if(hRes
== S_OK
) /* I don't know what is this 8 byts information is we have to figure out */
6122 if(!bStrem1
) /* if it is a second OLE stream data */
6124 pData
->dwDataLength
-= 8;
6125 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)(pData
->strUnknown
), sizeof(pData
->strUnknown
));
6126 if(dwSize
!= sizeof(pData
->strUnknown
))
6128 hRes
= CONVERT10_E_OLESTREAM_GET
;
6134 if(pData
->dwDataLength
> 0)
6136 pData
->pData
= (BYTE
*)HeapAlloc(GetProcessHeap(),0,pData
->dwDataLength
);
6138 /* Get Data (ex. IStorage, Metafile, or BMP) */
6141 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)pData
->pData
, pData
->dwDataLength
);
6142 if(dwSize
!= pData
->dwDataLength
)
6144 hRes
= CONVERT10_E_OLESTREAM_GET
;
6149 hRes
= CONVERT10_E_OLESTREAM_GET
;
6158 /*************************************************************************
6159 * OLECONVERT_SaveOLE10 [Internal]
6161 * Saves the OLE10 STREAM From memory
6164 * pData [I] Data Structure for the OLESTREAM Data
6165 * pOleStream [I] The OLESTREAM to save
6169 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6172 * This function is used by OleConvertIStorageToOLESTREAM only.
6175 HRESULT
OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA
*pData
, LPOLESTREAM pOleStream
)
6178 HRESULT hRes
= S_OK
;
6182 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwOleID
), sizeof(pData
->dwOleID
));
6183 if(dwSize
!= sizeof(pData
->dwOleID
))
6185 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6190 /* Set the TypeID */
6191 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwTypeID
), sizeof(pData
->dwTypeID
));
6192 if(dwSize
!= sizeof(pData
->dwTypeID
))
6194 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6198 if(pData
->dwOleID
== OLESTREAM_ID
&& pData
->dwTypeID
!= 0 && hRes
== S_OK
)
6200 /* Set the Lenght of the OleTypeName */
6201 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwOleTypeNameLength
), sizeof(pData
->dwOleTypeNameLength
));
6202 if(dwSize
!= sizeof(pData
->dwOleTypeNameLength
))
6204 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6209 if(pData
->dwOleTypeNameLength
> 0)
6211 /* Set the OleTypeName */
6212 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *) pData
->strOleTypeName
, pData
->dwOleTypeNameLength
);
6213 if(dwSize
!= pData
->dwOleTypeNameLength
)
6215 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6222 /* Set the width of the Metafile */
6223 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwMetaFileWidth
), sizeof(pData
->dwMetaFileWidth
));
6224 if(dwSize
!= sizeof(pData
->dwMetaFileWidth
))
6226 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6232 /* Set the height of the Metafile */
6233 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwMetaFileHeight
), sizeof(pData
->dwMetaFileHeight
));
6234 if(dwSize
!= sizeof(pData
->dwMetaFileHeight
))
6236 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6242 /* Set the lenght of the Data */
6243 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwDataLength
), sizeof(pData
->dwDataLength
));
6244 if(dwSize
!= sizeof(pData
->dwDataLength
))
6246 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6252 if(pData
->dwDataLength
> 0)
6254 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6255 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *) pData
->pData
, pData
->dwDataLength
);
6256 if(dwSize
!= pData
->dwDataLength
)
6258 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6266 /*************************************************************************
6267 * OLECONVERT_GetOLE20FromOLE10[Internal]
6269 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6270 * opens it, and copies the content to the dest IStorage for
6271 * OleConvertOLESTREAMToIStorage
6275 * pDestStorage [I] The IStorage to copy the data to
6276 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
6277 * nBufferLength [I] The size of the buffer
6286 void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage
, BYTE
*pBuffer
, DWORD nBufferLength
)
6290 IStorage
*pTempStorage
;
6291 DWORD dwNumOfBytesWritten
;
6292 WCHAR wstrTempDir
[MAX_PATH
], wstrTempFile
[MAX_PATH
];
6293 WCHAR wstrPrefix
[] = {'s', 'i', 's', 0};
6295 /* Create a temp File */
6296 GetTempPathW(MAX_PATH
, wstrTempDir
);
6297 GetTempFileNameW(wstrTempDir
, wstrPrefix
, 0, wstrTempFile
);
6298 hFile
= CreateFileW(wstrTempFile
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
6300 if(hFile
!= INVALID_HANDLE_VALUE
)
6302 /* Write IStorage Data to File */
6303 WriteFile(hFile
, pBuffer
, nBufferLength
, &dwNumOfBytesWritten
, NULL
);
6306 /* Open and copy temp storage to the Dest Storage */
6307 hRes
= StgOpenStorage(wstrTempFile
, NULL
, STGM_READ
, NULL
, 0, &pTempStorage
);
6310 hRes
= StorageImpl_CopyTo(pTempStorage
, 0, NULL
, NULL
, pDestStorage
);
6311 StorageBaseImpl_Release(pTempStorage
);
6313 DeleteFileW(wstrTempFile
);
6318 /*************************************************************************
6319 * OLECONVERT_WriteOLE20ToBuffer [Internal]
6321 * Saves the OLE10 STREAM From memory
6324 * pStorage [I] The Src IStorage to copy
6325 * pData [I] The Dest Memory to write to.
6328 * The size in bytes allocated for pData
6331 * Memory allocated for pData must be freed by the caller
6333 * Used by OleConvertIStorageToOLESTREAM only.
6336 DWORD
OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage
, BYTE
**pData
)
6340 DWORD nDataLength
= 0;
6341 IStorage
*pTempStorage
;
6342 WCHAR wstrTempDir
[MAX_PATH
], wstrTempFile
[MAX_PATH
];
6343 WCHAR wstrPrefix
[] = {'s', 'i', 's', 0};
6347 /* Create temp Storage */
6348 GetTempPathW(MAX_PATH
, wstrTempDir
);
6349 GetTempFileNameW(wstrTempDir
, wstrPrefix
, 0, wstrTempFile
);
6350 hRes
= StgCreateDocfile(wstrTempFile
, STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
, 0, &pTempStorage
);
6354 /* Copy Src Storage to the Temp Storage */
6355 StorageImpl_CopyTo(pStorage
, 0, NULL
, NULL
, pTempStorage
);
6356 StorageBaseImpl_Release(pTempStorage
);
6358 /* Open Temp Storage as a file and copy to memory */
6359 hFile
= CreateFileW(wstrTempFile
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
6360 if(hFile
!= INVALID_HANDLE_VALUE
)
6362 nDataLength
= GetFileSize(hFile
, NULL
);
6363 *pData
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,nDataLength
);
6364 ReadFile(hFile
, *pData
, nDataLength
, &nDataLength
, 0);
6367 DeleteFileW(wstrTempFile
);
6372 /*************************************************************************
6373 * OLECONVERT_CreateOleStream [Internal]
6375 * Creates the "\001OLE" stream in the IStorage if neccessary.
6378 * pStorage [I] Dest storage to create the stream in
6384 * This function is used by OleConvertOLESTREAMToIStorage only.
6386 * This stream is still unknown, MS Word seems to have extra data
6387 * but since the data is stored in the OLESTREAM there should be
6388 * no need to recreate the stream. If the stream is manually
6389 * deleted it will create it with this default data.
6392 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage
)
6396 WCHAR wstrStreamName
[] = {1,'O', 'l', 'e', 0};
6397 BYTE pOleStreamHeader
[] =
6399 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6401 0x00, 0x00, 0x00, 0x00
6404 /* Create stream if not present */
6405 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6406 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6410 /* Write default Data */
6411 hRes
= IStream_Write(pStream
, pOleStreamHeader
, sizeof(pOleStreamHeader
), NULL
);
6412 IStream_Release(pStream
);
6417 /*************************************************************************
6418 * OLECONVERT_CreateCompObjStream [Internal]
6420 * Creates a "\001CompObj" is the destination IStorage if necessary.
6423 * pStorage [I] The dest IStorage to create the CompObj Stream
6425 * strOleTypeName [I] The ProgID
6429 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6432 * This function is used by OleConvertOLESTREAMToIStorage only.
6434 * The stream data is stored in the OLESTREAM and there should be
6435 * no need to recreate the stream. If the stream is manually
6436 * deleted it will attempt to create it by querying the registry.
6440 HRESULT
OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage
, LPCSTR strOleTypeName
)
6443 HRESULT hStorageRes
, hRes
= S_OK
;
6444 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj
;
6445 WCHAR wstrStreamName
[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6447 BYTE pCompObjUnknown1
[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
6448 BYTE pCompObjUnknown2
[] = {0xF4, 0x39, 0xB2, 0x71};
6450 /* Initialize the CompObj structure */
6451 memset(&IStorageCompObj
, 0, sizeof(IStorageCompObj
));
6452 memcpy(&(IStorageCompObj
.byUnknown1
), pCompObjUnknown1
, sizeof(pCompObjUnknown1
));
6453 memcpy(&(IStorageCompObj
.byUnknown2
), pCompObjUnknown2
, sizeof(pCompObjUnknown2
));
6456 /* Create a CompObj stream if it doesn't exist */
6457 hStorageRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6458 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6459 if(hStorageRes
== S_OK
)
6461 /* copy the OleTypeName to the compobj struct */
6462 IStorageCompObj
.dwOleTypeNameLength
= strlen(strOleTypeName
)+1;
6463 strcpy(IStorageCompObj
.strOleTypeName
, strOleTypeName
);
6465 /* copy the OleTypeName to the compobj struct */
6466 /* Note: in the test made, these were Identical */
6467 IStorageCompObj
.dwProgIDNameLength
= strlen(strOleTypeName
)+1;
6468 strcpy(IStorageCompObj
.strProgIDName
, strOleTypeName
);
6471 hRes
= CLSIDFromProgID16(IStorageCompObj
.strProgIDName
, &(IStorageCompObj
.clsid
));
6477 /* Get the CLSID Default Name from the Registry */
6478 hErr
= RegOpenKeyA(HKEY_CLASSES_ROOT
, IStorageCompObj
.strProgIDName
, &hKey
);
6479 if(hErr
== ERROR_SUCCESS
)
6481 char strTemp
[OLESTREAM_MAX_STR_LEN
];
6482 IStorageCompObj
.dwCLSIDNameLength
= OLESTREAM_MAX_STR_LEN
;
6483 hErr
= RegQueryValueA(hKey
, NULL
, strTemp
, &(IStorageCompObj
.dwCLSIDNameLength
));
6484 if(hErr
== ERROR_SUCCESS
)
6486 strcpy(IStorageCompObj
.strCLSIDName
, strTemp
);
6492 /* Write CompObj Structure to stream */
6493 hRes
= IStream_Write(pStream
, IStorageCompObj
.byUnknown1
, sizeof(IStorageCompObj
.byUnknown1
), NULL
);
6495 WriteClassStm(pStream
,&(IStorageCompObj
.clsid
));
6497 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwCLSIDNameLength
), sizeof(IStorageCompObj
.dwCLSIDNameLength
), NULL
);
6498 if(IStorageCompObj
.dwCLSIDNameLength
> 0)
6500 hRes
= IStream_Write(pStream
, IStorageCompObj
.strCLSIDName
, IStorageCompObj
.dwCLSIDNameLength
, NULL
);
6502 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwOleTypeNameLength
) , sizeof(IStorageCompObj
.dwOleTypeNameLength
), NULL
);
6503 if(IStorageCompObj
.dwOleTypeNameLength
> 0)
6505 hRes
= IStream_Write(pStream
, IStorageCompObj
.strOleTypeName
, IStorageCompObj
.dwOleTypeNameLength
, NULL
);
6507 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwProgIDNameLength
) , sizeof(IStorageCompObj
.dwProgIDNameLength
), NULL
);
6508 if(IStorageCompObj
.dwProgIDNameLength
> 0)
6510 hRes
= IStream_Write(pStream
, IStorageCompObj
.strProgIDName
, IStorageCompObj
.dwProgIDNameLength
, NULL
);
6512 hRes
= IStream_Write(pStream
, IStorageCompObj
.byUnknown2
, sizeof(IStorageCompObj
.byUnknown2
), NULL
);
6513 IStream_Release(pStream
);
6519 /*************************************************************************
6520 * OLECONVERT_CreateOlePresStream[Internal]
6522 * Creates the "\002OlePres000" Stream with the Metafile data
6525 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
6526 * dwExtentX [I] Width of the Metafile
6527 * dwExtentY [I] Height of the Metafile
6528 * pData [I] Metafile data
6529 * dwDataLength [I] Size of the Metafile data
6533 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6536 * This function is used by OleConvertOLESTREAMToIStorage only.
6539 void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage
, DWORD dwExtentX
, DWORD dwExtentY
, BYTE
*pData
, DWORD dwDataLength
)
6543 WCHAR wstrStreamName
[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6544 BYTE pOlePresStreamHeader
[] =
6546 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
6547 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6548 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6549 0x00, 0x00, 0x00, 0x00
6552 BYTE pOlePresStreamHeaderEmpty
[] =
6554 0x00, 0x00, 0x00, 0x00,
6555 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6556 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6557 0x00, 0x00, 0x00, 0x00
6560 /* Create the OlePres000 Stream */
6561 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6562 STGM_CREATE
| STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6567 OLECONVERT_ISTORAGE_OLEPRES OlePres
;
6569 memset(&OlePres
, 0, sizeof(OlePres
));
6570 /* Do we have any metafile data to save */
6571 if(dwDataLength
> 0)
6573 memcpy(OlePres
.byUnknown1
, pOlePresStreamHeader
, sizeof(pOlePresStreamHeader
));
6574 nHeaderSize
= sizeof(pOlePresStreamHeader
);
6578 memcpy(OlePres
.byUnknown1
, pOlePresStreamHeaderEmpty
, sizeof(pOlePresStreamHeaderEmpty
));
6579 nHeaderSize
= sizeof(pOlePresStreamHeaderEmpty
);
6581 /* Set width and height of the metafile */
6582 OlePres
.dwExtentX
= dwExtentX
;
6583 OlePres
.dwExtentY
= -dwExtentY
;
6585 /* Set Data and Lenght */
6586 if(dwDataLength
> sizeof(METAFILEPICT16
))
6588 OlePres
.dwSize
= dwDataLength
- sizeof(METAFILEPICT16
);
6589 OlePres
.pData
= &(pData
[8]);
6591 /* Save OlePres000 Data to Stream */
6592 hRes
= IStream_Write(pStream
, OlePres
.byUnknown1
, nHeaderSize
, NULL
);
6593 hRes
= IStream_Write(pStream
, &(OlePres
.dwExtentX
), sizeof(OlePres
.dwExtentX
), NULL
);
6594 hRes
= IStream_Write(pStream
, &(OlePres
.dwExtentY
), sizeof(OlePres
.dwExtentY
), NULL
);
6595 hRes
= IStream_Write(pStream
, &(OlePres
.dwSize
), sizeof(OlePres
.dwSize
), NULL
);
6596 if(OlePres
.dwSize
> 0)
6598 hRes
= IStream_Write(pStream
, OlePres
.pData
, OlePres
.dwSize
, NULL
);
6600 IStream_Release(pStream
);
6604 /*************************************************************************
6605 * OLECONVERT_CreateOle10NativeStream [Internal]
6607 * Creates the "\001Ole10Native" Stream (should contain a BMP)
6610 * pStorage [I] Dest storage to create the stream in
6611 * pData [I] Ole10 Native Data (ex. bmp)
6612 * dwDataLength [I] Size of the Ole10 Native Data
6618 * This function is used by OleConvertOLESTREAMToIStorage only.
6620 * Might need to verify the data and return appropriate error message
6623 void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage
, BYTE
*pData
, DWORD dwDataLength
)
6627 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6629 /* Create the Ole10Native Stream */
6630 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6631 STGM_CREATE
| STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6635 /* Write info to stream */
6636 hRes
= IStream_Write(pStream
, &dwDataLength
, sizeof(dwDataLength
), NULL
);
6637 hRes
= IStream_Write(pStream
, pData
, dwDataLength
, NULL
);
6638 IStream_Release(pStream
);
6643 /*************************************************************************
6644 * OLECONVERT_GetOLE10ProgID [Internal]
6646 * Finds the ProgID (or OleTypeID) from the IStorage
6649 * pStorage [I] The Src IStorage to get the ProgID
6650 * strProgID [I] the ProgID string to get
6651 * dwSize [I] the size of the string
6655 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6658 * This function is used by OleConvertIStorageToOLESTREAM only.
6662 HRESULT
OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage
, char *strProgID
, DWORD
*dwSize
)
6666 LARGE_INTEGER iSeekPos
;
6667 OLECONVERT_ISTORAGE_COMPOBJ CompObj
;
6668 WCHAR wstrStreamName
[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6670 /* Open the CompObj Stream */
6671 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6672 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6676 /*Get the OleType from the CompObj Stream */
6677 iSeekPos
.s
.LowPart
= sizeof(CompObj
.byUnknown1
) + sizeof(CompObj
.clsid
);
6678 iSeekPos
.s
.HighPart
= 0;
6680 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_SET
, NULL
);
6681 IStream_Read(pStream
, &CompObj
.dwCLSIDNameLength
, sizeof(CompObj
.dwCLSIDNameLength
), NULL
);
6682 iSeekPos
.s
.LowPart
= CompObj
.dwCLSIDNameLength
;
6683 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_CUR
, NULL
);
6684 IStream_Read(pStream
, &CompObj
.dwOleTypeNameLength
, sizeof(CompObj
.dwOleTypeNameLength
), NULL
);
6685 iSeekPos
.s
.LowPart
= CompObj
.dwOleTypeNameLength
;
6686 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_CUR
, NULL
);
6688 IStream_Read(pStream
, dwSize
, sizeof(*dwSize
), NULL
);
6691 IStream_Read(pStream
, strProgID
, *dwSize
, NULL
);
6693 IStream_Release(pStream
);
6698 LPOLESTR wstrProgID
;
6700 /* Get the OleType from the registry */
6701 REFCLSID clsid
= &(stat
.clsid
);
6702 IStorage_Stat(pStorage
, &stat
, STATFLAG_NONAME
);
6703 hRes
= ProgIDFromCLSID(clsid
, &wstrProgID
);
6706 *dwSize
= WideCharToMultiByte(CP_ACP
, 0, wstrProgID
, -1, strProgID
, *dwSize
, NULL
, FALSE
);
6713 /*************************************************************************
6714 * OLECONVERT_GetOle10PresData [Internal]
6716 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
6719 * pStorage [I] Src IStroage
6720 * pOleStream [I] Dest OleStream Mem Struct
6726 * This function is used by OleConvertIStorageToOLESTREAM only.
6728 * Memory allocated for pData must be freed by the caller
6732 void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage
, OLECONVERT_OLESTREAM_DATA
*pOleStreamData
)
6737 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6739 /* Initialize Default data for OLESTREAM */
6740 pOleStreamData
[0].dwOleID
= OLESTREAM_ID
;
6741 pOleStreamData
[0].dwTypeID
= 2;
6742 pOleStreamData
[1].dwOleID
= OLESTREAM_ID
;
6743 pOleStreamData
[1].dwTypeID
= 0;
6744 pOleStreamData
[0].dwMetaFileWidth
= 0;
6745 pOleStreamData
[0].dwMetaFileHeight
= 0;
6746 pOleStreamData
[0].pData
= NULL
;
6747 pOleStreamData
[1].pData
= NULL
;
6749 /* Open Ole10Native Stream */
6750 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6751 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6755 /* Read Size and Data */
6756 IStream_Read(pStream
, &(pOleStreamData
->dwDataLength
), sizeof(pOleStreamData
->dwDataLength
), NULL
);
6757 if(pOleStreamData
->dwDataLength
> 0)
6759 pOleStreamData
->pData
= (LPSTR
) HeapAlloc(GetProcessHeap(),0,pOleStreamData
->dwDataLength
);
6760 IStream_Read(pStream
, pOleStreamData
->pData
, pOleStreamData
->dwDataLength
, NULL
);
6762 IStream_Release(pStream
);
6768 /*************************************************************************
6769 * OLECONVERT_GetOle20PresData[Internal]
6771 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
6774 * pStorage [I] Src IStroage
6775 * pOleStreamData [I] Dest OleStream Mem Struct
6781 * This function is used by OleConvertIStorageToOLESTREAM only.
6783 * Memory allocated for pData must be freed by the caller
6785 void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage
, OLECONVERT_OLESTREAM_DATA
*pOleStreamData
)
6789 OLECONVERT_ISTORAGE_OLEPRES olePress
;
6790 WCHAR wstrStreamName
[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6792 /* Initialize Default data for OLESTREAM */
6793 pOleStreamData
[0].dwOleID
= OLESTREAM_ID
;
6794 pOleStreamData
[0].dwTypeID
= 2;
6795 pOleStreamData
[0].dwMetaFileWidth
= 0;
6796 pOleStreamData
[0].dwMetaFileHeight
= 0;
6797 pOleStreamData
[0].dwDataLength
= OLECONVERT_WriteOLE20ToBuffer(pStorage
, &(pOleStreamData
[0].pData
));
6798 pOleStreamData
[1].dwOleID
= OLESTREAM_ID
;
6799 pOleStreamData
[1].dwTypeID
= 0;
6800 pOleStreamData
[1].dwOleTypeNameLength
= 0;
6801 pOleStreamData
[1].strOleTypeName
[0] = 0;
6802 pOleStreamData
[1].dwMetaFileWidth
= 0;
6803 pOleStreamData
[1].dwMetaFileHeight
= 0;
6804 pOleStreamData
[1].pData
= NULL
;
6805 pOleStreamData
[1].dwDataLength
= 0;
6808 /* Open OlePress000 stream */
6809 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6810 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6813 LARGE_INTEGER iSeekPos
;
6814 METAFILEPICT16 MetaFilePict
;
6815 char strMetafilePictName
[] = "METAFILEPICT";
6817 /* Set the TypeID for a Metafile */
6818 pOleStreamData
[1].dwTypeID
= 5;
6820 /* Set the OleTypeName to Metafile */
6821 pOleStreamData
[1].dwOleTypeNameLength
= strlen(strMetafilePictName
) +1;
6822 strcpy(pOleStreamData
[1].strOleTypeName
, strMetafilePictName
);
6824 iSeekPos
.s
.HighPart
= 0;
6825 iSeekPos
.s
.LowPart
= sizeof(olePress
.byUnknown1
);
6827 /* Get Presentation Data */
6828 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_SET
, NULL
);
6829 IStream_Read(pStream
, &(olePress
.dwExtentX
), sizeof(olePress
.dwExtentX
), NULL
);
6830 IStream_Read(pStream
, &(olePress
.dwExtentY
), sizeof(olePress
.dwExtentY
), NULL
);
6831 IStream_Read(pStream
, &(olePress
.dwSize
), sizeof(olePress
.dwSize
), NULL
);
6833 /*Set width and Height */
6834 pOleStreamData
[1].dwMetaFileWidth
= olePress
.dwExtentX
;
6835 pOleStreamData
[1].dwMetaFileHeight
= -olePress
.dwExtentY
;
6836 if(olePress
.dwSize
> 0)
6839 pOleStreamData
[1].dwDataLength
= olePress
.dwSize
+ sizeof(METAFILEPICT16
);
6841 /* Set MetaFilePict struct */
6842 MetaFilePict
.mm
= 8;
6843 MetaFilePict
.xExt
= olePress
.dwExtentX
;
6844 MetaFilePict
.yExt
= olePress
.dwExtentY
;
6845 MetaFilePict
.hMF
= 0;
6847 /* Get Metafile Data */
6848 pOleStreamData
[1].pData
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,pOleStreamData
[1].dwDataLength
);
6849 memcpy(pOleStreamData
[1].pData
, &MetaFilePict
, sizeof(MetaFilePict
));
6850 IStream_Read(pStream
, &(pOleStreamData
[1].pData
[sizeof(MetaFilePict
)]), pOleStreamData
[1].dwDataLength
-sizeof(METAFILEPICT16
), NULL
);
6852 IStream_Release(pStream
);
6856 /*************************************************************************
6857 * OleConvertOLESTREAMToIStorage [OLE32.87]
6862 * DVTARGETDEVICE paramenter is not handled
6863 * Still unsure of some mem fields for OLE 10 Stream
6864 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6865 * and "\001OLE" streams
6868 HRESULT WINAPI
OleConvertOLESTREAMToIStorage (
6869 LPOLESTREAM pOleStream
,
6871 const DVTARGETDEVICE
* ptd
)
6875 OLECONVERT_OLESTREAM_DATA pOleStreamData
[2];
6877 memset(pOleStreamData
, 0, sizeof(pOleStreamData
));
6881 FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
6884 if(pstg
== NULL
|| pOleStream
== NULL
)
6886 hRes
= E_INVALIDARG
;
6891 /* Load the OLESTREAM to Memory */
6892 hRes
= OLECONVERT_LoadOLE10(pOleStream
, &pOleStreamData
[0], TRUE
);
6897 /* Load the OLESTREAM to Memory (part 2)*/
6898 hRes
= OLECONVERT_LoadOLE10(pOleStream
, &pOleStreamData
[1], FALSE
);
6904 if(pOleStreamData
[0].dwDataLength
> sizeof(STORAGE_magic
))
6906 /* Do we have the IStorage Data in the OLESTREAM */
6907 if(memcmp(pOleStreamData
[0].pData
, STORAGE_magic
, sizeof(STORAGE_magic
)) ==0)
6909 OLECONVERT_GetOLE20FromOLE10(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
6910 OLECONVERT_CreateOlePresStream(pstg
, pOleStreamData
[1].dwMetaFileWidth
, pOleStreamData
[1].dwMetaFileHeight
, pOleStreamData
[1].pData
, pOleStreamData
[1].dwDataLength
);
6914 /* It must be an original OLE 1.0 source */
6915 OLECONVERT_CreateOle10NativeStream(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
6920 /* It must be an original OLE 1.0 source */
6921 OLECONVERT_CreateOle10NativeStream(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
6924 /* Create CompObj Stream if necessary */
6925 hRes
= OLECONVERT_CreateCompObjStream(pstg
, pOleStreamData
[0].strOleTypeName
);
6928 /*Create the Ole Stream if necessary */
6929 OLECONVERT_CreateOleStream(pstg
);
6934 /* Free allocated memory */
6935 for(i
=0; i
< 2; i
++)
6937 if(pOleStreamData
[i
].pData
!= NULL
)
6939 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pData
);
6941 if(pOleStreamData
[i
].pstrOleObjFileName
!= NULL
)
6943 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pstrOleObjFileName
);
6944 pOleStreamData
[i
].pstrOleObjFileName
= NULL
;
6950 /*************************************************************************
6951 * OleConvertIStorageToOLESTREAM [OLE32.85]
6958 * Still unsure of some mem fields for OLE 10 Stream
6959 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6960 * and "\001OLE" streams.
6963 HRESULT WINAPI
OleConvertIStorageToOLESTREAM (
6965 LPOLESTREAM pOleStream
)
6968 HRESULT hRes
= S_OK
;
6970 OLECONVERT_OLESTREAM_DATA pOleStreamData
[2];
6971 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6974 memset(pOleStreamData
, 0, sizeof(pOleStreamData
));
6976 if(pstg
== NULL
|| pOleStream
== NULL
)
6978 hRes
= E_INVALIDARG
;
6982 /* Get the ProgID */
6983 pOleStreamData
[0].dwOleTypeNameLength
= OLESTREAM_MAX_STR_LEN
;
6984 hRes
= OLECONVERT_GetOLE10ProgID(pstg
, pOleStreamData
[0].strOleTypeName
, &(pOleStreamData
[0].dwOleTypeNameLength
));
6988 /*Was it originaly Ole10 */
6989 hRes
= IStorage_OpenStream(pstg
, wstrStreamName
, 0, STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6992 IStream_Release(pStream
);
6993 /*Get Presentation Data for Ole10Native */
6994 OLECONVERT_GetOle10PresData(pstg
, pOleStreamData
);
6998 /*Get Presentation Data (OLE20)*/
6999 OLECONVERT_GetOle20PresData(pstg
, pOleStreamData
);
7002 /* Save OLESTREAM */
7003 hRes
= OLECONVERT_SaveOLE10(&(pOleStreamData
[0]), pOleStream
);
7006 hRes
= OLECONVERT_SaveOLE10(&(pOleStreamData
[1]), pOleStream
);
7011 /* Free allocated memory */
7012 for(i
=0; i
< 2; i
++)
7014 if(pOleStreamData
[i
].pData
!= NULL
)
7016 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pData
);
7023 /***********************************************************************
7024 * GetConvertStg (OLE32.68)
7026 HRESULT WINAPI
GetConvertStg(LPGUID guid
) {
7027 FIXME("(%s), unimplemented stub!\n",debugstr_guid(guid
));