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