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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "winbase.h" /* for lstrlenW() and the likes */
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
37 #include "storage32.h"
38 #include "ole2.h" /* For Write/ReadClassStm */
41 #include "wine/wingdi16.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(storage
);
48 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
49 #define OLESTREAM_ID 0x501
50 #define OLESTREAM_MAX_STR_LEN 255
52 static const char rootPropertyName
[] = "Root Entry";
55 /* OLESTREAM memory structure to use for Get and Put Routines */
56 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
61 DWORD dwOleTypeNameLength
;
62 CHAR strOleTypeName
[OLESTREAM_MAX_STR_LEN
];
63 CHAR
*pstrOleObjFileName
;
64 DWORD dwOleObjFileNameLength
;
65 DWORD dwMetaFileWidth
;
66 DWORD dwMetaFileHeight
;
67 CHAR strUnknown
[8]; /* don't know what is this 8 byts information in OLE stream. */
70 }OLECONVERT_OLESTREAM_DATA
;
72 /* CompObj Stream structure */
73 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
78 DWORD dwCLSIDNameLength
;
79 CHAR strCLSIDName
[OLESTREAM_MAX_STR_LEN
];
80 DWORD dwOleTypeNameLength
;
81 CHAR strOleTypeName
[OLESTREAM_MAX_STR_LEN
];
82 DWORD dwProgIDNameLength
;
83 CHAR strProgIDName
[OLESTREAM_MAX_STR_LEN
];
85 }OLECONVERT_ISTORAGE_COMPOBJ
;
88 /* Ole Presention Stream structure */
89 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
97 }OLECONVERT_ISTORAGE_OLEPRES
;
101 /***********************************************************************
102 * Forward declaration of internal functions used by the method DestroyElement
104 static HRESULT
deleteStorageProperty(
105 StorageImpl
*parentStorage
,
106 ULONG foundPropertyIndexToDelete
,
107 StgProperty propertyToDelete
);
109 static HRESULT
deleteStreamProperty(
110 StorageImpl
*parentStorage
,
111 ULONG foundPropertyIndexToDelete
,
112 StgProperty propertyToDelete
);
114 static HRESULT
findPlaceholder(
115 StorageImpl
*storage
,
116 ULONG propertyIndexToStore
,
117 ULONG storagePropertyIndex
,
120 static HRESULT
adjustPropertyChain(
122 StgProperty propertyToDelete
,
123 StgProperty parentProperty
,
124 ULONG parentPropertyId
,
127 /***********************************************************************
128 * Declaration of the functions used to manipulate StgProperty
131 static ULONG
getFreeProperty(
132 StorageImpl
*storage
);
134 static void updatePropertyChain(
135 StorageImpl
*storage
,
136 ULONG newPropertyIndex
,
137 StgProperty newProperty
);
139 static LONG
propertyNameCmp(
140 OLECHAR
*newProperty
,
141 OLECHAR
*currentProperty
);
144 /***********************************************************************
145 * Declaration of miscellaneous functions...
147 static HRESULT
validateSTGM(DWORD stgmValue
);
149 static DWORD
GetShareModeFromSTGM(DWORD stgm
);
150 static DWORD
GetAccessModeFromSTGM(DWORD stgm
);
151 static DWORD
GetCreationModeFromSTGM(DWORD stgm
);
154 * Virtual function table for the IStorage32Impl class.
156 static ICOM_VTABLE(IStorage
) Storage32Impl_Vtbl
=
158 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
159 StorageBaseImpl_QueryInterface
,
160 StorageBaseImpl_AddRef
,
161 StorageBaseImpl_Release
,
162 StorageBaseImpl_CreateStream
,
163 StorageBaseImpl_OpenStream
,
164 StorageImpl_CreateStorage
,
165 StorageBaseImpl_OpenStorage
,
167 StorageImpl_MoveElementTo
,
170 StorageBaseImpl_EnumElements
,
171 StorageImpl_DestroyElement
,
172 StorageBaseImpl_RenameElement
,
173 StorageImpl_SetElementTimes
,
174 StorageBaseImpl_SetClass
,
175 StorageImpl_SetStateBits
,
180 * Virtual function table for the Storage32InternalImpl class.
182 static ICOM_VTABLE(IStorage
) Storage32InternalImpl_Vtbl
=
184 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
185 StorageBaseImpl_QueryInterface
,
186 StorageBaseImpl_AddRef
,
187 StorageBaseImpl_Release
,
188 StorageBaseImpl_CreateStream
,
189 StorageBaseImpl_OpenStream
,
190 StorageImpl_CreateStorage
,
191 StorageBaseImpl_OpenStorage
,
193 StorageImpl_MoveElementTo
,
194 StorageInternalImpl_Commit
,
195 StorageInternalImpl_Revert
,
196 StorageBaseImpl_EnumElements
,
197 StorageImpl_DestroyElement
,
198 StorageBaseImpl_RenameElement
,
199 StorageImpl_SetElementTimes
,
200 StorageBaseImpl_SetClass
,
201 StorageImpl_SetStateBits
,
206 * Virtual function table for the IEnumSTATSTGImpl class.
208 static ICOM_VTABLE(IEnumSTATSTG
) IEnumSTATSTGImpl_Vtbl
=
210 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
211 IEnumSTATSTGImpl_QueryInterface
,
212 IEnumSTATSTGImpl_AddRef
,
213 IEnumSTATSTGImpl_Release
,
214 IEnumSTATSTGImpl_Next
,
215 IEnumSTATSTGImpl_Skip
,
216 IEnumSTATSTGImpl_Reset
,
217 IEnumSTATSTGImpl_Clone
224 /************************************************************************
225 ** Storage32BaseImpl implementatiion
228 /************************************************************************
229 * Storage32BaseImpl_QueryInterface (IUnknown)
231 * This method implements the common QueryInterface for all IStorage32
232 * implementations contained in this file.
234 * See Windows documentation for more details on IUnknown methods.
236 HRESULT WINAPI
StorageBaseImpl_QueryInterface(
241 ICOM_THIS(StorageBaseImpl
,iface
);
243 * Perform a sanity check on the parameters.
245 if ( (This
==0) || (ppvObject
==0) )
249 * Initialize the return parameter.
254 * Compare the riid with the interface IDs implemented by this object.
256 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
258 *ppvObject
= (IStorage
*)This
;
260 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IStorage
)) == 0)
262 *ppvObject
= (IStorage
*)This
;
266 * Check that we obtained an interface.
269 return E_NOINTERFACE
;
272 * Query Interface always increases the reference count by one when it is
275 StorageBaseImpl_AddRef(iface
);
280 /************************************************************************
281 * Storage32BaseImpl_AddRef (IUnknown)
283 * This method implements the common AddRef for all IStorage32
284 * implementations contained in this file.
286 * See Windows documentation for more details on IUnknown methods.
288 ULONG WINAPI
StorageBaseImpl_AddRef(
291 ICOM_THIS(StorageBaseImpl
,iface
);
297 /************************************************************************
298 * Storage32BaseImpl_Release (IUnknown)
300 * This method implements the common Release for all IStorage32
301 * implementations contained in this file.
303 * See Windows documentation for more details on IUnknown methods.
305 ULONG WINAPI
StorageBaseImpl_Release(
308 ICOM_THIS(StorageBaseImpl
,iface
);
310 * Decrease the reference count on this object.
315 * If the reference count goes down to 0, perform suicide.
320 * Since we are using a system of base-classes, we want to call the
321 * destructor of the appropriate derived class. To do this, we are
322 * using virtual functions to implement the destructor.
324 This
->v_destructor(This
);
332 /************************************************************************
333 * Storage32BaseImpl_OpenStream (IStorage)
335 * This method will open the specified stream object from the current storage.
337 * See Windows documentation for more details on IStorage methods.
339 HRESULT WINAPI
StorageBaseImpl_OpenStream(
341 const OLECHAR
* pwcsName
, /* [string][in] */
342 void* reserved1
, /* [unique][in] */
343 DWORD grfMode
, /* [in] */
344 DWORD reserved2
, /* [in] */
345 IStream
** ppstm
) /* [out] */
347 ICOM_THIS(StorageBaseImpl
,iface
);
348 IEnumSTATSTGImpl
* propertyEnumeration
;
349 StgStreamImpl
* newStream
;
350 StgProperty currentProperty
;
351 ULONG foundPropertyIndex
;
352 HRESULT res
= STG_E_UNKNOWN
;
354 TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
355 iface
, debugstr_w(pwcsName
), reserved1
, grfMode
, reserved2
, ppstm
);
358 * Perform a sanity check on the parameters.
360 if ( (pwcsName
==NULL
) || (ppstm
==0) )
367 * Initialize the out parameter
372 * Validate the STGM flags
374 if ( FAILED( validateSTGM(grfMode
) ))
376 res
= STG_E_INVALIDFLAG
;
383 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
384 (grfMode
& STGM_DELETEONRELEASE
) ||
385 (grfMode
& STGM_TRANSACTED
) )
387 res
= STG_E_INVALIDFUNCTION
;
392 * Create a property enumeration to search the properties
394 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
395 This
->ancestorStorage
,
396 This
->rootPropertySetIndex
);
399 * Search the enumeration for the property with the given name
401 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
407 * Delete the property enumeration since we don't need it anymore
409 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
412 * If it was found, construct the stream object and return a pointer to it.
414 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
415 (currentProperty
.propertyType
==PROPTYPE_STREAM
) )
417 newStream
= StgStreamImpl_Construct(This
, grfMode
, foundPropertyIndex
);
421 newStream
->grfMode
= grfMode
;
422 *ppstm
= (IStream
*)newStream
;
425 * Since we are returning a pointer to the interface, we have to
426 * nail down the reference.
428 StgStreamImpl_AddRef(*ppstm
);
438 res
= STG_E_FILENOTFOUND
;
442 TRACE("<-- IStream %p\n", *ppstm
);
443 TRACE("<-- %08lx\n", res
);
447 /************************************************************************
448 * Storage32BaseImpl_OpenStorage (IStorage)
450 * This method will open a new storage object from the current storage.
452 * See Windows documentation for more details on IStorage methods.
454 HRESULT WINAPI
StorageBaseImpl_OpenStorage(
456 const OLECHAR
* pwcsName
, /* [string][unique][in] */
457 IStorage
* pstgPriority
, /* [unique][in] */
458 DWORD grfMode
, /* [in] */
459 SNB snbExclude
, /* [unique][in] */
460 DWORD reserved
, /* [in] */
461 IStorage
** ppstg
) /* [out] */
463 ICOM_THIS(StorageBaseImpl
,iface
);
464 StorageInternalImpl
* newStorage
;
465 IEnumSTATSTGImpl
* propertyEnumeration
;
466 StgProperty currentProperty
;
467 ULONG foundPropertyIndex
;
468 HRESULT res
= STG_E_UNKNOWN
;
470 TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
471 iface
, debugstr_w(pwcsName
), pstgPriority
,
472 grfMode
, snbExclude
, reserved
, ppstg
);
475 * Perform a sanity check on the parameters.
477 if ( (This
==0) || (pwcsName
==NULL
) || (ppstg
==0) )
484 if (snbExclude
!= NULL
)
486 res
= STG_E_INVALIDPARAMETER
;
491 * Validate the STGM flags
493 if ( FAILED( validateSTGM(grfMode
) ))
495 res
= STG_E_INVALIDFLAG
;
502 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
503 (grfMode
& STGM_DELETEONRELEASE
) ||
504 (grfMode
& STGM_PRIORITY
) )
506 res
= STG_E_INVALIDFUNCTION
;
511 * Initialize the out parameter
516 * Create a property enumeration to search the properties
518 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
519 This
->ancestorStorage
,
520 This
->rootPropertySetIndex
);
523 * Search the enumeration for the property with the given name
525 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(
531 * Delete the property enumeration since we don't need it anymore
533 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
536 * If it was found, construct the stream object and return a pointer to it.
538 if ( (foundPropertyIndex
!=PROPERTY_NULL
) &&
539 (currentProperty
.propertyType
==PROPTYPE_STORAGE
) )
542 * Construct a new Storage object
544 newStorage
= StorageInternalImpl_Construct(
545 This
->ancestorStorage
,
550 *ppstg
= (IStorage
*)newStorage
;
553 * Since we are returning a pointer to the interface,
554 * we have to nail down the reference.
556 StorageBaseImpl_AddRef(*ppstg
);
562 res
= STG_E_INSUFFICIENTMEMORY
;
566 res
= STG_E_FILENOTFOUND
;
569 TRACE("<-- %08lx\n", res
);
573 /************************************************************************
574 * Storage32BaseImpl_EnumElements (IStorage)
576 * This method will create an enumerator object that can be used to
577 * retrieve informatino about all the properties in the storage object.
579 * See Windows documentation for more details on IStorage methods.
581 HRESULT WINAPI
StorageBaseImpl_EnumElements(
583 DWORD reserved1
, /* [in] */
584 void* reserved2
, /* [size_is][unique][in] */
585 DWORD reserved3
, /* [in] */
586 IEnumSTATSTG
** ppenum
) /* [out] */
588 ICOM_THIS(StorageBaseImpl
,iface
);
589 IEnumSTATSTGImpl
* newEnum
;
591 TRACE("(%p, %ld, %p, %ld, %p)\n",
592 iface
, reserved1
, reserved2
, reserved3
, ppenum
);
595 * Perform a sanity check on the parameters.
597 if ( (This
==0) || (ppenum
==0))
601 * Construct the enumerator.
603 newEnum
= IEnumSTATSTGImpl_Construct(
604 This
->ancestorStorage
,
605 This
->rootPropertySetIndex
);
609 *ppenum
= (IEnumSTATSTG
*)newEnum
;
612 * Don't forget to nail down a reference to the new object before
615 IEnumSTATSTGImpl_AddRef(*ppenum
);
620 return E_OUTOFMEMORY
;
623 /************************************************************************
624 * Storage32BaseImpl_Stat (IStorage)
626 * This method will retrieve information about this storage object.
628 * See Windows documentation for more details on IStorage methods.
630 HRESULT WINAPI
StorageBaseImpl_Stat(
632 STATSTG
* pstatstg
, /* [out] */
633 DWORD grfStatFlag
) /* [in] */
635 ICOM_THIS(StorageBaseImpl
,iface
);
636 StgProperty curProperty
;
638 HRESULT res
= STG_E_UNKNOWN
;
640 TRACE("(%p, %p, %lx)\n",
641 iface
, pstatstg
, grfStatFlag
);
644 * Perform a sanity check on the parameters.
646 if ( (This
==0) || (pstatstg
==0))
653 * Read the information from the property.
655 readSuccessful
= StorageImpl_ReadProperty(
656 This
->ancestorStorage
,
657 This
->rootPropertySetIndex
,
662 StorageUtl_CopyPropertyToSTATSTG(
676 TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %08lx, grfLocksSupported: %ld, grfStateBits: %08lx\n", debugstr_w(pstatstg
->pwcsName
), pstatstg
->type
, pstatstg
->cbSize
.s
.LowPart
, pstatstg
->cbSize
.s
.HighPart
, pstatstg
->grfMode
, pstatstg
->grfLocksSupported
, pstatstg
->grfStateBits
);
678 TRACE("<-- %08lx\n", res
);
682 /************************************************************************
683 * Storage32BaseImpl_RenameElement (IStorage)
685 * This method will rename the specified element.
687 * See Windows documentation for more details on IStorage methods.
689 * Implementation notes: The method used to rename consists of creating a clone
690 * of the deleted StgProperty object setting it with the new name and to
691 * perform a DestroyElement of the old StgProperty.
693 HRESULT WINAPI
StorageBaseImpl_RenameElement(
695 const OLECHAR
* pwcsOldName
, /* [in] */
696 const OLECHAR
* pwcsNewName
) /* [in] */
698 ICOM_THIS(StorageBaseImpl
,iface
);
699 IEnumSTATSTGImpl
* propertyEnumeration
;
700 StgProperty currentProperty
;
701 ULONG foundPropertyIndex
;
703 TRACE("(%p, %s, %s)\n",
704 iface
, debugstr_w(pwcsOldName
), debugstr_w(pwcsNewName
));
707 * Create a property enumeration to search the properties
709 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
710 This
->rootPropertySetIndex
);
713 * Search the enumeration for the new property name
715 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
719 if (foundPropertyIndex
!= PROPERTY_NULL
)
722 * There is already a property with the new name
724 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
725 return STG_E_FILEALREADYEXISTS
;
728 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)propertyEnumeration
);
731 * Search the enumeration for the old property name
733 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
738 * Delete the property enumeration since we don't need it anymore
740 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
742 if (foundPropertyIndex
!= PROPERTY_NULL
)
744 StgProperty renamedProperty
;
745 ULONG renamedPropertyIndex
;
748 * Setup a new property for the renamed property
750 renamedProperty
.sizeOfNameString
=
751 ( lstrlenW(pwcsNewName
)+1 ) * sizeof(WCHAR
);
753 if (renamedProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
754 return STG_E_INVALIDNAME
;
756 strcpyW(renamedProperty
.name
, pwcsNewName
);
758 renamedProperty
.propertyType
= currentProperty
.propertyType
;
759 renamedProperty
.startingBlock
= currentProperty
.startingBlock
;
760 renamedProperty
.size
.s
.LowPart
= currentProperty
.size
.s
.LowPart
;
761 renamedProperty
.size
.s
.HighPart
= currentProperty
.size
.s
.HighPart
;
763 renamedProperty
.previousProperty
= PROPERTY_NULL
;
764 renamedProperty
.nextProperty
= PROPERTY_NULL
;
767 * Bring the dirProperty link in case it is a storage and in which
768 * case the renamed storage elements don't require to be reorganized.
770 renamedProperty
.dirProperty
= currentProperty
.dirProperty
;
772 /* call CoFileTime to get the current time
773 renamedProperty.timeStampS1
774 renamedProperty.timeStampD1
775 renamedProperty.timeStampS2
776 renamedProperty.timeStampD2
777 renamedProperty.propertyUniqueID
781 * Obtain a free property in the property chain
783 renamedPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
786 * Save the new property into the new property spot
788 StorageImpl_WriteProperty(
789 This
->ancestorStorage
,
790 renamedPropertyIndex
,
794 * Find a spot in the property chain for our newly created property.
798 renamedPropertyIndex
,
802 * At this point the renamed property has been inserted in the tree,
803 * now, before to Destroy the old property we must zeroed it's dirProperty
804 * otherwise the DestroyProperty below will zap it all and we do not want
806 * Also, we fake that the old property is a storage so the DestroyProperty
807 * will not do a SetSize(0) on the stream data.
809 * This means that we need to tweek the StgProperty if it is a stream or a
812 StorageImpl_ReadProperty(This
->ancestorStorage
,
816 currentProperty
.dirProperty
= PROPERTY_NULL
;
817 currentProperty
.propertyType
= PROPTYPE_STORAGE
;
818 StorageImpl_WriteProperty(
819 This
->ancestorStorage
,
824 * Invoke Destroy to get rid of the ole property and automatically redo
825 * the linking of it's previous and next members...
827 StorageImpl_DestroyElement((IStorage
*)This
->ancestorStorage
, pwcsOldName
);
833 * There is no property with the old name
835 return STG_E_FILENOTFOUND
;
841 /************************************************************************
842 * Storage32BaseImpl_CreateStream (IStorage)
844 * This method will create a stream object within this storage
846 * See Windows documentation for more details on IStorage methods.
848 HRESULT WINAPI
StorageBaseImpl_CreateStream(
850 const OLECHAR
* pwcsName
, /* [string][in] */
851 DWORD grfMode
, /* [in] */
852 DWORD reserved1
, /* [in] */
853 DWORD reserved2
, /* [in] */
854 IStream
** ppstm
) /* [out] */
856 ICOM_THIS(StorageBaseImpl
,iface
);
857 IEnumSTATSTGImpl
* propertyEnumeration
;
858 StgStreamImpl
* newStream
;
859 StgProperty currentProperty
, newStreamProperty
;
860 ULONG foundPropertyIndex
, newPropertyIndex
;
862 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
863 iface
, debugstr_w(pwcsName
), grfMode
,
864 reserved1
, reserved2
, ppstm
);
867 * Validate parameters
870 return STG_E_INVALIDPOINTER
;
873 return STG_E_INVALIDNAME
;
876 * Validate the STGM flags
878 if ( FAILED( validateSTGM(grfMode
) ))
879 return STG_E_INVALIDFLAG
;
884 if ( !(grfMode
& STGM_SHARE_EXCLUSIVE
) ||
885 (grfMode
& STGM_DELETEONRELEASE
) ||
886 (grfMode
& STGM_TRANSACTED
) )
887 return STG_E_INVALIDFUNCTION
;
890 * Initialize the out parameter
895 * Create a property enumeration to search the properties
897 propertyEnumeration
= IEnumSTATSTGImpl_Construct(This
->ancestorStorage
,
898 This
->rootPropertySetIndex
);
900 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
904 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
906 if (foundPropertyIndex
!= PROPERTY_NULL
)
909 * An element with this name already exists
911 if (grfMode
& STGM_CREATE
)
913 IStorage_DestroyElement(iface
, pwcsName
);
916 return STG_E_FILEALREADYEXISTS
;
920 * memset the empty property
922 memset(&newStreamProperty
, 0, sizeof(StgProperty
));
924 newStreamProperty
.sizeOfNameString
=
925 ( lstrlenW(pwcsName
)+1 ) * sizeof(WCHAR
);
927 if (newStreamProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
928 return STG_E_INVALIDNAME
;
930 strcpyW(newStreamProperty
.name
, pwcsName
);
932 newStreamProperty
.propertyType
= PROPTYPE_STREAM
;
933 newStreamProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
934 newStreamProperty
.size
.s
.LowPart
= 0;
935 newStreamProperty
.size
.s
.HighPart
= 0;
937 newStreamProperty
.previousProperty
= PROPERTY_NULL
;
938 newStreamProperty
.nextProperty
= PROPERTY_NULL
;
939 newStreamProperty
.dirProperty
= PROPERTY_NULL
;
941 /* call CoFileTime to get the current time
942 newStreamProperty.timeStampS1
943 newStreamProperty.timeStampD1
944 newStreamProperty.timeStampS2
945 newStreamProperty.timeStampD2
948 /* newStreamProperty.propertyUniqueID */
951 * Get a free property or create a new one
953 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
956 * Save the new property into the new property spot
958 StorageImpl_WriteProperty(
959 This
->ancestorStorage
,
964 * Find a spot in the property chain for our newly created property.
972 * Open the stream to return it.
974 newStream
= StgStreamImpl_Construct(This
, grfMode
, newPropertyIndex
);
978 *ppstm
= (IStream
*)newStream
;
981 * Since we are returning a pointer to the interface, we have to nail down
984 StgStreamImpl_AddRef(*ppstm
);
988 return STG_E_INSUFFICIENTMEMORY
;
994 /************************************************************************
995 * Storage32BaseImpl_SetClass (IStorage)
997 * This method will write the specified CLSID in the property of this
1000 * See Windows documentation for more details on IStorage methods.
1002 HRESULT WINAPI
StorageBaseImpl_SetClass(
1004 REFCLSID clsid
) /* [in] */
1006 ICOM_THIS(StorageBaseImpl
,iface
);
1007 HRESULT hRes
= E_FAIL
;
1008 StgProperty curProperty
;
1011 TRACE("(%p, %p)\n", iface
, clsid
);
1013 success
= StorageImpl_ReadProperty(This
->ancestorStorage
,
1014 This
->rootPropertySetIndex
,
1018 curProperty
.propertyUniqueID
= *clsid
;
1020 success
= StorageImpl_WriteProperty(This
->ancestorStorage
,
1021 This
->rootPropertySetIndex
,
1030 /************************************************************************
1031 ** Storage32Impl implementation
1034 /************************************************************************
1035 * Storage32Impl_CreateStorage (IStorage)
1037 * This method will create the storage object within the provided storage.
1039 * See Windows documentation for more details on IStorage methods.
1041 HRESULT WINAPI
StorageImpl_CreateStorage(
1043 const OLECHAR
*pwcsName
, /* [string][in] */
1044 DWORD grfMode
, /* [in] */
1045 DWORD reserved1
, /* [in] */
1046 DWORD reserved2
, /* [in] */
1047 IStorage
**ppstg
) /* [out] */
1049 StorageImpl
* const This
=(StorageImpl
*)iface
;
1051 IEnumSTATSTGImpl
*propertyEnumeration
;
1052 StgProperty currentProperty
;
1053 StgProperty newProperty
;
1054 ULONG foundPropertyIndex
;
1055 ULONG newPropertyIndex
;
1058 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
1059 iface
, debugstr_w(pwcsName
), grfMode
,
1060 reserved1
, reserved2
, ppstg
);
1063 * Validate parameters
1066 return STG_E_INVALIDPOINTER
;
1069 return STG_E_INVALIDNAME
;
1072 * Validate the STGM flags
1074 if ( FAILED( validateSTGM(grfMode
) ) ||
1075 (grfMode
& STGM_DELETEONRELEASE
) )
1076 return STG_E_INVALIDFLAG
;
1079 * Initialize the out parameter
1084 * Create a property enumeration and search the properties
1086 propertyEnumeration
= IEnumSTATSTGImpl_Construct( This
->ancestorStorage
,
1087 This
->rootPropertySetIndex
);
1089 foundPropertyIndex
= IEnumSTATSTGImpl_FindProperty(propertyEnumeration
,
1092 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1094 if (foundPropertyIndex
!= PROPERTY_NULL
)
1097 * An element with this name already exists
1099 if (grfMode
& STGM_CREATE
)
1100 IStorage_DestroyElement(iface
, pwcsName
);
1102 return STG_E_FILEALREADYEXISTS
;
1106 * memset the empty property
1108 memset(&newProperty
, 0, sizeof(StgProperty
));
1110 newProperty
.sizeOfNameString
= (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
);
1112 if (newProperty
.sizeOfNameString
> PROPERTY_NAME_BUFFER_LEN
)
1113 return STG_E_INVALIDNAME
;
1115 strcpyW(newProperty
.name
, pwcsName
);
1117 newProperty
.propertyType
= PROPTYPE_STORAGE
;
1118 newProperty
.startingBlock
= BLOCK_END_OF_CHAIN
;
1119 newProperty
.size
.s
.LowPart
= 0;
1120 newProperty
.size
.s
.HighPart
= 0;
1122 newProperty
.previousProperty
= PROPERTY_NULL
;
1123 newProperty
.nextProperty
= PROPERTY_NULL
;
1124 newProperty
.dirProperty
= PROPERTY_NULL
;
1126 /* call CoFileTime to get the current time
1127 newProperty.timeStampS1
1128 newProperty.timeStampD1
1129 newProperty.timeStampS2
1130 newProperty.timeStampD2
1133 /* newStorageProperty.propertyUniqueID */
1136 * Obtain a free property in the property chain
1138 newPropertyIndex
= getFreeProperty(This
->ancestorStorage
);
1141 * Save the new property into the new property spot
1143 StorageImpl_WriteProperty(
1144 This
->ancestorStorage
,
1149 * Find a spot in the property chain for our newly created property.
1151 updatePropertyChain(
1157 * Open it to get a pointer to return.
1159 hr
= IStorage_OpenStorage(
1168 if( (hr
!= S_OK
) || (*ppstg
== NULL
))
1178 /***************************************************************************
1182 * Get a free property or create a new one.
1184 static ULONG
getFreeProperty(
1185 StorageImpl
*storage
)
1187 ULONG currentPropertyIndex
= 0;
1188 ULONG newPropertyIndex
= PROPERTY_NULL
;
1189 BOOL readSuccessful
= TRUE
;
1190 StgProperty currentProperty
;
1195 * Start by reading the root property
1197 readSuccessful
= StorageImpl_ReadProperty(storage
->ancestorStorage
,
1198 currentPropertyIndex
,
1202 if (currentProperty
.sizeOfNameString
== 0)
1205 * The property existis and is available, we found it.
1207 newPropertyIndex
= currentPropertyIndex
;
1213 * We exhausted the property list, we will create more space below
1215 newPropertyIndex
= currentPropertyIndex
;
1217 currentPropertyIndex
++;
1219 } while (newPropertyIndex
== PROPERTY_NULL
);
1222 * grow the property chain
1224 if (! readSuccessful
)
1226 StgProperty emptyProperty
;
1227 ULARGE_INTEGER newSize
;
1228 ULONG propertyIndex
;
1229 ULONG lastProperty
= 0;
1230 ULONG blockCount
= 0;
1233 * obtain the new count of property blocks
1235 blockCount
= BlockChainStream_GetCount(
1236 storage
->ancestorStorage
->rootBlockChain
)+1;
1239 * initialize the size used by the property stream
1241 newSize
.s
.HighPart
= 0;
1242 newSize
.s
.LowPart
= storage
->bigBlockSize
* blockCount
;
1245 * add a property block to the property chain
1247 BlockChainStream_SetSize(storage
->ancestorStorage
->rootBlockChain
, newSize
);
1250 * memset the empty property in order to initialize the unused newly
1253 memset(&emptyProperty
, 0, sizeof(StgProperty
));
1258 lastProperty
= storage
->bigBlockSize
/ PROPSET_BLOCK_SIZE
* blockCount
;
1261 propertyIndex
= newPropertyIndex
;
1262 propertyIndex
< lastProperty
;
1265 StorageImpl_WriteProperty(
1266 storage
->ancestorStorage
,
1272 return newPropertyIndex
;
1275 /****************************************************************************
1279 * Case insensitive comparaison of StgProperty.name by first considering
1282 * Returns <0 when newPrpoerty < currentProperty
1283 * >0 when newPrpoerty > currentProperty
1284 * 0 when newPrpoerty == currentProperty
1286 static LONG
propertyNameCmp(
1287 OLECHAR
*newProperty
,
1288 OLECHAR
*currentProperty
)
1290 LONG diff
= lstrlenW(newProperty
) - lstrlenW(currentProperty
);
1295 * We compare the string themselves only when they are of the same lenght
1297 diff
= lstrcmpiW( newProperty
, currentProperty
);
1303 /****************************************************************************
1307 * Properly link this new element in the property chain.
1309 static void updatePropertyChain(
1310 StorageImpl
*storage
,
1311 ULONG newPropertyIndex
,
1312 StgProperty newProperty
)
1314 StgProperty currentProperty
;
1317 * Read the root property
1319 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1320 storage
->rootPropertySetIndex
,
1323 if (currentProperty
.dirProperty
!= PROPERTY_NULL
)
1326 * The root storage contains some element, therefore, start the research
1327 * for the appropriate location.
1330 ULONG current
, next
, previous
, currentPropertyId
;
1333 * Keep the StgProperty sequence number of the storage first property
1335 currentPropertyId
= currentProperty
.dirProperty
;
1340 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1341 currentProperty
.dirProperty
,
1344 previous
= currentProperty
.previousProperty
;
1345 next
= currentProperty
.nextProperty
;
1346 current
= currentPropertyId
;
1350 LONG diff
= propertyNameCmp( newProperty
.name
, currentProperty
.name
);
1354 if (previous
!= PROPERTY_NULL
)
1356 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1363 currentProperty
.previousProperty
= newPropertyIndex
;
1364 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1372 if (next
!= PROPERTY_NULL
)
1374 StorageImpl_ReadProperty(storage
->ancestorStorage
,
1381 currentProperty
.nextProperty
= newPropertyIndex
;
1382 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1391 * Trying to insert an item with the same name in the
1392 * subtree structure.
1397 previous
= currentProperty
.previousProperty
;
1398 next
= currentProperty
.nextProperty
;
1404 * The root storage is empty, link the new property to it's dir property
1406 currentProperty
.dirProperty
= newPropertyIndex
;
1407 StorageImpl_WriteProperty(storage
->ancestorStorage
,
1408 storage
->rootPropertySetIndex
,
1414 /*************************************************************************
1417 HRESULT WINAPI
StorageImpl_CopyTo(
1419 DWORD ciidExclude
, /* [in] */
1420 const IID
* rgiidExclude
, /* [size_is][unique][in] */
1421 SNB snbExclude
, /* [unique][in] */
1422 IStorage
* pstgDest
) /* [unique][in] */
1424 IEnumSTATSTG
*elements
= 0;
1425 STATSTG curElement
, strStat
;
1427 IStorage
*pstgTmp
, *pstgChild
;
1428 IStream
*pstrTmp
, *pstrChild
;
1430 if ((ciidExclude
!= 0) || (rgiidExclude
!= NULL
) || (snbExclude
!= NULL
))
1431 FIXME("Exclude option not implemented\n");
1433 TRACE("(%p, %ld, %p, %p, %p)\n",
1434 iface
, ciidExclude
, rgiidExclude
,
1435 snbExclude
, pstgDest
);
1438 * Perform a sanity check
1440 if ( pstgDest
== 0 )
1441 return STG_E_INVALIDPOINTER
;
1444 * Enumerate the elements
1446 hr
= IStorage_EnumElements( iface
, 0, 0, 0, &elements
);
1454 IStorage_Stat( iface
, &curElement
, STATFLAG_NONAME
);
1455 IStorage_SetClass( pstgDest
, &curElement
.clsid
);
1460 * Obtain the next element
1462 hr
= IEnumSTATSTG_Next( elements
, 1, &curElement
, NULL
);
1464 if ( hr
== S_FALSE
)
1466 hr
= S_OK
; /* done, every element has been copied */
1470 if (curElement
.type
== STGTY_STORAGE
)
1473 * open child source storage
1475 hr
= IStorage_OpenStorage( iface
, curElement
.pwcsName
, NULL
,
1476 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1477 NULL
, 0, &pstgChild
);
1483 * Check if destination storage is not a child of the source
1484 * storage, which will cause an infinite loop
1486 if (pstgChild
== pstgDest
)
1488 IEnumSTATSTG_Release(elements
);
1490 return STG_E_ACCESSDENIED
;
1494 * create a new storage in destination storage
1496 hr
= IStorage_CreateStorage( pstgDest
, curElement
.pwcsName
,
1497 STGM_FAILIFTHERE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1501 * if it already exist, don't create a new one use this one
1503 if (hr
== STG_E_FILEALREADYEXISTS
)
1505 hr
= IStorage_OpenStorage( pstgDest
, curElement
.pwcsName
, NULL
,
1506 STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1507 NULL
, 0, &pstgTmp
);
1515 * do the copy recursively
1517 hr
= IStorage_CopyTo( pstgChild
, ciidExclude
, rgiidExclude
,
1518 snbExclude
, pstgTmp
);
1520 IStorage_Release( pstgTmp
);
1521 IStorage_Release( pstgChild
);
1523 else if (curElement
.type
== STGTY_STREAM
)
1526 * create a new stream in destination storage. If the stream already
1527 * exist, it will be deleted and a new one will be created.
1529 hr
= IStorage_CreateStream( pstgDest
, curElement
.pwcsName
,
1530 STGM_CREATE
|STGM_WRITE
|STGM_SHARE_EXCLUSIVE
,
1537 * open child stream storage
1539 hr
= IStorage_OpenStream( iface
, curElement
.pwcsName
, NULL
,
1540 STGM_READ
|STGM_SHARE_EXCLUSIVE
,
1547 * Get the size of the source stream
1549 IStream_Stat( pstrChild
, &strStat
, STATFLAG_NONAME
);
1552 * Set the size of the destination stream.
1554 IStream_SetSize(pstrTmp
, strStat
.cbSize
);
1559 hr
= IStream_CopyTo( pstrChild
, pstrTmp
, strStat
.cbSize
,
1562 IStream_Release( pstrTmp
);
1563 IStream_Release( pstrChild
);
1567 WARN("unknown element type: %ld\n", curElement
.type
);
1570 } while (hr
== S_OK
);
1575 IEnumSTATSTG_Release(elements
);
1580 /*************************************************************************
1581 * MoveElementTo (IStorage)
1583 HRESULT WINAPI
StorageImpl_MoveElementTo(
1585 const OLECHAR
*pwcsName
, /* [string][in] */
1586 IStorage
*pstgDest
, /* [unique][in] */
1587 const OLECHAR
*pwcsNewName
,/* [string][in] */
1588 DWORD grfFlags
) /* [in] */
1590 FIXME("not implemented!\n");
1594 /*************************************************************************
1597 HRESULT WINAPI
StorageImpl_Commit(
1599 DWORD grfCommitFlags
)/* [in] */
1601 FIXME("(%ld): stub!\n", grfCommitFlags
);
1605 /*************************************************************************
1608 HRESULT WINAPI
StorageImpl_Revert(
1611 FIXME("not implemented!\n");
1615 /*************************************************************************
1616 * DestroyElement (IStorage)
1618 * Stategy: This implementation is build this way for simplicity not for speed.
1619 * I always delete the top most element of the enumeration and adjust
1620 * the deleted element pointer all the time. This takes longer to
1621 * do but allow to reinvoke DestroyElement whenever we encounter a
1622 * storage object. The optimisation reside in the usage of another
1623 * enumeration stategy that would give all the leaves of a storage
1624 * first. (postfix order)
1626 HRESULT WINAPI
StorageImpl_DestroyElement(
1628 const OLECHAR
*pwcsName
)/* [string][in] */
1630 StorageImpl
* const This
=(StorageImpl
*)iface
;
1632 IEnumSTATSTGImpl
* propertyEnumeration
;
1635 StgProperty propertyToDelete
;
1636 StgProperty parentProperty
;
1637 ULONG foundPropertyIndexToDelete
;
1638 ULONG typeOfRelation
;
1639 ULONG parentPropertyId
;
1642 iface
, debugstr_w(pwcsName
));
1645 * Perform a sanity check on the parameters.
1648 return STG_E_INVALIDPOINTER
;
1651 * Create a property enumeration to search the property with the given name
1653 propertyEnumeration
= IEnumSTATSTGImpl_Construct(
1654 This
->ancestorStorage
,
1655 This
->rootPropertySetIndex
);
1657 foundPropertyIndexToDelete
= IEnumSTATSTGImpl_FindProperty(
1658 propertyEnumeration
,
1662 IEnumSTATSTGImpl_Destroy(propertyEnumeration
);
1664 if ( foundPropertyIndexToDelete
== PROPERTY_NULL
)
1666 return STG_E_FILENOTFOUND
;
1670 * Find the parent property of the property to delete (the one that
1671 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1672 * the parent is This. Otherwise, the parent is one of it's sibling...
1676 * First, read This's StgProperty..
1678 res
= StorageImpl_ReadProperty(
1679 This
->ancestorStorage
,
1680 This
->rootPropertySetIndex
,
1686 * Second, check to see if by any chance the actual storage (This) is not
1687 * the parent of the property to delete... We never know...
1689 if ( parentProperty
.dirProperty
== foundPropertyIndexToDelete
)
1692 * Set data as it would have been done in the else part...
1694 typeOfRelation
= PROPERTY_RELATION_DIR
;
1695 parentPropertyId
= This
->rootPropertySetIndex
;
1700 * Create a property enumeration to search the parent properties, and
1701 * delete it once done.
1703 IEnumSTATSTGImpl
* propertyEnumeration2
;
1705 propertyEnumeration2
= IEnumSTATSTGImpl_Construct(
1706 This
->ancestorStorage
,
1707 This
->rootPropertySetIndex
);
1709 typeOfRelation
= IEnumSTATSTGImpl_FindParentProperty(
1710 propertyEnumeration2
,
1711 foundPropertyIndexToDelete
,
1715 IEnumSTATSTGImpl_Destroy(propertyEnumeration2
);
1718 if ( propertyToDelete
.propertyType
== PROPTYPE_STORAGE
)
1720 hr
= deleteStorageProperty(
1722 foundPropertyIndexToDelete
,
1725 else if ( propertyToDelete
.propertyType
== PROPTYPE_STREAM
)
1727 hr
= deleteStreamProperty(
1729 foundPropertyIndexToDelete
,
1737 * Adjust the property chain
1739 hr
= adjustPropertyChain(
1750 /************************************************************************
1751 * StorageImpl_Stat (IStorage)
1753 * This method will retrieve information about this storage object.
1755 * See Windows documentation for more details on IStorage methods.
1757 HRESULT WINAPI
StorageImpl_Stat( IStorage
* iface
,
1758 STATSTG
* pstatstg
, /* [out] */
1759 DWORD grfStatFlag
) /* [in] */
1761 StorageImpl
* const This
= (StorageImpl
*)iface
;
1762 HRESULT result
= StorageBaseImpl_Stat( iface
, pstatstg
, grfStatFlag
);
1764 if ( !FAILED(result
) && ((grfStatFlag
& STATFLAG_NONAME
) == 0) && This
->pwcsName
)
1766 CoTaskMemFree(pstatstg
->pwcsName
);
1767 pstatstg
->pwcsName
= CoTaskMemAlloc((lstrlenW(This
->pwcsName
)+1)*sizeof(WCHAR
));
1768 strcpyW(pstatstg
->pwcsName
, This
->pwcsName
);
1776 /*********************************************************************
1780 * Perform the deletion of a complete storage node
1783 static HRESULT
deleteStorageProperty(
1784 StorageImpl
*parentStorage
,
1785 ULONG indexOfPropertyToDelete
,
1786 StgProperty propertyToDelete
)
1788 IEnumSTATSTG
*elements
= 0;
1789 IStorage
*childStorage
= 0;
1790 STATSTG currentElement
;
1792 HRESULT destroyHr
= S_OK
;
1795 * Open the storage and enumerate it
1797 hr
= StorageBaseImpl_OpenStorage(
1798 (IStorage
*)parentStorage
,
1799 propertyToDelete
.name
,
1801 STGM_SHARE_EXCLUSIVE
,
1812 * Enumerate the elements
1814 IStorage_EnumElements( childStorage
, 0, 0, 0, &elements
);
1819 * Obtain the next element
1821 hr
= IEnumSTATSTG_Next(elements
, 1, ¤tElement
, NULL
);
1824 destroyHr
= StorageImpl_DestroyElement(
1825 (IStorage
*)childStorage
,
1826 (OLECHAR
*)currentElement
.pwcsName
);
1828 CoTaskMemFree(currentElement
.pwcsName
);
1832 * We need to Reset the enumeration every time because we delete elements
1833 * and the enumeration could be invalid
1835 IEnumSTATSTG_Reset(elements
);
1837 } while ((hr
== S_OK
) && (destroyHr
== S_OK
));
1840 * Invalidate the property by zeroing it's name member.
1842 propertyToDelete
.sizeOfNameString
= 0;
1844 StorageImpl_WriteProperty(parentStorage
->ancestorStorage
,
1845 indexOfPropertyToDelete
,
1848 IStorage_Release(childStorage
);
1849 IEnumSTATSTG_Release(elements
);
1854 /*********************************************************************
1858 * Perform the deletion of a stream node
1861 static HRESULT
deleteStreamProperty(
1862 StorageImpl
*parentStorage
,
1863 ULONG indexOfPropertyToDelete
,
1864 StgProperty propertyToDelete
)
1868 ULARGE_INTEGER size
;
1870 size
.s
.HighPart
= 0;
1873 hr
= StorageBaseImpl_OpenStream(
1874 (IStorage
*)parentStorage
,
1875 (OLECHAR
*)propertyToDelete
.name
,
1877 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
,
1889 hr
= IStream_SetSize(pis
, size
);
1897 * Release the stream object.
1899 IStream_Release(pis
);
1902 * Invalidate the property by zeroing it's name member.
1904 propertyToDelete
.sizeOfNameString
= 0;
1907 * Here we should re-read the property so we get the updated pointer
1908 * but since we are here to zap it, I don't do it...
1910 StorageImpl_WriteProperty(
1911 parentStorage
->ancestorStorage
,
1912 indexOfPropertyToDelete
,
1918 /*********************************************************************
1922 * Finds a placeholder for the StgProperty within the Storage
1925 static HRESULT
findPlaceholder(
1926 StorageImpl
*storage
,
1927 ULONG propertyIndexToStore
,
1928 ULONG storePropertyIndex
,
1931 StgProperty storeProperty
;
1936 * Read the storage property
1938 res
= StorageImpl_ReadProperty(
1939 storage
->ancestorStorage
,
1948 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
1950 if (storeProperty
.previousProperty
!= PROPERTY_NULL
)
1952 return findPlaceholder(
1954 propertyIndexToStore
,
1955 storeProperty
.previousProperty
,
1960 storeProperty
.previousProperty
= propertyIndexToStore
;
1963 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
1965 if (storeProperty
.nextProperty
!= PROPERTY_NULL
)
1967 return findPlaceholder(
1969 propertyIndexToStore
,
1970 storeProperty
.nextProperty
,
1975 storeProperty
.nextProperty
= propertyIndexToStore
;
1978 else if (typeOfRelation
== PROPERTY_RELATION_DIR
)
1980 if (storeProperty
.dirProperty
!= PROPERTY_NULL
)
1982 return findPlaceholder(
1984 propertyIndexToStore
,
1985 storeProperty
.dirProperty
,
1990 storeProperty
.dirProperty
= propertyIndexToStore
;
1994 hr
= StorageImpl_WriteProperty(
1995 storage
->ancestorStorage
,
2007 /*************************************************************************
2011 * This method takes the previous and the next property link of a property
2012 * to be deleted and find them a place in the Storage.
2014 static HRESULT
adjustPropertyChain(
2016 StgProperty propertyToDelete
,
2017 StgProperty parentProperty
,
2018 ULONG parentPropertyId
,
2021 ULONG newLinkProperty
= PROPERTY_NULL
;
2022 BOOL needToFindAPlaceholder
= FALSE
;
2023 ULONG storeNode
= PROPERTY_NULL
;
2024 ULONG toStoreNode
= PROPERTY_NULL
;
2025 INT relationType
= 0;
2029 if (typeOfRelation
== PROPERTY_RELATION_PREVIOUS
)
2031 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
2034 * Set the parent previous to the property to delete previous
2036 newLinkProperty
= propertyToDelete
.previousProperty
;
2038 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2041 * We also need to find a storage for the other link, setup variables
2042 * to do this at the end...
2044 needToFindAPlaceholder
= TRUE
;
2045 storeNode
= propertyToDelete
.previousProperty
;
2046 toStoreNode
= propertyToDelete
.nextProperty
;
2047 relationType
= PROPERTY_RELATION_NEXT
;
2050 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2053 * Set the parent previous to the property to delete next
2055 newLinkProperty
= propertyToDelete
.nextProperty
;
2059 * Link it for real...
2061 parentProperty
.previousProperty
= newLinkProperty
;
2064 else if (typeOfRelation
== PROPERTY_RELATION_NEXT
)
2066 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
2069 * Set the parent next to the property to delete next previous
2071 newLinkProperty
= propertyToDelete
.previousProperty
;
2073 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2076 * We also need to find a storage for the other link, setup variables
2077 * to do this at the end...
2079 needToFindAPlaceholder
= TRUE
;
2080 storeNode
= propertyToDelete
.previousProperty
;
2081 toStoreNode
= propertyToDelete
.nextProperty
;
2082 relationType
= PROPERTY_RELATION_NEXT
;
2085 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2088 * Set the parent next to the property to delete next
2090 newLinkProperty
= propertyToDelete
.nextProperty
;
2094 * Link it for real...
2096 parentProperty
.nextProperty
= newLinkProperty
;
2098 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2100 if (propertyToDelete
.previousProperty
!= PROPERTY_NULL
)
2103 * Set the parent dir to the property to delete previous
2105 newLinkProperty
= propertyToDelete
.previousProperty
;
2107 if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2110 * We also need to find a storage for the other link, setup variables
2111 * to do this at the end...
2113 needToFindAPlaceholder
= TRUE
;
2114 storeNode
= propertyToDelete
.previousProperty
;
2115 toStoreNode
= propertyToDelete
.nextProperty
;
2116 relationType
= PROPERTY_RELATION_NEXT
;
2119 else if (propertyToDelete
.nextProperty
!= PROPERTY_NULL
)
2122 * Set the parent dir to the property to delete next
2124 newLinkProperty
= propertyToDelete
.nextProperty
;
2128 * Link it for real...
2130 parentProperty
.dirProperty
= newLinkProperty
;
2134 * Write back the parent property
2136 res
= StorageImpl_WriteProperty(
2137 This
->ancestorStorage
,
2146 * If a placeholder is required for the other link, then, find one and
2147 * get out of here...
2149 if (needToFindAPlaceholder
)
2151 hr
= findPlaceholder(
2162 /******************************************************************************
2163 * SetElementTimes (IStorage)
2165 HRESULT WINAPI
StorageImpl_SetElementTimes(
2167 const OLECHAR
*pwcsName
,/* [string][in] */
2168 const FILETIME
*pctime
, /* [in] */
2169 const FILETIME
*patime
, /* [in] */
2170 const FILETIME
*pmtime
) /* [in] */
2172 FIXME("(%s,...), stub!\n",debugstr_w(pwcsName
));
2176 /******************************************************************************
2177 * SetStateBits (IStorage)
2179 HRESULT WINAPI
StorageImpl_SetStateBits(
2181 DWORD grfStateBits
,/* [in] */
2182 DWORD grfMask
) /* [in] */
2184 FIXME("not implemented!\n");
2188 HRESULT
StorageImpl_Construct(
2198 StgProperty currentProperty
;
2199 BOOL readSuccessful
;
2200 ULONG currentPropertyIndex
;
2202 if ( FAILED( validateSTGM(openFlags
) ))
2203 return STG_E_INVALIDFLAG
;
2205 memset(This
, 0, sizeof(StorageImpl
));
2208 * Initialize the virtual function table.
2210 ICOM_VTBL(This
) = &Storage32Impl_Vtbl
;
2211 This
->v_destructor
= &StorageImpl_Destroy
;
2214 * This is the top-level storage so initialize the ancestor pointer
2217 This
->ancestorStorage
= This
;
2220 * Initialize the physical support of the storage.
2222 This
->hFile
= hFile
;
2225 * Store copy of file path.
2228 This
->pwcsName
= HeapAlloc(GetProcessHeap(), 0,
2229 (lstrlenW(pwcsName
)+1)*sizeof(WCHAR
));
2230 if (!This
->pwcsName
)
2231 return STG_E_INSUFFICIENTMEMORY
;
2232 strcpyW(This
->pwcsName
, pwcsName
);
2236 * Initialize the big block cache.
2238 This
->bigBlockSize
= DEF_BIG_BLOCK_SIZE
;
2239 This
->smallBlockSize
= DEF_SMALL_BLOCK_SIZE
;
2240 This
->bigBlockFile
= BIGBLOCKFILE_Construct(hFile
,
2246 if (This
->bigBlockFile
== 0)
2251 ULARGE_INTEGER size
;
2252 BYTE
* bigBlockBuffer
;
2255 * Initialize all header variables:
2256 * - The big block depot consists of one block and it is at block 0
2257 * - The properties start at block 1
2258 * - There is no small block depot
2260 memset( This
->bigBlockDepotStart
,
2262 sizeof(This
->bigBlockDepotStart
));
2264 This
->bigBlockDepotCount
= 1;
2265 This
->bigBlockDepotStart
[0] = 0;
2266 This
->rootStartBlock
= 1;
2267 This
->smallBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2268 This
->bigBlockSizeBits
= DEF_BIG_BLOCK_SIZE_BITS
;
2269 This
->smallBlockSizeBits
= DEF_SMALL_BLOCK_SIZE_BITS
;
2270 This
->extBigBlockDepotStart
= BLOCK_END_OF_CHAIN
;
2271 This
->extBigBlockDepotCount
= 0;
2273 StorageImpl_SaveFileHeader(This
);
2276 * Add one block for the big block depot and one block for the properties
2278 size
.s
.HighPart
= 0;
2279 size
.s
.LowPart
= This
->bigBlockSize
* 3;
2280 BIGBLOCKFILE_SetSize(This
->bigBlockFile
, size
);
2283 * Initialize the big block depot
2285 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, 0);
2286 memset(bigBlockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2287 StorageUtl_WriteDWord(bigBlockBuffer
, 0, BLOCK_SPECIAL
);
2288 StorageUtl_WriteDWord(bigBlockBuffer
, sizeof(ULONG
), BLOCK_END_OF_CHAIN
);
2289 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
2294 * Load the header for the file.
2296 hr
= StorageImpl_LoadFileHeader(This
);
2300 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2307 * There is no block depot cached yet.
2309 This
->indexBlockDepotCached
= 0xFFFFFFFF;
2312 * Start searching for free blocks with block 0.
2314 This
->prevFreeBlock
= 0;
2317 * Create the block chain abstractions.
2319 This
->rootBlockChain
=
2320 BlockChainStream_Construct(This
, &This
->rootStartBlock
, PROPERTY_NULL
);
2322 This
->smallBlockDepotChain
= BlockChainStream_Construct(
2324 &This
->smallBlockDepotStart
,
2328 * Write the root property
2332 StgProperty rootProp
;
2334 * Initialize the property chain
2336 memset(&rootProp
, 0, sizeof(rootProp
));
2337 MultiByteToWideChar( CP_ACP
, 0, rootPropertyName
, -1, rootProp
.name
,
2338 sizeof(rootProp
.name
)/sizeof(WCHAR
) );
2339 rootProp
.sizeOfNameString
= (strlenW(rootProp
.name
)+1) * sizeof(WCHAR
);
2340 rootProp
.propertyType
= PROPTYPE_ROOT
;
2341 rootProp
.previousProperty
= PROPERTY_NULL
;
2342 rootProp
.nextProperty
= PROPERTY_NULL
;
2343 rootProp
.dirProperty
= PROPERTY_NULL
;
2344 rootProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
2345 rootProp
.size
.s
.HighPart
= 0;
2346 rootProp
.size
.s
.LowPart
= 0;
2348 StorageImpl_WriteProperty(This
, 0, &rootProp
);
2352 * Find the ID of the root in the property sets.
2354 currentPropertyIndex
= 0;
2358 readSuccessful
= StorageImpl_ReadProperty(
2360 currentPropertyIndex
,
2365 if ( (currentProperty
.sizeOfNameString
!= 0 ) &&
2366 (currentProperty
.propertyType
== PROPTYPE_ROOT
) )
2368 This
->rootPropertySetIndex
= currentPropertyIndex
;
2372 currentPropertyIndex
++;
2374 } while (readSuccessful
&& (This
->rootPropertySetIndex
== PROPERTY_NULL
) );
2376 if (!readSuccessful
)
2383 * Create the block chain abstraction for the small block root chain.
2385 This
->smallBlockRootChain
= BlockChainStream_Construct(
2388 This
->rootPropertySetIndex
);
2393 void StorageImpl_Destroy(
2396 TRACE("(%p)\n", This
);
2399 HeapFree(GetProcessHeap(), 0, This
->pwcsName
);
2401 BlockChainStream_Destroy(This
->smallBlockRootChain
);
2402 BlockChainStream_Destroy(This
->rootBlockChain
);
2403 BlockChainStream_Destroy(This
->smallBlockDepotChain
);
2405 BIGBLOCKFILE_Destructor(This
->bigBlockFile
);
2409 /******************************************************************************
2410 * Storage32Impl_GetNextFreeBigBlock
2412 * Returns the index of the next free big block.
2413 * If the big block depot is filled, this method will enlarge it.
2416 ULONG
StorageImpl_GetNextFreeBigBlock(
2419 ULONG depotBlockIndexPos
;
2421 ULONG depotBlockOffset
;
2422 ULONG blocksPerDepot
= This
->bigBlockSize
/ sizeof(ULONG
);
2423 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2425 ULONG freeBlock
= BLOCK_UNUSED
;
2427 depotIndex
= This
->prevFreeBlock
/ blocksPerDepot
;
2428 depotBlockOffset
= (This
->prevFreeBlock
% blocksPerDepot
) * sizeof(ULONG
);
2431 * Scan the entire big block depot until we find a block marked free
2433 while (nextBlockIndex
!= BLOCK_UNUSED
)
2435 if (depotIndex
< COUNT_BBDEPOTINHEADER
)
2437 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotIndex
];
2440 * Grow the primary depot.
2442 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2444 depotBlockIndexPos
= depotIndex
*blocksPerDepot
;
2447 * Add a block depot.
2449 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2450 This
->bigBlockDepotCount
++;
2451 This
->bigBlockDepotStart
[depotIndex
] = depotBlockIndexPos
;
2454 * Flag it as a block depot.
2456 StorageImpl_SetNextBlockInChain(This
,
2460 /* Save new header information.
2462 StorageImpl_SaveFileHeader(This
);
2467 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotIndex
);
2469 if (depotBlockIndexPos
== BLOCK_UNUSED
)
2472 * Grow the extended depot.
2474 ULONG extIndex
= BLOCK_UNUSED
;
2475 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2476 ULONG extBlockOffset
= numExtBlocks
% (blocksPerDepot
- 1);
2478 if (extBlockOffset
== 0)
2480 /* We need an extended block.
2482 extIndex
= Storage32Impl_AddExtBlockDepot(This
);
2483 This
->extBigBlockDepotCount
++;
2484 depotBlockIndexPos
= extIndex
+ 1;
2487 depotBlockIndexPos
= depotIndex
* blocksPerDepot
;
2490 * Add a block depot and mark it in the extended block.
2492 Storage32Impl_AddBlockDepot(This
, depotBlockIndexPos
);
2493 This
->bigBlockDepotCount
++;
2494 Storage32Impl_SetExtDepotBlock(This
, depotIndex
, depotBlockIndexPos
);
2496 /* Flag the block depot.
2498 StorageImpl_SetNextBlockInChain(This
,
2502 /* If necessary, flag the extended depot block.
2504 if (extIndex
!= BLOCK_UNUSED
)
2505 StorageImpl_SetNextBlockInChain(This
, extIndex
, BLOCK_EXTBBDEPOT
);
2507 /* Save header information.
2509 StorageImpl_SaveFileHeader(This
);
2513 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2515 if (depotBuffer
!= 0)
2517 while ( ( (depotBlockOffset
/sizeof(ULONG
) ) < blocksPerDepot
) &&
2518 ( nextBlockIndex
!= BLOCK_UNUSED
))
2520 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2522 if (nextBlockIndex
== BLOCK_UNUSED
)
2524 freeBlock
= (depotIndex
* blocksPerDepot
) +
2525 (depotBlockOffset
/sizeof(ULONG
));
2528 depotBlockOffset
+= sizeof(ULONG
);
2531 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2535 depotBlockOffset
= 0;
2538 This
->prevFreeBlock
= freeBlock
;
2543 /******************************************************************************
2544 * Storage32Impl_AddBlockDepot
2546 * This will create a depot block, essentially it is a block initialized
2549 void Storage32Impl_AddBlockDepot(StorageImpl
* This
, ULONG blockIndex
)
2553 blockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
2556 * Initialize blocks as free
2558 memset(blockBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2560 StorageImpl_ReleaseBigBlock(This
, blockBuffer
);
2563 /******************************************************************************
2564 * Storage32Impl_GetExtDepotBlock
2566 * Returns the index of the block that corresponds to the specified depot
2567 * index. This method is only for depot indexes equal or greater than
2568 * COUNT_BBDEPOTINHEADER.
2570 ULONG
Storage32Impl_GetExtDepotBlock(StorageImpl
* This
, ULONG depotIndex
)
2572 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2573 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2574 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2575 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2576 ULONG blockIndex
= BLOCK_UNUSED
;
2577 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2579 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2581 if (This
->extBigBlockDepotStart
== BLOCK_END_OF_CHAIN
)
2582 return BLOCK_UNUSED
;
2584 while (extBlockCount
> 0)
2586 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2590 if (extBlockIndex
!= BLOCK_UNUSED
)
2594 depotBuffer
= StorageImpl_GetROBigBlock(This
, extBlockIndex
);
2596 if (depotBuffer
!= 0)
2598 StorageUtl_ReadDWord(depotBuffer
,
2599 extBlockOffset
* sizeof(ULONG
),
2602 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2609 /******************************************************************************
2610 * Storage32Impl_SetExtDepotBlock
2612 * Associates the specified block index to the specified depot index.
2613 * This method is only for depot indexes equal or greater than
2614 * COUNT_BBDEPOTINHEADER.
2616 void Storage32Impl_SetExtDepotBlock(StorageImpl
* This
,
2620 ULONG depotBlocksPerExtBlock
= (This
->bigBlockSize
/ sizeof(ULONG
)) - 1;
2621 ULONG numExtBlocks
= depotIndex
- COUNT_BBDEPOTINHEADER
;
2622 ULONG extBlockCount
= numExtBlocks
/ depotBlocksPerExtBlock
;
2623 ULONG extBlockOffset
= numExtBlocks
% depotBlocksPerExtBlock
;
2624 ULONG extBlockIndex
= This
->extBigBlockDepotStart
;
2626 assert(depotIndex
>= COUNT_BBDEPOTINHEADER
);
2628 while (extBlockCount
> 0)
2630 extBlockIndex
= Storage32Impl_GetNextExtendedBlock(This
, extBlockIndex
);
2634 if (extBlockIndex
!= BLOCK_UNUSED
)
2638 depotBuffer
= StorageImpl_GetBigBlock(This
, extBlockIndex
);
2640 if (depotBuffer
!= 0)
2642 StorageUtl_WriteDWord(depotBuffer
,
2643 extBlockOffset
* sizeof(ULONG
),
2646 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2651 /******************************************************************************
2652 * Storage32Impl_AddExtBlockDepot
2654 * Creates an extended depot block.
2656 ULONG
Storage32Impl_AddExtBlockDepot(StorageImpl
* This
)
2658 ULONG numExtBlocks
= This
->extBigBlockDepotCount
;
2659 ULONG nextExtBlock
= This
->extBigBlockDepotStart
;
2660 BYTE
* depotBuffer
= NULL
;
2661 ULONG index
= BLOCK_UNUSED
;
2662 ULONG nextBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2663 ULONG blocksPerDepotBlock
= This
->bigBlockSize
/ sizeof(ULONG
);
2664 ULONG depotBlocksPerExtBlock
= blocksPerDepotBlock
- 1;
2666 index
= (COUNT_BBDEPOTINHEADER
+ (numExtBlocks
* depotBlocksPerExtBlock
)) *
2667 blocksPerDepotBlock
;
2669 if ((numExtBlocks
== 0) && (nextExtBlock
== BLOCK_END_OF_CHAIN
))
2672 * The first extended block.
2674 This
->extBigBlockDepotStart
= index
;
2680 * Follow the chain to the last one.
2682 for (i
= 0; i
< (numExtBlocks
- 1); i
++)
2684 nextExtBlock
= Storage32Impl_GetNextExtendedBlock(This
, nextExtBlock
);
2688 * Add the new extended block to the chain.
2690 depotBuffer
= StorageImpl_GetBigBlock(This
, nextExtBlock
);
2691 StorageUtl_WriteDWord(depotBuffer
, nextBlockOffset
, index
);
2692 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2696 * Initialize this block.
2698 depotBuffer
= StorageImpl_GetBigBlock(This
, index
);
2699 memset(depotBuffer
, BLOCK_UNUSED
, This
->bigBlockSize
);
2700 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2705 /******************************************************************************
2706 * Storage32Impl_FreeBigBlock
2708 * This method will flag the specified block as free in the big block depot.
2710 void StorageImpl_FreeBigBlock(
2714 StorageImpl_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
2716 if (blockIndex
< This
->prevFreeBlock
)
2717 This
->prevFreeBlock
= blockIndex
;
2720 /************************************************************************
2721 * Storage32Impl_GetNextBlockInChain
2723 * This method will retrieve the block index of the next big block in
2726 * Params: This - Pointer to the Storage object.
2727 * blockIndex - Index of the block to retrieve the chain
2730 * Returns: This method returns the index of the next block in the chain.
2731 * It will return the constants:
2732 * BLOCK_SPECIAL - If the block given was not part of a
2734 * BLOCK_END_OF_CHAIN - If the block given was the last in
2736 * BLOCK_UNUSED - If the block given was not past of a chain
2738 * BLOCK_EXTBBDEPOT - This block is part of the extended
2741 * See Windows documentation for more details on IStorage methods.
2743 ULONG
StorageImpl_GetNextBlockInChain(
2747 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2748 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2749 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2750 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2752 ULONG depotBlockIndexPos
;
2754 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2757 * Cache the currently accessed depot block.
2759 if (depotBlockCount
!= This
->indexBlockDepotCached
)
2761 This
->indexBlockDepotCached
= depotBlockCount
;
2763 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2765 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2770 * We have to look in the extended depot.
2772 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2775 depotBuffer
= StorageImpl_GetROBigBlock(This
, depotBlockIndexPos
);
2781 for (index
= 0; index
< NUM_BLOCKS_PER_DEPOT_BLOCK
; index
++)
2783 StorageUtl_ReadDWord(depotBuffer
, index
*sizeof(ULONG
), &nextBlockIndex
);
2784 This
->blockDepotCached
[index
] = nextBlockIndex
;
2787 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2791 nextBlockIndex
= This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)];
2793 return nextBlockIndex
;
2796 /******************************************************************************
2797 * Storage32Impl_GetNextExtendedBlock
2799 * Given an extended block this method will return the next extended block.
2802 * The last ULONG of an extended block is the block index of the next
2803 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2807 * - The index of the next extended block
2808 * - BLOCK_UNUSED: there is no next extended block.
2809 * - Any other return values denotes failure.
2811 ULONG
Storage32Impl_GetNextExtendedBlock(StorageImpl
* This
, ULONG blockIndex
)
2813 ULONG nextBlockIndex
= BLOCK_SPECIAL
;
2814 ULONG depotBlockOffset
= This
->bigBlockSize
- sizeof(ULONG
);
2817 depotBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
2821 StorageUtl_ReadDWord(depotBuffer
, depotBlockOffset
, &nextBlockIndex
);
2823 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2826 return nextBlockIndex
;
2829 /******************************************************************************
2830 * Storage32Impl_SetNextBlockInChain
2832 * This method will write the index of the specified block's next block
2833 * in the big block depot.
2835 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2838 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2839 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2840 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2843 void StorageImpl_SetNextBlockInChain(
2848 ULONG offsetInDepot
= blockIndex
* sizeof (ULONG
);
2849 ULONG depotBlockCount
= offsetInDepot
/ This
->bigBlockSize
;
2850 ULONG depotBlockOffset
= offsetInDepot
% This
->bigBlockSize
;
2851 ULONG depotBlockIndexPos
;
2854 assert(depotBlockCount
< This
->bigBlockDepotCount
);
2855 assert(blockIndex
!= nextBlock
);
2857 if (depotBlockCount
< COUNT_BBDEPOTINHEADER
)
2859 depotBlockIndexPos
= This
->bigBlockDepotStart
[depotBlockCount
];
2864 * We have to look in the extended depot.
2866 depotBlockIndexPos
= Storage32Impl_GetExtDepotBlock(This
, depotBlockCount
);
2869 depotBuffer
= StorageImpl_GetBigBlock(This
, depotBlockIndexPos
);
2873 StorageUtl_WriteDWord(depotBuffer
, depotBlockOffset
, nextBlock
);
2874 StorageImpl_ReleaseBigBlock(This
, depotBuffer
);
2878 * Update the cached block depot, if necessary.
2880 if (depotBlockCount
== This
->indexBlockDepotCached
)
2882 This
->blockDepotCached
[depotBlockOffset
/sizeof(ULONG
)] = nextBlock
;
2886 /******************************************************************************
2887 * Storage32Impl_LoadFileHeader
2889 * This method will read in the file header, i.e. big block index -1.
2891 HRESULT
StorageImpl_LoadFileHeader(
2894 HRESULT hr
= STG_E_FILENOTFOUND
;
2895 void* headerBigBlock
= NULL
;
2899 * Get a pointer to the big block of data containing the header.
2901 headerBigBlock
= StorageImpl_GetROBigBlock(This
, -1);
2904 * Extract the information from the header.
2906 if (headerBigBlock
!=0)
2909 * Check for the "magic number" signature and return an error if it is not
2912 if (memcmp(headerBigBlock
, STORAGE_oldmagic
, sizeof(STORAGE_oldmagic
))==0)
2914 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2915 return STG_E_OLDFORMAT
;
2918 if (memcmp(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
))!=0)
2920 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
2921 return STG_E_INVALIDHEADER
;
2924 StorageUtl_ReadWord(
2926 OFFSET_BIGBLOCKSIZEBITS
,
2927 &This
->bigBlockSizeBits
);
2929 StorageUtl_ReadWord(
2931 OFFSET_SMALLBLOCKSIZEBITS
,
2932 &This
->smallBlockSizeBits
);
2934 StorageUtl_ReadDWord(
2936 OFFSET_BBDEPOTCOUNT
,
2937 &This
->bigBlockDepotCount
);
2939 StorageUtl_ReadDWord(
2941 OFFSET_ROOTSTARTBLOCK
,
2942 &This
->rootStartBlock
);
2944 StorageUtl_ReadDWord(
2946 OFFSET_SBDEPOTSTART
,
2947 &This
->smallBlockDepotStart
);
2949 StorageUtl_ReadDWord(
2951 OFFSET_EXTBBDEPOTSTART
,
2952 &This
->extBigBlockDepotStart
);
2954 StorageUtl_ReadDWord(
2956 OFFSET_EXTBBDEPOTCOUNT
,
2957 &This
->extBigBlockDepotCount
);
2959 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
2961 StorageUtl_ReadDWord(
2963 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
2964 &(This
->bigBlockDepotStart
[index
]));
2968 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2972 This
->bigBlockSize
= 0x000000001 << (DWORD
)This
->bigBlockSizeBits
;
2973 This
->smallBlockSize
= 0x000000001 << (DWORD
)This
->smallBlockSizeBits
;
2977 This
->bigBlockSize
= 0x000000001 >> (DWORD
)This
->bigBlockSizeBits
;
2978 This
->smallBlockSize
= 0x000000001 >> (DWORD
)This
->smallBlockSizeBits
;
2982 * Right now, the code is making some assumptions about the size of the
2983 * blocks, just make sure they are what we're expecting.
2985 if (This
->bigBlockSize
!= DEF_BIG_BLOCK_SIZE
||
2986 This
->smallBlockSize
!= DEF_SMALL_BLOCK_SIZE
)
2988 WARN("Broken OLE storage file\n");
2989 hr
= STG_E_INVALIDHEADER
;
2995 * Release the block.
2997 StorageImpl_ReleaseBigBlock(This
, headerBigBlock
);
3003 /******************************************************************************
3004 * Storage32Impl_SaveFileHeader
3006 * This method will save to the file the header, i.e. big block -1.
3008 void StorageImpl_SaveFileHeader(
3011 BYTE headerBigBlock
[BIG_BLOCK_SIZE
];
3016 * Get a pointer to the big block of data containing the header.
3018 success
= StorageImpl_ReadBigBlock(This
, -1, headerBigBlock
);
3021 * If the block read failed, the file is probably new.
3026 * Initialize for all unknown fields.
3028 memset(headerBigBlock
, 0, BIG_BLOCK_SIZE
);
3031 * Initialize the magic number.
3033 memcpy(headerBigBlock
, STORAGE_magic
, sizeof(STORAGE_magic
));
3036 * And a bunch of things we don't know what they mean
3038 StorageUtl_WriteWord(headerBigBlock
, 0x18, 0x3b);
3039 StorageUtl_WriteWord(headerBigBlock
, 0x1a, 0x3);
3040 StorageUtl_WriteWord(headerBigBlock
, 0x1c, (WORD
)-2);
3041 StorageUtl_WriteDWord(headerBigBlock
, 0x38, (DWORD
)0x1000);
3042 StorageUtl_WriteDWord(headerBigBlock
, 0x40, (DWORD
)0x0001);
3046 * Write the information to the header.
3048 if (headerBigBlock
!=0)
3050 StorageUtl_WriteWord(
3052 OFFSET_BIGBLOCKSIZEBITS
,
3053 This
->bigBlockSizeBits
);
3055 StorageUtl_WriteWord(
3057 OFFSET_SMALLBLOCKSIZEBITS
,
3058 This
->smallBlockSizeBits
);
3060 StorageUtl_WriteDWord(
3062 OFFSET_BBDEPOTCOUNT
,
3063 This
->bigBlockDepotCount
);
3065 StorageUtl_WriteDWord(
3067 OFFSET_ROOTSTARTBLOCK
,
3068 This
->rootStartBlock
);
3070 StorageUtl_WriteDWord(
3072 OFFSET_SBDEPOTSTART
,
3073 This
->smallBlockDepotStart
);
3075 StorageUtl_WriteDWord(
3077 OFFSET_EXTBBDEPOTSTART
,
3078 This
->extBigBlockDepotStart
);
3080 StorageUtl_WriteDWord(
3082 OFFSET_EXTBBDEPOTCOUNT
,
3083 This
->extBigBlockDepotCount
);
3085 for (index
= 0; index
< COUNT_BBDEPOTINHEADER
; index
++)
3087 StorageUtl_WriteDWord(
3089 OFFSET_BBDEPOTSTART
+ (sizeof(ULONG
)*index
),
3090 (This
->bigBlockDepotStart
[index
]));
3095 * Write the big block back to the file.
3097 StorageImpl_WriteBigBlock(This
, -1, headerBigBlock
);
3100 /******************************************************************************
3101 * Storage32Impl_ReadProperty
3103 * This method will read the specified property from the property chain.
3105 BOOL
StorageImpl_ReadProperty(
3108 StgProperty
* buffer
)
3110 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3111 ULARGE_INTEGER offsetInPropSet
;
3112 BOOL readSuccessful
;
3115 offsetInPropSet
.s
.HighPart
= 0;
3116 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3118 readSuccessful
= BlockChainStream_ReadAt(
3119 This
->rootBlockChain
,
3127 /* replace the name of root entry (often "Root Entry") by the file name */
3128 WCHAR
*propName
= (index
== This
->rootPropertySetIndex
) ?
3129 This
->filename
: (WCHAR
*)currentProperty
+OFFSET_PS_NAME
;
3131 memset(buffer
->name
, 0, sizeof(buffer
->name
));
3135 PROPERTY_NAME_BUFFER_LEN
);
3136 TRACE("storage name: %s\n", debugstr_w(buffer
->name
));
3138 memcpy(&buffer
->propertyType
, currentProperty
+ OFFSET_PS_PROPERTYTYPE
, 1);
3140 StorageUtl_ReadWord(
3142 OFFSET_PS_NAMELENGTH
,
3143 &buffer
->sizeOfNameString
);
3145 StorageUtl_ReadDWord(
3147 OFFSET_PS_PREVIOUSPROP
,
3148 &buffer
->previousProperty
);
3150 StorageUtl_ReadDWord(
3153 &buffer
->nextProperty
);
3155 StorageUtl_ReadDWord(
3158 &buffer
->dirProperty
);
3160 StorageUtl_ReadGUID(
3163 &buffer
->propertyUniqueID
);
3165 StorageUtl_ReadDWord(
3168 &buffer
->timeStampS1
);
3170 StorageUtl_ReadDWord(
3173 &buffer
->timeStampD1
);
3175 StorageUtl_ReadDWord(
3178 &buffer
->timeStampS2
);
3180 StorageUtl_ReadDWord(
3183 &buffer
->timeStampD2
);
3185 StorageUtl_ReadDWord(
3187 OFFSET_PS_STARTBLOCK
,
3188 &buffer
->startingBlock
);
3190 StorageUtl_ReadDWord(
3193 &buffer
->size
.s
.LowPart
);
3195 buffer
->size
.s
.HighPart
= 0;
3198 return readSuccessful
;
3201 /*********************************************************************
3202 * Write the specified property into the property chain
3204 BOOL
StorageImpl_WriteProperty(
3207 StgProperty
* buffer
)
3209 BYTE currentProperty
[PROPSET_BLOCK_SIZE
];
3210 ULARGE_INTEGER offsetInPropSet
;
3211 BOOL writeSuccessful
;
3214 offsetInPropSet
.s
.HighPart
= 0;
3215 offsetInPropSet
.s
.LowPart
= index
* PROPSET_BLOCK_SIZE
;
3217 memset(currentProperty
, 0, PROPSET_BLOCK_SIZE
);
3220 currentProperty
+ OFFSET_PS_NAME
,
3222 PROPERTY_NAME_BUFFER_LEN
);
3224 memcpy(currentProperty
+ OFFSET_PS_PROPERTYTYPE
, &buffer
->propertyType
, 1);
3226 StorageUtl_WriteWord(
3228 OFFSET_PS_NAMELENGTH
,
3229 buffer
->sizeOfNameString
);
3231 StorageUtl_WriteDWord(
3233 OFFSET_PS_PREVIOUSPROP
,
3234 buffer
->previousProperty
);
3236 StorageUtl_WriteDWord(
3239 buffer
->nextProperty
);
3241 StorageUtl_WriteDWord(
3244 buffer
->dirProperty
);
3246 StorageUtl_WriteGUID(
3249 &buffer
->propertyUniqueID
);
3251 StorageUtl_WriteDWord(
3254 buffer
->timeStampS1
);
3256 StorageUtl_WriteDWord(
3259 buffer
->timeStampD1
);
3261 StorageUtl_WriteDWord(
3264 buffer
->timeStampS2
);
3266 StorageUtl_WriteDWord(
3269 buffer
->timeStampD2
);
3271 StorageUtl_WriteDWord(
3273 OFFSET_PS_STARTBLOCK
,
3274 buffer
->startingBlock
);
3276 StorageUtl_WriteDWord(
3279 buffer
->size
.s
.LowPart
);
3281 writeSuccessful
= BlockChainStream_WriteAt(This
->rootBlockChain
,
3286 return writeSuccessful
;
3289 BOOL
StorageImpl_ReadBigBlock(
3294 void* bigBlockBuffer
;
3296 bigBlockBuffer
= StorageImpl_GetROBigBlock(This
, blockIndex
);
3298 if (bigBlockBuffer
!=0)
3300 memcpy(buffer
, bigBlockBuffer
, This
->bigBlockSize
);
3302 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3310 BOOL
StorageImpl_WriteBigBlock(
3315 void* bigBlockBuffer
;
3317 bigBlockBuffer
= StorageImpl_GetBigBlock(This
, blockIndex
);
3319 if (bigBlockBuffer
!=0)
3321 memcpy(bigBlockBuffer
, buffer
, This
->bigBlockSize
);
3323 StorageImpl_ReleaseBigBlock(This
, bigBlockBuffer
);
3331 void* StorageImpl_GetROBigBlock(
3335 return BIGBLOCKFILE_GetROBigBlock(This
->bigBlockFile
, blockIndex
);
3338 void* StorageImpl_GetBigBlock(
3342 return BIGBLOCKFILE_GetBigBlock(This
->bigBlockFile
, blockIndex
);
3345 void StorageImpl_ReleaseBigBlock(
3349 BIGBLOCKFILE_ReleaseBigBlock(This
->bigBlockFile
, pBigBlock
);
3352 /******************************************************************************
3353 * Storage32Impl_SmallBlocksToBigBlocks
3355 * This method will convert a small block chain to a big block chain.
3356 * The small block chain will be destroyed.
3358 BlockChainStream
* Storage32Impl_SmallBlocksToBigBlocks(
3360 SmallBlockChainStream
** ppsbChain
)
3362 ULONG bbHeadOfChain
= BLOCK_END_OF_CHAIN
;
3363 ULARGE_INTEGER size
, offset
;
3364 ULONG cbRead
, cbWritten
, cbTotalRead
, cbTotalWritten
;
3365 ULONG propertyIndex
;
3366 BOOL successRead
, successWrite
;
3367 StgProperty chainProperty
;
3369 BlockChainStream
*bbTempChain
= NULL
;
3370 BlockChainStream
*bigBlockChain
= NULL
;
3373 * Create a temporary big block chain that doesn't have
3374 * an associated property. This temporary chain will be
3375 * used to copy data from small blocks to big blocks.
3377 bbTempChain
= BlockChainStream_Construct(This
,
3382 * Grow the big block chain.
3384 size
= SmallBlockChainStream_GetSize(*ppsbChain
);
3385 BlockChainStream_SetSize(bbTempChain
, size
);
3388 * Copy the contents of the small block chain to the big block chain
3389 * by small block size increments.
3391 offset
.s
.LowPart
= 0;
3392 offset
.s
.HighPart
= 0;
3396 buffer
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE
);
3399 successRead
= SmallBlockChainStream_ReadAt(*ppsbChain
,
3401 DEF_SMALL_BLOCK_SIZE
,
3404 cbTotalRead
+= cbRead
;
3406 successWrite
= BlockChainStream_WriteAt(bbTempChain
,
3411 cbTotalWritten
+= cbWritten
;
3413 offset
.s
.LowPart
+= This
->smallBlockSize
;
3415 } while (successRead
&& successWrite
);
3416 HeapFree(GetProcessHeap(),0,buffer
);
3418 assert(cbTotalRead
== cbTotalWritten
);
3421 * Destroy the small block chain.
3423 propertyIndex
= (*ppsbChain
)->ownerPropertyIndex
;
3424 size
.s
.HighPart
= 0;
3426 SmallBlockChainStream_SetSize(*ppsbChain
, size
);
3427 SmallBlockChainStream_Destroy(*ppsbChain
);
3431 * Change the property information. This chain is now a big block chain
3432 * and it doesn't reside in the small blocks chain anymore.
3434 StorageImpl_ReadProperty(This
, propertyIndex
, &chainProperty
);
3436 chainProperty
.startingBlock
= bbHeadOfChain
;
3438 StorageImpl_WriteProperty(This
, propertyIndex
, &chainProperty
);
3441 * Destroy the temporary propertyless big block chain.
3442 * Create a new big block chain associated with this property.
3444 BlockChainStream_Destroy(bbTempChain
);
3445 bigBlockChain
= BlockChainStream_Construct(This
,
3449 return bigBlockChain
;
3452 /******************************************************************************
3453 ** Storage32InternalImpl implementation
3456 StorageInternalImpl
* StorageInternalImpl_Construct(
3457 StorageImpl
* ancestorStorage
,
3458 ULONG rootPropertyIndex
)
3460 StorageInternalImpl
* newStorage
;
3463 * Allocate space for the new storage object
3465 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl
));
3469 memset(newStorage
, 0, sizeof(StorageInternalImpl
));
3472 * Initialize the virtual function table.
3474 ICOM_VTBL(newStorage
) = &Storage32InternalImpl_Vtbl
;
3475 newStorage
->v_destructor
= &StorageInternalImpl_Destroy
;
3478 * Keep the ancestor storage pointer and nail a reference to it.
3480 newStorage
->ancestorStorage
= ancestorStorage
;
3481 StorageBaseImpl_AddRef((IStorage
*)(newStorage
->ancestorStorage
));
3484 * Keep the index of the root property set for this storage,
3486 newStorage
->rootPropertySetIndex
= rootPropertyIndex
;
3494 void StorageInternalImpl_Destroy(
3495 StorageInternalImpl
* This
)
3497 StorageBaseImpl_Release((IStorage
*)This
->ancestorStorage
);
3498 HeapFree(GetProcessHeap(), 0, This
);
3501 /******************************************************************************
3503 ** Storage32InternalImpl_Commit
3505 ** The non-root storages cannot be opened in transacted mode thus this function
3508 HRESULT WINAPI
StorageInternalImpl_Commit(
3510 DWORD grfCommitFlags
) /* [in] */
3515 /******************************************************************************
3517 ** Storage32InternalImpl_Revert
3519 ** The non-root storages cannot be opened in transacted mode thus this function
3522 HRESULT WINAPI
StorageInternalImpl_Revert(
3528 /******************************************************************************
3529 ** IEnumSTATSTGImpl implementation
3532 IEnumSTATSTGImpl
* IEnumSTATSTGImpl_Construct(
3533 StorageImpl
* parentStorage
,
3534 ULONG firstPropertyNode
)
3536 IEnumSTATSTGImpl
* newEnumeration
;
3538 newEnumeration
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl
));
3540 if (newEnumeration
!=0)
3543 * Set-up the virtual function table and reference count.
3545 ICOM_VTBL(newEnumeration
) = &IEnumSTATSTGImpl_Vtbl
;
3546 newEnumeration
->ref
= 0;
3549 * We want to nail-down the reference to the storage in case the
3550 * enumeration out-lives the storage in the client application.
3552 newEnumeration
->parentStorage
= parentStorage
;
3553 IStorage_AddRef((IStorage
*)newEnumeration
->parentStorage
);
3555 newEnumeration
->firstPropertyNode
= firstPropertyNode
;
3558 * Initialize the search stack
3560 newEnumeration
->stackSize
= 0;
3561 newEnumeration
->stackMaxSize
= ENUMSTATSGT_SIZE_INCREMENT
;
3562 newEnumeration
->stackToVisit
=
3563 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
)*ENUMSTATSGT_SIZE_INCREMENT
);
3566 * Make sure the current node of the iterator is the first one.
3568 IEnumSTATSTGImpl_Reset((IEnumSTATSTG
*)newEnumeration
);
3571 return newEnumeration
;
3574 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl
* This
)
3576 IStorage_Release((IStorage
*)This
->parentStorage
);
3577 HeapFree(GetProcessHeap(), 0, This
->stackToVisit
);
3578 HeapFree(GetProcessHeap(), 0, This
);
3581 HRESULT WINAPI
IEnumSTATSTGImpl_QueryInterface(
3582 IEnumSTATSTG
* iface
,
3586 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3589 * Perform a sanity check on the parameters.
3592 return E_INVALIDARG
;
3595 * Initialize the return parameter.
3600 * Compare the riid with the interface IDs implemented by this object.
3602 if (memcmp(&IID_IUnknown
, riid
, sizeof(IID_IUnknown
)) == 0)
3604 *ppvObject
= (IEnumSTATSTG
*)This
;
3606 else if (memcmp(&IID_IStorage
, riid
, sizeof(IID_IEnumSTATSTG
)) == 0)
3608 *ppvObject
= (IEnumSTATSTG
*)This
;
3612 * Check that we obtained an interface.
3614 if ((*ppvObject
)==0)
3615 return E_NOINTERFACE
;
3618 * Query Interface always increases the reference count by one when it is
3621 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG
*)This
);
3626 ULONG WINAPI
IEnumSTATSTGImpl_AddRef(
3627 IEnumSTATSTG
* iface
)
3629 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3635 ULONG WINAPI
IEnumSTATSTGImpl_Release(
3636 IEnumSTATSTG
* iface
)
3638 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3646 * If the reference count goes down to 0, perform suicide.
3650 IEnumSTATSTGImpl_Destroy(This
);
3656 HRESULT WINAPI
IEnumSTATSTGImpl_Next(
3657 IEnumSTATSTG
* iface
,
3660 ULONG
* pceltFetched
)
3662 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3664 StgProperty currentProperty
;
3665 STATSTG
* currentReturnStruct
= rgelt
;
3666 ULONG objectFetched
= 0;
3667 ULONG currentSearchNode
;
3670 * Perform a sanity check on the parameters.
3672 if ( (rgelt
==0) || ( (celt
!=1) && (pceltFetched
==0) ) )
3673 return E_INVALIDARG
;
3676 * To avoid the special case, get another pointer to a ULONG value if
3677 * the caller didn't supply one.
3679 if (pceltFetched
==0)
3680 pceltFetched
= &objectFetched
;
3683 * Start the iteration, we will iterate until we hit the end of the
3684 * linked list or until we hit the number of items to iterate through
3689 * Start with the node at the top of the stack.
3691 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3693 while ( ( *pceltFetched
< celt
) &&
3694 ( currentSearchNode
!=PROPERTY_NULL
) )
3697 * Remove the top node from the stack
3699 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3702 * Read the property from the storage.
3704 StorageImpl_ReadProperty(This
->parentStorage
,
3709 * Copy the information to the return buffer.
3711 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct
,
3716 * Step to the next item in the iteration
3719 currentReturnStruct
++;
3722 * Push the next search node in the search stack.
3724 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3727 * continue the iteration.
3729 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3732 if (*pceltFetched
== celt
)
3739 HRESULT WINAPI
IEnumSTATSTGImpl_Skip(
3740 IEnumSTATSTG
* iface
,
3743 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3745 StgProperty currentProperty
;
3746 ULONG objectFetched
= 0;
3747 ULONG currentSearchNode
;
3750 * Start with the node at the top of the stack.
3752 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3754 while ( (objectFetched
< celt
) &&
3755 (currentSearchNode
!=PROPERTY_NULL
) )
3758 * Remove the top node from the stack
3760 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3763 * Read the property from the storage.
3765 StorageImpl_ReadProperty(This
->parentStorage
,
3770 * Step to the next item in the iteration
3775 * Push the next search node in the search stack.
3777 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
.nextProperty
);
3780 * continue the iteration.
3782 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3785 if (objectFetched
== celt
)
3791 HRESULT WINAPI
IEnumSTATSTGImpl_Reset(
3792 IEnumSTATSTG
* iface
)
3794 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3796 StgProperty rootProperty
;
3797 BOOL readSuccessful
;
3800 * Re-initialize the search stack to an empty stack
3802 This
->stackSize
= 0;
3805 * Read the root property from the storage.
3807 readSuccessful
= StorageImpl_ReadProperty(
3808 This
->parentStorage
,
3809 This
->firstPropertyNode
,
3814 assert(rootProperty
.sizeOfNameString
!=0);
3817 * Push the search node in the search stack.
3819 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.dirProperty
);
3825 HRESULT WINAPI
IEnumSTATSTGImpl_Clone(
3826 IEnumSTATSTG
* iface
,
3827 IEnumSTATSTG
** ppenum
)
3829 IEnumSTATSTGImpl
* const This
=(IEnumSTATSTGImpl
*)iface
;
3831 IEnumSTATSTGImpl
* newClone
;
3834 * Perform a sanity check on the parameters.
3837 return E_INVALIDARG
;
3839 newClone
= IEnumSTATSTGImpl_Construct(This
->parentStorage
,
3840 This
->firstPropertyNode
);
3844 * The new clone enumeration must point to the same current node as
3847 newClone
->stackSize
= This
->stackSize
;
3848 newClone
->stackMaxSize
= This
->stackMaxSize
;
3849 newClone
->stackToVisit
=
3850 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG
) * newClone
->stackMaxSize
);
3853 newClone
->stackToVisit
,
3855 sizeof(ULONG
) * newClone
->stackSize
);
3857 *ppenum
= (IEnumSTATSTG
*)newClone
;
3860 * Don't forget to nail down a reference to the clone before
3863 IEnumSTATSTGImpl_AddRef(*ppenum
);
3868 INT
IEnumSTATSTGImpl_FindParentProperty(
3869 IEnumSTATSTGImpl
*This
,
3870 ULONG childProperty
,
3871 StgProperty
*currentProperty
,
3874 ULONG currentSearchNode
;
3878 * To avoid the special case, get another pointer to a ULONG value if
3879 * the caller didn't supply one.
3882 thisNodeId
= &foundNode
;
3885 * Start with the node at the top of the stack.
3887 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3890 while (currentSearchNode
!=PROPERTY_NULL
)
3893 * Store the current node in the returned parameters
3895 *thisNodeId
= currentSearchNode
;
3898 * Remove the top node from the stack
3900 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3903 * Read the property from the storage.
3905 StorageImpl_ReadProperty(
3906 This
->parentStorage
,
3910 if (currentProperty
->previousProperty
== childProperty
)
3911 return PROPERTY_RELATION_PREVIOUS
;
3913 else if (currentProperty
->nextProperty
== childProperty
)
3914 return PROPERTY_RELATION_NEXT
;
3916 else if (currentProperty
->dirProperty
== childProperty
)
3917 return PROPERTY_RELATION_DIR
;
3920 * Push the next search node in the search stack.
3922 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3925 * continue the iteration.
3927 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3930 return PROPERTY_NULL
;
3933 ULONG
IEnumSTATSTGImpl_FindProperty(
3934 IEnumSTATSTGImpl
* This
,
3935 const OLECHAR
* lpszPropName
,
3936 StgProperty
* currentProperty
)
3938 ULONG currentSearchNode
;
3941 * Start with the node at the top of the stack.
3943 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3945 while (currentSearchNode
!=PROPERTY_NULL
)
3948 * Remove the top node from the stack
3950 IEnumSTATSTGImpl_PopSearchNode(This
, TRUE
);
3953 * Read the property from the storage.
3955 StorageImpl_ReadProperty(This
->parentStorage
,
3959 if ( propertyNameCmp(
3960 (OLECHAR
*)currentProperty
->name
,
3961 (OLECHAR
*)lpszPropName
) == 0)
3962 return currentSearchNode
;
3965 * Push the next search node in the search stack.
3967 IEnumSTATSTGImpl_PushSearchNode(This
, currentProperty
->nextProperty
);
3970 * continue the iteration.
3972 currentSearchNode
= IEnumSTATSTGImpl_PopSearchNode(This
, FALSE
);
3975 return PROPERTY_NULL
;
3978 void IEnumSTATSTGImpl_PushSearchNode(
3979 IEnumSTATSTGImpl
* This
,
3982 StgProperty rootProperty
;
3983 BOOL readSuccessful
;
3986 * First, make sure we're not trying to push an unexisting node.
3988 if (nodeToPush
==PROPERTY_NULL
)
3992 * First push the node to the stack
3994 if (This
->stackSize
== This
->stackMaxSize
)
3996 This
->stackMaxSize
+= ENUMSTATSGT_SIZE_INCREMENT
;
3998 This
->stackToVisit
= HeapReAlloc(
4002 sizeof(ULONG
) * This
->stackMaxSize
);
4005 This
->stackToVisit
[This
->stackSize
] = nodeToPush
;
4009 * Read the root property from the storage.
4011 readSuccessful
= StorageImpl_ReadProperty(
4012 This
->parentStorage
,
4018 assert(rootProperty
.sizeOfNameString
!=0);
4021 * Push the previous search node in the search stack.
4023 IEnumSTATSTGImpl_PushSearchNode(This
, rootProperty
.previousProperty
);
4027 ULONG
IEnumSTATSTGImpl_PopSearchNode(
4028 IEnumSTATSTGImpl
* This
,
4033 if (This
->stackSize
== 0)
4034 return PROPERTY_NULL
;
4036 topNode
= This
->stackToVisit
[This
->stackSize
-1];
4044 /******************************************************************************
4045 ** StorageUtl implementation
4048 void StorageUtl_ReadWord(void* buffer
, ULONG offset
, WORD
* value
)
4050 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(WORD
));
4053 void StorageUtl_WriteWord(void* buffer
, ULONG offset
, WORD value
)
4055 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(WORD
));
4058 void StorageUtl_ReadDWord(void* buffer
, ULONG offset
, DWORD
* value
)
4060 memcpy(value
, (BYTE
*)buffer
+offset
, sizeof(DWORD
));
4063 void StorageUtl_WriteDWord(void* buffer
, ULONG offset
, DWORD value
)
4065 memcpy((BYTE
*)buffer
+offset
, &value
, sizeof(DWORD
));
4068 void StorageUtl_ReadGUID(void* buffer
, ULONG offset
, GUID
* value
)
4070 StorageUtl_ReadDWord(buffer
, offset
, &(value
->Data1
));
4071 StorageUtl_ReadWord(buffer
, offset
+4, &(value
->Data2
));
4072 StorageUtl_ReadWord(buffer
, offset
+6, &(value
->Data3
));
4074 memcpy(value
->Data4
, (BYTE
*)buffer
+offset
+8, sizeof(value
->Data4
));
4077 void StorageUtl_WriteGUID(void* buffer
, ULONG offset
, GUID
* value
)
4079 StorageUtl_WriteDWord(buffer
, offset
, value
->Data1
);
4080 StorageUtl_WriteWord(buffer
, offset
+4, value
->Data2
);
4081 StorageUtl_WriteWord(buffer
, offset
+6, value
->Data3
);
4083 memcpy((BYTE
*)buffer
+offset
+8, value
->Data4
, sizeof(value
->Data4
));
4086 void StorageUtl_CopyPropertyToSTATSTG(
4087 STATSTG
* destination
,
4088 StgProperty
* source
,
4092 * The copy of the string occurs only when the flag is not set
4094 if ((statFlags
& STATFLAG_NONAME
) != 0)
4096 destination
->pwcsName
= 0;
4100 destination
->pwcsName
=
4101 CoTaskMemAlloc((lstrlenW(source
->name
)+1)*sizeof(WCHAR
));
4103 strcpyW((LPWSTR
)destination
->pwcsName
, source
->name
);
4106 switch (source
->propertyType
)
4108 case PROPTYPE_STORAGE
:
4110 destination
->type
= STGTY_STORAGE
;
4112 case PROPTYPE_STREAM
:
4113 destination
->type
= STGTY_STREAM
;
4116 destination
->type
= STGTY_STREAM
;
4120 destination
->cbSize
= source
->size
;
4122 currentReturnStruct->mtime = {0}; TODO
4123 currentReturnStruct->ctime = {0};
4124 currentReturnStruct->atime = {0};
4126 destination
->grfMode
= 0;
4127 destination
->grfLocksSupported
= 0;
4128 destination
->clsid
= source
->propertyUniqueID
;
4129 destination
->grfStateBits
= 0;
4130 destination
->reserved
= 0;
4133 /******************************************************************************
4134 ** BlockChainStream implementation
4137 BlockChainStream
* BlockChainStream_Construct(
4138 StorageImpl
* parentStorage
,
4139 ULONG
* headOfStreamPlaceHolder
,
4140 ULONG propertyIndex
)
4142 BlockChainStream
* newStream
;
4145 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream
));
4147 newStream
->parentStorage
= parentStorage
;
4148 newStream
->headOfStreamPlaceHolder
= headOfStreamPlaceHolder
;
4149 newStream
->ownerPropertyIndex
= propertyIndex
;
4150 newStream
->lastBlockNoInSequence
= 0xFFFFFFFF;
4151 newStream
->tailIndex
= BLOCK_END_OF_CHAIN
;
4152 newStream
->numBlocks
= 0;
4154 blockIndex
= BlockChainStream_GetHeadOfChain(newStream
);
4156 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4158 newStream
->numBlocks
++;
4159 newStream
->tailIndex
= blockIndex
;
4161 blockIndex
= StorageImpl_GetNextBlockInChain(
4169 void BlockChainStream_Destroy(BlockChainStream
* This
)
4171 HeapFree(GetProcessHeap(), 0, This
);
4174 /******************************************************************************
4175 * BlockChainStream_GetHeadOfChain
4177 * Returns the head of this stream chain.
4178 * Some special chains don't have properties, their heads are kept in
4179 * This->headOfStreamPlaceHolder.
4182 ULONG
BlockChainStream_GetHeadOfChain(BlockChainStream
* This
)
4184 StgProperty chainProperty
;
4185 BOOL readSuccessful
;
4187 if (This
->headOfStreamPlaceHolder
!= 0)
4188 return *(This
->headOfStreamPlaceHolder
);
4190 if (This
->ownerPropertyIndex
!= PROPERTY_NULL
)
4192 readSuccessful
= StorageImpl_ReadProperty(
4193 This
->parentStorage
,
4194 This
->ownerPropertyIndex
,
4199 return chainProperty
.startingBlock
;
4203 return BLOCK_END_OF_CHAIN
;
4206 /******************************************************************************
4207 * BlockChainStream_GetCount
4209 * Returns the number of blocks that comprises this chain.
4210 * This is not the size of the stream as the last block may not be full!
4213 ULONG
BlockChainStream_GetCount(BlockChainStream
* This
)
4218 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4220 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4224 blockIndex
= StorageImpl_GetNextBlockInChain(
4225 This
->parentStorage
,
4232 /******************************************************************************
4233 * BlockChainStream_ReadAt
4235 * Reads a specified number of bytes from this chain at the specified offset.
4236 * bytesRead may be NULL.
4237 * Failure will be returned if the specified number of bytes has not been read.
4239 BOOL
BlockChainStream_ReadAt(BlockChainStream
* This
,
4240 ULARGE_INTEGER offset
,
4245 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4246 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4247 ULONG bytesToReadInBuffer
;
4250 BYTE
* bigBlockBuffer
;
4253 * Find the first block in the stream that contains part of the buffer.
4255 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4256 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4257 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4259 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4260 This
->lastBlockNoInSequence
= blockNoInSequence
;
4264 ULONG temp
= blockNoInSequence
;
4266 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4267 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4268 This
->lastBlockNoInSequence
= temp
;
4271 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4274 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4276 blockNoInSequence
--;
4279 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4282 * Start reading the buffer.
4285 bufferWalker
= buffer
;
4287 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4290 * Calculate how many bytes we can copy from this big block.
4292 bytesToReadInBuffer
=
4293 min(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4296 * Copy those bytes to the buffer
4299 StorageImpl_GetROBigBlock(This
->parentStorage
, blockIndex
);
4301 memcpy(bufferWalker
, bigBlockBuffer
+ offsetInBlock
, bytesToReadInBuffer
);
4303 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4306 * Step to the next big block.
4309 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4311 bufferWalker
+= bytesToReadInBuffer
;
4312 size
-= bytesToReadInBuffer
;
4313 *bytesRead
+= bytesToReadInBuffer
;
4314 offsetInBlock
= 0; /* There is no offset on the next block */
4321 /******************************************************************************
4322 * BlockChainStream_WriteAt
4324 * Writes the specified number of bytes to this chain at the specified offset.
4325 * bytesWritten may be NULL.
4326 * Will fail if not all specified number of bytes have been written.
4328 BOOL
BlockChainStream_WriteAt(BlockChainStream
* This
,
4329 ULARGE_INTEGER offset
,
4332 ULONG
* bytesWritten
)
4334 ULONG blockNoInSequence
= offset
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4335 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->bigBlockSize
;
4339 BYTE
* bigBlockBuffer
;
4342 * Find the first block in the stream that contains part of the buffer.
4344 if ( (This
->lastBlockNoInSequence
== 0xFFFFFFFF) ||
4345 (This
->lastBlockNoInSequenceIndex
== BLOCK_END_OF_CHAIN
) ||
4346 (blockNoInSequence
< This
->lastBlockNoInSequence
) )
4348 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4349 This
->lastBlockNoInSequence
= blockNoInSequence
;
4353 ULONG temp
= blockNoInSequence
;
4355 blockIndex
= This
->lastBlockNoInSequenceIndex
;
4356 blockNoInSequence
-= This
->lastBlockNoInSequence
;
4357 This
->lastBlockNoInSequence
= temp
;
4360 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
4363 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4365 blockNoInSequence
--;
4368 This
->lastBlockNoInSequenceIndex
= blockIndex
;
4371 * Here, I'm casting away the constness on the buffer variable
4372 * This is OK since we don't intend to modify that buffer.
4375 bufferWalker
= (BYTE
*)buffer
;
4377 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
4380 * Calculate how many bytes we can copy from this big block.
4383 min(This
->parentStorage
->bigBlockSize
- offsetInBlock
, size
);
4386 * Copy those bytes to the buffer
4388 bigBlockBuffer
= StorageImpl_GetBigBlock(This
->parentStorage
, blockIndex
);
4390 memcpy(bigBlockBuffer
+ offsetInBlock
, bufferWalker
, bytesToWrite
);
4392 StorageImpl_ReleaseBigBlock(This
->parentStorage
, bigBlockBuffer
);
4395 * Step to the next big block.
4398 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4400 bufferWalker
+= bytesToWrite
;
4401 size
-= bytesToWrite
;
4402 *bytesWritten
+= bytesToWrite
;
4403 offsetInBlock
= 0; /* There is no offset on the next block */
4409 /******************************************************************************
4410 * BlockChainStream_Shrink
4412 * Shrinks this chain in the big block depot.
4414 BOOL
BlockChainStream_Shrink(BlockChainStream
* This
,
4415 ULARGE_INTEGER newSize
)
4417 ULONG blockIndex
, extraBlock
;
4422 * Reset the last accessed block cache.
4424 This
->lastBlockNoInSequence
= 0xFFFFFFFF;
4425 This
->lastBlockNoInSequenceIndex
= BLOCK_END_OF_CHAIN
;
4428 * Figure out how many blocks are needed to contain the new size
4430 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4432 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4435 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4438 * Go to the new end of chain
4440 while (count
< numBlocks
)
4443 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4448 /* Get the next block before marking the new end */
4450 StorageImpl_GetNextBlockInChain(This
->parentStorage
, blockIndex
);
4452 /* Mark the new end of chain */
4453 StorageImpl_SetNextBlockInChain(
4454 This
->parentStorage
,
4456 BLOCK_END_OF_CHAIN
);
4458 This
->tailIndex
= blockIndex
;
4459 This
->numBlocks
= numBlocks
;
4462 * Mark the extra blocks as free
4464 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
4467 StorageImpl_GetNextBlockInChain(This
->parentStorage
, extraBlock
);
4469 StorageImpl_FreeBigBlock(This
->parentStorage
, extraBlock
);
4470 extraBlock
= blockIndex
;
4476 /******************************************************************************
4477 * BlockChainStream_Enlarge
4479 * Grows this chain in the big block depot.
4481 BOOL
BlockChainStream_Enlarge(BlockChainStream
* This
,
4482 ULARGE_INTEGER newSize
)
4484 ULONG blockIndex
, currentBlock
;
4486 ULONG oldNumBlocks
= 0;
4488 blockIndex
= BlockChainStream_GetHeadOfChain(This
);
4491 * Empty chain. Create the head.
4493 if (blockIndex
== BLOCK_END_OF_CHAIN
)
4495 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4496 StorageImpl_SetNextBlockInChain(This
->parentStorage
,
4498 BLOCK_END_OF_CHAIN
);
4500 if (This
->headOfStreamPlaceHolder
!= 0)
4502 *(This
->headOfStreamPlaceHolder
) = blockIndex
;
4506 StgProperty chainProp
;
4507 assert(This
->ownerPropertyIndex
!= PROPERTY_NULL
);
4509 StorageImpl_ReadProperty(
4510 This
->parentStorage
,
4511 This
->ownerPropertyIndex
,
4514 chainProp
.startingBlock
= blockIndex
;
4516 StorageImpl_WriteProperty(
4517 This
->parentStorage
,
4518 This
->ownerPropertyIndex
,
4522 This
->tailIndex
= blockIndex
;
4523 This
->numBlocks
= 1;
4527 * Figure out how many blocks are needed to contain this stream
4529 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->bigBlockSize
;
4531 if ((newSize
.s
.LowPart
% This
->parentStorage
->bigBlockSize
) != 0)
4535 * Go to the current end of chain
4537 if (This
->tailIndex
== BLOCK_END_OF_CHAIN
)
4539 currentBlock
= blockIndex
;
4541 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
4544 currentBlock
= blockIndex
;
4547 StorageImpl_GetNextBlockInChain(This
->parentStorage
, currentBlock
);
4550 This
->tailIndex
= currentBlock
;
4553 currentBlock
= This
->tailIndex
;
4554 oldNumBlocks
= This
->numBlocks
;
4557 * Add new blocks to the chain
4559 if (oldNumBlocks
< newNumBlocks
)
4561 while (oldNumBlocks
< newNumBlocks
)
4563 blockIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4565 StorageImpl_SetNextBlockInChain(
4566 This
->parentStorage
,
4570 StorageImpl_SetNextBlockInChain(
4571 This
->parentStorage
,
4573 BLOCK_END_OF_CHAIN
);
4575 currentBlock
= blockIndex
;
4579 This
->tailIndex
= blockIndex
;
4580 This
->numBlocks
= newNumBlocks
;
4586 /******************************************************************************
4587 * BlockChainStream_SetSize
4589 * Sets the size of this stream. The big block depot will be updated.
4590 * The file will grow if we grow the chain.
4592 * TODO: Free the actual blocks in the file when we shrink the chain.
4593 * Currently, the blocks are still in the file. So the file size
4594 * doesn't shrink even if we shrink streams.
4596 BOOL
BlockChainStream_SetSize(
4597 BlockChainStream
* This
,
4598 ULARGE_INTEGER newSize
)
4600 ULARGE_INTEGER size
= BlockChainStream_GetSize(This
);
4602 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
4605 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
4607 BlockChainStream_Shrink(This
, newSize
);
4611 ULARGE_INTEGER fileSize
=
4612 BIGBLOCKFILE_GetSize(This
->parentStorage
->bigBlockFile
);
4614 ULONG diff
= newSize
.s
.LowPart
- size
.s
.LowPart
;
4617 * Make sure the file stays a multiple of blocksize
4619 if ((diff
% This
->parentStorage
->bigBlockSize
) != 0)
4620 diff
+= (This
->parentStorage
->bigBlockSize
-
4621 (diff
% This
->parentStorage
->bigBlockSize
) );
4623 fileSize
.s
.LowPart
+= diff
;
4624 BIGBLOCKFILE_SetSize(This
->parentStorage
->bigBlockFile
, fileSize
);
4626 BlockChainStream_Enlarge(This
, newSize
);
4632 /******************************************************************************
4633 * BlockChainStream_GetSize
4635 * Returns the size of this chain.
4636 * Will return the block count if this chain doesn't have a property.
4638 ULARGE_INTEGER
BlockChainStream_GetSize(BlockChainStream
* This
)
4640 StgProperty chainProperty
;
4642 if(This
->headOfStreamPlaceHolder
== NULL
)
4645 * This chain is a data stream read the property and return
4646 * the appropriate size
4648 StorageImpl_ReadProperty(
4649 This
->parentStorage
,
4650 This
->ownerPropertyIndex
,
4653 return chainProperty
.size
;
4658 * this chain is a chain that does not have a property, figure out the
4659 * size by making the product number of used blocks times the
4662 ULARGE_INTEGER result
;
4663 result
.s
.HighPart
= 0;
4666 BlockChainStream_GetCount(This
) *
4667 This
->parentStorage
->bigBlockSize
;
4673 /******************************************************************************
4674 ** SmallBlockChainStream implementation
4677 SmallBlockChainStream
* SmallBlockChainStream_Construct(
4678 StorageImpl
* parentStorage
,
4679 ULONG propertyIndex
)
4681 SmallBlockChainStream
* newStream
;
4683 newStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream
));
4685 newStream
->parentStorage
= parentStorage
;
4686 newStream
->ownerPropertyIndex
= propertyIndex
;
4691 void SmallBlockChainStream_Destroy(
4692 SmallBlockChainStream
* This
)
4694 HeapFree(GetProcessHeap(), 0, This
);
4697 /******************************************************************************
4698 * SmallBlockChainStream_GetHeadOfChain
4700 * Returns the head of this chain of small blocks.
4702 ULONG
SmallBlockChainStream_GetHeadOfChain(
4703 SmallBlockChainStream
* This
)
4705 StgProperty chainProperty
;
4706 BOOL readSuccessful
;
4708 if (This
->ownerPropertyIndex
)
4710 readSuccessful
= StorageImpl_ReadProperty(
4711 This
->parentStorage
,
4712 This
->ownerPropertyIndex
,
4717 return chainProperty
.startingBlock
;
4722 return BLOCK_END_OF_CHAIN
;
4725 /******************************************************************************
4726 * SmallBlockChainStream_GetNextBlockInChain
4728 * Returns the index of the next small block in this chain.
4731 * - BLOCK_END_OF_CHAIN: end of this chain
4732 * - BLOCK_UNUSED: small block 'blockIndex' is free
4734 ULONG
SmallBlockChainStream_GetNextBlockInChain(
4735 SmallBlockChainStream
* This
,
4738 ULARGE_INTEGER offsetOfBlockInDepot
;
4740 ULONG nextBlockInChain
= BLOCK_END_OF_CHAIN
;
4744 offsetOfBlockInDepot
.s
.HighPart
= 0;
4745 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4748 * Read those bytes in the buffer from the small block file.
4750 success
= BlockChainStream_ReadAt(
4751 This
->parentStorage
->smallBlockDepotChain
,
4752 offsetOfBlockInDepot
,
4759 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockInChain
);
4762 return nextBlockInChain
;
4765 /******************************************************************************
4766 * SmallBlockChainStream_SetNextBlockInChain
4768 * Writes the index of the next block of the specified block in the small
4770 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4771 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4773 void SmallBlockChainStream_SetNextBlockInChain(
4774 SmallBlockChainStream
* This
,
4778 ULARGE_INTEGER offsetOfBlockInDepot
;
4782 offsetOfBlockInDepot
.s
.HighPart
= 0;
4783 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4785 StorageUtl_WriteDWord(&buffer
, 0, nextBlock
);
4788 * Read those bytes in the buffer from the small block file.
4790 BlockChainStream_WriteAt(
4791 This
->parentStorage
->smallBlockDepotChain
,
4792 offsetOfBlockInDepot
,
4798 /******************************************************************************
4799 * SmallBlockChainStream_FreeBlock
4801 * Flag small block 'blockIndex' as free in the small block depot.
4803 void SmallBlockChainStream_FreeBlock(
4804 SmallBlockChainStream
* This
,
4807 SmallBlockChainStream_SetNextBlockInChain(This
, blockIndex
, BLOCK_UNUSED
);
4810 /******************************************************************************
4811 * SmallBlockChainStream_GetNextFreeBlock
4813 * Returns the index of a free small block. The small block depot will be
4814 * enlarged if necessary. The small block chain will also be enlarged if
4817 ULONG
SmallBlockChainStream_GetNextFreeBlock(
4818 SmallBlockChainStream
* This
)
4820 ULARGE_INTEGER offsetOfBlockInDepot
;
4823 ULONG blockIndex
= 0;
4824 ULONG nextBlockIndex
= BLOCK_END_OF_CHAIN
;
4825 BOOL success
= TRUE
;
4826 ULONG smallBlocksPerBigBlock
;
4828 offsetOfBlockInDepot
.s
.HighPart
= 0;
4831 * Scan the small block depot for a free block
4833 while (nextBlockIndex
!= BLOCK_UNUSED
)
4835 offsetOfBlockInDepot
.s
.LowPart
= blockIndex
* sizeof(ULONG
);
4837 success
= BlockChainStream_ReadAt(
4838 This
->parentStorage
->smallBlockDepotChain
,
4839 offsetOfBlockInDepot
,
4845 * If we run out of space for the small block depot, enlarge it
4849 StorageUtl_ReadDWord(&buffer
, 0, &nextBlockIndex
);
4851 if (nextBlockIndex
!= BLOCK_UNUSED
)
4857 BlockChainStream_GetCount(This
->parentStorage
->smallBlockDepotChain
);
4859 ULONG sbdIndex
= This
->parentStorage
->smallBlockDepotStart
;
4860 ULONG nextBlock
, newsbdIndex
;
4861 BYTE
* smallBlockDepot
;
4863 nextBlock
= sbdIndex
;
4864 while (nextBlock
!= BLOCK_END_OF_CHAIN
)
4866 sbdIndex
= nextBlock
;
4868 StorageImpl_GetNextBlockInChain(This
->parentStorage
, sbdIndex
);
4871 newsbdIndex
= StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4872 if (sbdIndex
!= BLOCK_END_OF_CHAIN
)
4873 StorageImpl_SetNextBlockInChain(
4874 This
->parentStorage
,
4878 StorageImpl_SetNextBlockInChain(
4879 This
->parentStorage
,
4881 BLOCK_END_OF_CHAIN
);
4884 * Initialize all the small blocks to free
4887 StorageImpl_GetBigBlock(This
->parentStorage
, newsbdIndex
);
4889 memset(smallBlockDepot
, BLOCK_UNUSED
, This
->parentStorage
->bigBlockSize
);
4890 StorageImpl_ReleaseBigBlock(This
->parentStorage
, smallBlockDepot
);
4895 * We have just created the small block depot.
4897 StgProperty rootProp
;
4901 * Save it in the header
4903 This
->parentStorage
->smallBlockDepotStart
= newsbdIndex
;
4904 StorageImpl_SaveFileHeader(This
->parentStorage
);
4907 * And allocate the first big block that will contain small blocks
4910 StorageImpl_GetNextFreeBigBlock(This
->parentStorage
);
4912 StorageImpl_SetNextBlockInChain(
4913 This
->parentStorage
,
4915 BLOCK_END_OF_CHAIN
);
4917 StorageImpl_ReadProperty(
4918 This
->parentStorage
,
4919 This
->parentStorage
->rootPropertySetIndex
,
4922 rootProp
.startingBlock
= sbStartIndex
;
4923 rootProp
.size
.s
.HighPart
= 0;
4924 rootProp
.size
.s
.LowPart
= This
->parentStorage
->bigBlockSize
;
4926 StorageImpl_WriteProperty(
4927 This
->parentStorage
,
4928 This
->parentStorage
->rootPropertySetIndex
,
4934 smallBlocksPerBigBlock
=
4935 This
->parentStorage
->bigBlockSize
/ This
->parentStorage
->smallBlockSize
;
4938 * Verify if we have to allocate big blocks to contain small blocks
4940 if (blockIndex
% smallBlocksPerBigBlock
== 0)
4942 StgProperty rootProp
;
4943 ULONG blocksRequired
= (blockIndex
/ smallBlocksPerBigBlock
) + 1;
4945 StorageImpl_ReadProperty(
4946 This
->parentStorage
,
4947 This
->parentStorage
->rootPropertySetIndex
,
4950 if (rootProp
.size
.s
.LowPart
<
4951 (blocksRequired
* This
->parentStorage
->bigBlockSize
))
4953 rootProp
.size
.s
.LowPart
+= This
->parentStorage
->bigBlockSize
;
4955 BlockChainStream_SetSize(
4956 This
->parentStorage
->smallBlockRootChain
,
4959 StorageImpl_WriteProperty(
4960 This
->parentStorage
,
4961 This
->parentStorage
->rootPropertySetIndex
,
4969 /******************************************************************************
4970 * SmallBlockChainStream_ReadAt
4972 * Reads a specified number of bytes from this chain at the specified offset.
4973 * bytesRead may be NULL.
4974 * Failure will be returned if the specified number of bytes has not been read.
4976 BOOL
SmallBlockChainStream_ReadAt(
4977 SmallBlockChainStream
* This
,
4978 ULARGE_INTEGER offset
,
4983 ULARGE_INTEGER offsetInBigBlockFile
;
4984 ULONG blockNoInSequence
=
4985 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
4987 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
4988 ULONG bytesToReadInBuffer
;
4990 ULONG bytesReadFromBigBlockFile
;
4994 * This should never happen on a small block file.
4996 assert(offset
.s
.HighPart
==0);
4999 * Find the first block in the stream that contains part of the buffer.
5001 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5003 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
5005 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5007 blockNoInSequence
--;
5011 * Start reading the buffer.
5014 bufferWalker
= buffer
;
5016 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
5019 * Calculate how many bytes we can copy from this small block.
5021 bytesToReadInBuffer
=
5022 min(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
5025 * Calculate the offset of the small block in the small block file.
5027 offsetInBigBlockFile
.s
.HighPart
= 0;
5028 offsetInBigBlockFile
.s
.LowPart
=
5029 blockIndex
* This
->parentStorage
->smallBlockSize
;
5031 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
5034 * Read those bytes in the buffer from the small block file.
5036 BlockChainStream_ReadAt(This
->parentStorage
->smallBlockRootChain
,
5037 offsetInBigBlockFile
,
5038 bytesToReadInBuffer
,
5040 &bytesReadFromBigBlockFile
);
5042 assert(bytesReadFromBigBlockFile
== bytesToReadInBuffer
);
5045 * Step to the next big block.
5047 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5048 bufferWalker
+= bytesToReadInBuffer
;
5049 size
-= bytesToReadInBuffer
;
5050 *bytesRead
+= bytesToReadInBuffer
;
5051 offsetInBlock
= 0; /* There is no offset on the next block */
5057 /******************************************************************************
5058 * SmallBlockChainStream_WriteAt
5060 * Writes the specified number of bytes to this chain at the specified offset.
5061 * bytesWritten may be NULL.
5062 * Will fail if not all specified number of bytes have been written.
5064 BOOL
SmallBlockChainStream_WriteAt(
5065 SmallBlockChainStream
* This
,
5066 ULARGE_INTEGER offset
,
5069 ULONG
* bytesWritten
)
5071 ULARGE_INTEGER offsetInBigBlockFile
;
5072 ULONG blockNoInSequence
=
5073 offset
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5075 ULONG offsetInBlock
= offset
.s
.LowPart
% This
->parentStorage
->smallBlockSize
;
5076 ULONG bytesToWriteInBuffer
;
5078 ULONG bytesWrittenFromBigBlockFile
;
5082 * This should never happen on a small block file.
5084 assert(offset
.s
.HighPart
==0);
5087 * Find the first block in the stream that contains part of the buffer.
5089 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5091 while ( (blockNoInSequence
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
))
5093 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5095 blockNoInSequence
--;
5099 * Start writing the buffer.
5101 * Here, I'm casting away the constness on the buffer variable
5102 * This is OK since we don't intend to modify that buffer.
5105 bufferWalker
= (BYTE
*)buffer
;
5106 while ( (size
> 0) && (blockIndex
!= BLOCK_END_OF_CHAIN
) )
5109 * Calculate how many bytes we can copy to this small block.
5111 bytesToWriteInBuffer
=
5112 min(This
->parentStorage
->smallBlockSize
- offsetInBlock
, size
);
5115 * Calculate the offset of the small block in the small block file.
5117 offsetInBigBlockFile
.s
.HighPart
= 0;
5118 offsetInBigBlockFile
.s
.LowPart
=
5119 blockIndex
* This
->parentStorage
->smallBlockSize
;
5121 offsetInBigBlockFile
.s
.LowPart
+= offsetInBlock
;
5124 * Write those bytes in the buffer to the small block file.
5126 BlockChainStream_WriteAt(This
->parentStorage
->smallBlockRootChain
,
5127 offsetInBigBlockFile
,
5128 bytesToWriteInBuffer
,
5130 &bytesWrittenFromBigBlockFile
);
5132 assert(bytesWrittenFromBigBlockFile
== bytesToWriteInBuffer
);
5135 * Step to the next big block.
5137 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5138 bufferWalker
+= bytesToWriteInBuffer
;
5139 size
-= bytesToWriteInBuffer
;
5140 *bytesWritten
+= bytesToWriteInBuffer
;
5141 offsetInBlock
= 0; /* There is no offset on the next block */
5147 /******************************************************************************
5148 * SmallBlockChainStream_Shrink
5150 * Shrinks this chain in the small block depot.
5152 BOOL
SmallBlockChainStream_Shrink(
5153 SmallBlockChainStream
* This
,
5154 ULARGE_INTEGER newSize
)
5156 ULONG blockIndex
, extraBlock
;
5160 numBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5162 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5165 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5168 * Go to the new end of chain
5170 while (count
< numBlocks
)
5172 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5177 * If the count is 0, we have a special case, the head of the chain was
5182 StgProperty chainProp
;
5184 StorageImpl_ReadProperty(This
->parentStorage
,
5185 This
->ownerPropertyIndex
,
5188 chainProp
.startingBlock
= BLOCK_END_OF_CHAIN
;
5190 StorageImpl_WriteProperty(This
->parentStorage
,
5191 This
->ownerPropertyIndex
,
5195 * We start freeing the chain at the head block.
5197 extraBlock
= blockIndex
;
5201 /* Get the next block before marking the new end */
5202 extraBlock
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5204 /* Mark the new end of chain */
5205 SmallBlockChainStream_SetNextBlockInChain(
5208 BLOCK_END_OF_CHAIN
);
5212 * Mark the extra blocks as free
5214 while (extraBlock
!= BLOCK_END_OF_CHAIN
)
5216 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, extraBlock
);
5217 SmallBlockChainStream_FreeBlock(This
, extraBlock
);
5218 extraBlock
= blockIndex
;
5224 /******************************************************************************
5225 * SmallBlockChainStream_Enlarge
5227 * Grows this chain in the small block depot.
5229 BOOL
SmallBlockChainStream_Enlarge(
5230 SmallBlockChainStream
* This
,
5231 ULARGE_INTEGER newSize
)
5233 ULONG blockIndex
, currentBlock
;
5235 ULONG oldNumBlocks
= 0;
5237 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5242 if (blockIndex
== BLOCK_END_OF_CHAIN
)
5245 StgProperty chainProp
;
5247 StorageImpl_ReadProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5250 chainProp
.startingBlock
= SmallBlockChainStream_GetNextFreeBlock(This
);
5252 StorageImpl_WriteProperty(This
->parentStorage
, This
->ownerPropertyIndex
,
5255 blockIndex
= chainProp
.startingBlock
;
5256 SmallBlockChainStream_SetNextBlockInChain(
5259 BLOCK_END_OF_CHAIN
);
5262 currentBlock
= blockIndex
;
5265 * Figure out how many blocks are needed to contain this stream
5267 newNumBlocks
= newSize
.s
.LowPart
/ This
->parentStorage
->smallBlockSize
;
5269 if ((newSize
.s
.LowPart
% This
->parentStorage
->smallBlockSize
) != 0)
5273 * Go to the current end of chain
5275 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5278 currentBlock
= blockIndex
;
5279 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, currentBlock
);
5283 * Add new blocks to the chain
5285 while (oldNumBlocks
< newNumBlocks
)
5287 blockIndex
= SmallBlockChainStream_GetNextFreeBlock(This
);
5288 SmallBlockChainStream_SetNextBlockInChain(This
, currentBlock
, blockIndex
);
5290 SmallBlockChainStream_SetNextBlockInChain(
5293 BLOCK_END_OF_CHAIN
);
5295 currentBlock
= blockIndex
;
5302 /******************************************************************************
5303 * SmallBlockChainStream_GetCount
5305 * Returns the number of blocks that comprises this chain.
5306 * This is not the size of this chain as the last block may not be full!
5308 ULONG
SmallBlockChainStream_GetCount(SmallBlockChainStream
* This
)
5313 blockIndex
= SmallBlockChainStream_GetHeadOfChain(This
);
5315 while (blockIndex
!= BLOCK_END_OF_CHAIN
)
5319 blockIndex
= SmallBlockChainStream_GetNextBlockInChain(This
, blockIndex
);
5325 /******************************************************************************
5326 * SmallBlockChainStream_SetSize
5328 * Sets the size of this stream.
5329 * The file will grow if we grow the chain.
5331 * TODO: Free the actual blocks in the file when we shrink the chain.
5332 * Currently, the blocks are still in the file. So the file size
5333 * doesn't shrink even if we shrink streams.
5335 BOOL
SmallBlockChainStream_SetSize(
5336 SmallBlockChainStream
* This
,
5337 ULARGE_INTEGER newSize
)
5339 ULARGE_INTEGER size
= SmallBlockChainStream_GetSize(This
);
5341 if (newSize
.s
.LowPart
== size
.s
.LowPart
)
5344 if (newSize
.s
.LowPart
< size
.s
.LowPart
)
5346 SmallBlockChainStream_Shrink(This
, newSize
);
5350 SmallBlockChainStream_Enlarge(This
, newSize
);
5356 /******************************************************************************
5357 * SmallBlockChainStream_GetSize
5359 * Returns the size of this chain.
5361 ULARGE_INTEGER
SmallBlockChainStream_GetSize(SmallBlockChainStream
* This
)
5363 StgProperty chainProperty
;
5365 StorageImpl_ReadProperty(
5366 This
->parentStorage
,
5367 This
->ownerPropertyIndex
,
5370 return chainProperty
.size
;
5373 /******************************************************************************
5374 * StgCreateDocfile [OLE32.144]
5376 HRESULT WINAPI
StgCreateDocfile(
5380 IStorage
**ppstgOpen
)
5382 StorageImpl
* newStorage
= 0;
5383 HANDLE hFile
= INVALID_HANDLE_VALUE
;
5388 DWORD fileAttributes
;
5389 WCHAR tempFileName
[MAX_PATH
];
5391 TRACE("(%s, %lx, %ld, %p)\n",
5392 debugstr_w(pwcsName
), grfMode
,
5393 reserved
, ppstgOpen
);
5396 * Validate the parameters
5399 return STG_E_INVALIDPOINTER
;
5402 * Validate the STGM flags
5404 if ( FAILED( validateSTGM(grfMode
) ))
5405 return STG_E_INVALIDFLAG
;
5408 * Generate a unique name.
5412 WCHAR tempPath
[MAX_PATH
];
5413 WCHAR prefix
[] = { 'S', 'T', 'O', 0 };
5415 if (!(grfMode
& STGM_SHARE_EXCLUSIVE
))
5416 return STG_E_INVALIDFLAG
;
5417 if (!(grfMode
& (STGM_WRITE
|STGM_READWRITE
)))
5418 return STG_E_INVALIDFLAG
;
5420 memset(tempPath
, 0, sizeof(tempPath
));
5421 memset(tempFileName
, 0, sizeof(tempFileName
));
5423 if ((GetTempPathW(MAX_PATH
, tempPath
)) == 0 )
5426 if (GetTempFileNameW(tempPath
, prefix
, 0, tempFileName
) != 0)
5427 pwcsName
= tempFileName
;
5429 return STG_E_INSUFFICIENTMEMORY
;
5431 creationMode
= TRUNCATE_EXISTING
;
5435 creationMode
= GetCreationModeFromSTGM(grfMode
);
5439 * Interpret the STGM value grfMode
5441 shareMode
= GetShareModeFromSTGM(grfMode
);
5442 accessMode
= GetAccessModeFromSTGM(grfMode
);
5444 if (grfMode
& STGM_DELETEONRELEASE
)
5445 fileAttributes
= FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE
;
5447 fileAttributes
= FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
;
5449 if (grfMode
& STGM_TRANSACTED
)
5450 FIXME("Transacted mode not implemented.\n");
5453 * Initialize the "out" parameter.
5457 hFile
= CreateFileW(pwcsName
,
5465 if (hFile
== INVALID_HANDLE_VALUE
)
5471 * Allocate and initialize the new IStorage32object.
5473 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5475 if (newStorage
== 0)
5476 return STG_E_INSUFFICIENTMEMORY
;
5478 hr
= StorageImpl_Construct(
5489 HeapFree(GetProcessHeap(), 0, newStorage
);
5494 * Get an "out" pointer for the caller.
5496 hr
= StorageBaseImpl_QueryInterface(
5497 (IStorage
*)newStorage
,
5498 (REFIID
)&IID_IStorage
,
5504 /******************************************************************************
5505 * StgOpenStorage [OLE32.148]
5507 HRESULT WINAPI
StgOpenStorage(
5508 const OLECHAR
*pwcsName
,
5509 IStorage
*pstgPriority
,
5513 IStorage
**ppstgOpen
)
5515 StorageImpl
* newStorage
= 0;
5520 WCHAR fullname
[MAX_PATH
];
5523 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5524 debugstr_w(pwcsName
), pstgPriority
, grfMode
,
5525 snbExclude
, reserved
, ppstgOpen
);
5528 * Perform a sanity check
5530 if (( pwcsName
== 0) || (ppstgOpen
== 0) )
5532 hr
= STG_E_INVALIDPOINTER
;
5537 * Validate the STGM flags
5539 if ( FAILED( validateSTGM(grfMode
) ))
5541 hr
= STG_E_INVALIDFLAG
;
5546 * Interpret the STGM value grfMode
5548 shareMode
= GetShareModeFromSTGM(grfMode
);
5549 accessMode
= GetAccessModeFromSTGM(grfMode
);
5552 * Initialize the "out" parameter.
5556 hFile
= CreateFileW( pwcsName
,
5561 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
5564 length
= GetFileSize(hFile
, NULL
);
5566 if (hFile
==INVALID_HANDLE_VALUE
)
5568 DWORD last_error
= GetLastError();
5574 case ERROR_FILE_NOT_FOUND
:
5575 hr
= STG_E_FILENOTFOUND
;
5578 case ERROR_PATH_NOT_FOUND
:
5579 hr
= STG_E_PATHNOTFOUND
;
5582 case ERROR_ACCESS_DENIED
:
5583 case ERROR_WRITE_PROTECT
:
5584 hr
= STG_E_ACCESSDENIED
;
5587 case ERROR_SHARING_VIOLATION
:
5588 hr
= STG_E_SHAREVIOLATION
;
5599 * Allocate and initialize the new IStorage32object.
5601 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5603 if (newStorage
== 0)
5605 hr
= STG_E_INSUFFICIENTMEMORY
;
5609 /* if the file's length was zero, initialize the storage */
5610 hr
= StorageImpl_Construct(
5621 HeapFree(GetProcessHeap(), 0, newStorage
);
5623 * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
5625 if(hr
== STG_E_INVALIDHEADER
)
5626 hr
= STG_E_FILEALREADYEXISTS
;
5630 /* prepare the file name string given in lieu of the root property name */
5631 GetFullPathNameW(pwcsName
, MAX_PATH
, fullname
, NULL
);
5632 memcpy(newStorage
->filename
, fullname
, PROPERTY_NAME_BUFFER_LEN
);
5633 newStorage
->filename
[PROPERTY_NAME_BUFFER_LEN
-1] = '\0';
5636 * Get an "out" pointer for the caller.
5638 hr
= StorageBaseImpl_QueryInterface(
5639 (IStorage
*)newStorage
,
5640 (REFIID
)&IID_IStorage
,
5644 TRACE("<-- %08lx, IStorage %p\n", hr
, ppstgOpen
? *ppstgOpen
: NULL
);
5648 /******************************************************************************
5649 * StgCreateDocfileOnILockBytes [OLE32.145]
5651 HRESULT WINAPI
StgCreateDocfileOnILockBytes(
5655 IStorage
** ppstgOpen
)
5657 StorageImpl
* newStorage
= 0;
5661 * Validate the parameters
5663 if ((ppstgOpen
== 0) || (plkbyt
== 0))
5664 return STG_E_INVALIDPOINTER
;
5667 * Allocate and initialize the new IStorage object.
5669 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5671 if (newStorage
== 0)
5672 return STG_E_INSUFFICIENTMEMORY
;
5674 hr
= StorageImpl_Construct(
5685 HeapFree(GetProcessHeap(), 0, newStorage
);
5690 * Get an "out" pointer for the caller.
5692 hr
= StorageBaseImpl_QueryInterface(
5693 (IStorage
*)newStorage
,
5694 (REFIID
)&IID_IStorage
,
5700 /******************************************************************************
5701 * StgOpenStorageOnILockBytes [OLE32.149]
5703 HRESULT WINAPI
StgOpenStorageOnILockBytes(
5705 IStorage
*pstgPriority
,
5709 IStorage
**ppstgOpen
)
5711 StorageImpl
* newStorage
= 0;
5715 * Perform a sanity check
5717 if ((plkbyt
== 0) || (ppstgOpen
== 0))
5718 return STG_E_INVALIDPOINTER
;
5721 * Validate the STGM flags
5723 if ( FAILED( validateSTGM(grfMode
) ))
5724 return STG_E_INVALIDFLAG
;
5727 * Initialize the "out" parameter.
5732 * Allocate and initialize the new IStorage object.
5734 newStorage
= HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl
));
5736 if (newStorage
== 0)
5737 return STG_E_INSUFFICIENTMEMORY
;
5739 hr
= StorageImpl_Construct(
5750 HeapFree(GetProcessHeap(), 0, newStorage
);
5755 * Get an "out" pointer for the caller.
5757 hr
= StorageBaseImpl_QueryInterface(
5758 (IStorage
*)newStorage
,
5759 (REFIID
)&IID_IStorage
,
5765 /******************************************************************************
5766 * StgSetTimes [ole32.150]
5767 * StgSetTimes [OLE32.150]
5771 HRESULT WINAPI
StgSetTimes(OLECHAR
*str
, FILETIME
*a
, FILETIME
*b
, FILETIME
*c
)
5773 FIXME("(%s, %p, %p, %p),stub!\n", debugstr_w(str
), a
, b
, c
);
5777 /******************************************************************************
5778 * StgIsStorageILockBytes [OLE32.147]
5780 * Determines if the ILockBytes contains a storage object.
5782 HRESULT WINAPI
StgIsStorageILockBytes(ILockBytes
*plkbyt
)
5785 ULARGE_INTEGER offset
;
5787 offset
.s
.HighPart
= 0;
5788 offset
.s
.LowPart
= 0;
5790 ILockBytes_ReadAt(plkbyt
, offset
, sig
, sizeof(sig
), NULL
);
5792 if (memcmp(sig
, STORAGE_magic
, sizeof(STORAGE_magic
)) == 0)
5798 /******************************************************************************
5799 * WriteClassStg [OLE32.158]
5801 * This method will store the specified CLSID in the specified storage object
5803 HRESULT WINAPI
WriteClassStg(IStorage
* pStg
, REFCLSID rclsid
)
5809 hRes
= IStorage_SetClass(pStg
, rclsid
);
5814 /***********************************************************************
5815 * ReadClassStg (OLE32.134)
5817 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5819 HRESULT WINAPI
ReadClassStg(IStorage
*pstg
,CLSID
*pclsid
){
5829 * read a STATSTG structure (contains the clsid) from the storage
5831 hRes
=IStorage_Stat(pstg
,&pstatstg
,STATFLAG_DEFAULT
);
5834 *pclsid
=pstatstg
.clsid
;
5839 /***********************************************************************
5840 * OleLoadFromStream (OLE32.113)
5842 * This function loads an object from stream
5844 HRESULT WINAPI
OleLoadFromStream(IStream
*pStm
,REFIID iidInterface
,void** ppvObj
)
5848 LPPERSISTSTREAM xstm
;
5850 TRACE("(%p,%s,%p)\n",pStm
,debugstr_guid(iidInterface
),ppvObj
);
5852 res
=ReadClassStm(pStm
,&clsid
);
5853 if (!SUCCEEDED(res
))
5855 res
=CoCreateInstance(&clsid
,NULL
,CLSCTX_INPROC_SERVER
,iidInterface
,ppvObj
);
5856 if (!SUCCEEDED(res
))
5858 res
=IUnknown_QueryInterface((IUnknown
*)*ppvObj
,&IID_IPersistStream
,(LPVOID
*)&xstm
);
5859 if (!SUCCEEDED(res
)) {
5860 IUnknown_Release((IUnknown
*)*ppvObj
);
5863 res
=IPersistStream_Load(xstm
,pStm
);
5864 IPersistStream_Release(xstm
);
5865 /* FIXME: all refcounts ok at this point? I think they should be:
5868 * xstm : 0 (released)
5873 /***********************************************************************
5874 * OleSaveToStream (OLE32.125)
5876 * This function saves an object with the IPersistStream interface on it
5877 * to the specified stream.
5879 HRESULT WINAPI
OleSaveToStream(IPersistStream
*pPStm
,IStream
*pStm
)
5885 TRACE("(%p,%p)\n",pPStm
,pStm
);
5887 res
=IPersistStream_GetClassID(pPStm
,&clsid
);
5889 if (SUCCEEDED(res
)){
5891 res
=WriteClassStm(pStm
,&clsid
);
5895 res
=IPersistStream_Save(pPStm
,pStm
,TRUE
);
5898 TRACE("Finished Save\n");
5902 /****************************************************************************
5903 * This method validate a STGM parameter that can contain the values below
5905 * STGM_DIRECT 0x00000000
5906 * STGM_TRANSACTED 0x00010000
5907 * STGM_SIMPLE 0x08000000
5909 * STGM_READ 0x00000000
5910 * STGM_WRITE 0x00000001
5911 * STGM_READWRITE 0x00000002
5913 * STGM_SHARE_DENY_NONE 0x00000040
5914 * STGM_SHARE_DENY_READ 0x00000030
5915 * STGM_SHARE_DENY_WRITE 0x00000020
5916 * STGM_SHARE_EXCLUSIVE 0x00000010
5918 * STGM_PRIORITY 0x00040000
5919 * STGM_DELETEONRELEASE 0x04000000
5921 * STGM_CREATE 0x00001000
5922 * STGM_CONVERT 0x00020000
5923 * STGM_FAILIFTHERE 0x00000000
5925 * STGM_NOSCRATCH 0x00100000
5926 * STGM_NOSNAPSHOT 0x00200000
5928 static HRESULT
validateSTGM(DWORD stgm
)
5930 BOOL bSTGM_TRANSACTED
= ((stgm
& STGM_TRANSACTED
) == STGM_TRANSACTED
);
5931 BOOL bSTGM_SIMPLE
= ((stgm
& STGM_SIMPLE
) == STGM_SIMPLE
);
5932 BOOL bSTGM_DIRECT
= ! (bSTGM_TRANSACTED
|| bSTGM_SIMPLE
);
5934 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
5935 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
5936 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
5938 BOOL bSTGM_SHARE_DENY_NONE
=
5939 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
5941 BOOL bSTGM_SHARE_DENY_READ
=
5942 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
5944 BOOL bSTGM_SHARE_DENY_WRITE
=
5945 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
5947 BOOL bSTGM_SHARE_EXCLUSIVE
=
5948 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
5950 BOOL bSTGM_CREATE
= ((stgm
& STGM_CREATE
) == STGM_CREATE
);
5951 BOOL bSTGM_CONVERT
= ((stgm
& STGM_CONVERT
) == STGM_CONVERT
);
5953 BOOL bSTGM_NOSCRATCH
= ((stgm
& STGM_NOSCRATCH
) == STGM_NOSCRATCH
);
5954 BOOL bSTGM_NOSNAPSHOT
= ((stgm
& STGM_NOSNAPSHOT
) == STGM_NOSNAPSHOT
);
5957 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5959 if ( ! bSTGM_DIRECT
)
5960 if( bSTGM_TRANSACTED
&& bSTGM_SIMPLE
)
5964 * STGM_WRITE | STGM_READWRITE | STGM_READ
5967 if( bSTGM_WRITE
&& bSTGM_READWRITE
)
5971 * STGM_SHARE_DENY_NONE | others
5972 * (I assume here that DENY_READ implies DENY_WRITE)
5974 if ( bSTGM_SHARE_DENY_NONE
)
5975 if ( bSTGM_SHARE_DENY_READ
||
5976 bSTGM_SHARE_DENY_WRITE
||
5977 bSTGM_SHARE_EXCLUSIVE
)
5981 * STGM_CREATE | STGM_CONVERT
5982 * if both are false, STGM_FAILIFTHERE is set to TRUE
5984 if ( bSTGM_CREATE
&& bSTGM_CONVERT
)
5988 * STGM_NOSCRATCH requires STGM_TRANSACTED
5990 if ( bSTGM_NOSCRATCH
&& ! bSTGM_TRANSACTED
)
5994 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5995 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5997 if (bSTGM_NOSNAPSHOT
)
5999 if ( ! ( bSTGM_TRANSACTED
&&
6000 !(bSTGM_SHARE_EXCLUSIVE
|| bSTGM_SHARE_DENY_WRITE
)) )
6007 /****************************************************************************
6008 * GetShareModeFromSTGM
6010 * This method will return a share mode flag from a STGM value.
6011 * The STGM value is assumed valid.
6013 static DWORD
GetShareModeFromSTGM(DWORD stgm
)
6015 DWORD dwShareMode
= 0;
6016 BOOL bSTGM_SHARE_DENY_NONE
=
6017 ((stgm
& STGM_SHARE_DENY_NONE
) == STGM_SHARE_DENY_NONE
);
6019 BOOL bSTGM_SHARE_DENY_READ
=
6020 ((stgm
& STGM_SHARE_DENY_READ
) == STGM_SHARE_DENY_READ
);
6022 BOOL bSTGM_SHARE_DENY_WRITE
=
6023 ((stgm
& STGM_SHARE_DENY_WRITE
) == STGM_SHARE_DENY_WRITE
);
6025 BOOL bSTGM_SHARE_EXCLUSIVE
=
6026 ((stgm
& STGM_SHARE_EXCLUSIVE
) == STGM_SHARE_EXCLUSIVE
);
6028 if ((bSTGM_SHARE_EXCLUSIVE
) || (bSTGM_SHARE_DENY_READ
))
6031 if (bSTGM_SHARE_DENY_NONE
)
6032 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
6034 if (bSTGM_SHARE_DENY_WRITE
)
6035 dwShareMode
= FILE_SHARE_READ
;
6040 /****************************************************************************
6041 * GetAccessModeFromSTGM
6043 * This method will return an access mode flag from a STGM value.
6044 * The STGM value is assumed valid.
6046 static DWORD
GetAccessModeFromSTGM(DWORD stgm
)
6048 DWORD dwDesiredAccess
= GENERIC_READ
;
6049 BOOL bSTGM_WRITE
= ((stgm
& STGM_WRITE
) == STGM_WRITE
);
6050 BOOL bSTGM_READWRITE
= ((stgm
& STGM_READWRITE
) == STGM_READWRITE
);
6051 BOOL bSTGM_READ
= ! (bSTGM_WRITE
|| bSTGM_READWRITE
);
6054 dwDesiredAccess
= GENERIC_READ
;
6057 dwDesiredAccess
|= GENERIC_WRITE
;
6059 if (bSTGM_READWRITE
)
6060 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
6062 return dwDesiredAccess
;
6065 /****************************************************************************
6066 * GetCreationModeFromSTGM
6068 * This method will return a creation mode flag from a STGM value.
6069 * The STGM value is assumed valid.
6071 static DWORD
GetCreationModeFromSTGM(DWORD stgm
)
6073 if ( stgm
& STGM_CREATE
)
6074 return CREATE_ALWAYS
;
6075 if (stgm
& STGM_CONVERT
) {
6076 FIXME("STGM_CONVERT not implemented!\n");
6079 /* All other cases */
6080 if (stgm
& ~ (STGM_CREATE
|STGM_CONVERT
))
6081 FIXME("unhandled storage mode : 0x%08lx\n",stgm
& ~ (STGM_CREATE
|STGM_CONVERT
));
6086 /*************************************************************************
6087 * OLECONVERT_LoadOLE10 [Internal]
6089 * Loads the OLE10 STREAM to memory
6092 * pOleStream [I] The OLESTREAM
6093 * pData [I] Data Structure for the OLESTREAM Data
6097 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
6098 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6101 * This function is used by OleConvertOLESTREAMToIStorage only.
6103 * Memory allocated for pData must be freed by the caller
6105 HRESULT
OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream
, OLECONVERT_OLESTREAM_DATA
*pData
, BOOL bStrem1
)
6108 HRESULT hRes
= S_OK
;
6112 pData
->pData
= NULL
;
6113 pData
->pstrOleObjFileName
= (CHAR
*) NULL
;
6115 for( nTryCnt
=0;nTryCnt
< max_try
; nTryCnt
++)
6118 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwOleID
), sizeof(pData
->dwOleID
));
6119 if(dwSize
!= sizeof(pData
->dwOleID
))
6121 hRes
= CONVERT10_E_OLESTREAM_GET
;
6123 else if(pData
->dwOleID
!= OLESTREAM_ID
)
6125 hRes
= CONVERT10_E_OLESTREAM_FMT
;
6136 /* Get the TypeID...more info needed for this field */
6137 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwTypeID
), sizeof(pData
->dwTypeID
));
6138 if(dwSize
!= sizeof(pData
->dwTypeID
))
6140 hRes
= CONVERT10_E_OLESTREAM_GET
;
6145 if(pData
->dwTypeID
!= 0)
6147 /* Get the lenght of the OleTypeName */
6148 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *) &(pData
->dwOleTypeNameLength
), sizeof(pData
->dwOleTypeNameLength
));
6149 if(dwSize
!= sizeof(pData
->dwOleTypeNameLength
))
6151 hRes
= CONVERT10_E_OLESTREAM_GET
;
6156 if(pData
->dwOleTypeNameLength
> 0)
6158 /* Get the OleTypeName */
6159 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)pData
->strOleTypeName
, pData
->dwOleTypeNameLength
);
6160 if(dwSize
!= pData
->dwOleTypeNameLength
)
6162 hRes
= CONVERT10_E_OLESTREAM_GET
;
6168 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwOleObjFileNameLength
), sizeof(pData
->dwOleObjFileNameLength
));
6169 if(dwSize
!= sizeof(pData
->dwOleObjFileNameLength
))
6171 hRes
= CONVERT10_E_OLESTREAM_GET
;
6175 if(pData
->dwOleObjFileNameLength
< 1) /* there is no file name exist */
6176 pData
->dwOleObjFileNameLength
= sizeof(pData
->dwOleObjFileNameLength
);
6177 pData
->pstrOleObjFileName
= (CHAR
*)malloc(pData
->dwOleObjFileNameLength
);
6178 if(pData
->pstrOleObjFileName
)
6180 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)(pData
->pstrOleObjFileName
),pData
->dwOleObjFileNameLength
);
6181 if(dwSize
!= pData
->dwOleObjFileNameLength
)
6183 hRes
= CONVERT10_E_OLESTREAM_GET
;
6187 hRes
= CONVERT10_E_OLESTREAM_GET
;
6192 /* Get the Width of the Metafile */
6193 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwMetaFileWidth
), sizeof(pData
->dwMetaFileWidth
));
6194 if(dwSize
!= sizeof(pData
->dwMetaFileWidth
))
6196 hRes
= CONVERT10_E_OLESTREAM_GET
;
6200 /* Get the Height of the Metafile */
6201 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwMetaFileHeight
), sizeof(pData
->dwMetaFileHeight
));
6202 if(dwSize
!= sizeof(pData
->dwMetaFileHeight
))
6204 hRes
= CONVERT10_E_OLESTREAM_GET
;
6210 /* Get the Lenght of the Data */
6211 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)&(pData
->dwDataLength
), sizeof(pData
->dwDataLength
));
6212 if(dwSize
!= sizeof(pData
->dwDataLength
))
6214 hRes
= CONVERT10_E_OLESTREAM_GET
;
6218 if(hRes
== S_OK
) /* I don't know what is this 8 byts information is we have to figure out */
6220 if(!bStrem1
) /* if it is a second OLE stream data */
6222 pData
->dwDataLength
-= 8;
6223 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)(pData
->strUnknown
), sizeof(pData
->strUnknown
));
6224 if(dwSize
!= sizeof(pData
->strUnknown
))
6226 hRes
= CONVERT10_E_OLESTREAM_GET
;
6232 if(pData
->dwDataLength
> 0)
6234 pData
->pData
= (BYTE
*)HeapAlloc(GetProcessHeap(),0,pData
->dwDataLength
);
6236 /* Get Data (ex. IStorage, Metafile, or BMP) */
6239 dwSize
= pOleStream
->lpstbl
->Get(pOleStream
, (void *)pData
->pData
, pData
->dwDataLength
);
6240 if(dwSize
!= pData
->dwDataLength
)
6242 hRes
= CONVERT10_E_OLESTREAM_GET
;
6247 hRes
= CONVERT10_E_OLESTREAM_GET
;
6256 /*************************************************************************
6257 * OLECONVERT_SaveOLE10 [Internal]
6259 * Saves the OLE10 STREAM From memory
6262 * pData [I] Data Structure for the OLESTREAM Data
6263 * pOleStream [I] The OLESTREAM to save
6267 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6270 * This function is used by OleConvertIStorageToOLESTREAM only.
6273 HRESULT
OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA
*pData
, LPOLESTREAM pOleStream
)
6276 HRESULT hRes
= S_OK
;
6280 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwOleID
), sizeof(pData
->dwOleID
));
6281 if(dwSize
!= sizeof(pData
->dwOleID
))
6283 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6288 /* Set the TypeID */
6289 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwTypeID
), sizeof(pData
->dwTypeID
));
6290 if(dwSize
!= sizeof(pData
->dwTypeID
))
6292 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6296 if(pData
->dwOleID
== OLESTREAM_ID
&& pData
->dwTypeID
!= 0 && hRes
== S_OK
)
6298 /* Set the Lenght of the OleTypeName */
6299 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwOleTypeNameLength
), sizeof(pData
->dwOleTypeNameLength
));
6300 if(dwSize
!= sizeof(pData
->dwOleTypeNameLength
))
6302 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6307 if(pData
->dwOleTypeNameLength
> 0)
6309 /* Set the OleTypeName */
6310 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *) pData
->strOleTypeName
, pData
->dwOleTypeNameLength
);
6311 if(dwSize
!= pData
->dwOleTypeNameLength
)
6313 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6320 /* Set the width of the Metafile */
6321 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwMetaFileWidth
), sizeof(pData
->dwMetaFileWidth
));
6322 if(dwSize
!= sizeof(pData
->dwMetaFileWidth
))
6324 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6330 /* Set the height of the Metafile */
6331 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwMetaFileHeight
), sizeof(pData
->dwMetaFileHeight
));
6332 if(dwSize
!= sizeof(pData
->dwMetaFileHeight
))
6334 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6340 /* Set the lenght of the Data */
6341 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *)&(pData
->dwDataLength
), sizeof(pData
->dwDataLength
));
6342 if(dwSize
!= sizeof(pData
->dwDataLength
))
6344 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6350 if(pData
->dwDataLength
> 0)
6352 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6353 dwSize
= pOleStream
->lpstbl
->Put(pOleStream
, (void *) pData
->pData
, pData
->dwDataLength
);
6354 if(dwSize
!= pData
->dwDataLength
)
6356 hRes
= CONVERT10_E_OLESTREAM_PUT
;
6364 /*************************************************************************
6365 * OLECONVERT_GetOLE20FromOLE10[Internal]
6367 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6368 * opens it, and copies the content to the dest IStorage for
6369 * OleConvertOLESTREAMToIStorage
6373 * pDestStorage [I] The IStorage to copy the data to
6374 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
6375 * nBufferLength [I] The size of the buffer
6384 void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage
, BYTE
*pBuffer
, DWORD nBufferLength
)
6388 IStorage
*pTempStorage
;
6389 DWORD dwNumOfBytesWritten
;
6390 WCHAR wstrTempDir
[MAX_PATH
], wstrTempFile
[MAX_PATH
];
6391 WCHAR wstrPrefix
[] = {'s', 'i', 's', 0};
6393 /* Create a temp File */
6394 GetTempPathW(MAX_PATH
, wstrTempDir
);
6395 GetTempFileNameW(wstrTempDir
, wstrPrefix
, 0, wstrTempFile
);
6396 hFile
= CreateFileW(wstrTempFile
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
6398 if(hFile
!= INVALID_HANDLE_VALUE
)
6400 /* Write IStorage Data to File */
6401 WriteFile(hFile
, pBuffer
, nBufferLength
, &dwNumOfBytesWritten
, NULL
);
6404 /* Open and copy temp storage to the Dest Storage */
6405 hRes
= StgOpenStorage(wstrTempFile
, NULL
, STGM_READ
, NULL
, 0, &pTempStorage
);
6408 hRes
= StorageImpl_CopyTo(pTempStorage
, 0, NULL
, NULL
, pDestStorage
);
6409 StorageBaseImpl_Release(pTempStorage
);
6411 DeleteFileW(wstrTempFile
);
6416 /*************************************************************************
6417 * OLECONVERT_WriteOLE20ToBuffer [Internal]
6419 * Saves the OLE10 STREAM From memory
6422 * pStorage [I] The Src IStorage to copy
6423 * pData [I] The Dest Memory to write to.
6426 * The size in bytes allocated for pData
6429 * Memory allocated for pData must be freed by the caller
6431 * Used by OleConvertIStorageToOLESTREAM only.
6434 DWORD
OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage
, BYTE
**pData
)
6438 DWORD nDataLength
= 0;
6439 IStorage
*pTempStorage
;
6440 WCHAR wstrTempDir
[MAX_PATH
], wstrTempFile
[MAX_PATH
];
6441 WCHAR wstrPrefix
[] = {'s', 'i', 's', 0};
6445 /* Create temp Storage */
6446 GetTempPathW(MAX_PATH
, wstrTempDir
);
6447 GetTempFileNameW(wstrTempDir
, wstrPrefix
, 0, wstrTempFile
);
6448 hRes
= StgCreateDocfile(wstrTempFile
, STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
, 0, &pTempStorage
);
6452 /* Copy Src Storage to the Temp Storage */
6453 StorageImpl_CopyTo(pStorage
, 0, NULL
, NULL
, pTempStorage
);
6454 StorageBaseImpl_Release(pTempStorage
);
6456 /* Open Temp Storage as a file and copy to memory */
6457 hFile
= CreateFileW(wstrTempFile
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
6458 if(hFile
!= INVALID_HANDLE_VALUE
)
6460 nDataLength
= GetFileSize(hFile
, NULL
);
6461 *pData
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,nDataLength
);
6462 ReadFile(hFile
, *pData
, nDataLength
, &nDataLength
, 0);
6465 DeleteFileW(wstrTempFile
);
6470 /*************************************************************************
6471 * OLECONVERT_CreateOleStream [Internal]
6473 * Creates the "\001OLE" stream in the IStorage if neccessary.
6476 * pStorage [I] Dest storage to create the stream in
6482 * This function is used by OleConvertOLESTREAMToIStorage only.
6484 * This stream is still unknown, MS Word seems to have extra data
6485 * but since the data is stored in the OLESTREAM there should be
6486 * no need to recreate the stream. If the stream is manually
6487 * deleted it will create it with this default data.
6490 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage
)
6494 WCHAR wstrStreamName
[] = {1,'O', 'l', 'e', 0};
6495 BYTE pOleStreamHeader
[] =
6497 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6499 0x00, 0x00, 0x00, 0x00
6502 /* Create stream if not present */
6503 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6504 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6508 /* Write default Data */
6509 hRes
= IStream_Write(pStream
, pOleStreamHeader
, sizeof(pOleStreamHeader
), NULL
);
6510 IStream_Release(pStream
);
6515 /*************************************************************************
6516 * OLECONVERT_CreateCompObjStream [Internal]
6518 * Creates a "\001CompObj" is the destination IStorage if necessary.
6521 * pStorage [I] The dest IStorage to create the CompObj Stream
6523 * strOleTypeName [I] The ProgID
6527 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6530 * This function is used by OleConvertOLESTREAMToIStorage only.
6532 * The stream data is stored in the OLESTREAM and there should be
6533 * no need to recreate the stream. If the stream is manually
6534 * deleted it will attempt to create it by querying the registry.
6538 HRESULT
OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage
, LPCSTR strOleTypeName
)
6541 HRESULT hStorageRes
, hRes
= S_OK
;
6542 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj
;
6543 WCHAR wstrStreamName
[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6545 BYTE pCompObjUnknown1
[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
6546 BYTE pCompObjUnknown2
[] = {0xF4, 0x39, 0xB2, 0x71};
6548 /* Initialize the CompObj structure */
6549 memset(&IStorageCompObj
, 0, sizeof(IStorageCompObj
));
6550 memcpy(&(IStorageCompObj
.byUnknown1
), pCompObjUnknown1
, sizeof(pCompObjUnknown1
));
6551 memcpy(&(IStorageCompObj
.byUnknown2
), pCompObjUnknown2
, sizeof(pCompObjUnknown2
));
6554 /* Create a CompObj stream if it doesn't exist */
6555 hStorageRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6556 STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6557 if(hStorageRes
== S_OK
)
6559 /* copy the OleTypeName to the compobj struct */
6560 IStorageCompObj
.dwOleTypeNameLength
= strlen(strOleTypeName
)+1;
6561 strcpy(IStorageCompObj
.strOleTypeName
, strOleTypeName
);
6563 /* copy the OleTypeName to the compobj struct */
6564 /* Note: in the test made, these were Identical */
6565 IStorageCompObj
.dwProgIDNameLength
= strlen(strOleTypeName
)+1;
6566 strcpy(IStorageCompObj
.strProgIDName
, strOleTypeName
);
6569 hRes
= CLSIDFromProgID16(IStorageCompObj
.strProgIDName
, &(IStorageCompObj
.clsid
));
6575 /* Get the CLSID Default Name from the Registry */
6576 hErr
= RegOpenKeyA(HKEY_CLASSES_ROOT
, IStorageCompObj
.strProgIDName
, &hKey
);
6577 if(hErr
== ERROR_SUCCESS
)
6579 char strTemp
[OLESTREAM_MAX_STR_LEN
];
6580 IStorageCompObj
.dwCLSIDNameLength
= OLESTREAM_MAX_STR_LEN
;
6581 hErr
= RegQueryValueA(hKey
, NULL
, strTemp
, &(IStorageCompObj
.dwCLSIDNameLength
));
6582 if(hErr
== ERROR_SUCCESS
)
6584 strcpy(IStorageCompObj
.strCLSIDName
, strTemp
);
6590 /* Write CompObj Structure to stream */
6591 hRes
= IStream_Write(pStream
, IStorageCompObj
.byUnknown1
, sizeof(IStorageCompObj
.byUnknown1
), NULL
);
6593 WriteClassStm(pStream
,&(IStorageCompObj
.clsid
));
6595 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwCLSIDNameLength
), sizeof(IStorageCompObj
.dwCLSIDNameLength
), NULL
);
6596 if(IStorageCompObj
.dwCLSIDNameLength
> 0)
6598 hRes
= IStream_Write(pStream
, IStorageCompObj
.strCLSIDName
, IStorageCompObj
.dwCLSIDNameLength
, NULL
);
6600 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwOleTypeNameLength
) , sizeof(IStorageCompObj
.dwOleTypeNameLength
), NULL
);
6601 if(IStorageCompObj
.dwOleTypeNameLength
> 0)
6603 hRes
= IStream_Write(pStream
, IStorageCompObj
.strOleTypeName
, IStorageCompObj
.dwOleTypeNameLength
, NULL
);
6605 hRes
= IStream_Write(pStream
, &(IStorageCompObj
.dwProgIDNameLength
) , sizeof(IStorageCompObj
.dwProgIDNameLength
), NULL
);
6606 if(IStorageCompObj
.dwProgIDNameLength
> 0)
6608 hRes
= IStream_Write(pStream
, IStorageCompObj
.strProgIDName
, IStorageCompObj
.dwProgIDNameLength
, NULL
);
6610 hRes
= IStream_Write(pStream
, IStorageCompObj
.byUnknown2
, sizeof(IStorageCompObj
.byUnknown2
), NULL
);
6611 IStream_Release(pStream
);
6617 /*************************************************************************
6618 * OLECONVERT_CreateOlePresStream[Internal]
6620 * Creates the "\002OlePres000" Stream with the Metafile data
6623 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
6624 * dwExtentX [I] Width of the Metafile
6625 * dwExtentY [I] Height of the Metafile
6626 * pData [I] Metafile data
6627 * dwDataLength [I] Size of the Metafile data
6631 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6634 * This function is used by OleConvertOLESTREAMToIStorage only.
6637 void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage
, DWORD dwExtentX
, DWORD dwExtentY
, BYTE
*pData
, DWORD dwDataLength
)
6641 WCHAR wstrStreamName
[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6642 BYTE pOlePresStreamHeader
[] =
6644 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
6645 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6646 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6647 0x00, 0x00, 0x00, 0x00
6650 BYTE pOlePresStreamHeaderEmpty
[] =
6652 0x00, 0x00, 0x00, 0x00,
6653 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6654 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6655 0x00, 0x00, 0x00, 0x00
6658 /* Create the OlePres000 Stream */
6659 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6660 STGM_CREATE
| STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6665 OLECONVERT_ISTORAGE_OLEPRES OlePres
;
6667 memset(&OlePres
, 0, sizeof(OlePres
));
6668 /* Do we have any metafile data to save */
6669 if(dwDataLength
> 0)
6671 memcpy(OlePres
.byUnknown1
, pOlePresStreamHeader
, sizeof(pOlePresStreamHeader
));
6672 nHeaderSize
= sizeof(pOlePresStreamHeader
);
6676 memcpy(OlePres
.byUnknown1
, pOlePresStreamHeaderEmpty
, sizeof(pOlePresStreamHeaderEmpty
));
6677 nHeaderSize
= sizeof(pOlePresStreamHeaderEmpty
);
6679 /* Set width and height of the metafile */
6680 OlePres
.dwExtentX
= dwExtentX
;
6681 OlePres
.dwExtentY
= -dwExtentY
;
6683 /* Set Data and Lenght */
6684 if(dwDataLength
> sizeof(METAFILEPICT16
))
6686 OlePres
.dwSize
= dwDataLength
- sizeof(METAFILEPICT16
);
6687 OlePres
.pData
= &(pData
[8]);
6689 /* Save OlePres000 Data to Stream */
6690 hRes
= IStream_Write(pStream
, OlePres
.byUnknown1
, nHeaderSize
, NULL
);
6691 hRes
= IStream_Write(pStream
, &(OlePres
.dwExtentX
), sizeof(OlePres
.dwExtentX
), NULL
);
6692 hRes
= IStream_Write(pStream
, &(OlePres
.dwExtentY
), sizeof(OlePres
.dwExtentY
), NULL
);
6693 hRes
= IStream_Write(pStream
, &(OlePres
.dwSize
), sizeof(OlePres
.dwSize
), NULL
);
6694 if(OlePres
.dwSize
> 0)
6696 hRes
= IStream_Write(pStream
, OlePres
.pData
, OlePres
.dwSize
, NULL
);
6698 IStream_Release(pStream
);
6702 /*************************************************************************
6703 * OLECONVERT_CreateOle10NativeStream [Internal]
6705 * Creates the "\001Ole10Native" Stream (should contain a BMP)
6708 * pStorage [I] Dest storage to create the stream in
6709 * pData [I] Ole10 Native Data (ex. bmp)
6710 * dwDataLength [I] Size of the Ole10 Native Data
6716 * This function is used by OleConvertOLESTREAMToIStorage only.
6718 * Might need to verify the data and return appropriate error message
6721 void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage
, BYTE
*pData
, DWORD dwDataLength
)
6725 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6727 /* Create the Ole10Native Stream */
6728 hRes
= IStorage_CreateStream(pStorage
, wstrStreamName
,
6729 STGM_CREATE
| STGM_WRITE
| STGM_SHARE_EXCLUSIVE
, 0, 0, &pStream
);
6733 /* Write info to stream */
6734 hRes
= IStream_Write(pStream
, &dwDataLength
, sizeof(dwDataLength
), NULL
);
6735 hRes
= IStream_Write(pStream
, pData
, dwDataLength
, NULL
);
6736 IStream_Release(pStream
);
6741 /*************************************************************************
6742 * OLECONVERT_GetOLE10ProgID [Internal]
6744 * Finds the ProgID (or OleTypeID) from the IStorage
6747 * pStorage [I] The Src IStorage to get the ProgID
6748 * strProgID [I] the ProgID string to get
6749 * dwSize [I] the size of the string
6753 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6756 * This function is used by OleConvertIStorageToOLESTREAM only.
6760 HRESULT
OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage
, char *strProgID
, DWORD
*dwSize
)
6764 LARGE_INTEGER iSeekPos
;
6765 OLECONVERT_ISTORAGE_COMPOBJ CompObj
;
6766 WCHAR wstrStreamName
[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6768 /* Open the CompObj Stream */
6769 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6770 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6774 /*Get the OleType from the CompObj Stream */
6775 iSeekPos
.s
.LowPart
= sizeof(CompObj
.byUnknown1
) + sizeof(CompObj
.clsid
);
6776 iSeekPos
.s
.HighPart
= 0;
6778 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_SET
, NULL
);
6779 IStream_Read(pStream
, &CompObj
.dwCLSIDNameLength
, sizeof(CompObj
.dwCLSIDNameLength
), NULL
);
6780 iSeekPos
.s
.LowPart
= CompObj
.dwCLSIDNameLength
;
6781 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_CUR
, NULL
);
6782 IStream_Read(pStream
, &CompObj
.dwOleTypeNameLength
, sizeof(CompObj
.dwOleTypeNameLength
), NULL
);
6783 iSeekPos
.s
.LowPart
= CompObj
.dwOleTypeNameLength
;
6784 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_CUR
, NULL
);
6786 IStream_Read(pStream
, dwSize
, sizeof(*dwSize
), NULL
);
6789 IStream_Read(pStream
, strProgID
, *dwSize
, NULL
);
6791 IStream_Release(pStream
);
6796 LPOLESTR wstrProgID
;
6798 /* Get the OleType from the registry */
6799 REFCLSID clsid
= &(stat
.clsid
);
6800 IStorage_Stat(pStorage
, &stat
, STATFLAG_NONAME
);
6801 hRes
= ProgIDFromCLSID(clsid
, &wstrProgID
);
6804 *dwSize
= WideCharToMultiByte(CP_ACP
, 0, wstrProgID
, -1, strProgID
, *dwSize
, NULL
, FALSE
);
6811 /*************************************************************************
6812 * OLECONVERT_GetOle10PresData [Internal]
6814 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
6817 * pStorage [I] Src IStroage
6818 * pOleStream [I] Dest OleStream Mem Struct
6824 * This function is used by OleConvertIStorageToOLESTREAM only.
6826 * Memory allocated for pData must be freed by the caller
6830 void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage
, OLECONVERT_OLESTREAM_DATA
*pOleStreamData
)
6835 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6837 /* Initialize Default data for OLESTREAM */
6838 pOleStreamData
[0].dwOleID
= OLESTREAM_ID
;
6839 pOleStreamData
[0].dwTypeID
= 2;
6840 pOleStreamData
[1].dwOleID
= OLESTREAM_ID
;
6841 pOleStreamData
[1].dwTypeID
= 0;
6842 pOleStreamData
[0].dwMetaFileWidth
= 0;
6843 pOleStreamData
[0].dwMetaFileHeight
= 0;
6844 pOleStreamData
[0].pData
= NULL
;
6845 pOleStreamData
[1].pData
= NULL
;
6847 /* Open Ole10Native Stream */
6848 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6849 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6853 /* Read Size and Data */
6854 IStream_Read(pStream
, &(pOleStreamData
->dwDataLength
), sizeof(pOleStreamData
->dwDataLength
), NULL
);
6855 if(pOleStreamData
->dwDataLength
> 0)
6857 pOleStreamData
->pData
= (LPSTR
) HeapAlloc(GetProcessHeap(),0,pOleStreamData
->dwDataLength
);
6858 IStream_Read(pStream
, pOleStreamData
->pData
, pOleStreamData
->dwDataLength
, NULL
);
6860 IStream_Release(pStream
);
6866 /*************************************************************************
6867 * OLECONVERT_GetOle20PresData[Internal]
6869 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
6872 * pStorage [I] Src IStroage
6873 * pOleStreamData [I] Dest OleStream Mem Struct
6879 * This function is used by OleConvertIStorageToOLESTREAM only.
6881 * Memory allocated for pData must be freed by the caller
6883 void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage
, OLECONVERT_OLESTREAM_DATA
*pOleStreamData
)
6887 OLECONVERT_ISTORAGE_OLEPRES olePress
;
6888 WCHAR wstrStreamName
[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6890 /* Initialize Default data for OLESTREAM */
6891 pOleStreamData
[0].dwOleID
= OLESTREAM_ID
;
6892 pOleStreamData
[0].dwTypeID
= 2;
6893 pOleStreamData
[0].dwMetaFileWidth
= 0;
6894 pOleStreamData
[0].dwMetaFileHeight
= 0;
6895 pOleStreamData
[0].dwDataLength
= OLECONVERT_WriteOLE20ToBuffer(pStorage
, &(pOleStreamData
[0].pData
));
6896 pOleStreamData
[1].dwOleID
= OLESTREAM_ID
;
6897 pOleStreamData
[1].dwTypeID
= 0;
6898 pOleStreamData
[1].dwOleTypeNameLength
= 0;
6899 pOleStreamData
[1].strOleTypeName
[0] = 0;
6900 pOleStreamData
[1].dwMetaFileWidth
= 0;
6901 pOleStreamData
[1].dwMetaFileHeight
= 0;
6902 pOleStreamData
[1].pData
= NULL
;
6903 pOleStreamData
[1].dwDataLength
= 0;
6906 /* Open OlePress000 stream */
6907 hRes
= IStorage_OpenStream(pStorage
, wstrStreamName
, NULL
,
6908 STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
6911 LARGE_INTEGER iSeekPos
;
6912 METAFILEPICT16 MetaFilePict
;
6913 char strMetafilePictName
[] = "METAFILEPICT";
6915 /* Set the TypeID for a Metafile */
6916 pOleStreamData
[1].dwTypeID
= 5;
6918 /* Set the OleTypeName to Metafile */
6919 pOleStreamData
[1].dwOleTypeNameLength
= strlen(strMetafilePictName
) +1;
6920 strcpy(pOleStreamData
[1].strOleTypeName
, strMetafilePictName
);
6922 iSeekPos
.s
.HighPart
= 0;
6923 iSeekPos
.s
.LowPart
= sizeof(olePress
.byUnknown1
);
6925 /* Get Presentation Data */
6926 IStream_Seek(pStream
, iSeekPos
, STREAM_SEEK_SET
, NULL
);
6927 IStream_Read(pStream
, &(olePress
.dwExtentX
), sizeof(olePress
.dwExtentX
), NULL
);
6928 IStream_Read(pStream
, &(olePress
.dwExtentY
), sizeof(olePress
.dwExtentY
), NULL
);
6929 IStream_Read(pStream
, &(olePress
.dwSize
), sizeof(olePress
.dwSize
), NULL
);
6931 /*Set width and Height */
6932 pOleStreamData
[1].dwMetaFileWidth
= olePress
.dwExtentX
;
6933 pOleStreamData
[1].dwMetaFileHeight
= -olePress
.dwExtentY
;
6934 if(olePress
.dwSize
> 0)
6937 pOleStreamData
[1].dwDataLength
= olePress
.dwSize
+ sizeof(METAFILEPICT16
);
6939 /* Set MetaFilePict struct */
6940 MetaFilePict
.mm
= 8;
6941 MetaFilePict
.xExt
= olePress
.dwExtentX
;
6942 MetaFilePict
.yExt
= olePress
.dwExtentY
;
6943 MetaFilePict
.hMF
= 0;
6945 /* Get Metafile Data */
6946 pOleStreamData
[1].pData
= (BYTE
*) HeapAlloc(GetProcessHeap(),0,pOleStreamData
[1].dwDataLength
);
6947 memcpy(pOleStreamData
[1].pData
, &MetaFilePict
, sizeof(MetaFilePict
));
6948 IStream_Read(pStream
, &(pOleStreamData
[1].pData
[sizeof(MetaFilePict
)]), pOleStreamData
[1].dwDataLength
-sizeof(METAFILEPICT16
), NULL
);
6950 IStream_Release(pStream
);
6954 /*************************************************************************
6955 * OleConvertOLESTREAMToIStorage [OLE32.87]
6960 * DVTARGETDEVICE paramenter is not handled
6961 * Still unsure of some mem fields for OLE 10 Stream
6962 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6963 * and "\001OLE" streams
6966 HRESULT WINAPI
OleConvertOLESTREAMToIStorage (
6967 LPOLESTREAM pOleStream
,
6969 const DVTARGETDEVICE
* ptd
)
6973 OLECONVERT_OLESTREAM_DATA pOleStreamData
[2];
6975 memset(pOleStreamData
, 0, sizeof(pOleStreamData
));
6979 FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
6982 if(pstg
== NULL
|| pOleStream
== NULL
)
6984 hRes
= E_INVALIDARG
;
6989 /* Load the OLESTREAM to Memory */
6990 hRes
= OLECONVERT_LoadOLE10(pOleStream
, &pOleStreamData
[0], TRUE
);
6995 /* Load the OLESTREAM to Memory (part 2)*/
6996 hRes
= OLECONVERT_LoadOLE10(pOleStream
, &pOleStreamData
[1], FALSE
);
7002 if(pOleStreamData
[0].dwDataLength
> sizeof(STORAGE_magic
))
7004 /* Do we have the IStorage Data in the OLESTREAM */
7005 if(memcmp(pOleStreamData
[0].pData
, STORAGE_magic
, sizeof(STORAGE_magic
)) ==0)
7007 OLECONVERT_GetOLE20FromOLE10(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
7008 OLECONVERT_CreateOlePresStream(pstg
, pOleStreamData
[1].dwMetaFileWidth
, pOleStreamData
[1].dwMetaFileHeight
, pOleStreamData
[1].pData
, pOleStreamData
[1].dwDataLength
);
7012 /* It must be an original OLE 1.0 source */
7013 OLECONVERT_CreateOle10NativeStream(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
7018 /* It must be an original OLE 1.0 source */
7019 OLECONVERT_CreateOle10NativeStream(pstg
, pOleStreamData
[0].pData
, pOleStreamData
[0].dwDataLength
);
7022 /* Create CompObj Stream if necessary */
7023 hRes
= OLECONVERT_CreateCompObjStream(pstg
, pOleStreamData
[0].strOleTypeName
);
7026 /*Create the Ole Stream if necessary */
7027 OLECONVERT_CreateOleStream(pstg
);
7032 /* Free allocated memory */
7033 for(i
=0; i
< 2; i
++)
7035 if(pOleStreamData
[i
].pData
!= NULL
)
7037 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pData
);
7039 if(pOleStreamData
[i
].pstrOleObjFileName
!= NULL
)
7041 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pstrOleObjFileName
);
7042 pOleStreamData
[i
].pstrOleObjFileName
= NULL
;
7048 /*************************************************************************
7049 * OleConvertIStorageToOLESTREAM [OLE32.85]
7056 * Still unsure of some mem fields for OLE 10 Stream
7057 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7058 * and "\001OLE" streams.
7061 HRESULT WINAPI
OleConvertIStorageToOLESTREAM (
7063 LPOLESTREAM pOleStream
)
7066 HRESULT hRes
= S_OK
;
7068 OLECONVERT_OLESTREAM_DATA pOleStreamData
[2];
7069 WCHAR wstrStreamName
[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7072 memset(pOleStreamData
, 0, sizeof(pOleStreamData
));
7074 if(pstg
== NULL
|| pOleStream
== NULL
)
7076 hRes
= E_INVALIDARG
;
7080 /* Get the ProgID */
7081 pOleStreamData
[0].dwOleTypeNameLength
= OLESTREAM_MAX_STR_LEN
;
7082 hRes
= OLECONVERT_GetOLE10ProgID(pstg
, pOleStreamData
[0].strOleTypeName
, &(pOleStreamData
[0].dwOleTypeNameLength
));
7086 /* Was it originally Ole10 */
7087 hRes
= IStorage_OpenStream(pstg
, wstrStreamName
, 0, STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, &pStream
);
7090 IStream_Release(pStream
);
7091 /* Get Presentation Data for Ole10Native */
7092 OLECONVERT_GetOle10PresData(pstg
, pOleStreamData
);
7096 /* Get Presentation Data (OLE20) */
7097 OLECONVERT_GetOle20PresData(pstg
, pOleStreamData
);
7100 /* Save OLESTREAM */
7101 hRes
= OLECONVERT_SaveOLE10(&(pOleStreamData
[0]), pOleStream
);
7104 hRes
= OLECONVERT_SaveOLE10(&(pOleStreamData
[1]), pOleStream
);
7109 /* Free allocated memory */
7110 for(i
=0; i
< 2; i
++)
7112 if(pOleStreamData
[i
].pData
!= NULL
)
7114 HeapFree(GetProcessHeap(),0,pOleStreamData
[i
].pData
);
7121 /***********************************************************************
7122 * GetConvertStg (OLE32.68)
7124 HRESULT WINAPI
GetConvertStg(LPGUID guid
) {
7125 FIXME("(%s), unimplemented stub!\n",debugstr_guid(guid
));