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