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