ole32: We do need to implement Commit/Revert for non-root storage.
[wine] / dlls / ole32 / storage32.c
1 /*
2  * Compound Storage (32 bit version)
3  * Storage implementation
4  *
5  * This file contains the compound file implementation
6  * of the storage interface.
7  *
8  * Copyright 1999 Francis Beaudet
9  * Copyright 1999 Sylvain St-Germain
10  * Copyright 1999 Thuy Nguyen
11  * Copyright 2005 Mike McCormack
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26  *
27  * NOTES
28  *  The compound file implementation of IStorage used for create
29  *  and manage substorages and streams within a storage object
30  *  residing in a compound file object.
31  */
32
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #define COBJMACROS
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winnls.h"
46 #include "winuser.h"
47 #include "wine/unicode.h"
48 #include "wine/debug.h"
49
50 #include "storage32.h"
51 #include "ole2.h"      /* For Write/ReadClassStm */
52
53 #include "winreg.h"
54 #include "wine/wingdi16.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(storage);
57
58 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
59 #define OLESTREAM_ID 0x501
60 #define OLESTREAM_MAX_STR_LEN 255
61
62 /*
63  * These are signatures to detect the type of Document file.
64  */
65 static const BYTE STORAGE_magic[8]    ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
66 static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
67
68 static const char rootPropertyName[] = "Root Entry";
69
70 /****************************************************************************
71  * Storage32InternalImpl definitions.
72  *
73  * Definition of the implementation structure for the IStorage32 interface.
74  * This one implements the IStorage32 interface for storage that are
75  * inside another storage.
76  */
77 struct StorageInternalImpl
78 {
79   struct StorageBaseImpl base;
80   /*
81    * There is no specific data for this class.
82    */
83 };
84 typedef struct StorageInternalImpl StorageInternalImpl;
85
86 /* Method definitions for the Storage32InternalImpl class. */
87 static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage,
88                                                           DWORD openFlags, ULONG rootTropertyIndex);
89 static void StorageImpl_Destroy(StorageBaseImpl* iface);
90 static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
91 static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, const void* buffer);
92 static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
93 static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
94 static void StorageImpl_SaveFileHeader(StorageImpl* This);
95
96 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex);
97 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
98 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex);
99 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex);
100 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex);
101
102 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This);
103 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This);
104 static ULONG BlockChainStream_GetCount(BlockChainStream* This);
105
106 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
107 static ULONG SmallBlockChainStream_GetHeadOfChain(SmallBlockChainStream* This);
108 static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
109     ULONG blockIndex, ULONG offset, DWORD value);
110 static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl*  This,
111     ULONG blockIndex, ULONG offset, DWORD* value);
112
113 /* OLESTREAM memory structure to use for Get and Put Routines */
114 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
115 typedef struct
116 {
117     DWORD dwOleID;
118     DWORD dwTypeID;
119     DWORD dwOleTypeNameLength;
120     CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
121     CHAR  *pstrOleObjFileName;
122     DWORD dwOleObjFileNameLength;
123     DWORD dwMetaFileWidth;
124     DWORD dwMetaFileHeight;
125     CHAR  strUnknown[8]; /* don't know what this 8 byte information in OLE stream is. */
126     DWORD dwDataLength;
127     BYTE *pData;
128 }OLECONVERT_OLESTREAM_DATA;
129
130 /* CompObj Stream structure */
131 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
132 typedef struct
133 {
134     BYTE byUnknown1[12];
135     CLSID clsid;
136     DWORD dwCLSIDNameLength;
137     CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
138     DWORD dwOleTypeNameLength;
139     CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
140     DWORD dwProgIDNameLength;
141     CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
142     BYTE byUnknown2[16];
143 }OLECONVERT_ISTORAGE_COMPOBJ;
144
145
146 /* Ole Presentation Stream structure */
147 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
148 typedef struct
149 {
150     BYTE byUnknown1[28];
151     DWORD dwExtentX;
152     DWORD dwExtentY;
153     DWORD dwSize;
154     BYTE *pData;
155 }OLECONVERT_ISTORAGE_OLEPRES;
156
157
158
159 /***********************************************************************
160  * Forward declaration of internal functions used by the method DestroyElement
161  */
162 static HRESULT deleteStorageProperty(
163   StorageImpl *parentStorage,
164   ULONG        foundPropertyIndexToDelete,
165   StgProperty  propertyToDelete);
166
167 static HRESULT deleteStreamProperty(
168   StorageImpl *parentStorage,
169   ULONG         foundPropertyIndexToDelete,
170   StgProperty   propertyToDelete);
171
172 static HRESULT findPlaceholder(
173   StorageImpl *storage,
174   ULONG         propertyIndexToStore,
175   ULONG         storagePropertyIndex,
176   INT         typeOfRelation);
177
178 static HRESULT adjustPropertyChain(
179   StorageImpl *This,
180   StgProperty   propertyToDelete,
181   StgProperty   parentProperty,
182   ULONG         parentPropertyId,
183   INT         typeOfRelation);
184
185 /***********************************************************************
186  * Declaration of the functions used to manipulate StgProperty
187  */
188
189 static ULONG getFreeProperty(
190   StorageImpl *storage);
191
192 static void updatePropertyChain(
193   StorageImpl *storage,
194   ULONG       newPropertyIndex,
195   StgProperty newProperty);
196
197 static LONG propertyNameCmp(
198     const OLECHAR *newProperty,
199     const OLECHAR *currentProperty);
200
201
202 /***********************************************************************
203  * Declaration of miscellaneous functions...
204  */
205 static HRESULT validateSTGM(DWORD stgmValue);
206
207 static DWORD GetShareModeFromSTGM(DWORD stgm);
208 static DWORD GetAccessModeFromSTGM(DWORD stgm);
209 static DWORD GetCreationModeFromSTGM(DWORD stgm);
210
211 extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
212
213
214 /****************************************************************************
215  * IEnumSTATSTGImpl definitions.
216  *
217  * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
218  * This class allows iterating through the content of a storage and to find
219  * specific items inside it.
220  */
221 struct IEnumSTATSTGImpl
222 {
223   const IEnumSTATSTGVtbl *lpVtbl;    /* Needs to be the first item in the struct
224                                 * since we want to cast this in an IEnumSTATSTG pointer */
225
226   LONG           ref;                   /* Reference count */
227   StorageImpl*   parentStorage;         /* Reference to the parent storage */
228   ULONG          firstPropertyNode;     /* Index of the root of the storage to enumerate */
229
230   /*
231    * The current implementation of the IEnumSTATSTGImpl class uses a stack
232    * to walk the property sets to get the content of a storage. This stack
233    * is implemented by the following 3 data members
234    */
235   ULONG          stackSize;
236   ULONG          stackMaxSize;
237   ULONG*         stackToVisit;
238
239 #define ENUMSTATSGT_SIZE_INCREMENT 10
240 };
241
242
243 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, ULONG firstPropertyNode);
244 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This);
245 static void IEnumSTATSTGImpl_PushSearchNode(IEnumSTATSTGImpl* This, ULONG nodeToPush);
246 static ULONG IEnumSTATSTGImpl_PopSearchNode(IEnumSTATSTGImpl* This, BOOL remove);
247 static ULONG IEnumSTATSTGImpl_FindProperty(IEnumSTATSTGImpl* This, const OLECHAR* lpszPropName,
248                                            StgProperty* buffer);
249 static INT IEnumSTATSTGImpl_FindParentProperty(IEnumSTATSTGImpl *This, ULONG childProperty,
250                                                StgProperty *currentProperty, ULONG *propertyId);
251
252 /************************************************************************
253 ** Block Functions
254 */
255
256 static ULONG BLOCK_GetBigBlockOffset(ULONG index)
257 {
258     if (index == 0xffffffff)
259         index = 0;
260     else
261         index ++;
262
263     return index * BIG_BLOCK_SIZE;
264 }
265
266 /************************************************************************
267 ** Storage32BaseImpl implementation
268 */
269 static HRESULT StorageImpl_ReadAt(StorageImpl* This,
270   ULARGE_INTEGER offset,
271   void*          buffer,
272   ULONG          size,
273   ULONG*         bytesRead)
274 {
275     return BIGBLOCKFILE_ReadAt(This->bigBlockFile,offset,buffer,size,bytesRead);
276 }
277
278 static HRESULT StorageImpl_WriteAt(StorageImpl* This,
279   ULARGE_INTEGER offset,
280   const void*    buffer,
281   const ULONG    size,
282   ULONG*         bytesWritten)
283 {
284     return BIGBLOCKFILE_WriteAt(This->bigBlockFile,offset,buffer,size,bytesWritten);
285 }
286
287 /************************************************************************
288  * Storage32BaseImpl_QueryInterface (IUnknown)
289  *
290  * This method implements the common QueryInterface for all IStorage32
291  * implementations contained in this file.
292  *
293  * See Windows documentation for more details on IUnknown methods.
294  */
295 static HRESULT WINAPI StorageBaseImpl_QueryInterface(
296   IStorage*        iface,
297   REFIID             riid,
298   void**             ppvObject)
299 {
300   StorageBaseImpl *This = (StorageBaseImpl *)iface;
301   /*
302    * Perform a sanity check on the parameters.
303    */
304   if ( (This==0) || (ppvObject==0) )
305     return E_INVALIDARG;
306
307   /*
308    * Initialize the return parameter.
309    */
310   *ppvObject = 0;
311
312   /*
313    * Compare the riid with the interface IDs implemented by this object.
314    */
315   if (IsEqualGUID(&IID_IUnknown, riid) ||
316       IsEqualGUID(&IID_IStorage, riid))
317   {
318     *ppvObject = This;
319   }
320   else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
321   {
322     *ppvObject = &This->pssVtbl;
323   }
324
325   /*
326    * Check that we obtained an interface.
327    */
328   if ((*ppvObject)==0)
329     return E_NOINTERFACE;
330
331   /*
332    * Query Interface always increases the reference count by one when it is
333    * successful
334    */
335   IStorage_AddRef(iface);
336
337   return S_OK;
338 }
339
340 /************************************************************************
341  * Storage32BaseImpl_AddRef (IUnknown)
342  *
343  * This method implements the common AddRef for all IStorage32
344  * implementations contained in this file.
345  *
346  * See Windows documentation for more details on IUnknown methods.
347  */
348 static ULONG WINAPI StorageBaseImpl_AddRef(
349             IStorage* iface)
350 {
351   StorageBaseImpl *This = (StorageBaseImpl *)iface;
352   ULONG ref = InterlockedIncrement(&This->ref);
353
354   TRACE("(%p) AddRef to %d\n", This, ref);
355
356   return ref;
357 }
358
359 /************************************************************************
360  * Storage32BaseImpl_Release (IUnknown)
361  *
362  * This method implements the common Release for all IStorage32
363  * implementations contained in this file.
364  *
365  * See Windows documentation for more details on IUnknown methods.
366  */
367 static ULONG WINAPI StorageBaseImpl_Release(
368       IStorage* iface)
369 {
370   StorageBaseImpl *This = (StorageBaseImpl *)iface;
371   /*
372    * Decrease the reference count on this object.
373    */
374   ULONG ref = InterlockedDecrement(&This->ref);
375
376   TRACE("(%p) ReleaseRef to %d\n", This, ref);
377
378   /*
379    * If the reference count goes down to 0, perform suicide.
380    */
381   if (ref == 0)
382   {
383     /*
384      * Since we are using a system of base-classes, we want to call the
385      * destructor of the appropriate derived class. To do this, we are
386      * using virtual functions to implement the destructor.
387      */
388     This->v_destructor(This);
389   }
390
391   return ref;
392 }
393
394 /************************************************************************
395  * Storage32BaseImpl_OpenStream (IStorage)
396  *
397  * This method will open the specified stream object from the current storage.
398  *
399  * See Windows documentation for more details on IStorage methods.
400  */
401 static HRESULT WINAPI StorageBaseImpl_OpenStream(
402   IStorage*        iface,
403   const OLECHAR*   pwcsName,  /* [string][in] */
404   void*            reserved1, /* [unique][in] */
405   DWORD            grfMode,   /* [in]  */
406   DWORD            reserved2, /* [in]  */
407   IStream**        ppstm)     /* [out] */
408 {
409   StorageBaseImpl *This = (StorageBaseImpl *)iface;
410   IEnumSTATSTGImpl* propertyEnumeration;
411   StgStreamImpl*    newStream;
412   StgProperty       currentProperty;
413   ULONG             foundPropertyIndex;
414   HRESULT           res = STG_E_UNKNOWN;
415
416   TRACE("(%p, %s, %p, %x, %d, %p)\n",
417         iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
418
419   /*
420    * Perform a sanity check on the parameters.
421    */
422   if ( (pwcsName==NULL) || (ppstm==0) )
423   {
424     res = E_INVALIDARG;
425     goto end;
426   }
427
428   /*
429    * Initialize the out parameter
430    */
431   *ppstm = NULL;
432
433   /*
434    * Validate the STGM flags
435    */
436   if ( FAILED( validateSTGM(grfMode) ) ||
437        STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
438   {
439     res = STG_E_INVALIDFLAG;
440     goto end;
441   }
442
443   /*
444    * As documented.
445    */
446   if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) )
447   {
448     res = STG_E_INVALIDFUNCTION;
449     goto end;
450   }
451
452   /*
453    * Check that we're compatible with the parent's storage mode, but
454    * only if we are not in transacted mode
455    */
456   if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
457     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
458     {
459       res = STG_E_ACCESSDENIED;
460       goto end;
461     }
462   }
463
464   /*
465    * Create a property enumeration to search the properties
466    */
467   propertyEnumeration = IEnumSTATSTGImpl_Construct(
468     This->ancestorStorage,
469     This->rootPropertySetIndex);
470
471   /*
472    * Search the enumeration for the property with the given name
473    */
474   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
475     propertyEnumeration,
476     pwcsName,
477     &currentProperty);
478
479   /*
480    * Delete the property enumeration since we don't need it anymore
481    */
482   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
483
484   /*
485    * If it was found, construct the stream object and return a pointer to it.
486    */
487   if ( (foundPropertyIndex!=PROPERTY_NULL) &&
488        (currentProperty.propertyType==PROPTYPE_STREAM) )
489   {
490     newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
491
492     if (newStream!=0)
493     {
494       newStream->grfMode = grfMode;
495       *ppstm = (IStream*)newStream;
496
497       /*
498        * Since we are returning a pointer to the interface, we have to
499        * nail down the reference.
500        */
501       IStream_AddRef(*ppstm);
502
503       res = S_OK;
504       goto end;
505     }
506
507     res = E_OUTOFMEMORY;
508     goto end;
509   }
510
511   res = STG_E_FILENOTFOUND;
512
513 end:
514   if (res == S_OK)
515     TRACE("<-- IStream %p\n", *ppstm);
516   TRACE("<-- %08x\n", res);
517   return res;
518 }
519
520 /************************************************************************
521  * Storage32BaseImpl_OpenStorage (IStorage)
522  *
523  * This method will open a new storage object from the current storage.
524  *
525  * See Windows documentation for more details on IStorage methods.
526  */
527 static HRESULT WINAPI StorageBaseImpl_OpenStorage(
528   IStorage*        iface,
529   const OLECHAR*   pwcsName,      /* [string][unique][in] */
530   IStorage*        pstgPriority,  /* [unique][in] */
531   DWORD            grfMode,       /* [in] */
532   SNB              snbExclude,    /* [unique][in] */
533   DWORD            reserved,      /* [in] */
534   IStorage**       ppstg)         /* [out] */
535 {
536   StorageBaseImpl *This = (StorageBaseImpl *)iface;
537   StorageInternalImpl* newStorage;
538   IEnumSTATSTGImpl*      propertyEnumeration;
539   StgProperty            currentProperty;
540   ULONG                  foundPropertyIndex;
541   HRESULT                res = STG_E_UNKNOWN;
542
543   TRACE("(%p, %s, %p, %x, %p, %d, %p)\n",
544         iface, debugstr_w(pwcsName), pstgPriority,
545         grfMode, snbExclude, reserved, ppstg);
546
547   /*
548    * Perform a sanity check on the parameters.
549    */
550   if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
551   {
552     res = E_INVALIDARG;
553     goto end;
554   }
555
556   /* as documented */
557   if (snbExclude != NULL)
558   {
559     res = STG_E_INVALIDPARAMETER;
560     goto end;
561   }
562
563   /*
564    * Validate the STGM flags
565    */
566   if ( FAILED( validateSTGM(grfMode) ))
567   {
568     res = STG_E_INVALIDFLAG;
569     goto end;
570   }
571
572   /*
573    * As documented.
574    */
575   if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
576         (grfMode & STGM_DELETEONRELEASE) ||
577         (grfMode & STGM_PRIORITY) )
578   {
579     res = STG_E_INVALIDFUNCTION;
580     goto end;
581   }
582
583   /*
584    * Check that we're compatible with the parent's storage mode,
585    * but only if we are not transacted
586    */
587   if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
588     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
589     {
590       res = STG_E_ACCESSDENIED;
591       goto end;
592     }
593   }
594
595   /*
596    * Initialize the out parameter
597    */
598   *ppstg = NULL;
599
600   /*
601    * Create a property enumeration to search the properties
602    */
603   propertyEnumeration = IEnumSTATSTGImpl_Construct(
604                           This->ancestorStorage,
605                           This->rootPropertySetIndex);
606
607   /*
608    * Search the enumeration for the property with the given name
609    */
610   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
611                          propertyEnumeration,
612                          pwcsName,
613                          &currentProperty);
614
615   /*
616    * Delete the property enumeration since we don't need it anymore
617    */
618   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
619
620   /*
621    * If it was found, construct the stream object and return a pointer to it.
622    */
623   if ( (foundPropertyIndex!=PROPERTY_NULL) &&
624        (currentProperty.propertyType==PROPTYPE_STORAGE) )
625   {
626     /*
627      * Construct a new Storage object
628      */
629     newStorage = StorageInternalImpl_Construct(
630                    This->ancestorStorage,
631                    grfMode,
632                    foundPropertyIndex);
633
634     if (newStorage != 0)
635     {
636       *ppstg = (IStorage*)newStorage;
637
638       /*
639        * Since we are returning a pointer to the interface,
640        * we have to nail down the reference.
641        */
642       StorageBaseImpl_AddRef(*ppstg);
643
644       res = S_OK;
645       goto end;
646     }
647
648     res = STG_E_INSUFFICIENTMEMORY;
649     goto end;
650   }
651
652   res = STG_E_FILENOTFOUND;
653
654 end:
655   TRACE("<-- %08x\n", res);
656   return res;
657 }
658
659 /************************************************************************
660  * Storage32BaseImpl_EnumElements (IStorage)
661  *
662  * This method will create an enumerator object that can be used to
663  * retrieve information about all the properties in the storage object.
664  *
665  * See Windows documentation for more details on IStorage methods.
666  */
667 static HRESULT WINAPI StorageBaseImpl_EnumElements(
668   IStorage*       iface,
669   DWORD           reserved1, /* [in] */
670   void*           reserved2, /* [size_is][unique][in] */
671   DWORD           reserved3, /* [in] */
672   IEnumSTATSTG**  ppenum)    /* [out] */
673 {
674   StorageBaseImpl *This = (StorageBaseImpl *)iface;
675   IEnumSTATSTGImpl* newEnum;
676
677   TRACE("(%p, %d, %p, %d, %p)\n",
678         iface, reserved1, reserved2, reserved3, ppenum);
679
680   /*
681    * Perform a sanity check on the parameters.
682    */
683   if ( (This==0) || (ppenum==0))
684     return E_INVALIDARG;
685
686   /*
687    * Construct the enumerator.
688    */
689   newEnum = IEnumSTATSTGImpl_Construct(
690               This->ancestorStorage,
691               This->rootPropertySetIndex);
692
693   if (newEnum!=0)
694   {
695     *ppenum = (IEnumSTATSTG*)newEnum;
696
697     /*
698      * Don't forget to nail down a reference to the new object before
699      * returning it.
700      */
701     IEnumSTATSTG_AddRef(*ppenum);
702
703     return S_OK;
704   }
705
706   return E_OUTOFMEMORY;
707 }
708
709 /************************************************************************
710  * Storage32BaseImpl_Stat (IStorage)
711  *
712  * This method will retrieve information about this storage object.
713  *
714  * See Windows documentation for more details on IStorage methods.
715  */
716 static HRESULT WINAPI StorageBaseImpl_Stat(
717   IStorage*        iface,
718   STATSTG*         pstatstg,     /* [out] */
719   DWORD            grfStatFlag)  /* [in] */
720 {
721   StorageBaseImpl *This = (StorageBaseImpl *)iface;
722   StgProperty    curProperty;
723   BOOL           readSuccessful;
724   HRESULT        res = STG_E_UNKNOWN;
725
726   TRACE("(%p, %p, %x)\n",
727         iface, pstatstg, grfStatFlag);
728
729   /*
730    * Perform a sanity check on the parameters.
731    */
732   if ( (This==0) || (pstatstg==0))
733   {
734     res = E_INVALIDARG;
735     goto end;
736   }
737
738   /*
739    * Read the information from the property.
740    */
741   readSuccessful = StorageImpl_ReadProperty(
742                     This->ancestorStorage,
743                     This->rootPropertySetIndex,
744                     &curProperty);
745
746   if (readSuccessful)
747   {
748     StorageUtl_CopyPropertyToSTATSTG(
749       pstatstg,
750       &curProperty,
751       grfStatFlag);
752
753     pstatstg->grfMode = This->openFlags;
754     pstatstg->grfStateBits = This->stateBits;
755
756     res = S_OK;
757     goto end;
758   }
759
760   res = E_FAIL;
761
762 end:
763   if (res == S_OK)
764   {
765     TRACE("<-- STATSTG: pwcsName: %s, type: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
766   }
767   TRACE("<-- %08x\n", res);
768   return res;
769 }
770
771 /************************************************************************
772  * Storage32BaseImpl_RenameElement (IStorage)
773  *
774  * This method will rename the specified element.
775  *
776  * See Windows documentation for more details on IStorage methods.
777  *
778  * Implementation notes: The method used to rename consists of creating a clone
779  *    of the deleted StgProperty object setting it with the new name and to
780  *    perform a DestroyElement of the old StgProperty.
781  */
782 static HRESULT WINAPI StorageBaseImpl_RenameElement(
783             IStorage*        iface,
784             const OLECHAR*   pwcsOldName,  /* [in] */
785             const OLECHAR*   pwcsNewName)  /* [in] */
786 {
787   StorageBaseImpl *This = (StorageBaseImpl *)iface;
788   IEnumSTATSTGImpl* propertyEnumeration;
789   StgProperty       currentProperty;
790   ULONG             foundPropertyIndex;
791
792   TRACE("(%p, %s, %s)\n",
793         iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
794
795   /*
796    * Create a property enumeration to search the properties
797    */
798   propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
799                                                    This->rootPropertySetIndex);
800
801   /*
802    * Search the enumeration for the new property name
803    */
804   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
805                                                      pwcsNewName,
806                                                      &currentProperty);
807
808   if (foundPropertyIndex != PROPERTY_NULL)
809   {
810     /*
811      * There is already a property with the new name
812      */
813     IEnumSTATSTGImpl_Destroy(propertyEnumeration);
814     return STG_E_FILEALREADYEXISTS;
815   }
816
817   IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration);
818
819   /*
820    * Search the enumeration for the old property name
821    */
822   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
823                                                      pwcsOldName,
824                                                      &currentProperty);
825
826   /*
827    * Delete the property enumeration since we don't need it anymore
828    */
829   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
830
831   if (foundPropertyIndex != PROPERTY_NULL)
832   {
833     StgProperty renamedProperty;
834     ULONG       renamedPropertyIndex;
835
836     /*
837      * Setup a new property for the renamed property
838      */
839     renamedProperty.sizeOfNameString =
840       ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
841
842     if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
843       return STG_E_INVALIDNAME;
844
845     strcpyW(renamedProperty.name, pwcsNewName);
846
847     renamedProperty.propertyType  = currentProperty.propertyType;
848     renamedProperty.startingBlock = currentProperty.startingBlock;
849     renamedProperty.size.u.LowPart  = currentProperty.size.u.LowPart;
850     renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart;
851
852     renamedProperty.previousProperty = PROPERTY_NULL;
853     renamedProperty.nextProperty     = PROPERTY_NULL;
854
855     /*
856      * Bring the dirProperty link in case it is a storage and in which
857      * case the renamed storage elements don't require to be reorganized.
858      */
859     renamedProperty.dirProperty = currentProperty.dirProperty;
860
861     /* call CoFileTime to get the current time
862     renamedProperty.timeStampS1
863     renamedProperty.timeStampD1
864     renamedProperty.timeStampS2
865     renamedProperty.timeStampD2
866     renamedProperty.propertyUniqueID
867     */
868
869     /*
870      * Obtain a free property in the property chain
871      */
872     renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
873
874     /*
875      * Save the new property into the new property spot
876      */
877     StorageImpl_WriteProperty(
878       This->ancestorStorage,
879       renamedPropertyIndex,
880       &renamedProperty);
881
882     /*
883      * Find a spot in the property chain for our newly created property.
884      */
885     updatePropertyChain(
886       (StorageImpl*)This,
887       renamedPropertyIndex,
888       renamedProperty);
889
890     /*
891      * At this point the renamed property has been inserted in the tree,
892      * now, before Destroying the old property we must zero its dirProperty
893      * otherwise the DestroyProperty below will zap it all and we do not want
894      * this to happen.
895      * Also, we fake that the old property is a storage so the DestroyProperty
896      * will not do a SetSize(0) on the stream data.
897      *
898      * This means that we need to tweak the StgProperty if it is a stream or a
899      * non empty storage.
900      */
901     StorageImpl_ReadProperty(This->ancestorStorage,
902                              foundPropertyIndex,
903                              &currentProperty);
904
905     currentProperty.dirProperty  = PROPERTY_NULL;
906     currentProperty.propertyType = PROPTYPE_STORAGE;
907     StorageImpl_WriteProperty(
908       This->ancestorStorage,
909       foundPropertyIndex,
910       &currentProperty);
911
912     /*
913      * Invoke Destroy to get rid of the ole property and automatically redo
914      * the linking of its previous and next members...
915      */
916     IStorage_DestroyElement(iface, pwcsOldName);
917
918   }
919   else
920   {
921     /*
922      * There is no property with the old name
923      */
924     return STG_E_FILENOTFOUND;
925   }
926
927   return S_OK;
928 }
929
930 /************************************************************************
931  * Storage32BaseImpl_CreateStream (IStorage)
932  *
933  * This method will create a stream object within this storage
934  *
935  * See Windows documentation for more details on IStorage methods.
936  */
937 static HRESULT WINAPI StorageBaseImpl_CreateStream(
938             IStorage*        iface,
939             const OLECHAR*   pwcsName,  /* [string][in] */
940             DWORD            grfMode,   /* [in] */
941             DWORD            reserved1, /* [in] */
942             DWORD            reserved2, /* [in] */
943             IStream**        ppstm)     /* [out] */
944 {
945   StorageBaseImpl *This = (StorageBaseImpl *)iface;
946   IEnumSTATSTGImpl* propertyEnumeration;
947   StgStreamImpl*    newStream;
948   StgProperty       currentProperty, newStreamProperty;
949   ULONG             foundPropertyIndex, newPropertyIndex;
950
951   TRACE("(%p, %s, %x, %d, %d, %p)\n",
952         iface, debugstr_w(pwcsName), grfMode,
953         reserved1, reserved2, ppstm);
954
955   /*
956    * Validate parameters
957    */
958   if (ppstm == 0)
959     return STG_E_INVALIDPOINTER;
960
961   if (pwcsName == 0)
962     return STG_E_INVALIDNAME;
963
964   if (reserved1 || reserved2)
965     return STG_E_INVALIDPARAMETER;
966
967   /*
968    * Validate the STGM flags
969    */
970   if ( FAILED( validateSTGM(grfMode) ))
971     return STG_E_INVALIDFLAG;
972
973   if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) 
974     return STG_E_INVALIDFLAG;
975
976   /*
977    * As documented.
978    */
979   if ((grfMode & STGM_DELETEONRELEASE) ||
980       (grfMode & STGM_TRANSACTED))
981     return STG_E_INVALIDFUNCTION;
982
983   /* Can't create a stream on read-only storage */
984   if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
985     return STG_E_ACCESSDENIED;
986
987   /*
988    * Check that we're compatible with the parent's storage mode
989    * if not in transacted mode
990    */
991   if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
992     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
993       return STG_E_ACCESSDENIED;
994   }
995
996   if(This->ancestorStorage->base.openFlags & STGM_SIMPLE)
997     if(grfMode & STGM_CREATE) return STG_E_INVALIDFLAG;
998
999   /*
1000    * Initialize the out parameter
1001    */
1002   *ppstm = 0;
1003
1004   /*
1005    * Create a property enumeration to search the properties
1006    */
1007   propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
1008                                                    This->rootPropertySetIndex);
1009
1010   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1011                                                      pwcsName,
1012                                                      &currentProperty);
1013
1014   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1015
1016   if (foundPropertyIndex != PROPERTY_NULL)
1017   {
1018     /*
1019      * An element with this name already exists
1020      */
1021     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
1022     {
1023       StgStreamImpl *strm;
1024
1025       LIST_FOR_EACH_ENTRY(strm, &This->strmHead, StgStreamImpl, StrmListEntry)
1026       {
1027         if (strm->ownerProperty == foundPropertyIndex)
1028         {
1029           TRACE("Stream deleted %p\n", strm);
1030           strm->parentStorage = NULL;
1031           list_remove(&strm->StrmListEntry);
1032         }
1033       }
1034       IStorage_DestroyElement(iface, pwcsName);
1035     }
1036     else
1037       return STG_E_FILEALREADYEXISTS;
1038   }
1039   else if (STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
1040   {
1041     WARN("read-only storage\n");
1042     return STG_E_ACCESSDENIED;
1043   }
1044
1045   /*
1046    * memset the empty property
1047    */
1048   memset(&newStreamProperty, 0, sizeof(StgProperty));
1049
1050   newStreamProperty.sizeOfNameString =
1051       ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
1052
1053   if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1054     return STG_E_INVALIDNAME;
1055
1056   strcpyW(newStreamProperty.name, pwcsName);
1057
1058   newStreamProperty.propertyType  = PROPTYPE_STREAM;
1059   newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
1060   newStreamProperty.size.u.LowPart  = 0;
1061   newStreamProperty.size.u.HighPart = 0;
1062
1063   newStreamProperty.previousProperty = PROPERTY_NULL;
1064   newStreamProperty.nextProperty     = PROPERTY_NULL;
1065   newStreamProperty.dirProperty      = PROPERTY_NULL;
1066
1067   /* call CoFileTime to get the current time
1068   newStreamProperty.timeStampS1
1069   newStreamProperty.timeStampD1
1070   newStreamProperty.timeStampS2
1071   newStreamProperty.timeStampD2
1072   */
1073
1074   /*  newStreamProperty.propertyUniqueID */
1075
1076   /*
1077    * Get a free property or create a new one
1078    */
1079   newPropertyIndex = getFreeProperty(This->ancestorStorage);
1080
1081   /*
1082    * Save the new property into the new property spot
1083    */
1084   StorageImpl_WriteProperty(
1085     This->ancestorStorage,
1086     newPropertyIndex,
1087     &newStreamProperty);
1088
1089   /*
1090    * Find a spot in the property chain for our newly created property.
1091    */
1092   updatePropertyChain(
1093     (StorageImpl*)This,
1094     newPropertyIndex,
1095     newStreamProperty);
1096
1097   /*
1098    * Open the stream to return it.
1099    */
1100   newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
1101
1102   if (newStream != 0)
1103   {
1104     *ppstm = (IStream*)newStream;
1105
1106     /*
1107      * Since we are returning a pointer to the interface, we have to nail down
1108      * the reference.
1109      */
1110     IStream_AddRef(*ppstm);
1111   }
1112   else
1113   {
1114     return STG_E_INSUFFICIENTMEMORY;
1115   }
1116
1117   return S_OK;
1118 }
1119
1120 /************************************************************************
1121  * Storage32BaseImpl_SetClass (IStorage)
1122  *
1123  * This method will write the specified CLSID in the property of this
1124  * storage.
1125  *
1126  * See Windows documentation for more details on IStorage methods.
1127  */
1128 static HRESULT WINAPI StorageBaseImpl_SetClass(
1129   IStorage*        iface,
1130   REFCLSID         clsid) /* [in] */
1131 {
1132   StorageBaseImpl *This = (StorageBaseImpl *)iface;
1133   HRESULT hRes = E_FAIL;
1134   StgProperty curProperty;
1135   BOOL success;
1136
1137   TRACE("(%p, %p)\n", iface, clsid);
1138
1139   success = StorageImpl_ReadProperty(This->ancestorStorage,
1140                                        This->rootPropertySetIndex,
1141                                        &curProperty);
1142   if (success)
1143   {
1144     curProperty.propertyUniqueID = *clsid;
1145
1146     success =  StorageImpl_WriteProperty(This->ancestorStorage,
1147                                            This->rootPropertySetIndex,
1148                                            &curProperty);
1149     if (success)
1150       hRes = S_OK;
1151   }
1152
1153   return hRes;
1154 }
1155
1156 /************************************************************************
1157 ** Storage32Impl implementation
1158 */
1159
1160 /************************************************************************
1161  * Storage32Impl_CreateStorage (IStorage)
1162  *
1163  * This method will create the storage object within the provided storage.
1164  *
1165  * See Windows documentation for more details on IStorage methods.
1166  */
1167 static HRESULT WINAPI StorageImpl_CreateStorage(
1168   IStorage*      iface,
1169   const OLECHAR  *pwcsName, /* [string][in] */
1170   DWORD            grfMode,   /* [in] */
1171   DWORD            reserved1, /* [in] */
1172   DWORD            reserved2, /* [in] */
1173   IStorage       **ppstg)   /* [out] */
1174 {
1175   StorageImpl* const This=(StorageImpl*)iface;
1176
1177   IEnumSTATSTGImpl *propertyEnumeration;
1178   StgProperty      currentProperty;
1179   StgProperty      newProperty;
1180   ULONG            foundPropertyIndex;
1181   ULONG            newPropertyIndex;
1182   HRESULT          hr;
1183
1184   TRACE("(%p, %s, %x, %d, %d, %p)\n",
1185         iface, debugstr_w(pwcsName), grfMode,
1186         reserved1, reserved2, ppstg);
1187
1188   /*
1189    * Validate parameters
1190    */
1191   if (ppstg == 0)
1192     return STG_E_INVALIDPOINTER;
1193
1194   if (pwcsName == 0)
1195     return STG_E_INVALIDNAME;
1196
1197   /*
1198    * Initialize the out parameter
1199    */
1200   *ppstg = NULL;
1201
1202   /*
1203    * Validate the STGM flags
1204    */
1205   if ( FAILED( validateSTGM(grfMode) ) ||
1206        (grfMode & STGM_DELETEONRELEASE) )
1207   {
1208     WARN("bad grfMode: 0x%x\n", grfMode);
1209     return STG_E_INVALIDFLAG;
1210   }
1211
1212   /*
1213    * Check that we're compatible with the parent's storage mode
1214    */
1215   if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->base.openFlags ) )
1216   {
1217     WARN("access denied\n");
1218     return STG_E_ACCESSDENIED;
1219   }
1220
1221   /*
1222    * Create a property enumeration and search the properties
1223    */
1224   propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage,
1225                                                     This->base.rootPropertySetIndex);
1226
1227   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1228                                                      pwcsName,
1229                                                      &currentProperty);
1230   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1231
1232   if (foundPropertyIndex != PROPERTY_NULL)
1233   {
1234     /*
1235      * An element with this name already exists
1236      */
1237     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE &&
1238         STGM_ACCESS_MODE(This->base.openFlags) != STGM_READ)
1239     {
1240       hr = IStorage_DestroyElement(iface, pwcsName);
1241       if (FAILED(hr))
1242         return hr;
1243     }
1244     else
1245     {
1246       WARN("file already exists\n");
1247       return STG_E_FILEALREADYEXISTS;
1248     }
1249   }
1250   else if (STGM_ACCESS_MODE(This->base.openFlags) == STGM_READ)
1251   {
1252     WARN("read-only storage\n");
1253     return STG_E_ACCESSDENIED;
1254   }
1255
1256   /*
1257    * memset the empty property
1258    */
1259   memset(&newProperty, 0, sizeof(StgProperty));
1260
1261   newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1262
1263   if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1264   {
1265     FIXME("name too long\n");
1266     return STG_E_INVALIDNAME;
1267   }
1268
1269   strcpyW(newProperty.name, pwcsName);
1270
1271   newProperty.propertyType  = PROPTYPE_STORAGE;
1272   newProperty.startingBlock = BLOCK_END_OF_CHAIN;
1273   newProperty.size.u.LowPart  = 0;
1274   newProperty.size.u.HighPart = 0;
1275
1276   newProperty.previousProperty = PROPERTY_NULL;
1277   newProperty.nextProperty     = PROPERTY_NULL;
1278   newProperty.dirProperty      = PROPERTY_NULL;
1279
1280   /* call CoFileTime to get the current time
1281   newProperty.timeStampS1
1282   newProperty.timeStampD1
1283   newProperty.timeStampS2
1284   newProperty.timeStampD2
1285   */
1286
1287   /*  newStorageProperty.propertyUniqueID */
1288
1289   /*
1290    * Obtain a free property in the property chain
1291    */
1292   newPropertyIndex = getFreeProperty(This->base.ancestorStorage);
1293
1294   /*
1295    * Save the new property into the new property spot
1296    */
1297   StorageImpl_WriteProperty(
1298     This->base.ancestorStorage,
1299     newPropertyIndex,
1300     &newProperty);
1301
1302   /*
1303    * Find a spot in the property chain for our newly created property.
1304    */
1305   updatePropertyChain(
1306     This,
1307     newPropertyIndex,
1308     newProperty);
1309
1310   /*
1311    * Open it to get a pointer to return.
1312    */
1313   hr = IStorage_OpenStorage(iface, pwcsName, 0, grfMode, 0, 0, ppstg);
1314
1315   if( (hr != S_OK) || (*ppstg == NULL))
1316   {
1317     return hr;
1318   }
1319
1320
1321   return S_OK;
1322 }
1323
1324
1325 /***************************************************************************
1326  *
1327  * Internal Method
1328  *
1329  * Get a free property or create a new one.
1330  */
1331 static ULONG getFreeProperty(
1332   StorageImpl *storage)
1333 {
1334   ULONG       currentPropertyIndex = 0;
1335   ULONG       newPropertyIndex     = PROPERTY_NULL;
1336   BOOL      readSuccessful        = TRUE;
1337   StgProperty currentProperty;
1338
1339   do
1340   {
1341     /*
1342      * Start by reading the root property
1343      */
1344     readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage,
1345                                                currentPropertyIndex,
1346                                                &currentProperty);
1347     if (readSuccessful)
1348     {
1349       if (currentProperty.sizeOfNameString == 0)
1350       {
1351         /*
1352          * The property existis and is available, we found it.
1353          */
1354         newPropertyIndex = currentPropertyIndex;
1355       }
1356     }
1357     else
1358     {
1359       /*
1360        * We exhausted the property list, we will create more space below
1361        */
1362       newPropertyIndex = currentPropertyIndex;
1363     }
1364     currentPropertyIndex++;
1365
1366   } while (newPropertyIndex == PROPERTY_NULL);
1367
1368   /*
1369    * grow the property chain
1370    */
1371   if (! readSuccessful)
1372   {
1373     StgProperty    emptyProperty;
1374     ULARGE_INTEGER newSize;
1375     ULONG          propertyIndex;
1376     ULONG          lastProperty  = 0;
1377     ULONG          blockCount    = 0;
1378
1379     /*
1380      * obtain the new count of property blocks
1381      */
1382     blockCount = BlockChainStream_GetCount(
1383                    storage->base.ancestorStorage->rootBlockChain)+1;
1384
1385     /*
1386      * initialize the size used by the property stream
1387      */
1388     newSize.u.HighPart = 0;
1389     newSize.u.LowPart  = storage->bigBlockSize * blockCount;
1390
1391     /*
1392      * add a property block to the property chain
1393      */
1394     BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize);
1395
1396     /*
1397      * memset the empty property in order to initialize the unused newly
1398      * created property
1399      */
1400     memset(&emptyProperty, 0, sizeof(StgProperty));
1401
1402     /*
1403      * initialize them
1404      */
1405     lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1406
1407     for(
1408       propertyIndex = newPropertyIndex;
1409       propertyIndex < lastProperty;
1410       propertyIndex++)
1411     {
1412       StorageImpl_WriteProperty(
1413         storage->base.ancestorStorage,
1414         propertyIndex,
1415         &emptyProperty);
1416     }
1417   }
1418
1419   return newPropertyIndex;
1420 }
1421
1422 /****************************************************************************
1423  *
1424  * Internal Method
1425  *
1426  * Case insensitive comparison of StgProperty.name by first considering
1427  * their size.
1428  *
1429  * Returns <0 when newProperty < currentProperty
1430  *         >0 when newProperty > currentProperty
1431  *          0 when newProperty == currentProperty
1432  */
1433 static LONG propertyNameCmp(
1434     const OLECHAR *newProperty,
1435     const OLECHAR *currentProperty)
1436 {
1437   LONG diff      = lstrlenW(newProperty) - lstrlenW(currentProperty);
1438
1439   if (diff == 0)
1440   {
1441     /*
1442      * We compare the string themselves only when they are of the same length
1443      */
1444     diff = lstrcmpiW( newProperty, currentProperty);
1445   }
1446
1447   return diff;
1448 }
1449
1450 /****************************************************************************
1451  *
1452  * Internal Method
1453  *
1454  * Properly link this new element in the property chain.
1455  */
1456 static void updatePropertyChain(
1457   StorageImpl *storage,
1458   ULONG         newPropertyIndex,
1459   StgProperty   newProperty)
1460 {
1461   StgProperty currentProperty;
1462
1463   /*
1464    * Read the root property
1465    */
1466   StorageImpl_ReadProperty(storage->base.ancestorStorage,
1467                              storage->base.rootPropertySetIndex,
1468                              &currentProperty);
1469
1470   if (currentProperty.dirProperty != PROPERTY_NULL)
1471   {
1472     /*
1473      * The root storage contains some element, therefore, start the research
1474      * for the appropriate location.
1475      */
1476     BOOL found = 0;
1477     ULONG  current, next, previous, currentPropertyId;
1478
1479     /*
1480      * Keep the StgProperty sequence number of the storage first property
1481      */
1482     currentPropertyId = currentProperty.dirProperty;
1483
1484     /*
1485      * Read
1486      */
1487     StorageImpl_ReadProperty(storage->base.ancestorStorage,
1488                                currentProperty.dirProperty,
1489                                &currentProperty);
1490
1491     previous = currentProperty.previousProperty;
1492     next     = currentProperty.nextProperty;
1493     current  = currentPropertyId;
1494
1495     while (found == 0)
1496     {
1497       LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1498
1499       if (diff < 0)
1500       {
1501         if (previous != PROPERTY_NULL)
1502         {
1503           StorageImpl_ReadProperty(storage->base.ancestorStorage,
1504                                      previous,
1505                                      &currentProperty);
1506           current = previous;
1507         }
1508         else
1509         {
1510           currentProperty.previousProperty = newPropertyIndex;
1511           StorageImpl_WriteProperty(storage->base.ancestorStorage,
1512                                       current,
1513                                       &currentProperty);
1514           found = 1;
1515         }
1516       }
1517       else if (diff > 0)
1518       {
1519         if (next != PROPERTY_NULL)
1520         {
1521           StorageImpl_ReadProperty(storage->base.ancestorStorage,
1522                                      next,
1523                                      &currentProperty);
1524           current = next;
1525         }
1526         else
1527         {
1528           currentProperty.nextProperty = newPropertyIndex;
1529           StorageImpl_WriteProperty(storage->base.ancestorStorage,
1530                                       current,
1531                                       &currentProperty);
1532           found = 1;
1533         }
1534       }
1535       else
1536       {
1537         /*
1538          * Trying to insert an item with the same name in the
1539          * subtree structure.
1540          */
1541         assert(FALSE);
1542       }
1543
1544       previous = currentProperty.previousProperty;
1545       next     = currentProperty.nextProperty;
1546     }
1547   }
1548   else
1549   {
1550     /*
1551      * The root storage is empty, link the new property to its dir property
1552      */
1553     currentProperty.dirProperty = newPropertyIndex;
1554     StorageImpl_WriteProperty(storage->base.ancestorStorage,
1555                                 storage->base.rootPropertySetIndex,
1556                                 &currentProperty);
1557   }
1558 }
1559
1560
1561 /*************************************************************************
1562  * CopyTo (IStorage)
1563  */
1564 static HRESULT WINAPI StorageImpl_CopyTo(
1565   IStorage*   iface,
1566   DWORD       ciidExclude,  /* [in] */
1567   const IID*  rgiidExclude, /* [size_is][unique][in] */
1568   SNB         snbExclude,   /* [unique][in] */
1569   IStorage*   pstgDest)     /* [unique][in] */
1570 {
1571   IEnumSTATSTG *elements     = 0;
1572   STATSTG      curElement, strStat;
1573   HRESULT      hr;
1574   IStorage     *pstgTmp, *pstgChild;
1575   IStream      *pstrTmp, *pstrChild;
1576
1577   if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
1578     FIXME("Exclude option not implemented\n");
1579
1580   TRACE("(%p, %d, %p, %p, %p)\n",
1581         iface, ciidExclude, rgiidExclude,
1582         snbExclude, pstgDest);
1583
1584   /*
1585    * Perform a sanity check
1586    */
1587   if ( pstgDest == 0 )
1588     return STG_E_INVALIDPOINTER;
1589
1590   /*
1591    * Enumerate the elements
1592    */
1593   hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1594
1595   if ( hr != S_OK )
1596     return hr;
1597
1598   /*
1599    * set the class ID
1600    */
1601   IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1602   IStorage_SetClass( pstgDest, &curElement.clsid );
1603
1604   do
1605   {
1606     /*
1607      * Obtain the next element
1608      */
1609     hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1610
1611     if ( hr == S_FALSE )
1612     {
1613       hr = S_OK;   /* done, every element has been copied */
1614       break;
1615     }
1616
1617     if (curElement.type == STGTY_STORAGE)
1618     {
1619       /*
1620        * open child source storage
1621        */
1622       hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1623                                  STGM_READ|STGM_SHARE_EXCLUSIVE,
1624                                  NULL, 0, &pstgChild );
1625
1626       if (hr != S_OK)
1627         break;
1628
1629       /*
1630        * Check if destination storage is not a child of the source
1631        * storage, which will cause an infinite loop
1632        */
1633       if (pstgChild == pstgDest)
1634       {
1635         IEnumSTATSTG_Release(elements);
1636
1637         return STG_E_ACCESSDENIED;
1638       }
1639
1640       /*
1641        * create a new storage in destination storage
1642        */
1643       hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1644                                    STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1645                                    0, 0,
1646                                    &pstgTmp );
1647       /*
1648        * if it already exist, don't create a new one use this one
1649        */
1650       if (hr == STG_E_FILEALREADYEXISTS)
1651       {
1652         hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1653                                    STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1654                                    NULL, 0, &pstgTmp );
1655       }
1656
1657       if (hr != S_OK)
1658         break;
1659
1660
1661       /*
1662        * do the copy recursively
1663        */
1664       hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1665                                snbExclude, pstgTmp );
1666
1667       IStorage_Release( pstgTmp );
1668       IStorage_Release( pstgChild );
1669     }
1670     else if (curElement.type == STGTY_STREAM)
1671     {
1672       /*
1673        * create a new stream in destination storage. If the stream already
1674        * exist, it will be deleted and a new one will be created.
1675        */
1676       hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1677                                   STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1678                                   0, 0, &pstrTmp );
1679
1680       if (hr != S_OK)
1681         break;
1682
1683       /*
1684        * open child stream storage
1685        */
1686       hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
1687                                 STGM_READ|STGM_SHARE_EXCLUSIVE,
1688                                 0, &pstrChild );
1689
1690       if (hr != S_OK)
1691         break;
1692
1693       /*
1694        * Get the size of the source stream
1695        */
1696       IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1697
1698       /*
1699        * Set the size of the destination stream.
1700        */
1701       IStream_SetSize(pstrTmp, strStat.cbSize);
1702
1703       /*
1704        * do the copy
1705        */
1706       hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1707                            NULL, NULL );
1708
1709       IStream_Release( pstrTmp );
1710       IStream_Release( pstrChild );
1711     }
1712     else
1713     {
1714       WARN("unknown element type: %d\n", curElement.type);
1715     }
1716
1717   } while (hr == S_OK);
1718
1719   /*
1720    * Clean-up
1721    */
1722   IEnumSTATSTG_Release(elements);
1723
1724   return hr;
1725 }
1726
1727 /*************************************************************************
1728  * MoveElementTo (IStorage)
1729  */
1730 static HRESULT WINAPI StorageImpl_MoveElementTo(
1731   IStorage*     iface,
1732   const OLECHAR *pwcsName,   /* [string][in] */
1733   IStorage      *pstgDest,   /* [unique][in] */
1734   const OLECHAR *pwcsNewName,/* [string][in] */
1735   DWORD           grfFlags)    /* [in] */
1736 {
1737   FIXME("(%p %s %p %s %u): stub\n", iface,
1738          debugstr_w(pwcsName), pstgDest,
1739          debugstr_w(pwcsNewName), grfFlags);
1740   return E_NOTIMPL;
1741 }
1742
1743 /*************************************************************************
1744  * Commit (IStorage)
1745  *
1746  * Ensures that any changes made to a storage object open in transacted mode
1747  * are reflected in the parent storage
1748  *
1749  * NOTES
1750  *  Wine doesn't implement transacted mode, which seems to be a basic
1751  *  optimization, so we can ignore this stub for now.
1752  */
1753 static HRESULT WINAPI StorageImpl_Commit(
1754   IStorage*   iface,
1755   DWORD         grfCommitFlags)/* [in] */
1756 {
1757   FIXME("(%p %d): stub\n", iface, grfCommitFlags);
1758   return S_OK;
1759 }
1760
1761 /*************************************************************************
1762  * Revert (IStorage)
1763  *
1764  * Discard all changes that have been made since the last commit operation
1765  */
1766 static HRESULT WINAPI StorageImpl_Revert(
1767   IStorage* iface)
1768 {
1769   FIXME("(%p): stub\n", iface);
1770   return E_NOTIMPL;
1771 }
1772
1773 /*************************************************************************
1774  * DestroyElement (IStorage)
1775  *
1776  * Strategy: This implementation is built this way for simplicity not for speed.
1777  *          I always delete the topmost element of the enumeration and adjust
1778  *          the deleted element pointer all the time.  This takes longer to
1779  *          do but allow to reinvoke DestroyElement whenever we encounter a
1780  *          storage object.  The optimisation resides in the usage of another
1781  *          enumeration strategy that would give all the leaves of a storage
1782  *          first. (postfix order)
1783  */
1784 static HRESULT WINAPI StorageImpl_DestroyElement(
1785   IStorage*     iface,
1786   const OLECHAR *pwcsName)/* [string][in] */
1787 {
1788   StorageImpl* const This=(StorageImpl*)iface;
1789
1790   IEnumSTATSTGImpl* propertyEnumeration;
1791   HRESULT           hr = S_OK;
1792   BOOL            res;
1793   StgProperty       propertyToDelete;
1794   StgProperty       parentProperty;
1795   ULONG             foundPropertyIndexToDelete;
1796   ULONG             typeOfRelation;
1797   ULONG             parentPropertyId = 0;
1798
1799   TRACE("(%p, %s)\n",
1800         iface, debugstr_w(pwcsName));
1801
1802   /*
1803    * Perform a sanity check on the parameters.
1804    */
1805   if (pwcsName==NULL)
1806     return STG_E_INVALIDPOINTER;
1807
1808   if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
1809     return STG_E_ACCESSDENIED;
1810
1811   /*
1812    * Create a property enumeration to search the property with the given name
1813    */
1814   propertyEnumeration = IEnumSTATSTGImpl_Construct(
1815     This->base.ancestorStorage,
1816     This->base.rootPropertySetIndex);
1817
1818   foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1819     propertyEnumeration,
1820     pwcsName,
1821     &propertyToDelete);
1822
1823   IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1824
1825   if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1826   {
1827     return STG_E_FILENOTFOUND;
1828   }
1829
1830   /*
1831    * Find the parent property of the property to delete (the one that
1832    * link to it).  If This->dirProperty == foundPropertyIndexToDelete,
1833    * the parent is This. Otherwise, the parent is one of its sibling...
1834    */
1835
1836   /*
1837    * First, read This's StgProperty..
1838    */
1839   res = StorageImpl_ReadProperty(
1840           This->base.ancestorStorage,
1841           This->base.rootPropertySetIndex,
1842           &parentProperty);
1843
1844   assert(res);
1845
1846   /*
1847    * Second, check to see if by any chance the actual storage (This) is not
1848    * the parent of the property to delete... We never know...
1849    */
1850   if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1851   {
1852     /*
1853      * Set data as it would have been done in the else part...
1854      */
1855     typeOfRelation   = PROPERTY_RELATION_DIR;
1856     parentPropertyId = This->base.rootPropertySetIndex;
1857   }
1858   else
1859   {
1860     /*
1861      * Create a property enumeration to search the parent properties, and
1862      * delete it once done.
1863      */
1864     IEnumSTATSTGImpl* propertyEnumeration2;
1865
1866     propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1867       This->base.ancestorStorage,
1868       This->base.rootPropertySetIndex);
1869
1870     typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1871       propertyEnumeration2,
1872       foundPropertyIndexToDelete,
1873       &parentProperty,
1874       &parentPropertyId);
1875
1876     IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1877   }
1878
1879   if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1880   {
1881     hr = deleteStorageProperty(
1882            This,
1883            foundPropertyIndexToDelete,
1884            propertyToDelete);
1885   }
1886   else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1887   {
1888     hr = deleteStreamProperty(
1889            This,
1890            foundPropertyIndexToDelete,
1891            propertyToDelete);
1892   }
1893
1894   if (hr!=S_OK)
1895     return hr;
1896
1897   /*
1898    * Adjust the property chain
1899    */
1900   hr = adjustPropertyChain(
1901         This,
1902         propertyToDelete,
1903         parentProperty,
1904         parentPropertyId,
1905         typeOfRelation);
1906
1907   return hr;
1908 }
1909
1910
1911 /************************************************************************
1912  * StorageImpl_Stat (IStorage)
1913  *
1914  * This method will retrieve information about this storage object.
1915  *
1916  * See Windows documentation for more details on IStorage methods.
1917  */
1918 static HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
1919                                  STATSTG*  pstatstg,     /* [out] */
1920                                  DWORD     grfStatFlag)  /* [in] */
1921 {
1922   StorageImpl* const This = (StorageImpl*)iface;
1923   HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag );
1924
1925   if ( SUCCEEDED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName )
1926   {
1927       CoTaskMemFree(pstatstg->pwcsName);
1928       pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
1929       strcpyW(pstatstg->pwcsName, This->pwcsName);
1930   }
1931
1932   return result;
1933 }
1934
1935 /******************************************************************************
1936  * Internal stream list handlers
1937  */
1938
1939 void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm)
1940 {
1941   TRACE("Stream added (stg=%p strm=%p)\n", stg, strm);
1942   list_add_tail(&stg->strmHead,&strm->StrmListEntry);
1943 }
1944
1945 void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm)
1946 {
1947   TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm);
1948   list_remove(&(strm->StrmListEntry));
1949 }
1950
1951 static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg)
1952 {
1953   struct list *cur, *cur2;
1954   StgStreamImpl *strm=NULL;
1955
1956   LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) {
1957     strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry);
1958     TRACE("Streams deleted (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev);
1959     strm->parentStorage = NULL;
1960     list_remove(cur);
1961   }
1962 }
1963
1964
1965 /*********************************************************************
1966  *
1967  * Internal Method
1968  *
1969  * Perform the deletion of a complete storage node
1970  *
1971  */
1972 static HRESULT deleteStorageProperty(
1973   StorageImpl *parentStorage,
1974   ULONG        indexOfPropertyToDelete,
1975   StgProperty  propertyToDelete)
1976 {
1977   IEnumSTATSTG *elements     = 0;
1978   IStorage   *childStorage = 0;
1979   STATSTG      currentElement;
1980   HRESULT      hr;
1981   HRESULT      destroyHr = S_OK;
1982
1983   /*
1984    * Open the storage and enumerate it
1985    */
1986   hr = StorageBaseImpl_OpenStorage(
1987         (IStorage*)parentStorage,
1988         propertyToDelete.name,
1989         0,
1990         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
1991         0,
1992         0,
1993         &childStorage);
1994
1995   if (hr != S_OK)
1996   {
1997     return hr;
1998   }
1999
2000   /*
2001    * Enumerate the elements
2002    */
2003   IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
2004
2005   do
2006   {
2007     /*
2008      * Obtain the next element
2009      */
2010     hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
2011     if (hr==S_OK)
2012     {
2013       destroyHr = StorageImpl_DestroyElement(childStorage, currentElement.pwcsName);
2014
2015       CoTaskMemFree(currentElement.pwcsName);
2016     }
2017
2018     /*
2019      * We need to Reset the enumeration every time because we delete elements
2020      * and the enumeration could be invalid
2021      */
2022     IEnumSTATSTG_Reset(elements);
2023
2024   } while ((hr == S_OK) && (destroyHr == S_OK));
2025
2026   /*
2027    * Invalidate the property by zeroing its name member.
2028    */
2029   propertyToDelete.sizeOfNameString = 0;
2030
2031   StorageImpl_WriteProperty(parentStorage->base.ancestorStorage,
2032                             indexOfPropertyToDelete,
2033                             &propertyToDelete);
2034
2035   IStorage_Release(childStorage);
2036   IEnumSTATSTG_Release(elements);
2037
2038   return destroyHr;
2039 }
2040
2041 /*********************************************************************
2042  *
2043  * Internal Method
2044  *
2045  * Perform the deletion of a stream node
2046  *
2047  */
2048 static HRESULT deleteStreamProperty(
2049   StorageImpl *parentStorage,
2050   ULONG         indexOfPropertyToDelete,
2051   StgProperty   propertyToDelete)
2052 {
2053   IStream      *pis;
2054   HRESULT        hr;
2055   ULARGE_INTEGER size;
2056
2057   size.u.HighPart = 0;
2058   size.u.LowPart = 0;
2059
2060   hr = StorageBaseImpl_OpenStream((IStorage*)parentStorage,
2061         propertyToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis);
2062
2063   if (hr!=S_OK)
2064   {
2065     return(hr);
2066   }
2067
2068   /*
2069    * Zap the stream
2070    */
2071   hr = IStream_SetSize(pis, size);
2072
2073   if(hr != S_OK)
2074   {
2075     return hr;
2076   }
2077
2078   /*
2079    * Release the stream object.
2080    */
2081   IStream_Release(pis);
2082
2083   /*
2084    * Invalidate the property by zeroing its name member.
2085    */
2086   propertyToDelete.sizeOfNameString = 0;
2087
2088   /*
2089    * Here we should re-read the property so we get the updated pointer
2090    * but since we are here to zap it, I don't do it...
2091    */
2092   StorageImpl_WriteProperty(
2093     parentStorage->base.ancestorStorage,
2094     indexOfPropertyToDelete,
2095     &propertyToDelete);
2096
2097   return S_OK;
2098 }
2099
2100 /*********************************************************************
2101  *
2102  * Internal Method
2103  *
2104  * Finds a placeholder for the StgProperty within the Storage
2105  *
2106  */
2107 static HRESULT findPlaceholder(
2108   StorageImpl *storage,
2109   ULONG         propertyIndexToStore,
2110   ULONG         storePropertyIndex,
2111   INT         typeOfRelation)
2112 {
2113   StgProperty storeProperty;
2114   BOOL      res = TRUE;
2115
2116   /*
2117    * Read the storage property
2118    */
2119   res = StorageImpl_ReadProperty(
2120           storage->base.ancestorStorage,
2121           storePropertyIndex,
2122           &storeProperty);
2123
2124   if(! res)
2125   {
2126     return E_FAIL;
2127   }
2128
2129   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
2130   {
2131     if (storeProperty.previousProperty != PROPERTY_NULL)
2132     {
2133       return findPlaceholder(
2134                storage,
2135                propertyIndexToStore,
2136                storeProperty.previousProperty,
2137                typeOfRelation);
2138     }
2139     else
2140     {
2141       storeProperty.previousProperty = propertyIndexToStore;
2142     }
2143   }
2144   else if (typeOfRelation == PROPERTY_RELATION_NEXT)
2145   {
2146     if (storeProperty.nextProperty != PROPERTY_NULL)
2147     {
2148       return findPlaceholder(
2149                storage,
2150                propertyIndexToStore,
2151                storeProperty.nextProperty,
2152                typeOfRelation);
2153     }
2154     else
2155     {
2156       storeProperty.nextProperty = propertyIndexToStore;
2157     }
2158   }
2159   else if (typeOfRelation == PROPERTY_RELATION_DIR)
2160   {
2161     if (storeProperty.dirProperty != PROPERTY_NULL)
2162     {
2163       return findPlaceholder(
2164                storage,
2165                propertyIndexToStore,
2166                storeProperty.dirProperty,
2167                typeOfRelation);
2168     }
2169     else
2170     {
2171       storeProperty.dirProperty = propertyIndexToStore;
2172     }
2173   }
2174
2175   res = StorageImpl_WriteProperty(
2176          storage->base.ancestorStorage,
2177          storePropertyIndex,
2178          &storeProperty);
2179
2180   if(!res)
2181   {
2182     return E_FAIL;
2183   }
2184
2185   return S_OK;
2186 }
2187
2188 /*************************************************************************
2189  *
2190  * Internal Method
2191  *
2192  * This method takes the previous and the next property link of a property
2193  * to be deleted and find them a place in the Storage.
2194  */
2195 static HRESULT adjustPropertyChain(
2196   StorageImpl *This,
2197   StgProperty   propertyToDelete,
2198   StgProperty   parentProperty,
2199   ULONG         parentPropertyId,
2200   INT         typeOfRelation)
2201 {
2202   ULONG   newLinkProperty        = PROPERTY_NULL;
2203   BOOL  needToFindAPlaceholder = FALSE;
2204   ULONG   storeNode              = PROPERTY_NULL;
2205   ULONG   toStoreNode            = PROPERTY_NULL;
2206   INT   relationType           = 0;
2207   HRESULT hr                     = S_OK;
2208   BOOL  res                    = TRUE;
2209
2210   if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
2211   {
2212     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2213     {
2214       /*
2215        * Set the parent previous to the property to delete previous
2216        */
2217       newLinkProperty = propertyToDelete.previousProperty;
2218
2219       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2220       {
2221         /*
2222          * We also need to find a storage for the other link, setup variables
2223          * to do this at the end...
2224          */
2225         needToFindAPlaceholder = TRUE;
2226         storeNode              = propertyToDelete.previousProperty;
2227         toStoreNode            = propertyToDelete.nextProperty;
2228         relationType           = PROPERTY_RELATION_NEXT;
2229       }
2230     }
2231     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2232     {
2233       /*
2234        * Set the parent previous to the property to delete next
2235        */
2236       newLinkProperty = propertyToDelete.nextProperty;
2237     }
2238
2239     /*
2240      * Link it for real...
2241      */
2242     parentProperty.previousProperty = newLinkProperty;
2243
2244   }
2245   else if (typeOfRelation == PROPERTY_RELATION_NEXT)
2246   {
2247     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2248     {
2249       /*
2250        * Set the parent next to the property to delete next previous
2251        */
2252       newLinkProperty = propertyToDelete.previousProperty;
2253
2254       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2255       {
2256         /*
2257          * We also need to find a storage for the other link, setup variables
2258          * to do this at the end...
2259          */
2260         needToFindAPlaceholder = TRUE;
2261         storeNode              = propertyToDelete.previousProperty;
2262         toStoreNode            = propertyToDelete.nextProperty;
2263         relationType           = PROPERTY_RELATION_NEXT;
2264       }
2265     }
2266     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2267     {
2268       /*
2269        * Set the parent next to the property to delete next
2270        */
2271       newLinkProperty = propertyToDelete.nextProperty;
2272     }
2273
2274     /*
2275      * Link it for real...
2276      */
2277     parentProperty.nextProperty = newLinkProperty;
2278   }
2279   else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2280   {
2281     if (propertyToDelete.previousProperty != PROPERTY_NULL)
2282     {
2283       /*
2284        * Set the parent dir to the property to delete previous
2285        */
2286       newLinkProperty = propertyToDelete.previousProperty;
2287
2288       if (propertyToDelete.nextProperty != PROPERTY_NULL)
2289       {
2290         /*
2291          * We also need to find a storage for the other link, setup variables
2292          * to do this at the end...
2293          */
2294         needToFindAPlaceholder = TRUE;
2295         storeNode              = propertyToDelete.previousProperty;
2296         toStoreNode            = propertyToDelete.nextProperty;
2297         relationType           = PROPERTY_RELATION_NEXT;
2298       }
2299     }
2300     else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2301     {
2302       /*
2303        * Set the parent dir to the property to delete next
2304        */
2305       newLinkProperty = propertyToDelete.nextProperty;
2306     }
2307
2308     /*
2309      * Link it for real...
2310      */
2311     parentProperty.dirProperty = newLinkProperty;
2312   }
2313
2314   /*
2315    * Write back the parent property
2316    */
2317   res = StorageImpl_WriteProperty(
2318           This->base.ancestorStorage,
2319           parentPropertyId,
2320           &parentProperty);
2321   if(! res)
2322   {
2323     return E_FAIL;
2324   }
2325
2326   /*
2327    * If a placeholder is required for the other link, then, find one and
2328    * get out of here...
2329    */
2330   if (needToFindAPlaceholder)
2331   {
2332     hr = findPlaceholder(
2333            This,
2334            toStoreNode,
2335            storeNode,
2336            relationType);
2337   }
2338
2339   return hr;
2340 }
2341
2342
2343 /******************************************************************************
2344  * SetElementTimes (IStorage)
2345  */
2346 static HRESULT WINAPI StorageImpl_SetElementTimes(
2347   IStorage*     iface,
2348   const OLECHAR *pwcsName,/* [string][in] */
2349   const FILETIME  *pctime,  /* [in] */
2350   const FILETIME  *patime,  /* [in] */
2351   const FILETIME  *pmtime)  /* [in] */
2352 {
2353   FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));
2354   return S_OK;
2355 }
2356
2357 /******************************************************************************
2358  * SetStateBits (IStorage)
2359  */
2360 static HRESULT WINAPI StorageImpl_SetStateBits(
2361   IStorage*   iface,
2362   DWORD         grfStateBits,/* [in] */
2363   DWORD         grfMask)     /* [in] */
2364 {
2365   StorageImpl* const This = (StorageImpl*)iface;
2366   This->base.stateBits = (This->base.stateBits & ~grfMask) | (grfStateBits & grfMask);
2367   return S_OK;
2368 }
2369
2370 /*
2371  * Virtual function table for the IStorage32Impl class.
2372  */
2373 static const IStorageVtbl Storage32Impl_Vtbl =
2374 {
2375     StorageBaseImpl_QueryInterface,
2376     StorageBaseImpl_AddRef,
2377     StorageBaseImpl_Release,
2378     StorageBaseImpl_CreateStream,
2379     StorageBaseImpl_OpenStream,
2380     StorageImpl_CreateStorage,
2381     StorageBaseImpl_OpenStorage,
2382     StorageImpl_CopyTo,
2383     StorageImpl_MoveElementTo,
2384     StorageImpl_Commit,
2385     StorageImpl_Revert,
2386     StorageBaseImpl_EnumElements,
2387     StorageImpl_DestroyElement,
2388     StorageBaseImpl_RenameElement,
2389     StorageImpl_SetElementTimes,
2390     StorageBaseImpl_SetClass,
2391     StorageImpl_SetStateBits,
2392     StorageImpl_Stat
2393 };
2394
2395 static HRESULT StorageImpl_Construct(
2396   StorageImpl* This,
2397   HANDLE       hFile,
2398   LPCOLESTR    pwcsName,
2399   ILockBytes*  pLkbyt,
2400   DWORD        openFlags,
2401   BOOL         fileBased,
2402   BOOL         create)
2403 {
2404   HRESULT     hr = S_OK;
2405   StgProperty currentProperty;
2406   BOOL      readSuccessful;
2407   ULONG       currentPropertyIndex;
2408
2409   if ( FAILED( validateSTGM(openFlags) ))
2410     return STG_E_INVALIDFLAG;
2411
2412   memset(This, 0, sizeof(StorageImpl));
2413
2414   list_init(&This->base.strmHead);
2415
2416   This->base.lpVtbl = &Storage32Impl_Vtbl;
2417   This->base.pssVtbl = &IPropertySetStorage_Vtbl;
2418   This->base.v_destructor = StorageImpl_Destroy;
2419   This->base.openFlags = (openFlags & ~STGM_CREATE);
2420   This->create = create;
2421
2422   /*
2423    * This is the top-level storage so initialize the ancestor pointer
2424    * to this.
2425    */
2426   This->base.ancestorStorage = This;
2427
2428   This->hFile = hFile;
2429
2430   if(pwcsName) {
2431       This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
2432                                 (lstrlenW(pwcsName)+1)*sizeof(WCHAR));
2433       if (!This->pwcsName)
2434          return STG_E_INSUFFICIENTMEMORY;
2435       strcpyW(This->pwcsName, pwcsName);
2436   }
2437
2438   /*
2439    * Initialize the big block cache.
2440    */
2441   This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
2442   This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2443   This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
2444                                                 pLkbyt,
2445                                                 openFlags,
2446                                                 This->bigBlockSize,
2447                                                 fileBased);
2448
2449   if (This->bigBlockFile == 0)
2450     return E_FAIL;
2451
2452   if (create)
2453   {
2454     ULARGE_INTEGER size;
2455     BYTE bigBlockBuffer[BIG_BLOCK_SIZE];
2456
2457     /*
2458      * Initialize all header variables:
2459      * - The big block depot consists of one block and it is at block 0
2460      * - The properties start at block 1
2461      * - There is no small block depot
2462      */
2463     memset( This->bigBlockDepotStart,
2464             BLOCK_UNUSED,
2465             sizeof(This->bigBlockDepotStart));
2466
2467     This->bigBlockDepotCount    = 1;
2468     This->bigBlockDepotStart[0] = 0;
2469     This->rootStartBlock        = 1;
2470     This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
2471     This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
2472     This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
2473     This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2474     This->extBigBlockDepotCount = 0;
2475
2476     StorageImpl_SaveFileHeader(This);
2477
2478     /*
2479      * Add one block for the big block depot and one block for the properties
2480      */
2481     size.u.HighPart = 0;
2482     size.u.LowPart  = This->bigBlockSize * 3;
2483     BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
2484
2485     /*
2486      * Initialize the big block depot
2487      */
2488     memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2489     StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2490     StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2491     StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
2492   }
2493   else
2494   {
2495     /*
2496      * Load the header for the file.
2497      */
2498     hr = StorageImpl_LoadFileHeader(This);
2499
2500     if (FAILED(hr))
2501     {
2502       BIGBLOCKFILE_Destructor(This->bigBlockFile);
2503
2504       return hr;
2505     }
2506   }
2507
2508   /*
2509    * There is no block depot cached yet.
2510    */
2511   This->indexBlockDepotCached = 0xFFFFFFFF;
2512
2513   /*
2514    * Start searching for free blocks with block 0.
2515    */
2516   This->prevFreeBlock = 0;
2517
2518   /*
2519    * Create the block chain abstractions.
2520    */
2521   if(!(This->rootBlockChain =
2522        BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL)))
2523     return STG_E_READFAULT;
2524
2525   if(!(This->smallBlockDepotChain =
2526        BlockChainStream_Construct(This, &This->smallBlockDepotStart,
2527                                   PROPERTY_NULL)))
2528     return STG_E_READFAULT;
2529
2530   /*
2531    * Write the root property (memory only)
2532    */
2533   if (create)
2534   {
2535     StgProperty rootProp;
2536     /*
2537      * Initialize the property chain
2538      */
2539     memset(&rootProp, 0, sizeof(rootProp));
2540     MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,
2541                          sizeof(rootProp.name)/sizeof(WCHAR) );
2542     rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR);
2543     rootProp.propertyType     = PROPTYPE_ROOT;
2544     rootProp.previousProperty = PROPERTY_NULL;
2545     rootProp.nextProperty     = PROPERTY_NULL;
2546     rootProp.dirProperty      = PROPERTY_NULL;
2547     rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
2548     rootProp.size.u.HighPart    = 0;
2549     rootProp.size.u.LowPart     = 0;
2550
2551     StorageImpl_WriteProperty(This, 0, &rootProp);
2552   }
2553
2554   /*
2555    * Find the ID of the root in the property sets.
2556    */
2557   currentPropertyIndex = 0;
2558
2559   do
2560   {
2561     readSuccessful = StorageImpl_ReadProperty(
2562                       This,
2563                       currentPropertyIndex,
2564                       &currentProperty);
2565
2566     if (readSuccessful)
2567     {
2568       if ( (currentProperty.sizeOfNameString != 0 ) &&
2569            (currentProperty.propertyType     == PROPTYPE_ROOT) )
2570       {
2571         This->base.rootPropertySetIndex = currentPropertyIndex;
2572       }
2573     }
2574
2575     currentPropertyIndex++;
2576
2577   } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) );
2578
2579   if (!readSuccessful)
2580   {
2581     /* TODO CLEANUP */
2582     return STG_E_READFAULT;
2583   }
2584
2585   /*
2586    * Create the block chain abstraction for the small block root chain.
2587    */
2588   if(!(This->smallBlockRootChain =
2589        BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex)))
2590     return STG_E_READFAULT;
2591
2592   return hr;
2593 }
2594
2595 static void StorageImpl_Destroy(StorageBaseImpl* iface)
2596 {
2597   StorageImpl *This = (StorageImpl*) iface;
2598   TRACE("(%p)\n", This);
2599
2600   StorageBaseImpl_DeleteAll(&This->base);
2601
2602   HeapFree(GetProcessHeap(), 0, This->pwcsName);
2603
2604   BlockChainStream_Destroy(This->smallBlockRootChain);
2605   BlockChainStream_Destroy(This->rootBlockChain);
2606   BlockChainStream_Destroy(This->smallBlockDepotChain);
2607
2608   BIGBLOCKFILE_Destructor(This->bigBlockFile);
2609   HeapFree(GetProcessHeap(), 0, This);
2610 }
2611
2612 /******************************************************************************
2613  *      Storage32Impl_GetNextFreeBigBlock
2614  *
2615  * Returns the index of the next free big block.
2616  * If the big block depot is filled, this method will enlarge it.
2617  *
2618  */
2619 static ULONG StorageImpl_GetNextFreeBigBlock(
2620   StorageImpl* This)
2621 {
2622   ULONG depotBlockIndexPos;
2623   BYTE depotBuffer[BIG_BLOCK_SIZE];
2624   BOOL success;
2625   ULONG depotBlockOffset;
2626   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
2627   ULONG nextBlockIndex    = BLOCK_SPECIAL;
2628   int   depotIndex        = 0;
2629   ULONG freeBlock         = BLOCK_UNUSED;
2630
2631   depotIndex = This->prevFreeBlock / blocksPerDepot;
2632   depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2633
2634   /*
2635    * Scan the entire big block depot until we find a block marked free
2636    */
2637   while (nextBlockIndex != BLOCK_UNUSED)
2638   {
2639     if (depotIndex < COUNT_BBDEPOTINHEADER)
2640     {
2641       depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2642
2643       /*
2644        * Grow the primary depot.
2645        */
2646       if (depotBlockIndexPos == BLOCK_UNUSED)
2647       {
2648         depotBlockIndexPos = depotIndex*blocksPerDepot;
2649
2650         /*
2651          * Add a block depot.
2652          */
2653         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2654         This->bigBlockDepotCount++;
2655         This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2656
2657         /*
2658          * Flag it as a block depot.
2659          */
2660         StorageImpl_SetNextBlockInChain(This,
2661                                           depotBlockIndexPos,
2662                                           BLOCK_SPECIAL);
2663
2664         /* Save new header information.
2665          */
2666         StorageImpl_SaveFileHeader(This);
2667       }
2668     }
2669     else
2670     {
2671       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2672
2673       if (depotBlockIndexPos == BLOCK_UNUSED)
2674       {
2675         /*
2676          * Grow the extended depot.
2677          */
2678         ULONG extIndex       = BLOCK_UNUSED;
2679         ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
2680         ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2681
2682         if (extBlockOffset == 0)
2683         {
2684           /* We need an extended block.
2685            */
2686           extIndex = Storage32Impl_AddExtBlockDepot(This);
2687           This->extBigBlockDepotCount++;
2688           depotBlockIndexPos = extIndex + 1;
2689         }
2690         else
2691           depotBlockIndexPos = depotIndex * blocksPerDepot;
2692
2693         /*
2694          * Add a block depot and mark it in the extended block.
2695          */
2696         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2697         This->bigBlockDepotCount++;
2698         Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2699
2700         /* Flag the block depot.
2701          */
2702         StorageImpl_SetNextBlockInChain(This,
2703                                           depotBlockIndexPos,
2704                                           BLOCK_SPECIAL);
2705
2706         /* If necessary, flag the extended depot block.
2707          */
2708         if (extIndex != BLOCK_UNUSED)
2709           StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2710
2711         /* Save header information.
2712          */
2713         StorageImpl_SaveFileHeader(This);
2714       }
2715     }
2716
2717     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
2718
2719     if (success)
2720     {
2721       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2722               ( nextBlockIndex != BLOCK_UNUSED))
2723       {
2724         StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2725
2726         if (nextBlockIndex == BLOCK_UNUSED)
2727         {
2728           freeBlock = (depotIndex * blocksPerDepot) +
2729                       (depotBlockOffset/sizeof(ULONG));
2730         }
2731
2732         depotBlockOffset += sizeof(ULONG);
2733       }
2734     }
2735
2736     depotIndex++;
2737     depotBlockOffset = 0;
2738   }
2739
2740   /*
2741    * make sure that the block physically exists before using it
2742    */
2743   BIGBLOCKFILE_EnsureExists(This->bigBlockFile, freeBlock);
2744
2745   This->prevFreeBlock = freeBlock;
2746
2747   return freeBlock;
2748 }
2749
2750 /******************************************************************************
2751  *      Storage32Impl_AddBlockDepot
2752  *
2753  * This will create a depot block, essentially it is a block initialized
2754  * to BLOCK_UNUSEDs.
2755  */
2756 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2757 {
2758   BYTE blockBuffer[BIG_BLOCK_SIZE];
2759
2760   /*
2761    * Initialize blocks as free
2762    */
2763   memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2764   StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
2765 }
2766
2767 /******************************************************************************
2768  *      Storage32Impl_GetExtDepotBlock
2769  *
2770  * Returns the index of the block that corresponds to the specified depot
2771  * index. This method is only for depot indexes equal or greater than
2772  * COUNT_BBDEPOTINHEADER.
2773  */
2774 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2775 {
2776   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2777   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
2778   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
2779   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
2780   ULONG blockIndex             = BLOCK_UNUSED;
2781   ULONG extBlockIndex          = This->extBigBlockDepotStart;
2782
2783   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2784
2785   if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2786     return BLOCK_UNUSED;
2787
2788   while (extBlockCount > 0)
2789   {
2790     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2791     extBlockCount--;
2792   }
2793
2794   if (extBlockIndex != BLOCK_UNUSED)
2795     StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
2796                         extBlockOffset * sizeof(ULONG), &blockIndex);
2797
2798   return blockIndex;
2799 }
2800
2801 /******************************************************************************
2802  *      Storage32Impl_SetExtDepotBlock
2803  *
2804  * Associates the specified block index to the specified depot index.
2805  * This method is only for depot indexes equal or greater than
2806  * COUNT_BBDEPOTINHEADER.
2807  */
2808 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
2809 {
2810   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2811   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
2812   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
2813   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
2814   ULONG extBlockIndex          = This->extBigBlockDepotStart;
2815
2816   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2817
2818   while (extBlockCount > 0)
2819   {
2820     extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2821     extBlockCount--;
2822   }
2823
2824   if (extBlockIndex != BLOCK_UNUSED)
2825   {
2826     StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
2827                         extBlockOffset * sizeof(ULONG),
2828                         blockIndex);
2829   }
2830 }
2831
2832 /******************************************************************************
2833  *      Storage32Impl_AddExtBlockDepot
2834  *
2835  * Creates an extended depot block.
2836  */
2837 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2838 {
2839   ULONG numExtBlocks           = This->extBigBlockDepotCount;
2840   ULONG nextExtBlock           = This->extBigBlockDepotStart;
2841   BYTE  depotBuffer[BIG_BLOCK_SIZE];
2842   ULONG index                  = BLOCK_UNUSED;
2843   ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
2844   ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
2845   ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2846
2847   index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2848           blocksPerDepotBlock;
2849
2850   if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2851   {
2852     /*
2853      * The first extended block.
2854      */
2855     This->extBigBlockDepotStart = index;
2856   }
2857   else
2858   {
2859     unsigned int i;
2860     /*
2861      * Follow the chain to the last one.
2862      */
2863     for (i = 0; i < (numExtBlocks - 1); i++)
2864     {
2865       nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2866     }
2867
2868     /*
2869      * Add the new extended block to the chain.
2870      */
2871     StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
2872                                      index);
2873   }
2874
2875   /*
2876    * Initialize this block.
2877    */
2878   memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2879   StorageImpl_WriteBigBlock(This, index, depotBuffer);
2880
2881   return index;
2882 }
2883
2884 /******************************************************************************
2885  *      Storage32Impl_FreeBigBlock
2886  *
2887  * This method will flag the specified block as free in the big block depot.
2888  */
2889 static void StorageImpl_FreeBigBlock(
2890   StorageImpl* This,
2891   ULONG          blockIndex)
2892 {
2893   StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2894
2895   if (blockIndex < This->prevFreeBlock)
2896     This->prevFreeBlock = blockIndex;
2897 }
2898
2899 /************************************************************************
2900  * Storage32Impl_GetNextBlockInChain
2901  *
2902  * This method will retrieve the block index of the next big block in
2903  * in the chain.
2904  *
2905  * Params:  This       - Pointer to the Storage object.
2906  *          blockIndex - Index of the block to retrieve the chain
2907  *                       for.
2908  *          nextBlockIndex - receives the return value.
2909  *
2910  * Returns: This method returns the index of the next block in the chain.
2911  *          It will return the constants:
2912  *              BLOCK_SPECIAL - If the block given was not part of a
2913  *                              chain.
2914  *              BLOCK_END_OF_CHAIN - If the block given was the last in
2915  *                                   a chain.
2916  *              BLOCK_UNUSED - If the block given was not past of a chain
2917  *                             and is available.
2918  *              BLOCK_EXTBBDEPOT - This block is part of the extended
2919  *                                 big block depot.
2920  *
2921  * See Windows documentation for more details on IStorage methods.
2922  */
2923 static HRESULT StorageImpl_GetNextBlockInChain(
2924   StorageImpl* This,
2925   ULONG        blockIndex,
2926   ULONG*       nextBlockIndex)
2927 {
2928   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
2929   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
2930   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2931   BYTE depotBuffer[BIG_BLOCK_SIZE];
2932   BOOL success;
2933   ULONG depotBlockIndexPos;
2934   int index;
2935
2936   *nextBlockIndex   = BLOCK_SPECIAL;
2937
2938   if(depotBlockCount >= This->bigBlockDepotCount)
2939   {
2940     WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
2941          This->bigBlockDepotCount);
2942     return STG_E_READFAULT;
2943   }
2944
2945   /*
2946    * Cache the currently accessed depot block.
2947    */
2948   if (depotBlockCount != This->indexBlockDepotCached)
2949   {
2950     This->indexBlockDepotCached = depotBlockCount;
2951
2952     if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2953     {
2954       depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2955     }
2956     else
2957     {
2958       /*
2959        * We have to look in the extended depot.
2960        */
2961       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2962     }
2963
2964     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
2965
2966     if (!success)
2967       return STG_E_READFAULT;
2968
2969     for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2970     {
2971       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
2972       This->blockDepotCached[index] = *nextBlockIndex;
2973     }
2974   }
2975
2976   *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2977
2978   return S_OK;
2979 }
2980
2981 /******************************************************************************
2982  *      Storage32Impl_GetNextExtendedBlock
2983  *
2984  * Given an extended block this method will return the next extended block.
2985  *
2986  * NOTES:
2987  * The last ULONG of an extended block is the block index of the next
2988  * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2989  * depot.
2990  *
2991  * Return values:
2992  *    - The index of the next extended block
2993  *    - BLOCK_UNUSED: there is no next extended block.
2994  *    - Any other return values denotes failure.
2995  */
2996 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2997 {
2998   ULONG nextBlockIndex   = BLOCK_SPECIAL;
2999   ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
3000
3001   StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
3002                         &nextBlockIndex);
3003
3004   return nextBlockIndex;
3005 }
3006
3007 /******************************************************************************
3008  *      Storage32Impl_SetNextBlockInChain
3009  *
3010  * This method will write the index of the specified block's next block
3011  * in the big block depot.
3012  *
3013  * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
3014  *              do the following
3015  *
3016  * Storage32Impl_SetNextBlockInChain(This, 3, 1);
3017  * Storage32Impl_SetNextBlockInChain(This, 1, 7);
3018  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
3019  *
3020  */
3021 static void StorageImpl_SetNextBlockInChain(
3022           StorageImpl* This,
3023           ULONG          blockIndex,
3024           ULONG          nextBlock)
3025 {
3026   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
3027   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
3028   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3029   ULONG depotBlockIndexPos;
3030
3031   assert(depotBlockCount < This->bigBlockDepotCount);
3032   assert(blockIndex != nextBlock);
3033
3034   if (depotBlockCount < COUNT_BBDEPOTINHEADER)
3035   {
3036     depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
3037   }
3038   else
3039   {
3040     /*
3041      * We have to look in the extended depot.
3042      */
3043     depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
3044   }
3045
3046   StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
3047                         nextBlock);
3048   /*
3049    * Update the cached block depot, if necessary.
3050    */
3051   if (depotBlockCount == This->indexBlockDepotCached)
3052   {
3053     This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
3054   }
3055 }
3056
3057 /******************************************************************************
3058  *      Storage32Impl_LoadFileHeader
3059  *
3060  * This method will read in the file header, i.e. big block index -1.
3061  */
3062 static HRESULT StorageImpl_LoadFileHeader(
3063           StorageImpl* This)
3064 {
3065   HRESULT hr = STG_E_FILENOTFOUND;
3066   BYTE    headerBigBlock[BIG_BLOCK_SIZE];
3067   BOOL    success;
3068   int     index;
3069
3070   TRACE("\n");
3071   /*
3072    * Get a pointer to the big block of data containing the header.
3073    */
3074   success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
3075
3076   /*
3077    * Extract the information from the header.
3078    */
3079   if (success)
3080   {
3081     /*
3082      * Check for the "magic number" signature and return an error if it is not
3083      * found.
3084      */
3085     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
3086     {
3087       return STG_E_OLDFORMAT;
3088     }
3089
3090     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
3091     {
3092       return STG_E_INVALIDHEADER;
3093     }
3094
3095     StorageUtl_ReadWord(
3096       headerBigBlock,
3097       OFFSET_BIGBLOCKSIZEBITS,
3098       &This->bigBlockSizeBits);
3099
3100     StorageUtl_ReadWord(
3101       headerBigBlock,
3102       OFFSET_SMALLBLOCKSIZEBITS,
3103       &This->smallBlockSizeBits);
3104
3105     StorageUtl_ReadDWord(
3106       headerBigBlock,
3107       OFFSET_BBDEPOTCOUNT,
3108       &This->bigBlockDepotCount);
3109
3110     StorageUtl_ReadDWord(
3111       headerBigBlock,
3112       OFFSET_ROOTSTARTBLOCK,
3113       &This->rootStartBlock);
3114
3115     StorageUtl_ReadDWord(
3116       headerBigBlock,
3117       OFFSET_SBDEPOTSTART,
3118       &This->smallBlockDepotStart);
3119
3120     StorageUtl_ReadDWord(
3121       headerBigBlock,
3122       OFFSET_EXTBBDEPOTSTART,
3123       &This->extBigBlockDepotStart);
3124
3125     StorageUtl_ReadDWord(
3126       headerBigBlock,
3127       OFFSET_EXTBBDEPOTCOUNT,
3128       &This->extBigBlockDepotCount);
3129
3130     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3131     {
3132       StorageUtl_ReadDWord(
3133         headerBigBlock,
3134         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3135         &(This->bigBlockDepotStart[index]));
3136     }
3137
3138     /*
3139      * Make the bitwise arithmetic to get the size of the blocks in bytes.
3140      */
3141     This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
3142     This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
3143
3144     /*
3145      * Right now, the code is making some assumptions about the size of the
3146      * blocks, just make sure they are what we're expecting.
3147      */
3148     if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE ||
3149         This->smallBlockSize != DEF_SMALL_BLOCK_SIZE)
3150     {
3151         WARN("Broken OLE storage file\n");
3152         hr = STG_E_INVALIDHEADER;
3153     }
3154     else
3155         hr = S_OK;
3156   }
3157
3158   return hr;
3159 }
3160
3161 /******************************************************************************
3162  *      Storage32Impl_SaveFileHeader
3163  *
3164  * This method will save to the file the header, i.e. big block -1.
3165  */
3166 static void StorageImpl_SaveFileHeader(
3167           StorageImpl* This)
3168 {
3169   BYTE   headerBigBlock[BIG_BLOCK_SIZE];
3170   int    index;
3171   BOOL success;
3172
3173   /*
3174    * Get a pointer to the big block of data containing the header.
3175    */
3176   success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
3177
3178   /*
3179    * If the block read failed, the file is probably new.
3180    */
3181   if (!success)
3182   {
3183     /*
3184      * Initialize for all unknown fields.
3185      */
3186     memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
3187
3188     /*
3189      * Initialize the magic number.
3190      */
3191     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
3192
3193     /*
3194      * And a bunch of things we don't know what they mean
3195      */
3196     StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
3197     StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
3198     StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
3199     StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
3200   }
3201
3202   /*
3203    * Write the information to the header.
3204    */
3205   StorageUtl_WriteWord(
3206     headerBigBlock,
3207     OFFSET_BIGBLOCKSIZEBITS,
3208     This->bigBlockSizeBits);
3209
3210   StorageUtl_WriteWord(
3211     headerBigBlock,
3212     OFFSET_SMALLBLOCKSIZEBITS,
3213     This->smallBlockSizeBits);
3214
3215   StorageUtl_WriteDWord(
3216     headerBigBlock,
3217     OFFSET_BBDEPOTCOUNT,
3218     This->bigBlockDepotCount);
3219
3220   StorageUtl_WriteDWord(
3221     headerBigBlock,
3222     OFFSET_ROOTSTARTBLOCK,
3223     This->rootStartBlock);
3224
3225   StorageUtl_WriteDWord(
3226     headerBigBlock,
3227     OFFSET_SBDEPOTSTART,
3228     This->smallBlockDepotStart);
3229
3230   StorageUtl_WriteDWord(
3231     headerBigBlock,
3232     OFFSET_SBDEPOTCOUNT,
3233     This->smallBlockDepotChain ?
3234      BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
3235
3236   StorageUtl_WriteDWord(
3237     headerBigBlock,
3238     OFFSET_EXTBBDEPOTSTART,
3239     This->extBigBlockDepotStart);
3240
3241   StorageUtl_WriteDWord(
3242     headerBigBlock,
3243     OFFSET_EXTBBDEPOTCOUNT,
3244     This->extBigBlockDepotCount);
3245
3246   for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3247   {
3248     StorageUtl_WriteDWord(
3249       headerBigBlock,
3250       OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3251       (This->bigBlockDepotStart[index]));
3252   }
3253
3254   /*
3255    * Write the big block back to the file.
3256    */
3257   StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
3258 }
3259
3260 /******************************************************************************
3261  *      Storage32Impl_ReadProperty
3262  *
3263  * This method will read the specified property from the property chain.
3264  */
3265 BOOL StorageImpl_ReadProperty(
3266   StorageImpl* This,
3267   ULONG          index,
3268   StgProperty*   buffer)
3269 {
3270   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3271   ULARGE_INTEGER offsetInPropSet;
3272   HRESULT        readRes;
3273   ULONG          bytesRead;
3274
3275   offsetInPropSet.u.HighPart = 0;
3276   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3277
3278   readRes = BlockChainStream_ReadAt(
3279                     This->rootBlockChain,
3280                     offsetInPropSet,
3281                     PROPSET_BLOCK_SIZE,
3282                     currentProperty,
3283                     &bytesRead);
3284
3285   if (SUCCEEDED(readRes))
3286   {
3287     /* replace the name of root entry (often "Root Entry") by the file name */
3288     WCHAR *propName = (index == This->base.rootPropertySetIndex) ?
3289                         This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;
3290
3291     memset(buffer->name, 0, sizeof(buffer->name));
3292     memcpy(
3293       buffer->name,
3294       propName,
3295       PROPERTY_NAME_BUFFER_LEN );
3296     TRACE("storage name: %s\n", debugstr_w(buffer->name));
3297
3298     memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3299
3300     StorageUtl_ReadWord(
3301       currentProperty,
3302       OFFSET_PS_NAMELENGTH,
3303       &buffer->sizeOfNameString);
3304
3305     StorageUtl_ReadDWord(
3306       currentProperty,
3307       OFFSET_PS_PREVIOUSPROP,
3308       &buffer->previousProperty);
3309
3310     StorageUtl_ReadDWord(
3311       currentProperty,
3312       OFFSET_PS_NEXTPROP,
3313       &buffer->nextProperty);
3314
3315     StorageUtl_ReadDWord(
3316       currentProperty,
3317       OFFSET_PS_DIRPROP,
3318       &buffer->dirProperty);
3319
3320     StorageUtl_ReadGUID(
3321       currentProperty,
3322       OFFSET_PS_GUID,
3323       &buffer->propertyUniqueID);
3324
3325     StorageUtl_ReadDWord(
3326       currentProperty,
3327       OFFSET_PS_TSS1,
3328       &buffer->timeStampS1);
3329
3330     StorageUtl_ReadDWord(
3331       currentProperty,
3332       OFFSET_PS_TSD1,
3333       &buffer->timeStampD1);
3334
3335     StorageUtl_ReadDWord(
3336       currentProperty,
3337       OFFSET_PS_TSS2,
3338       &buffer->timeStampS2);
3339
3340     StorageUtl_ReadDWord(
3341       currentProperty,
3342       OFFSET_PS_TSD2,
3343       &buffer->timeStampD2);
3344
3345     StorageUtl_ReadDWord(
3346       currentProperty,
3347       OFFSET_PS_STARTBLOCK,
3348       &buffer->startingBlock);
3349
3350     StorageUtl_ReadDWord(
3351       currentProperty,
3352       OFFSET_PS_SIZE,
3353       &buffer->size.u.LowPart);
3354
3355     buffer->size.u.HighPart = 0;
3356   }
3357
3358   return SUCCEEDED(readRes) ? TRUE : FALSE;
3359 }
3360
3361 /*********************************************************************
3362  * Write the specified property into the property chain
3363  */
3364 BOOL StorageImpl_WriteProperty(
3365   StorageImpl*          This,
3366   ULONG                 index,
3367   const StgProperty*    buffer)
3368 {
3369   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
3370   ULARGE_INTEGER offsetInPropSet;
3371   HRESULT        writeRes;
3372   ULONG          bytesWritten;
3373
3374   offsetInPropSet.u.HighPart = 0;
3375   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
3376
3377   memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3378
3379   memcpy(
3380     currentProperty + OFFSET_PS_NAME,
3381     buffer->name,
3382     PROPERTY_NAME_BUFFER_LEN );
3383
3384   memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3385
3386   StorageUtl_WriteWord(
3387     currentProperty,
3388       OFFSET_PS_NAMELENGTH,
3389       buffer->sizeOfNameString);
3390
3391   StorageUtl_WriteDWord(
3392     currentProperty,
3393       OFFSET_PS_PREVIOUSPROP,
3394       buffer->previousProperty);
3395
3396   StorageUtl_WriteDWord(
3397     currentProperty,
3398       OFFSET_PS_NEXTPROP,
3399       buffer->nextProperty);
3400
3401   StorageUtl_WriteDWord(
3402     currentProperty,
3403       OFFSET_PS_DIRPROP,
3404       buffer->dirProperty);
3405
3406   StorageUtl_WriteGUID(
3407     currentProperty,
3408       OFFSET_PS_GUID,
3409       &buffer->propertyUniqueID);
3410
3411   StorageUtl_WriteDWord(
3412     currentProperty,
3413       OFFSET_PS_TSS1,
3414       buffer->timeStampS1);
3415
3416   StorageUtl_WriteDWord(
3417     currentProperty,
3418       OFFSET_PS_TSD1,
3419       buffer->timeStampD1);
3420
3421   StorageUtl_WriteDWord(
3422     currentProperty,
3423       OFFSET_PS_TSS2,
3424       buffer->timeStampS2);
3425
3426   StorageUtl_WriteDWord(
3427     currentProperty,
3428       OFFSET_PS_TSD2,
3429       buffer->timeStampD2);
3430
3431   StorageUtl_WriteDWord(
3432     currentProperty,
3433       OFFSET_PS_STARTBLOCK,
3434       buffer->startingBlock);
3435
3436   StorageUtl_WriteDWord(
3437     currentProperty,
3438       OFFSET_PS_SIZE,
3439       buffer->size.u.LowPart);
3440
3441   writeRes = BlockChainStream_WriteAt(This->rootBlockChain,
3442                                       offsetInPropSet,
3443                                       PROPSET_BLOCK_SIZE,
3444                                       currentProperty,
3445                                       &bytesWritten);
3446   return SUCCEEDED(writeRes) ? TRUE : FALSE;
3447 }
3448
3449 static BOOL StorageImpl_ReadBigBlock(
3450   StorageImpl* This,
3451   ULONG          blockIndex,
3452   void*          buffer)
3453 {
3454   ULARGE_INTEGER ulOffset;
3455   DWORD  read;
3456
3457   ulOffset.u.HighPart = 0;
3458   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3459
3460   StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
3461   return (read == This->bigBlockSize);
3462 }
3463
3464 static BOOL StorageImpl_ReadDWordFromBigBlock(
3465   StorageImpl*  This,
3466   ULONG         blockIndex,
3467   ULONG         offset,
3468   DWORD*        value)
3469 {
3470   ULARGE_INTEGER ulOffset;
3471   DWORD  read;
3472   DWORD  tmp;
3473
3474   ulOffset.u.HighPart = 0;
3475   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3476   ulOffset.u.LowPart += offset;
3477
3478   StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
3479   *value = lendian32toh(tmp);
3480   return (read == sizeof(DWORD));
3481 }
3482
3483 static BOOL StorageImpl_WriteBigBlock(
3484   StorageImpl*  This,
3485   ULONG         blockIndex,
3486   const void*   buffer)
3487 {
3488   ULARGE_INTEGER ulOffset;
3489   DWORD  wrote;
3490
3491   ulOffset.u.HighPart = 0;
3492   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3493
3494   StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
3495   return (wrote == This->bigBlockSize);
3496 }
3497
3498 static BOOL StorageImpl_WriteDWordToBigBlock(
3499   StorageImpl* This,
3500   ULONG         blockIndex,
3501   ULONG         offset,
3502   DWORD         value)
3503 {
3504   ULARGE_INTEGER ulOffset;
3505   DWORD  wrote;
3506
3507   ulOffset.u.HighPart = 0;
3508   ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
3509   ulOffset.u.LowPart += offset;
3510
3511   value = htole32(value);
3512   StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
3513   return (wrote == sizeof(DWORD));
3514 }
3515
3516 /******************************************************************************
3517  *              Storage32Impl_SmallBlocksToBigBlocks
3518  *
3519  * This method will convert a small block chain to a big block chain.
3520  * The small block chain will be destroyed.
3521  */
3522 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3523                       StorageImpl* This,
3524                       SmallBlockChainStream** ppsbChain)
3525 {
3526   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3527   ULARGE_INTEGER size, offset;
3528   ULONG cbRead, cbWritten;
3529   ULARGE_INTEGER cbTotalRead;
3530   ULONG propertyIndex;
3531   HRESULT resWrite = S_OK;
3532   HRESULT resRead;
3533   StgProperty chainProperty;
3534   BYTE *buffer;
3535   BlockChainStream *bbTempChain = NULL;
3536   BlockChainStream *bigBlockChain = NULL;
3537
3538   /*
3539    * Create a temporary big block chain that doesn't have
3540    * an associated property. This temporary chain will be
3541    * used to copy data from small blocks to big blocks.
3542    */
3543   bbTempChain = BlockChainStream_Construct(This,
3544                                            &bbHeadOfChain,
3545                                            PROPERTY_NULL);
3546   if(!bbTempChain) return NULL;
3547   /*
3548    * Grow the big block chain.
3549    */
3550   size = SmallBlockChainStream_GetSize(*ppsbChain);
3551   BlockChainStream_SetSize(bbTempChain, size);
3552
3553   /*
3554    * Copy the contents of the small block chain to the big block chain
3555    * by small block size increments.
3556    */
3557   offset.u.LowPart = 0;
3558   offset.u.HighPart = 0;
3559   cbTotalRead.QuadPart = 0;
3560
3561   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3562   do
3563   {
3564     resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3565                                            offset,
3566                                            min(This->smallBlockSize, size.u.LowPart - offset.u.LowPart),
3567                                            buffer,
3568                                            &cbRead);
3569     if (FAILED(resRead))
3570         break;
3571
3572     if (cbRead > 0)
3573     {
3574         cbTotalRead.QuadPart += cbRead;
3575
3576         resWrite = BlockChainStream_WriteAt(bbTempChain,
3577                                             offset,
3578                                             cbRead,
3579                                             buffer,
3580                                             &cbWritten);
3581
3582         if (FAILED(resWrite))
3583             break;
3584
3585         offset.u.LowPart += cbRead;
3586     }
3587   } while (cbTotalRead.QuadPart < size.QuadPart);
3588   HeapFree(GetProcessHeap(),0,buffer);
3589
3590   size.u.HighPart = 0;
3591   size.u.LowPart  = 0;
3592
3593   if (FAILED(resRead) || FAILED(resWrite))
3594   {
3595     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
3596     BlockChainStream_SetSize(bbTempChain, size);
3597     BlockChainStream_Destroy(bbTempChain);
3598     return NULL;
3599   }
3600
3601   /*
3602    * Destroy the small block chain.
3603    */
3604   propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3605   SmallBlockChainStream_SetSize(*ppsbChain, size);
3606   SmallBlockChainStream_Destroy(*ppsbChain);
3607   *ppsbChain = 0;
3608
3609   /*
3610    * Change the property information. This chain is now a big block chain
3611    * and it doesn't reside in the small blocks chain anymore.
3612    */
3613   StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3614
3615   chainProperty.startingBlock = bbHeadOfChain;
3616
3617   StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3618
3619   /*
3620    * Destroy the temporary propertyless big block chain.
3621    * Create a new big block chain associated with this property.
3622    */
3623   BlockChainStream_Destroy(bbTempChain);
3624   bigBlockChain = BlockChainStream_Construct(This,
3625                                              NULL,
3626                                              propertyIndex);
3627
3628   return bigBlockChain;
3629 }
3630
3631 /******************************************************************************
3632  *              Storage32Impl_BigBlocksToSmallBlocks
3633  *
3634  * This method will convert a big block chain to a small block chain.
3635  * The big block chain will be destroyed on success.
3636  */
3637 SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
3638                            StorageImpl* This,
3639                            BlockChainStream** ppbbChain)
3640 {
3641     ULARGE_INTEGER size, offset, cbTotalRead;
3642     ULONG cbRead, cbWritten, propertyIndex, sbHeadOfChain = BLOCK_END_OF_CHAIN;
3643     HRESULT resWrite = S_OK, resRead;
3644     StgProperty chainProperty;
3645     BYTE* buffer;
3646     SmallBlockChainStream* sbTempChain;
3647
3648     TRACE("%p %p\n", This, ppbbChain);
3649
3650     sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain,
3651             PROPERTY_NULL);
3652
3653     if(!sbTempChain)
3654         return NULL;
3655
3656     size = BlockChainStream_GetSize(*ppbbChain);
3657     SmallBlockChainStream_SetSize(sbTempChain, size);
3658
3659     offset.u.HighPart = 0;
3660     offset.u.LowPart = 0;
3661     cbTotalRead.QuadPart = 0;
3662     buffer = HeapAlloc(GetProcessHeap(), 0, This->bigBlockSize);
3663     do
3664     {
3665         resRead = BlockChainStream_ReadAt(*ppbbChain, offset,
3666                 min(This->bigBlockSize, size.u.LowPart - offset.u.LowPart),
3667                 buffer, &cbRead);
3668
3669         if(FAILED(resRead))
3670             break;
3671
3672         if(cbRead > 0)
3673         {
3674             cbTotalRead.QuadPart += cbRead;
3675
3676             resWrite = SmallBlockChainStream_WriteAt(sbTempChain, offset,
3677                     cbRead, buffer, &cbWritten);
3678
3679             if(FAILED(resWrite))
3680                 break;
3681
3682             offset.u.LowPart += cbRead;
3683         }
3684     }while(cbTotalRead.QuadPart < size.QuadPart);
3685     HeapFree(GetProcessHeap(), 0, buffer);
3686
3687     size.u.HighPart = 0;
3688     size.u.LowPart = 0;
3689
3690     if(FAILED(resRead) || FAILED(resWrite))
3691     {
3692         ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
3693         SmallBlockChainStream_SetSize(sbTempChain, size);
3694         SmallBlockChainStream_Destroy(sbTempChain);
3695         return NULL;
3696     }
3697
3698     /* destroy the original big block chain */
3699     propertyIndex = (*ppbbChain)->ownerPropertyIndex;
3700     BlockChainStream_SetSize(*ppbbChain, size);
3701     BlockChainStream_Destroy(*ppbbChain);
3702     *ppbbChain = NULL;
3703
3704     StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3705     chainProperty.startingBlock = sbHeadOfChain;
3706     StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3707
3708     SmallBlockChainStream_Destroy(sbTempChain);
3709     return SmallBlockChainStream_Construct(This, NULL, propertyIndex);
3710 }
3711
3712 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
3713 {
3714   StorageInternalImpl* This = (StorageInternalImpl*) iface;
3715
3716   HeapFree(GetProcessHeap(), 0, This);
3717 }
3718
3719 /******************************************************************************
3720 **
3721 ** Storage32InternalImpl_Commit
3722 **
3723 */
3724 static HRESULT WINAPI StorageInternalImpl_Commit(
3725   IStorage*            iface,
3726   DWORD                  grfCommitFlags)  /* [in] */
3727 {
3728   FIXME("(%p,%x): stub\n", iface, grfCommitFlags);
3729   return S_OK;
3730 }
3731
3732 /******************************************************************************
3733 **
3734 ** Storage32InternalImpl_Revert
3735 **
3736 */
3737 static HRESULT WINAPI StorageInternalImpl_Revert(
3738   IStorage*            iface)
3739 {
3740   FIXME("(%p): stub\n", iface);
3741   return S_OK;
3742 }
3743
3744 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3745 {
3746   IStorage_Release((IStorage*)This->parentStorage);
3747   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3748   HeapFree(GetProcessHeap(), 0, This);
3749 }
3750
3751 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3752   IEnumSTATSTG*     iface,
3753   REFIID            riid,
3754   void**            ppvObject)
3755 {
3756   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3757
3758   /*
3759    * Perform a sanity check on the parameters.
3760    */
3761   if (ppvObject==0)
3762     return E_INVALIDARG;
3763
3764   /*
3765    * Initialize the return parameter.
3766    */
3767   *ppvObject = 0;
3768
3769   /*
3770    * Compare the riid with the interface IDs implemented by this object.
3771    */
3772   if (IsEqualGUID(&IID_IUnknown, riid) ||
3773       IsEqualGUID(&IID_IEnumSTATSTG, riid))
3774   {
3775     *ppvObject = This;
3776     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
3777     return S_OK;
3778   }
3779
3780   return E_NOINTERFACE;
3781 }
3782
3783 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
3784   IEnumSTATSTG* iface)
3785 {
3786   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3787   return InterlockedIncrement(&This->ref);
3788 }
3789
3790 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
3791   IEnumSTATSTG* iface)
3792 {
3793   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3794
3795   ULONG newRef;
3796
3797   newRef = InterlockedDecrement(&This->ref);
3798
3799   /*
3800    * If the reference count goes down to 0, perform suicide.
3801    */
3802   if (newRef==0)
3803   {
3804     IEnumSTATSTGImpl_Destroy(This);
3805   }
3806
3807   return newRef;
3808 }
3809
3810 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
3811   IEnumSTATSTG* iface,
3812   ULONG             celt,
3813   STATSTG*          rgelt,
3814   ULONG*            pceltFetched)
3815 {
3816   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3817
3818   StgProperty currentProperty;
3819   STATSTG*    currentReturnStruct = rgelt;
3820   ULONG       objectFetched       = 0;
3821   ULONG      currentSearchNode;
3822
3823   /*
3824    * Perform a sanity check on the parameters.
3825    */
3826   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3827     return E_INVALIDARG;
3828
3829   /*
3830    * To avoid the special case, get another pointer to a ULONG value if
3831    * the caller didn't supply one.
3832    */
3833   if (pceltFetched==0)
3834     pceltFetched = &objectFetched;
3835
3836   /*
3837    * Start the iteration, we will iterate until we hit the end of the
3838    * linked list or until we hit the number of items to iterate through
3839    */
3840   *pceltFetched = 0;
3841
3842   /*
3843    * Start with the node at the top of the stack.
3844    */
3845   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3846
3847   while ( ( *pceltFetched < celt) &&
3848           ( currentSearchNode!=PROPERTY_NULL) )
3849   {
3850     /*
3851      * Remove the top node from the stack
3852      */
3853     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3854
3855     /*
3856      * Read the property from the storage.
3857      */
3858     StorageImpl_ReadProperty(This->parentStorage,
3859       currentSearchNode,
3860       &currentProperty);
3861
3862     /*
3863      * Copy the information to the return buffer.
3864      */
3865     StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3866       &currentProperty,
3867       STATFLAG_DEFAULT);
3868
3869     /*
3870      * Step to the next item in the iteration
3871      */
3872     (*pceltFetched)++;
3873     currentReturnStruct++;
3874
3875     /*
3876      * Push the next search node in the search stack.
3877      */
3878     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3879
3880     /*
3881      * continue the iteration.
3882      */
3883     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3884   }
3885
3886   if (*pceltFetched == celt)
3887     return S_OK;
3888
3889   return S_FALSE;
3890 }
3891
3892
3893 static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3894   IEnumSTATSTG* iface,
3895   ULONG             celt)
3896 {
3897   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3898
3899   StgProperty currentProperty;
3900   ULONG       objectFetched       = 0;
3901   ULONG       currentSearchNode;
3902
3903   /*
3904    * Start with the node at the top of the stack.
3905    */
3906   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3907
3908   while ( (objectFetched < celt) &&
3909           (currentSearchNode!=PROPERTY_NULL) )
3910   {
3911     /*
3912      * Remove the top node from the stack
3913      */
3914     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3915
3916     /*
3917      * Read the property from the storage.
3918      */
3919     StorageImpl_ReadProperty(This->parentStorage,
3920       currentSearchNode,
3921       &currentProperty);
3922
3923     /*
3924      * Step to the next item in the iteration
3925      */
3926     objectFetched++;
3927
3928     /*
3929      * Push the next search node in the search stack.
3930      */
3931     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3932
3933     /*
3934      * continue the iteration.
3935      */
3936     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3937   }
3938
3939   if (objectFetched == celt)
3940     return S_OK;
3941
3942   return S_FALSE;
3943 }
3944
3945 static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3946   IEnumSTATSTG* iface)
3947 {
3948   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3949
3950   StgProperty rootProperty;
3951   BOOL      readSuccessful;
3952
3953   /*
3954    * Re-initialize the search stack to an empty stack
3955    */
3956   This->stackSize = 0;
3957
3958   /*
3959    * Read the root property from the storage.
3960    */
3961   readSuccessful = StorageImpl_ReadProperty(
3962                     This->parentStorage,
3963                     This->firstPropertyNode,
3964                     &rootProperty);
3965
3966   if (readSuccessful)
3967   {
3968     assert(rootProperty.sizeOfNameString!=0);
3969
3970     /*
3971      * Push the search node in the search stack.
3972      */
3973     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3974   }
3975
3976   return S_OK;
3977 }
3978
3979 static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3980   IEnumSTATSTG* iface,
3981   IEnumSTATSTG**    ppenum)
3982 {
3983   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3984
3985   IEnumSTATSTGImpl* newClone;
3986
3987   /*
3988    * Perform a sanity check on the parameters.
3989    */
3990   if (ppenum==0)
3991     return E_INVALIDARG;
3992
3993   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3994                This->firstPropertyNode);
3995
3996
3997   /*
3998    * The new clone enumeration must point to the same current node as
3999    * the ole one.
4000    */
4001   newClone->stackSize    = This->stackSize    ;
4002   newClone->stackMaxSize = This->stackMaxSize ;
4003   newClone->stackToVisit =
4004     HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
4005
4006   memcpy(
4007     newClone->stackToVisit,
4008     This->stackToVisit,
4009     sizeof(ULONG) * newClone->stackSize);
4010
4011   *ppenum = (IEnumSTATSTG*)newClone;
4012
4013   /*
4014    * Don't forget to nail down a reference to the clone before
4015    * returning it.
4016    */
4017   IEnumSTATSTGImpl_AddRef(*ppenum);
4018
4019   return S_OK;
4020 }
4021
4022 static INT IEnumSTATSTGImpl_FindParentProperty(
4023   IEnumSTATSTGImpl *This,
4024   ULONG             childProperty,
4025   StgProperty      *currentProperty,
4026   ULONG            *thisNodeId)
4027 {
4028   ULONG currentSearchNode;
4029   ULONG foundNode;
4030
4031   /*
4032    * To avoid the special case, get another pointer to a ULONG value if
4033    * the caller didn't supply one.
4034    */
4035   if (thisNodeId==0)
4036     thisNodeId = &foundNode;
4037
4038   /*
4039    * Start with the node at the top of the stack.
4040    */
4041   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4042
4043
4044   while (currentSearchNode!=PROPERTY_NULL)
4045   {
4046     /*
4047      * Store the current node in the returned parameters
4048      */
4049     *thisNodeId = currentSearchNode;
4050
4051     /*
4052      * Remove the top node from the stack
4053      */
4054     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
4055
4056     /*
4057      * Read the property from the storage.
4058      */
4059     StorageImpl_ReadProperty(
4060       This->parentStorage,
4061       currentSearchNode,
4062       currentProperty);
4063
4064     if (currentProperty->previousProperty == childProperty)
4065       return PROPERTY_RELATION_PREVIOUS;
4066
4067     else if (currentProperty->nextProperty == childProperty)
4068       return PROPERTY_RELATION_NEXT;
4069
4070     else if (currentProperty->dirProperty == childProperty)
4071       return PROPERTY_RELATION_DIR;
4072
4073     /*
4074      * Push the next search node in the search stack.
4075      */
4076     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
4077
4078     /*
4079      * continue the iteration.
4080      */
4081     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4082   }
4083
4084   return PROPERTY_NULL;
4085 }
4086
4087 static ULONG IEnumSTATSTGImpl_FindProperty(
4088   IEnumSTATSTGImpl* This,
4089   const OLECHAR*  lpszPropName,
4090   StgProperty*      currentProperty)
4091 {
4092   ULONG currentSearchNode;
4093
4094   /*
4095    * Start with the node at the top of the stack.
4096    */
4097   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4098
4099   while (currentSearchNode!=PROPERTY_NULL)
4100   {
4101     /*
4102      * Remove the top node from the stack
4103      */
4104     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
4105
4106     /*
4107      * Read the property from the storage.
4108      */
4109     StorageImpl_ReadProperty(This->parentStorage,
4110       currentSearchNode,
4111       currentProperty);
4112
4113     if (propertyNameCmp(currentProperty->name, lpszPropName) == 0)
4114       return currentSearchNode;
4115
4116     /*
4117      * Push the next search node in the search stack.
4118      */
4119     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
4120
4121     /*
4122      * continue the iteration.
4123      */
4124     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4125   }
4126
4127   return PROPERTY_NULL;
4128 }
4129
4130 static void IEnumSTATSTGImpl_PushSearchNode(
4131   IEnumSTATSTGImpl* This,
4132   ULONG             nodeToPush)
4133 {
4134   StgProperty rootProperty;
4135   BOOL      readSuccessful;
4136
4137   /*
4138    * First, make sure we're not trying to push an unexisting node.
4139    */
4140   if (nodeToPush==PROPERTY_NULL)
4141     return;
4142
4143   /*
4144    * First push the node to the stack
4145    */
4146   if (This->stackSize == This->stackMaxSize)
4147   {
4148     This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
4149
4150     This->stackToVisit = HeapReAlloc(
4151                            GetProcessHeap(),
4152                            0,
4153                            This->stackToVisit,
4154                            sizeof(ULONG) * This->stackMaxSize);
4155   }
4156
4157   This->stackToVisit[This->stackSize] = nodeToPush;
4158   This->stackSize++;
4159
4160   /*
4161    * Read the root property from the storage.
4162    */
4163   readSuccessful = StorageImpl_ReadProperty(
4164                     This->parentStorage,
4165                     nodeToPush,
4166                     &rootProperty);
4167
4168   if (readSuccessful)
4169   {
4170     assert(rootProperty.sizeOfNameString!=0);
4171
4172     /*
4173      * Push the previous search node in the search stack.
4174      */
4175     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
4176   }
4177 }
4178
4179 static ULONG IEnumSTATSTGImpl_PopSearchNode(
4180   IEnumSTATSTGImpl* This,
4181   BOOL            remove)
4182 {
4183   ULONG topNode;
4184
4185   if (This->stackSize == 0)
4186     return PROPERTY_NULL;
4187
4188   topNode = This->stackToVisit[This->stackSize-1];
4189
4190   if (remove)
4191     This->stackSize--;
4192
4193   return topNode;
4194 }
4195
4196 /*
4197  * Virtual function table for the IEnumSTATSTGImpl class.
4198  */
4199 static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
4200 {
4201     IEnumSTATSTGImpl_QueryInterface,
4202     IEnumSTATSTGImpl_AddRef,
4203     IEnumSTATSTGImpl_Release,
4204     IEnumSTATSTGImpl_Next,
4205     IEnumSTATSTGImpl_Skip,
4206     IEnumSTATSTGImpl_Reset,
4207     IEnumSTATSTGImpl_Clone
4208 };
4209
4210 /******************************************************************************
4211 ** IEnumSTATSTGImpl implementation
4212 */
4213
4214 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
4215   StorageImpl* parentStorage,
4216   ULONG          firstPropertyNode)
4217 {
4218   IEnumSTATSTGImpl* newEnumeration;
4219
4220   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
4221
4222   if (newEnumeration!=0)
4223   {
4224     /*
4225      * Set-up the virtual function table and reference count.
4226      */
4227     newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;
4228     newEnumeration->ref       = 0;
4229
4230     /*
4231      * We want to nail-down the reference to the storage in case the
4232      * enumeration out-lives the storage in the client application.
4233      */
4234     newEnumeration->parentStorage = parentStorage;
4235     IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
4236
4237     newEnumeration->firstPropertyNode   = firstPropertyNode;
4238
4239     /*
4240      * Initialize the search stack
4241      */
4242     newEnumeration->stackSize    = 0;
4243     newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
4244     newEnumeration->stackToVisit =
4245       HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
4246
4247     /*
4248      * Make sure the current node of the iterator is the first one.
4249      */
4250     IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
4251   }
4252
4253   return newEnumeration;
4254 }
4255
4256 /*
4257  * Virtual function table for the Storage32InternalImpl class.
4258  */
4259 static const IStorageVtbl Storage32InternalImpl_Vtbl =
4260 {
4261     StorageBaseImpl_QueryInterface,
4262     StorageBaseImpl_AddRef,
4263     StorageBaseImpl_Release,
4264     StorageBaseImpl_CreateStream,
4265     StorageBaseImpl_OpenStream,
4266     StorageImpl_CreateStorage,
4267     StorageBaseImpl_OpenStorage,
4268     StorageImpl_CopyTo,
4269     StorageImpl_MoveElementTo,
4270     StorageInternalImpl_Commit,
4271     StorageInternalImpl_Revert,
4272     StorageBaseImpl_EnumElements,
4273     StorageImpl_DestroyElement,
4274     StorageBaseImpl_RenameElement,
4275     StorageImpl_SetElementTimes,
4276     StorageBaseImpl_SetClass,
4277     StorageImpl_SetStateBits,
4278     StorageBaseImpl_Stat
4279 };
4280
4281 /******************************************************************************
4282 ** Storage32InternalImpl implementation
4283 */
4284
4285 static StorageInternalImpl* StorageInternalImpl_Construct(
4286   StorageImpl* ancestorStorage,
4287   DWORD        openFlags,
4288   ULONG        rootPropertyIndex)
4289 {
4290   StorageInternalImpl* newStorage;
4291
4292   /*
4293    * Allocate space for the new storage object
4294    */
4295   newStorage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StorageInternalImpl));
4296
4297   if (newStorage!=0)
4298   {
4299     /*
4300      * Initialize the stream list
4301      */
4302     list_init(&newStorage->base.strmHead);
4303
4304     /*
4305      * Initialize the virtual function table.
4306      */
4307     newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
4308     newStorage->base.v_destructor = StorageInternalImpl_Destroy;
4309     newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
4310
4311     /*
4312      * Keep the ancestor storage pointer but do not nail a reference to it.
4313      */
4314     newStorage->base.ancestorStorage = ancestorStorage;
4315
4316     /*
4317      * Keep the index of the root property set for this storage,
4318      */
4319     newStorage->base.rootPropertySetIndex = rootPropertyIndex;
4320
4321     return newStorage;
4322   }
4323
4324   return 0;
4325 }
4326
4327 /******************************************************************************
4328 ** StorageUtl implementation
4329 */
4330
4331 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
4332 {
4333   WORD tmp;
4334
4335   memcpy(&tmp, buffer+offset, sizeof(WORD));
4336   *value = lendian16toh(tmp);
4337 }
4338
4339 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
4340 {
4341   value = htole16(value);
4342   memcpy(buffer+offset, &value, sizeof(WORD));
4343 }
4344
4345 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
4346 {
4347   DWORD tmp;
4348
4349   memcpy(&tmp, buffer+offset, sizeof(DWORD));
4350   *value = lendian32toh(tmp);
4351 }
4352
4353 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
4354 {
4355   value = htole32(value);
4356   memcpy(buffer+offset, &value, sizeof(DWORD));
4357 }
4358
4359 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
4360  ULARGE_INTEGER* value)
4361 {
4362 #ifdef WORDS_BIGENDIAN
4363     ULARGE_INTEGER tmp;
4364
4365     memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
4366     value->u.LowPart = htole32(tmp.u.HighPart);
4367     value->u.HighPart = htole32(tmp.u.LowPart);
4368 #else
4369     memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
4370 #endif
4371 }
4372
4373 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
4374  const ULARGE_INTEGER *value)
4375 {
4376 #ifdef WORDS_BIGENDIAN
4377     ULARGE_INTEGER tmp;
4378
4379     tmp.u.LowPart = htole32(value->u.HighPart);
4380     tmp.u.HighPart = htole32(value->u.LowPart);
4381     memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
4382 #else
4383     memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
4384 #endif
4385 }
4386
4387 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
4388 {
4389   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
4390   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
4391   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
4392
4393   memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
4394 }
4395
4396 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
4397 {
4398   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
4399   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
4400   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
4401
4402   memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
4403 }
4404
4405 void StorageUtl_CopyPropertyToSTATSTG(
4406   STATSTG*              destination,
4407   const StgProperty*    source,
4408   int                   statFlags)
4409 {
4410   /*
4411    * The copy of the string occurs only when the flag is not set
4412    */
4413   if( ((statFlags & STATFLAG_NONAME) != 0) || 
4414        (source->name == NULL) || 
4415        (source->name[0] == 0) )
4416   {
4417     destination->pwcsName = 0;
4418   }
4419   else
4420   {
4421     destination->pwcsName =
4422       CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
4423
4424     strcpyW(destination->pwcsName, source->name);
4425   }
4426
4427   switch (source->propertyType)
4428   {
4429     case PROPTYPE_STORAGE:
4430     case PROPTYPE_ROOT:
4431       destination->type = STGTY_STORAGE;
4432       break;
4433     case PROPTYPE_STREAM:
4434       destination->type = STGTY_STREAM;
4435       break;
4436     default:
4437       destination->type = STGTY_STREAM;
4438       break;
4439   }
4440
4441   destination->cbSize            = source->size;
4442 /*
4443   currentReturnStruct->mtime     = {0}; TODO
4444   currentReturnStruct->ctime     = {0};
4445   currentReturnStruct->atime     = {0};
4446 */
4447   destination->grfMode           = 0;
4448   destination->grfLocksSupported = 0;
4449   destination->clsid             = source->propertyUniqueID;
4450   destination->grfStateBits      = 0;
4451   destination->reserved          = 0;
4452 }
4453
4454 /******************************************************************************
4455 ** BlockChainStream implementation
4456 */
4457
4458 BlockChainStream* BlockChainStream_Construct(
4459   StorageImpl* parentStorage,
4460   ULONG*         headOfStreamPlaceHolder,
4461   ULONG          propertyIndex)
4462 {
4463   BlockChainStream* newStream;
4464   ULONG blockIndex;
4465
4466   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4467
4468   newStream->parentStorage           = parentStorage;
4469   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4470   newStream->ownerPropertyIndex      = propertyIndex;
4471   newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
4472   newStream->tailIndex               = BLOCK_END_OF_CHAIN;
4473   newStream->numBlocks               = 0;
4474
4475   blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4476
4477   while (blockIndex != BLOCK_END_OF_CHAIN)
4478   {
4479     newStream->numBlocks++;
4480     newStream->tailIndex = blockIndex;
4481
4482     if(FAILED(StorageImpl_GetNextBlockInChain(
4483               parentStorage,
4484               blockIndex,
4485               &blockIndex)))
4486     {
4487       HeapFree(GetProcessHeap(), 0, newStream);
4488       return NULL;
4489     }
4490   }
4491
4492   return newStream;
4493 }
4494
4495 void BlockChainStream_Destroy(BlockChainStream* This)
4496 {
4497   HeapFree(GetProcessHeap(), 0, This);
4498 }
4499
4500 /******************************************************************************
4501  *      BlockChainStream_GetHeadOfChain
4502  *
4503  * Returns the head of this stream chain.
4504  * Some special chains don't have properties, their heads are kept in
4505  * This->headOfStreamPlaceHolder.
4506  *
4507  */
4508 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4509 {
4510   StgProperty chainProperty;
4511   BOOL      readSuccessful;
4512
4513   if (This->headOfStreamPlaceHolder != 0)
4514     return *(This->headOfStreamPlaceHolder);
4515
4516   if (This->ownerPropertyIndex != PROPERTY_NULL)
4517   {
4518     readSuccessful = StorageImpl_ReadProperty(
4519                       This->parentStorage,
4520                       This->ownerPropertyIndex,
4521                       &chainProperty);
4522
4523     if (readSuccessful)
4524     {
4525       return chainProperty.startingBlock;
4526     }
4527   }
4528
4529   return BLOCK_END_OF_CHAIN;
4530 }
4531
4532 /******************************************************************************
4533  *       BlockChainStream_GetCount
4534  *
4535  * Returns the number of blocks that comprises this chain.
4536  * This is not the size of the stream as the last block may not be full!
4537  *
4538  */
4539 static ULONG BlockChainStream_GetCount(BlockChainStream* This)
4540 {
4541   ULONG blockIndex;
4542   ULONG count = 0;
4543
4544   blockIndex = BlockChainStream_GetHeadOfChain(This);
4545
4546   while (blockIndex != BLOCK_END_OF_CHAIN)
4547   {
4548     count++;
4549
4550     if(FAILED(StorageImpl_GetNextBlockInChain(
4551                    This->parentStorage,
4552                    blockIndex,
4553                    &blockIndex)))
4554       return 0;
4555   }
4556
4557   return count;
4558 }
4559
4560 /******************************************************************************
4561  *      BlockChainStream_ReadAt
4562  *
4563  * Reads a specified number of bytes from this chain at the specified offset.
4564  * bytesRead may be NULL.
4565  * Failure will be returned if the specified number of bytes has not been read.
4566  */
4567 HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
4568   ULARGE_INTEGER offset,
4569   ULONG          size,
4570   void*          buffer,
4571   ULONG*         bytesRead)
4572 {
4573   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4574   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4575   ULONG bytesToReadInBuffer;
4576   ULONG blockIndex;
4577   BYTE* bufferWalker;
4578
4579   TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
4580
4581   /*
4582    * Find the first block in the stream that contains part of the buffer.
4583    */
4584   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4585        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4586        (blockNoInSequence < This->lastBlockNoInSequence) )
4587   {
4588     blockIndex = BlockChainStream_GetHeadOfChain(This);
4589     This->lastBlockNoInSequence = blockNoInSequence;
4590   }
4591   else
4592   {
4593     ULONG temp = blockNoInSequence;
4594
4595     blockIndex = This->lastBlockNoInSequenceIndex;
4596     blockNoInSequence -= This->lastBlockNoInSequence;
4597     This->lastBlockNoInSequence = temp;
4598   }
4599
4600   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4601   {
4602     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4603       return STG_E_DOCFILECORRUPT;
4604     blockNoInSequence--;
4605   }
4606
4607   if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN))
4608       return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */
4609
4610   This->lastBlockNoInSequenceIndex = blockIndex;
4611
4612   /*
4613    * Start reading the buffer.
4614    */
4615   *bytesRead   = 0;
4616   bufferWalker = buffer;
4617
4618   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4619   {
4620     ULARGE_INTEGER ulOffset;
4621     DWORD bytesReadAt;
4622     /*
4623      * Calculate how many bytes we can copy from this big block.
4624      */
4625     bytesToReadInBuffer =
4626       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4627
4628      TRACE("block %i\n",blockIndex);
4629      ulOffset.u.HighPart = 0;
4630      ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
4631                              offsetInBlock;
4632
4633      StorageImpl_ReadAt(This->parentStorage,
4634          ulOffset,
4635          bufferWalker,
4636          bytesToReadInBuffer,
4637          &bytesReadAt);
4638     /*
4639      * Step to the next big block.
4640      */
4641     if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4642       return STG_E_DOCFILECORRUPT;
4643
4644     bufferWalker += bytesReadAt;
4645     size         -= bytesReadAt;
4646     *bytesRead   += bytesReadAt;
4647     offsetInBlock = 0;  /* There is no offset on the next block */
4648
4649     if (bytesToReadInBuffer != bytesReadAt)
4650         break;
4651   }
4652
4653   return (size == 0) ? S_OK : STG_E_READFAULT;
4654 }
4655
4656 /******************************************************************************
4657  *      BlockChainStream_WriteAt
4658  *
4659  * Writes the specified number of bytes to this chain at the specified offset.
4660  * Will fail if not all specified number of bytes have been written.
4661  */
4662 HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
4663   ULARGE_INTEGER    offset,
4664   ULONG             size,
4665   const void*       buffer,
4666   ULONG*            bytesWritten)
4667 {
4668   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4669   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4670   ULONG bytesToWrite;
4671   ULONG blockIndex;
4672   const BYTE* bufferWalker;
4673
4674   /*
4675    * Find the first block in the stream that contains part of the buffer.
4676    */
4677   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4678        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4679        (blockNoInSequence < This->lastBlockNoInSequence) )
4680   {
4681     blockIndex = BlockChainStream_GetHeadOfChain(This);
4682     This->lastBlockNoInSequence = blockNoInSequence;
4683   }
4684   else
4685   {
4686     ULONG temp = blockNoInSequence;
4687
4688     blockIndex = This->lastBlockNoInSequenceIndex;
4689     blockNoInSequence -= This->lastBlockNoInSequence;
4690     This->lastBlockNoInSequence = temp;
4691   }
4692
4693   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4694   {
4695     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4696                                               &blockIndex)))
4697       return STG_E_DOCFILECORRUPT;
4698     blockNoInSequence--;
4699   }
4700
4701   This->lastBlockNoInSequenceIndex = blockIndex;
4702
4703   /* BlockChainStream_SetSize should have already been called to ensure we have
4704    * enough blocks in the chain to write into */
4705   if (blockIndex == BLOCK_END_OF_CHAIN)
4706   {
4707     ERR("not enough blocks in chain to write data\n");
4708     return STG_E_DOCFILECORRUPT;
4709   }
4710
4711   *bytesWritten   = 0;
4712   bufferWalker = buffer;
4713
4714   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4715   {
4716     ULARGE_INTEGER ulOffset;
4717     DWORD bytesWrittenAt;
4718     /*
4719      * Calculate how many bytes we can copy from this big block.
4720      */
4721     bytesToWrite =
4722       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4723
4724     TRACE("block %i\n",blockIndex);
4725     ulOffset.u.HighPart = 0;
4726     ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
4727                              offsetInBlock;
4728
4729     StorageImpl_WriteAt(This->parentStorage,
4730          ulOffset,
4731          bufferWalker,
4732          bytesToWrite,
4733          &bytesWrittenAt);
4734
4735     /*
4736      * Step to the next big block.
4737      */
4738     if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4739                                               &blockIndex)))
4740       return STG_E_DOCFILECORRUPT;
4741
4742     bufferWalker  += bytesWrittenAt;
4743     size          -= bytesWrittenAt;
4744     *bytesWritten += bytesWrittenAt;
4745     offsetInBlock  = 0;      /* There is no offset on the next block */
4746
4747     if (bytesWrittenAt != bytesToWrite)
4748       break;
4749   }
4750
4751   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
4752 }
4753
4754 /******************************************************************************
4755  *      BlockChainStream_Shrink
4756  *
4757  * Shrinks this chain in the big block depot.
4758  */
4759 static BOOL BlockChainStream_Shrink(BlockChainStream* This,
4760                                     ULARGE_INTEGER    newSize)
4761 {
4762   ULONG blockIndex, extraBlock;
4763   ULONG numBlocks;
4764   ULONG count = 1;
4765
4766   /*
4767    * Reset the last accessed block cache.
4768    */
4769   This->lastBlockNoInSequence = 0xFFFFFFFF;
4770   This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4771
4772   /*
4773    * Figure out how many blocks are needed to contain the new size
4774    */
4775   numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4776
4777   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4778     numBlocks++;
4779
4780   blockIndex = BlockChainStream_GetHeadOfChain(This);
4781
4782   /*
4783    * Go to the new end of chain
4784    */
4785   while (count < numBlocks)
4786   {
4787     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4788                                               &blockIndex)))
4789       return FALSE;
4790     count++;
4791   }
4792
4793   /* Get the next block before marking the new end */
4794   if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4795                                             &extraBlock)))
4796     return FALSE;
4797
4798   /* Mark the new end of chain */
4799   StorageImpl_SetNextBlockInChain(
4800     This->parentStorage,
4801     blockIndex,
4802     BLOCK_END_OF_CHAIN);
4803
4804   This->tailIndex = blockIndex;
4805   This->numBlocks = numBlocks;
4806
4807   /*
4808    * Mark the extra blocks as free
4809    */
4810   while (extraBlock != BLOCK_END_OF_CHAIN)
4811   {
4812     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock,
4813                                               &blockIndex)))
4814       return FALSE;
4815     StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4816     extraBlock = blockIndex;
4817   }
4818
4819   return TRUE;
4820 }
4821
4822 /******************************************************************************
4823  *      BlockChainStream_Enlarge
4824  *
4825  * Grows this chain in the big block depot.
4826  */
4827 static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4828                                      ULARGE_INTEGER    newSize)
4829 {
4830   ULONG blockIndex, currentBlock;
4831   ULONG newNumBlocks;
4832   ULONG oldNumBlocks = 0;
4833
4834   blockIndex = BlockChainStream_GetHeadOfChain(This);
4835
4836   /*
4837    * Empty chain. Create the head.
4838    */
4839   if (blockIndex == BLOCK_END_OF_CHAIN)
4840   {
4841     blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4842     StorageImpl_SetNextBlockInChain(This->parentStorage,
4843                                       blockIndex,
4844                                       BLOCK_END_OF_CHAIN);
4845
4846     if (This->headOfStreamPlaceHolder != 0)
4847     {
4848       *(This->headOfStreamPlaceHolder) = blockIndex;
4849     }
4850     else
4851     {
4852       StgProperty chainProp;
4853       assert(This->ownerPropertyIndex != PROPERTY_NULL);
4854
4855       StorageImpl_ReadProperty(
4856         This->parentStorage,
4857         This->ownerPropertyIndex,
4858         &chainProp);
4859
4860       chainProp.startingBlock = blockIndex;
4861
4862       StorageImpl_WriteProperty(
4863         This->parentStorage,
4864         This->ownerPropertyIndex,
4865         &chainProp);
4866     }
4867
4868     This->tailIndex = blockIndex;
4869     This->numBlocks = 1;
4870   }
4871
4872   /*
4873    * Figure out how many blocks are needed to contain this stream
4874    */
4875   newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4876
4877   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4878     newNumBlocks++;
4879
4880   /*
4881    * Go to the current end of chain
4882    */
4883   if (This->tailIndex == BLOCK_END_OF_CHAIN)
4884   {
4885     currentBlock = blockIndex;
4886
4887     while (blockIndex != BLOCK_END_OF_CHAIN)
4888     {
4889       This->numBlocks++;
4890       currentBlock = blockIndex;
4891
4892       if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
4893                                                 &blockIndex)))
4894         return FALSE;
4895     }
4896
4897     This->tailIndex = currentBlock;
4898   }
4899
4900   currentBlock = This->tailIndex;
4901   oldNumBlocks = This->numBlocks;
4902
4903   /*
4904    * Add new blocks to the chain
4905    */
4906   if (oldNumBlocks < newNumBlocks)
4907   {
4908     while (oldNumBlocks < newNumBlocks)
4909     {
4910       blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4911
4912       StorageImpl_SetNextBlockInChain(
4913         This->parentStorage,
4914         currentBlock,
4915         blockIndex);
4916
4917       StorageImpl_SetNextBlockInChain(
4918         This->parentStorage,
4919         blockIndex,
4920         BLOCK_END_OF_CHAIN);
4921
4922       currentBlock = blockIndex;
4923       oldNumBlocks++;
4924     }
4925
4926     This->tailIndex = blockIndex;
4927     This->numBlocks = newNumBlocks;
4928   }
4929
4930   return TRUE;
4931 }
4932
4933 /******************************************************************************
4934  *      BlockChainStream_SetSize
4935  *
4936  * Sets the size of this stream. The big block depot will be updated.
4937  * The file will grow if we grow the chain.
4938  *
4939  * TODO: Free the actual blocks in the file when we shrink the chain.
4940  *       Currently, the blocks are still in the file. So the file size
4941  *       doesn't shrink even if we shrink streams.
4942  */
4943 BOOL BlockChainStream_SetSize(
4944   BlockChainStream* This,
4945   ULARGE_INTEGER    newSize)
4946 {
4947   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4948
4949   if (newSize.u.LowPart == size.u.LowPart)
4950     return TRUE;
4951
4952   if (newSize.u.LowPart < size.u.LowPart)
4953   {
4954     BlockChainStream_Shrink(This, newSize);
4955   }
4956   else
4957   {
4958     BlockChainStream_Enlarge(This, newSize);
4959   }
4960
4961   return TRUE;
4962 }
4963
4964 /******************************************************************************
4965  *      BlockChainStream_GetSize
4966  *
4967  * Returns the size of this chain.
4968  * Will return the block count if this chain doesn't have a property.
4969  */
4970 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4971 {
4972   StgProperty chainProperty;
4973
4974   if(This->headOfStreamPlaceHolder == NULL)
4975   {
4976     /*
4977      * This chain is a data stream read the property and return
4978      * the appropriate size
4979      */
4980     StorageImpl_ReadProperty(
4981       This->parentStorage,
4982       This->ownerPropertyIndex,
4983       &chainProperty);
4984
4985     return chainProperty.size;
4986   }
4987   else
4988   {
4989     /*
4990      * this chain is a chain that does not have a property, figure out the
4991      * size by making the product number of used blocks times the
4992      * size of them
4993      */
4994     ULARGE_INTEGER result;
4995     result.u.HighPart = 0;
4996
4997     result.u.LowPart  =
4998       BlockChainStream_GetCount(This) *
4999       This->parentStorage->bigBlockSize;
5000
5001     return result;
5002   }
5003 }
5004
5005 /******************************************************************************
5006 ** SmallBlockChainStream implementation
5007 */
5008
5009 SmallBlockChainStream* SmallBlockChainStream_Construct(
5010   StorageImpl* parentStorage,
5011   ULONG*         headOfStreamPlaceHolder,
5012   ULONG          propertyIndex)
5013 {
5014   SmallBlockChainStream* newStream;
5015
5016   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
5017
5018   newStream->parentStorage      = parentStorage;
5019   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
5020   newStream->ownerPropertyIndex = propertyIndex;
5021
5022   return newStream;
5023 }
5024
5025 void SmallBlockChainStream_Destroy(
5026   SmallBlockChainStream* This)
5027 {
5028   HeapFree(GetProcessHeap(), 0, This);
5029 }
5030
5031 /******************************************************************************
5032  *      SmallBlockChainStream_GetHeadOfChain
5033  *
5034  * Returns the head of this chain of small blocks.
5035  */
5036 static ULONG SmallBlockChainStream_GetHeadOfChain(
5037   SmallBlockChainStream* This)
5038 {
5039   StgProperty chainProperty;
5040   BOOL      readSuccessful;
5041
5042   if (This->headOfStreamPlaceHolder != NULL)
5043     return *(This->headOfStreamPlaceHolder);
5044
5045   if (This->ownerPropertyIndex)
5046   {
5047     readSuccessful = StorageImpl_ReadProperty(
5048                       This->parentStorage,
5049                       This->ownerPropertyIndex,
5050                       &chainProperty);
5051
5052     if (readSuccessful)
5053     {
5054       return chainProperty.startingBlock;
5055     }
5056
5057   }
5058
5059   return BLOCK_END_OF_CHAIN;
5060 }
5061
5062 /******************************************************************************
5063  *      SmallBlockChainStream_GetNextBlockInChain
5064  *
5065  * Returns the index of the next small block in this chain.
5066  *
5067  * Return Values:
5068  *    - BLOCK_END_OF_CHAIN: end of this chain
5069  *    - BLOCK_UNUSED: small block 'blockIndex' is free
5070  */
5071 static HRESULT SmallBlockChainStream_GetNextBlockInChain(
5072   SmallBlockChainStream* This,
5073   ULONG                  blockIndex,
5074   ULONG*                 nextBlockInChain)
5075 {
5076   ULARGE_INTEGER offsetOfBlockInDepot;
5077   DWORD  buffer;
5078   ULONG  bytesRead;
5079   HRESULT res;
5080
5081   *nextBlockInChain = BLOCK_END_OF_CHAIN;
5082
5083   offsetOfBlockInDepot.u.HighPart = 0;
5084   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
5085
5086   /*
5087    * Read those bytes in the buffer from the small block file.
5088    */
5089   res = BlockChainStream_ReadAt(
5090               This->parentStorage->smallBlockDepotChain,
5091               offsetOfBlockInDepot,
5092               sizeof(DWORD),
5093               &buffer,
5094               &bytesRead);
5095
5096   if (SUCCEEDED(res))
5097   {
5098     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
5099     return S_OK;
5100   }
5101
5102   return res;
5103 }
5104
5105 /******************************************************************************
5106  *       SmallBlockChainStream_SetNextBlockInChain
5107  *
5108  * Writes the index of the next block of the specified block in the small
5109  * block depot.
5110  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
5111  * To flag a block as free use BLOCK_UNUSED as nextBlock.
5112  */
5113 static void SmallBlockChainStream_SetNextBlockInChain(
5114   SmallBlockChainStream* This,
5115   ULONG                  blockIndex,
5116   ULONG                  nextBlock)
5117 {
5118   ULARGE_INTEGER offsetOfBlockInDepot;
5119   DWORD  buffer;
5120   ULONG  bytesWritten;
5121
5122   offsetOfBlockInDepot.u.HighPart = 0;
5123   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
5124
5125   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
5126
5127   /*
5128    * Read those bytes in the buffer from the small block file.
5129    */
5130   BlockChainStream_WriteAt(
5131     This->parentStorage->smallBlockDepotChain,
5132     offsetOfBlockInDepot,
5133     sizeof(DWORD),
5134     &buffer,
5135     &bytesWritten);
5136 }
5137
5138 /******************************************************************************
5139  *      SmallBlockChainStream_FreeBlock
5140  *
5141  * Flag small block 'blockIndex' as free in the small block depot.
5142  */
5143 static void SmallBlockChainStream_FreeBlock(
5144   SmallBlockChainStream* This,
5145   ULONG                  blockIndex)
5146 {
5147   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
5148 }
5149
5150 /******************************************************************************
5151  *      SmallBlockChainStream_GetNextFreeBlock
5152  *
5153  * Returns the index of a free small block. The small block depot will be
5154  * enlarged if necessary. The small block chain will also be enlarged if
5155  * necessary.
5156  */
5157 static ULONG SmallBlockChainStream_GetNextFreeBlock(
5158   SmallBlockChainStream* This)
5159 {
5160   ULARGE_INTEGER offsetOfBlockInDepot;
5161   DWORD buffer;
5162   ULONG bytesRead;
5163   ULONG blockIndex = 0;
5164   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
5165   HRESULT res = S_OK;
5166   ULONG smallBlocksPerBigBlock;
5167
5168   offsetOfBlockInDepot.u.HighPart = 0;
5169
5170   /*
5171    * Scan the small block depot for a free block
5172    */
5173   while (nextBlockIndex != BLOCK_UNUSED)
5174   {
5175     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
5176
5177     res = BlockChainStream_ReadAt(
5178                 This->parentStorage->smallBlockDepotChain,
5179                 offsetOfBlockInDepot,
5180                 sizeof(DWORD),
5181                 &buffer,
5182                 &bytesRead);
5183
5184     /*
5185      * If we run out of space for the small block depot, enlarge it
5186      */
5187     if (SUCCEEDED(res))
5188     {
5189       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
5190
5191       if (nextBlockIndex != BLOCK_UNUSED)
5192         blockIndex++;
5193     }
5194     else
5195     {
5196       ULONG count =
5197         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
5198
5199       ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
5200       ULONG nextBlock, newsbdIndex;
5201       BYTE smallBlockDepot[BIG_BLOCK_SIZE];
5202
5203       nextBlock = sbdIndex;
5204       while (nextBlock != BLOCK_END_OF_CHAIN)
5205       {
5206         sbdIndex = nextBlock;
5207         StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);
5208       }
5209
5210       newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5211       if (sbdIndex != BLOCK_END_OF_CHAIN)
5212         StorageImpl_SetNextBlockInChain(
5213           This->parentStorage,
5214           sbdIndex,
5215           newsbdIndex);
5216
5217       StorageImpl_SetNextBlockInChain(
5218         This->parentStorage,
5219         newsbdIndex,
5220         BLOCK_END_OF_CHAIN);
5221
5222       /*
5223        * Initialize all the small blocks to free
5224        */
5225       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
5226       StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot);
5227
5228       if (count == 0)
5229       {
5230         /*
5231          * We have just created the small block depot.
5232          */
5233         StgProperty rootProp;
5234         ULONG sbStartIndex;
5235
5236         /*
5237          * Save it in the header
5238          */
5239         This->parentStorage->smallBlockDepotStart = newsbdIndex;
5240         StorageImpl_SaveFileHeader(This->parentStorage);
5241
5242         /*
5243          * And allocate the first big block that will contain small blocks
5244          */
5245         sbStartIndex =
5246           StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5247
5248         StorageImpl_SetNextBlockInChain(
5249           This->parentStorage,
5250           sbStartIndex,
5251           BLOCK_END_OF_CHAIN);
5252
5253         StorageImpl_ReadProperty(
5254           This->parentStorage,
5255           This->parentStorage->base.rootPropertySetIndex,
5256           &rootProp);
5257
5258         rootProp.startingBlock = sbStartIndex;
5259         rootProp.size.u.HighPart = 0;
5260         rootProp.size.u.LowPart  = This->parentStorage->bigBlockSize;
5261
5262         StorageImpl_WriteProperty(
5263           This->parentStorage,
5264           This->parentStorage->base.rootPropertySetIndex,
5265           &rootProp);
5266       }
5267       else
5268         StorageImpl_SaveFileHeader(This->parentStorage);
5269     }
5270   }
5271
5272   smallBlocksPerBigBlock =
5273     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
5274
5275   /*
5276    * Verify if we have to allocate big blocks to contain small blocks
5277    */
5278   if (blockIndex % smallBlocksPerBigBlock == 0)
5279   {
5280     StgProperty rootProp;
5281     ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
5282
5283     StorageImpl_ReadProperty(
5284       This->parentStorage,
5285       This->parentStorage->base.rootPropertySetIndex,
5286       &rootProp);
5287
5288     if (rootProp.size.u.LowPart <
5289        (blocksRequired * This->parentStorage->bigBlockSize))
5290     {
5291       rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
5292
5293       BlockChainStream_SetSize(
5294         This->parentStorage->smallBlockRootChain,
5295         rootProp.size);
5296
5297       StorageImpl_WriteProperty(
5298         This->parentStorage,
5299         This->parentStorage->base.rootPropertySetIndex,
5300         &rootProp);
5301     }
5302   }
5303
5304   return blockIndex;
5305 }
5306
5307 /******************************************************************************
5308  *      SmallBlockChainStream_ReadAt
5309  *
5310  * Reads a specified number of bytes from this chain at the specified offset.
5311  * bytesRead may be NULL.
5312  * Failure will be returned if the specified number of bytes has not been read.
5313  */
5314 HRESULT SmallBlockChainStream_ReadAt(
5315   SmallBlockChainStream* This,
5316   ULARGE_INTEGER         offset,
5317   ULONG                  size,
5318   void*                  buffer,
5319   ULONG*                 bytesRead)
5320 {
5321   HRESULT rc = S_OK;
5322   ULARGE_INTEGER offsetInBigBlockFile;
5323   ULONG blockNoInSequence =
5324     offset.u.LowPart / This->parentStorage->smallBlockSize;
5325
5326   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5327   ULONG bytesToReadInBuffer;
5328   ULONG blockIndex;
5329   ULONG bytesReadFromBigBlockFile;
5330   BYTE* bufferWalker;
5331
5332   /*
5333    * This should never happen on a small block file.
5334    */
5335   assert(offset.u.HighPart==0);
5336
5337   /*
5338    * Find the first block in the stream that contains part of the buffer.
5339    */
5340   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5341
5342   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5343   {
5344     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5345     if(FAILED(rc))
5346       return rc;
5347     blockNoInSequence--;
5348   }
5349
5350   /*
5351    * Start reading the buffer.
5352    */
5353   *bytesRead   = 0;
5354   bufferWalker = buffer;
5355
5356   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5357   {
5358     /*
5359      * Calculate how many bytes we can copy from this small block.
5360      */
5361     bytesToReadInBuffer =
5362       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5363
5364     /*
5365      * Calculate the offset of the small block in the small block file.
5366      */
5367     offsetInBigBlockFile.u.HighPart  = 0;
5368     offsetInBigBlockFile.u.LowPart   =
5369       blockIndex * This->parentStorage->smallBlockSize;
5370
5371     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5372
5373     /*
5374      * Read those bytes in the buffer from the small block file.
5375      * The small block has already been identified so it shouldn't fail
5376      * unless the file is corrupt.
5377      */
5378     rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
5379       offsetInBigBlockFile,
5380       bytesToReadInBuffer,
5381       bufferWalker,
5382       &bytesReadFromBigBlockFile);
5383
5384     if (FAILED(rc))
5385       return rc;
5386
5387     /*
5388      * Step to the next big block.
5389      */
5390     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5391     if(FAILED(rc))
5392       return STG_E_DOCFILECORRUPT;
5393
5394     bufferWalker += bytesReadFromBigBlockFile;
5395     size         -= bytesReadFromBigBlockFile;
5396     *bytesRead   += bytesReadFromBigBlockFile;
5397     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
5398   }
5399
5400   return (size == 0) ? S_OK : STG_E_READFAULT;
5401 }
5402
5403 /******************************************************************************
5404  *       SmallBlockChainStream_WriteAt
5405  *
5406  * Writes the specified number of bytes to this chain at the specified offset.
5407  * Will fail if not all specified number of bytes have been written.
5408  */
5409 HRESULT SmallBlockChainStream_WriteAt(
5410   SmallBlockChainStream* This,
5411   ULARGE_INTEGER offset,
5412   ULONG          size,
5413   const void*    buffer,
5414   ULONG*         bytesWritten)
5415 {
5416   ULARGE_INTEGER offsetInBigBlockFile;
5417   ULONG blockNoInSequence =
5418     offset.u.LowPart / This->parentStorage->smallBlockSize;
5419
5420   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5421   ULONG bytesToWriteInBuffer;
5422   ULONG blockIndex;
5423   ULONG bytesWrittenToBigBlockFile;
5424   const BYTE* bufferWalker;
5425   HRESULT res;
5426
5427   /*
5428    * This should never happen on a small block file.
5429    */
5430   assert(offset.u.HighPart==0);
5431
5432   /*
5433    * Find the first block in the stream that contains part of the buffer.
5434    */
5435   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5436
5437   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5438   {
5439     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5440       return STG_E_DOCFILECORRUPT;
5441     blockNoInSequence--;
5442   }
5443
5444   /*
5445    * Start writing the buffer.
5446    */
5447   *bytesWritten   = 0;
5448   bufferWalker = buffer;
5449   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5450   {
5451     /*
5452      * Calculate how many bytes we can copy to this small block.
5453      */
5454     bytesToWriteInBuffer =
5455       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5456
5457     /*
5458      * Calculate the offset of the small block in the small block file.
5459      */
5460     offsetInBigBlockFile.u.HighPart  = 0;
5461     offsetInBigBlockFile.u.LowPart   =
5462       blockIndex * This->parentStorage->smallBlockSize;
5463
5464     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5465
5466     /*
5467      * Write those bytes in the buffer to the small block file.
5468      */
5469     res = BlockChainStream_WriteAt(
5470       This->parentStorage->smallBlockRootChain,
5471       offsetInBigBlockFile,
5472       bytesToWriteInBuffer,
5473       bufferWalker,
5474       &bytesWrittenToBigBlockFile);
5475     if (FAILED(res))
5476       return res;
5477
5478     /*
5479      * Step to the next big block.
5480      */
5481     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5482                                                         &blockIndex)))
5483       return FALSE;
5484     bufferWalker  += bytesWrittenToBigBlockFile;
5485     size          -= bytesWrittenToBigBlockFile;
5486     *bytesWritten += bytesWrittenToBigBlockFile;
5487     offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
5488   }
5489
5490   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
5491 }
5492
5493 /******************************************************************************
5494  *       SmallBlockChainStream_Shrink
5495  *
5496  * Shrinks this chain in the small block depot.
5497  */
5498 static BOOL SmallBlockChainStream_Shrink(
5499   SmallBlockChainStream* This,
5500   ULARGE_INTEGER newSize)
5501 {
5502   ULONG blockIndex, extraBlock;
5503   ULONG numBlocks;
5504   ULONG count = 0;
5505
5506   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5507
5508   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5509     numBlocks++;
5510
5511   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5512
5513   /*
5514    * Go to the new end of chain
5515    */
5516   while (count < numBlocks)
5517   {
5518     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5519                                                         &blockIndex)))
5520       return FALSE;
5521     count++;
5522   }
5523
5524   /*
5525    * If the count is 0, we have a special case, the head of the chain was
5526    * just freed.
5527    */
5528   if (count == 0)
5529   {
5530     StgProperty chainProp;
5531
5532     StorageImpl_ReadProperty(This->parentStorage,
5533                              This->ownerPropertyIndex,
5534                              &chainProp);
5535
5536     chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5537
5538     StorageImpl_WriteProperty(This->parentStorage,
5539                               This->ownerPropertyIndex,
5540                               &chainProp);
5541
5542     /*
5543      * We start freeing the chain at the head block.
5544      */
5545     extraBlock = blockIndex;
5546   }
5547   else
5548   {
5549     /* Get the next block before marking the new end */
5550     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5551                                                         &extraBlock)))
5552       return FALSE;
5553
5554     /* Mark the new end of chain */
5555     SmallBlockChainStream_SetNextBlockInChain(
5556       This,
5557       blockIndex,
5558       BLOCK_END_OF_CHAIN);
5559   }
5560
5561   /*
5562    * Mark the extra blocks as free
5563    */
5564   while (extraBlock != BLOCK_END_OF_CHAIN)
5565   {
5566     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
5567                                                         &blockIndex)))
5568       return FALSE;
5569     SmallBlockChainStream_FreeBlock(This, extraBlock);
5570     extraBlock = blockIndex;
5571   }
5572
5573   return TRUE;
5574 }
5575
5576 /******************************************************************************
5577  *      SmallBlockChainStream_Enlarge
5578  *
5579  * Grows this chain in the small block depot.
5580  */
5581 static BOOL SmallBlockChainStream_Enlarge(
5582   SmallBlockChainStream* This,
5583   ULARGE_INTEGER newSize)
5584 {
5585   ULONG blockIndex, currentBlock;
5586   ULONG newNumBlocks;
5587   ULONG oldNumBlocks = 0;
5588
5589   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5590
5591   /*
5592    * Empty chain. Create the head.
5593    */
5594   if (blockIndex == BLOCK_END_OF_CHAIN)
5595   {
5596     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5597     SmallBlockChainStream_SetNextBlockInChain(
5598         This,
5599         blockIndex,
5600         BLOCK_END_OF_CHAIN);
5601
5602     if (This->headOfStreamPlaceHolder != NULL)
5603     {
5604       *(This->headOfStreamPlaceHolder) = blockIndex;
5605     }
5606     else
5607     {
5608       StgProperty chainProp;
5609
5610       StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5611                                    &chainProp);
5612
5613       chainProp.startingBlock = blockIndex;
5614
5615       StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5616                                   &chainProp);
5617     }
5618   }
5619
5620   currentBlock = blockIndex;
5621
5622   /*
5623    * Figure out how many blocks are needed to contain this stream
5624    */
5625   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5626
5627   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5628     newNumBlocks++;
5629
5630   /*
5631    * Go to the current end of chain
5632    */
5633   while (blockIndex != BLOCK_END_OF_CHAIN)
5634   {
5635     oldNumBlocks++;
5636     currentBlock = blockIndex;
5637     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
5638       return FALSE;
5639   }
5640
5641   /*
5642    * Add new blocks to the chain
5643    */
5644   while (oldNumBlocks < newNumBlocks)
5645   {
5646     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5647     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5648
5649     SmallBlockChainStream_SetNextBlockInChain(
5650       This,
5651       blockIndex,
5652       BLOCK_END_OF_CHAIN);
5653
5654     currentBlock = blockIndex;
5655     oldNumBlocks++;
5656   }
5657
5658   return TRUE;
5659 }
5660
5661 /******************************************************************************
5662  *      SmallBlockChainStream_SetSize
5663  *
5664  * Sets the size of this stream.
5665  * The file will grow if we grow the chain.
5666  *
5667  * TODO: Free the actual blocks in the file when we shrink the chain.
5668  *       Currently, the blocks are still in the file. So the file size
5669  *       doesn't shrink even if we shrink streams.
5670  */
5671 BOOL SmallBlockChainStream_SetSize(
5672                 SmallBlockChainStream* This,
5673                 ULARGE_INTEGER    newSize)
5674 {
5675   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5676
5677   if (newSize.u.LowPart == size.u.LowPart)
5678     return TRUE;
5679
5680   if (newSize.u.LowPart < size.u.LowPart)
5681   {
5682     SmallBlockChainStream_Shrink(This, newSize);
5683   }
5684   else
5685   {
5686     SmallBlockChainStream_Enlarge(This, newSize);
5687   }
5688
5689   return TRUE;
5690 }
5691
5692 /******************************************************************************
5693  *       SmallBlockChainStream_GetCount
5694  *
5695  * Returns the number of small blocks that comprises this chain.
5696  * This is not the size of the stream as the last block may not be full!
5697  *
5698  */
5699 static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5700 {
5701     ULONG blockIndex;
5702     ULONG count = 0;
5703
5704     blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5705
5706     while(blockIndex != BLOCK_END_OF_CHAIN)
5707     {
5708         count++;
5709
5710         if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This,
5711                         blockIndex, &blockIndex)))
5712             return 0;
5713     }
5714
5715     return count;
5716 }
5717
5718 /******************************************************************************
5719  *      SmallBlockChainStream_GetSize
5720  *
5721  * Returns the size of this chain.
5722  */
5723 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5724 {
5725   StgProperty chainProperty;
5726
5727   if(This->headOfStreamPlaceHolder != NULL)
5728   {
5729     ULARGE_INTEGER result;
5730     result.u.HighPart = 0;
5731
5732     result.u.LowPart = SmallBlockChainStream_GetCount(This) *
5733         This->parentStorage->smallBlockSize;
5734
5735     return result;
5736   }
5737
5738   StorageImpl_ReadProperty(
5739     This->parentStorage,
5740     This->ownerPropertyIndex,
5741     &chainProperty);
5742
5743   return chainProperty.size;
5744 }
5745
5746 /******************************************************************************
5747  *    StgCreateDocfile  [OLE32.@]
5748  * Creates a new compound file storage object
5749  *
5750  * PARAMS
5751  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
5752  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
5753  *  reserved  [ ?] unused?, usually 0
5754  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
5755  *
5756  * RETURNS
5757  *  S_OK if the file was successfully created
5758  *  some STG_E_ value if error
5759  * NOTES
5760  *  if pwcsName is NULL, create file with new unique name
5761  *  the function can returns
5762  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
5763  *  (unrealized now)
5764  */
5765 HRESULT WINAPI StgCreateDocfile(
5766   LPCOLESTR pwcsName,
5767   DWORD       grfMode,
5768   DWORD       reserved,
5769   IStorage  **ppstgOpen)
5770 {
5771   StorageImpl* newStorage = 0;
5772   HANDLE       hFile      = INVALID_HANDLE_VALUE;
5773   HRESULT        hr         = STG_E_INVALIDFLAG;
5774   DWORD          shareMode;
5775   DWORD          accessMode;
5776   DWORD          creationMode;
5777   DWORD          fileAttributes;
5778   WCHAR          tempFileName[MAX_PATH];
5779
5780   TRACE("(%s, %x, %d, %p)\n",
5781         debugstr_w(pwcsName), grfMode,
5782         reserved, ppstgOpen);
5783
5784   /*
5785    * Validate the parameters
5786    */
5787   if (ppstgOpen == 0)
5788     return STG_E_INVALIDPOINTER;
5789   if (reserved != 0)
5790     return STG_E_INVALIDPARAMETER;
5791
5792   /* if no share mode given then DENY_NONE is the default */
5793   if (STGM_SHARE_MODE(grfMode) == 0)
5794       grfMode |= STGM_SHARE_DENY_NONE;
5795
5796   /*
5797    * Validate the STGM flags
5798    */
5799   if ( FAILED( validateSTGM(grfMode) ))
5800     goto end;
5801
5802   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
5803   switch(STGM_ACCESS_MODE(grfMode))
5804   {
5805   case STGM_WRITE:
5806   case STGM_READWRITE:
5807     break;
5808   default:
5809     goto end;
5810   }
5811
5812   /* in direct mode, can only use SHARE_EXCLUSIVE */
5813   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
5814     goto end;
5815
5816   /* but in transacted mode, any share mode is valid */
5817
5818   /*
5819    * Generate a unique name.
5820    */
5821   if (pwcsName == 0)
5822   {
5823     WCHAR tempPath[MAX_PATH];
5824     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5825
5826     memset(tempPath, 0, sizeof(tempPath));
5827     memset(tempFileName, 0, sizeof(tempFileName));
5828
5829     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5830       tempPath[0] = '.';
5831
5832     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5833       pwcsName = tempFileName;
5834     else
5835     {
5836       hr = STG_E_INSUFFICIENTMEMORY;
5837       goto end;
5838     }
5839
5840     creationMode = TRUNCATE_EXISTING;
5841   }
5842   else
5843   {
5844     creationMode = GetCreationModeFromSTGM(grfMode);
5845   }
5846
5847   /*
5848    * Interpret the STGM value grfMode
5849    */
5850   shareMode    = FILE_SHARE_READ | FILE_SHARE_WRITE;
5851   accessMode   = GetAccessModeFromSTGM(grfMode);
5852
5853   if (grfMode & STGM_DELETEONRELEASE)
5854     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5855   else
5856     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5857
5858   if (STGM_SHARE_MODE(grfMode) && !(grfMode & STGM_SHARE_DENY_NONE))
5859       FIXME("Storage share mode not implemented.\n");
5860
5861   if (grfMode & STGM_TRANSACTED)
5862     FIXME("Transacted mode not implemented.\n");
5863
5864   /*
5865    * Initialize the "out" parameter.
5866    */
5867   *ppstgOpen = 0;
5868
5869   hFile = CreateFileW(pwcsName,
5870                         accessMode,
5871                         shareMode,
5872                         NULL,
5873                         creationMode,
5874                         fileAttributes,
5875                         0);
5876
5877   if (hFile == INVALID_HANDLE_VALUE)
5878   {
5879     if(GetLastError() == ERROR_FILE_EXISTS)
5880       hr = STG_E_FILEALREADYEXISTS;
5881     else
5882       hr = E_FAIL;
5883     goto end;
5884   }
5885
5886   /*
5887    * Allocate and initialize the new IStorage32object.
5888    */
5889   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5890
5891   if (newStorage == 0)
5892   {
5893     hr = STG_E_INSUFFICIENTMEMORY;
5894     goto end;
5895   }
5896
5897   hr = StorageImpl_Construct(
5898          newStorage,
5899          hFile,
5900         pwcsName,
5901          NULL,
5902          grfMode,
5903          TRUE,
5904          TRUE);
5905
5906   if (FAILED(hr))
5907   {
5908     HeapFree(GetProcessHeap(), 0, newStorage);
5909     goto end;
5910   }
5911
5912   /*
5913    * Get an "out" pointer for the caller.
5914    */
5915   hr = StorageBaseImpl_QueryInterface(
5916          (IStorage*)newStorage,
5917          &IID_IStorage,
5918          (void**)ppstgOpen);
5919 end:
5920   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
5921
5922   return hr;
5923 }
5924
5925 /******************************************************************************
5926  *              StgCreateStorageEx        [OLE32.@]
5927  */
5928 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5929 {
5930     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5931           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5932
5933     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
5934     {
5935         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
5936         return STG_E_INVALIDPARAMETER;  
5937     }
5938
5939     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5940     {
5941         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
5942         return STG_E_INVALIDPARAMETER;  
5943     }
5944
5945     if (stgfmt == STGFMT_FILE)
5946     {
5947         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5948         return STG_E_INVALIDPARAMETER;
5949     }
5950
5951     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
5952     {
5953         FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
5954         return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
5955     }
5956
5957     ERR("Invalid stgfmt argument\n");
5958     return STG_E_INVALIDPARAMETER;
5959 }
5960
5961 /******************************************************************************
5962  *              StgCreatePropSetStg       [OLE32.@]
5963  */
5964 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
5965  IPropertySetStorage **ppPropSetStg)
5966 {
5967     HRESULT hr;
5968
5969     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
5970     if (reserved)
5971         hr = STG_E_INVALIDPARAMETER;
5972     else
5973         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
5974          (void**)ppPropSetStg);
5975     return hr;
5976 }
5977
5978 /******************************************************************************
5979  *              StgOpenStorageEx      [OLE32.@]
5980  */
5981 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5982 {
5983     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5984           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5985
5986     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
5987     {
5988         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
5989         return STG_E_INVALIDPARAMETER;  
5990     }
5991
5992     switch (stgfmt)
5993     {
5994     case STGFMT_FILE:
5995         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5996         return STG_E_INVALIDPARAMETER;
5997         
5998     case STGFMT_STORAGE:
5999         break;
6000
6001     case STGFMT_DOCFILE:
6002         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
6003         {
6004             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
6005             return STG_E_INVALIDPARAMETER;  
6006         }
6007         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
6008         break;
6009
6010     case STGFMT_ANY:
6011         WARN("STGFMT_ANY assuming storage\n");
6012         break;
6013
6014     default:
6015         return STG_E_INVALIDPARAMETER;
6016     }
6017
6018     return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
6019 }
6020
6021
6022 /******************************************************************************
6023  *              StgOpenStorage        [OLE32.@]
6024  */
6025 HRESULT WINAPI StgOpenStorage(
6026   const OLECHAR *pwcsName,
6027   IStorage      *pstgPriority,
6028   DWORD          grfMode,
6029   SNB            snbExclude,
6030   DWORD          reserved,
6031   IStorage     **ppstgOpen)
6032 {
6033   StorageImpl*   newStorage = 0;
6034   HRESULT        hr = S_OK;
6035   HANDLE         hFile = 0;
6036   DWORD          shareMode;
6037   DWORD          accessMode;
6038   WCHAR          fullname[MAX_PATH];
6039
6040   TRACE("(%s, %p, %x, %p, %d, %p)\n",
6041         debugstr_w(pwcsName), pstgPriority, grfMode,
6042         snbExclude, reserved, ppstgOpen);
6043
6044   /*
6045    * Perform sanity checks
6046    */
6047   if (pwcsName == 0)
6048   {
6049     hr = STG_E_INVALIDNAME;
6050     goto end;
6051   }
6052
6053   if (ppstgOpen == 0)
6054   {
6055     hr = STG_E_INVALIDPOINTER;
6056     goto end;
6057   }
6058
6059   if (reserved)
6060   {
6061     hr = STG_E_INVALIDPARAMETER;
6062     goto end;
6063   }
6064
6065   if (grfMode & STGM_PRIORITY)
6066   {
6067     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
6068       return STG_E_INVALIDFLAG;
6069     if (grfMode & STGM_DELETEONRELEASE)
6070       return STG_E_INVALIDFUNCTION;
6071     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
6072       return STG_E_INVALIDFLAG;
6073     grfMode &= ~0xf0; /* remove the existing sharing mode */
6074     grfMode |= STGM_SHARE_DENY_NONE;
6075
6076     /* STGM_PRIORITY stops other IStorage objects on the same file from
6077      * committing until the STGM_PRIORITY IStorage is closed. it also
6078      * stops non-transacted mode StgOpenStorage calls with write access from
6079      * succeeding. obviously, both of these cannot be achieved through just
6080      * file share flags */
6081     FIXME("STGM_PRIORITY mode not implemented correctly\n");
6082   }
6083
6084   /*
6085    * Validate the sharing mode
6086    */
6087   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
6088     switch(STGM_SHARE_MODE(grfMode))
6089     {
6090       case STGM_SHARE_EXCLUSIVE:
6091       case STGM_SHARE_DENY_WRITE:
6092         break;
6093       default:
6094         hr = STG_E_INVALIDFLAG;
6095         goto end;
6096     }
6097
6098   /*
6099    * Validate the STGM flags
6100    */
6101   if ( FAILED( validateSTGM(grfMode) ) ||
6102        (grfMode&STGM_CREATE))
6103   {
6104     hr = STG_E_INVALIDFLAG;
6105     goto end;
6106   }
6107
6108   /* shared reading requires transacted mode */
6109   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
6110       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
6111      !(grfMode&STGM_TRANSACTED) )
6112   {
6113     hr = STG_E_INVALIDFLAG;
6114     goto end;
6115   }
6116
6117   /*
6118    * Interpret the STGM value grfMode
6119    */
6120   shareMode    = GetShareModeFromSTGM(grfMode);
6121   accessMode   = GetAccessModeFromSTGM(grfMode);
6122
6123   /*
6124    * Initialize the "out" parameter.
6125    */
6126   *ppstgOpen = 0;
6127
6128   hFile = CreateFileW( pwcsName,
6129                        accessMode,
6130                        shareMode,
6131                        NULL,
6132                        OPEN_EXISTING,
6133                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
6134                        0);
6135
6136   if (hFile==INVALID_HANDLE_VALUE)
6137   {
6138     DWORD last_error = GetLastError();
6139
6140     hr = E_FAIL;
6141
6142     switch (last_error)
6143     {
6144       case ERROR_FILE_NOT_FOUND:
6145         hr = STG_E_FILENOTFOUND;
6146         break;
6147
6148       case ERROR_PATH_NOT_FOUND:
6149         hr = STG_E_PATHNOTFOUND;
6150         break;
6151
6152       case ERROR_ACCESS_DENIED:
6153       case ERROR_WRITE_PROTECT:
6154         hr = STG_E_ACCESSDENIED;
6155         break;
6156
6157       case ERROR_SHARING_VIOLATION:
6158         hr = STG_E_SHAREVIOLATION;
6159         break;
6160
6161       default:
6162         hr = E_FAIL;
6163     }
6164
6165     goto end;
6166   }
6167
6168   /*
6169    * Refuse to open the file if it's too small to be a structured storage file
6170    * FIXME: verify the file when reading instead of here
6171    */
6172   if (GetFileSize(hFile, NULL) < 0x100)
6173   {
6174     CloseHandle(hFile);
6175     hr = STG_E_FILEALREADYEXISTS;
6176     goto end;
6177   }
6178
6179   /*
6180    * Allocate and initialize the new IStorage32object.
6181    */
6182   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6183
6184   if (newStorage == 0)
6185   {
6186     hr = STG_E_INSUFFICIENTMEMORY;
6187     goto end;
6188   }
6189
6190   /* Initialize the storage */
6191   hr = StorageImpl_Construct(
6192          newStorage,
6193          hFile,
6194          pwcsName,
6195          NULL,
6196          grfMode,
6197          TRUE,
6198          FALSE );
6199
6200   if (FAILED(hr))
6201   {
6202     HeapFree(GetProcessHeap(), 0, newStorage);
6203     /*
6204      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6205      */
6206     if(hr == STG_E_INVALIDHEADER)
6207         hr = STG_E_FILEALREADYEXISTS;
6208     goto end;
6209   }
6210
6211   /* prepare the file name string given in lieu of the root property name */
6212   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
6213   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
6214   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
6215
6216   /*
6217    * Get an "out" pointer for the caller.
6218    */
6219   hr = StorageBaseImpl_QueryInterface(
6220          (IStorage*)newStorage,
6221          &IID_IStorage,
6222          (void**)ppstgOpen);
6223
6224 end:
6225   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6226   return hr;
6227 }
6228
6229 /******************************************************************************
6230  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6231  */
6232 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6233       ILockBytes *plkbyt,
6234       DWORD grfMode,
6235       DWORD reserved,
6236       IStorage** ppstgOpen)
6237 {
6238   StorageImpl*   newStorage = 0;
6239   HRESULT        hr         = S_OK;
6240
6241   /*
6242    * Validate the parameters
6243    */
6244   if ((ppstgOpen == 0) || (plkbyt == 0))
6245     return STG_E_INVALIDPOINTER;
6246
6247   /*
6248    * Allocate and initialize the new IStorage object.
6249    */
6250   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6251
6252   if (newStorage == 0)
6253     return STG_E_INSUFFICIENTMEMORY;
6254
6255   hr = StorageImpl_Construct(
6256          newStorage,
6257          0,
6258         0,
6259          plkbyt,
6260          grfMode,
6261          FALSE,
6262          TRUE);
6263
6264   if (FAILED(hr))
6265   {
6266     HeapFree(GetProcessHeap(), 0, newStorage);
6267     return hr;
6268   }
6269
6270   /*
6271    * Get an "out" pointer for the caller.
6272    */
6273   hr = StorageBaseImpl_QueryInterface(
6274          (IStorage*)newStorage,
6275          &IID_IStorage,
6276          (void**)ppstgOpen);
6277
6278   return hr;
6279 }
6280
6281 /******************************************************************************
6282  *    StgOpenStorageOnILockBytes    [OLE32.@]
6283  */
6284 HRESULT WINAPI StgOpenStorageOnILockBytes(
6285       ILockBytes *plkbyt,
6286       IStorage *pstgPriority,
6287       DWORD grfMode,
6288       SNB snbExclude,
6289       DWORD reserved,
6290       IStorage **ppstgOpen)
6291 {
6292   StorageImpl* newStorage = 0;
6293   HRESULT        hr = S_OK;
6294
6295   /*
6296    * Perform a sanity check
6297    */
6298   if ((plkbyt == 0) || (ppstgOpen == 0))
6299     return STG_E_INVALIDPOINTER;
6300
6301   /*
6302    * Validate the STGM flags
6303    */
6304   if ( FAILED( validateSTGM(grfMode) ))
6305     return STG_E_INVALIDFLAG;
6306
6307   /*
6308    * Initialize the "out" parameter.
6309    */
6310   *ppstgOpen = 0;
6311
6312   /*
6313    * Allocate and initialize the new IStorage object.
6314    */
6315   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6316
6317   if (newStorage == 0)
6318     return STG_E_INSUFFICIENTMEMORY;
6319
6320   hr = StorageImpl_Construct(
6321          newStorage,
6322          0,
6323          0,
6324          plkbyt,
6325          grfMode,
6326          FALSE,
6327          FALSE);
6328
6329   if (FAILED(hr))
6330   {
6331     HeapFree(GetProcessHeap(), 0, newStorage);
6332     return hr;
6333   }
6334
6335   /*
6336    * Get an "out" pointer for the caller.
6337    */
6338   hr = StorageBaseImpl_QueryInterface(
6339          (IStorage*)newStorage,
6340          &IID_IStorage,
6341          (void**)ppstgOpen);
6342
6343   return hr;
6344 }
6345
6346 /******************************************************************************
6347  *              StgSetTimes [ole32.@]
6348  *              StgSetTimes [OLE32.@]
6349  *
6350  *
6351  */
6352 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6353                            FILETIME const *patime, FILETIME const *pmtime)
6354 {
6355   IStorage *stg = NULL;
6356   HRESULT r;
6357  
6358   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6359
6360   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6361                      0, 0, &stg);
6362   if( SUCCEEDED(r) )
6363   {
6364     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6365     IStorage_Release(stg);
6366   }
6367
6368   return r;
6369 }
6370
6371 /******************************************************************************
6372  *              StgIsStorageILockBytes        [OLE32.@]
6373  *
6374  * Determines if the ILockBytes contains a storage object.
6375  */
6376 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6377 {
6378   BYTE sig[8];
6379   ULARGE_INTEGER offset;
6380
6381   offset.u.HighPart = 0;
6382   offset.u.LowPart  = 0;
6383
6384   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6385
6386   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6387     return S_OK;
6388
6389   return S_FALSE;
6390 }
6391
6392 /******************************************************************************
6393  *              WriteClassStg        [OLE32.@]
6394  *
6395  * This method will store the specified CLSID in the specified storage object
6396  */
6397 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6398 {
6399   HRESULT hRes;
6400
6401   if(!pStg)
6402     return E_INVALIDARG;
6403
6404   if(!rclsid)
6405     return STG_E_INVALIDPOINTER;
6406
6407   hRes = IStorage_SetClass(pStg, rclsid);
6408
6409   return hRes;
6410 }
6411
6412 /***********************************************************************
6413  *    ReadClassStg (OLE32.@)
6414  *
6415  * This method reads the CLSID previously written to a storage object with
6416  * the WriteClassStg.
6417  *
6418  * PARAMS
6419  *  pstg    [I] IStorage pointer
6420  *  pclsid  [O] Pointer to where the CLSID is written
6421  *
6422  * RETURNS
6423  *  Success: S_OK.
6424  *  Failure: HRESULT code.
6425  */
6426 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6427
6428     STATSTG pstatstg;
6429     HRESULT hRes;
6430
6431     TRACE("(%p, %p)\n", pstg, pclsid);
6432
6433     if(!pstg || !pclsid)
6434         return E_INVALIDARG;
6435
6436    /*
6437     * read a STATSTG structure (contains the clsid) from the storage
6438     */
6439     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_NONAME);
6440
6441     if(SUCCEEDED(hRes))
6442         *pclsid=pstatstg.clsid;
6443
6444     return hRes;
6445 }
6446
6447 /***********************************************************************
6448  *    OleLoadFromStream (OLE32.@)
6449  *
6450  * This function loads an object from stream
6451  */
6452 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6453 {
6454     CLSID       clsid;
6455     HRESULT     res;
6456     LPPERSISTSTREAM     xstm;
6457
6458     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6459
6460     res=ReadClassStm(pStm,&clsid);
6461     if (FAILED(res))
6462         return res;
6463     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6464     if (FAILED(res))
6465         return res;
6466     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6467     if (FAILED(res)) {
6468         IUnknown_Release((IUnknown*)*ppvObj);
6469         return res;
6470     }
6471     res=IPersistStream_Load(xstm,pStm);
6472     IPersistStream_Release(xstm);
6473     /* FIXME: all refcounts ok at this point? I think they should be:
6474      *          pStm    : unchanged
6475      *          ppvObj  : 1
6476      *          xstm    : 0 (released)
6477      */
6478     return res;
6479 }
6480
6481 /***********************************************************************
6482  *    OleSaveToStream (OLE32.@)
6483  *
6484  * This function saves an object with the IPersistStream interface on it
6485  * to the specified stream.
6486  */
6487 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6488 {
6489
6490     CLSID clsid;
6491     HRESULT res;
6492
6493     TRACE("(%p,%p)\n",pPStm,pStm);
6494
6495     res=IPersistStream_GetClassID(pPStm,&clsid);
6496
6497     if (SUCCEEDED(res)){
6498
6499         res=WriteClassStm(pStm,&clsid);
6500
6501         if (SUCCEEDED(res))
6502
6503             res=IPersistStream_Save(pPStm,pStm,TRUE);
6504     }
6505
6506     TRACE("Finished Save\n");
6507     return res;
6508 }
6509
6510 /****************************************************************************
6511  * This method validate a STGM parameter that can contain the values below
6512  *
6513  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6514  * The stgm values contained in 0xffff0000 are bitmasks.
6515  *
6516  * STGM_DIRECT               0x00000000
6517  * STGM_TRANSACTED           0x00010000
6518  * STGM_SIMPLE               0x08000000
6519  *
6520  * STGM_READ                 0x00000000
6521  * STGM_WRITE                0x00000001
6522  * STGM_READWRITE            0x00000002
6523  *
6524  * STGM_SHARE_DENY_NONE      0x00000040
6525  * STGM_SHARE_DENY_READ      0x00000030
6526  * STGM_SHARE_DENY_WRITE     0x00000020
6527  * STGM_SHARE_EXCLUSIVE      0x00000010
6528  *
6529  * STGM_PRIORITY             0x00040000
6530  * STGM_DELETEONRELEASE      0x04000000
6531  *
6532  * STGM_CREATE               0x00001000
6533  * STGM_CONVERT              0x00020000
6534  * STGM_FAILIFTHERE          0x00000000
6535  *
6536  * STGM_NOSCRATCH            0x00100000
6537  * STGM_NOSNAPSHOT           0x00200000
6538  */
6539 static HRESULT validateSTGM(DWORD stgm)
6540 {
6541   DWORD access = STGM_ACCESS_MODE(stgm);
6542   DWORD share  = STGM_SHARE_MODE(stgm);
6543   DWORD create = STGM_CREATE_MODE(stgm);
6544
6545   if (stgm&~STGM_KNOWN_FLAGS)
6546   {
6547     ERR("unknown flags %08x\n", stgm);
6548     return E_FAIL;
6549   }
6550
6551   switch (access)
6552   {
6553   case STGM_READ:
6554   case STGM_WRITE:
6555   case STGM_READWRITE:
6556     break;
6557   default:
6558     return E_FAIL;
6559   }
6560
6561   switch (share)
6562   {
6563   case STGM_SHARE_DENY_NONE:
6564   case STGM_SHARE_DENY_READ:
6565   case STGM_SHARE_DENY_WRITE:
6566   case STGM_SHARE_EXCLUSIVE:
6567     break;
6568   default:
6569     return E_FAIL;
6570   }
6571
6572   switch (create)
6573   {
6574   case STGM_CREATE:
6575   case STGM_FAILIFTHERE:
6576     break;
6577   default:
6578     return E_FAIL;
6579   }
6580
6581   /*
6582    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6583    */
6584   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6585       return E_FAIL;
6586
6587   /*
6588    * STGM_CREATE | STGM_CONVERT
6589    * if both are false, STGM_FAILIFTHERE is set to TRUE
6590    */
6591   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6592     return E_FAIL;
6593
6594   /*
6595    * STGM_NOSCRATCH requires STGM_TRANSACTED
6596    */
6597   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6598     return E_FAIL;
6599
6600   /*
6601    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6602    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6603    */
6604   if ( (stgm & STGM_NOSNAPSHOT) &&
6605         (!(stgm & STGM_TRANSACTED) ||
6606          share == STGM_SHARE_EXCLUSIVE ||
6607          share == STGM_SHARE_DENY_WRITE) )
6608     return E_FAIL;
6609
6610   return S_OK;
6611 }
6612
6613 /****************************************************************************
6614  *      GetShareModeFromSTGM
6615  *
6616  * This method will return a share mode flag from a STGM value.
6617  * The STGM value is assumed valid.
6618  */
6619 static DWORD GetShareModeFromSTGM(DWORD stgm)
6620 {
6621   switch (STGM_SHARE_MODE(stgm))
6622   {
6623   case STGM_SHARE_DENY_NONE:
6624     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6625   case STGM_SHARE_DENY_READ:
6626     return FILE_SHARE_WRITE;
6627   case STGM_SHARE_DENY_WRITE:
6628     return FILE_SHARE_READ;
6629   case STGM_SHARE_EXCLUSIVE:
6630     return 0;
6631   }
6632   ERR("Invalid share mode!\n");
6633   assert(0);
6634   return 0;
6635 }
6636
6637 /****************************************************************************
6638  *      GetAccessModeFromSTGM
6639  *
6640  * This method will return an access mode flag from a STGM value.
6641  * The STGM value is assumed valid.
6642  */
6643 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6644 {
6645   switch (STGM_ACCESS_MODE(stgm))
6646   {
6647   case STGM_READ:
6648     return GENERIC_READ;
6649   case STGM_WRITE:
6650   case STGM_READWRITE:
6651     return GENERIC_READ | GENERIC_WRITE;
6652   }
6653   ERR("Invalid access mode!\n");
6654   assert(0);
6655   return 0;
6656 }
6657
6658 /****************************************************************************
6659  *      GetCreationModeFromSTGM
6660  *
6661  * This method will return a creation mode flag from a STGM value.
6662  * The STGM value is assumed valid.
6663  */
6664 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6665 {
6666   switch(STGM_CREATE_MODE(stgm))
6667   {
6668   case STGM_CREATE:
6669     return CREATE_ALWAYS;
6670   case STGM_CONVERT:
6671     FIXME("STGM_CONVERT not implemented!\n");
6672     return CREATE_NEW;
6673   case STGM_FAILIFTHERE:
6674     return CREATE_NEW;
6675   }
6676   ERR("Invalid create mode!\n");
6677   assert(0);
6678   return 0;
6679 }
6680
6681
6682 /*************************************************************************
6683  * OLECONVERT_LoadOLE10 [Internal]
6684  *
6685  * Loads the OLE10 STREAM to memory
6686  *
6687  * PARAMS
6688  *     pOleStream   [I] The OLESTREAM
6689  *     pData        [I] Data Structure for the OLESTREAM Data
6690  *
6691  * RETURNS
6692  *     Success:  S_OK
6693  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6694  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalid
6695  *
6696  * NOTES
6697  *     This function is used by OleConvertOLESTREAMToIStorage only.
6698  *
6699  *     Memory allocated for pData must be freed by the caller
6700  */
6701 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6702 {
6703         DWORD dwSize;
6704         HRESULT hRes = S_OK;
6705         int nTryCnt=0;
6706         int max_try = 6;
6707
6708         pData->pData = NULL;
6709         pData->pstrOleObjFileName = NULL;
6710
6711         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6712         {
6713         /* Get the OleID */
6714         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6715         if(dwSize != sizeof(pData->dwOleID))
6716         {
6717                 hRes = CONVERT10_E_OLESTREAM_GET;
6718         }
6719         else if(pData->dwOleID != OLESTREAM_ID)
6720         {
6721                 hRes = CONVERT10_E_OLESTREAM_FMT;
6722         }
6723                 else
6724                 {
6725                         hRes = S_OK;
6726                         break;
6727                 }
6728         }
6729
6730         if(hRes == S_OK)
6731         {
6732                 /* Get the TypeID... more info needed for this field */
6733                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6734                 if(dwSize != sizeof(pData->dwTypeID))
6735                 {
6736                         hRes = CONVERT10_E_OLESTREAM_GET;
6737                 }
6738         }
6739         if(hRes == S_OK)
6740         {
6741                 if(pData->dwTypeID != 0)
6742                 {
6743                         /* Get the length of the OleTypeName */
6744                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6745                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6746                         {
6747                                 hRes = CONVERT10_E_OLESTREAM_GET;
6748                         }
6749
6750                         if(hRes == S_OK)
6751                         {
6752                                 if(pData->dwOleTypeNameLength > 0)
6753                                 {
6754                                         /* Get the OleTypeName */
6755                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
6756                                         if(dwSize != pData->dwOleTypeNameLength)
6757                                         {
6758                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6759                                         }
6760                                 }
6761                         }
6762                         if(bStrem1)
6763                         {
6764                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6765                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6766                                 {
6767                                         hRes = CONVERT10_E_OLESTREAM_GET;
6768                                 }
6769                         if(hRes == S_OK)
6770                         {
6771                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6772                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6773                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6774                                         if(pData->pstrOleObjFileName)
6775                                         {
6776                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->pstrOleObjFileName, pData->dwOleObjFileNameLength);
6777                                                 if(dwSize != pData->dwOleObjFileNameLength)
6778                                                 {
6779                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6780                                                 }
6781                                         }
6782                                         else
6783                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6784                                 }
6785                         }
6786                         else
6787                         {
6788                                 /* Get the Width of the Metafile */
6789                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6790                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6791                                 {
6792                                         hRes = CONVERT10_E_OLESTREAM_GET;
6793                                 }
6794                         if(hRes == S_OK)
6795                         {
6796                                 /* Get the Height of the Metafile */
6797                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6798                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6799                                 {
6800                                         hRes = CONVERT10_E_OLESTREAM_GET;
6801                                 }
6802                         }
6803                         }
6804                         if(hRes == S_OK)
6805                         {
6806                                 /* Get the Length of the Data */
6807                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6808                                 if(dwSize != sizeof(pData->dwDataLength))
6809                                 {
6810                                         hRes = CONVERT10_E_OLESTREAM_GET;
6811                                 }
6812                         }
6813
6814                         if(hRes == S_OK) /* I don't know what this 8 byte information is. We have to figure out */
6815                         {
6816                                 if(!bStrem1) /* if it is a second OLE stream data */
6817                                 {
6818                                         pData->dwDataLength -= 8;
6819                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strUnknown, sizeof(pData->strUnknown));
6820                                         if(dwSize != sizeof(pData->strUnknown))
6821                                         {
6822                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6823                                         }
6824                                 }
6825                         }
6826                         if(hRes == S_OK)
6827                         {
6828                                 if(pData->dwDataLength > 0)
6829                                 {
6830                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6831
6832                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6833                                         if(pData->pData)
6834                                         {
6835                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6836                                                 if(dwSize != pData->dwDataLength)
6837                                                 {
6838                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6839                                                 }
6840                                         }
6841                                         else
6842                                         {
6843                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6844                                         }
6845                                 }
6846                         }
6847                 }
6848         }
6849         return hRes;
6850 }
6851
6852 /*************************************************************************
6853  * OLECONVERT_SaveOLE10 [Internal]
6854  *
6855  * Saves the OLE10 STREAM From memory
6856  *
6857  * PARAMS
6858  *     pData        [I] Data Structure for the OLESTREAM Data
6859  *     pOleStream   [I] The OLESTREAM to save
6860  *
6861  * RETURNS
6862  *     Success:  S_OK
6863  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6864  *
6865  * NOTES
6866  *     This function is used by OleConvertIStorageToOLESTREAM only.
6867  *
6868  */
6869 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6870 {
6871     DWORD dwSize;
6872     HRESULT hRes = S_OK;
6873
6874
6875    /* Set the OleID */
6876     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6877     if(dwSize != sizeof(pData->dwOleID))
6878     {
6879         hRes = CONVERT10_E_OLESTREAM_PUT;
6880     }
6881
6882     if(hRes == S_OK)
6883     {
6884         /* Set the TypeID */
6885         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6886         if(dwSize != sizeof(pData->dwTypeID))
6887         {
6888             hRes = CONVERT10_E_OLESTREAM_PUT;
6889         }
6890     }
6891
6892     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6893     {
6894         /* Set the Length of the OleTypeName */
6895         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6896         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6897         {
6898             hRes = CONVERT10_E_OLESTREAM_PUT;
6899         }
6900
6901         if(hRes == S_OK)
6902         {
6903             if(pData->dwOleTypeNameLength > 0)
6904             {
6905                 /* Set the OleTypeName */
6906                 dwSize = pOleStream->lpstbl->Put(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
6907                 if(dwSize != pData->dwOleTypeNameLength)
6908                 {
6909                     hRes = CONVERT10_E_OLESTREAM_PUT;
6910                 }
6911             }
6912         }
6913
6914         if(hRes == S_OK)
6915         {
6916             /* Set the width of the Metafile */
6917             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6918             if(dwSize != sizeof(pData->dwMetaFileWidth))
6919             {
6920                 hRes = CONVERT10_E_OLESTREAM_PUT;
6921             }
6922         }
6923
6924         if(hRes == S_OK)
6925         {
6926             /* Set the height of the Metafile */
6927             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6928             if(dwSize != sizeof(pData->dwMetaFileHeight))
6929             {
6930                 hRes = CONVERT10_E_OLESTREAM_PUT;
6931             }
6932         }
6933
6934         if(hRes == S_OK)
6935         {
6936             /* Set the length of the Data */
6937             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6938             if(dwSize != sizeof(pData->dwDataLength))
6939             {
6940                 hRes = CONVERT10_E_OLESTREAM_PUT;
6941             }
6942         }
6943
6944         if(hRes == S_OK)
6945         {
6946             if(pData->dwDataLength > 0)
6947             {
6948                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6949                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6950                 if(dwSize != pData->dwDataLength)
6951                 {
6952                     hRes = CONVERT10_E_OLESTREAM_PUT;
6953                 }
6954             }
6955         }
6956     }
6957     return hRes;
6958 }
6959
6960 /*************************************************************************
6961  * OLECONVERT_GetOLE20FromOLE10[Internal]
6962  *
6963  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6964  * opens it, and copies the content to the dest IStorage for
6965  * OleConvertOLESTREAMToIStorage
6966  *
6967  *
6968  * PARAMS
6969  *     pDestStorage  [I] The IStorage to copy the data to
6970  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6971  *     nBufferLength [I] The size of the buffer
6972  *
6973  * RETURNS
6974  *     Nothing
6975  *
6976  * NOTES
6977  *
6978  *
6979  */
6980 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
6981 {
6982     HRESULT hRes;
6983     HANDLE hFile;
6984     IStorage *pTempStorage;
6985     DWORD dwNumOfBytesWritten;
6986     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6987     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6988
6989     /* Create a temp File */
6990     GetTempPathW(MAX_PATH, wstrTempDir);
6991     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6992     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6993
6994     if(hFile != INVALID_HANDLE_VALUE)
6995     {
6996         /* Write IStorage Data to File */
6997         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6998         CloseHandle(hFile);
6999
7000         /* Open and copy temp storage to the Dest Storage */
7001         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
7002         if(hRes == S_OK)
7003         {
7004             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
7005             StorageBaseImpl_Release(pTempStorage);
7006         }
7007         DeleteFileW(wstrTempFile);
7008     }
7009 }
7010
7011
7012 /*************************************************************************
7013  * OLECONVERT_WriteOLE20ToBuffer [Internal]
7014  *
7015  * Saves the OLE10 STREAM From memory
7016  *
7017  * PARAMS
7018  *     pStorage  [I] The Src IStorage to copy
7019  *     pData     [I] The Dest Memory to write to.
7020  *
7021  * RETURNS
7022  *     The size in bytes allocated for pData
7023  *
7024  * NOTES
7025  *     Memory allocated for pData must be freed by the caller
7026  *
7027  *     Used by OleConvertIStorageToOLESTREAM only.
7028  *
7029  */
7030 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
7031 {
7032     HANDLE hFile;
7033     HRESULT hRes;
7034     DWORD nDataLength = 0;
7035     IStorage *pTempStorage;
7036     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
7037     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
7038
7039     *pData = NULL;
7040
7041     /* Create temp Storage */
7042     GetTempPathW(MAX_PATH, wstrTempDir);
7043     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
7044     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
7045
7046     if(hRes == S_OK)
7047     {
7048         /* Copy Src Storage to the Temp Storage */
7049         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
7050         StorageBaseImpl_Release(pTempStorage);
7051
7052         /* Open Temp Storage as a file and copy to memory */
7053         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7054         if(hFile != INVALID_HANDLE_VALUE)
7055         {
7056             nDataLength = GetFileSize(hFile, NULL);
7057             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
7058             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
7059             CloseHandle(hFile);
7060         }
7061         DeleteFileW(wstrTempFile);
7062     }
7063     return nDataLength;
7064 }
7065
7066 /*************************************************************************
7067  * OLECONVERT_CreateOleStream [Internal]
7068  *
7069  * Creates the "\001OLE" stream in the IStorage if necessary.
7070  *
7071  * PARAMS
7072  *     pStorage     [I] Dest storage to create the stream in
7073  *
7074  * RETURNS
7075  *     Nothing
7076  *
7077  * NOTES
7078  *     This function is used by OleConvertOLESTREAMToIStorage only.
7079  *
7080  *     This stream is still unknown, MS Word seems to have extra data
7081  *     but since the data is stored in the OLESTREAM there should be
7082  *     no need to recreate the stream.  If the stream is manually
7083  *     deleted it will create it with this default data.
7084  *
7085  */
7086 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
7087 {
7088     HRESULT hRes;
7089     IStream *pStream;
7090     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
7091     BYTE pOleStreamHeader [] =
7092     {
7093         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
7094         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7095         0x00, 0x00, 0x00, 0x00
7096     };
7097
7098     /* Create stream if not present */
7099     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7100         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7101
7102     if(hRes == S_OK)
7103     {
7104         /* Write default Data */
7105         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
7106         IStream_Release(pStream);
7107     }
7108 }
7109
7110 /* write a string to a stream, preceded by its length */
7111 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
7112 {
7113     HRESULT r;
7114     LPSTR str;
7115     DWORD len = 0;
7116
7117     if( string )
7118         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
7119     r = IStream_Write( stm, &len, sizeof(len), NULL);
7120     if( FAILED( r ) )
7121         return r;
7122     if(len == 0)
7123         return r;
7124     str = CoTaskMemAlloc( len );
7125     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
7126     r = IStream_Write( stm, str, len, NULL);
7127     CoTaskMemFree( str );
7128     return r;
7129 }
7130
7131 /* read a string preceded by its length from a stream */
7132 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
7133 {
7134     HRESULT r;
7135     DWORD len, count = 0;
7136     LPSTR str;
7137     LPWSTR wstr;
7138
7139     r = IStream_Read( stm, &len, sizeof(len), &count );
7140     if( FAILED( r ) )
7141         return r;
7142     if( count != sizeof(len) )
7143         return E_OUTOFMEMORY;
7144
7145     TRACE("%d bytes\n",len);
7146     
7147     str = CoTaskMemAlloc( len );
7148     if( !str )
7149         return E_OUTOFMEMORY;
7150     count = 0;
7151     r = IStream_Read( stm, str, len, &count );
7152     if( FAILED( r ) )
7153         return r;
7154     if( count != len )
7155     {
7156         CoTaskMemFree( str );
7157         return E_OUTOFMEMORY;
7158     }
7159
7160     TRACE("Read string %s\n",debugstr_an(str,len));
7161
7162     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
7163     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
7164     if( wstr )
7165          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
7166     CoTaskMemFree( str );
7167
7168     *string = wstr;
7169
7170     return r;
7171 }
7172
7173
7174 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
7175     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
7176 {
7177     IStream *pstm;
7178     HRESULT r = S_OK;
7179     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7180
7181     static const BYTE unknown1[12] =
7182        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
7183          0xFF, 0xFF, 0xFF, 0xFF};
7184     static const BYTE unknown2[16] =
7185        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
7186          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
7187
7188     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
7189            debugstr_w(lpszUserType), debugstr_w(szClipName),
7190            debugstr_w(szProgIDName));
7191
7192     /*  Create a CompObj stream */
7193     r = IStorage_CreateStream(pstg, szwStreamName,
7194         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7195     if( FAILED (r) )
7196         return r;
7197
7198     /* Write CompObj Structure to stream */
7199     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7200
7201     if( SUCCEEDED( r ) )
7202         r = WriteClassStm( pstm, clsid );
7203
7204     if( SUCCEEDED( r ) )
7205         r = STREAM_WriteString( pstm, lpszUserType );
7206     if( SUCCEEDED( r ) )
7207         r = STREAM_WriteString( pstm, szClipName );
7208     if( SUCCEEDED( r ) )
7209         r = STREAM_WriteString( pstm, szProgIDName );
7210     if( SUCCEEDED( r ) )
7211         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7212
7213     IStream_Release( pstm );
7214
7215     return r;
7216 }
7217
7218 /***********************************************************************
7219  *               WriteFmtUserTypeStg (OLE32.@)
7220  */
7221 HRESULT WINAPI WriteFmtUserTypeStg(
7222           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7223 {
7224     HRESULT r;
7225     WCHAR szwClipName[0x40];
7226     CLSID clsid = CLSID_NULL;
7227     LPWSTR wstrProgID = NULL;
7228     DWORD n;
7229
7230     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7231
7232     /* get the clipboard format name */
7233     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName)/sizeof(szwClipName[0]) );
7234     szwClipName[n]=0;
7235
7236     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7237
7238     /* FIXME: There's room to save a CLSID and its ProgID, but
7239        the CLSID is not looked up in the registry and in all the
7240        tests I wrote it was CLSID_NULL.  Where does it come from?
7241     */
7242
7243     /* get the real program ID.  This may fail, but that's fine */
7244     ProgIDFromCLSID(&clsid, &wstrProgID);
7245
7246     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7247
7248     r = STORAGE_WriteCompObj( pstg, &clsid, 
7249                               lpszUserType, szwClipName, wstrProgID );
7250
7251     CoTaskMemFree(wstrProgID);
7252
7253     return r;
7254 }
7255
7256
7257 /******************************************************************************
7258  *              ReadFmtUserTypeStg        [OLE32.@]
7259  */
7260 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7261 {
7262     HRESULT r;
7263     IStream *stm = 0;
7264     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7265     unsigned char unknown1[12];
7266     unsigned char unknown2[16];
7267     DWORD count;
7268     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7269     CLSID clsid;
7270
7271     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7272
7273     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7274                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7275     if( FAILED ( r ) )
7276     {
7277         WARN("Failed to open stream r = %08x\n", r);
7278         return r;
7279     }
7280
7281     /* read the various parts of the structure */
7282     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7283     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7284         goto end;
7285     r = ReadClassStm( stm, &clsid );
7286     if( FAILED( r ) )
7287         goto end;
7288
7289     r = STREAM_ReadString( stm, &szCLSIDName );
7290     if( FAILED( r ) )
7291         goto end;
7292
7293     r = STREAM_ReadString( stm, &szOleTypeName );
7294     if( FAILED( r ) )
7295         goto end;
7296
7297     r = STREAM_ReadString( stm, &szProgIDName );
7298     if( FAILED( r ) )
7299         goto end;
7300
7301     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7302     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7303         goto end;
7304
7305     /* ok, success... now we just need to store what we found */
7306     if( pcf )
7307         *pcf = RegisterClipboardFormatW( szOleTypeName );
7308     CoTaskMemFree( szOleTypeName );
7309
7310     if( lplpszUserType )
7311         *lplpszUserType = szCLSIDName;
7312     CoTaskMemFree( szProgIDName );
7313
7314 end:
7315     IStream_Release( stm );
7316
7317     return r;
7318 }
7319
7320
7321 /*************************************************************************
7322  * OLECONVERT_CreateCompObjStream [Internal]
7323  *
7324  * Creates a "\001CompObj" is the destination IStorage if necessary.
7325  *
7326  * PARAMS
7327  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7328  *                        if necessary.
7329  *     strOleTypeName [I] The ProgID
7330  *
7331  * RETURNS
7332  *     Success:  S_OK
7333  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7334  *
7335  * NOTES
7336  *     This function is used by OleConvertOLESTREAMToIStorage only.
7337  *
7338  *     The stream data is stored in the OLESTREAM and there should be
7339  *     no need to recreate the stream.  If the stream is manually
7340  *     deleted it will attempt to create it by querying the registry.
7341  *
7342  *
7343  */
7344 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7345 {
7346     IStream *pStream;
7347     HRESULT hStorageRes, hRes = S_OK;
7348     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7349     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7350     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7351
7352     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7353     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7354
7355     /* Initialize the CompObj structure */
7356     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7357     memcpy(IStorageCompObj.byUnknown1, pCompObjUnknown1, sizeof(pCompObjUnknown1));
7358     memcpy(IStorageCompObj.byUnknown2, pCompObjUnknown2, sizeof(pCompObjUnknown2));
7359
7360
7361     /*  Create a CompObj stream if it doesn't exist */
7362     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7363         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7364     if(hStorageRes == S_OK)
7365     {
7366         /* copy the OleTypeName to the compobj struct */
7367         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7368         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7369
7370         /* copy the OleTypeName to the compobj struct */
7371         /* Note: in the test made, these were Identical      */
7372         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7373         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7374
7375         /* Get the CLSID */
7376         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7377                              bufferW, OLESTREAM_MAX_STR_LEN );
7378         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7379
7380         if(hRes == S_OK)
7381         {
7382             HKEY hKey;
7383             LONG hErr;
7384             /* Get the CLSID Default Name from the Registry */
7385             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7386             if(hErr == ERROR_SUCCESS)
7387             {
7388                 char strTemp[OLESTREAM_MAX_STR_LEN];
7389                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7390                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7391                 if(hErr == ERROR_SUCCESS)
7392                 {
7393                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7394                 }
7395                 RegCloseKey(hKey);
7396             }
7397         }
7398
7399         /* Write CompObj Structure to stream */
7400         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7401
7402         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7403
7404         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7405         if(IStorageCompObj.dwCLSIDNameLength > 0)
7406         {
7407             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7408         }
7409         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7410         if(IStorageCompObj.dwOleTypeNameLength > 0)
7411         {
7412             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7413         }
7414         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7415         if(IStorageCompObj.dwProgIDNameLength > 0)
7416         {
7417             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7418         }
7419         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7420         IStream_Release(pStream);
7421     }
7422     return hRes;
7423 }
7424
7425
7426 /*************************************************************************
7427  * OLECONVERT_CreateOlePresStream[Internal]
7428  *
7429  * Creates the "\002OlePres000" Stream with the Metafile data
7430  *
7431  * PARAMS
7432  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7433  *     dwExtentX    [I] Width of the Metafile
7434  *     dwExtentY    [I] Height of the Metafile
7435  *     pData        [I] Metafile data
7436  *     dwDataLength [I] Size of the Metafile data
7437  *
7438  * RETURNS
7439  *     Success:  S_OK
7440  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7441  *
7442  * NOTES
7443  *     This function is used by OleConvertOLESTREAMToIStorage only.
7444  *
7445  */
7446 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7447 {
7448     HRESULT hRes;
7449     IStream *pStream;
7450     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7451     BYTE pOlePresStreamHeader [] =
7452     {
7453         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7454         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7455         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7456         0x00, 0x00, 0x00, 0x00
7457     };
7458
7459     BYTE pOlePresStreamHeaderEmpty [] =
7460     {
7461         0x00, 0x00, 0x00, 0x00,
7462         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7463         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7464         0x00, 0x00, 0x00, 0x00
7465     };
7466
7467     /* Create the OlePres000 Stream */
7468     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7469         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7470
7471     if(hRes == S_OK)
7472     {
7473         DWORD nHeaderSize;
7474         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7475
7476         memset(&OlePres, 0, sizeof(OlePres));
7477         /* Do we have any metafile data to save */
7478         if(dwDataLength > 0)
7479         {
7480             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7481             nHeaderSize = sizeof(pOlePresStreamHeader);
7482         }
7483         else
7484         {
7485             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7486             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7487         }
7488         /* Set width and height of the metafile */
7489         OlePres.dwExtentX = dwExtentX;
7490         OlePres.dwExtentY = -dwExtentY;
7491
7492         /* Set Data and Length */
7493         if(dwDataLength > sizeof(METAFILEPICT16))
7494         {
7495             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7496             OlePres.pData = &(pData[8]);
7497         }
7498         /* Save OlePres000 Data to Stream */
7499         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7500         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7501         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7502         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7503         if(OlePres.dwSize > 0)
7504         {
7505             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7506         }
7507         IStream_Release(pStream);
7508     }
7509 }
7510
7511 /*************************************************************************
7512  * OLECONVERT_CreateOle10NativeStream [Internal]
7513  *
7514  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7515  *
7516  * PARAMS
7517  *     pStorage     [I] Dest storage to create the stream in
7518  *     pData        [I] Ole10 Native Data (ex. bmp)
7519  *     dwDataLength [I] Size of the Ole10 Native Data
7520  *
7521  * RETURNS
7522  *     Nothing
7523  *
7524  * NOTES
7525  *     This function is used by OleConvertOLESTREAMToIStorage only.
7526  *
7527  *     Might need to verify the data and return appropriate error message
7528  *
7529  */
7530 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
7531 {
7532     HRESULT hRes;
7533     IStream *pStream;
7534     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7535
7536     /* Create the Ole10Native Stream */
7537     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7538         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7539
7540     if(hRes == S_OK)
7541     {
7542         /* Write info to stream */
7543         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7544         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7545         IStream_Release(pStream);
7546     }
7547
7548 }
7549
7550 /*************************************************************************
7551  * OLECONVERT_GetOLE10ProgID [Internal]
7552  *
7553  * Finds the ProgID (or OleTypeID) from the IStorage
7554  *
7555  * PARAMS
7556  *     pStorage        [I] The Src IStorage to get the ProgID
7557  *     strProgID       [I] the ProgID string to get
7558  *     dwSize          [I] the size of the string
7559  *
7560  * RETURNS
7561  *     Success:  S_OK
7562  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7563  *
7564  * NOTES
7565  *     This function is used by OleConvertIStorageToOLESTREAM only.
7566  *
7567  *
7568  */
7569 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7570 {
7571     HRESULT hRes;
7572     IStream *pStream;
7573     LARGE_INTEGER iSeekPos;
7574     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7575     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7576
7577     /* Open the CompObj Stream */
7578     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7579         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7580     if(hRes == S_OK)
7581     {
7582
7583         /*Get the OleType from the CompObj Stream */
7584         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7585         iSeekPos.u.HighPart = 0;
7586
7587         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7588         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7589         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7590         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7591         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7592         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7593         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7594
7595         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7596         if(*dwSize > 0)
7597         {
7598             IStream_Read(pStream, strProgID, *dwSize, NULL);
7599         }
7600         IStream_Release(pStream);
7601     }
7602     else
7603     {
7604         STATSTG stat;
7605         LPOLESTR wstrProgID;
7606
7607         /* Get the OleType from the registry */
7608         REFCLSID clsid = &(stat.clsid);
7609         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7610         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7611         if(hRes == S_OK)
7612         {
7613             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7614         }
7615
7616     }
7617     return hRes;
7618 }
7619
7620 /*************************************************************************
7621  * OLECONVERT_GetOle10PresData [Internal]
7622  *
7623  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7624  *
7625  * PARAMS
7626  *     pStorage     [I] Src IStroage
7627  *     pOleStream   [I] Dest OleStream Mem Struct
7628  *
7629  * RETURNS
7630  *     Nothing
7631  *
7632  * NOTES
7633  *     This function is used by OleConvertIStorageToOLESTREAM only.
7634  *
7635  *     Memory allocated for pData must be freed by the caller
7636  *
7637  *
7638  */
7639 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7640 {
7641
7642     HRESULT hRes;
7643     IStream *pStream;
7644     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7645
7646     /* Initialize Default data for OLESTREAM */
7647     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7648     pOleStreamData[0].dwTypeID = 2;
7649     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7650     pOleStreamData[1].dwTypeID = 0;
7651     pOleStreamData[0].dwMetaFileWidth = 0;
7652     pOleStreamData[0].dwMetaFileHeight = 0;
7653     pOleStreamData[0].pData = NULL;
7654     pOleStreamData[1].pData = NULL;
7655
7656     /* Open Ole10Native Stream */
7657     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7658         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7659     if(hRes == S_OK)
7660     {
7661
7662         /* Read Size and Data */
7663         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7664         if(pOleStreamData->dwDataLength > 0)
7665         {
7666             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7667             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7668         }
7669         IStream_Release(pStream);
7670     }
7671
7672 }
7673
7674
7675 /*************************************************************************
7676  * OLECONVERT_GetOle20PresData[Internal]
7677  *
7678  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7679  *
7680  * PARAMS
7681  *     pStorage         [I] Src IStroage
7682  *     pOleStreamData   [I] Dest OleStream Mem Struct
7683  *
7684  * RETURNS
7685  *     Nothing
7686  *
7687  * NOTES
7688  *     This function is used by OleConvertIStorageToOLESTREAM only.
7689  *
7690  *     Memory allocated for pData must be freed by the caller
7691  */
7692 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7693 {
7694     HRESULT hRes;
7695     IStream *pStream;
7696     OLECONVERT_ISTORAGE_OLEPRES olePress;
7697     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7698
7699     /* Initialize Default data for OLESTREAM */
7700     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7701     pOleStreamData[0].dwTypeID = 2;
7702     pOleStreamData[0].dwMetaFileWidth = 0;
7703     pOleStreamData[0].dwMetaFileHeight = 0;
7704     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7705     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7706     pOleStreamData[1].dwTypeID = 0;
7707     pOleStreamData[1].dwOleTypeNameLength = 0;
7708     pOleStreamData[1].strOleTypeName[0] = 0;
7709     pOleStreamData[1].dwMetaFileWidth = 0;
7710     pOleStreamData[1].dwMetaFileHeight = 0;
7711     pOleStreamData[1].pData = NULL;
7712     pOleStreamData[1].dwDataLength = 0;
7713
7714
7715     /* Open OlePress000 stream */
7716     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7717         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7718     if(hRes == S_OK)
7719     {
7720         LARGE_INTEGER iSeekPos;
7721         METAFILEPICT16 MetaFilePict;
7722         static const char strMetafilePictName[] = "METAFILEPICT";
7723
7724         /* Set the TypeID for a Metafile */
7725         pOleStreamData[1].dwTypeID = 5;
7726
7727         /* Set the OleTypeName to Metafile */
7728         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7729         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7730
7731         iSeekPos.u.HighPart = 0;
7732         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7733
7734         /* Get Presentation Data */
7735         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7736         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7737         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7738         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7739
7740         /*Set width and Height */
7741         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7742         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7743         if(olePress.dwSize > 0)
7744         {
7745             /* Set Length */
7746             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7747
7748             /* Set MetaFilePict struct */
7749             MetaFilePict.mm = 8;
7750             MetaFilePict.xExt = olePress.dwExtentX;
7751             MetaFilePict.yExt = olePress.dwExtentY;
7752             MetaFilePict.hMF = 0;
7753
7754             /* Get Metafile Data */
7755             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7756             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7757             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7758         }
7759         IStream_Release(pStream);
7760     }
7761 }
7762
7763 /*************************************************************************
7764  * OleConvertOLESTREAMToIStorage [OLE32.@]
7765  *
7766  * Read info on MSDN
7767  *
7768  * TODO
7769  *      DVTARGETDEVICE parameter is not handled
7770  *      Still unsure of some mem fields for OLE 10 Stream
7771  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7772  *      and "\001OLE" streams
7773  *
7774  */
7775 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7776     LPOLESTREAM pOleStream,
7777     LPSTORAGE pstg,
7778     const DVTARGETDEVICE* ptd)
7779 {
7780     int i;
7781     HRESULT hRes=S_OK;
7782     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7783
7784     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
7785
7786     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7787
7788     if(ptd != NULL)
7789     {
7790         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7791     }
7792
7793     if(pstg == NULL || pOleStream == NULL)
7794     {
7795         hRes = E_INVALIDARG;
7796     }
7797
7798     if(hRes == S_OK)
7799     {
7800         /* Load the OLESTREAM to Memory */
7801         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7802     }
7803
7804     if(hRes == S_OK)
7805     {
7806         /* Load the OLESTREAM to Memory (part 2)*/
7807         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7808     }
7809
7810     if(hRes == S_OK)
7811     {
7812
7813         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7814         {
7815             /* Do we have the IStorage Data in the OLESTREAM */
7816             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7817             {
7818                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7819                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7820             }
7821             else
7822             {
7823                 /* It must be an original OLE 1.0 source */
7824                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7825             }
7826         }
7827         else
7828         {
7829             /* It must be an original OLE 1.0 source */
7830             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7831         }
7832
7833         /* Create CompObj Stream if necessary */
7834         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7835         if(hRes == S_OK)
7836         {
7837             /*Create the Ole Stream if necessary */
7838             OLECONVERT_CreateOleStream(pstg);
7839         }
7840     }
7841
7842
7843     /* Free allocated memory */
7844     for(i=0; i < 2; i++)
7845     {
7846         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7847         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7848         pOleStreamData[i].pstrOleObjFileName = NULL;
7849     }
7850     return hRes;
7851 }
7852
7853 /*************************************************************************
7854  * OleConvertIStorageToOLESTREAM [OLE32.@]
7855  *
7856  * Read info on MSDN
7857  *
7858  * Read info on MSDN
7859  *
7860  * TODO
7861  *      Still unsure of some mem fields for OLE 10 Stream
7862  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7863  *      and "\001OLE" streams.
7864  *
7865  */
7866 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7867     LPSTORAGE pstg,
7868     LPOLESTREAM pOleStream)
7869 {
7870     int i;
7871     HRESULT hRes = S_OK;
7872     IStream *pStream;
7873     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7874     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7875
7876     TRACE("%p %p\n", pstg, pOleStream);
7877
7878     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7879
7880     if(pstg == NULL || pOleStream == NULL)
7881     {
7882         hRes = E_INVALIDARG;
7883     }
7884     if(hRes == S_OK)
7885     {
7886         /* Get the ProgID */
7887         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7888         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7889     }
7890     if(hRes == S_OK)
7891     {
7892         /* Was it originally Ole10 */
7893         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7894         if(hRes == S_OK)
7895         {
7896             IStream_Release(pStream);
7897             /* Get Presentation Data for Ole10Native */
7898             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7899         }
7900         else
7901         {
7902             /* Get Presentation Data (OLE20) */
7903             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7904         }
7905
7906         /* Save OLESTREAM */
7907         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7908         if(hRes == S_OK)
7909         {
7910             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7911         }
7912
7913     }
7914
7915     /* Free allocated memory */
7916     for(i=0; i < 2; i++)
7917     {
7918         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7919     }
7920
7921     return hRes;
7922 }
7923
7924 /***********************************************************************
7925  *              GetConvertStg (OLE32.@)
7926  */
7927 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7928     FIXME("unimplemented stub!\n");
7929     return E_FAIL;
7930 }
7931
7932 /******************************************************************************
7933  * StgIsStorageFile [OLE32.@]
7934  * Verify if the file contains a storage object
7935  *
7936  * PARAMS
7937  *  fn      [ I] Filename
7938  *
7939  * RETURNS
7940  *  S_OK    if file has magic bytes as a storage object
7941  *  S_FALSE if file is not storage
7942  */
7943 HRESULT WINAPI
7944 StgIsStorageFile(LPCOLESTR fn)
7945 {
7946         HANDLE          hf;
7947         BYTE            magic[8];
7948         DWORD           bytes_read;
7949
7950         TRACE("%s\n", debugstr_w(fn));
7951         hf = CreateFileW(fn, GENERIC_READ,
7952                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7953                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7954
7955         if (hf == INVALID_HANDLE_VALUE)
7956                 return STG_E_FILENOTFOUND;
7957
7958         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7959         {
7960                 WARN(" unable to read file\n");
7961                 CloseHandle(hf);
7962                 return S_FALSE;
7963         }
7964
7965         CloseHandle(hf);
7966
7967         if (bytes_read != 8) {
7968                 WARN(" too short\n");
7969                 return S_FALSE;
7970         }
7971
7972         if (!memcmp(magic,STORAGE_magic,8)) {
7973                 WARN(" -> YES\n");
7974                 return S_OK;
7975         }
7976
7977         WARN(" -> Invalid header.\n");
7978         return S_FALSE;
7979 }
7980
7981 /***********************************************************************
7982  *              WriteClassStm (OLE32.@)
7983  *
7984  * Writes a CLSID to a stream.
7985  *
7986  * PARAMS
7987  *  pStm   [I] Stream to write to.
7988  *  rclsid [I] CLSID to write.
7989  *
7990  * RETURNS
7991  *  Success: S_OK.
7992  *  Failure: HRESULT code.
7993  */
7994 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
7995 {
7996     TRACE("(%p,%p)\n",pStm,rclsid);
7997
7998     if (!pStm || !rclsid)
7999         return E_INVALIDARG;
8000
8001     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
8002 }
8003
8004 /***********************************************************************
8005  *              ReadClassStm (OLE32.@)
8006  *
8007  * Reads a CLSID from a stream.
8008  *
8009  * PARAMS
8010  *  pStm   [I] Stream to read from.
8011  *  rclsid [O] CLSID to read.
8012  *
8013  * RETURNS
8014  *  Success: S_OK.
8015  *  Failure: HRESULT code.
8016  */
8017 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
8018 {
8019     ULONG nbByte;
8020     HRESULT res;
8021
8022     TRACE("(%p,%p)\n",pStm,pclsid);
8023
8024     if (!pStm || !pclsid)
8025         return E_INVALIDARG;
8026
8027     /* clear the output args */
8028     *pclsid = CLSID_NULL;
8029
8030     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
8031
8032     if (FAILED(res))
8033         return res;
8034
8035     if (nbByte != sizeof(CLSID))
8036         return STG_E_READFAULT;
8037     else
8038         return S_OK;
8039 }