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