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