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