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