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