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