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