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