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