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