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