Optimized include/*.h: (recursively) include all headers needed by
[wine/testsucceed.git] / ole / storage32.c
blobf7a2dabf120d94fc5bcdef96b3db17466d9b6e01
1 /*
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
13 #include <assert.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
18 #include "windows.h"
19 #include "winerror.h"
20 #include "file.h"
21 #include "ole.h"
22 #include "ole2.h"
23 #include "objbase.h"
24 #include "crtdll.h"
25 #include "tchar.h"
26 #include "heap.h"
28 #include "winnt.h"
29 #include "winbase.h"
30 #include "debug.h"
32 #include "storage32.h"
34 #define FILE_BEGIN 0
36 static const char rootPropertyName[] = "Root Entry";
38 /***********************************************************************
39 * Forward declaration of internal functions used by the method DestroyElement
41 static HRESULT deleteStorageProperty(
42 Storage32Impl *parentStorage,
43 OLECHAR32 *propertyToDeleteName);
45 static HRESULT deleteStreamProperty(
46 Storage32Impl *parentStorage,
47 ULONG foundPropertyIndexToDelete,
48 StgProperty propertyToDelete);
50 static HRESULT findPlaceholder(
51 Storage32Impl *storage,
52 ULONG propertyIndexToStore,
53 ULONG storagePropertyIndex,
54 INT32 typeOfRelation);
56 static HRESULT adjustPropertyChain(
57 Storage32Impl *This,
58 StgProperty propertyToDelete,
59 StgProperty parentProperty,
60 ULONG parentPropertyId,
61 INT32 typeOfRelation);
63 /***********************************************************************
64 * Declaration of the functions used to manipulate StgProperty
67 static ULONG getFreeProperty(
68 Storage32Impl *storage);
70 static void updatePropertyChain(
71 Storage32Impl *storage,
72 ULONG newPropertyIndex,
73 StgProperty newProperty);
75 static LONG propertyNameCmp(
76 OLECHAR32 *newProperty,
77 OLECHAR32 *currentProperty);
80 /***********************************************************************
81 * Declaration of miscellaneous functions...
83 static HRESULT validateSTGM(DWORD stgmValue);
85 static DWORD GetShareModeFromSTGM(DWORD stgm);
86 static DWORD GetAccessModeFromSTGM(DWORD stgm);
87 static DWORD GetCreationModeFromSTGM(DWORD stgm);
90 * Virtual function table for the IStorage32Impl class.
92 static ICOM_VTABLE(IStorage32) Storage32Impl_VTable =
95 VTABLE_FUNC(Storage32BaseImpl_QueryInterface),
96 VTABLE_FUNC(Storage32BaseImpl_AddRef),
97 VTABLE_FUNC(Storage32BaseImpl_Release)
99 VTABLE_FUNC(Storage32BaseImpl_CreateStream),
100 VTABLE_FUNC(Storage32BaseImpl_OpenStream),
101 VTABLE_FUNC(Storage32Impl_CreateStorage),
102 VTABLE_FUNC(Storage32BaseImpl_OpenStorage),
103 VTABLE_FUNC(Storage32Impl_CopyTo),
104 VTABLE_FUNC(Storage32Impl_MoveElementTo),
105 VTABLE_FUNC(Storage32Impl_Commit),
106 VTABLE_FUNC(Storage32Impl_Revert),
107 VTABLE_FUNC(Storage32BaseImpl_EnumElements),
108 VTABLE_FUNC(Storage32Impl_DestroyElement),
109 VTABLE_FUNC(Storage32BaseImpl_RenameElement),
110 VTABLE_FUNC(Storage32Impl_SetElementTimes),
111 VTABLE_FUNC(Storage32BaseImpl_SetClass),
112 VTABLE_FUNC(Storage32Impl_SetStateBits),
113 VTABLE_FUNC(Storage32BaseImpl_Stat)
117 * Virtual function table for the Storage32InternalImpl class.
119 static ICOM_VTABLE(IStorage32) Storage32InternalImpl_VTable =
122 VTABLE_FUNC(Storage32BaseImpl_QueryInterface),
123 VTABLE_FUNC(Storage32BaseImpl_AddRef),
124 VTABLE_FUNC(Storage32BaseImpl_Release)
126 VTABLE_FUNC(Storage32BaseImpl_CreateStream),
127 VTABLE_FUNC(Storage32BaseImpl_OpenStream),
128 VTABLE_FUNC(Storage32Impl_CreateStorage),
129 VTABLE_FUNC(Storage32BaseImpl_OpenStorage),
130 VTABLE_FUNC(Storage32Impl_CopyTo),
131 VTABLE_FUNC(Storage32Impl_MoveElementTo),
132 VTABLE_FUNC(Storage32InternalImpl_Commit),
133 VTABLE_FUNC(Storage32InternalImpl_Revert),
134 VTABLE_FUNC(Storage32BaseImpl_EnumElements),
135 VTABLE_FUNC(Storage32Impl_DestroyElement),
136 VTABLE_FUNC(Storage32BaseImpl_RenameElement),
137 VTABLE_FUNC(Storage32Impl_SetElementTimes),
138 VTABLE_FUNC(Storage32BaseImpl_SetClass),
139 VTABLE_FUNC(Storage32Impl_SetStateBits),
140 VTABLE_FUNC(Storage32BaseImpl_Stat)
144 * Virtual function table for the IEnumSTATSTGImpl class.
146 static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
149 VTABLE_FUNC(IEnumSTATSTGImpl_QueryInterface),
150 VTABLE_FUNC(IEnumSTATSTGImpl_AddRef),
151 VTABLE_FUNC(IEnumSTATSTGImpl_Release)
153 VTABLE_FUNC(IEnumSTATSTGImpl_Next),
154 VTABLE_FUNC(IEnumSTATSTGImpl_Skip),
155 VTABLE_FUNC(IEnumSTATSTGImpl_Reset),
156 VTABLE_FUNC(IEnumSTATSTGImpl_Clone)
163 /************************************************************************
164 ** Storage32BaseImpl implementatiion
167 /************************************************************************
168 * Storage32BaseImpl_QueryInterface (IUnknown)
170 * This method implements the common QueryInterface for all IStorage32
171 * implementations contained in this file.
173 * See Windows documentation for more details on IUnknown methods.
175 HRESULT WINAPI Storage32BaseImpl_QueryInterface(
176 Storage32BaseImpl* This,
177 REFIID riid,
178 void** ppvObject)
181 * Perform a sanity check on the parameters.
183 if ( (This==0) || (ppvObject==0) )
184 return E_INVALIDARG;
187 * Initialize the return parameter.
189 *ppvObject = 0;
192 * Compare the riid with the interface IDs implemented by this object.
194 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
196 *ppvObject = (IStorage32*)This;
198 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
200 *ppvObject = (IStorage32*)This;
204 * Check that we obtained an interface.
206 if ((*ppvObject)==0)
207 return E_NOINTERFACE;
210 * Query Interface always increases the reference count by one when it is
211 * successful
213 Storage32BaseImpl_AddRef(This);
215 return S_OK;;
218 /************************************************************************
219 * Storage32BaseImpl_AddRef (IUnknown)
221 * This method implements the common AddRef for all IStorage32
222 * implementations contained in this file.
224 * See Windows documentation for more details on IUnknown methods.
226 ULONG WINAPI Storage32BaseImpl_AddRef(
227 Storage32BaseImpl* This)
229 This->ref++;
231 return This->ref;
234 /************************************************************************
235 * Storage32BaseImpl_Release (IUnknown)
237 * This method implements the common Release for all IStorage32
238 * implementations contained in this file.
240 * See Windows documentation for more details on IUnknown methods.
242 ULONG WINAPI Storage32BaseImpl_Release(
243 Storage32BaseImpl* This)
246 * Decrease the reference count on this object.
248 This->ref--;
251 * If the reference count goes down to 0, perform suicide.
253 if (This->ref==0)
256 * Since we are using a system of base-classes, we want to call the
257 * destructor of the appropriate derived class. To do this, we are
258 * using virtual functions to implement the destructor.
260 This->v_destructor(This);
262 return 0;
265 return This->ref;
268 /************************************************************************
269 * Storage32BaseImpl_OpenStream (IStorage)
271 * This method will open the specified stream object from the current storage.
273 * See Windows documentation for more details on IStorage methods.
275 HRESULT WINAPI Storage32BaseImpl_OpenStream(
276 Storage32BaseImpl* This,
277 const OLECHAR32* pwcsName, /* [string][in] */
278 void* reserved1, /* [unique][in] */
279 DWORD grfMode, /* [in] */
280 DWORD reserved2, /* [in] */
281 IStream32** ppstm) /* [out] */
283 IEnumSTATSTGImpl* propertyEnumeration;
284 StgStreamImpl* newStream;
285 StgProperty currentProperty;
286 ULONG foundPropertyIndex;
289 * Perform a sanity check on the parameters.
291 if ( (pwcsName==NULL) || (ppstm==0) )
292 return E_INVALIDARG;
295 * Initialize the out parameter
297 *ppstm = 0;
300 * Validate the STGM flags
302 if ( FAILED( validateSTGM(grfMode) ))
303 return STG_E_INVALIDFLAG;
306 * As documented.
308 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
309 (grfMode & STGM_DELETEONRELEASE) ||
310 (grfMode & STGM_TRANSACTED) )
311 return STG_E_INVALIDFUNCTION;
314 * Create a property enumeration to search the properties
316 propertyEnumeration = IEnumSTATSTGImpl_Construct(
317 This->ancestorStorage,
318 This->rootPropertySetIndex);
321 * Search the enumeration for the property with the given name
323 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
324 propertyEnumeration,
325 pwcsName,
326 &currentProperty);
329 * Delete the property enumeration since we don't need it anymore
331 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
334 * If it was found, construct the stream object and return a pointer to it.
336 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
337 (currentProperty.propertyType==PROPTYPE_STREAM) )
339 newStream = StgStreamImpl_Construct(This, foundPropertyIndex);
341 if (newStream!=0)
344 * Since we are returning a pointer to the interface, we have to
345 * nail down the reference.
347 StgStreamImpl_AddRef(newStream);
349 *ppstm = (IStream32*)newStream;
351 return S_OK;
354 return E_OUTOFMEMORY;
357 return STG_E_FILENOTFOUND;
360 /************************************************************************
361 * Storage32BaseImpl_OpenStorage (IStorage)
363 * This method will open a new storage object from the current storage.
365 * See Windows documentation for more details on IStorage methods.
367 HRESULT WINAPI Storage32BaseImpl_OpenStorage(
368 Storage32BaseImpl* This,
369 const OLECHAR32* pwcsName, /* [string][unique][in] */
370 IStorage32* pstgPriority, /* [unique][in] */
371 DWORD grfMode, /* [in] */
372 SNB32 snbExclude, /* [unique][in] */
373 DWORD reserved, /* [in] */
374 IStorage32** ppstg) /* [out] */
376 Storage32InternalImpl* newStorage;
377 IEnumSTATSTGImpl* propertyEnumeration;
378 StgProperty currentProperty;
379 ULONG foundPropertyIndex;
382 * Perform a sanity check on the parameters.
384 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
385 return E_INVALIDARG;
388 * Validate the STGM flags
390 if ( FAILED( validateSTGM(grfMode) ))
391 return STG_E_INVALIDFLAG;
394 * As documented.
396 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
397 (grfMode & STGM_DELETEONRELEASE) ||
398 (grfMode & STGM_PRIORITY) )
399 return STG_E_INVALIDFUNCTION;
402 * Initialize the out parameter
404 *ppstg = 0;
407 * Create a property enumeration to search the properties
409 propertyEnumeration = IEnumSTATSTGImpl_Construct(
410 This->ancestorStorage,
411 This->rootPropertySetIndex);
414 * Search the enumeration for the property with the given name
416 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
417 propertyEnumeration,
418 pwcsName,
419 &currentProperty);
422 * Delete the property enumeration since we don't need it anymore
424 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
427 * If it was found, construct the stream object and return a pointer to it.
429 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
430 (currentProperty.propertyType==PROPTYPE_STORAGE) )
433 * Construct a new Storage object
435 newStorage = Storage32InternalImpl_Construct(
436 This->ancestorStorage,
437 foundPropertyIndex);
439 if (newStorage != 0)
442 * Since we are returning a pointer to the interface,
443 * we have to nail down the reference.
445 Storage32BaseImpl_AddRef((Storage32BaseImpl*)newStorage);
447 *ppstg = (IStorage32*)newStorage;
449 return S_OK;
452 return STG_E_INSUFFICIENTMEMORY;
455 return STG_E_FILENOTFOUND;
458 /************************************************************************
459 * Storage32BaseImpl_EnumElements (IStorage)
461 * This method will create an enumerator object that can be used to
462 * retrieve informatino about all the properties in the storage object.
464 * See Windows documentation for more details on IStorage methods.
466 HRESULT WINAPI Storage32BaseImpl_EnumElements(
467 Storage32BaseImpl* This,
468 DWORD reserved1, /* [in] */
469 void* reserved2, /* [size_is][unique][in] */
470 DWORD reserved3, /* [in] */
471 IEnumSTATSTG** ppenum) /* [out] */
473 IEnumSTATSTGImpl* newEnum;
476 * Perform a sanity check on the parameters.
478 if ( (This==0) || (ppenum==0))
479 return E_INVALIDARG;
482 * Construct the enumerator.
484 newEnum = IEnumSTATSTGImpl_Construct(
485 This->ancestorStorage,
486 This->rootPropertySetIndex);
488 if (newEnum!=0)
491 * Don't forget to nail down a reference to the new object before
492 * returning it.
494 IEnumSTATSTGImpl_AddRef(newEnum);
496 *ppenum = (IEnumSTATSTG*)newEnum;
498 return S_OK;
501 return E_OUTOFMEMORY;
504 /************************************************************************
505 * Storage32BaseImpl_Stat (IStorage)
507 * This method will retrieve information about this storage object.
509 * See Windows documentation for more details on IStorage methods.
511 HRESULT WINAPI Storage32BaseImpl_Stat(
512 Storage32BaseImpl* This,
513 STATSTG* pstatstg, /* [out] */
514 DWORD grfStatFlag) /* [in] */
516 StgProperty curProperty;
517 BOOL32 readSucessful;
520 * Perform a sanity check on the parameters.
522 if ( (This==0) || (pstatstg==0))
523 return E_INVALIDARG;
526 * Read the information from the property.
528 readSucessful = Storage32Impl_ReadProperty(
529 This->ancestorStorage,
530 This->rootPropertySetIndex,
531 &curProperty);
533 if (readSucessful)
535 StorageUtl_CopyPropertyToSTATSTG(
536 pstatstg,
537 &curProperty,
538 grfStatFlag);
540 return S_OK;
543 return E_FAIL;
546 /************************************************************************
547 * Storage32BaseImpl_RenameElement (IStorage)
549 * This method will rename the specified element.
551 * See Windows documentation for more details on IStorage methods.
553 * Implementation notes: The method used to rename consists of creating a clone
554 * of the deleted StgProperty object setting it with the new name and to
555 * perform a DestroyElement of the old StgProperty.
557 HRESULT WINAPI Storage32BaseImpl_RenameElement(
558 Storage32BaseImpl* This,
559 const OLECHAR32* pwcsOldName, /* [in] */
560 const OLECHAR32* pwcsNewName) /* [in] */
562 IEnumSTATSTGImpl* propertyEnumeration;
563 StgProperty currentProperty;
564 ULONG foundPropertyIndex;
567 * Create a property enumeration to search the properties
569 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
570 This->rootPropertySetIndex);
573 * Search the enumeration for the new property name
575 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
576 pwcsNewName,
577 &currentProperty);
579 if (foundPropertyIndex != PROPERTY_NULL)
582 * There is already a property with the new name
584 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
585 return STG_E_FILEALREADYEXISTS;
588 IEnumSTATSTGImpl_Reset(propertyEnumeration);
591 * Search the enumeration for the old property name
593 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
594 pwcsOldName,
595 &currentProperty);
598 * Delete the property enumeration since we don't need it anymore
600 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
602 if (foundPropertyIndex != PROPERTY_NULL)
604 StgProperty renamedProperty;
605 ULONG renamedPropertyIndex;
608 * Setup a new property for the renamed property
610 renamedProperty.sizeOfNameString =
611 ( lstrlen32W(pwcsNewName)+1 ) * sizeof(WCHAR);
613 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
614 return STG_E_INVALIDNAME;
616 lstrcpy32W(renamedProperty.name, pwcsNewName);
618 renamedProperty.propertyType = currentProperty.propertyType;
619 renamedProperty.startingBlock = currentProperty.startingBlock;
620 renamedProperty.size.LowPart = currentProperty.size.LowPart;
621 renamedProperty.size.HighPart = currentProperty.size.HighPart;
623 renamedProperty.previousProperty = PROPERTY_NULL;
624 renamedProperty.nextProperty = PROPERTY_NULL;
627 * Bring the dirProperty link in case it is a storage and in which
628 * case the renamed storage elements don't require to be reorganized.
630 renamedProperty.dirProperty = currentProperty.dirProperty;
632 /* call CoFileTime to get the current time
633 renamedProperty.timeStampS1
634 renamedProperty.timeStampD1
635 renamedProperty.timeStampS2
636 renamedProperty.timeStampD2
637 renamedProperty.propertyUniqueID
641 * Obtain a free property in the property chain
643 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
646 * Save the new property into the new property spot
648 Storage32Impl_WriteProperty(
649 This->ancestorStorage,
650 renamedPropertyIndex,
651 &renamedProperty);
654 * Find a spot in the property chain for our newly created property.
656 updatePropertyChain(
657 (Storage32Impl*)This,
658 renamedPropertyIndex,
659 renamedProperty);
662 * At this point the renamed property has been inserted in the tree,
663 * now, before to Destroy the old property we must zeroed it's dirProperty
664 * otherwise the DestroyProperty below will zap it all and we do not want
665 * this to happen.
666 * Also, we fake that the old property is a storage so the DestroyProperty
667 * will not do a SetSize(0) on the stream data.
669 * This means that we need to tweek the StgProperty if it is a stream or a
670 * non empty storage.
672 currentProperty.dirProperty = PROPERTY_NULL;
673 currentProperty.propertyType = PROPTYPE_STORAGE;
674 Storage32Impl_WriteProperty(
675 This->ancestorStorage,
676 foundPropertyIndex,
677 &currentProperty);
680 * Invoke Destroy to get rid of the ole property and automatically redo
681 * the linking of it's previous and next members...
683 Storage32Impl_DestroyElement(This->ancestorStorage, pwcsOldName);
686 else
689 * There is no property with the old name
691 return STG_E_FILENOTFOUND;
694 return S_OK;
697 /************************************************************************
698 * Storage32BaseImpl_CreateStream (IStorage)
700 * This method will create a stream object within this storage
702 * See Windows documentation for more details on IStorage methods.
704 HRESULT WINAPI Storage32BaseImpl_CreateStream(
705 Storage32BaseImpl* This,
706 const OLECHAR32* pwcsName, /* [string][in] */
707 DWORD grfMode, /* [in] */
708 DWORD reserved1, /* [in] */
709 DWORD reserved2, /* [in] */
710 IStream32** ppstm) /* [out] */
712 IEnumSTATSTGImpl* propertyEnumeration;
713 StgStreamImpl* newStream;
714 StgProperty currentProperty, newStreamProperty;
715 ULONG foundPropertyIndex, newPropertyIndex;
718 * Validate parameters
720 if (ppstm == 0)
721 return STG_E_INVALIDPOINTER;
723 if (pwcsName == 0)
724 return STG_E_INVALIDNAME;
727 * Validate the STGM flags
729 if ( FAILED( validateSTGM(grfMode) ))
730 return STG_E_INVALIDFLAG;
733 * As documented.
735 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
736 (grfMode & STGM_DELETEONRELEASE) ||
737 (grfMode & STGM_TRANSACTED) )
738 return STG_E_INVALIDFUNCTION;
741 * Initialize the out parameter
743 *ppstm = 0;
746 * Create a property enumeration to search the properties
748 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
749 This->rootPropertySetIndex);
751 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
752 pwcsName,
753 &currentProperty);
755 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
757 if (foundPropertyIndex != PROPERTY_NULL)
760 * An element with this name already exists
762 if (grfMode & STGM_CREATE)
763 Storage32Impl_DestroyElement(This->ancestorStorage, pwcsName);
764 else
765 return STG_E_FILEALREADYEXISTS;
769 * memset the empty property
771 memset(&newStreamProperty, 0, sizeof(StgProperty));
773 newStreamProperty.sizeOfNameString =
774 ( lstrlen32W(pwcsName)+1 ) * sizeof(WCHAR);
776 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
777 return STG_E_INVALIDNAME;
779 lstrcpy32W(newStreamProperty.name, pwcsName);
781 newStreamProperty.propertyType = PROPTYPE_STREAM;
782 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
783 newStreamProperty.size.LowPart = 0;
784 newStreamProperty.size.HighPart = 0;
786 newStreamProperty.previousProperty = PROPERTY_NULL;
787 newStreamProperty.nextProperty = PROPERTY_NULL;
788 newStreamProperty.dirProperty = PROPERTY_NULL;
790 /* call CoFileTime to get the current time
791 newStreamProperty.timeStampS1
792 newStreamProperty.timeStampD1
793 newStreamProperty.timeStampS2
794 newStreamProperty.timeStampD2
797 /* newStreamProperty.propertyUniqueID */
800 * Get a free property or create a new one
802 newPropertyIndex = getFreeProperty(This->ancestorStorage);
805 * Save the new property into the new property spot
807 Storage32Impl_WriteProperty(
808 This->ancestorStorage,
809 newPropertyIndex,
810 &newStreamProperty);
813 * Find a spot in the property chain for our newly created property.
815 updatePropertyChain(
816 (Storage32Impl*)This,
817 newPropertyIndex,
818 newStreamProperty);
821 * Open the stream to return it.
823 newStream = StgStreamImpl_Construct(This, newPropertyIndex);
825 if (newStream != 0)
828 * Since we are returning a pointer to the interface, we have to nail down
829 * the reference.
831 StgStreamImpl_AddRef(newStream);
833 *ppstm = (IStream32*)newStream;
835 else
837 return STG_E_INSUFFICIENTMEMORY;
840 return S_OK;
843 /************************************************************************
844 * Storage32BaseImpl_SetClass (IStorage)
846 * This method will write the specified CLSID in the property of this
847 * storage.
849 * See Windows documentation for more details on IStorage methods.
851 HRESULT WINAPI Storage32BaseImpl_SetClass(
852 Storage32BaseImpl* This,
853 REFCLSID clsid) /* [in] */
855 HRESULT hRes = E_FAIL;
856 StgProperty curProperty;
857 BOOL32 success;
859 success = Storage32Impl_ReadProperty(This->ancestorStorage,
860 This->rootPropertySetIndex,
861 &curProperty);
862 if (success)
864 curProperty.propertyUniqueID = *clsid;
866 success = Storage32Impl_WriteProperty(This->ancestorStorage,
867 This->rootPropertySetIndex,
868 &curProperty);
869 if (success)
870 hRes = S_OK;
873 return hRes;
876 /************************************************************************
877 ** Storage32Impl implementation
880 /************************************************************************
881 * Storage32Impl_CreateStorage
883 * This method will create the storage object within the provided storage.
885 * See Windows documentation for more details on IStorage methods.
887 HRESULT WINAPI Storage32Impl_CreateStorage(
888 Storage32Impl *This,
889 const OLECHAR32 *pwcsName, /* [string][in] */
890 DWORD grfMode, /* [in] */
891 DWORD reserved1, /* [in] */
892 DWORD reserved2, /* [in] */
893 IStorage32 **ppstg) /* [out] */
895 IEnumSTATSTGImpl *propertyEnumeration;
896 StgProperty currentProperty;
897 StgProperty newProperty;
898 ULONG foundPropertyIndex;
899 ULONG newPropertyIndex;
900 HRESULT hr;
903 * Validate parameters
905 if (ppstg == 0)
906 return STG_E_INVALIDPOINTER;
908 if (pwcsName == 0)
909 return STG_E_INVALIDNAME;
912 * Validate the STGM flags
914 if ( FAILED( validateSTGM(grfMode) ) ||
915 (grfMode & STGM_DELETEONRELEASE) )
916 return STG_E_INVALIDFLAG;
919 * Initialize the out parameter
921 *ppstg = 0;
924 * Create a property enumeration and search the properties
926 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
927 This->rootPropertySetIndex);
929 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
930 pwcsName,
931 &currentProperty);
932 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
934 if (foundPropertyIndex != PROPERTY_NULL)
937 * An element with this name already exists
939 if (grfMode & STGM_CREATE)
940 Storage32Impl_DestroyElement(This->ancestorStorage, pwcsName);
941 else
942 return STG_E_FILEALREADYEXISTS;
946 * memset the empty property
948 memset(&newProperty, 0, sizeof(StgProperty));
950 newProperty.sizeOfNameString = (lstrlen32W(pwcsName)+1)*sizeof(WCHAR);
952 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
953 return STG_E_INVALIDNAME;
955 lstrcpy32W(newProperty.name, pwcsName);
957 newProperty.propertyType = PROPTYPE_STORAGE;
958 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
959 newProperty.size.LowPart = 0;
960 newProperty.size.HighPart = 0;
962 newProperty.previousProperty = PROPERTY_NULL;
963 newProperty.nextProperty = PROPERTY_NULL;
964 newProperty.dirProperty = PROPERTY_NULL;
966 /* call CoFileTime to get the current time
967 newProperty.timeStampS1
968 newProperty.timeStampD1
969 newProperty.timeStampS2
970 newProperty.timeStampD2
973 /* newStorageProperty.propertyUniqueID */
976 * Obtain a free property in the property chain
978 newPropertyIndex = getFreeProperty(This->ancestorStorage);
981 * Save the new property into the new property spot
983 Storage32Impl_WriteProperty(
984 This->ancestorStorage,
985 newPropertyIndex,
986 &newProperty);
989 * Find a spot in the property chain for our newly created property.
991 updatePropertyChain(
992 This,
993 newPropertyIndex,
994 newProperty);
997 * Open it to get a pointer to return.
999 hr = Storage32BaseImpl_OpenStorage(
1000 (Storage32BaseImpl*)This,
1001 (OLECHAR32*)pwcsName,
1003 grfMode,
1006 ppstg);
1008 if( (hr != S_OK) || (*ppstg == NULL))
1010 return hr;
1013 return S_OK;
1017 /***************************************************************************
1019 * Internal Method
1021 * Get a free property or create a new one.
1023 static ULONG getFreeProperty(
1024 Storage32Impl *storage)
1026 ULONG currentPropertyIndex = 0;
1027 ULONG newPropertyIndex = PROPERTY_NULL;
1028 BOOL32 readSucessful = TRUE;
1029 StgProperty currentProperty;
1034 * Start by reading the root property
1036 readSucessful = Storage32Impl_ReadProperty(storage->ancestorStorage,
1037 currentPropertyIndex,
1038 &currentProperty);
1039 if (readSucessful)
1041 if (currentProperty.sizeOfNameString == 0)
1044 * The property existis and is available, we found it.
1046 newPropertyIndex = currentPropertyIndex;
1049 else
1052 * We exhausted the property list, we will create more space below
1054 newPropertyIndex = currentPropertyIndex;
1056 currentPropertyIndex++;
1058 } while (newPropertyIndex == PROPERTY_NULL);
1061 * grow the property chain
1063 if (! readSucessful)
1065 StgProperty emptyProperty;
1066 ULARGE_INTEGER newSize;
1067 ULONG propertyIndex;
1068 ULONG lastProperty = 0;
1069 ULONG blockCount = 0;
1072 * obtain the new count of property blocks
1074 blockCount = BlockChainStream_GetCount(
1075 storage->ancestorStorage->rootBlockChain)+1;
1078 * initialize the size used by the property stream
1080 newSize.HighPart = 0;
1081 newSize.LowPart = storage->bigBlockSize * blockCount;
1084 * add a property block to the property chain
1086 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1089 * memset the empty property in order to initialize the unused newly
1090 * created property
1092 memset(&emptyProperty, 0, sizeof(StgProperty));
1095 * initialize them
1097 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1099 for(
1100 propertyIndex = newPropertyIndex;
1101 propertyIndex < lastProperty;
1102 propertyIndex++)
1104 Storage32Impl_WriteProperty(
1105 storage->ancestorStorage,
1106 propertyIndex,
1107 &emptyProperty);
1111 return newPropertyIndex;
1114 /****************************************************************************
1116 * Internal Method
1118 * Case insensitive comparaison of StgProperty.name by first considering
1119 * their size.
1121 * Returns <0 when newPrpoerty < currentProperty
1122 * >0 when newPrpoerty > currentProperty
1123 * 0 when newPrpoerty == currentProperty
1125 static LONG propertyNameCmp(
1126 OLECHAR32 *newProperty,
1127 OLECHAR32 *currentProperty)
1129 LONG sizeOfNew = (lstrlen32W(newProperty) +1) * sizeof(WCHAR);
1130 LONG sizeOfCur = (lstrlen32W(currentProperty)+1) * sizeof(WCHAR);
1131 LONG diff = sizeOfNew - sizeOfCur;
1133 if (diff == 0)
1136 * We compare the string themselves only when they are of the same lenght
1138 WCHAR wsnew[PROPERTY_NAME_MAX_LEN];
1139 WCHAR wscur[PROPERTY_NAME_MAX_LEN];
1141 diff = lstrcmp32W( (LPCWSTR)CRTDLL__wcsupr(
1142 lstrcpyn32W(wsnew, newProperty, sizeOfNew)),
1143 (LPCWSTR)CRTDLL__wcsupr(
1144 lstrcpyn32W(wscur, currentProperty, sizeOfCur)));
1147 return diff;
1150 /****************************************************************************
1152 * Internal Method
1154 * Properly link this new element in the property chain.
1156 static void updatePropertyChain(
1157 Storage32Impl *storage,
1158 ULONG newPropertyIndex,
1159 StgProperty newProperty)
1161 StgProperty currentProperty;
1164 * Read the root property
1166 Storage32Impl_ReadProperty(storage->ancestorStorage,
1167 storage->rootPropertySetIndex,
1168 &currentProperty);
1170 if (currentProperty.dirProperty != PROPERTY_NULL)
1173 * The root storage contains some element, therefore, start the research
1174 * for the appropriate location.
1176 BOOL32 found = 0;
1177 ULONG current, next, previous, currentPropertyId;
1180 * Keep the StgProperty sequence number of the storage first property
1182 currentPropertyId = currentProperty.dirProperty;
1185 * Read
1187 Storage32Impl_ReadProperty(storage->ancestorStorage,
1188 currentProperty.dirProperty,
1189 &currentProperty);
1191 previous = currentProperty.previousProperty;
1192 next = currentProperty.nextProperty;
1193 current = currentPropertyId;
1195 while (found == 0)
1197 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1199 if (diff < 0)
1201 if (previous != PROPERTY_NULL)
1203 Storage32Impl_ReadProperty(storage->ancestorStorage,
1204 previous,
1205 &currentProperty);
1206 current = previous;
1208 else
1210 currentProperty.previousProperty = newPropertyIndex;
1211 Storage32Impl_WriteProperty(storage->ancestorStorage,
1212 current,
1213 &currentProperty);
1214 found = 1;
1217 else
1219 if (next != PROPERTY_NULL)
1221 Storage32Impl_ReadProperty(storage->ancestorStorage,
1222 next,
1223 &currentProperty);
1224 current = next;
1226 else
1228 currentProperty.nextProperty = newPropertyIndex;
1229 Storage32Impl_WriteProperty(storage->ancestorStorage,
1230 current,
1231 &currentProperty);
1232 found = 1;
1236 previous = currentProperty.previousProperty;
1237 next = currentProperty.nextProperty;
1240 else
1243 * The root storage is empty, link the new property to it's dir property
1245 currentProperty.dirProperty = newPropertyIndex;
1246 Storage32Impl_WriteProperty(storage->ancestorStorage,
1247 storage->rootPropertySetIndex,
1248 &currentProperty);
1253 HRESULT WINAPI Storage32Impl_CopyTo(
1254 Storage32Impl *This,
1255 DWORD ciidExclude, /* [in] */
1256 const IID *rgiidExclude,/* [size_is][unique][in] */
1257 SNB32 snbExclude, /* [unique][in] */
1258 IStorage32 *pstgDest) /* [unique][in] */
1260 return E_NOTIMPL;
1263 HRESULT WINAPI Storage32Impl_MoveElementTo(
1264 Storage32Impl *This,
1265 const OLECHAR32 *pwcsName, /* [string][in] */
1266 IStorage32 *pstgDest, /* [unique][in] */
1267 const OLECHAR32 *pwcsNewName,/* [string][in] */
1268 DWORD grfFlags) /* [in] */
1270 return E_NOTIMPL;
1273 HRESULT WINAPI Storage32Impl_Commit(
1274 Storage32Impl *This,
1275 DWORD grfCommitFlags)/* [in] */
1277 FIXME(ole, "(%ld): stub!\n", grfCommitFlags);
1278 return S_OK;
1281 HRESULT WINAPI Storage32Impl_Revert(
1282 Storage32Impl* This)
1284 return E_NOTIMPL;
1287 /*************************************************************************
1288 * DestroyElement.
1290 * Stategy: This implementation is build this way for simplicity not for speed.
1291 * I allways delete the top most element of the enumeration and adjust
1292 * the deleted element pointer all the time. This takes longer to
1293 * do but allow to reinvoke DestroyElement whenever we encounter a
1294 * storage object. The optimisation reside in the usage of another
1295 * enumeration stategy that would give all the leaves of a storage
1296 * first. (postfix order)
1298 HRESULT WINAPI Storage32Impl_DestroyElement(
1299 Storage32Impl *This,
1300 const OLECHAR32 *pwcsName)/* [string][in] */
1302 IEnumSTATSTGImpl* propertyEnumeration;
1303 HRESULT hr = S_OK;
1304 BOOL32 res;
1305 StgProperty propertyToDelete;
1306 StgProperty parentProperty;
1307 ULONG foundPropertyIndexToDelete;
1308 ULONG typeOfRelation;
1309 ULONG parentPropertyId;
1312 * Perform a sanity check on the parameters.
1314 if (pwcsName==NULL)
1315 return STG_E_INVALIDPOINTER;
1318 * Create a property enumeration to search the property with the given name
1320 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1321 This->ancestorStorage,
1322 This->rootPropertySetIndex);
1324 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1325 propertyEnumeration,
1326 pwcsName,
1327 &propertyToDelete);
1329 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1331 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1333 return STG_E_FILENOTFOUND;
1337 * Find the parent property of the property to delete (the one that
1338 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1339 * the parent is This. Otherwise, the parent is one of it's sibling...
1343 * First, read This's StgProperty..
1345 res = Storage32Impl_ReadProperty(
1346 This->ancestorStorage,
1347 This->rootPropertySetIndex,
1348 &parentProperty);
1350 assert(res==TRUE);
1353 * Second, check to see if by any chance the actual storage (This) is not
1354 * the parent of the property to delete... We never know...
1356 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1359 * Set data as it would have been done in the else part...
1361 typeOfRelation = PROPERTY_RELATION_DIR;
1362 parentPropertyId = This->rootPropertySetIndex;
1364 else
1367 * Create a property enumeration to search the parent properties, and
1368 * delete it once done.
1370 IEnumSTATSTGImpl* propertyEnumeration2;
1372 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1373 This->ancestorStorage,
1374 This->rootPropertySetIndex);
1376 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1377 propertyEnumeration2,
1378 foundPropertyIndexToDelete,
1379 &parentProperty,
1380 &parentPropertyId);
1382 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1385 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1387 hr = deleteStorageProperty(
1388 This,
1389 propertyToDelete.name);
1391 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1393 hr = deleteStreamProperty(
1394 This,
1395 foundPropertyIndexToDelete,
1396 propertyToDelete);
1399 if (hr!=S_OK)
1400 return hr;
1403 * Adjust the property chain
1405 hr = adjustPropertyChain(
1406 This,
1407 propertyToDelete,
1408 parentProperty,
1409 parentPropertyId,
1410 typeOfRelation);
1412 return hr;
1416 /*********************************************************************
1418 * Internal Method
1420 * Perform the deletion of a complete storage node
1423 static HRESULT deleteStorageProperty(
1424 Storage32Impl *parentStorage,
1425 OLECHAR32 *propertyToDeleteName)
1427 IEnumSTATSTG *elements = 0;
1428 IStorage32 *childStorage = 0;
1429 STATSTG currentElement;
1430 HRESULT hr;
1431 HRESULT destroyHr = S_OK;
1434 * Open the storage and enumerate it
1436 hr = Storage32BaseImpl_OpenStorage(
1437 (Storage32BaseImpl*)parentStorage,
1438 propertyToDeleteName,
1440 STGM_SHARE_EXCLUSIVE,
1443 &childStorage);
1445 if (hr != S_OK)
1447 return hr;
1451 * Enumerate the elements
1453 IStorage32_EnumElements( childStorage, 0, 0, 0, &elements);
1458 * Obtain the next element
1460 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1461 if (hr==S_OK)
1463 destroyHr = Storage32Impl_DestroyElement(
1464 (Storage32Impl*)childStorage,
1465 (OLECHAR32*)currentElement.pwcsName);
1467 CoTaskMemFree(currentElement.pwcsName);
1471 * We need to Reset the enumeration every time because we delete elements
1472 * and the enumeration could be invalid
1474 IEnumSTATSTG_Reset(elements);
1476 } while ((hr == S_OK) && (destroyHr == S_OK));
1478 IStorage32_Release(childStorage);
1479 IEnumSTATSTG_Release(elements);
1481 return destroyHr;
1484 /*********************************************************************
1486 * Internal Method
1488 * Perform the deletion of a stream node
1491 static HRESULT deleteStreamProperty(
1492 Storage32Impl *parentStorage,
1493 ULONG indexOfPropertyToDelete,
1494 StgProperty propertyToDelete)
1496 IStream32 *pis;
1497 HRESULT hr;
1498 ULARGE_INTEGER size;
1500 size.HighPart = 0;
1501 size.LowPart = 0;
1503 hr = Storage32BaseImpl_OpenStream(
1504 (Storage32BaseImpl*)parentStorage,
1505 (OLECHAR32*)propertyToDelete.name,
1506 NULL,
1507 STGM_SHARE_EXCLUSIVE,
1509 &pis);
1511 if (hr!=S_OK)
1513 return(hr);
1517 * Zap the stream
1519 hr = IStream32_SetSize(pis, size);
1521 if(hr != S_OK)
1523 return hr;
1527 * Invalidate the property by zeroing it's name member.
1529 propertyToDelete.sizeOfNameString = 0;
1532 * Here we should re-read the property so we get the updated pointer
1533 * but since we are here to zap it, I don't do it...
1536 Storage32Impl_WriteProperty(
1537 parentStorage->ancestorStorage,
1538 indexOfPropertyToDelete,
1539 &propertyToDelete);
1541 return S_OK;
1544 /*********************************************************************
1546 * Internal Method
1548 * Finds a placeholder for the StgProperty within the Storage
1551 static HRESULT findPlaceholder(
1552 Storage32Impl *storage,
1553 ULONG propertyIndexToStore,
1554 ULONG storePropertyIndex,
1555 INT32 typeOfRelation)
1557 StgProperty storeProperty;
1558 HRESULT hr = S_OK;
1559 BOOL32 res = TRUE;
1562 * Read the storage property
1564 res = Storage32Impl_ReadProperty(
1565 storage->ancestorStorage,
1566 storePropertyIndex,
1567 &storeProperty);
1569 if(! res)
1571 return E_FAIL;
1574 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1576 if (storeProperty.previousProperty != PROPERTY_NULL)
1578 return findPlaceholder(
1579 storage,
1580 propertyIndexToStore,
1581 storeProperty.previousProperty,
1582 typeOfRelation);
1584 else
1586 storeProperty.previousProperty = propertyIndexToStore;
1589 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1591 if (storeProperty.nextProperty != PROPERTY_NULL)
1593 return findPlaceholder(
1594 storage,
1595 propertyIndexToStore,
1596 storeProperty.nextProperty,
1597 typeOfRelation);
1599 else
1601 storeProperty.nextProperty = propertyIndexToStore;
1604 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1606 if (storeProperty.dirProperty != PROPERTY_NULL)
1608 return findPlaceholder(
1609 storage,
1610 propertyIndexToStore,
1611 storeProperty.dirProperty,
1612 typeOfRelation);
1614 else
1616 storeProperty.dirProperty = propertyIndexToStore;
1620 hr = Storage32Impl_WriteProperty(
1621 storage->ancestorStorage,
1622 storePropertyIndex,
1623 &storeProperty);
1625 if(! hr)
1627 return E_FAIL;
1630 return S_OK;
1633 /*************************************************************************
1635 * Internal Method
1637 * This method takes the previous and the next property link of a property
1638 * to be deleted and find them a place in the Storage.
1640 static HRESULT adjustPropertyChain(
1641 Storage32Impl *This,
1642 StgProperty propertyToDelete,
1643 StgProperty parentProperty,
1644 ULONG parentPropertyId,
1645 INT32 typeOfRelation)
1647 ULONG newLinkProperty = PROPERTY_NULL;
1648 BOOL32 needToFindAPlaceholder = FALSE;
1649 ULONG storeNode = PROPERTY_NULL;
1650 ULONG toStoreNode = PROPERTY_NULL;
1651 INT32 relationType = 0;
1652 HRESULT hr = S_OK;
1653 BOOL32 res = TRUE;
1655 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1657 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1660 * Set the parent previous to the property to delete previous
1662 newLinkProperty = propertyToDelete.previousProperty;
1664 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1667 * We also need to find a storage for the other link, setup variables
1668 * to do this at the end...
1670 needToFindAPlaceholder = TRUE;
1671 storeNode = propertyToDelete.previousProperty;
1672 toStoreNode = propertyToDelete.nextProperty;
1673 relationType = PROPERTY_RELATION_NEXT;
1676 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1679 * Set the parent previous to the property to delete next
1681 newLinkProperty = propertyToDelete.nextProperty;
1685 * Link it for real...
1687 parentProperty.previousProperty = newLinkProperty;
1690 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1692 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1695 * Set the parent next to the property to delete next previous
1697 newLinkProperty = propertyToDelete.previousProperty;
1699 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1702 * We also need to find a storage for the other link, setup variables
1703 * to do this at the end...
1705 needToFindAPlaceholder = TRUE;
1706 storeNode = propertyToDelete.previousProperty;
1707 toStoreNode = propertyToDelete.nextProperty;
1708 relationType = PROPERTY_RELATION_NEXT;
1711 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1714 * Set the parent next to the property to delete next
1716 newLinkProperty = propertyToDelete.nextProperty;
1720 * Link it for real...
1722 parentProperty.nextProperty = newLinkProperty;
1724 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
1726 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1729 * Set the parent dir to the property to delete previous
1731 newLinkProperty = propertyToDelete.previousProperty;
1733 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1736 * We also need to find a storage for the other link, setup variables
1737 * to do this at the end...
1739 needToFindAPlaceholder = TRUE;
1740 storeNode = propertyToDelete.previousProperty;
1741 toStoreNode = propertyToDelete.nextProperty;
1742 relationType = PROPERTY_RELATION_NEXT;
1745 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1748 * Set the parent dir to the property to delete next
1750 newLinkProperty = propertyToDelete.nextProperty;
1754 * Link it for real...
1756 parentProperty.dirProperty = newLinkProperty;
1760 * Write back the parent property
1762 res = Storage32Impl_WriteProperty(
1763 This->ancestorStorage,
1764 parentPropertyId,
1765 &parentProperty);
1766 if(! res)
1768 return E_FAIL;
1772 * If a placeholder is required for the other link, then, find one and
1773 * get out of here...
1775 if (needToFindAPlaceholder)
1777 hr = findPlaceholder(
1778 This,
1779 toStoreNode,
1780 storeNode,
1781 relationType);
1784 return hr;
1788 HRESULT WINAPI Storage32Impl_SetElementTimes(
1789 Storage32Impl *This,
1790 const OLECHAR32 *pwcsName,/* [string][in] */
1791 const FILETIME *pctime, /* [in] */
1792 const FILETIME *patime, /* [in] */
1793 const FILETIME *pmtime) /* [in] */
1795 return E_NOTIMPL;
1798 HRESULT WINAPI Storage32Impl_SetStateBits(
1799 Storage32Impl *This,
1800 DWORD grfStateBits,/* [in] */
1801 DWORD grfMask) /* [in] */
1803 return E_NOTIMPL;
1806 HRESULT Storage32Impl_Construct(
1807 Storage32Impl* This,
1808 HANDLE32 hFile,
1809 DWORD openFlags)
1811 HRESULT hr = S_OK;
1812 StgProperty currentProperty;
1813 BOOL32 readSucessful;
1814 ULONG currentPropertyIndex;
1816 if ( FAILED( validateSTGM(openFlags) ))
1817 return STG_E_INVALIDFLAG;
1819 memset(This, 0, sizeof(Storage32Impl));
1822 * Initialize the virtual fgunction table.
1824 This->lpvtbl = &Storage32Impl_VTable;
1825 This->v_destructor = &Storage32Impl_Destroy;
1828 * This is the top-level storage so initialize the ancester pointer
1829 * to this.
1831 This->ancestorStorage = This;
1834 * Initialize the physical support of the storage.
1836 This->hFile = hFile;
1839 * Initialize the big block cache.
1841 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
1842 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
1843 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile, This->bigBlockSize);
1845 if (openFlags & STGM_CREATE)
1847 ULARGE_INTEGER size;
1848 BYTE* bigBlockBuffer;
1851 * Initialize all header variables:
1852 * - The big block depot consists of one block and it is at block 0
1853 * - The properties start at block 1
1854 * - There is no small block depot
1856 memset( This->bigBlockDepotStart,
1857 BLOCK_UNUSED,
1858 sizeof(This->bigBlockDepotStart));
1860 This->bigBlockDepotCount = 1;
1861 This->bigBlockDepotStart[0] = 0;
1862 This->rootStartBlock = 1;
1863 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
1864 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
1865 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
1866 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
1867 This->extBigBlockDepotCount = 0;
1869 Storage32Impl_SaveFileHeader(This);
1872 * Add one block for the big block depot and one block for the properties
1874 size.HighPart = 0;
1875 size.LowPart = This->bigBlockSize * 3;
1876 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
1879 * Initialize the big block depot
1881 bigBlockBuffer = Storage32Impl_GetBigBlock(This, 0);
1882 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
1883 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
1884 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
1885 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
1887 else
1890 * Load the header for the file.
1892 Storage32Impl_LoadFileHeader(This);
1896 * Create the block chain abstractions.
1898 This->rootBlockChain =
1899 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
1901 This->smallBlockDepotChain = BlockChainStream_Construct(
1902 This,
1903 &This->smallBlockDepotStart,
1904 PROPERTY_NULL);
1907 * Write the root property
1909 if (openFlags & STGM_CREATE)
1911 StgProperty rootProp;
1913 * Initialize the property chain
1915 memset(&rootProp, 0, sizeof(rootProp));
1916 lstrcpyAtoW(rootProp.name, rootPropertyName);
1918 rootProp.sizeOfNameString = (lstrlen32W(rootProp.name)+1) * sizeof(WCHAR);
1919 rootProp.propertyType = PROPTYPE_ROOT;
1920 rootProp.previousProperty = PROPERTY_NULL;
1921 rootProp.nextProperty = PROPERTY_NULL;
1922 rootProp.dirProperty = PROPERTY_NULL;
1923 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
1924 rootProp.size.HighPart = 0;
1925 rootProp.size.LowPart = 0;
1927 Storage32Impl_WriteProperty(This, 0, &rootProp);
1931 * Find the ID of the root int he property sets.
1933 currentPropertyIndex = 0;
1937 readSucessful = Storage32Impl_ReadProperty(
1938 This,
1939 currentPropertyIndex,
1940 &currentProperty);
1942 if (readSucessful)
1944 if ( (currentProperty.sizeOfNameString != 0 ) &&
1945 (currentProperty.propertyType == PROPTYPE_ROOT) )
1947 This->rootPropertySetIndex = currentPropertyIndex;
1951 currentPropertyIndex++;
1953 } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
1955 if (!readSucessful)
1957 /* TODO CLEANUP */
1958 return E_FAIL;
1962 * Create the block chain abstraction for the small block root chain.
1964 This->smallBlockRootChain = BlockChainStream_Construct(
1965 This,
1966 NULL,
1967 This->rootPropertySetIndex);
1969 return hr;
1972 void Storage32Impl_Destroy(
1973 Storage32Impl* This)
1975 BlockChainStream_Destroy(This->smallBlockRootChain);
1976 BlockChainStream_Destroy(This->rootBlockChain);
1977 BlockChainStream_Destroy(This->smallBlockDepotChain);
1979 BIGBLOCKFILE_Destructor(This->bigBlockFile);
1980 return;
1983 /******************************************************************************
1984 * Storage32Impl_GetNextFreeBigBlock
1986 * Returns the index of the next free big block.
1987 * If the big block depot is filled, this method will enlarge it.
1989 * TODO: Handle the case when the big block depot becomes bigger
1990 * than COUNT_BBDEPOTINHEADER.
1992 ULONG Storage32Impl_GetNextFreeBigBlock(
1993 Storage32Impl* This)
1995 ULONG depotBlockIndexPos;
1996 void *depotBuffer;
1997 ULONG depotBlockOffset;
1998 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
1999 ULONG nextBlockIndex = BLOCK_SPECIAL;
2000 int depotIndex = 0;
2001 ULONG blockNoInSequence = 0;
2004 * Scan the entire big block depot until we find a block marked free
2006 while ( (depotIndex < COUNT_BBDEPOTINHEADER) &&
2007 (nextBlockIndex != BLOCK_UNUSED))
2009 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2011 if (depotBlockIndexPos == BLOCK_UNUSED)
2014 * No more space in the big block depot, we have to enlarge it
2016 depotBlockIndexPos = depotIndex*blocksPerDepot;
2017 depotBuffer = Storage32Impl_GetBigBlock(This, depotBlockIndexPos);
2019 depotBlockOffset = 0;
2021 /* mark this block as being part of the big block depot
2023 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, BLOCK_SPECIAL);
2024 depotBlockOffset += sizeof(ULONG);
2026 /* initialize blocks as free
2028 while ((depotBlockOffset < blocksPerDepot))
2030 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, BLOCK_UNUSED);
2031 depotBlockOffset += sizeof(ULONG);
2034 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2036 /* Save the information to the file header
2038 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2039 This->bigBlockDepotCount++;
2040 Storage32Impl_SaveFileHeader(This);
2043 depotBuffer = Storage32Impl_GetROBigBlock(This, depotBlockIndexPos);
2045 if (depotBuffer != 0)
2047 depotBlockOffset = 0;
2049 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2050 ( nextBlockIndex != BLOCK_UNUSED))
2052 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2054 if (nextBlockIndex != BLOCK_UNUSED)
2055 blockNoInSequence++;
2057 depotBlockOffset += sizeof(ULONG);
2060 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2063 depotIndex++;
2066 return blockNoInSequence;
2069 /******************************************************************************
2070 * Storage32Impl_FreeBigBlock
2072 * This method will flag the specified block as free in the big block depot.
2074 void Storage32Impl_FreeBigBlock(
2075 Storage32Impl* This,
2076 ULONG blockIndex)
2078 Storage32Impl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2081 /************************************************************************
2082 * Storage32Impl_GetNextBlockInChain
2084 * This method will retrieve the block index of the next big block in
2085 * in the chain.
2087 * Params: This - Pointer to the Storage object.
2088 * blockIndex - Index of the block to retrieve the chain
2089 * for.
2091 * Returns: This method returns the index of the next block in the chain.
2092 * It will return the constants:
2093 * BLOCK_SPECIAL - If the block given was not part of a
2094 * chain.
2095 * BLOCK_END_OF_CHAIN - If the block given was the last in
2096 * a chain.
2097 * BLOCK_UNUSED - If the block given was not past of a chain
2098 * and is available.
2100 * See Windows documentation for more details on IStorage methods.
2102 ULONG Storage32Impl_GetNextBlockInChain(
2103 Storage32Impl* This,
2104 ULONG blockIndex)
2106 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2107 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2108 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2109 ULONG nextBlockIndex = BLOCK_SPECIAL;
2110 void* depotBuffer;
2111 ULONG depotBlockIndexPos;
2113 assert(depotBlockCount < This->bigBlockDepotCount);
2114 assert(depotBlockCount < COUNT_BBDEPOTINHEADER);
2116 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2118 depotBuffer = Storage32Impl_GetROBigBlock(This, depotBlockIndexPos);
2120 if (depotBuffer!=0)
2122 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2124 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2127 return nextBlockIndex;
2130 /******************************************************************************
2131 * Storage32Impl_SetNextBlockInChain
2133 * This method will write the index of the specified block's next block
2134 * in the big block depot.
2136 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2137 * do the following
2139 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2140 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2141 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2144 void Storage32Impl_SetNextBlockInChain(
2145 Storage32Impl* This,
2146 ULONG blockIndex,
2147 ULONG nextBlock)
2149 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2150 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2151 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2152 ULONG depotBlockIndexPos;
2153 void* depotBuffer;
2155 assert(depotBlockCount < This->bigBlockDepotCount);
2156 assert(depotBlockCount < COUNT_BBDEPOTINHEADER);
2158 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2160 depotBuffer = Storage32Impl_GetBigBlock(This, depotBlockIndexPos);
2162 if (depotBuffer!=0)
2164 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2165 Storage32Impl_ReleaseBigBlock(This, depotBuffer);
2168 return;
2171 /******************************************************************************
2172 * Storage32Impl_LoadFileHeader
2174 * This method will read in the file header, i.e. big block index -1.
2176 HRESULT Storage32Impl_LoadFileHeader(
2177 Storage32Impl* This)
2179 HRESULT hr = STG_E_FILENOTFOUND;
2180 void* headerBigBlock = NULL;
2181 int index;
2184 * Get a pointer to the big block of data containing the header.
2186 headerBigBlock = Storage32Impl_GetROBigBlock(This, -1);
2189 * Extract the information from the header.
2191 if (headerBigBlock!=0)
2194 * Check for the "magic number" signature and return an error if it is not
2195 * found.
2197 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2199 Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2200 return STG_E_OLDFORMAT;
2203 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2205 Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2206 return STG_E_INVALIDHEADER;
2209 StorageUtl_ReadWord(
2210 headerBigBlock,
2211 OFFSET_BIGBLOCKSIZEBITS,
2212 &This->bigBlockSizeBits);
2214 StorageUtl_ReadWord(
2215 headerBigBlock,
2216 OFFSET_SMALLBLOCKSIZEBITS,
2217 &This->smallBlockSizeBits);
2219 StorageUtl_ReadDWord(
2220 headerBigBlock,
2221 OFFSET_BBDEPOTCOUNT,
2222 &This->bigBlockDepotCount);
2224 StorageUtl_ReadDWord(
2225 headerBigBlock,
2226 OFFSET_ROOTSTARTBLOCK,
2227 &This->rootStartBlock);
2229 StorageUtl_ReadDWord(
2230 headerBigBlock,
2231 OFFSET_SBDEPOTSTART,
2232 &This->smallBlockDepotStart);
2234 StorageUtl_ReadDWord(
2235 headerBigBlock,
2236 OFFSET_EXTBBDEPOTSTART,
2237 &This->extBigBlockDepotStart);
2239 StorageUtl_ReadDWord(
2240 headerBigBlock,
2241 OFFSET_EXTBBDEPOTCOUNT,
2242 &This->extBigBlockDepotCount);
2244 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2246 StorageUtl_ReadDWord(
2247 headerBigBlock,
2248 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2249 &(This->bigBlockDepotStart[index]));
2253 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2255 if ((1 << 2) == 4)
2257 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2258 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2260 else
2262 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2263 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2267 * Right now, the code is making some assumptions about the size of the
2268 * blocks, just make sure they are what we're expecting.
2270 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2271 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2274 * Release the block.
2276 Storage32Impl_ReleaseBigBlock(This, headerBigBlock);
2279 return hr;
2282 /******************************************************************************
2283 * Storage32Impl_SaveFileHeader
2285 * This method will save to the file the header, i.e. big block -1.
2287 void Storage32Impl_SaveFileHeader(
2288 Storage32Impl* This)
2290 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2291 int index;
2292 BOOL32 success;
2295 * Get a pointer to the big block of data containing the header.
2297 success = Storage32Impl_ReadBigBlock(This, -1, headerBigBlock);
2300 * If the block read failed, the file is probably new.
2302 if (!success)
2305 * Initialize for all unknown fields.
2307 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2310 * Initialize the magic number.
2312 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2315 * And a bunch of things we don't know what they mean
2317 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2318 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2319 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2320 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2321 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2325 * Write the information to the header.
2327 if (headerBigBlock!=0)
2329 StorageUtl_WriteWord(
2330 headerBigBlock,
2331 OFFSET_BIGBLOCKSIZEBITS,
2332 This->bigBlockSizeBits);
2334 StorageUtl_WriteWord(
2335 headerBigBlock,
2336 OFFSET_SMALLBLOCKSIZEBITS,
2337 This->smallBlockSizeBits);
2339 StorageUtl_WriteDWord(
2340 headerBigBlock,
2341 OFFSET_BBDEPOTCOUNT,
2342 This->bigBlockDepotCount);
2344 StorageUtl_WriteDWord(
2345 headerBigBlock,
2346 OFFSET_ROOTSTARTBLOCK,
2347 This->rootStartBlock);
2349 StorageUtl_WriteDWord(
2350 headerBigBlock,
2351 OFFSET_SBDEPOTSTART,
2352 This->smallBlockDepotStart);
2354 StorageUtl_WriteDWord(
2355 headerBigBlock,
2356 OFFSET_EXTBBDEPOTSTART,
2357 This->extBigBlockDepotStart);
2359 StorageUtl_WriteDWord(
2360 headerBigBlock,
2361 OFFSET_EXTBBDEPOTCOUNT,
2362 This->extBigBlockDepotCount);
2364 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2366 StorageUtl_WriteDWord(
2367 headerBigBlock,
2368 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2369 (This->bigBlockDepotStart[index]));
2374 * Write the big block back to the file.
2376 Storage32Impl_WriteBigBlock(This, -1, headerBigBlock);
2379 /******************************************************************************
2380 * Storage32Impl_ReadProperty
2382 * This method will read the specified property from the property chain.
2384 BOOL32 Storage32Impl_ReadProperty(
2385 Storage32Impl* This,
2386 ULONG index,
2387 StgProperty* buffer)
2389 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2390 ULARGE_INTEGER offsetInPropSet;
2391 BOOL32 readSucessful;
2392 ULONG bytesRead;
2394 offsetInPropSet.HighPart = 0;
2395 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2397 readSucessful = BlockChainStream_ReadAt(
2398 This->rootBlockChain,
2399 offsetInPropSet,
2400 PROPSET_BLOCK_SIZE,
2401 currentProperty,
2402 &bytesRead);
2404 if (readSucessful)
2406 memset(buffer->name, 0, sizeof(buffer->name));
2407 memcpy(
2408 buffer->name,
2409 currentProperty+OFFSET_PS_NAME,
2410 PROPERTY_NAME_BUFFER_LEN );
2412 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
2414 StorageUtl_ReadWord(
2415 currentProperty,
2416 OFFSET_PS_NAMELENGTH,
2417 &buffer->sizeOfNameString);
2419 StorageUtl_ReadDWord(
2420 currentProperty,
2421 OFFSET_PS_PREVIOUSPROP,
2422 &buffer->previousProperty);
2424 StorageUtl_ReadDWord(
2425 currentProperty,
2426 OFFSET_PS_NEXTPROP,
2427 &buffer->nextProperty);
2429 StorageUtl_ReadDWord(
2430 currentProperty,
2431 OFFSET_PS_DIRPROP,
2432 &buffer->dirProperty);
2434 StorageUtl_ReadGUID(
2435 currentProperty,
2436 OFFSET_PS_GUID,
2437 &buffer->propertyUniqueID);
2439 StorageUtl_ReadDWord(
2440 currentProperty,
2441 OFFSET_PS_TSS1,
2442 &buffer->timeStampS1);
2444 StorageUtl_ReadDWord(
2445 currentProperty,
2446 OFFSET_PS_TSD1,
2447 &buffer->timeStampD1);
2449 StorageUtl_ReadDWord(
2450 currentProperty,
2451 OFFSET_PS_TSS2,
2452 &buffer->timeStampS2);
2454 StorageUtl_ReadDWord(
2455 currentProperty,
2456 OFFSET_PS_TSD2,
2457 &buffer->timeStampD2);
2459 StorageUtl_ReadDWord(
2460 currentProperty,
2461 OFFSET_PS_STARTBLOCK,
2462 &buffer->startingBlock);
2464 StorageUtl_ReadDWord(
2465 currentProperty,
2466 OFFSET_PS_SIZE,
2467 &buffer->size.LowPart);
2469 buffer->size.HighPart = 0;
2472 return readSucessful;
2475 /*********************************************************************
2476 * Write the specified property into the property chain
2478 BOOL32 Storage32Impl_WriteProperty(
2479 Storage32Impl* This,
2480 ULONG index,
2481 StgProperty* buffer)
2483 BYTE currentProperty[PROPSET_BLOCK_SIZE];
2484 ULARGE_INTEGER offsetInPropSet;
2485 BOOL32 writeSucessful;
2486 ULONG bytesWritten;
2488 offsetInPropSet.HighPart = 0;
2489 offsetInPropSet.LowPart = index * PROPSET_BLOCK_SIZE;
2491 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
2493 memcpy(
2494 currentProperty + OFFSET_PS_NAME,
2495 buffer->name,
2496 PROPERTY_NAME_BUFFER_LEN );
2498 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
2501 * Reassign the size in case of mistake....
2503 buffer->sizeOfNameString = (lstrlen32W(buffer->name)+1) * sizeof(WCHAR);
2505 StorageUtl_WriteWord(
2506 currentProperty,
2507 OFFSET_PS_NAMELENGTH,
2508 buffer->sizeOfNameString);
2510 StorageUtl_WriteDWord(
2511 currentProperty,
2512 OFFSET_PS_PREVIOUSPROP,
2513 buffer->previousProperty);
2515 StorageUtl_WriteDWord(
2516 currentProperty,
2517 OFFSET_PS_NEXTPROP,
2518 buffer->nextProperty);
2520 StorageUtl_WriteDWord(
2521 currentProperty,
2522 OFFSET_PS_DIRPROP,
2523 buffer->dirProperty);
2525 StorageUtl_WriteGUID(
2526 currentProperty,
2527 OFFSET_PS_GUID,
2528 &buffer->propertyUniqueID);
2530 StorageUtl_WriteDWord(
2531 currentProperty,
2532 OFFSET_PS_TSS1,
2533 buffer->timeStampS1);
2535 StorageUtl_WriteDWord(
2536 currentProperty,
2537 OFFSET_PS_TSD1,
2538 buffer->timeStampD1);
2540 StorageUtl_WriteDWord(
2541 currentProperty,
2542 OFFSET_PS_TSS2,
2543 buffer->timeStampS2);
2545 StorageUtl_WriteDWord(
2546 currentProperty,
2547 OFFSET_PS_TSD2,
2548 buffer->timeStampD2);
2550 StorageUtl_WriteDWord(
2551 currentProperty,
2552 OFFSET_PS_STARTBLOCK,
2553 buffer->startingBlock);
2555 StorageUtl_WriteDWord(
2556 currentProperty,
2557 OFFSET_PS_SIZE,
2558 buffer->size.LowPart);
2560 writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
2561 offsetInPropSet,
2562 PROPSET_BLOCK_SIZE,
2563 currentProperty,
2564 &bytesWritten);
2565 return writeSucessful;
2568 BOOL32 Storage32Impl_ReadBigBlock(
2569 Storage32Impl* This,
2570 ULONG blockIndex,
2571 void* buffer)
2573 void* bigBlockBuffer;
2575 bigBlockBuffer = Storage32Impl_GetROBigBlock(This, blockIndex);
2577 if (bigBlockBuffer!=0)
2579 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
2581 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2583 return TRUE;
2586 return FALSE;
2589 BOOL32 Storage32Impl_WriteBigBlock(
2590 Storage32Impl* This,
2591 ULONG blockIndex,
2592 void* buffer)
2594 void* bigBlockBuffer;
2596 bigBlockBuffer = Storage32Impl_GetBigBlock(This, blockIndex);
2598 if (bigBlockBuffer!=0)
2600 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
2602 Storage32Impl_ReleaseBigBlock(This, bigBlockBuffer);
2604 return TRUE;
2607 return FALSE;
2610 void* Storage32Impl_GetROBigBlock(
2611 Storage32Impl* This,
2612 ULONG blockIndex)
2614 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
2617 void* Storage32Impl_GetBigBlock(
2618 Storage32Impl* This,
2619 ULONG blockIndex)
2621 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
2624 void Storage32Impl_ReleaseBigBlock(
2625 Storage32Impl* This,
2626 void* pBigBlock)
2628 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
2631 /******************************************************************************
2632 * Storage32Impl_SmallBlocksToBigBlocks
2634 * This method will convert a small block chain to a big block chain.
2635 * The small block chain will be destroyed.
2637 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
2638 Storage32Impl* This,
2639 SmallBlockChainStream** ppsbChain)
2641 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
2642 ULARGE_INTEGER size, offset;
2643 ULONG cbRead, cbWritten;
2644 ULONG propertyIndex;
2645 BOOL32 successRead, successWrite;
2646 StgProperty chainProperty;
2647 BYTE buffer[DEF_SMALL_BLOCK_SIZE];
2648 BlockChainStream *bbTempChain = NULL;
2649 BlockChainStream *bigBlockChain = NULL;
2652 * Create a temporary big block chain that doesn't have
2653 * an associated property. This temporary chain will be
2654 * used to copy data from small blocks to big blocks.
2656 bbTempChain = BlockChainStream_Construct(This,
2657 &bbHeadOfChain,
2658 PROPERTY_NULL);
2661 * Grow the big block chain.
2663 size = SmallBlockChainStream_GetSize(*ppsbChain);
2664 BlockChainStream_SetSize(bbTempChain, size);
2667 * Copy the contents of the small block chain to the big block chain
2668 * by small block size increments.
2670 offset.LowPart = 0;
2671 offset.HighPart = 0;
2675 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
2676 offset,
2677 sizeof(buffer),
2678 buffer,
2679 &cbRead);
2681 successWrite = BlockChainStream_WriteAt(bbTempChain,
2682 offset,
2683 sizeof(buffer),
2684 buffer,
2685 &cbWritten);
2686 offset.LowPart += This->smallBlockSize;
2688 } while (successRead && successWrite);
2690 assert(cbRead == cbWritten);
2693 * Destroy the small block chain.
2695 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
2696 size.HighPart = 0;
2697 size.LowPart = 0;
2698 SmallBlockChainStream_SetSize(*ppsbChain, size);
2699 SmallBlockChainStream_Destroy(*ppsbChain);
2700 *ppsbChain = 0;
2703 * Change the property information. This chain is now a big block chain
2704 * and it doesn't reside in the small blocks chain anymore.
2706 Storage32Impl_ReadProperty(This, propertyIndex, &chainProperty);
2708 chainProperty.startingBlock = bbHeadOfChain;
2710 Storage32Impl_WriteProperty(This, propertyIndex, &chainProperty);
2713 * Destroy the temporary propertyless big block chain.
2714 * Create a new big block chain associated with this property.
2716 BlockChainStream_Destroy(bbTempChain);
2717 bigBlockChain = BlockChainStream_Construct(This,
2718 NULL,
2719 propertyIndex);
2721 return bigBlockChain;
2724 /******************************************************************************
2725 ** Storage32InternalImpl implementation
2728 Storage32InternalImpl* Storage32InternalImpl_Construct(
2729 Storage32Impl* ancestorStorage,
2730 ULONG rootPropertyIndex)
2732 Storage32InternalImpl* newStorage;
2735 * Allocate space for the new storage object
2737 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32InternalImpl));
2739 if (newStorage!=0)
2741 memset(newStorage, 0, sizeof(Storage32InternalImpl));
2744 * Initialize the virtual function table.
2746 newStorage->lpvtbl = &Storage32InternalImpl_VTable;
2747 newStorage->v_destructor = &Storage32InternalImpl_Destroy;
2750 * Keep the ancestor storage pointer and nail a reference to it.
2752 newStorage->ancestorStorage = ancestorStorage;
2753 Storage32BaseImpl_AddRef((Storage32BaseImpl*)(newStorage->ancestorStorage));
2756 * Keep the index of the root property set for this storage,
2758 newStorage->rootPropertySetIndex = rootPropertyIndex;
2760 return newStorage;
2763 return 0;
2766 void Storage32InternalImpl_Destroy(
2767 Storage32InternalImpl* This)
2769 HeapFree(GetProcessHeap(), 0, This);
2772 /******************************************************************************
2774 ** Storage32InternalImpl_Commit
2776 ** The non-root storages cannot be opened in transacted mode thus this function
2777 ** does nothing.
2779 HRESULT WINAPI Storage32InternalImpl_Commit(
2780 Storage32InternalImpl* This,
2781 DWORD grfCommitFlags) /* [in] */
2783 return S_OK;
2786 /******************************************************************************
2788 ** Storage32InternalImpl_Revert
2790 ** The non-root storages cannot be opened in transacted mode thus this function
2791 ** does nothing.
2793 HRESULT WINAPI Storage32InternalImpl_Revert(
2794 Storage32InternalImpl* This)
2796 return S_OK;
2799 /******************************************************************************
2800 ** IEnumSTATSTGImpl implementation
2803 IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
2804 Storage32Impl* parentStorage,
2805 ULONG firstPropertyNode)
2807 IEnumSTATSTGImpl* newEnumeration;
2809 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
2811 if (newEnumeration!=0)
2814 * Set-up the virtual function table and reference count.
2816 newEnumeration->lpvtbl = &IEnumSTATSTGImpl_Vtbl;
2817 newEnumeration->ref = 0;
2820 * We want to nail-down the reference to the storage in case the
2821 * enumeration out-lives the storage in the client application.
2823 newEnumeration->parentStorage = parentStorage;
2824 IStorage32_AddRef(newEnumeration->parentStorage);
2826 newEnumeration->firstPropertyNode = firstPropertyNode;
2829 * Initialize the search stack
2831 newEnumeration->stackSize = 0;
2832 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
2833 newEnumeration->stackToVisit =
2834 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
2837 * Make sure the current node of the iterator is the first one.
2839 IEnumSTATSTGImpl_Reset(newEnumeration);
2842 return newEnumeration;
2845 void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
2847 IStorage32_Release(This->parentStorage);
2848 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
2849 HeapFree(GetProcessHeap(), 0, This);
2852 HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
2853 IEnumSTATSTGImpl* This,
2854 REFIID riid,
2855 void** ppvObject)
2858 * Perform a sanity check on the parameters.
2860 if (ppvObject==0)
2861 return E_INVALIDARG;
2864 * Initialize the return parameter.
2866 *ppvObject = 0;
2869 * Compare the riid with the interface IDs implemented by this object.
2871 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
2873 *ppvObject = (IEnumSTATSTG*)This;
2875 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
2877 *ppvObject = (IEnumSTATSTG*)This;
2881 * Check that we obtained an interface.
2883 if ((*ppvObject)==0)
2884 return E_NOINTERFACE;
2887 * Query Interface always increases the reference count by one when it is
2888 * successful
2890 IEnumSTATSTGImpl_AddRef(This);
2892 return S_OK;;
2895 ULONG WINAPI IEnumSTATSTGImpl_AddRef(
2896 IEnumSTATSTGImpl* This)
2898 This->ref++;
2899 return This->ref;
2902 ULONG WINAPI IEnumSTATSTGImpl_Release(
2903 IEnumSTATSTGImpl* This)
2905 ULONG newRef;
2907 This->ref--;
2908 newRef = This->ref;
2911 * If the reference count goes down to 0, perform suicide.
2913 if (newRef==0)
2915 IEnumSTATSTGImpl_Destroy(This);
2918 return newRef;;
2921 HRESULT WINAPI IEnumSTATSTGImpl_Next(
2922 IEnumSTATSTGImpl* This,
2923 ULONG celt,
2924 STATSTG* rgelt,
2925 ULONG* pceltFetched)
2927 StgProperty currentProperty;
2928 STATSTG* currentReturnStruct = rgelt;
2929 ULONG objectFetched = 0;
2930 ULONG currentSearchNode;
2933 * Perform a sanity check on the parameters.
2935 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
2936 return E_INVALIDARG;
2939 * To avoid the special case, get another pointer to a ULONG value if
2940 * the caller didn't supply one.
2942 if (pceltFetched==0)
2943 pceltFetched = &objectFetched;
2946 * Start the iteration, we will iterate until we hit the end of the
2947 * linked list or until we hit the number of items to iterate through
2949 *pceltFetched = 0;
2952 * Start with the node at the top of the stack.
2954 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
2956 while ( ( *pceltFetched < celt) &&
2957 ( currentSearchNode!=PROPERTY_NULL) )
2960 * Remove the top node from the stack
2962 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
2965 * Read the property from the storage.
2967 Storage32Impl_ReadProperty(This->parentStorage,
2968 currentSearchNode,
2969 &currentProperty);
2972 * Copy the information to the return buffer.
2974 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
2975 &currentProperty,
2976 STATFLAG_DEFAULT);
2979 * Step to the next item in the iteration
2981 (*pceltFetched)++;
2982 currentReturnStruct++;
2985 * Push the next search node in the search stack.
2987 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
2990 * continue the iteration.
2992 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
2995 if (*pceltFetched == celt)
2996 return S_OK;
2998 return S_FALSE;
3002 HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3003 IEnumSTATSTGImpl* This,
3004 ULONG celt)
3006 StgProperty currentProperty;
3007 ULONG objectFetched = 0;
3008 ULONG currentSearchNode;
3011 * Start with the node at the top of the stack.
3013 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3015 while ( (objectFetched < celt) &&
3016 (currentSearchNode!=PROPERTY_NULL) )
3019 * Remove the top node from the stack
3021 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3024 * Read the property from the storage.
3026 Storage32Impl_ReadProperty(This->parentStorage,
3027 currentSearchNode,
3028 &currentProperty);
3031 * Step to the next item in the iteration
3033 objectFetched++;
3036 * Push the next search node in the search stack.
3038 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3041 * continue the iteration.
3043 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3046 if (objectFetched == celt)
3047 return S_OK;
3049 return S_FALSE;
3052 HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3053 IEnumSTATSTGImpl* This)
3055 StgProperty rootProperty;
3056 BOOL32 readSucessful;
3059 * Re-initialize the search stack to an empty stack
3061 This->stackSize = 0;
3064 * Read the root property from the storage.
3066 readSucessful = Storage32Impl_ReadProperty(
3067 This->parentStorage,
3068 This->firstPropertyNode,
3069 &rootProperty);
3071 if (readSucessful)
3073 assert(rootProperty.sizeOfNameString!=0);
3076 * Push the search node in the search stack.
3078 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3081 return S_OK;
3084 HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3085 IEnumSTATSTGImpl* This,
3086 IEnumSTATSTG** ppenum)
3088 IEnumSTATSTGImpl* newClone;
3091 * Perform a sanity check on the parameters.
3093 if (ppenum==0)
3094 return E_INVALIDARG;
3096 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3097 This->firstPropertyNode);
3101 * The new clone enumeration must point to the same current node as
3102 * the ole one.
3104 newClone->stackSize = This->stackSize ;
3105 newClone->stackMaxSize = This->stackMaxSize ;
3106 newClone->stackToVisit =
3107 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3109 memcpy(
3110 newClone->stackToVisit,
3111 This->stackToVisit,
3112 sizeof(ULONG) * newClone->stackSize);
3115 * Don't forget to nail down a reference to the clone before
3116 * returning it.
3118 IEnumSTATSTGImpl_AddRef(newClone);
3120 *ppenum = (IEnumSTATSTG*)newClone;
3122 return S_OK;
3125 INT32 IEnumSTATSTGImpl_FindParentProperty(
3126 IEnumSTATSTGImpl *This,
3127 ULONG childProperty,
3128 StgProperty *currentProperty,
3129 ULONG *thisNodeId)
3131 ULONG currentSearchNode;
3132 ULONG foundNode;
3135 * To avoid the special case, get another pointer to a ULONG value if
3136 * the caller didn't supply one.
3138 if (thisNodeId==0)
3139 thisNodeId = &foundNode;
3142 * Start with the node at the top of the stack.
3144 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3147 while (currentSearchNode!=PROPERTY_NULL)
3150 * Store the current node in the returned parameters
3152 *thisNodeId = currentSearchNode;
3155 * Remove the top node from the stack
3157 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3160 * Read the property from the storage.
3162 Storage32Impl_ReadProperty(
3163 This->parentStorage,
3164 currentSearchNode,
3165 currentProperty);
3167 if (currentProperty->previousProperty == childProperty)
3168 return PROPERTY_RELATION_PREVIOUS;
3170 else if (currentProperty->nextProperty == childProperty)
3171 return PROPERTY_RELATION_NEXT;
3173 else if (currentProperty->dirProperty == childProperty)
3174 return PROPERTY_RELATION_DIR;
3177 * Push the next search node in the search stack.
3179 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3182 * continue the iteration.
3184 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3187 return PROPERTY_NULL;
3190 ULONG IEnumSTATSTGImpl_FindProperty(
3191 IEnumSTATSTGImpl* This,
3192 const OLECHAR32* lpszPropName,
3193 StgProperty* currentProperty)
3195 ULONG currentSearchNode;
3198 * Start with the node at the top of the stack.
3200 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3202 while (currentSearchNode!=PROPERTY_NULL)
3205 * Remove the top node from the stack
3207 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3210 * Read the property from the storage.
3212 Storage32Impl_ReadProperty(This->parentStorage,
3213 currentSearchNode,
3214 currentProperty);
3216 if ( propertyNameCmp(
3217 (OLECHAR32*)currentProperty->name,
3218 (OLECHAR32*)lpszPropName) == 0)
3219 return currentSearchNode;
3222 * Push the next search node in the search stack.
3224 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3227 * continue the iteration.
3229 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3232 return PROPERTY_NULL;
3235 void IEnumSTATSTGImpl_PushSearchNode(
3236 IEnumSTATSTGImpl* This,
3237 ULONG nodeToPush)
3239 StgProperty rootProperty;
3240 BOOL32 readSucessful;
3243 * First, make sure we're not trying to push an unexisting node.
3245 if (nodeToPush==PROPERTY_NULL)
3246 return;
3249 * First push the node to the stack
3251 if (This->stackSize == This->stackMaxSize)
3253 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3255 This->stackToVisit = HeapReAlloc(
3256 GetProcessHeap(),
3258 This->stackToVisit,
3259 sizeof(ULONG) * This->stackMaxSize);
3262 This->stackToVisit[This->stackSize] = nodeToPush;
3263 This->stackSize++;
3266 * Read the root property from the storage.
3268 readSucessful = Storage32Impl_ReadProperty(
3269 This->parentStorage,
3270 nodeToPush,
3271 &rootProperty);
3273 if (readSucessful)
3275 assert(rootProperty.sizeOfNameString!=0);
3278 * Push the previous search node in the search stack.
3280 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3284 ULONG IEnumSTATSTGImpl_PopSearchNode(
3285 IEnumSTATSTGImpl* This,
3286 BOOL32 remove)
3288 ULONG topNode;
3290 if (This->stackSize == 0)
3291 return PROPERTY_NULL;
3293 topNode = This->stackToVisit[This->stackSize-1];
3295 if (remove)
3296 This->stackSize--;
3298 return topNode;
3301 /******************************************************************************
3302 ** StorageUtl implementation
3305 void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3307 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3310 void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3312 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3315 void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3317 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3320 void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3322 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3325 void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3327 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3328 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3329 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3331 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3334 void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3336 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3337 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3338 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3340 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3343 void StorageUtl_CopyPropertyToSTATSTG(
3344 STATSTG* destination,
3345 StgProperty* source,
3346 int statFlags)
3349 * The copy of the string occurs only when the flag is not set
3351 if ((statFlags & STATFLAG_NONAME) != 0)
3353 destination->pwcsName = 0;
3355 else
3357 destination->pwcsName =
3358 CoTaskMemAlloc((lstrlen32W(source->name)+1)*sizeof(WCHAR));
3360 lstrcpy32W((LPWSTR)destination->pwcsName, source->name);
3363 switch (source->propertyType)
3365 case PROPTYPE_STORAGE:
3366 case PROPTYPE_ROOT:
3367 destination->type = STGTY_STORAGE;
3368 break;
3369 case PROPTYPE_STREAM:
3370 destination->type = STGTY_STREAM;
3371 break;
3372 default:
3373 destination->type = STGTY_STREAM;
3374 break;
3377 destination->cbSize = source->size;
3379 currentReturnStruct->mtime = {0}; TODO
3380 currentReturnStruct->ctime = {0};
3381 currentReturnStruct->atime = {0};
3383 destination->grfMode = 0;
3384 destination->grfLocksSupported = 0;
3385 destination->clsid = source->propertyUniqueID;
3386 destination->grfStateBits = 0;
3387 destination->reserved = 0;
3390 /******************************************************************************
3391 ** BlockChainStream implementation
3394 BlockChainStream* BlockChainStream_Construct(
3395 Storage32Impl* parentStorage,
3396 ULONG* headOfStreamPlaceHolder,
3397 ULONG propertyIndex)
3399 BlockChainStream* newStream;
3401 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
3403 newStream->parentStorage = parentStorage;
3404 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
3405 newStream->ownerPropertyIndex = propertyIndex;
3407 return newStream;
3410 void BlockChainStream_Destroy(BlockChainStream* This)
3412 HeapFree(GetProcessHeap(), 0, This);
3415 /******************************************************************************
3416 * BlockChainStream_GetHeadOfChain
3418 * Returns the head of this stream chain.
3419 * Some special chains don't have properties, their heads are kept in
3420 * This->headOfStreamPlaceHolder.
3423 ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
3425 StgProperty chainProperty;
3426 BOOL32 readSucessful;
3428 if (This->headOfStreamPlaceHolder != 0)
3429 return *(This->headOfStreamPlaceHolder);
3431 if (This->ownerPropertyIndex != PROPERTY_NULL)
3433 readSucessful = Storage32Impl_ReadProperty(
3434 This->parentStorage,
3435 This->ownerPropertyIndex,
3436 &chainProperty);
3438 if (readSucessful)
3440 return chainProperty.startingBlock;
3444 return BLOCK_END_OF_CHAIN;
3447 /******************************************************************************
3448 * BlockChainStream_GetCount
3450 * Returns the number of blocks that comprises this chain.
3451 * This is not the size of the stream as the last block may not be full!
3454 ULONG BlockChainStream_GetCount(BlockChainStream* This)
3456 ULONG blockIndex;
3457 ULONG count = 0;
3459 blockIndex = BlockChainStream_GetHeadOfChain(This);
3461 while (blockIndex != BLOCK_END_OF_CHAIN)
3463 count++;
3465 blockIndex = Storage32Impl_GetNextBlockInChain(
3466 This->parentStorage,
3467 blockIndex);
3470 return count;
3473 /******************************************************************************
3474 * BlockChainStream_ReadAt
3476 * Reads a specified number of bytes from this chain at the specified offset.
3477 * bytesRead may be NULL.
3478 * Failure will be returned if the specified number of bytes has not been read.
3480 BOOL32 BlockChainStream_ReadAt(BlockChainStream* This,
3481 ULARGE_INTEGER offset,
3482 ULONG size,
3483 void* buffer,
3484 ULONG* bytesRead)
3486 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3487 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3488 ULONG bytesToReadInBuffer;
3489 ULONG blockIndex;
3490 BYTE* bufferWalker;
3491 BYTE* bigBlockBuffer;
3494 * Find the first block in the stream that contains part of the buffer.
3496 blockIndex = BlockChainStream_GetHeadOfChain(This);
3498 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3500 blockIndex =
3501 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3503 blockNoInSequence--;
3507 * Start reading the buffer.
3509 *bytesRead = 0;
3510 bufferWalker = buffer;
3512 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3515 * Calculate how many bytes we can copy from this big block.
3517 bytesToReadInBuffer =
3518 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3521 * Copy those bytes to the buffer
3523 bigBlockBuffer =
3524 Storage32Impl_GetROBigBlock(This->parentStorage, blockIndex);
3526 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
3528 Storage32Impl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3531 * Step to the next big block.
3533 blockIndex =
3534 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3536 bufferWalker += bytesToReadInBuffer;
3537 size -= bytesToReadInBuffer;
3538 *bytesRead += bytesToReadInBuffer;
3539 offsetInBlock = 0; /* There is no offset on the next block */
3543 return (size == 0);
3546 /******************************************************************************
3547 * BlockChainStream_WriteAt
3549 * Writes the specified number of bytes to this chain at the specified offset.
3550 * bytesWritten may be NULL.
3551 * Will fail if not all specified number of bytes have been written.
3553 BOOL32 BlockChainStream_WriteAt(BlockChainStream* This,
3554 ULARGE_INTEGER offset,
3555 ULONG size,
3556 const void* buffer,
3557 ULONG* bytesWritten)
3559 ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
3560 ULONG offsetInBlock = offset.LowPart % This->parentStorage->bigBlockSize;
3561 ULONG bytesToWrite;
3562 ULONG blockIndex;
3563 BYTE* bufferWalker;
3564 BYTE* bigBlockBuffer;
3567 * Find the first block in the stream that contains part of the buffer.
3569 blockIndex = BlockChainStream_GetHeadOfChain(This);
3571 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
3573 blockIndex =
3574 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3576 blockNoInSequence--;
3580 * Here, I'm casting away the constness on the buffer variable
3581 * This is OK since we don't intend to modify that buffer.
3583 *bytesWritten = 0;
3584 bufferWalker = (BYTE*)buffer;
3586 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
3589 * Calculate how many bytes we can copy from this big block.
3591 bytesToWrite =
3592 MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
3595 * Copy those bytes to the buffer
3597 bigBlockBuffer = Storage32Impl_GetBigBlock(This->parentStorage, blockIndex);
3599 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
3601 Storage32Impl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
3604 * Step to the next big block.
3606 blockIndex =
3607 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3609 bufferWalker += bytesToWrite;
3610 size -= bytesToWrite;
3611 *bytesWritten += bytesToWrite;
3612 offsetInBlock = 0; /* There is no offset on the next block */
3615 return (size == 0);
3618 /******************************************************************************
3619 * BlockChainStream_Shrink
3621 * Shrinks this chain in the big block depot.
3623 BOOL32 BlockChainStream_Shrink(BlockChainStream* This,
3624 ULARGE_INTEGER newSize)
3626 ULONG blockIndex, extraBlock;
3627 ULONG numBlocks;
3628 ULONG count = 1;
3631 * Figure out how many blocks are needed to contain the new size
3633 numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3635 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3636 numBlocks++;
3638 blockIndex = BlockChainStream_GetHeadOfChain(This);
3641 * Go to the new end of chain
3643 while (count < numBlocks)
3645 blockIndex =
3646 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3648 count++;
3651 /* Get the next block before marking the new end */
3652 extraBlock =
3653 Storage32Impl_GetNextBlockInChain(This->parentStorage, blockIndex);
3655 /* Mark the new end of chain */
3656 Storage32Impl_SetNextBlockInChain(
3657 This->parentStorage,
3658 blockIndex,
3659 BLOCK_END_OF_CHAIN);
3662 * Mark the extra blocks as free
3664 while (extraBlock != BLOCK_END_OF_CHAIN)
3666 blockIndex =
3667 Storage32Impl_GetNextBlockInChain(This->parentStorage, extraBlock);
3669 Storage32Impl_FreeBigBlock(This->parentStorage, extraBlock);
3670 extraBlock = blockIndex;
3673 return TRUE;
3676 /******************************************************************************
3677 * BlockChainStream_Enlarge
3679 * Grows this chain in the big block depot.
3681 BOOL32 BlockChainStream_Enlarge(BlockChainStream* This,
3682 ULARGE_INTEGER newSize)
3684 ULONG blockIndex, currentBlock;
3685 ULONG newNumBlocks;
3686 ULONG oldNumBlocks = 0;
3688 blockIndex = BlockChainStream_GetHeadOfChain(This);
3691 * Empty chain. Create the head.
3693 if (blockIndex == BLOCK_END_OF_CHAIN)
3695 blockIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
3696 Storage32Impl_SetNextBlockInChain(This->parentStorage,
3697 blockIndex,
3698 BLOCK_END_OF_CHAIN);
3700 if (This->headOfStreamPlaceHolder != 0)
3702 *(This->headOfStreamPlaceHolder) = blockIndex;
3704 else
3706 StgProperty chainProp;
3707 assert(This->ownerPropertyIndex != PROPERTY_NULL);
3709 Storage32Impl_ReadProperty(
3710 This->parentStorage,
3711 This->ownerPropertyIndex,
3712 &chainProp);
3714 chainProp.startingBlock = blockIndex;
3716 Storage32Impl_WriteProperty(
3717 This->parentStorage,
3718 This->ownerPropertyIndex,
3719 &chainProp);
3723 currentBlock = blockIndex;
3726 * Figure out how many blocks are needed to contain this stream
3728 newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
3730 if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
3731 newNumBlocks++;
3734 * Go to the current end of chain
3736 while (blockIndex != BLOCK_END_OF_CHAIN)
3738 oldNumBlocks++;
3739 currentBlock = blockIndex;
3741 blockIndex =
3742 Storage32Impl_GetNextBlockInChain(This->parentStorage, currentBlock);
3746 * Add new blocks to the chain
3748 while (oldNumBlocks < newNumBlocks)
3750 blockIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
3752 Storage32Impl_SetNextBlockInChain(
3753 This->parentStorage,
3754 currentBlock,
3755 blockIndex);
3757 Storage32Impl_SetNextBlockInChain(
3758 This->parentStorage,
3759 blockIndex,
3760 BLOCK_END_OF_CHAIN);
3762 currentBlock = blockIndex;
3763 oldNumBlocks++;
3766 return TRUE;
3769 /******************************************************************************
3770 * BlockChainStream_SetSize
3772 * Sets the size of this stream. The big block depot will be updated.
3773 * The file will grow if we grow the chain.
3775 * TODO: Free the actual blocks in the file when we shrink the chain.
3776 * Currently, the blocks are still in the file. So the file size
3777 * doesn't shrink even if we shrink streams.
3779 BOOL32 BlockChainStream_SetSize(
3780 BlockChainStream* This,
3781 ULARGE_INTEGER newSize)
3783 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
3785 if (newSize.LowPart == size.LowPart)
3786 return TRUE;
3788 if (newSize.LowPart < size.LowPart)
3790 BlockChainStream_Shrink(This, newSize);
3792 else
3794 ULARGE_INTEGER fileSize =
3795 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
3797 ULONG diff = newSize.LowPart - size.LowPart;
3800 * Make sure the file stays a multiple of blocksize
3802 if ((diff % This->parentStorage->bigBlockSize) != 0)
3803 diff += (This->parentStorage->bigBlockSize -
3804 (diff % This->parentStorage->bigBlockSize) );
3806 fileSize.LowPart += diff;
3807 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
3809 BlockChainStream_Enlarge(This, newSize);
3812 return TRUE;
3815 /******************************************************************************
3816 * BlockChainStream_GetSize
3818 * Returns the size of this chain.
3819 * Will return the block count if this chain doesn't have a property.
3821 ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
3823 StgProperty chainProperty;
3825 if(This->headOfStreamPlaceHolder == NULL)
3828 * This chain is a data stream read the property and return
3829 * the appropriate size
3831 Storage32Impl_ReadProperty(
3832 This->parentStorage,
3833 This->ownerPropertyIndex,
3834 &chainProperty);
3836 return chainProperty.size;
3838 else
3841 * this chain is a chain that does not have a property, figure out the
3842 * size by making the product number of used blocks times the
3843 * size of them
3845 ULARGE_INTEGER result;
3846 result.HighPart = 0;
3848 result.LowPart =
3849 BlockChainStream_GetCount(This) *
3850 This->parentStorage->bigBlockSize;
3852 return result;
3856 /******************************************************************************
3857 ** SmallBlockChainStream implementation
3860 SmallBlockChainStream* SmallBlockChainStream_Construct(
3861 Storage32Impl* parentStorage,
3862 ULONG propertyIndex)
3864 SmallBlockChainStream* newStream;
3866 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
3868 newStream->parentStorage = parentStorage;
3869 newStream->ownerPropertyIndex = propertyIndex;
3871 return newStream;
3874 void SmallBlockChainStream_Destroy(
3875 SmallBlockChainStream* This)
3877 HeapFree(GetProcessHeap(), 0, This);
3880 /******************************************************************************
3881 * SmallBlockChainStream_GetHeadOfChain
3883 * Returns the head of this chain of small blocks.
3885 ULONG SmallBlockChainStream_GetHeadOfChain(
3886 SmallBlockChainStream* This)
3888 StgProperty chainProperty;
3889 BOOL32 readSucessful;
3891 if (This->ownerPropertyIndex)
3893 readSucessful = Storage32Impl_ReadProperty(
3894 This->parentStorage,
3895 This->ownerPropertyIndex,
3896 &chainProperty);
3898 if (readSucessful)
3900 return chainProperty.startingBlock;
3905 return BLOCK_END_OF_CHAIN;
3908 /******************************************************************************
3909 * SmallBlockChainStream_GetNextBlockInChain
3911 * Returns the index of the next small block in this chain.
3913 * Return Values:
3914 * - BLOCK_END_OF_CHAIN: end of this chain
3915 * - BLOCK_UNUSED: small block 'blockIndex' is free
3917 ULONG SmallBlockChainStream_GetNextBlockInChain(
3918 SmallBlockChainStream* This,
3919 ULONG blockIndex)
3921 ULARGE_INTEGER offsetOfBlockInDepot;
3922 DWORD buffer;
3923 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
3924 ULONG bytesRead;
3925 BOOL32 success;
3927 offsetOfBlockInDepot.HighPart = 0;
3928 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
3931 * Read those bytes in the buffer from the small block file.
3933 success = BlockChainStream_ReadAt(
3934 This->parentStorage->smallBlockDepotChain,
3935 offsetOfBlockInDepot,
3936 sizeof(DWORD),
3937 &buffer,
3938 &bytesRead);
3940 if (success)
3942 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
3945 return nextBlockInChain;
3948 /******************************************************************************
3949 * SmallBlockChainStream_SetNextBlockInChain
3951 * Writes the index of the next block of the specified block in the small
3952 * block depot.
3953 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
3954 * To flag a block as free use BLOCK_UNUSED as nextBlock.
3956 void SmallBlockChainStream_SetNextBlockInChain(
3957 SmallBlockChainStream* This,
3958 ULONG blockIndex,
3959 ULONG nextBlock)
3961 ULARGE_INTEGER offsetOfBlockInDepot;
3962 DWORD buffer;
3963 ULONG bytesWritten;
3965 offsetOfBlockInDepot.HighPart = 0;
3966 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
3968 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
3971 * Read those bytes in the buffer from the small block file.
3973 BlockChainStream_WriteAt(
3974 This->parentStorage->smallBlockDepotChain,
3975 offsetOfBlockInDepot,
3976 sizeof(DWORD),
3977 &buffer,
3978 &bytesWritten);
3981 /******************************************************************************
3982 * SmallBlockChainStream_FreeBlock
3984 * Flag small block 'blockIndex' as free in the small block depot.
3986 void SmallBlockChainStream_FreeBlock(
3987 SmallBlockChainStream* This,
3988 ULONG blockIndex)
3990 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
3993 /******************************************************************************
3994 * SmallBlockChainStream_GetNextFreeBlock
3996 * Returns the index of a free small block. The small block depot will be
3997 * enlarged if necessary. The small block chain will also be enlarged if
3998 * necessary.
4000 ULONG SmallBlockChainStream_GetNextFreeBlock(
4001 SmallBlockChainStream* This)
4003 ULARGE_INTEGER offsetOfBlockInDepot;
4004 DWORD buffer;
4005 ULONG bytesRead;
4006 ULONG blockIndex = 0;
4007 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4008 BOOL32 success = TRUE;
4009 ULONG smallBlocksPerBigBlock;
4011 offsetOfBlockInDepot.HighPart = 0;
4014 * Scan the small block depot for a free block
4016 while (nextBlockIndex != BLOCK_UNUSED)
4018 offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
4020 success = BlockChainStream_ReadAt(
4021 This->parentStorage->smallBlockDepotChain,
4022 offsetOfBlockInDepot,
4023 sizeof(DWORD),
4024 &buffer,
4025 &bytesRead);
4028 * If we run out of space for the small block depot, enlarge it
4030 if (success)
4032 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4034 if (nextBlockIndex != BLOCK_UNUSED)
4035 blockIndex++;
4037 else
4039 ULONG count =
4040 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4042 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4043 ULONG nextBlock, newsbdIndex;
4044 BYTE* smallBlockDepot;
4046 nextBlock = sbdIndex;
4047 while (nextBlock != BLOCK_END_OF_CHAIN)
4049 sbdIndex = nextBlock;
4050 nextBlock =
4051 Storage32Impl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4054 newsbdIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
4055 if (sbdIndex != BLOCK_END_OF_CHAIN)
4056 Storage32Impl_SetNextBlockInChain(
4057 This->parentStorage,
4058 sbdIndex,
4059 newsbdIndex);
4061 Storage32Impl_SetNextBlockInChain(
4062 This->parentStorage,
4063 newsbdIndex,
4064 BLOCK_END_OF_CHAIN);
4067 * Initialize all the small blocks to free
4069 smallBlockDepot =
4070 Storage32Impl_GetBigBlock(This->parentStorage, newsbdIndex);
4072 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4073 Storage32Impl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4075 if (count == 0)
4078 * We have just created the small block depot.
4080 StgProperty rootProp;
4081 ULONG sbStartIndex;
4084 * Save it in the header
4086 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4087 Storage32Impl_SaveFileHeader(This->parentStorage);
4090 * And allocate the first big block that will contain small blocks
4092 sbStartIndex =
4093 Storage32Impl_GetNextFreeBigBlock(This->parentStorage);
4095 Storage32Impl_SetNextBlockInChain(
4096 This->parentStorage,
4097 sbStartIndex,
4098 BLOCK_END_OF_CHAIN);
4100 Storage32Impl_ReadProperty(
4101 This->parentStorage,
4102 This->parentStorage->rootPropertySetIndex,
4103 &rootProp);
4105 rootProp.startingBlock = sbStartIndex;
4106 rootProp.size.HighPart = 0;
4107 rootProp.size.LowPart = This->parentStorage->bigBlockSize;
4109 Storage32Impl_WriteProperty(
4110 This->parentStorage,
4111 This->parentStorage->rootPropertySetIndex,
4112 &rootProp);
4117 smallBlocksPerBigBlock =
4118 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4121 * Verify if we have to allocate big blocks to contain small blocks
4123 if (blockIndex % smallBlocksPerBigBlock == 0)
4125 StgProperty rootProp;
4126 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4128 Storage32Impl_ReadProperty(
4129 This->parentStorage,
4130 This->parentStorage->rootPropertySetIndex,
4131 &rootProp);
4133 if (rootProp.size.LowPart <
4134 (blocksRequired * This->parentStorage->bigBlockSize))
4136 rootProp.size.LowPart += This->parentStorage->bigBlockSize;
4138 BlockChainStream_SetSize(
4139 This->parentStorage->smallBlockRootChain,
4140 rootProp.size);
4142 Storage32Impl_WriteProperty(
4143 This->parentStorage,
4144 This->parentStorage->rootPropertySetIndex,
4145 &rootProp);
4149 return blockIndex;
4152 /******************************************************************************
4153 * SmallBlockChainStream_ReadAt
4155 * Reads a specified number of bytes from this chain at the specified offset.
4156 * bytesRead may be NULL.
4157 * Failure will be returned if the specified number of bytes has not been read.
4159 BOOL32 SmallBlockChainStream_ReadAt(
4160 SmallBlockChainStream* This,
4161 ULARGE_INTEGER offset,
4162 ULONG size,
4163 void* buffer,
4164 ULONG* bytesRead)
4166 ULARGE_INTEGER offsetInBigBlockFile;
4167 ULONG blockNoInSequence =
4168 offset.LowPart / This->parentStorage->smallBlockSize;
4170 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4171 ULONG bytesToReadInBuffer;
4172 ULONG blockIndex;
4173 ULONG bytesReadFromBigBlockFile;
4174 BYTE* bufferWalker;
4177 * This should never happen on a small block file.
4179 assert(offset.HighPart==0);
4182 * Find the first block in the stream that contains part of the buffer.
4184 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4186 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4188 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4190 blockNoInSequence--;
4194 * Start reading the buffer.
4196 *bytesRead = 0;
4197 bufferWalker = buffer;
4199 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4202 * Calculate how many bytes we can copy from this small block.
4204 bytesToReadInBuffer =
4205 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4208 * Calculate the offset of the small block in the small block file.
4210 offsetInBigBlockFile.HighPart = 0;
4211 offsetInBigBlockFile.LowPart =
4212 blockIndex * This->parentStorage->smallBlockSize;
4214 offsetInBigBlockFile.LowPart += offsetInBlock;
4217 * Read those bytes in the buffer from the small block file.
4219 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4220 offsetInBigBlockFile,
4221 bytesToReadInBuffer,
4222 bufferWalker,
4223 &bytesReadFromBigBlockFile);
4225 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4228 * Step to the next big block.
4230 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4231 bufferWalker += bytesToReadInBuffer;
4232 size -= bytesToReadInBuffer;
4233 *bytesRead += bytesToReadInBuffer;
4234 offsetInBlock = 0; /* There is no offset on the next block */
4237 return (size == 0);
4240 /******************************************************************************
4241 * SmallBlockChainStream_WriteAt
4243 * Writes the specified number of bytes to this chain at the specified offset.
4244 * bytesWritten may be NULL.
4245 * Will fail if not all specified number of bytes have been written.
4247 BOOL32 SmallBlockChainStream_WriteAt(
4248 SmallBlockChainStream* This,
4249 ULARGE_INTEGER offset,
4250 ULONG size,
4251 const void* buffer,
4252 ULONG* bytesWritten)
4254 ULARGE_INTEGER offsetInBigBlockFile;
4255 ULONG blockNoInSequence =
4256 offset.LowPart / This->parentStorage->smallBlockSize;
4258 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
4259 ULONG bytesToWriteInBuffer;
4260 ULONG blockIndex;
4261 ULONG bytesWrittenFromBigBlockFile;
4262 BYTE* bufferWalker;
4265 * This should never happen on a small block file.
4267 assert(offset.HighPart==0);
4270 * Find the first block in the stream that contains part of the buffer.
4272 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4274 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4276 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4278 blockNoInSequence--;
4282 * Start writing the buffer.
4284 * Here, I'm casting away the constness on the buffer variable
4285 * This is OK since we don't intend to modify that buffer.
4287 *bytesWritten = 0;
4288 bufferWalker = (BYTE*)buffer;
4289 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4292 * Calculate how many bytes we can copy to this small block.
4294 bytesToWriteInBuffer =
4295 MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
4298 * Calculate the offset of the small block in the small block file.
4300 offsetInBigBlockFile.HighPart = 0;
4301 offsetInBigBlockFile.LowPart =
4302 blockIndex * This->parentStorage->smallBlockSize;
4304 offsetInBigBlockFile.LowPart += offsetInBlock;
4307 * Write those bytes in the buffer to the small block file.
4309 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
4310 offsetInBigBlockFile,
4311 bytesToWriteInBuffer,
4312 bufferWalker,
4313 &bytesWrittenFromBigBlockFile);
4315 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
4318 * Step to the next big block.
4320 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4321 bufferWalker += bytesToWriteInBuffer;
4322 size -= bytesToWriteInBuffer;
4323 *bytesWritten += bytesToWriteInBuffer;
4324 offsetInBlock = 0; /* There is no offset on the next block */
4327 return (size == 0);
4330 /******************************************************************************
4331 * SmallBlockChainStream_Shrink
4333 * Shrinks this chain in the small block depot.
4335 BOOL32 SmallBlockChainStream_Shrink(
4336 SmallBlockChainStream* This,
4337 ULARGE_INTEGER newSize)
4339 ULONG blockIndex, extraBlock;
4340 ULONG numBlocks;
4341 ULONG count = 1;
4343 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4345 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4346 numBlocks++;
4348 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4351 * Go to the new end of chain
4353 while (count < numBlocks)
4355 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4356 count++;
4359 /* Get the next block before marking the new end */
4360 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4362 /* Mark the new end of chain */
4363 SmallBlockChainStream_SetNextBlockInChain(
4364 This,
4365 blockIndex,
4366 BLOCK_END_OF_CHAIN);
4369 * Mark the extra blocks as free
4371 while (extraBlock != BLOCK_END_OF_CHAIN)
4373 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
4374 SmallBlockChainStream_FreeBlock(This, extraBlock);
4375 extraBlock = blockIndex;
4378 return TRUE;
4381 /******************************************************************************
4382 * SmallBlockChainStream_Enlarge
4384 * Grows this chain in the small block depot.
4386 BOOL32 SmallBlockChainStream_Enlarge(
4387 SmallBlockChainStream* This,
4388 ULARGE_INTEGER newSize)
4390 ULONG blockIndex, currentBlock;
4391 ULONG newNumBlocks;
4392 ULONG oldNumBlocks = 0;
4394 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4397 * Empty chain
4399 if (blockIndex == BLOCK_END_OF_CHAIN)
4401 StgProperty chainProp;
4403 Storage32Impl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
4404 &chainProp);
4406 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
4408 Storage32Impl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
4409 &chainProp);
4411 blockIndex = chainProp.startingBlock;
4412 SmallBlockChainStream_SetNextBlockInChain(
4413 This,
4414 blockIndex,
4415 BLOCK_END_OF_CHAIN);
4418 currentBlock = blockIndex;
4421 * Figure out how many blocks are needed to contain this stream
4423 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
4425 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
4426 newNumBlocks++;
4429 * Go to the current end of chain
4431 while (blockIndex != BLOCK_END_OF_CHAIN)
4433 oldNumBlocks++;
4434 currentBlock = blockIndex;
4435 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
4439 * Add new blocks to the chain
4441 while (oldNumBlocks < newNumBlocks)
4443 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
4444 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
4446 SmallBlockChainStream_SetNextBlockInChain(
4447 This,
4448 blockIndex,
4449 BLOCK_END_OF_CHAIN);
4451 currentBlock = blockIndex;
4452 oldNumBlocks++;
4455 return TRUE;
4458 /******************************************************************************
4459 * SmallBlockChainStream_GetCount
4461 * Returns the number of blocks that comprises this chain.
4462 * This is not the size of this chain as the last block may not be full!
4464 ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
4466 ULONG blockIndex;
4467 ULONG count = 0;
4469 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4471 while (blockIndex != BLOCK_END_OF_CHAIN)
4473 count++;
4475 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4478 return count;
4481 /******************************************************************************
4482 * SmallBlockChainStream_SetSize
4484 * Sets the size of this stream.
4485 * The file will grow if we grow the chain.
4487 * TODO: Free the actual blocks in the file when we shrink the chain.
4488 * Currently, the blocks are still in the file. So the file size
4489 * doesn't shrink even if we shrink streams.
4491 BOOL32 SmallBlockChainStream_SetSize(
4492 SmallBlockChainStream* This,
4493 ULARGE_INTEGER newSize)
4495 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
4497 if (newSize.LowPart == size.LowPart)
4498 return TRUE;
4500 if (newSize.LowPart < size.LowPart)
4502 SmallBlockChainStream_Shrink(This, newSize);
4504 else
4506 SmallBlockChainStream_Enlarge(This, newSize);
4509 return TRUE;
4512 /******************************************************************************
4513 * SmallBlockChainStream_GetSize
4515 * Returns the size of this chain.
4517 ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
4519 StgProperty chainProperty;
4521 Storage32Impl_ReadProperty(
4522 This->parentStorage,
4523 This->ownerPropertyIndex,
4524 &chainProperty);
4526 return chainProperty.size;
4529 /******************************************************************************
4530 * StgCreateDocfile32 [OLE32.144]
4531 * TODO Validate grfMode (STGM)
4533 HRESULT WINAPI StgCreateDocfile32(
4534 LPCOLESTR32 pwcsName,
4535 DWORD grfMode,
4536 DWORD reserved,
4537 IStorage32 **ppstgOpen)
4539 Storage32Impl* newStorage = 0;
4540 HANDLE32 hFile = INVALID_HANDLE_VALUE32;
4541 HRESULT hr = S_OK;
4542 DWORD shareMode;
4543 DWORD accessMode;
4544 DWORD creationMode;
4545 DWORD fileAttributes;
4548 * Validate the parameters
4550 if ((ppstgOpen == 0) || (pwcsName == 0))
4551 return STG_E_INVALIDPOINTER;
4554 * Validate the STGM flags
4556 if ( FAILED( validateSTGM(grfMode) ))
4557 return STG_E_INVALIDFLAG;
4560 * Interpret the STGM value grfMode
4562 shareMode = GetShareModeFromSTGM(grfMode);
4563 accessMode = GetAccessModeFromSTGM(grfMode);
4564 creationMode = GetCreationModeFromSTGM(grfMode);
4566 if (grfMode & STGM_DELETEONRELEASE)
4567 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
4568 else
4569 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
4571 if (grfMode & STGM_TRANSACTED)
4572 FIXME(ole, "Transacted mode not implemented.\n");
4575 * Initialize the "out" parameter.
4577 *ppstgOpen = 0;
4579 hFile = CreateFile32W(pwcsName,
4580 accessMode,
4581 shareMode,
4582 NULL,
4583 creationMode,
4584 fileAttributes,
4587 if (hFile == INVALID_HANDLE_VALUE32)
4589 return E_FAIL;
4593 * Allocate and initialize the new IStorage32object.
4595 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl));
4597 if (newStorage == 0)
4598 return STG_E_INSUFFICIENTMEMORY;
4600 hr = Storage32Impl_Construct(
4601 newStorage,
4602 hFile,
4603 grfMode);
4605 if (FAILED(hr))
4606 return hr;
4609 * Get an "out" pointer for the caller.
4611 hr = Storage32BaseImpl_QueryInterface(
4612 (Storage32BaseImpl*)newStorage,
4613 (REFIID)&IID_IStorage,
4614 (void**)ppstgOpen);
4616 return hr;
4619 /******************************************************************************
4620 * StgOpenStorage32 [OLE32.148]
4622 HRESULT WINAPI StgOpenStorage32(
4623 const OLECHAR32 *pwcsName,
4624 IStorage32 *pstgPriority,
4625 DWORD grfMode,
4626 SNB32 snbExclude,
4627 DWORD reserved,
4628 IStorage32 **ppstgOpen)
4630 Storage32Impl* newStorage = 0;
4631 HRESULT hr = S_OK;
4632 HANDLE32 hFile = 0;
4633 DWORD shareMode;
4634 DWORD accessMode;
4637 * Perform a sanity check
4639 if (( pwcsName == 0) || (ppstgOpen == 0) )
4640 return STG_E_INVALIDPOINTER;
4643 * Validate the STGM flags
4645 if ( FAILED( validateSTGM(grfMode) ))
4646 return STG_E_INVALIDFLAG;
4649 * Interpret the STGM value grfMode
4651 shareMode = GetShareModeFromSTGM(grfMode);
4652 accessMode = GetAccessModeFromSTGM(grfMode);
4655 * Initialize the "out" parameter.
4657 *ppstgOpen = 0;
4659 hFile = CreateFile32W( pwcsName,
4660 accessMode,
4661 shareMode,
4662 NULL,
4663 OPEN_EXISTING,
4664 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
4668 if (hFile==INVALID_HANDLE_VALUE32)
4670 return E_FAIL;
4674 * Allocate and initialize the new IStorage32object.
4676 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(Storage32Impl));
4678 if (newStorage == 0)
4679 return STG_E_INSUFFICIENTMEMORY;
4681 hr = Storage32Impl_Construct(
4682 newStorage,
4683 hFile,
4684 grfMode);
4686 if (FAILED(hr))
4687 return hr;
4690 * Get an "out" pointer for the caller.
4692 hr = Storage32BaseImpl_QueryInterface(
4693 (Storage32BaseImpl*)newStorage,
4694 (REFIID)&IID_IStorage,
4695 (void**)ppstgOpen);
4697 return hr;
4700 /******************************************************************************
4701 * WriteClassStg32 [OLE32.148]
4703 * This method will store the specified CLSID in the specified storage object
4705 HRESULT WINAPI WriteClassStg32(IStorage32* pStg, REFCLSID rclsid)
4707 HRESULT hRes;
4709 assert(pStg != 0);
4711 hRes = IStorage32_SetClass(pStg, rclsid);
4713 return hRes;
4717 /****************************************************************************
4718 * This method validate a STGM parameter that can contain the values below
4720 * STGM_DIRECT 0x00000000
4721 * STGM_TRANSACTED 0x00010000
4722 * STGM_SIMPLE 0x08000000
4724 * STGM_READ 0x00000000
4725 * STGM_WRITE 0x00000001
4726 * STGM_READWRITE 0x00000002
4728 * STGM_SHARE_DENY_NONE 0x00000040
4729 * STGM_SHARE_DENY_READ 0x00000030
4730 * STGM_SHARE_DENY_WRITE 0x00000020
4731 * STGM_SHARE_EXCLUSIVE 0x00000010
4733 * STGM_PRIORITY 0x00040000
4734 * STGM_DELETEONRELEASE 0x04000000
4736 * STGM_CREATE 0x00001000
4737 * STGM_CONVERT 0x00020000
4738 * STGM_FAILIFTHERE 0x00000000
4740 * STGM_NOSCRATCH 0x00100000
4741 * STGM_NOSNAPSHOT 0x00200000
4743 static HRESULT validateSTGM(DWORD stgm)
4745 BOOL32 bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
4746 BOOL32 bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
4747 BOOL32 bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
4749 BOOL32 bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
4750 BOOL32 bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
4751 BOOL32 bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
4753 BOOL32 bSTGM_SHARE_DENY_NONE =
4754 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
4756 BOOL32 bSTGM_SHARE_DENY_READ =
4757 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
4759 BOOL32 bSTGM_SHARE_DENY_WRITE =
4760 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
4762 BOOL32 bSTGM_SHARE_EXCLUSIVE =
4763 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
4765 BOOL32 bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
4766 BOOL32 bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
4768 BOOL32 bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
4769 BOOL32 bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
4772 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
4774 if ( ! bSTGM_DIRECT )
4775 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
4776 return E_FAIL;
4779 * STGM_WRITE | STGM_READWRITE | STGM_READ
4781 if ( ! bSTGM_READ )
4782 if( bSTGM_WRITE && bSTGM_READWRITE )
4783 return E_FAIL;
4786 * STGM_SHARE_DENY_NONE | others
4787 * (I assume here that DENY_READ implies DENY_WRITE)
4789 if ( bSTGM_SHARE_DENY_NONE )
4790 if ( bSTGM_SHARE_DENY_READ ||
4791 bSTGM_SHARE_DENY_WRITE ||
4792 bSTGM_SHARE_EXCLUSIVE)
4793 return E_FAIL;
4796 * STGM_CREATE | STGM_CONVERT
4797 * if both are false, STGM_FAILIFTHERE is set to TRUE
4799 if ( bSTGM_CREATE && bSTGM_CONVERT )
4800 return E_FAIL;
4803 * STGM_NOSCRATCH requires STGM_TRANSACTED
4805 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
4806 return E_FAIL;
4809 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
4810 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
4812 if (bSTGM_NOSNAPSHOT)
4814 if ( ! ( bSTGM_TRANSACTED &&
4815 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
4816 return E_FAIL;
4819 return S_OK;
4822 /****************************************************************************
4823 * GetShareModeFromSTGM
4825 * This method will return a share mode flag from a STGM value.
4826 * The STGM value is assumed valid.
4828 static DWORD GetShareModeFromSTGM(DWORD stgm)
4830 DWORD dwShareMode = 0;
4831 BOOL32 bSTGM_SHARE_DENY_NONE =
4832 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
4834 BOOL32 bSTGM_SHARE_DENY_READ =
4835 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
4837 BOOL32 bSTGM_SHARE_DENY_WRITE =
4838 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
4840 BOOL32 bSTGM_SHARE_EXCLUSIVE =
4841 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
4843 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
4844 dwShareMode = 0;
4846 if (bSTGM_SHARE_DENY_NONE)
4847 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
4849 if (bSTGM_SHARE_DENY_WRITE)
4850 dwShareMode = FILE_SHARE_READ;
4852 return dwShareMode;
4855 /****************************************************************************
4856 * GetAccessModeFromSTGM
4858 * This method will return an access mode flag from a STGM value.
4859 * The STGM value is assumed valid.
4861 static DWORD GetAccessModeFromSTGM(DWORD stgm)
4863 DWORD dwDesiredAccess = 0;
4864 BOOL32 bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
4865 BOOL32 bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
4866 BOOL32 bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
4868 if (bSTGM_READ)
4869 dwDesiredAccess = GENERIC_READ;
4871 if (bSTGM_WRITE)
4872 dwDesiredAccess |= GENERIC_WRITE;
4874 if (bSTGM_READWRITE)
4875 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
4877 return dwDesiredAccess;
4880 /****************************************************************************
4881 * GetCreationModeFromSTGM
4883 * This method will return a creation mode flag from a STGM value.
4884 * The STGM value is assumed valid.
4886 static DWORD GetCreationModeFromSTGM(DWORD stgm)
4888 DWORD dwCreationDistribution;
4889 BOOL32 bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
4890 BOOL32 bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
4891 BOOL32 bSTGM_FAILIFTHERE = ! (bSTGM_CREATE || bSTGM_CONVERT);
4893 if (bSTGM_CREATE)
4894 dwCreationDistribution = CREATE_NEW;
4895 else if (bSTGM_FAILIFTHERE)
4896 dwCreationDistribution = CREATE_NEW;
4897 else if (bSTGM_CONVERT)
4899 FIXME(ole, "STGM_CONVERT not implemented!\n");
4900 dwCreationDistribution = CREATE_NEW;
4903 return dwCreationDistribution;