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