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