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