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