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