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