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