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