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