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