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