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