jscript: Added Object function invocation implementation.
[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   StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
3717   HeapFree(GetProcessHeap(), 0, This);
3718 }
3719
3720 /******************************************************************************
3721 **
3722 ** Storage32InternalImpl_Commit
3723 **
3724 ** The non-root storages cannot be opened in transacted mode thus this function
3725 ** does nothing.
3726 */
3727 static HRESULT WINAPI StorageInternalImpl_Commit(
3728   IStorage*            iface,
3729   DWORD                  grfCommitFlags)  /* [in] */
3730 {
3731   return S_OK;
3732 }
3733
3734 /******************************************************************************
3735 **
3736 ** Storage32InternalImpl_Revert
3737 **
3738 ** The non-root storages cannot be opened in transacted mode thus this function
3739 ** does nothing.
3740 */
3741 static HRESULT WINAPI StorageInternalImpl_Revert(
3742   IStorage*            iface)
3743 {
3744   return S_OK;
3745 }
3746
3747 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3748 {
3749   IStorage_Release((IStorage*)This->parentStorage);
3750   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3751   HeapFree(GetProcessHeap(), 0, This);
3752 }
3753
3754 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3755   IEnumSTATSTG*     iface,
3756   REFIID            riid,
3757   void**            ppvObject)
3758 {
3759   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3760
3761   /*
3762    * Perform a sanity check on the parameters.
3763    */
3764   if (ppvObject==0)
3765     return E_INVALIDARG;
3766
3767   /*
3768    * Initialize the return parameter.
3769    */
3770   *ppvObject = 0;
3771
3772   /*
3773    * Compare the riid with the interface IDs implemented by this object.
3774    */
3775   if (IsEqualGUID(&IID_IUnknown, riid) ||
3776       IsEqualGUID(&IID_IEnumSTATSTG, riid))
3777   {
3778     *ppvObject = This;
3779     IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
3780     return S_OK;
3781   }
3782
3783   return E_NOINTERFACE;
3784 }
3785
3786 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
3787   IEnumSTATSTG* iface)
3788 {
3789   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3790   return InterlockedIncrement(&This->ref);
3791 }
3792
3793 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
3794   IEnumSTATSTG* iface)
3795 {
3796   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3797
3798   ULONG newRef;
3799
3800   newRef = InterlockedDecrement(&This->ref);
3801
3802   /*
3803    * If the reference count goes down to 0, perform suicide.
3804    */
3805   if (newRef==0)
3806   {
3807     IEnumSTATSTGImpl_Destroy(This);
3808   }
3809
3810   return newRef;
3811 }
3812
3813 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
3814   IEnumSTATSTG* iface,
3815   ULONG             celt,
3816   STATSTG*          rgelt,
3817   ULONG*            pceltFetched)
3818 {
3819   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3820
3821   StgProperty currentProperty;
3822   STATSTG*    currentReturnStruct = rgelt;
3823   ULONG       objectFetched       = 0;
3824   ULONG      currentSearchNode;
3825
3826   /*
3827    * Perform a sanity check on the parameters.
3828    */
3829   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3830     return E_INVALIDARG;
3831
3832   /*
3833    * To avoid the special case, get another pointer to a ULONG value if
3834    * the caller didn't supply one.
3835    */
3836   if (pceltFetched==0)
3837     pceltFetched = &objectFetched;
3838
3839   /*
3840    * Start the iteration, we will iterate until we hit the end of the
3841    * linked list or until we hit the number of items to iterate through
3842    */
3843   *pceltFetched = 0;
3844
3845   /*
3846    * Start with the node at the top of the stack.
3847    */
3848   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3849
3850   while ( ( *pceltFetched < celt) &&
3851           ( currentSearchNode!=PROPERTY_NULL) )
3852   {
3853     /*
3854      * Remove the top node from the stack
3855      */
3856     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3857
3858     /*
3859      * Read the property from the storage.
3860      */
3861     StorageImpl_ReadProperty(This->parentStorage,
3862       currentSearchNode,
3863       &currentProperty);
3864
3865     /*
3866      * Copy the information to the return buffer.
3867      */
3868     StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3869       &currentProperty,
3870       STATFLAG_DEFAULT);
3871
3872     /*
3873      * Step to the next item in the iteration
3874      */
3875     (*pceltFetched)++;
3876     currentReturnStruct++;
3877
3878     /*
3879      * Push the next search node in the search stack.
3880      */
3881     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3882
3883     /*
3884      * continue the iteration.
3885      */
3886     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3887   }
3888
3889   if (*pceltFetched == celt)
3890     return S_OK;
3891
3892   return S_FALSE;
3893 }
3894
3895
3896 static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3897   IEnumSTATSTG* iface,
3898   ULONG             celt)
3899 {
3900   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3901
3902   StgProperty currentProperty;
3903   ULONG       objectFetched       = 0;
3904   ULONG       currentSearchNode;
3905
3906   /*
3907    * Start with the node at the top of the stack.
3908    */
3909   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3910
3911   while ( (objectFetched < celt) &&
3912           (currentSearchNode!=PROPERTY_NULL) )
3913   {
3914     /*
3915      * Remove the top node from the stack
3916      */
3917     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3918
3919     /*
3920      * Read the property from the storage.
3921      */
3922     StorageImpl_ReadProperty(This->parentStorage,
3923       currentSearchNode,
3924       &currentProperty);
3925
3926     /*
3927      * Step to the next item in the iteration
3928      */
3929     objectFetched++;
3930
3931     /*
3932      * Push the next search node in the search stack.
3933      */
3934     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3935
3936     /*
3937      * continue the iteration.
3938      */
3939     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3940   }
3941
3942   if (objectFetched == celt)
3943     return S_OK;
3944
3945   return S_FALSE;
3946 }
3947
3948 static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3949   IEnumSTATSTG* iface)
3950 {
3951   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3952
3953   StgProperty rootProperty;
3954   BOOL      readSuccessful;
3955
3956   /*
3957    * Re-initialize the search stack to an empty stack
3958    */
3959   This->stackSize = 0;
3960
3961   /*
3962    * Read the root property from the storage.
3963    */
3964   readSuccessful = StorageImpl_ReadProperty(
3965                     This->parentStorage,
3966                     This->firstPropertyNode,
3967                     &rootProperty);
3968
3969   if (readSuccessful)
3970   {
3971     assert(rootProperty.sizeOfNameString!=0);
3972
3973     /*
3974      * Push the search node in the search stack.
3975      */
3976     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3977   }
3978
3979   return S_OK;
3980 }
3981
3982 static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3983   IEnumSTATSTG* iface,
3984   IEnumSTATSTG**    ppenum)
3985 {
3986   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3987
3988   IEnumSTATSTGImpl* newClone;
3989
3990   /*
3991    * Perform a sanity check on the parameters.
3992    */
3993   if (ppenum==0)
3994     return E_INVALIDARG;
3995
3996   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3997                This->firstPropertyNode);
3998
3999
4000   /*
4001    * The new clone enumeration must point to the same current node as
4002    * the ole one.
4003    */
4004   newClone->stackSize    = This->stackSize    ;
4005   newClone->stackMaxSize = This->stackMaxSize ;
4006   newClone->stackToVisit =
4007     HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
4008
4009   memcpy(
4010     newClone->stackToVisit,
4011     This->stackToVisit,
4012     sizeof(ULONG) * newClone->stackSize);
4013
4014   *ppenum = (IEnumSTATSTG*)newClone;
4015
4016   /*
4017    * Don't forget to nail down a reference to the clone before
4018    * returning it.
4019    */
4020   IEnumSTATSTGImpl_AddRef(*ppenum);
4021
4022   return S_OK;
4023 }
4024
4025 static INT IEnumSTATSTGImpl_FindParentProperty(
4026   IEnumSTATSTGImpl *This,
4027   ULONG             childProperty,
4028   StgProperty      *currentProperty,
4029   ULONG            *thisNodeId)
4030 {
4031   ULONG currentSearchNode;
4032   ULONG foundNode;
4033
4034   /*
4035    * To avoid the special case, get another pointer to a ULONG value if
4036    * the caller didn't supply one.
4037    */
4038   if (thisNodeId==0)
4039     thisNodeId = &foundNode;
4040
4041   /*
4042    * Start with the node at the top of the stack.
4043    */
4044   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4045
4046
4047   while (currentSearchNode!=PROPERTY_NULL)
4048   {
4049     /*
4050      * Store the current node in the returned parameters
4051      */
4052     *thisNodeId = currentSearchNode;
4053
4054     /*
4055      * Remove the top node from the stack
4056      */
4057     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
4058
4059     /*
4060      * Read the property from the storage.
4061      */
4062     StorageImpl_ReadProperty(
4063       This->parentStorage,
4064       currentSearchNode,
4065       currentProperty);
4066
4067     if (currentProperty->previousProperty == childProperty)
4068       return PROPERTY_RELATION_PREVIOUS;
4069
4070     else if (currentProperty->nextProperty == childProperty)
4071       return PROPERTY_RELATION_NEXT;
4072
4073     else if (currentProperty->dirProperty == childProperty)
4074       return PROPERTY_RELATION_DIR;
4075
4076     /*
4077      * Push the next search node in the search stack.
4078      */
4079     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
4080
4081     /*
4082      * continue the iteration.
4083      */
4084     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4085   }
4086
4087   return PROPERTY_NULL;
4088 }
4089
4090 static ULONG IEnumSTATSTGImpl_FindProperty(
4091   IEnumSTATSTGImpl* This,
4092   const OLECHAR*  lpszPropName,
4093   StgProperty*      currentProperty)
4094 {
4095   ULONG currentSearchNode;
4096
4097   /*
4098    * Start with the node at the top of the stack.
4099    */
4100   currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4101
4102   while (currentSearchNode!=PROPERTY_NULL)
4103   {
4104     /*
4105      * Remove the top node from the stack
4106      */
4107     IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
4108
4109     /*
4110      * Read the property from the storage.
4111      */
4112     StorageImpl_ReadProperty(This->parentStorage,
4113       currentSearchNode,
4114       currentProperty);
4115
4116     if (propertyNameCmp(currentProperty->name, lpszPropName) == 0)
4117       return currentSearchNode;
4118
4119     /*
4120      * Push the next search node in the search stack.
4121      */
4122     IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
4123
4124     /*
4125      * continue the iteration.
4126      */
4127     currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
4128   }
4129
4130   return PROPERTY_NULL;
4131 }
4132
4133 static void IEnumSTATSTGImpl_PushSearchNode(
4134   IEnumSTATSTGImpl* This,
4135   ULONG             nodeToPush)
4136 {
4137   StgProperty rootProperty;
4138   BOOL      readSuccessful;
4139
4140   /*
4141    * First, make sure we're not trying to push an unexisting node.
4142    */
4143   if (nodeToPush==PROPERTY_NULL)
4144     return;
4145
4146   /*
4147    * First push the node to the stack
4148    */
4149   if (This->stackSize == This->stackMaxSize)
4150   {
4151     This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
4152
4153     This->stackToVisit = HeapReAlloc(
4154                            GetProcessHeap(),
4155                            0,
4156                            This->stackToVisit,
4157                            sizeof(ULONG) * This->stackMaxSize);
4158   }
4159
4160   This->stackToVisit[This->stackSize] = nodeToPush;
4161   This->stackSize++;
4162
4163   /*
4164    * Read the root property from the storage.
4165    */
4166   readSuccessful = StorageImpl_ReadProperty(
4167                     This->parentStorage,
4168                     nodeToPush,
4169                     &rootProperty);
4170
4171   if (readSuccessful)
4172   {
4173     assert(rootProperty.sizeOfNameString!=0);
4174
4175     /*
4176      * Push the previous search node in the search stack.
4177      */
4178     IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
4179   }
4180 }
4181
4182 static ULONG IEnumSTATSTGImpl_PopSearchNode(
4183   IEnumSTATSTGImpl* This,
4184   BOOL            remove)
4185 {
4186   ULONG topNode;
4187
4188   if (This->stackSize == 0)
4189     return PROPERTY_NULL;
4190
4191   topNode = This->stackToVisit[This->stackSize-1];
4192
4193   if (remove)
4194     This->stackSize--;
4195
4196   return topNode;
4197 }
4198
4199 /*
4200  * Virtual function table for the IEnumSTATSTGImpl class.
4201  */
4202 static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
4203 {
4204     IEnumSTATSTGImpl_QueryInterface,
4205     IEnumSTATSTGImpl_AddRef,
4206     IEnumSTATSTGImpl_Release,
4207     IEnumSTATSTGImpl_Next,
4208     IEnumSTATSTGImpl_Skip,
4209     IEnumSTATSTGImpl_Reset,
4210     IEnumSTATSTGImpl_Clone
4211 };
4212
4213 /******************************************************************************
4214 ** IEnumSTATSTGImpl implementation
4215 */
4216
4217 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
4218   StorageImpl* parentStorage,
4219   ULONG          firstPropertyNode)
4220 {
4221   IEnumSTATSTGImpl* newEnumeration;
4222
4223   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
4224
4225   if (newEnumeration!=0)
4226   {
4227     /*
4228      * Set-up the virtual function table and reference count.
4229      */
4230     newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;
4231     newEnumeration->ref       = 0;
4232
4233     /*
4234      * We want to nail-down the reference to the storage in case the
4235      * enumeration out-lives the storage in the client application.
4236      */
4237     newEnumeration->parentStorage = parentStorage;
4238     IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
4239
4240     newEnumeration->firstPropertyNode   = firstPropertyNode;
4241
4242     /*
4243      * Initialize the search stack
4244      */
4245     newEnumeration->stackSize    = 0;
4246     newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
4247     newEnumeration->stackToVisit =
4248       HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
4249
4250     /*
4251      * Make sure the current node of the iterator is the first one.
4252      */
4253     IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
4254   }
4255
4256   return newEnumeration;
4257 }
4258
4259 /*
4260  * Virtual function table for the Storage32InternalImpl class.
4261  */
4262 static const IStorageVtbl Storage32InternalImpl_Vtbl =
4263 {
4264     StorageBaseImpl_QueryInterface,
4265     StorageBaseImpl_AddRef,
4266     StorageBaseImpl_Release,
4267     StorageBaseImpl_CreateStream,
4268     StorageBaseImpl_OpenStream,
4269     StorageImpl_CreateStorage,
4270     StorageBaseImpl_OpenStorage,
4271     StorageImpl_CopyTo,
4272     StorageImpl_MoveElementTo,
4273     StorageInternalImpl_Commit,
4274     StorageInternalImpl_Revert,
4275     StorageBaseImpl_EnumElements,
4276     StorageImpl_DestroyElement,
4277     StorageBaseImpl_RenameElement,
4278     StorageImpl_SetElementTimes,
4279     StorageBaseImpl_SetClass,
4280     StorageImpl_SetStateBits,
4281     StorageBaseImpl_Stat
4282 };
4283
4284 /******************************************************************************
4285 ** Storage32InternalImpl implementation
4286 */
4287
4288 static StorageInternalImpl* StorageInternalImpl_Construct(
4289   StorageImpl* ancestorStorage,
4290   DWORD        openFlags,
4291   ULONG        rootPropertyIndex)
4292 {
4293   StorageInternalImpl* newStorage;
4294
4295   /*
4296    * Allocate space for the new storage object
4297    */
4298   newStorage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StorageInternalImpl));
4299
4300   if (newStorage!=0)
4301   {
4302     /*
4303      * Initialize the stream list
4304      */
4305     list_init(&newStorage->base.strmHead);
4306
4307     /*
4308      * Initialize the virtual function table.
4309      */
4310     newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
4311     newStorage->base.v_destructor = StorageInternalImpl_Destroy;
4312     newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
4313
4314     /*
4315      * Keep the ancestor storage pointer and nail a reference to it.
4316      */
4317     newStorage->base.ancestorStorage = ancestorStorage;
4318     StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage));
4319
4320     /*
4321      * Keep the index of the root property set for this storage,
4322      */
4323     newStorage->base.rootPropertySetIndex = rootPropertyIndex;
4324
4325     return newStorage;
4326   }
4327
4328   return 0;
4329 }
4330
4331 /******************************************************************************
4332 ** StorageUtl implementation
4333 */
4334
4335 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
4336 {
4337   WORD tmp;
4338
4339   memcpy(&tmp, buffer+offset, sizeof(WORD));
4340   *value = lendian16toh(tmp);
4341 }
4342
4343 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
4344 {
4345   value = htole16(value);
4346   memcpy(buffer+offset, &value, sizeof(WORD));
4347 }
4348
4349 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
4350 {
4351   DWORD tmp;
4352
4353   memcpy(&tmp, buffer+offset, sizeof(DWORD));
4354   *value = lendian32toh(tmp);
4355 }
4356
4357 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
4358 {
4359   value = htole32(value);
4360   memcpy(buffer+offset, &value, sizeof(DWORD));
4361 }
4362
4363 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
4364  ULARGE_INTEGER* value)
4365 {
4366 #ifdef WORDS_BIGENDIAN
4367     ULARGE_INTEGER tmp;
4368
4369     memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
4370     value->u.LowPart = htole32(tmp.u.HighPart);
4371     value->u.HighPart = htole32(tmp.u.LowPart);
4372 #else
4373     memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
4374 #endif
4375 }
4376
4377 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
4378  const ULARGE_INTEGER *value)
4379 {
4380 #ifdef WORDS_BIGENDIAN
4381     ULARGE_INTEGER tmp;
4382
4383     tmp.u.LowPart = htole32(value->u.HighPart);
4384     tmp.u.HighPart = htole32(value->u.LowPart);
4385     memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
4386 #else
4387     memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
4388 #endif
4389 }
4390
4391 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
4392 {
4393   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
4394   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
4395   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
4396
4397   memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
4398 }
4399
4400 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
4401 {
4402   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
4403   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
4404   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
4405
4406   memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
4407 }
4408
4409 void StorageUtl_CopyPropertyToSTATSTG(
4410   STATSTG*              destination,
4411   const StgProperty*    source,
4412   int                   statFlags)
4413 {
4414   /*
4415    * The copy of the string occurs only when the flag is not set
4416    */
4417   if( ((statFlags & STATFLAG_NONAME) != 0) || 
4418        (source->name == NULL) || 
4419        (source->name[0] == 0) )
4420   {
4421     destination->pwcsName = 0;
4422   }
4423   else
4424   {
4425     destination->pwcsName =
4426       CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
4427
4428     strcpyW(destination->pwcsName, source->name);
4429   }
4430
4431   switch (source->propertyType)
4432   {
4433     case PROPTYPE_STORAGE:
4434     case PROPTYPE_ROOT:
4435       destination->type = STGTY_STORAGE;
4436       break;
4437     case PROPTYPE_STREAM:
4438       destination->type = STGTY_STREAM;
4439       break;
4440     default:
4441       destination->type = STGTY_STREAM;
4442       break;
4443   }
4444
4445   destination->cbSize            = source->size;
4446 /*
4447   currentReturnStruct->mtime     = {0}; TODO
4448   currentReturnStruct->ctime     = {0};
4449   currentReturnStruct->atime     = {0};
4450 */
4451   destination->grfMode           = 0;
4452   destination->grfLocksSupported = 0;
4453   destination->clsid             = source->propertyUniqueID;
4454   destination->grfStateBits      = 0;
4455   destination->reserved          = 0;
4456 }
4457
4458 /******************************************************************************
4459 ** BlockChainStream implementation
4460 */
4461
4462 BlockChainStream* BlockChainStream_Construct(
4463   StorageImpl* parentStorage,
4464   ULONG*         headOfStreamPlaceHolder,
4465   ULONG          propertyIndex)
4466 {
4467   BlockChainStream* newStream;
4468   ULONG blockIndex;
4469
4470   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4471
4472   newStream->parentStorage           = parentStorage;
4473   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4474   newStream->ownerPropertyIndex      = propertyIndex;
4475   newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
4476   newStream->tailIndex               = BLOCK_END_OF_CHAIN;
4477   newStream->numBlocks               = 0;
4478
4479   blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4480
4481   while (blockIndex != BLOCK_END_OF_CHAIN)
4482   {
4483     newStream->numBlocks++;
4484     newStream->tailIndex = blockIndex;
4485
4486     if(FAILED(StorageImpl_GetNextBlockInChain(
4487               parentStorage,
4488               blockIndex,
4489               &blockIndex)))
4490     {
4491       HeapFree(GetProcessHeap(), 0, newStream);
4492       return NULL;
4493     }
4494   }
4495
4496   return newStream;
4497 }
4498
4499 void BlockChainStream_Destroy(BlockChainStream* This)
4500 {
4501   HeapFree(GetProcessHeap(), 0, This);
4502 }
4503
4504 /******************************************************************************
4505  *      BlockChainStream_GetHeadOfChain
4506  *
4507  * Returns the head of this stream chain.
4508  * Some special chains don't have properties, their heads are kept in
4509  * This->headOfStreamPlaceHolder.
4510  *
4511  */
4512 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4513 {
4514   StgProperty chainProperty;
4515   BOOL      readSuccessful;
4516
4517   if (This->headOfStreamPlaceHolder != 0)
4518     return *(This->headOfStreamPlaceHolder);
4519
4520   if (This->ownerPropertyIndex != PROPERTY_NULL)
4521   {
4522     readSuccessful = StorageImpl_ReadProperty(
4523                       This->parentStorage,
4524                       This->ownerPropertyIndex,
4525                       &chainProperty);
4526
4527     if (readSuccessful)
4528     {
4529       return chainProperty.startingBlock;
4530     }
4531   }
4532
4533   return BLOCK_END_OF_CHAIN;
4534 }
4535
4536 /******************************************************************************
4537  *       BlockChainStream_GetCount
4538  *
4539  * Returns the number of blocks that comprises this chain.
4540  * This is not the size of the stream as the last block may not be full!
4541  *
4542  */
4543 static ULONG BlockChainStream_GetCount(BlockChainStream* This)
4544 {
4545   ULONG blockIndex;
4546   ULONG count = 0;
4547
4548   blockIndex = BlockChainStream_GetHeadOfChain(This);
4549
4550   while (blockIndex != BLOCK_END_OF_CHAIN)
4551   {
4552     count++;
4553
4554     if(FAILED(StorageImpl_GetNextBlockInChain(
4555                    This->parentStorage,
4556                    blockIndex,
4557                    &blockIndex)))
4558       return 0;
4559   }
4560
4561   return count;
4562 }
4563
4564 /******************************************************************************
4565  *      BlockChainStream_ReadAt
4566  *
4567  * Reads a specified number of bytes from this chain at the specified offset.
4568  * bytesRead may be NULL.
4569  * Failure will be returned if the specified number of bytes has not been read.
4570  */
4571 HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
4572   ULARGE_INTEGER offset,
4573   ULONG          size,
4574   void*          buffer,
4575   ULONG*         bytesRead)
4576 {
4577   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4578   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4579   ULONG bytesToReadInBuffer;
4580   ULONG blockIndex;
4581   BYTE* bufferWalker;
4582
4583   TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
4584
4585   /*
4586    * Find the first block in the stream that contains part of the buffer.
4587    */
4588   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4589        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4590        (blockNoInSequence < This->lastBlockNoInSequence) )
4591   {
4592     blockIndex = BlockChainStream_GetHeadOfChain(This);
4593     This->lastBlockNoInSequence = blockNoInSequence;
4594   }
4595   else
4596   {
4597     ULONG temp = blockNoInSequence;
4598
4599     blockIndex = This->lastBlockNoInSequenceIndex;
4600     blockNoInSequence -= This->lastBlockNoInSequence;
4601     This->lastBlockNoInSequence = temp;
4602   }
4603
4604   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4605   {
4606     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4607       return STG_E_DOCFILECORRUPT;
4608     blockNoInSequence--;
4609   }
4610
4611   if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN))
4612       return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */
4613
4614   This->lastBlockNoInSequenceIndex = blockIndex;
4615
4616   /*
4617    * Start reading the buffer.
4618    */
4619   *bytesRead   = 0;
4620   bufferWalker = buffer;
4621
4622   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4623   {
4624     ULARGE_INTEGER ulOffset;
4625     DWORD bytesReadAt;
4626     /*
4627      * Calculate how many bytes we can copy from this big block.
4628      */
4629     bytesToReadInBuffer =
4630       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4631
4632      TRACE("block %i\n",blockIndex);
4633      ulOffset.u.HighPart = 0;
4634      ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
4635                              offsetInBlock;
4636
4637      StorageImpl_ReadAt(This->parentStorage,
4638          ulOffset,
4639          bufferWalker,
4640          bytesToReadInBuffer,
4641          &bytesReadAt);
4642     /*
4643      * Step to the next big block.
4644      */
4645     if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
4646       return STG_E_DOCFILECORRUPT;
4647
4648     bufferWalker += bytesReadAt;
4649     size         -= bytesReadAt;
4650     *bytesRead   += bytesReadAt;
4651     offsetInBlock = 0;  /* There is no offset on the next block */
4652
4653     if (bytesToReadInBuffer != bytesReadAt)
4654         break;
4655   }
4656
4657   return (size == 0) ? S_OK : STG_E_READFAULT;
4658 }
4659
4660 /******************************************************************************
4661  *      BlockChainStream_WriteAt
4662  *
4663  * Writes the specified number of bytes to this chain at the specified offset.
4664  * Will fail if not all specified number of bytes have been written.
4665  */
4666 HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
4667   ULARGE_INTEGER    offset,
4668   ULONG             size,
4669   const void*       buffer,
4670   ULONG*            bytesWritten)
4671 {
4672   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
4673   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
4674   ULONG bytesToWrite;
4675   ULONG blockIndex;
4676   const BYTE* bufferWalker;
4677
4678   /*
4679    * Find the first block in the stream that contains part of the buffer.
4680    */
4681   if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4682        (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4683        (blockNoInSequence < This->lastBlockNoInSequence) )
4684   {
4685     blockIndex = BlockChainStream_GetHeadOfChain(This);
4686     This->lastBlockNoInSequence = blockNoInSequence;
4687   }
4688   else
4689   {
4690     ULONG temp = blockNoInSequence;
4691
4692     blockIndex = This->lastBlockNoInSequenceIndex;
4693     blockNoInSequence -= This->lastBlockNoInSequence;
4694     This->lastBlockNoInSequence = temp;
4695   }
4696
4697   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
4698   {
4699     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4700                                               &blockIndex)))
4701       return STG_E_DOCFILECORRUPT;
4702     blockNoInSequence--;
4703   }
4704
4705   This->lastBlockNoInSequenceIndex = blockIndex;
4706
4707   /* BlockChainStream_SetSize should have already been called to ensure we have
4708    * enough blocks in the chain to write into */
4709   if (blockIndex == BLOCK_END_OF_CHAIN)
4710   {
4711     ERR("not enough blocks in chain to write data\n");
4712     return STG_E_DOCFILECORRUPT;
4713   }
4714
4715   *bytesWritten   = 0;
4716   bufferWalker = buffer;
4717
4718   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4719   {
4720     ULARGE_INTEGER ulOffset;
4721     DWORD bytesWrittenAt;
4722     /*
4723      * Calculate how many bytes we can copy from this big block.
4724      */
4725     bytesToWrite =
4726       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4727
4728     TRACE("block %i\n",blockIndex);
4729     ulOffset.u.HighPart = 0;
4730     ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
4731                              offsetInBlock;
4732
4733     StorageImpl_WriteAt(This->parentStorage,
4734          ulOffset,
4735          bufferWalker,
4736          bytesToWrite,
4737          &bytesWrittenAt);
4738
4739     /*
4740      * Step to the next big block.
4741      */
4742     if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4743                                               &blockIndex)))
4744       return STG_E_DOCFILECORRUPT;
4745
4746     bufferWalker  += bytesWrittenAt;
4747     size          -= bytesWrittenAt;
4748     *bytesWritten += bytesWrittenAt;
4749     offsetInBlock  = 0;      /* There is no offset on the next block */
4750
4751     if (bytesWrittenAt != bytesToWrite)
4752       break;
4753   }
4754
4755   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
4756 }
4757
4758 /******************************************************************************
4759  *      BlockChainStream_Shrink
4760  *
4761  * Shrinks this chain in the big block depot.
4762  */
4763 static BOOL BlockChainStream_Shrink(BlockChainStream* This,
4764                                     ULARGE_INTEGER    newSize)
4765 {
4766   ULONG blockIndex, extraBlock;
4767   ULONG numBlocks;
4768   ULONG count = 1;
4769
4770   /*
4771    * Reset the last accessed block cache.
4772    */
4773   This->lastBlockNoInSequence = 0xFFFFFFFF;
4774   This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4775
4776   /*
4777    * Figure out how many blocks are needed to contain the new size
4778    */
4779   numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4780
4781   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4782     numBlocks++;
4783
4784   blockIndex = BlockChainStream_GetHeadOfChain(This);
4785
4786   /*
4787    * Go to the new end of chain
4788    */
4789   while (count < numBlocks)
4790   {
4791     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4792                                               &blockIndex)))
4793       return FALSE;
4794     count++;
4795   }
4796
4797   /* Get the next block before marking the new end */
4798   if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
4799                                             &extraBlock)))
4800     return FALSE;
4801
4802   /* Mark the new end of chain */
4803   StorageImpl_SetNextBlockInChain(
4804     This->parentStorage,
4805     blockIndex,
4806     BLOCK_END_OF_CHAIN);
4807
4808   This->tailIndex = blockIndex;
4809   This->numBlocks = numBlocks;
4810
4811   /*
4812    * Mark the extra blocks as free
4813    */
4814   while (extraBlock != BLOCK_END_OF_CHAIN)
4815   {
4816     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock,
4817                                               &blockIndex)))
4818       return FALSE;
4819     StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4820     extraBlock = blockIndex;
4821   }
4822
4823   return TRUE;
4824 }
4825
4826 /******************************************************************************
4827  *      BlockChainStream_Enlarge
4828  *
4829  * Grows this chain in the big block depot.
4830  */
4831 static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4832                                      ULARGE_INTEGER    newSize)
4833 {
4834   ULONG blockIndex, currentBlock;
4835   ULONG newNumBlocks;
4836   ULONG oldNumBlocks = 0;
4837
4838   blockIndex = BlockChainStream_GetHeadOfChain(This);
4839
4840   /*
4841    * Empty chain. Create the head.
4842    */
4843   if (blockIndex == BLOCK_END_OF_CHAIN)
4844   {
4845     blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4846     StorageImpl_SetNextBlockInChain(This->parentStorage,
4847                                       blockIndex,
4848                                       BLOCK_END_OF_CHAIN);
4849
4850     if (This->headOfStreamPlaceHolder != 0)
4851     {
4852       *(This->headOfStreamPlaceHolder) = blockIndex;
4853     }
4854     else
4855     {
4856       StgProperty chainProp;
4857       assert(This->ownerPropertyIndex != PROPERTY_NULL);
4858
4859       StorageImpl_ReadProperty(
4860         This->parentStorage,
4861         This->ownerPropertyIndex,
4862         &chainProp);
4863
4864       chainProp.startingBlock = blockIndex;
4865
4866       StorageImpl_WriteProperty(
4867         This->parentStorage,
4868         This->ownerPropertyIndex,
4869         &chainProp);
4870     }
4871
4872     This->tailIndex = blockIndex;
4873     This->numBlocks = 1;
4874   }
4875
4876   /*
4877    * Figure out how many blocks are needed to contain this stream
4878    */
4879   newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
4880
4881   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
4882     newNumBlocks++;
4883
4884   /*
4885    * Go to the current end of chain
4886    */
4887   if (This->tailIndex == BLOCK_END_OF_CHAIN)
4888   {
4889     currentBlock = blockIndex;
4890
4891     while (blockIndex != BLOCK_END_OF_CHAIN)
4892     {
4893       This->numBlocks++;
4894       currentBlock = blockIndex;
4895
4896       if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
4897                                                 &blockIndex)))
4898         return FALSE;
4899     }
4900
4901     This->tailIndex = currentBlock;
4902   }
4903
4904   currentBlock = This->tailIndex;
4905   oldNumBlocks = This->numBlocks;
4906
4907   /*
4908    * Add new blocks to the chain
4909    */
4910   if (oldNumBlocks < newNumBlocks)
4911   {
4912     while (oldNumBlocks < newNumBlocks)
4913     {
4914       blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4915
4916       StorageImpl_SetNextBlockInChain(
4917         This->parentStorage,
4918         currentBlock,
4919         blockIndex);
4920
4921       StorageImpl_SetNextBlockInChain(
4922         This->parentStorage,
4923         blockIndex,
4924         BLOCK_END_OF_CHAIN);
4925
4926       currentBlock = blockIndex;
4927       oldNumBlocks++;
4928     }
4929
4930     This->tailIndex = blockIndex;
4931     This->numBlocks = newNumBlocks;
4932   }
4933
4934   return TRUE;
4935 }
4936
4937 /******************************************************************************
4938  *      BlockChainStream_SetSize
4939  *
4940  * Sets the size of this stream. The big block depot will be updated.
4941  * The file will grow if we grow the chain.
4942  *
4943  * TODO: Free the actual blocks in the file when we shrink the chain.
4944  *       Currently, the blocks are still in the file. So the file size
4945  *       doesn't shrink even if we shrink streams.
4946  */
4947 BOOL BlockChainStream_SetSize(
4948   BlockChainStream* This,
4949   ULARGE_INTEGER    newSize)
4950 {
4951   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4952
4953   if (newSize.u.LowPart == size.u.LowPart)
4954     return TRUE;
4955
4956   if (newSize.u.LowPart < size.u.LowPart)
4957   {
4958     BlockChainStream_Shrink(This, newSize);
4959   }
4960   else
4961   {
4962     BlockChainStream_Enlarge(This, newSize);
4963   }
4964
4965   return TRUE;
4966 }
4967
4968 /******************************************************************************
4969  *      BlockChainStream_GetSize
4970  *
4971  * Returns the size of this chain.
4972  * Will return the block count if this chain doesn't have a property.
4973  */
4974 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4975 {
4976   StgProperty chainProperty;
4977
4978   if(This->headOfStreamPlaceHolder == NULL)
4979   {
4980     /*
4981      * This chain is a data stream read the property and return
4982      * the appropriate size
4983      */
4984     StorageImpl_ReadProperty(
4985       This->parentStorage,
4986       This->ownerPropertyIndex,
4987       &chainProperty);
4988
4989     return chainProperty.size;
4990   }
4991   else
4992   {
4993     /*
4994      * this chain is a chain that does not have a property, figure out the
4995      * size by making the product number of used blocks times the
4996      * size of them
4997      */
4998     ULARGE_INTEGER result;
4999     result.u.HighPart = 0;
5000
5001     result.u.LowPart  =
5002       BlockChainStream_GetCount(This) *
5003       This->parentStorage->bigBlockSize;
5004
5005     return result;
5006   }
5007 }
5008
5009 /******************************************************************************
5010 ** SmallBlockChainStream implementation
5011 */
5012
5013 SmallBlockChainStream* SmallBlockChainStream_Construct(
5014   StorageImpl* parentStorage,
5015   ULONG*         headOfStreamPlaceHolder,
5016   ULONG          propertyIndex)
5017 {
5018   SmallBlockChainStream* newStream;
5019
5020   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
5021
5022   newStream->parentStorage      = parentStorage;
5023   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
5024   newStream->ownerPropertyIndex = propertyIndex;
5025
5026   return newStream;
5027 }
5028
5029 void SmallBlockChainStream_Destroy(
5030   SmallBlockChainStream* This)
5031 {
5032   HeapFree(GetProcessHeap(), 0, This);
5033 }
5034
5035 /******************************************************************************
5036  *      SmallBlockChainStream_GetHeadOfChain
5037  *
5038  * Returns the head of this chain of small blocks.
5039  */
5040 static ULONG SmallBlockChainStream_GetHeadOfChain(
5041   SmallBlockChainStream* This)
5042 {
5043   StgProperty chainProperty;
5044   BOOL      readSuccessful;
5045
5046   if (This->headOfStreamPlaceHolder != NULL)
5047     return *(This->headOfStreamPlaceHolder);
5048
5049   if (This->ownerPropertyIndex)
5050   {
5051     readSuccessful = StorageImpl_ReadProperty(
5052                       This->parentStorage,
5053                       This->ownerPropertyIndex,
5054                       &chainProperty);
5055
5056     if (readSuccessful)
5057     {
5058       return chainProperty.startingBlock;
5059     }
5060
5061   }
5062
5063   return BLOCK_END_OF_CHAIN;
5064 }
5065
5066 /******************************************************************************
5067  *      SmallBlockChainStream_GetNextBlockInChain
5068  *
5069  * Returns the index of the next small block in this chain.
5070  *
5071  * Return Values:
5072  *    - BLOCK_END_OF_CHAIN: end of this chain
5073  *    - BLOCK_UNUSED: small block 'blockIndex' is free
5074  */
5075 static HRESULT SmallBlockChainStream_GetNextBlockInChain(
5076   SmallBlockChainStream* This,
5077   ULONG                  blockIndex,
5078   ULONG*                 nextBlockInChain)
5079 {
5080   ULARGE_INTEGER offsetOfBlockInDepot;
5081   DWORD  buffer;
5082   ULONG  bytesRead;
5083   HRESULT res;
5084
5085   *nextBlockInChain = BLOCK_END_OF_CHAIN;
5086
5087   offsetOfBlockInDepot.u.HighPart = 0;
5088   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
5089
5090   /*
5091    * Read those bytes in the buffer from the small block file.
5092    */
5093   res = BlockChainStream_ReadAt(
5094               This->parentStorage->smallBlockDepotChain,
5095               offsetOfBlockInDepot,
5096               sizeof(DWORD),
5097               &buffer,
5098               &bytesRead);
5099
5100   if (SUCCEEDED(res))
5101   {
5102     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
5103     return S_OK;
5104   }
5105
5106   return res;
5107 }
5108
5109 /******************************************************************************
5110  *       SmallBlockChainStream_SetNextBlockInChain
5111  *
5112  * Writes the index of the next block of the specified block in the small
5113  * block depot.
5114  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
5115  * To flag a block as free use BLOCK_UNUSED as nextBlock.
5116  */
5117 static void SmallBlockChainStream_SetNextBlockInChain(
5118   SmallBlockChainStream* This,
5119   ULONG                  blockIndex,
5120   ULONG                  nextBlock)
5121 {
5122   ULARGE_INTEGER offsetOfBlockInDepot;
5123   DWORD  buffer;
5124   ULONG  bytesWritten;
5125
5126   offsetOfBlockInDepot.u.HighPart = 0;
5127   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
5128
5129   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
5130
5131   /*
5132    * Read those bytes in the buffer from the small block file.
5133    */
5134   BlockChainStream_WriteAt(
5135     This->parentStorage->smallBlockDepotChain,
5136     offsetOfBlockInDepot,
5137     sizeof(DWORD),
5138     &buffer,
5139     &bytesWritten);
5140 }
5141
5142 /******************************************************************************
5143  *      SmallBlockChainStream_FreeBlock
5144  *
5145  * Flag small block 'blockIndex' as free in the small block depot.
5146  */
5147 static void SmallBlockChainStream_FreeBlock(
5148   SmallBlockChainStream* This,
5149   ULONG                  blockIndex)
5150 {
5151   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
5152 }
5153
5154 /******************************************************************************
5155  *      SmallBlockChainStream_GetNextFreeBlock
5156  *
5157  * Returns the index of a free small block. The small block depot will be
5158  * enlarged if necessary. The small block chain will also be enlarged if
5159  * necessary.
5160  */
5161 static ULONG SmallBlockChainStream_GetNextFreeBlock(
5162   SmallBlockChainStream* This)
5163 {
5164   ULARGE_INTEGER offsetOfBlockInDepot;
5165   DWORD buffer;
5166   ULONG bytesRead;
5167   ULONG blockIndex = 0;
5168   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
5169   HRESULT res = S_OK;
5170   ULONG smallBlocksPerBigBlock;
5171
5172   offsetOfBlockInDepot.u.HighPart = 0;
5173
5174   /*
5175    * Scan the small block depot for a free block
5176    */
5177   while (nextBlockIndex != BLOCK_UNUSED)
5178   {
5179     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
5180
5181     res = BlockChainStream_ReadAt(
5182                 This->parentStorage->smallBlockDepotChain,
5183                 offsetOfBlockInDepot,
5184                 sizeof(DWORD),
5185                 &buffer,
5186                 &bytesRead);
5187
5188     /*
5189      * If we run out of space for the small block depot, enlarge it
5190      */
5191     if (SUCCEEDED(res))
5192     {
5193       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
5194
5195       if (nextBlockIndex != BLOCK_UNUSED)
5196         blockIndex++;
5197     }
5198     else
5199     {
5200       ULONG count =
5201         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
5202
5203       ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
5204       ULONG nextBlock, newsbdIndex;
5205       BYTE smallBlockDepot[BIG_BLOCK_SIZE];
5206
5207       nextBlock = sbdIndex;
5208       while (nextBlock != BLOCK_END_OF_CHAIN)
5209       {
5210         sbdIndex = nextBlock;
5211         StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);
5212       }
5213
5214       newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5215       if (sbdIndex != BLOCK_END_OF_CHAIN)
5216         StorageImpl_SetNextBlockInChain(
5217           This->parentStorage,
5218           sbdIndex,
5219           newsbdIndex);
5220
5221       StorageImpl_SetNextBlockInChain(
5222         This->parentStorage,
5223         newsbdIndex,
5224         BLOCK_END_OF_CHAIN);
5225
5226       /*
5227        * Initialize all the small blocks to free
5228        */
5229       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
5230       StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot);
5231
5232       if (count == 0)
5233       {
5234         /*
5235          * We have just created the small block depot.
5236          */
5237         StgProperty rootProp;
5238         ULONG sbStartIndex;
5239
5240         /*
5241          * Save it in the header
5242          */
5243         This->parentStorage->smallBlockDepotStart = newsbdIndex;
5244         StorageImpl_SaveFileHeader(This->parentStorage);
5245
5246         /*
5247          * And allocate the first big block that will contain small blocks
5248          */
5249         sbStartIndex =
5250           StorageImpl_GetNextFreeBigBlock(This->parentStorage);
5251
5252         StorageImpl_SetNextBlockInChain(
5253           This->parentStorage,
5254           sbStartIndex,
5255           BLOCK_END_OF_CHAIN);
5256
5257         StorageImpl_ReadProperty(
5258           This->parentStorage,
5259           This->parentStorage->base.rootPropertySetIndex,
5260           &rootProp);
5261
5262         rootProp.startingBlock = sbStartIndex;
5263         rootProp.size.u.HighPart = 0;
5264         rootProp.size.u.LowPart  = This->parentStorage->bigBlockSize;
5265
5266         StorageImpl_WriteProperty(
5267           This->parentStorage,
5268           This->parentStorage->base.rootPropertySetIndex,
5269           &rootProp);
5270       }
5271       else
5272         StorageImpl_SaveFileHeader(This->parentStorage);
5273     }
5274   }
5275
5276   smallBlocksPerBigBlock =
5277     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
5278
5279   /*
5280    * Verify if we have to allocate big blocks to contain small blocks
5281    */
5282   if (blockIndex % smallBlocksPerBigBlock == 0)
5283   {
5284     StgProperty rootProp;
5285     ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
5286
5287     StorageImpl_ReadProperty(
5288       This->parentStorage,
5289       This->parentStorage->base.rootPropertySetIndex,
5290       &rootProp);
5291
5292     if (rootProp.size.u.LowPart <
5293        (blocksRequired * This->parentStorage->bigBlockSize))
5294     {
5295       rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
5296
5297       BlockChainStream_SetSize(
5298         This->parentStorage->smallBlockRootChain,
5299         rootProp.size);
5300
5301       StorageImpl_WriteProperty(
5302         This->parentStorage,
5303         This->parentStorage->base.rootPropertySetIndex,
5304         &rootProp);
5305     }
5306   }
5307
5308   return blockIndex;
5309 }
5310
5311 /******************************************************************************
5312  *      SmallBlockChainStream_ReadAt
5313  *
5314  * Reads a specified number of bytes from this chain at the specified offset.
5315  * bytesRead may be NULL.
5316  * Failure will be returned if the specified number of bytes has not been read.
5317  */
5318 HRESULT SmallBlockChainStream_ReadAt(
5319   SmallBlockChainStream* This,
5320   ULARGE_INTEGER         offset,
5321   ULONG                  size,
5322   void*                  buffer,
5323   ULONG*                 bytesRead)
5324 {
5325   HRESULT rc = S_OK;
5326   ULARGE_INTEGER offsetInBigBlockFile;
5327   ULONG blockNoInSequence =
5328     offset.u.LowPart / This->parentStorage->smallBlockSize;
5329
5330   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5331   ULONG bytesToReadInBuffer;
5332   ULONG blockIndex;
5333   ULONG bytesReadFromBigBlockFile;
5334   BYTE* bufferWalker;
5335
5336   /*
5337    * This should never happen on a small block file.
5338    */
5339   assert(offset.u.HighPart==0);
5340
5341   /*
5342    * Find the first block in the stream that contains part of the buffer.
5343    */
5344   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5345
5346   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5347   {
5348     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5349     if(FAILED(rc))
5350       return rc;
5351     blockNoInSequence--;
5352   }
5353
5354   /*
5355    * Start reading the buffer.
5356    */
5357   *bytesRead   = 0;
5358   bufferWalker = buffer;
5359
5360   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5361   {
5362     /*
5363      * Calculate how many bytes we can copy from this small block.
5364      */
5365     bytesToReadInBuffer =
5366       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5367
5368     /*
5369      * Calculate the offset of the small block in the small block file.
5370      */
5371     offsetInBigBlockFile.u.HighPart  = 0;
5372     offsetInBigBlockFile.u.LowPart   =
5373       blockIndex * This->parentStorage->smallBlockSize;
5374
5375     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5376
5377     /*
5378      * Read those bytes in the buffer from the small block file.
5379      * The small block has already been identified so it shouldn't fail
5380      * unless the file is corrupt.
5381      */
5382     rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
5383       offsetInBigBlockFile,
5384       bytesToReadInBuffer,
5385       bufferWalker,
5386       &bytesReadFromBigBlockFile);
5387
5388     if (FAILED(rc))
5389       return rc;
5390
5391     /*
5392      * Step to the next big block.
5393      */
5394     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
5395     if(FAILED(rc))
5396       return STG_E_DOCFILECORRUPT;
5397
5398     bufferWalker += bytesReadFromBigBlockFile;
5399     size         -= bytesReadFromBigBlockFile;
5400     *bytesRead   += bytesReadFromBigBlockFile;
5401     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
5402   }
5403
5404   return (size == 0) ? S_OK : STG_E_READFAULT;
5405 }
5406
5407 /******************************************************************************
5408  *       SmallBlockChainStream_WriteAt
5409  *
5410  * Writes the specified number of bytes to this chain at the specified offset.
5411  * Will fail if not all specified number of bytes have been written.
5412  */
5413 HRESULT SmallBlockChainStream_WriteAt(
5414   SmallBlockChainStream* This,
5415   ULARGE_INTEGER offset,
5416   ULONG          size,
5417   const void*    buffer,
5418   ULONG*         bytesWritten)
5419 {
5420   ULARGE_INTEGER offsetInBigBlockFile;
5421   ULONG blockNoInSequence =
5422     offset.u.LowPart / This->parentStorage->smallBlockSize;
5423
5424   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
5425   ULONG bytesToWriteInBuffer;
5426   ULONG blockIndex;
5427   ULONG bytesWrittenToBigBlockFile;
5428   const BYTE* bufferWalker;
5429   HRESULT res;
5430
5431   /*
5432    * This should never happen on a small block file.
5433    */
5434   assert(offset.u.HighPart==0);
5435
5436   /*
5437    * Find the first block in the stream that contains part of the buffer.
5438    */
5439   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5440
5441   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
5442   {
5443     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
5444       return STG_E_DOCFILECORRUPT;
5445     blockNoInSequence--;
5446   }
5447
5448   /*
5449    * Start writing the buffer.
5450    */
5451   *bytesWritten   = 0;
5452   bufferWalker = buffer;
5453   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
5454   {
5455     /*
5456      * Calculate how many bytes we can copy to this small block.
5457      */
5458     bytesToWriteInBuffer =
5459       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5460
5461     /*
5462      * Calculate the offset of the small block in the small block file.
5463      */
5464     offsetInBigBlockFile.u.HighPart  = 0;
5465     offsetInBigBlockFile.u.LowPart   =
5466       blockIndex * This->parentStorage->smallBlockSize;
5467
5468     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
5469
5470     /*
5471      * Write those bytes in the buffer to the small block file.
5472      */
5473     res = BlockChainStream_WriteAt(
5474       This->parentStorage->smallBlockRootChain,
5475       offsetInBigBlockFile,
5476       bytesToWriteInBuffer,
5477       bufferWalker,
5478       &bytesWrittenToBigBlockFile);
5479     if (FAILED(res))
5480       return res;
5481
5482     /*
5483      * Step to the next big block.
5484      */
5485     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5486                                                         &blockIndex)))
5487       return FALSE;
5488     bufferWalker  += bytesWrittenToBigBlockFile;
5489     size          -= bytesWrittenToBigBlockFile;
5490     *bytesWritten += bytesWrittenToBigBlockFile;
5491     offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
5492   }
5493
5494   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
5495 }
5496
5497 /******************************************************************************
5498  *       SmallBlockChainStream_Shrink
5499  *
5500  * Shrinks this chain in the small block depot.
5501  */
5502 static BOOL SmallBlockChainStream_Shrink(
5503   SmallBlockChainStream* This,
5504   ULARGE_INTEGER newSize)
5505 {
5506   ULONG blockIndex, extraBlock;
5507   ULONG numBlocks;
5508   ULONG count = 0;
5509
5510   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5511
5512   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5513     numBlocks++;
5514
5515   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5516
5517   /*
5518    * Go to the new end of chain
5519    */
5520   while (count < numBlocks)
5521   {
5522     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5523                                                         &blockIndex)))
5524       return FALSE;
5525     count++;
5526   }
5527
5528   /*
5529    * If the count is 0, we have a special case, the head of the chain was
5530    * just freed.
5531    */
5532   if (count == 0)
5533   {
5534     StgProperty chainProp;
5535
5536     StorageImpl_ReadProperty(This->parentStorage,
5537                              This->ownerPropertyIndex,
5538                              &chainProp);
5539
5540     chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5541
5542     StorageImpl_WriteProperty(This->parentStorage,
5543                               This->ownerPropertyIndex,
5544                               &chainProp);
5545
5546     /*
5547      * We start freeing the chain at the head block.
5548      */
5549     extraBlock = blockIndex;
5550   }
5551   else
5552   {
5553     /* Get the next block before marking the new end */
5554     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
5555                                                         &extraBlock)))
5556       return FALSE;
5557
5558     /* Mark the new end of chain */
5559     SmallBlockChainStream_SetNextBlockInChain(
5560       This,
5561       blockIndex,
5562       BLOCK_END_OF_CHAIN);
5563   }
5564
5565   /*
5566    * Mark the extra blocks as free
5567    */
5568   while (extraBlock != BLOCK_END_OF_CHAIN)
5569   {
5570     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
5571                                                         &blockIndex)))
5572       return FALSE;
5573     SmallBlockChainStream_FreeBlock(This, extraBlock);
5574     extraBlock = blockIndex;
5575   }
5576
5577   return TRUE;
5578 }
5579
5580 /******************************************************************************
5581  *      SmallBlockChainStream_Enlarge
5582  *
5583  * Grows this chain in the small block depot.
5584  */
5585 static BOOL SmallBlockChainStream_Enlarge(
5586   SmallBlockChainStream* This,
5587   ULARGE_INTEGER newSize)
5588 {
5589   ULONG blockIndex, currentBlock;
5590   ULONG newNumBlocks;
5591   ULONG oldNumBlocks = 0;
5592
5593   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5594
5595   /*
5596    * Empty chain. Create the head.
5597    */
5598   if (blockIndex == BLOCK_END_OF_CHAIN)
5599   {
5600     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5601     SmallBlockChainStream_SetNextBlockInChain(
5602         This,
5603         blockIndex,
5604         BLOCK_END_OF_CHAIN);
5605
5606     if (This->headOfStreamPlaceHolder != NULL)
5607     {
5608       *(This->headOfStreamPlaceHolder) = blockIndex;
5609     }
5610     else
5611     {
5612       StgProperty chainProp;
5613
5614       StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5615                                    &chainProp);
5616
5617       chainProp.startingBlock = blockIndex;
5618
5619       StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5620                                   &chainProp);
5621     }
5622   }
5623
5624   currentBlock = blockIndex;
5625
5626   /*
5627    * Figure out how many blocks are needed to contain this stream
5628    */
5629   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
5630
5631   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
5632     newNumBlocks++;
5633
5634   /*
5635    * Go to the current end of chain
5636    */
5637   while (blockIndex != BLOCK_END_OF_CHAIN)
5638   {
5639     oldNumBlocks++;
5640     currentBlock = blockIndex;
5641     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
5642       return FALSE;
5643   }
5644
5645   /*
5646    * Add new blocks to the chain
5647    */
5648   while (oldNumBlocks < newNumBlocks)
5649   {
5650     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5651     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5652
5653     SmallBlockChainStream_SetNextBlockInChain(
5654       This,
5655       blockIndex,
5656       BLOCK_END_OF_CHAIN);
5657
5658     currentBlock = blockIndex;
5659     oldNumBlocks++;
5660   }
5661
5662   return TRUE;
5663 }
5664
5665 /******************************************************************************
5666  *      SmallBlockChainStream_SetSize
5667  *
5668  * Sets the size of this stream.
5669  * The file will grow if we grow the chain.
5670  *
5671  * TODO: Free the actual blocks in the file when we shrink the chain.
5672  *       Currently, the blocks are still in the file. So the file size
5673  *       doesn't shrink even if we shrink streams.
5674  */
5675 BOOL SmallBlockChainStream_SetSize(
5676                 SmallBlockChainStream* This,
5677                 ULARGE_INTEGER    newSize)
5678 {
5679   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5680
5681   if (newSize.u.LowPart == size.u.LowPart)
5682     return TRUE;
5683
5684   if (newSize.u.LowPart < size.u.LowPart)
5685   {
5686     SmallBlockChainStream_Shrink(This, newSize);
5687   }
5688   else
5689   {
5690     SmallBlockChainStream_Enlarge(This, newSize);
5691   }
5692
5693   return TRUE;
5694 }
5695
5696 /******************************************************************************
5697  *       SmallBlockChainStream_GetCount
5698  *
5699  * Returns the number of small blocks that comprises this chain.
5700  * This is not the size of the stream as the last block may not be full!
5701  *
5702  */
5703 static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5704 {
5705     ULONG blockIndex;
5706     ULONG count = 0;
5707
5708     blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5709
5710     while(blockIndex != BLOCK_END_OF_CHAIN)
5711     {
5712         count++;
5713
5714         if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This,
5715                         blockIndex, &blockIndex)))
5716             return 0;
5717     }
5718
5719     return count;
5720 }
5721
5722 /******************************************************************************
5723  *      SmallBlockChainStream_GetSize
5724  *
5725  * Returns the size of this chain.
5726  */
5727 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5728 {
5729   StgProperty chainProperty;
5730
5731   if(This->headOfStreamPlaceHolder != NULL)
5732   {
5733     ULARGE_INTEGER result;
5734     result.u.HighPart = 0;
5735
5736     result.u.LowPart = SmallBlockChainStream_GetCount(This) *
5737         This->parentStorage->smallBlockSize;
5738
5739     return result;
5740   }
5741
5742   StorageImpl_ReadProperty(
5743     This->parentStorage,
5744     This->ownerPropertyIndex,
5745     &chainProperty);
5746
5747   return chainProperty.size;
5748 }
5749
5750 /******************************************************************************
5751  *    StgCreateDocfile  [OLE32.@]
5752  * Creates a new compound file storage object
5753  *
5754  * PARAMS
5755  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
5756  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
5757  *  reserved  [ ?] unused?, usually 0
5758  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
5759  *
5760  * RETURNS
5761  *  S_OK if the file was successfully created
5762  *  some STG_E_ value if error
5763  * NOTES
5764  *  if pwcsName is NULL, create file with new unique name
5765  *  the function can returns
5766  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
5767  *  (unrealized now)
5768  */
5769 HRESULT WINAPI StgCreateDocfile(
5770   LPCOLESTR pwcsName,
5771   DWORD       grfMode,
5772   DWORD       reserved,
5773   IStorage  **ppstgOpen)
5774 {
5775   StorageImpl* newStorage = 0;
5776   HANDLE       hFile      = INVALID_HANDLE_VALUE;
5777   HRESULT        hr         = STG_E_INVALIDFLAG;
5778   DWORD          shareMode;
5779   DWORD          accessMode;
5780   DWORD          creationMode;
5781   DWORD          fileAttributes;
5782   WCHAR          tempFileName[MAX_PATH];
5783
5784   TRACE("(%s, %x, %d, %p)\n",
5785         debugstr_w(pwcsName), grfMode,
5786         reserved, ppstgOpen);
5787
5788   /*
5789    * Validate the parameters
5790    */
5791   if (ppstgOpen == 0)
5792     return STG_E_INVALIDPOINTER;
5793   if (reserved != 0)
5794     return STG_E_INVALIDPARAMETER;
5795
5796   /* if no share mode given then DENY_NONE is the default */
5797   if (STGM_SHARE_MODE(grfMode) == 0)
5798       grfMode |= STGM_SHARE_DENY_NONE;
5799
5800   /*
5801    * Validate the STGM flags
5802    */
5803   if ( FAILED( validateSTGM(grfMode) ))
5804     goto end;
5805
5806   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
5807   switch(STGM_ACCESS_MODE(grfMode))
5808   {
5809   case STGM_WRITE:
5810   case STGM_READWRITE:
5811     break;
5812   default:
5813     goto end;
5814   }
5815
5816   /* in direct mode, can only use SHARE_EXCLUSIVE */
5817   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
5818     goto end;
5819
5820   /* but in transacted mode, any share mode is valid */
5821
5822   /*
5823    * Generate a unique name.
5824    */
5825   if (pwcsName == 0)
5826   {
5827     WCHAR tempPath[MAX_PATH];
5828     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5829
5830     memset(tempPath, 0, sizeof(tempPath));
5831     memset(tempFileName, 0, sizeof(tempFileName));
5832
5833     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5834       tempPath[0] = '.';
5835
5836     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5837       pwcsName = tempFileName;
5838     else
5839     {
5840       hr = STG_E_INSUFFICIENTMEMORY;
5841       goto end;
5842     }
5843
5844     creationMode = TRUNCATE_EXISTING;
5845   }
5846   else
5847   {
5848     creationMode = GetCreationModeFromSTGM(grfMode);
5849   }
5850
5851   /*
5852    * Interpret the STGM value grfMode
5853    */
5854   shareMode    = FILE_SHARE_READ | FILE_SHARE_WRITE;
5855   accessMode   = GetAccessModeFromSTGM(grfMode);
5856
5857   if (grfMode & STGM_DELETEONRELEASE)
5858     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5859   else
5860     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5861
5862   if (STGM_SHARE_MODE(grfMode) && !(grfMode & STGM_SHARE_DENY_NONE))
5863       FIXME("Storage share mode not implemented.\n");
5864
5865   if (grfMode & STGM_TRANSACTED)
5866     FIXME("Transacted mode not implemented.\n");
5867
5868   /*
5869    * Initialize the "out" parameter.
5870    */
5871   *ppstgOpen = 0;
5872
5873   hFile = CreateFileW(pwcsName,
5874                         accessMode,
5875                         shareMode,
5876                         NULL,
5877                         creationMode,
5878                         fileAttributes,
5879                         0);
5880
5881   if (hFile == INVALID_HANDLE_VALUE)
5882   {
5883     if(GetLastError() == ERROR_FILE_EXISTS)
5884       hr = STG_E_FILEALREADYEXISTS;
5885     else
5886       hr = E_FAIL;
5887     goto end;
5888   }
5889
5890   /*
5891    * Allocate and initialize the new IStorage32object.
5892    */
5893   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5894
5895   if (newStorage == 0)
5896   {
5897     hr = STG_E_INSUFFICIENTMEMORY;
5898     goto end;
5899   }
5900
5901   hr = StorageImpl_Construct(
5902          newStorage,
5903          hFile,
5904         pwcsName,
5905          NULL,
5906          grfMode,
5907          TRUE,
5908          TRUE);
5909
5910   if (FAILED(hr))
5911   {
5912     HeapFree(GetProcessHeap(), 0, newStorage);
5913     goto end;
5914   }
5915
5916   /*
5917    * Get an "out" pointer for the caller.
5918    */
5919   hr = StorageBaseImpl_QueryInterface(
5920          (IStorage*)newStorage,
5921          &IID_IStorage,
5922          (void**)ppstgOpen);
5923 end:
5924   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
5925
5926   return hr;
5927 }
5928
5929 /******************************************************************************
5930  *              StgCreateStorageEx        [OLE32.@]
5931  */
5932 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5933 {
5934     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5935           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5936
5937     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
5938     {
5939         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
5940         return STG_E_INVALIDPARAMETER;  
5941     }
5942
5943     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
5944     {
5945         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
5946         return STG_E_INVALIDPARAMETER;  
5947     }
5948
5949     if (stgfmt == STGFMT_FILE)
5950     {
5951         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
5952         return STG_E_INVALIDPARAMETER;
5953     }
5954
5955     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
5956     {
5957         FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
5958         return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
5959     }
5960
5961     ERR("Invalid stgfmt argument\n");
5962     return STG_E_INVALIDPARAMETER;
5963 }
5964
5965 /******************************************************************************
5966  *              StgCreatePropSetStg       [OLE32.@]
5967  */
5968 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
5969  IPropertySetStorage **ppPropSetStg)
5970 {
5971     HRESULT hr;
5972
5973     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
5974     if (reserved)
5975         hr = STG_E_INVALIDPARAMETER;
5976     else
5977         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
5978          (void**)ppPropSetStg);
5979     return hr;
5980 }
5981
5982 /******************************************************************************
5983  *              StgOpenStorageEx      [OLE32.@]
5984  */
5985 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
5986 {
5987     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
5988           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
5989
5990     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
5991     {
5992         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
5993         return STG_E_INVALIDPARAMETER;  
5994     }
5995
5996     switch (stgfmt)
5997     {
5998     case STGFMT_FILE:
5999         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
6000         return STG_E_INVALIDPARAMETER;
6001         
6002     case STGFMT_STORAGE:
6003         break;
6004
6005     case STGFMT_DOCFILE:
6006         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
6007         {
6008             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
6009             return STG_E_INVALIDPARAMETER;  
6010         }
6011         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
6012         break;
6013
6014     case STGFMT_ANY:
6015         WARN("STGFMT_ANY assuming storage\n");
6016         break;
6017
6018     default:
6019         return STG_E_INVALIDPARAMETER;
6020     }
6021
6022     return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
6023 }
6024
6025
6026 /******************************************************************************
6027  *              StgOpenStorage        [OLE32.@]
6028  */
6029 HRESULT WINAPI StgOpenStorage(
6030   const OLECHAR *pwcsName,
6031   IStorage      *pstgPriority,
6032   DWORD          grfMode,
6033   SNB            snbExclude,
6034   DWORD          reserved,
6035   IStorage     **ppstgOpen)
6036 {
6037   StorageImpl*   newStorage = 0;
6038   HRESULT        hr = S_OK;
6039   HANDLE         hFile = 0;
6040   DWORD          shareMode;
6041   DWORD          accessMode;
6042   WCHAR          fullname[MAX_PATH];
6043
6044   TRACE("(%s, %p, %x, %p, %d, %p)\n",
6045         debugstr_w(pwcsName), pstgPriority, grfMode,
6046         snbExclude, reserved, ppstgOpen);
6047
6048   /*
6049    * Perform sanity checks
6050    */
6051   if (pwcsName == 0)
6052   {
6053     hr = STG_E_INVALIDNAME;
6054     goto end;
6055   }
6056
6057   if (ppstgOpen == 0)
6058   {
6059     hr = STG_E_INVALIDPOINTER;
6060     goto end;
6061   }
6062
6063   if (reserved)
6064   {
6065     hr = STG_E_INVALIDPARAMETER;
6066     goto end;
6067   }
6068
6069   if (grfMode & STGM_PRIORITY)
6070   {
6071     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
6072       return STG_E_INVALIDFLAG;
6073     if (grfMode & STGM_DELETEONRELEASE)
6074       return STG_E_INVALIDFUNCTION;
6075     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
6076       return STG_E_INVALIDFLAG;
6077     grfMode &= ~0xf0; /* remove the existing sharing mode */
6078     grfMode |= STGM_SHARE_DENY_NONE;
6079
6080     /* STGM_PRIORITY stops other IStorage objects on the same file from
6081      * committing until the STGM_PRIORITY IStorage is closed. it also
6082      * stops non-transacted mode StgOpenStorage calls with write access from
6083      * succeeding. obviously, both of these cannot be achieved through just
6084      * file share flags */
6085     FIXME("STGM_PRIORITY mode not implemented correctly\n");
6086   }
6087
6088   /*
6089    * Validate the sharing mode
6090    */
6091   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
6092     switch(STGM_SHARE_MODE(grfMode))
6093     {
6094       case STGM_SHARE_EXCLUSIVE:
6095       case STGM_SHARE_DENY_WRITE:
6096         break;
6097       default:
6098         hr = STG_E_INVALIDFLAG;
6099         goto end;
6100     }
6101
6102   /*
6103    * Validate the STGM flags
6104    */
6105   if ( FAILED( validateSTGM(grfMode) ) ||
6106        (grfMode&STGM_CREATE))
6107   {
6108     hr = STG_E_INVALIDFLAG;
6109     goto end;
6110   }
6111
6112   /* shared reading requires transacted mode */
6113   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
6114       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
6115      !(grfMode&STGM_TRANSACTED) )
6116   {
6117     hr = STG_E_INVALIDFLAG;
6118     goto end;
6119   }
6120
6121   /*
6122    * Interpret the STGM value grfMode
6123    */
6124   shareMode    = GetShareModeFromSTGM(grfMode);
6125   accessMode   = GetAccessModeFromSTGM(grfMode);
6126
6127   /*
6128    * Initialize the "out" parameter.
6129    */
6130   *ppstgOpen = 0;
6131
6132   hFile = CreateFileW( pwcsName,
6133                        accessMode,
6134                        shareMode,
6135                        NULL,
6136                        OPEN_EXISTING,
6137                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
6138                        0);
6139
6140   if (hFile==INVALID_HANDLE_VALUE)
6141   {
6142     DWORD last_error = GetLastError();
6143
6144     hr = E_FAIL;
6145
6146     switch (last_error)
6147     {
6148       case ERROR_FILE_NOT_FOUND:
6149         hr = STG_E_FILENOTFOUND;
6150         break;
6151
6152       case ERROR_PATH_NOT_FOUND:
6153         hr = STG_E_PATHNOTFOUND;
6154         break;
6155
6156       case ERROR_ACCESS_DENIED:
6157       case ERROR_WRITE_PROTECT:
6158         hr = STG_E_ACCESSDENIED;
6159         break;
6160
6161       case ERROR_SHARING_VIOLATION:
6162         hr = STG_E_SHAREVIOLATION;
6163         break;
6164
6165       default:
6166         hr = E_FAIL;
6167     }
6168
6169     goto end;
6170   }
6171
6172   /*
6173    * Refuse to open the file if it's too small to be a structured storage file
6174    * FIXME: verify the file when reading instead of here
6175    */
6176   if (GetFileSize(hFile, NULL) < 0x100)
6177   {
6178     CloseHandle(hFile);
6179     hr = STG_E_FILEALREADYEXISTS;
6180     goto end;
6181   }
6182
6183   /*
6184    * Allocate and initialize the new IStorage32object.
6185    */
6186   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6187
6188   if (newStorage == 0)
6189   {
6190     hr = STG_E_INSUFFICIENTMEMORY;
6191     goto end;
6192   }
6193
6194   /* Initialize the storage */
6195   hr = StorageImpl_Construct(
6196          newStorage,
6197          hFile,
6198          pwcsName,
6199          NULL,
6200          grfMode,
6201          TRUE,
6202          FALSE );
6203
6204   if (FAILED(hr))
6205   {
6206     HeapFree(GetProcessHeap(), 0, newStorage);
6207     /*
6208      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
6209      */
6210     if(hr == STG_E_INVALIDHEADER)
6211         hr = STG_E_FILEALREADYEXISTS;
6212     goto end;
6213   }
6214
6215   /* prepare the file name string given in lieu of the root property name */
6216   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
6217   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
6218   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
6219
6220   /*
6221    * Get an "out" pointer for the caller.
6222    */
6223   hr = StorageBaseImpl_QueryInterface(
6224          (IStorage*)newStorage,
6225          &IID_IStorage,
6226          (void**)ppstgOpen);
6227
6228 end:
6229   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
6230   return hr;
6231 }
6232
6233 /******************************************************************************
6234  *    StgCreateDocfileOnILockBytes    [OLE32.@]
6235  */
6236 HRESULT WINAPI StgCreateDocfileOnILockBytes(
6237       ILockBytes *plkbyt,
6238       DWORD grfMode,
6239       DWORD reserved,
6240       IStorage** ppstgOpen)
6241 {
6242   StorageImpl*   newStorage = 0;
6243   HRESULT        hr         = S_OK;
6244
6245   /*
6246    * Validate the parameters
6247    */
6248   if ((ppstgOpen == 0) || (plkbyt == 0))
6249     return STG_E_INVALIDPOINTER;
6250
6251   /*
6252    * Allocate and initialize the new IStorage object.
6253    */
6254   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6255
6256   if (newStorage == 0)
6257     return STG_E_INSUFFICIENTMEMORY;
6258
6259   hr = StorageImpl_Construct(
6260          newStorage,
6261          0,
6262         0,
6263          plkbyt,
6264          grfMode,
6265          FALSE,
6266          TRUE);
6267
6268   if (FAILED(hr))
6269   {
6270     HeapFree(GetProcessHeap(), 0, newStorage);
6271     return hr;
6272   }
6273
6274   /*
6275    * Get an "out" pointer for the caller.
6276    */
6277   hr = StorageBaseImpl_QueryInterface(
6278          (IStorage*)newStorage,
6279          &IID_IStorage,
6280          (void**)ppstgOpen);
6281
6282   return hr;
6283 }
6284
6285 /******************************************************************************
6286  *    StgOpenStorageOnILockBytes    [OLE32.@]
6287  */
6288 HRESULT WINAPI StgOpenStorageOnILockBytes(
6289       ILockBytes *plkbyt,
6290       IStorage *pstgPriority,
6291       DWORD grfMode,
6292       SNB snbExclude,
6293       DWORD reserved,
6294       IStorage **ppstgOpen)
6295 {
6296   StorageImpl* newStorage = 0;
6297   HRESULT        hr = S_OK;
6298
6299   /*
6300    * Perform a sanity check
6301    */
6302   if ((plkbyt == 0) || (ppstgOpen == 0))
6303     return STG_E_INVALIDPOINTER;
6304
6305   /*
6306    * Validate the STGM flags
6307    */
6308   if ( FAILED( validateSTGM(grfMode) ))
6309     return STG_E_INVALIDFLAG;
6310
6311   /*
6312    * Initialize the "out" parameter.
6313    */
6314   *ppstgOpen = 0;
6315
6316   /*
6317    * Allocate and initialize the new IStorage object.
6318    */
6319   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6320
6321   if (newStorage == 0)
6322     return STG_E_INSUFFICIENTMEMORY;
6323
6324   hr = StorageImpl_Construct(
6325          newStorage,
6326          0,
6327          0,
6328          plkbyt,
6329          grfMode,
6330          FALSE,
6331          FALSE);
6332
6333   if (FAILED(hr))
6334   {
6335     HeapFree(GetProcessHeap(), 0, newStorage);
6336     return hr;
6337   }
6338
6339   /*
6340    * Get an "out" pointer for the caller.
6341    */
6342   hr = StorageBaseImpl_QueryInterface(
6343          (IStorage*)newStorage,
6344          &IID_IStorage,
6345          (void**)ppstgOpen);
6346
6347   return hr;
6348 }
6349
6350 /******************************************************************************
6351  *              StgSetTimes [ole32.@]
6352  *              StgSetTimes [OLE32.@]
6353  *
6354  *
6355  */
6356 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6357                            FILETIME const *patime, FILETIME const *pmtime)
6358 {
6359   IStorage *stg = NULL;
6360   HRESULT r;
6361  
6362   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6363
6364   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6365                      0, 0, &stg);
6366   if( SUCCEEDED(r) )
6367   {
6368     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6369     IStorage_Release(stg);
6370   }
6371
6372   return r;
6373 }
6374
6375 /******************************************************************************
6376  *              StgIsStorageILockBytes        [OLE32.@]
6377  *
6378  * Determines if the ILockBytes contains a storage object.
6379  */
6380 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6381 {
6382   BYTE sig[8];
6383   ULARGE_INTEGER offset;
6384
6385   offset.u.HighPart = 0;
6386   offset.u.LowPart  = 0;
6387
6388   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6389
6390   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6391     return S_OK;
6392
6393   return S_FALSE;
6394 }
6395
6396 /******************************************************************************
6397  *              WriteClassStg        [OLE32.@]
6398  *
6399  * This method will store the specified CLSID in the specified storage object
6400  */
6401 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6402 {
6403   HRESULT hRes;
6404
6405   if(!pStg)
6406     return E_INVALIDARG;
6407
6408   if(!rclsid)
6409     return STG_E_INVALIDPOINTER;
6410
6411   hRes = IStorage_SetClass(pStg, rclsid);
6412
6413   return hRes;
6414 }
6415
6416 /***********************************************************************
6417  *    ReadClassStg (OLE32.@)
6418  *
6419  * This method reads the CLSID previously written to a storage object with
6420  * the WriteClassStg.
6421  *
6422  * PARAMS
6423  *  pstg    [I] IStorage pointer
6424  *  pclsid  [O] Pointer to where the CLSID is written
6425  *
6426  * RETURNS
6427  *  Success: S_OK.
6428  *  Failure: HRESULT code.
6429  */
6430 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6431
6432     STATSTG pstatstg;
6433     HRESULT hRes;
6434
6435     TRACE("(%p, %p)\n", pstg, pclsid);
6436
6437     if(!pstg || !pclsid)
6438         return E_INVALIDARG;
6439
6440    /*
6441     * read a STATSTG structure (contains the clsid) from the storage
6442     */
6443     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_NONAME);
6444
6445     if(SUCCEEDED(hRes))
6446         *pclsid=pstatstg.clsid;
6447
6448     return hRes;
6449 }
6450
6451 /***********************************************************************
6452  *    OleLoadFromStream (OLE32.@)
6453  *
6454  * This function loads an object from stream
6455  */
6456 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6457 {
6458     CLSID       clsid;
6459     HRESULT     res;
6460     LPPERSISTSTREAM     xstm;
6461
6462     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6463
6464     res=ReadClassStm(pStm,&clsid);
6465     if (FAILED(res))
6466         return res;
6467     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6468     if (FAILED(res))
6469         return res;
6470     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6471     if (FAILED(res)) {
6472         IUnknown_Release((IUnknown*)*ppvObj);
6473         return res;
6474     }
6475     res=IPersistStream_Load(xstm,pStm);
6476     IPersistStream_Release(xstm);
6477     /* FIXME: all refcounts ok at this point? I think they should be:
6478      *          pStm    : unchanged
6479      *          ppvObj  : 1
6480      *          xstm    : 0 (released)
6481      */
6482     return res;
6483 }
6484
6485 /***********************************************************************
6486  *    OleSaveToStream (OLE32.@)
6487  *
6488  * This function saves an object with the IPersistStream interface on it
6489  * to the specified stream.
6490  */
6491 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6492 {
6493
6494     CLSID clsid;
6495     HRESULT res;
6496
6497     TRACE("(%p,%p)\n",pPStm,pStm);
6498
6499     res=IPersistStream_GetClassID(pPStm,&clsid);
6500
6501     if (SUCCEEDED(res)){
6502
6503         res=WriteClassStm(pStm,&clsid);
6504
6505         if (SUCCEEDED(res))
6506
6507             res=IPersistStream_Save(pPStm,pStm,TRUE);
6508     }
6509
6510     TRACE("Finished Save\n");
6511     return res;
6512 }
6513
6514 /****************************************************************************
6515  * This method validate a STGM parameter that can contain the values below
6516  *
6517  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6518  * The stgm values contained in 0xffff0000 are bitmasks.
6519  *
6520  * STGM_DIRECT               0x00000000
6521  * STGM_TRANSACTED           0x00010000
6522  * STGM_SIMPLE               0x08000000
6523  *
6524  * STGM_READ                 0x00000000
6525  * STGM_WRITE                0x00000001
6526  * STGM_READWRITE            0x00000002
6527  *
6528  * STGM_SHARE_DENY_NONE      0x00000040
6529  * STGM_SHARE_DENY_READ      0x00000030
6530  * STGM_SHARE_DENY_WRITE     0x00000020
6531  * STGM_SHARE_EXCLUSIVE      0x00000010
6532  *
6533  * STGM_PRIORITY             0x00040000
6534  * STGM_DELETEONRELEASE      0x04000000
6535  *
6536  * STGM_CREATE               0x00001000
6537  * STGM_CONVERT              0x00020000
6538  * STGM_FAILIFTHERE          0x00000000
6539  *
6540  * STGM_NOSCRATCH            0x00100000
6541  * STGM_NOSNAPSHOT           0x00200000
6542  */
6543 static HRESULT validateSTGM(DWORD stgm)
6544 {
6545   DWORD access = STGM_ACCESS_MODE(stgm);
6546   DWORD share  = STGM_SHARE_MODE(stgm);
6547   DWORD create = STGM_CREATE_MODE(stgm);
6548
6549   if (stgm&~STGM_KNOWN_FLAGS)
6550   {
6551     ERR("unknown flags %08x\n", stgm);
6552     return E_FAIL;
6553   }
6554
6555   switch (access)
6556   {
6557   case STGM_READ:
6558   case STGM_WRITE:
6559   case STGM_READWRITE:
6560     break;
6561   default:
6562     return E_FAIL;
6563   }
6564
6565   switch (share)
6566   {
6567   case STGM_SHARE_DENY_NONE:
6568   case STGM_SHARE_DENY_READ:
6569   case STGM_SHARE_DENY_WRITE:
6570   case STGM_SHARE_EXCLUSIVE:
6571     break;
6572   default:
6573     return E_FAIL;
6574   }
6575
6576   switch (create)
6577   {
6578   case STGM_CREATE:
6579   case STGM_FAILIFTHERE:
6580     break;
6581   default:
6582     return E_FAIL;
6583   }
6584
6585   /*
6586    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6587    */
6588   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6589       return E_FAIL;
6590
6591   /*
6592    * STGM_CREATE | STGM_CONVERT
6593    * if both are false, STGM_FAILIFTHERE is set to TRUE
6594    */
6595   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6596     return E_FAIL;
6597
6598   /*
6599    * STGM_NOSCRATCH requires STGM_TRANSACTED
6600    */
6601   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6602     return E_FAIL;
6603
6604   /*
6605    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6606    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6607    */
6608   if ( (stgm & STGM_NOSNAPSHOT) &&
6609         (!(stgm & STGM_TRANSACTED) ||
6610          share == STGM_SHARE_EXCLUSIVE ||
6611          share == STGM_SHARE_DENY_WRITE) )
6612     return E_FAIL;
6613
6614   return S_OK;
6615 }
6616
6617 /****************************************************************************
6618  *      GetShareModeFromSTGM
6619  *
6620  * This method will return a share mode flag from a STGM value.
6621  * The STGM value is assumed valid.
6622  */
6623 static DWORD GetShareModeFromSTGM(DWORD stgm)
6624 {
6625   switch (STGM_SHARE_MODE(stgm))
6626   {
6627   case STGM_SHARE_DENY_NONE:
6628     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6629   case STGM_SHARE_DENY_READ:
6630     return FILE_SHARE_WRITE;
6631   case STGM_SHARE_DENY_WRITE:
6632     return FILE_SHARE_READ;
6633   case STGM_SHARE_EXCLUSIVE:
6634     return 0;
6635   }
6636   ERR("Invalid share mode!\n");
6637   assert(0);
6638   return 0;
6639 }
6640
6641 /****************************************************************************
6642  *      GetAccessModeFromSTGM
6643  *
6644  * This method will return an access mode flag from a STGM value.
6645  * The STGM value is assumed valid.
6646  */
6647 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6648 {
6649   switch (STGM_ACCESS_MODE(stgm))
6650   {
6651   case STGM_READ:
6652     return GENERIC_READ;
6653   case STGM_WRITE:
6654   case STGM_READWRITE:
6655     return GENERIC_READ | GENERIC_WRITE;
6656   }
6657   ERR("Invalid access mode!\n");
6658   assert(0);
6659   return 0;
6660 }
6661
6662 /****************************************************************************
6663  *      GetCreationModeFromSTGM
6664  *
6665  * This method will return a creation mode flag from a STGM value.
6666  * The STGM value is assumed valid.
6667  */
6668 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6669 {
6670   switch(STGM_CREATE_MODE(stgm))
6671   {
6672   case STGM_CREATE:
6673     return CREATE_ALWAYS;
6674   case STGM_CONVERT:
6675     FIXME("STGM_CONVERT not implemented!\n");
6676     return CREATE_NEW;
6677   case STGM_FAILIFTHERE:
6678     return CREATE_NEW;
6679   }
6680   ERR("Invalid create mode!\n");
6681   assert(0);
6682   return 0;
6683 }
6684
6685
6686 /*************************************************************************
6687  * OLECONVERT_LoadOLE10 [Internal]
6688  *
6689  * Loads the OLE10 STREAM to memory
6690  *
6691  * PARAMS
6692  *     pOleStream   [I] The OLESTREAM
6693  *     pData        [I] Data Structure for the OLESTREAM Data
6694  *
6695  * RETURNS
6696  *     Success:  S_OK
6697  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6698  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalid
6699  *
6700  * NOTES
6701  *     This function is used by OleConvertOLESTREAMToIStorage only.
6702  *
6703  *     Memory allocated for pData must be freed by the caller
6704  */
6705 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6706 {
6707         DWORD dwSize;
6708         HRESULT hRes = S_OK;
6709         int nTryCnt=0;
6710         int max_try = 6;
6711
6712         pData->pData = NULL;
6713         pData->pstrOleObjFileName = NULL;
6714
6715         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6716         {
6717         /* Get the OleID */
6718         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6719         if(dwSize != sizeof(pData->dwOleID))
6720         {
6721                 hRes = CONVERT10_E_OLESTREAM_GET;
6722         }
6723         else if(pData->dwOleID != OLESTREAM_ID)
6724         {
6725                 hRes = CONVERT10_E_OLESTREAM_FMT;
6726         }
6727                 else
6728                 {
6729                         hRes = S_OK;
6730                         break;
6731                 }
6732         }
6733
6734         if(hRes == S_OK)
6735         {
6736                 /* Get the TypeID... more info needed for this field */
6737                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6738                 if(dwSize != sizeof(pData->dwTypeID))
6739                 {
6740                         hRes = CONVERT10_E_OLESTREAM_GET;
6741                 }
6742         }
6743         if(hRes == S_OK)
6744         {
6745                 if(pData->dwTypeID != 0)
6746                 {
6747                         /* Get the length of the OleTypeName */
6748                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6749                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6750                         {
6751                                 hRes = CONVERT10_E_OLESTREAM_GET;
6752                         }
6753
6754                         if(hRes == S_OK)
6755                         {
6756                                 if(pData->dwOleTypeNameLength > 0)
6757                                 {
6758                                         /* Get the OleTypeName */
6759                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
6760                                         if(dwSize != pData->dwOleTypeNameLength)
6761                                         {
6762                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6763                                         }
6764                                 }
6765                         }
6766                         if(bStrem1)
6767                         {
6768                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6769                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6770                                 {
6771                                         hRes = CONVERT10_E_OLESTREAM_GET;
6772                                 }
6773                         if(hRes == S_OK)
6774                         {
6775                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6776                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6777                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6778                                         if(pData->pstrOleObjFileName)
6779                                         {
6780                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->pstrOleObjFileName, pData->dwOleObjFileNameLength);
6781                                                 if(dwSize != pData->dwOleObjFileNameLength)
6782                                                 {
6783                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6784                                                 }
6785                                         }
6786                                         else
6787                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6788                                 }
6789                         }
6790                         else
6791                         {
6792                                 /* Get the Width of the Metafile */
6793                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6794                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6795                                 {
6796                                         hRes = CONVERT10_E_OLESTREAM_GET;
6797                                 }
6798                         if(hRes == S_OK)
6799                         {
6800                                 /* Get the Height of the Metafile */
6801                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6802                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6803                                 {
6804                                         hRes = CONVERT10_E_OLESTREAM_GET;
6805                                 }
6806                         }
6807                         }
6808                         if(hRes == S_OK)
6809                         {
6810                                 /* Get the Length of the Data */
6811                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6812                                 if(dwSize != sizeof(pData->dwDataLength))
6813                                 {
6814                                         hRes = CONVERT10_E_OLESTREAM_GET;
6815                                 }
6816                         }
6817
6818                         if(hRes == S_OK) /* I don't know what this 8 byte information is. We have to figure out */
6819                         {
6820                                 if(!bStrem1) /* if it is a second OLE stream data */
6821                                 {
6822                                         pData->dwDataLength -= 8;
6823                                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strUnknown, sizeof(pData->strUnknown));
6824                                         if(dwSize != sizeof(pData->strUnknown))
6825                                         {
6826                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6827                                         }
6828                                 }
6829                         }
6830                         if(hRes == S_OK)
6831                         {
6832                                 if(pData->dwDataLength > 0)
6833                                 {
6834                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6835
6836                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6837                                         if(pData->pData)
6838                                         {
6839                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6840                                                 if(dwSize != pData->dwDataLength)
6841                                                 {
6842                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6843                                                 }
6844                                         }
6845                                         else
6846                                         {
6847                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6848                                         }
6849                                 }
6850                         }
6851                 }
6852         }
6853         return hRes;
6854 }
6855
6856 /*************************************************************************
6857  * OLECONVERT_SaveOLE10 [Internal]
6858  *
6859  * Saves the OLE10 STREAM From memory
6860  *
6861  * PARAMS
6862  *     pData        [I] Data Structure for the OLESTREAM Data
6863  *     pOleStream   [I] The OLESTREAM to save
6864  *
6865  * RETURNS
6866  *     Success:  S_OK
6867  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6868  *
6869  * NOTES
6870  *     This function is used by OleConvertIStorageToOLESTREAM only.
6871  *
6872  */
6873 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6874 {
6875     DWORD dwSize;
6876     HRESULT hRes = S_OK;
6877
6878
6879    /* Set the OleID */
6880     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6881     if(dwSize != sizeof(pData->dwOleID))
6882     {
6883         hRes = CONVERT10_E_OLESTREAM_PUT;
6884     }
6885
6886     if(hRes == S_OK)
6887     {
6888         /* Set the TypeID */
6889         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6890         if(dwSize != sizeof(pData->dwTypeID))
6891         {
6892             hRes = CONVERT10_E_OLESTREAM_PUT;
6893         }
6894     }
6895
6896     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6897     {
6898         /* Set the Length of the OleTypeName */
6899         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6900         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6901         {
6902             hRes = CONVERT10_E_OLESTREAM_PUT;
6903         }
6904
6905         if(hRes == S_OK)
6906         {
6907             if(pData->dwOleTypeNameLength > 0)
6908             {
6909                 /* Set the OleTypeName */
6910                 dwSize = pOleStream->lpstbl->Put(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
6911                 if(dwSize != pData->dwOleTypeNameLength)
6912                 {
6913                     hRes = CONVERT10_E_OLESTREAM_PUT;
6914                 }
6915             }
6916         }
6917
6918         if(hRes == S_OK)
6919         {
6920             /* Set the width of the Metafile */
6921             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6922             if(dwSize != sizeof(pData->dwMetaFileWidth))
6923             {
6924                 hRes = CONVERT10_E_OLESTREAM_PUT;
6925             }
6926         }
6927
6928         if(hRes == S_OK)
6929         {
6930             /* Set the height of the Metafile */
6931             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6932             if(dwSize != sizeof(pData->dwMetaFileHeight))
6933             {
6934                 hRes = CONVERT10_E_OLESTREAM_PUT;
6935             }
6936         }
6937
6938         if(hRes == S_OK)
6939         {
6940             /* Set the length of the Data */
6941             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6942             if(dwSize != sizeof(pData->dwDataLength))
6943             {
6944                 hRes = CONVERT10_E_OLESTREAM_PUT;
6945             }
6946         }
6947
6948         if(hRes == S_OK)
6949         {
6950             if(pData->dwDataLength > 0)
6951             {
6952                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6953                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6954                 if(dwSize != pData->dwDataLength)
6955                 {
6956                     hRes = CONVERT10_E_OLESTREAM_PUT;
6957                 }
6958             }
6959         }
6960     }
6961     return hRes;
6962 }
6963
6964 /*************************************************************************
6965  * OLECONVERT_GetOLE20FromOLE10[Internal]
6966  *
6967  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6968  * opens it, and copies the content to the dest IStorage for
6969  * OleConvertOLESTREAMToIStorage
6970  *
6971  *
6972  * PARAMS
6973  *     pDestStorage  [I] The IStorage to copy the data to
6974  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6975  *     nBufferLength [I] The size of the buffer
6976  *
6977  * RETURNS
6978  *     Nothing
6979  *
6980  * NOTES
6981  *
6982  *
6983  */
6984 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
6985 {
6986     HRESULT hRes;
6987     HANDLE hFile;
6988     IStorage *pTempStorage;
6989     DWORD dwNumOfBytesWritten;
6990     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6991     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6992
6993     /* Create a temp File */
6994     GetTempPathW(MAX_PATH, wstrTempDir);
6995     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6996     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6997
6998     if(hFile != INVALID_HANDLE_VALUE)
6999     {
7000         /* Write IStorage Data to File */
7001         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
7002         CloseHandle(hFile);
7003
7004         /* Open and copy temp storage to the Dest Storage */
7005         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
7006         if(hRes == S_OK)
7007         {
7008             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
7009             StorageBaseImpl_Release(pTempStorage);
7010         }
7011         DeleteFileW(wstrTempFile);
7012     }
7013 }
7014
7015
7016 /*************************************************************************
7017  * OLECONVERT_WriteOLE20ToBuffer [Internal]
7018  *
7019  * Saves the OLE10 STREAM From memory
7020  *
7021  * PARAMS
7022  *     pStorage  [I] The Src IStorage to copy
7023  *     pData     [I] The Dest Memory to write to.
7024  *
7025  * RETURNS
7026  *     The size in bytes allocated for pData
7027  *
7028  * NOTES
7029  *     Memory allocated for pData must be freed by the caller
7030  *
7031  *     Used by OleConvertIStorageToOLESTREAM only.
7032  *
7033  */
7034 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
7035 {
7036     HANDLE hFile;
7037     HRESULT hRes;
7038     DWORD nDataLength = 0;
7039     IStorage *pTempStorage;
7040     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
7041     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
7042
7043     *pData = NULL;
7044
7045     /* Create temp Storage */
7046     GetTempPathW(MAX_PATH, wstrTempDir);
7047     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
7048     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
7049
7050     if(hRes == S_OK)
7051     {
7052         /* Copy Src Storage to the Temp Storage */
7053         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
7054         StorageBaseImpl_Release(pTempStorage);
7055
7056         /* Open Temp Storage as a file and copy to memory */
7057         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7058         if(hFile != INVALID_HANDLE_VALUE)
7059         {
7060             nDataLength = GetFileSize(hFile, NULL);
7061             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
7062             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
7063             CloseHandle(hFile);
7064         }
7065         DeleteFileW(wstrTempFile);
7066     }
7067     return nDataLength;
7068 }
7069
7070 /*************************************************************************
7071  * OLECONVERT_CreateOleStream [Internal]
7072  *
7073  * Creates the "\001OLE" stream in the IStorage if necessary.
7074  *
7075  * PARAMS
7076  *     pStorage     [I] Dest storage to create the stream in
7077  *
7078  * RETURNS
7079  *     Nothing
7080  *
7081  * NOTES
7082  *     This function is used by OleConvertOLESTREAMToIStorage only.
7083  *
7084  *     This stream is still unknown, MS Word seems to have extra data
7085  *     but since the data is stored in the OLESTREAM there should be
7086  *     no need to recreate the stream.  If the stream is manually
7087  *     deleted it will create it with this default data.
7088  *
7089  */
7090 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
7091 {
7092     HRESULT hRes;
7093     IStream *pStream;
7094     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
7095     BYTE pOleStreamHeader [] =
7096     {
7097         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
7098         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7099         0x00, 0x00, 0x00, 0x00
7100     };
7101
7102     /* Create stream if not present */
7103     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7104         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7105
7106     if(hRes == S_OK)
7107     {
7108         /* Write default Data */
7109         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
7110         IStream_Release(pStream);
7111     }
7112 }
7113
7114 /* write a string to a stream, preceded by its length */
7115 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
7116 {
7117     HRESULT r;
7118     LPSTR str;
7119     DWORD len = 0;
7120
7121     if( string )
7122         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
7123     r = IStream_Write( stm, &len, sizeof(len), NULL);
7124     if( FAILED( r ) )
7125         return r;
7126     if(len == 0)
7127         return r;
7128     str = CoTaskMemAlloc( len );
7129     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
7130     r = IStream_Write( stm, str, len, NULL);
7131     CoTaskMemFree( str );
7132     return r;
7133 }
7134
7135 /* read a string preceded by its length from a stream */
7136 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
7137 {
7138     HRESULT r;
7139     DWORD len, count = 0;
7140     LPSTR str;
7141     LPWSTR wstr;
7142
7143     r = IStream_Read( stm, &len, sizeof(len), &count );
7144     if( FAILED( r ) )
7145         return r;
7146     if( count != sizeof(len) )
7147         return E_OUTOFMEMORY;
7148
7149     TRACE("%d bytes\n",len);
7150     
7151     str = CoTaskMemAlloc( len );
7152     if( !str )
7153         return E_OUTOFMEMORY;
7154     count = 0;
7155     r = IStream_Read( stm, str, len, &count );
7156     if( FAILED( r ) )
7157         return r;
7158     if( count != len )
7159     {
7160         CoTaskMemFree( str );
7161         return E_OUTOFMEMORY;
7162     }
7163
7164     TRACE("Read string %s\n",debugstr_an(str,len));
7165
7166     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
7167     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
7168     if( wstr )
7169          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
7170     CoTaskMemFree( str );
7171
7172     *string = wstr;
7173
7174     return r;
7175 }
7176
7177
7178 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
7179     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
7180 {
7181     IStream *pstm;
7182     HRESULT r = S_OK;
7183     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7184
7185     static const BYTE unknown1[12] =
7186        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
7187          0xFF, 0xFF, 0xFF, 0xFF};
7188     static const BYTE unknown2[16] =
7189        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
7190          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
7191
7192     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
7193            debugstr_w(lpszUserType), debugstr_w(szClipName),
7194            debugstr_w(szProgIDName));
7195
7196     /*  Create a CompObj stream */
7197     r = IStorage_CreateStream(pstg, szwStreamName,
7198         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
7199     if( FAILED (r) )
7200         return r;
7201
7202     /* Write CompObj Structure to stream */
7203     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
7204
7205     if( SUCCEEDED( r ) )
7206         r = WriteClassStm( pstm, clsid );
7207
7208     if( SUCCEEDED( r ) )
7209         r = STREAM_WriteString( pstm, lpszUserType );
7210     if( SUCCEEDED( r ) )
7211         r = STREAM_WriteString( pstm, szClipName );
7212     if( SUCCEEDED( r ) )
7213         r = STREAM_WriteString( pstm, szProgIDName );
7214     if( SUCCEEDED( r ) )
7215         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
7216
7217     IStream_Release( pstm );
7218
7219     return r;
7220 }
7221
7222 /***********************************************************************
7223  *               WriteFmtUserTypeStg (OLE32.@)
7224  */
7225 HRESULT WINAPI WriteFmtUserTypeStg(
7226           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
7227 {
7228     HRESULT r;
7229     WCHAR szwClipName[0x40];
7230     CLSID clsid = CLSID_NULL;
7231     LPWSTR wstrProgID = NULL;
7232     DWORD n;
7233
7234     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
7235
7236     /* get the clipboard format name */
7237     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName)/sizeof(szwClipName[0]) );
7238     szwClipName[n]=0;
7239
7240     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
7241
7242     /* FIXME: There's room to save a CLSID and its ProgID, but
7243        the CLSID is not looked up in the registry and in all the
7244        tests I wrote it was CLSID_NULL.  Where does it come from?
7245     */
7246
7247     /* get the real program ID.  This may fail, but that's fine */
7248     ProgIDFromCLSID(&clsid, &wstrProgID);
7249
7250     TRACE("progid is %s\n",debugstr_w(wstrProgID));
7251
7252     r = STORAGE_WriteCompObj( pstg, &clsid, 
7253                               lpszUserType, szwClipName, wstrProgID );
7254
7255     CoTaskMemFree(wstrProgID);
7256
7257     return r;
7258 }
7259
7260
7261 /******************************************************************************
7262  *              ReadFmtUserTypeStg        [OLE32.@]
7263  */
7264 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
7265 {
7266     HRESULT r;
7267     IStream *stm = 0;
7268     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
7269     unsigned char unknown1[12];
7270     unsigned char unknown2[16];
7271     DWORD count;
7272     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
7273     CLSID clsid;
7274
7275     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
7276
7277     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
7278                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
7279     if( FAILED ( r ) )
7280     {
7281         WARN("Failed to open stream r = %08x\n", r);
7282         return r;
7283     }
7284
7285     /* read the various parts of the structure */
7286     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
7287     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
7288         goto end;
7289     r = ReadClassStm( stm, &clsid );
7290     if( FAILED( r ) )
7291         goto end;
7292
7293     r = STREAM_ReadString( stm, &szCLSIDName );
7294     if( FAILED( r ) )
7295         goto end;
7296
7297     r = STREAM_ReadString( stm, &szOleTypeName );
7298     if( FAILED( r ) )
7299         goto end;
7300
7301     r = STREAM_ReadString( stm, &szProgIDName );
7302     if( FAILED( r ) )
7303         goto end;
7304
7305     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7306     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7307         goto end;
7308
7309     /* ok, success... now we just need to store what we found */
7310     if( pcf )
7311         *pcf = RegisterClipboardFormatW( szOleTypeName );
7312     CoTaskMemFree( szOleTypeName );
7313
7314     if( lplpszUserType )
7315         *lplpszUserType = szCLSIDName;
7316     CoTaskMemFree( szProgIDName );
7317
7318 end:
7319     IStream_Release( stm );
7320
7321     return r;
7322 }
7323
7324
7325 /*************************************************************************
7326  * OLECONVERT_CreateCompObjStream [Internal]
7327  *
7328  * Creates a "\001CompObj" is the destination IStorage if necessary.
7329  *
7330  * PARAMS
7331  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7332  *                        if necessary.
7333  *     strOleTypeName [I] The ProgID
7334  *
7335  * RETURNS
7336  *     Success:  S_OK
7337  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7338  *
7339  * NOTES
7340  *     This function is used by OleConvertOLESTREAMToIStorage only.
7341  *
7342  *     The stream data is stored in the OLESTREAM and there should be
7343  *     no need to recreate the stream.  If the stream is manually
7344  *     deleted it will attempt to create it by querying the registry.
7345  *
7346  *
7347  */
7348 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7349 {
7350     IStream *pStream;
7351     HRESULT hStorageRes, hRes = S_OK;
7352     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7353     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7354     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7355
7356     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7357     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7358
7359     /* Initialize the CompObj structure */
7360     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7361     memcpy(IStorageCompObj.byUnknown1, pCompObjUnknown1, sizeof(pCompObjUnknown1));
7362     memcpy(IStorageCompObj.byUnknown2, pCompObjUnknown2, sizeof(pCompObjUnknown2));
7363
7364
7365     /*  Create a CompObj stream if it doesn't exist */
7366     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7367         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7368     if(hStorageRes == S_OK)
7369     {
7370         /* copy the OleTypeName to the compobj struct */
7371         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7372         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7373
7374         /* copy the OleTypeName to the compobj struct */
7375         /* Note: in the test made, these were Identical      */
7376         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7377         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7378
7379         /* Get the CLSID */
7380         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7381                              bufferW, OLESTREAM_MAX_STR_LEN );
7382         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7383
7384         if(hRes == S_OK)
7385         {
7386             HKEY hKey;
7387             LONG hErr;
7388             /* Get the CLSID Default Name from the Registry */
7389             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7390             if(hErr == ERROR_SUCCESS)
7391             {
7392                 char strTemp[OLESTREAM_MAX_STR_LEN];
7393                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7394                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7395                 if(hErr == ERROR_SUCCESS)
7396                 {
7397                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7398                 }
7399                 RegCloseKey(hKey);
7400             }
7401         }
7402
7403         /* Write CompObj Structure to stream */
7404         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7405
7406         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7407
7408         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7409         if(IStorageCompObj.dwCLSIDNameLength > 0)
7410         {
7411             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7412         }
7413         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7414         if(IStorageCompObj.dwOleTypeNameLength > 0)
7415         {
7416             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7417         }
7418         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7419         if(IStorageCompObj.dwProgIDNameLength > 0)
7420         {
7421             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7422         }
7423         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7424         IStream_Release(pStream);
7425     }
7426     return hRes;
7427 }
7428
7429
7430 /*************************************************************************
7431  * OLECONVERT_CreateOlePresStream[Internal]
7432  *
7433  * Creates the "\002OlePres000" Stream with the Metafile data
7434  *
7435  * PARAMS
7436  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7437  *     dwExtentX    [I] Width of the Metafile
7438  *     dwExtentY    [I] Height of the Metafile
7439  *     pData        [I] Metafile data
7440  *     dwDataLength [I] Size of the Metafile data
7441  *
7442  * RETURNS
7443  *     Success:  S_OK
7444  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7445  *
7446  * NOTES
7447  *     This function is used by OleConvertOLESTREAMToIStorage only.
7448  *
7449  */
7450 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7451 {
7452     HRESULT hRes;
7453     IStream *pStream;
7454     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7455     BYTE pOlePresStreamHeader [] =
7456     {
7457         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7458         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7459         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7460         0x00, 0x00, 0x00, 0x00
7461     };
7462
7463     BYTE pOlePresStreamHeaderEmpty [] =
7464     {
7465         0x00, 0x00, 0x00, 0x00,
7466         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7467         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7468         0x00, 0x00, 0x00, 0x00
7469     };
7470
7471     /* Create the OlePres000 Stream */
7472     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7473         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7474
7475     if(hRes == S_OK)
7476     {
7477         DWORD nHeaderSize;
7478         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7479
7480         memset(&OlePres, 0, sizeof(OlePres));
7481         /* Do we have any metafile data to save */
7482         if(dwDataLength > 0)
7483         {
7484             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7485             nHeaderSize = sizeof(pOlePresStreamHeader);
7486         }
7487         else
7488         {
7489             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7490             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7491         }
7492         /* Set width and height of the metafile */
7493         OlePres.dwExtentX = dwExtentX;
7494         OlePres.dwExtentY = -dwExtentY;
7495
7496         /* Set Data and Length */
7497         if(dwDataLength > sizeof(METAFILEPICT16))
7498         {
7499             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7500             OlePres.pData = &(pData[8]);
7501         }
7502         /* Save OlePres000 Data to Stream */
7503         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7504         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7505         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7506         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7507         if(OlePres.dwSize > 0)
7508         {
7509             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7510         }
7511         IStream_Release(pStream);
7512     }
7513 }
7514
7515 /*************************************************************************
7516  * OLECONVERT_CreateOle10NativeStream [Internal]
7517  *
7518  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7519  *
7520  * PARAMS
7521  *     pStorage     [I] Dest storage to create the stream in
7522  *     pData        [I] Ole10 Native Data (ex. bmp)
7523  *     dwDataLength [I] Size of the Ole10 Native Data
7524  *
7525  * RETURNS
7526  *     Nothing
7527  *
7528  * NOTES
7529  *     This function is used by OleConvertOLESTREAMToIStorage only.
7530  *
7531  *     Might need to verify the data and return appropriate error message
7532  *
7533  */
7534 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
7535 {
7536     HRESULT hRes;
7537     IStream *pStream;
7538     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7539
7540     /* Create the Ole10Native Stream */
7541     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7542         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7543
7544     if(hRes == S_OK)
7545     {
7546         /* Write info to stream */
7547         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7548         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7549         IStream_Release(pStream);
7550     }
7551
7552 }
7553
7554 /*************************************************************************
7555  * OLECONVERT_GetOLE10ProgID [Internal]
7556  *
7557  * Finds the ProgID (or OleTypeID) from the IStorage
7558  *
7559  * PARAMS
7560  *     pStorage        [I] The Src IStorage to get the ProgID
7561  *     strProgID       [I] the ProgID string to get
7562  *     dwSize          [I] the size of the string
7563  *
7564  * RETURNS
7565  *     Success:  S_OK
7566  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7567  *
7568  * NOTES
7569  *     This function is used by OleConvertIStorageToOLESTREAM only.
7570  *
7571  *
7572  */
7573 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7574 {
7575     HRESULT hRes;
7576     IStream *pStream;
7577     LARGE_INTEGER iSeekPos;
7578     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7579     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7580
7581     /* Open the CompObj Stream */
7582     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7583         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7584     if(hRes == S_OK)
7585     {
7586
7587         /*Get the OleType from the CompObj Stream */
7588         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7589         iSeekPos.u.HighPart = 0;
7590
7591         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7592         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7593         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7594         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7595         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7596         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7597         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7598
7599         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7600         if(*dwSize > 0)
7601         {
7602             IStream_Read(pStream, strProgID, *dwSize, NULL);
7603         }
7604         IStream_Release(pStream);
7605     }
7606     else
7607     {
7608         STATSTG stat;
7609         LPOLESTR wstrProgID;
7610
7611         /* Get the OleType from the registry */
7612         REFCLSID clsid = &(stat.clsid);
7613         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7614         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7615         if(hRes == S_OK)
7616         {
7617             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7618         }
7619
7620     }
7621     return hRes;
7622 }
7623
7624 /*************************************************************************
7625  * OLECONVERT_GetOle10PresData [Internal]
7626  *
7627  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7628  *
7629  * PARAMS
7630  *     pStorage     [I] Src IStroage
7631  *     pOleStream   [I] Dest OleStream Mem Struct
7632  *
7633  * RETURNS
7634  *     Nothing
7635  *
7636  * NOTES
7637  *     This function is used by OleConvertIStorageToOLESTREAM only.
7638  *
7639  *     Memory allocated for pData must be freed by the caller
7640  *
7641  *
7642  */
7643 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7644 {
7645
7646     HRESULT hRes;
7647     IStream *pStream;
7648     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7649
7650     /* Initialize Default data for OLESTREAM */
7651     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7652     pOleStreamData[0].dwTypeID = 2;
7653     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7654     pOleStreamData[1].dwTypeID = 0;
7655     pOleStreamData[0].dwMetaFileWidth = 0;
7656     pOleStreamData[0].dwMetaFileHeight = 0;
7657     pOleStreamData[0].pData = NULL;
7658     pOleStreamData[1].pData = NULL;
7659
7660     /* Open Ole10Native Stream */
7661     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7662         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7663     if(hRes == S_OK)
7664     {
7665
7666         /* Read Size and Data */
7667         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7668         if(pOleStreamData->dwDataLength > 0)
7669         {
7670             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7671             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7672         }
7673         IStream_Release(pStream);
7674     }
7675
7676 }
7677
7678
7679 /*************************************************************************
7680  * OLECONVERT_GetOle20PresData[Internal]
7681  *
7682  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7683  *
7684  * PARAMS
7685  *     pStorage         [I] Src IStroage
7686  *     pOleStreamData   [I] Dest OleStream Mem Struct
7687  *
7688  * RETURNS
7689  *     Nothing
7690  *
7691  * NOTES
7692  *     This function is used by OleConvertIStorageToOLESTREAM only.
7693  *
7694  *     Memory allocated for pData must be freed by the caller
7695  */
7696 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7697 {
7698     HRESULT hRes;
7699     IStream *pStream;
7700     OLECONVERT_ISTORAGE_OLEPRES olePress;
7701     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7702
7703     /* Initialize Default data for OLESTREAM */
7704     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7705     pOleStreamData[0].dwTypeID = 2;
7706     pOleStreamData[0].dwMetaFileWidth = 0;
7707     pOleStreamData[0].dwMetaFileHeight = 0;
7708     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7709     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7710     pOleStreamData[1].dwTypeID = 0;
7711     pOleStreamData[1].dwOleTypeNameLength = 0;
7712     pOleStreamData[1].strOleTypeName[0] = 0;
7713     pOleStreamData[1].dwMetaFileWidth = 0;
7714     pOleStreamData[1].dwMetaFileHeight = 0;
7715     pOleStreamData[1].pData = NULL;
7716     pOleStreamData[1].dwDataLength = 0;
7717
7718
7719     /* Open OlePress000 stream */
7720     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7721         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7722     if(hRes == S_OK)
7723     {
7724         LARGE_INTEGER iSeekPos;
7725         METAFILEPICT16 MetaFilePict;
7726         static const char strMetafilePictName[] = "METAFILEPICT";
7727
7728         /* Set the TypeID for a Metafile */
7729         pOleStreamData[1].dwTypeID = 5;
7730
7731         /* Set the OleTypeName to Metafile */
7732         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7733         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7734
7735         iSeekPos.u.HighPart = 0;
7736         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7737
7738         /* Get Presentation Data */
7739         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7740         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7741         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7742         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7743
7744         /*Set width and Height */
7745         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7746         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7747         if(olePress.dwSize > 0)
7748         {
7749             /* Set Length */
7750             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7751
7752             /* Set MetaFilePict struct */
7753             MetaFilePict.mm = 8;
7754             MetaFilePict.xExt = olePress.dwExtentX;
7755             MetaFilePict.yExt = olePress.dwExtentY;
7756             MetaFilePict.hMF = 0;
7757
7758             /* Get Metafile Data */
7759             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7760             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7761             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7762         }
7763         IStream_Release(pStream);
7764     }
7765 }
7766
7767 /*************************************************************************
7768  * OleConvertOLESTREAMToIStorage [OLE32.@]
7769  *
7770  * Read info on MSDN
7771  *
7772  * TODO
7773  *      DVTARGETDEVICE parameter is not handled
7774  *      Still unsure of some mem fields for OLE 10 Stream
7775  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7776  *      and "\001OLE" streams
7777  *
7778  */
7779 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7780     LPOLESTREAM pOleStream,
7781     LPSTORAGE pstg,
7782     const DVTARGETDEVICE* ptd)
7783 {
7784     int i;
7785     HRESULT hRes=S_OK;
7786     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7787
7788     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
7789
7790     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7791
7792     if(ptd != NULL)
7793     {
7794         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7795     }
7796
7797     if(pstg == NULL || pOleStream == NULL)
7798     {
7799         hRes = E_INVALIDARG;
7800     }
7801
7802     if(hRes == S_OK)
7803     {
7804         /* Load the OLESTREAM to Memory */
7805         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7806     }
7807
7808     if(hRes == S_OK)
7809     {
7810         /* Load the OLESTREAM to Memory (part 2)*/
7811         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7812     }
7813
7814     if(hRes == S_OK)
7815     {
7816
7817         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7818         {
7819             /* Do we have the IStorage Data in the OLESTREAM */
7820             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7821             {
7822                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7823                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7824             }
7825             else
7826             {
7827                 /* It must be an original OLE 1.0 source */
7828                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7829             }
7830         }
7831         else
7832         {
7833             /* It must be an original OLE 1.0 source */
7834             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7835         }
7836
7837         /* Create CompObj Stream if necessary */
7838         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7839         if(hRes == S_OK)
7840         {
7841             /*Create the Ole Stream if necessary */
7842             OLECONVERT_CreateOleStream(pstg);
7843         }
7844     }
7845
7846
7847     /* Free allocated memory */
7848     for(i=0; i < 2; i++)
7849     {
7850         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7851         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7852         pOleStreamData[i].pstrOleObjFileName = NULL;
7853     }
7854     return hRes;
7855 }
7856
7857 /*************************************************************************
7858  * OleConvertIStorageToOLESTREAM [OLE32.@]
7859  *
7860  * Read info on MSDN
7861  *
7862  * Read info on MSDN
7863  *
7864  * TODO
7865  *      Still unsure of some mem fields for OLE 10 Stream
7866  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7867  *      and "\001OLE" streams.
7868  *
7869  */
7870 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7871     LPSTORAGE pstg,
7872     LPOLESTREAM pOleStream)
7873 {
7874     int i;
7875     HRESULT hRes = S_OK;
7876     IStream *pStream;
7877     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7878     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7879
7880     TRACE("%p %p\n", pstg, pOleStream);
7881
7882     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7883
7884     if(pstg == NULL || pOleStream == NULL)
7885     {
7886         hRes = E_INVALIDARG;
7887     }
7888     if(hRes == S_OK)
7889     {
7890         /* Get the ProgID */
7891         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7892         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7893     }
7894     if(hRes == S_OK)
7895     {
7896         /* Was it originally Ole10 */
7897         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7898         if(hRes == S_OK)
7899         {
7900             IStream_Release(pStream);
7901             /* Get Presentation Data for Ole10Native */
7902             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7903         }
7904         else
7905         {
7906             /* Get Presentation Data (OLE20) */
7907             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7908         }
7909
7910         /* Save OLESTREAM */
7911         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7912         if(hRes == S_OK)
7913         {
7914             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7915         }
7916
7917     }
7918
7919     /* Free allocated memory */
7920     for(i=0; i < 2; i++)
7921     {
7922         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7923     }
7924
7925     return hRes;
7926 }
7927
7928 /***********************************************************************
7929  *              GetConvertStg (OLE32.@)
7930  */
7931 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7932     FIXME("unimplemented stub!\n");
7933     return E_FAIL;
7934 }
7935
7936 /******************************************************************************
7937  * StgIsStorageFile [OLE32.@]
7938  * Verify if the file contains a storage object
7939  *
7940  * PARAMS
7941  *  fn      [ I] Filename
7942  *
7943  * RETURNS
7944  *  S_OK    if file has magic bytes as a storage object
7945  *  S_FALSE if file is not storage
7946  */
7947 HRESULT WINAPI
7948 StgIsStorageFile(LPCOLESTR fn)
7949 {
7950         HANDLE          hf;
7951         BYTE            magic[8];
7952         DWORD           bytes_read;
7953
7954         TRACE("%s\n", debugstr_w(fn));
7955         hf = CreateFileW(fn, GENERIC_READ,
7956                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7957                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7958
7959         if (hf == INVALID_HANDLE_VALUE)
7960                 return STG_E_FILENOTFOUND;
7961
7962         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7963         {
7964                 WARN(" unable to read file\n");
7965                 CloseHandle(hf);
7966                 return S_FALSE;
7967         }
7968
7969         CloseHandle(hf);
7970
7971         if (bytes_read != 8) {
7972                 WARN(" too short\n");
7973                 return S_FALSE;
7974         }
7975
7976         if (!memcmp(magic,STORAGE_magic,8)) {
7977                 WARN(" -> YES\n");
7978                 return S_OK;
7979         }
7980
7981         WARN(" -> Invalid header.\n");
7982         return S_FALSE;
7983 }
7984
7985 /***********************************************************************
7986  *              WriteClassStm (OLE32.@)
7987  *
7988  * Writes a CLSID to a stream.
7989  *
7990  * PARAMS
7991  *  pStm   [I] Stream to write to.
7992  *  rclsid [I] CLSID to write.
7993  *
7994  * RETURNS
7995  *  Success: S_OK.
7996  *  Failure: HRESULT code.
7997  */
7998 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
7999 {
8000     TRACE("(%p,%p)\n",pStm,rclsid);
8001
8002     if (!pStm || !rclsid)
8003         return E_INVALIDARG;
8004
8005     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
8006 }
8007
8008 /***********************************************************************
8009  *              ReadClassStm (OLE32.@)
8010  *
8011  * Reads a CLSID from a stream.
8012  *
8013  * PARAMS
8014  *  pStm   [I] Stream to read from.
8015  *  rclsid [O] CLSID to read.
8016  *
8017  * RETURNS
8018  *  Success: S_OK.
8019  *  Failure: HRESULT code.
8020  */
8021 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
8022 {
8023     ULONG nbByte;
8024     HRESULT res;
8025
8026     TRACE("(%p,%p)\n",pStm,pclsid);
8027
8028     if (!pStm || !pclsid)
8029         return E_INVALIDARG;
8030
8031     /* clear the output args */
8032     *pclsid = CLSID_NULL;
8033
8034     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
8035
8036     if (FAILED(res))
8037         return res;
8038
8039     if (nbByte != sizeof(CLSID))
8040         return STG_E_READFAULT;
8041     else
8042         return S_OK;
8043 }