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