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