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