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