Remove redundant check.
[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   if (!(grfMode & STGM_TRANSACTED))
5806     switch(STGM_SHARE_MODE(grfMode))
5807     {
5808       case STGM_SHARE_EXCLUSIVE:
5809       case STGM_SHARE_DENY_WRITE:
5810         break;
5811       default:
5812         hr = STG_E_INVALIDFLAG;
5813         goto end;
5814     }
5815
5816   /*
5817    * Validate the STGM flags
5818    */
5819   if ( FAILED( validateSTGM(grfMode) ) ||
5820        (grfMode&STGM_CREATE))
5821   {
5822     hr = STG_E_INVALIDFLAG;
5823     goto end;
5824   }
5825
5826   /* shared reading requires transacted mode */
5827   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
5828       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
5829      !(grfMode&STGM_TRANSACTED) )
5830   {
5831     hr = STG_E_INVALIDFLAG;
5832     goto end;
5833   }
5834
5835   /*
5836    * Interpret the STGM value grfMode
5837    */
5838   shareMode    = GetShareModeFromSTGM(grfMode);
5839   accessMode   = GetAccessModeFromSTGM(grfMode);
5840
5841   /*
5842    * Initialize the "out" parameter.
5843    */
5844   *ppstgOpen = 0;
5845
5846   hFile = CreateFileW( pwcsName,
5847                        accessMode,
5848                        shareMode,
5849                        NULL,
5850                        OPEN_EXISTING,
5851                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5852                        0);
5853
5854   if (hFile==INVALID_HANDLE_VALUE)
5855   {
5856     DWORD last_error = GetLastError();
5857
5858     hr = E_FAIL;
5859
5860     switch (last_error)
5861     {
5862       case ERROR_FILE_NOT_FOUND:
5863         hr = STG_E_FILENOTFOUND;
5864         break;
5865
5866       case ERROR_PATH_NOT_FOUND:
5867         hr = STG_E_PATHNOTFOUND;
5868         break;
5869
5870       case ERROR_ACCESS_DENIED:
5871       case ERROR_WRITE_PROTECT:
5872         hr = STG_E_ACCESSDENIED;
5873         break;
5874
5875       case ERROR_SHARING_VIOLATION:
5876         hr = STG_E_SHAREVIOLATION;
5877         break;
5878
5879       default:
5880         hr = E_FAIL;
5881     }
5882
5883     goto end;
5884   }
5885
5886   /*
5887    * Refuse to open the file if it's too small to be a structured storage file
5888    * FIXME: verify the file when reading instead of here
5889    */
5890   length = GetFileSize(hFile, NULL);
5891   if (length < 0x100)
5892   {
5893     CloseHandle(hFile);
5894     hr = STG_E_FILEALREADYEXISTS;
5895     goto end;
5896   }
5897
5898   /*
5899    * Allocate and initialize the new IStorage32object.
5900    */
5901   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5902
5903   if (newStorage == 0)
5904   {
5905     hr = STG_E_INSUFFICIENTMEMORY;
5906     goto end;
5907   }
5908
5909   /* if the file's length was zero, initialize the storage */
5910   hr = StorageImpl_Construct(
5911          newStorage,
5912          hFile,
5913         pwcsName,
5914          NULL,
5915          grfMode,
5916          TRUE,
5917          FALSE );
5918
5919   if (FAILED(hr))
5920   {
5921     HeapFree(GetProcessHeap(), 0, newStorage);
5922     /*
5923      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
5924      */
5925     if(hr == STG_E_INVALIDHEADER)
5926         hr = STG_E_FILEALREADYEXISTS;
5927     goto end;
5928   }
5929
5930   /* prepare the file name string given in lieu of the root property name */
5931   GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
5932   memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
5933   newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
5934
5935   /*
5936    * Get an "out" pointer for the caller.
5937    */
5938   hr = StorageBaseImpl_QueryInterface(
5939          (IStorage*)newStorage,
5940          (REFIID)&IID_IStorage,
5941          (void**)ppstgOpen);
5942
5943 end:
5944   TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
5945   return hr;
5946 }
5947
5948 /******************************************************************************
5949  *    StgCreateDocfileOnILockBytes    [OLE32.@]
5950  */
5951 HRESULT WINAPI StgCreateDocfileOnILockBytes(
5952       ILockBytes *plkbyt,
5953       DWORD grfMode,
5954       DWORD reserved,
5955       IStorage** ppstgOpen)
5956 {
5957   StorageImpl*   newStorage = 0;
5958   HRESULT        hr         = S_OK;
5959
5960   /*
5961    * Validate the parameters
5962    */
5963   if ((ppstgOpen == 0) || (plkbyt == 0))
5964     return STG_E_INVALIDPOINTER;
5965
5966   /*
5967    * Allocate and initialize the new IStorage object.
5968    */
5969   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5970
5971   if (newStorage == 0)
5972     return STG_E_INSUFFICIENTMEMORY;
5973
5974   hr = StorageImpl_Construct(
5975          newStorage,
5976          0,
5977         0,
5978          plkbyt,
5979          grfMode,
5980          FALSE,
5981          TRUE);
5982
5983   if (FAILED(hr))
5984   {
5985     HeapFree(GetProcessHeap(), 0, newStorage);
5986     return hr;
5987   }
5988
5989   /*
5990    * Get an "out" pointer for the caller.
5991    */
5992   hr = StorageBaseImpl_QueryInterface(
5993          (IStorage*)newStorage,
5994          (REFIID)&IID_IStorage,
5995          (void**)ppstgOpen);
5996
5997   return hr;
5998 }
5999
6000 /******************************************************************************
6001  *    StgOpenStorageOnILockBytes    [OLE32.@]
6002  */
6003 HRESULT WINAPI StgOpenStorageOnILockBytes(
6004       ILockBytes *plkbyt,
6005       IStorage *pstgPriority,
6006       DWORD grfMode,
6007       SNB snbExclude,
6008       DWORD reserved,
6009       IStorage **ppstgOpen)
6010 {
6011   StorageImpl* newStorage = 0;
6012   HRESULT        hr = S_OK;
6013
6014   /*
6015    * Perform a sanity check
6016    */
6017   if ((plkbyt == 0) || (ppstgOpen == 0))
6018     return STG_E_INVALIDPOINTER;
6019
6020   /*
6021    * Validate the STGM flags
6022    */
6023   if ( FAILED( validateSTGM(grfMode) ))
6024     return STG_E_INVALIDFLAG;
6025
6026   /*
6027    * Initialize the "out" parameter.
6028    */
6029   *ppstgOpen = 0;
6030
6031   /*
6032    * Allocate and initialize the new IStorage object.
6033    */
6034   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
6035
6036   if (newStorage == 0)
6037     return STG_E_INSUFFICIENTMEMORY;
6038
6039   hr = StorageImpl_Construct(
6040          newStorage,
6041          0,
6042          0,
6043          plkbyt,
6044          grfMode,
6045          FALSE,
6046          FALSE);
6047
6048   if (FAILED(hr))
6049   {
6050     HeapFree(GetProcessHeap(), 0, newStorage);
6051     return hr;
6052   }
6053
6054   /*
6055    * Get an "out" pointer for the caller.
6056    */
6057   hr = StorageBaseImpl_QueryInterface(
6058          (IStorage*)newStorage,
6059          (REFIID)&IID_IStorage,
6060          (void**)ppstgOpen);
6061
6062   return hr;
6063 }
6064
6065 /******************************************************************************
6066  *              StgSetTimes [ole32.@]
6067  *              StgSetTimes [OLE32.@]
6068  *
6069  *
6070  */
6071 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
6072                            FILETIME const *patime, FILETIME const *pmtime)
6073 {
6074   IStorage *stg = NULL;
6075   HRESULT r;
6076  
6077   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
6078
6079   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
6080                      0, 0, &stg);
6081   if( SUCCEEDED(r) )
6082   {
6083     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
6084     IStorage_Release(stg);
6085   }
6086
6087   return r;
6088 }
6089
6090 /******************************************************************************
6091  *              StgIsStorageILockBytes        [OLE32.@]
6092  *
6093  * Determines if the ILockBytes contains a storage object.
6094  */
6095 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
6096 {
6097   BYTE sig[8];
6098   ULARGE_INTEGER offset;
6099
6100   offset.u.HighPart = 0;
6101   offset.u.LowPart  = 0;
6102
6103   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
6104
6105   if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
6106     return S_OK;
6107
6108   return S_FALSE;
6109 }
6110
6111 /******************************************************************************
6112  *              WriteClassStg        [OLE32.@]
6113  *
6114  * This method will store the specified CLSID in the specified storage object
6115  */
6116 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
6117 {
6118   HRESULT hRes;
6119
6120   assert(pStg != 0);
6121
6122   hRes = IStorage_SetClass(pStg, rclsid);
6123
6124   return hRes;
6125 }
6126
6127 /***********************************************************************
6128  *    ReadClassStg (OLE32.@)
6129  *
6130  * This method reads the CLSID previously written to a storage object with the WriteClassStg.
6131  */
6132 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
6133
6134     STATSTG pstatstg;
6135     HRESULT hRes;
6136
6137     TRACE("()\n");
6138
6139     if(pclsid==NULL)
6140         return E_POINTER;
6141    /*
6142     * read a STATSTG structure (contains the clsid) from the storage
6143     */
6144     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
6145
6146     if(SUCCEEDED(hRes))
6147         *pclsid=pstatstg.clsid;
6148
6149     return hRes;
6150 }
6151
6152 /***********************************************************************
6153  *    OleLoadFromStream (OLE32.@)
6154  *
6155  * This function loads an object from stream
6156  */
6157 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
6158 {
6159     CLSID       clsid;
6160     HRESULT     res;
6161     LPPERSISTSTREAM     xstm;
6162
6163     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
6164
6165     res=ReadClassStm(pStm,&clsid);
6166     if (!SUCCEEDED(res))
6167         return res;
6168     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
6169     if (!SUCCEEDED(res))
6170         return res;
6171     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
6172     if (!SUCCEEDED(res)) {
6173         IUnknown_Release((IUnknown*)*ppvObj);
6174         return res;
6175     }
6176     res=IPersistStream_Load(xstm,pStm);
6177     IPersistStream_Release(xstm);
6178     /* FIXME: all refcounts ok at this point? I think they should be:
6179      *          pStm    : unchanged
6180      *          ppvObj  : 1
6181      *          xstm    : 0 (released)
6182      */
6183     return res;
6184 }
6185
6186 /***********************************************************************
6187  *    OleSaveToStream (OLE32.@)
6188  *
6189  * This function saves an object with the IPersistStream interface on it
6190  * to the specified stream.
6191  */
6192 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
6193 {
6194
6195     CLSID clsid;
6196     HRESULT res;
6197
6198     TRACE("(%p,%p)\n",pPStm,pStm);
6199
6200     res=IPersistStream_GetClassID(pPStm,&clsid);
6201
6202     if (SUCCEEDED(res)){
6203
6204         res=WriteClassStm(pStm,&clsid);
6205
6206         if (SUCCEEDED(res))
6207
6208             res=IPersistStream_Save(pPStm,pStm,TRUE);
6209     }
6210
6211     TRACE("Finished Save\n");
6212     return res;
6213 }
6214
6215 /****************************************************************************
6216  * This method validate a STGM parameter that can contain the values below
6217  *
6218  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
6219  * The stgm values contained in 0xffff0000 are bitmasks.
6220  *
6221  * STGM_DIRECT               0x00000000
6222  * STGM_TRANSACTED           0x00010000
6223  * STGM_SIMPLE               0x08000000
6224  *
6225  * STGM_READ                 0x00000000
6226  * STGM_WRITE                0x00000001
6227  * STGM_READWRITE            0x00000002
6228  *
6229  * STGM_SHARE_DENY_NONE      0x00000040
6230  * STGM_SHARE_DENY_READ      0x00000030
6231  * STGM_SHARE_DENY_WRITE     0x00000020
6232  * STGM_SHARE_EXCLUSIVE      0x00000010
6233  *
6234  * STGM_PRIORITY             0x00040000
6235  * STGM_DELETEONRELEASE      0x04000000
6236  *
6237  * STGM_CREATE               0x00001000
6238  * STGM_CONVERT              0x00020000
6239  * STGM_FAILIFTHERE          0x00000000
6240  *
6241  * STGM_NOSCRATCH            0x00100000
6242  * STGM_NOSNAPSHOT           0x00200000
6243  */
6244 static HRESULT validateSTGM(DWORD stgm)
6245 {
6246   DWORD access = STGM_ACCESS_MODE(stgm);
6247   DWORD share  = STGM_SHARE_MODE(stgm);
6248   DWORD create = STGM_CREATE_MODE(stgm);
6249
6250   if (stgm&~STGM_KNOWN_FLAGS)
6251   {
6252     ERR("unknown flags %08lx\n", stgm);
6253     return E_FAIL;
6254   }
6255
6256   switch (access)
6257   {
6258   case STGM_READ:
6259   case STGM_WRITE:
6260   case STGM_READWRITE:
6261     break;
6262   default:
6263     return E_FAIL;
6264   }
6265
6266   switch (share)
6267   {
6268   case STGM_SHARE_DENY_NONE:
6269   case STGM_SHARE_DENY_READ:
6270   case STGM_SHARE_DENY_WRITE:
6271   case STGM_SHARE_EXCLUSIVE:
6272     break;
6273   default:
6274     return E_FAIL;
6275   }
6276
6277   switch (create)
6278   {
6279   case STGM_CREATE:
6280   case STGM_FAILIFTHERE:
6281     break;
6282   default:
6283     return E_FAIL;
6284   }
6285
6286   /*
6287    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
6288    */
6289   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
6290       return E_FAIL;
6291
6292   /*
6293    * STGM_CREATE | STGM_CONVERT
6294    * if both are false, STGM_FAILIFTHERE is set to TRUE
6295    */
6296   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
6297     return E_FAIL;
6298
6299   /*
6300    * STGM_NOSCRATCH requires STGM_TRANSACTED
6301    */
6302   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
6303     return E_FAIL;
6304
6305   /*
6306    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
6307    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
6308    */
6309   if ( (stgm & STGM_NOSNAPSHOT) &&
6310         (!(stgm & STGM_TRANSACTED) ||
6311          share == STGM_SHARE_EXCLUSIVE ||
6312          share == STGM_SHARE_DENY_WRITE) )
6313     return E_FAIL;
6314
6315   return S_OK;
6316 }
6317
6318 /****************************************************************************
6319  *      GetShareModeFromSTGM
6320  *
6321  * This method will return a share mode flag from a STGM value.
6322  * The STGM value is assumed valid.
6323  */
6324 static DWORD GetShareModeFromSTGM(DWORD stgm)
6325 {
6326   switch (STGM_SHARE_MODE(stgm))
6327   {
6328   case STGM_SHARE_DENY_NONE:
6329     return FILE_SHARE_READ | FILE_SHARE_WRITE;
6330   case STGM_SHARE_DENY_READ:
6331     return FILE_SHARE_WRITE;
6332   case STGM_SHARE_DENY_WRITE:
6333     return FILE_SHARE_READ;
6334   case STGM_SHARE_EXCLUSIVE:
6335     return 0;
6336   }
6337   ERR("Invalid share mode!\n");
6338   assert(0);
6339   return 0;
6340 }
6341
6342 /****************************************************************************
6343  *      GetAccessModeFromSTGM
6344  *
6345  * This method will return an access mode flag from a STGM value.
6346  * The STGM value is assumed valid.
6347  */
6348 static DWORD GetAccessModeFromSTGM(DWORD stgm)
6349 {
6350   switch (STGM_ACCESS_MODE(stgm))
6351   {
6352   case STGM_READ:
6353     return GENERIC_READ;
6354   case STGM_WRITE:
6355   case STGM_READWRITE:
6356     return GENERIC_READ | GENERIC_WRITE;
6357   }
6358   ERR("Invalid access mode!\n");
6359   assert(0);
6360   return 0;
6361 }
6362
6363 /****************************************************************************
6364  *      GetCreationModeFromSTGM
6365  *
6366  * This method will return a creation mode flag from a STGM value.
6367  * The STGM value is assumed valid.
6368  */
6369 static DWORD GetCreationModeFromSTGM(DWORD stgm)
6370 {
6371   switch(STGM_CREATE_MODE(stgm))
6372   {
6373   case STGM_CREATE:
6374     return CREATE_ALWAYS;
6375   case STGM_CONVERT:
6376     FIXME("STGM_CONVERT not implemented!\n");
6377     return CREATE_NEW;
6378   case STGM_FAILIFTHERE:
6379     return CREATE_NEW;
6380   }
6381   ERR("Invalid create mode!\n");
6382   assert(0);
6383   return 0;
6384 }
6385
6386
6387 /*************************************************************************
6388  * OLECONVERT_LoadOLE10 [Internal]
6389  *
6390  * Loads the OLE10 STREAM to memory
6391  *
6392  * PARAMS
6393  *     pOleStream   [I] The OLESTREAM
6394  *     pData        [I] Data Structure for the OLESTREAM Data
6395  *
6396  * RETURNS
6397  *     Success:  S_OK
6398  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
6399  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
6400  *
6401  * NOTES
6402  *     This function is used by OleConvertOLESTREAMToIStorage only.
6403  *
6404  *     Memory allocated for pData must be freed by the caller
6405  */
6406 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
6407 {
6408         DWORD dwSize;
6409         HRESULT hRes = S_OK;
6410         int nTryCnt=0;
6411         int max_try = 6;
6412
6413         pData->pData = NULL;
6414         pData->pstrOleObjFileName = (CHAR *) NULL;
6415
6416         for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
6417         {
6418         /* Get the OleID */
6419         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6420         if(dwSize != sizeof(pData->dwOleID))
6421         {
6422                 hRes = CONVERT10_E_OLESTREAM_GET;
6423         }
6424         else if(pData->dwOleID != OLESTREAM_ID)
6425         {
6426                 hRes = CONVERT10_E_OLESTREAM_FMT;
6427         }
6428                 else
6429                 {
6430                         hRes = S_OK;
6431                         break;
6432                 }
6433         }
6434
6435         if(hRes == S_OK)
6436         {
6437                 /* Get the TypeID...more info needed for this field */
6438                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6439                 if(dwSize != sizeof(pData->dwTypeID))
6440                 {
6441                         hRes = CONVERT10_E_OLESTREAM_GET;
6442                 }
6443         }
6444         if(hRes == S_OK)
6445         {
6446                 if(pData->dwTypeID != 0)
6447                 {
6448                         /* Get the length of the OleTypeName */
6449                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6450                         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6451                         {
6452                                 hRes = CONVERT10_E_OLESTREAM_GET;
6453                         }
6454
6455                         if(hRes == S_OK)
6456                         {
6457                                 if(pData->dwOleTypeNameLength > 0)
6458                                 {
6459                                         /* Get the OleTypeName */
6460                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6461                                         if(dwSize != pData->dwOleTypeNameLength)
6462                                         {
6463                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6464                                         }
6465                                 }
6466                         }
6467                         if(bStrem1)
6468                         {
6469                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6470                                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6471                                 {
6472                                         hRes = CONVERT10_E_OLESTREAM_GET;
6473                                 }
6474                         if(hRes == S_OK)
6475                         {
6476                                         if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6477                                                 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6478                                         pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
6479                                         if(pData->pstrOleObjFileName)
6480                                         {
6481                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6482                                                 if(dwSize != pData->dwOleObjFileNameLength)
6483                                                 {
6484                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6485                                                 }
6486                                         }
6487                                         else
6488                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6489                                 }
6490                         }
6491                         else
6492                         {
6493                                 /* Get the Width of the Metafile */
6494                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6495                                 if(dwSize != sizeof(pData->dwMetaFileWidth))
6496                                 {
6497                                         hRes = CONVERT10_E_OLESTREAM_GET;
6498                                 }
6499                         if(hRes == S_OK)
6500                         {
6501                                 /* Get the Height of the Metafile */
6502                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6503                                 if(dwSize != sizeof(pData->dwMetaFileHeight))
6504                                 {
6505                                         hRes = CONVERT10_E_OLESTREAM_GET;
6506                                 }
6507                         }
6508                         }
6509                         if(hRes == S_OK)
6510                         {
6511                                 /* Get the Length of the Data */
6512                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6513                                 if(dwSize != sizeof(pData->dwDataLength))
6514                                 {
6515                                         hRes = CONVERT10_E_OLESTREAM_GET;
6516                                 }
6517                         }
6518
6519                         if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6520                         {
6521                                 if(!bStrem1) /* if it is a second OLE stream data */
6522                                 {
6523                                         pData->dwDataLength -= 8;
6524                                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6525                                         if(dwSize != sizeof(pData->strUnknown))
6526                                         {
6527                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6528                                         }
6529                                 }
6530                         }
6531                         if(hRes == S_OK)
6532                         {
6533                                 if(pData->dwDataLength > 0)
6534                                 {
6535                                         pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6536
6537                                         /* Get Data (ex. IStorage, Metafile, or BMP) */
6538                                         if(pData->pData)
6539                                         {
6540                                                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6541                                                 if(dwSize != pData->dwDataLength)
6542                                                 {
6543                                                         hRes = CONVERT10_E_OLESTREAM_GET;
6544                                                 }
6545                                         }
6546                                         else
6547                                         {
6548                                                 hRes = CONVERT10_E_OLESTREAM_GET;
6549                                         }
6550                                 }
6551                         }
6552                 }
6553         }
6554         return hRes;
6555 }
6556
6557 /*************************************************************************
6558  * OLECONVERT_SaveOLE10 [Internal]
6559  *
6560  * Saves the OLE10 STREAM From memory
6561  *
6562  * PARAMS
6563  *     pData        [I] Data Structure for the OLESTREAM Data
6564  *     pOleStream   [I] The OLESTREAM to save
6565  *
6566  * RETURNS
6567  *     Success:  S_OK
6568  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
6569  *
6570  * NOTES
6571  *     This function is used by OleConvertIStorageToOLESTREAM only.
6572  *
6573  */
6574 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6575 {
6576     DWORD dwSize;
6577     HRESULT hRes = S_OK;
6578
6579
6580    /* Set the OleID */
6581     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6582     if(dwSize != sizeof(pData->dwOleID))
6583     {
6584         hRes = CONVERT10_E_OLESTREAM_PUT;
6585     }
6586
6587     if(hRes == S_OK)
6588     {
6589         /* Set the TypeID */
6590         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6591         if(dwSize != sizeof(pData->dwTypeID))
6592         {
6593             hRes = CONVERT10_E_OLESTREAM_PUT;
6594         }
6595     }
6596
6597     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6598     {
6599         /* Set the Length of the OleTypeName */
6600         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6601         if(dwSize != sizeof(pData->dwOleTypeNameLength))
6602         {
6603             hRes = CONVERT10_E_OLESTREAM_PUT;
6604         }
6605
6606         if(hRes == S_OK)
6607         {
6608             if(pData->dwOleTypeNameLength > 0)
6609             {
6610                 /* Set the OleTypeName */
6611                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
6612                 if(dwSize != pData->dwOleTypeNameLength)
6613                 {
6614                     hRes = CONVERT10_E_OLESTREAM_PUT;
6615                 }
6616             }
6617         }
6618
6619         if(hRes == S_OK)
6620         {
6621             /* Set the width of the Metafile */
6622             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6623             if(dwSize != sizeof(pData->dwMetaFileWidth))
6624             {
6625                 hRes = CONVERT10_E_OLESTREAM_PUT;
6626             }
6627         }
6628
6629         if(hRes == S_OK)
6630         {
6631             /* Set the height of the Metafile */
6632             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6633             if(dwSize != sizeof(pData->dwMetaFileHeight))
6634             {
6635                 hRes = CONVERT10_E_OLESTREAM_PUT;
6636             }
6637         }
6638
6639         if(hRes == S_OK)
6640         {
6641             /* Set the length of the Data */
6642             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6643             if(dwSize != sizeof(pData->dwDataLength))
6644             {
6645                 hRes = CONVERT10_E_OLESTREAM_PUT;
6646             }
6647         }
6648
6649         if(hRes == S_OK)
6650         {
6651             if(pData->dwDataLength > 0)
6652             {
6653                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6654                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
6655                 if(dwSize != pData->dwDataLength)
6656                 {
6657                     hRes = CONVERT10_E_OLESTREAM_PUT;
6658                 }
6659             }
6660         }
6661     }
6662     return hRes;
6663 }
6664
6665 /*************************************************************************
6666  * OLECONVERT_GetOLE20FromOLE10[Internal]
6667  *
6668  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6669  * opens it, and copies the content to the dest IStorage for
6670  * OleConvertOLESTREAMToIStorage
6671  *
6672  *
6673  * PARAMS
6674  *     pDestStorage  [I] The IStorage to copy the data to
6675  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
6676  *     nBufferLength [I] The size of the buffer
6677  *
6678  * RETURNS
6679  *     Nothing
6680  *
6681  * NOTES
6682  *
6683  *
6684  */
6685 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6686 {
6687     HRESULT hRes;
6688     HANDLE hFile;
6689     IStorage *pTempStorage;
6690     DWORD dwNumOfBytesWritten;
6691     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6692     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6693
6694     /* Create a temp File */
6695     GetTempPathW(MAX_PATH, wstrTempDir);
6696     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6697     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6698
6699     if(hFile != INVALID_HANDLE_VALUE)
6700     {
6701         /* Write IStorage Data to File */
6702         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6703         CloseHandle(hFile);
6704
6705         /* Open and copy temp storage to the Dest Storage */
6706         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6707         if(hRes == S_OK)
6708         {
6709             hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6710             StorageBaseImpl_Release(pTempStorage);
6711         }
6712         DeleteFileW(wstrTempFile);
6713     }
6714 }
6715
6716
6717 /*************************************************************************
6718  * OLECONVERT_WriteOLE20ToBuffer [Internal]
6719  *
6720  * Saves the OLE10 STREAM From memory
6721  *
6722  * PARAMS
6723  *     pStorage  [I] The Src IStorage to copy
6724  *     pData     [I] The Dest Memory to write to.
6725  *
6726  * RETURNS
6727  *     The size in bytes allocated for pData
6728  *
6729  * NOTES
6730  *     Memory allocated for pData must be freed by the caller
6731  *
6732  *     Used by OleConvertIStorageToOLESTREAM only.
6733  *
6734  */
6735 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6736 {
6737     HANDLE hFile;
6738     HRESULT hRes;
6739     DWORD nDataLength = 0;
6740     IStorage *pTempStorage;
6741     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6742     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6743
6744     *pData = NULL;
6745
6746     /* Create temp Storage */
6747     GetTempPathW(MAX_PATH, wstrTempDir);
6748     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6749     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6750
6751     if(hRes == S_OK)
6752     {
6753         /* Copy Src Storage to the Temp Storage */
6754         StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6755         StorageBaseImpl_Release(pTempStorage);
6756
6757         /* Open Temp Storage as a file and copy to memory */
6758         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6759         if(hFile != INVALID_HANDLE_VALUE)
6760         {
6761             nDataLength = GetFileSize(hFile, NULL);
6762             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
6763             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6764             CloseHandle(hFile);
6765         }
6766         DeleteFileW(wstrTempFile);
6767     }
6768     return nDataLength;
6769 }
6770
6771 /*************************************************************************
6772  * OLECONVERT_CreateOleStream [Internal]
6773  *
6774  * Creates the "\001OLE" stream in the IStorage if necessary.
6775  *
6776  * PARAMS
6777  *     pStorage     [I] Dest storage to create the stream in
6778  *
6779  * RETURNS
6780  *     Nothing
6781  *
6782  * NOTES
6783  *     This function is used by OleConvertOLESTREAMToIStorage only.
6784  *
6785  *     This stream is still unknown, MS Word seems to have extra data
6786  *     but since the data is stored in the OLESTREAM there should be
6787  *     no need to recreate the stream.  If the stream is manually
6788  *     deleted it will create it with this default data.
6789  *
6790  */
6791 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6792 {
6793     HRESULT hRes;
6794     IStream *pStream;
6795     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6796     BYTE pOleStreamHeader [] =
6797     {
6798         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6799         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6800         0x00, 0x00, 0x00, 0x00
6801     };
6802
6803     /* Create stream if not present */
6804     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6805         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6806
6807     if(hRes == S_OK)
6808     {
6809         /* Write default Data */
6810         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6811         IStream_Release(pStream);
6812     }
6813 }
6814
6815 /* write a string to a stream, preceded by its length */
6816 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
6817 {
6818     HRESULT r;
6819     LPSTR str;
6820     DWORD len = 0;
6821
6822     if( string )
6823         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
6824     r = IStream_Write( stm, &len, sizeof(len), NULL);
6825     if( FAILED( r ) )
6826         return r;
6827     if(len == 0)
6828         return r;
6829     str = CoTaskMemAlloc( len );
6830     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
6831     r = IStream_Write( stm, str, len, NULL);
6832     CoTaskMemFree( str );
6833     return r;
6834 }
6835
6836 /* read a string preceded by its length from a stream */
6837 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
6838 {
6839     HRESULT r;
6840     DWORD len, count = 0;
6841     LPSTR str;
6842     LPWSTR wstr;
6843
6844     r = IStream_Read( stm, &len, sizeof(len), &count );
6845     if( FAILED( r ) )
6846         return r;
6847     if( count != sizeof(len) )
6848         return E_OUTOFMEMORY;
6849
6850     TRACE("%ld bytes\n",len);
6851     
6852     str = CoTaskMemAlloc( len );
6853     if( !str )
6854         return E_OUTOFMEMORY;
6855     count = 0;
6856     r = IStream_Read( stm, str, len, &count );
6857     if( FAILED( r ) )
6858         return r;
6859     if( count != len )
6860     {
6861         CoTaskMemFree( str );
6862         return E_OUTOFMEMORY;
6863     }
6864
6865     TRACE("Read string %s\n",debugstr_an(str,len));
6866
6867     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
6868     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
6869     if( wstr )
6870          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
6871     CoTaskMemFree( str );
6872
6873     *string = wstr;
6874
6875     return r;
6876 }
6877
6878
6879 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
6880     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
6881 {
6882     IStream *pstm;
6883     HRESULT r = S_OK;
6884     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6885
6886     static const BYTE unknown1[12] =
6887        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
6888          0xFF, 0xFF, 0xFF, 0xFF};
6889     static const BYTE unknown2[16] =
6890        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
6891          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
6892
6893     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
6894            debugstr_w(lpszUserType), debugstr_w(szClipName),
6895            debugstr_w(szProgIDName));
6896
6897     /*  Create a CompObj stream if it doesn't exist */
6898     r = IStorage_CreateStream(pstg, szwStreamName,
6899         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
6900     if( FAILED (r) )
6901         return r;
6902
6903     /* Write CompObj Structure to stream */
6904     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
6905
6906     if( SUCCEEDED( r ) )
6907         r = WriteClassStm( pstm, clsid );
6908
6909     if( SUCCEEDED( r ) )
6910         r = STREAM_WriteString( pstm, lpszUserType );
6911     if( SUCCEEDED( r ) )
6912         r = STREAM_WriteString( pstm, szClipName );
6913     if( SUCCEEDED( r ) )
6914         r = STREAM_WriteString( pstm, szProgIDName );
6915     if( SUCCEEDED( r ) )
6916         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
6917
6918     IStream_Release( pstm );
6919
6920     return r;
6921 }
6922
6923 /***********************************************************************
6924  *               WriteFmtUserTypeStg (OLE32.@)
6925  */
6926 HRESULT WINAPI WriteFmtUserTypeStg(
6927           LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
6928 {
6929     HRESULT r;
6930     WCHAR szwClipName[0x40];
6931     CLSID clsid = CLSID_NULL;
6932     LPWSTR wstrProgID = NULL;
6933     DWORD n;
6934
6935     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
6936
6937     /* get the clipboard format name */
6938     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
6939     szwClipName[n]=0;
6940
6941     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
6942
6943     /* FIXME: There's room to save a CLSID and its ProgID, but
6944        the CLSID is not looked up in the registry and in all the
6945        tests I wrote it was CLSID_NULL.  Where does it come from?
6946     */
6947
6948     /* get the real program ID.  This may fail, but that's fine */
6949     ProgIDFromCLSID(&clsid, &wstrProgID);
6950
6951     TRACE("progid is %s\n",debugstr_w(wstrProgID));
6952
6953     r = STORAGE_WriteCompObj( pstg, &clsid, 
6954                               lpszUserType, szwClipName, wstrProgID );
6955
6956     CoTaskMemFree(wstrProgID);
6957
6958     return r;
6959 }
6960
6961
6962 /******************************************************************************
6963  *              ReadFmtUserTypeStg        [OLE32.@]
6964  */
6965 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
6966 {
6967     HRESULT r;
6968     IStream *stm = 0;
6969     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
6970     unsigned char unknown1[12];
6971     unsigned char unknown2[16];
6972     DWORD count;
6973     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
6974     CLSID clsid;
6975
6976     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
6977
6978     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
6979                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
6980     if( FAILED ( r ) )
6981     {
6982         WARN("Failed to open stream r = %08lx\n", r);
6983         return r;
6984     }
6985
6986     /* read the various parts of the structure */
6987     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
6988     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
6989         goto end;
6990     r = ReadClassStm( stm, &clsid );
6991     if( FAILED( r ) )
6992         goto end;
6993
6994     r = STREAM_ReadString( stm, &szCLSIDName );
6995     if( FAILED( r ) )
6996         goto end;
6997
6998     r = STREAM_ReadString( stm, &szOleTypeName );
6999     if( FAILED( r ) )
7000         goto end;
7001
7002     r = STREAM_ReadString( stm, &szProgIDName );
7003     if( FAILED( r ) )
7004         goto end;
7005
7006     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
7007     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
7008         goto end;
7009
7010     /* ok, success... now we just need to store what we found */
7011     if( pcf )
7012         *pcf = RegisterClipboardFormatW( szOleTypeName );
7013     CoTaskMemFree( szOleTypeName );
7014
7015     if( lplpszUserType )
7016         *lplpszUserType = szCLSIDName;
7017     CoTaskMemFree( szProgIDName );
7018
7019 end:
7020     IStream_Release( stm );
7021
7022     return r;
7023 }
7024
7025
7026 /*************************************************************************
7027  * OLECONVERT_CreateCompObjStream [Internal]
7028  *
7029  * Creates a "\001CompObj" is the destination IStorage if necessary.
7030  *
7031  * PARAMS
7032  *     pStorage       [I] The dest IStorage to create the CompObj Stream
7033  *                        if necessary.
7034  *     strOleTypeName [I] The ProgID
7035  *
7036  * RETURNS
7037  *     Success:  S_OK
7038  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7039  *
7040  * NOTES
7041  *     This function is used by OleConvertOLESTREAMToIStorage only.
7042  *
7043  *     The stream data is stored in the OLESTREAM and there should be
7044  *     no need to recreate the stream.  If the stream is manually
7045  *     deleted it will attempt to create it by querying the registry.
7046  *
7047  *
7048  */
7049 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
7050 {
7051     IStream *pStream;
7052     HRESULT hStorageRes, hRes = S_OK;
7053     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
7054     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7055     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
7056
7057     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
7058     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
7059
7060     /* Initialize the CompObj structure */
7061     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
7062     memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
7063     memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
7064
7065
7066     /*  Create a CompObj stream if it doesn't exist */
7067     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
7068         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7069     if(hStorageRes == S_OK)
7070     {
7071         /* copy the OleTypeName to the compobj struct */
7072         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
7073         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
7074
7075         /* copy the OleTypeName to the compobj struct */
7076         /* Note: in the test made, these were Identical      */
7077         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
7078         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
7079
7080         /* Get the CLSID */
7081         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
7082                              bufferW, OLESTREAM_MAX_STR_LEN );
7083         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
7084
7085         if(hRes == S_OK)
7086         {
7087             HKEY hKey;
7088             LONG hErr;
7089             /* Get the CLSID Default Name from the Registry */
7090             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
7091             if(hErr == ERROR_SUCCESS)
7092             {
7093                 char strTemp[OLESTREAM_MAX_STR_LEN];
7094                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
7095                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
7096                 if(hErr == ERROR_SUCCESS)
7097                 {
7098                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
7099                 }
7100                 RegCloseKey(hKey);
7101             }
7102         }
7103
7104         /* Write CompObj Structure to stream */
7105         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
7106
7107         WriteClassStm(pStream,&(IStorageCompObj.clsid));
7108
7109         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
7110         if(IStorageCompObj.dwCLSIDNameLength > 0)
7111         {
7112             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
7113         }
7114         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
7115         if(IStorageCompObj.dwOleTypeNameLength > 0)
7116         {
7117             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
7118         }
7119         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
7120         if(IStorageCompObj.dwProgIDNameLength > 0)
7121         {
7122             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
7123         }
7124         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
7125         IStream_Release(pStream);
7126     }
7127     return hRes;
7128 }
7129
7130
7131 /*************************************************************************
7132  * OLECONVERT_CreateOlePresStream[Internal]
7133  *
7134  * Creates the "\002OlePres000" Stream with the Metafile data
7135  *
7136  * PARAMS
7137  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
7138  *     dwExtentX    [I] Width of the Metafile
7139  *     dwExtentY    [I] Height of the Metafile
7140  *     pData        [I] Metafile data
7141  *     dwDataLength [I] Size of the Metafile data
7142  *
7143  * RETURNS
7144  *     Success:  S_OK
7145  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
7146  *
7147  * NOTES
7148  *     This function is used by OleConvertOLESTREAMToIStorage only.
7149  *
7150  */
7151 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
7152 {
7153     HRESULT hRes;
7154     IStream *pStream;
7155     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7156     BYTE pOlePresStreamHeader [] =
7157     {
7158         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
7159         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7160         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7161         0x00, 0x00, 0x00, 0x00
7162     };
7163
7164     BYTE pOlePresStreamHeaderEmpty [] =
7165     {
7166         0x00, 0x00, 0x00, 0x00,
7167         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
7168         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
7169         0x00, 0x00, 0x00, 0x00
7170     };
7171
7172     /* Create the OlePres000 Stream */
7173     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7174         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7175
7176     if(hRes == S_OK)
7177     {
7178         DWORD nHeaderSize;
7179         OLECONVERT_ISTORAGE_OLEPRES OlePres;
7180
7181         memset(&OlePres, 0, sizeof(OlePres));
7182         /* Do we have any metafile data to save */
7183         if(dwDataLength > 0)
7184         {
7185             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
7186             nHeaderSize = sizeof(pOlePresStreamHeader);
7187         }
7188         else
7189         {
7190             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
7191             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
7192         }
7193         /* Set width and height of the metafile */
7194         OlePres.dwExtentX = dwExtentX;
7195         OlePres.dwExtentY = -dwExtentY;
7196
7197         /* Set Data and Length */
7198         if(dwDataLength > sizeof(METAFILEPICT16))
7199         {
7200             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
7201             OlePres.pData = &(pData[8]);
7202         }
7203         /* Save OlePres000 Data to Stream */
7204         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
7205         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
7206         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
7207         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
7208         if(OlePres.dwSize > 0)
7209         {
7210             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
7211         }
7212         IStream_Release(pStream);
7213     }
7214 }
7215
7216 /*************************************************************************
7217  * OLECONVERT_CreateOle10NativeStream [Internal]
7218  *
7219  * Creates the "\001Ole10Native" Stream (should contain a BMP)
7220  *
7221  * PARAMS
7222  *     pStorage     [I] Dest storage to create the stream in
7223  *     pData        [I] Ole10 Native Data (ex. bmp)
7224  *     dwDataLength [I] Size of the Ole10 Native Data
7225  *
7226  * RETURNS
7227  *     Nothing
7228  *
7229  * NOTES
7230  *     This function is used by OleConvertOLESTREAMToIStorage only.
7231  *
7232  *     Might need to verify the data and return appropriate error message
7233  *
7234  */
7235 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
7236 {
7237     HRESULT hRes;
7238     IStream *pStream;
7239     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7240
7241     /* Create the Ole10Native Stream */
7242     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
7243         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
7244
7245     if(hRes == S_OK)
7246     {
7247         /* Write info to stream */
7248         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
7249         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
7250         IStream_Release(pStream);
7251     }
7252
7253 }
7254
7255 /*************************************************************************
7256  * OLECONVERT_GetOLE10ProgID [Internal]
7257  *
7258  * Finds the ProgID (or OleTypeID) from the IStorage
7259  *
7260  * PARAMS
7261  *     pStorage        [I] The Src IStorage to get the ProgID
7262  *     strProgID       [I] the ProgID string to get
7263  *     dwSize          [I] the size of the string
7264  *
7265  * RETURNS
7266  *     Success:  S_OK
7267  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
7268  *
7269  * NOTES
7270  *     This function is used by OleConvertIStorageToOLESTREAM only.
7271  *
7272  *
7273  */
7274 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
7275 {
7276     HRESULT hRes;
7277     IStream *pStream;
7278     LARGE_INTEGER iSeekPos;
7279     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
7280     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
7281
7282     /* Open the CompObj Stream */
7283     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7284         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7285     if(hRes == S_OK)
7286     {
7287
7288         /*Get the OleType from the CompObj Stream */
7289         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
7290         iSeekPos.u.HighPart = 0;
7291
7292         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7293         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
7294         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
7295         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7296         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
7297         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
7298         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
7299
7300         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
7301         if(*dwSize > 0)
7302         {
7303             IStream_Read(pStream, strProgID, *dwSize, NULL);
7304         }
7305         IStream_Release(pStream);
7306     }
7307     else
7308     {
7309         STATSTG stat;
7310         LPOLESTR wstrProgID;
7311
7312         /* Get the OleType from the registry */
7313         REFCLSID clsid = &(stat.clsid);
7314         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
7315         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
7316         if(hRes == S_OK)
7317         {
7318             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
7319         }
7320
7321     }
7322     return hRes;
7323 }
7324
7325 /*************************************************************************
7326  * OLECONVERT_GetOle10PresData [Internal]
7327  *
7328  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
7329  *
7330  * PARAMS
7331  *     pStorage     [I] Src IStroage
7332  *     pOleStream   [I] Dest OleStream Mem Struct
7333  *
7334  * RETURNS
7335  *     Nothing
7336  *
7337  * NOTES
7338  *     This function is used by OleConvertIStorageToOLESTREAM only.
7339  *
7340  *     Memory allocated for pData must be freed by the caller
7341  *
7342  *
7343  */
7344 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7345 {
7346
7347     HRESULT hRes;
7348     IStream *pStream;
7349     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7350
7351     /* Initialize Default data for OLESTREAM */
7352     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7353     pOleStreamData[0].dwTypeID = 2;
7354     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7355     pOleStreamData[1].dwTypeID = 0;
7356     pOleStreamData[0].dwMetaFileWidth = 0;
7357     pOleStreamData[0].dwMetaFileHeight = 0;
7358     pOleStreamData[0].pData = NULL;
7359     pOleStreamData[1].pData = NULL;
7360
7361     /* Open Ole10Native Stream */
7362     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7363         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7364     if(hRes == S_OK)
7365     {
7366
7367         /* Read Size and Data */
7368         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
7369         if(pOleStreamData->dwDataLength > 0)
7370         {
7371             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
7372             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
7373         }
7374         IStream_Release(pStream);
7375     }
7376
7377 }
7378
7379
7380 /*************************************************************************
7381  * OLECONVERT_GetOle20PresData[Internal]
7382  *
7383  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
7384  *
7385  * PARAMS
7386  *     pStorage         [I] Src IStroage
7387  *     pOleStreamData   [I] Dest OleStream Mem Struct
7388  *
7389  * RETURNS
7390  *     Nothing
7391  *
7392  * NOTES
7393  *     This function is used by OleConvertIStorageToOLESTREAM only.
7394  *
7395  *     Memory allocated for pData must be freed by the caller
7396  */
7397 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
7398 {
7399     HRESULT hRes;
7400     IStream *pStream;
7401     OLECONVERT_ISTORAGE_OLEPRES olePress;
7402     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
7403
7404     /* Initialize Default data for OLESTREAM */
7405     pOleStreamData[0].dwOleID = OLESTREAM_ID;
7406     pOleStreamData[0].dwTypeID = 2;
7407     pOleStreamData[0].dwMetaFileWidth = 0;
7408     pOleStreamData[0].dwMetaFileHeight = 0;
7409     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
7410     pOleStreamData[1].dwOleID = OLESTREAM_ID;
7411     pOleStreamData[1].dwTypeID = 0;
7412     pOleStreamData[1].dwOleTypeNameLength = 0;
7413     pOleStreamData[1].strOleTypeName[0] = 0;
7414     pOleStreamData[1].dwMetaFileWidth = 0;
7415     pOleStreamData[1].dwMetaFileHeight = 0;
7416     pOleStreamData[1].pData = NULL;
7417     pOleStreamData[1].dwDataLength = 0;
7418
7419
7420     /* Open OlePress000 stream */
7421     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
7422         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
7423     if(hRes == S_OK)
7424     {
7425         LARGE_INTEGER iSeekPos;
7426         METAFILEPICT16 MetaFilePict;
7427         static const char strMetafilePictName[] = "METAFILEPICT";
7428
7429         /* Set the TypeID for a Metafile */
7430         pOleStreamData[1].dwTypeID = 5;
7431
7432         /* Set the OleTypeName to Metafile */
7433         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
7434         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
7435
7436         iSeekPos.u.HighPart = 0;
7437         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
7438
7439         /* Get Presentation Data */
7440         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
7441         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
7442         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
7443         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
7444
7445         /*Set width and Height */
7446         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
7447         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
7448         if(olePress.dwSize > 0)
7449         {
7450             /* Set Length */
7451             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
7452
7453             /* Set MetaFilePict struct */
7454             MetaFilePict.mm = 8;
7455             MetaFilePict.xExt = olePress.dwExtentX;
7456             MetaFilePict.yExt = olePress.dwExtentY;
7457             MetaFilePict.hMF = 0;
7458
7459             /* Get Metafile Data */
7460             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
7461             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
7462             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
7463         }
7464         IStream_Release(pStream);
7465     }
7466 }
7467
7468 /*************************************************************************
7469  * OleConvertOLESTREAMToIStorage [OLE32.@]
7470  *
7471  * Read info on MSDN
7472  *
7473  * TODO
7474  *      DVTARGETDEVICE paramenter is not handled
7475  *      Still unsure of some mem fields for OLE 10 Stream
7476  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7477  *      and "\001OLE" streams
7478  *
7479  */
7480 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
7481     LPOLESTREAM pOleStream,
7482     LPSTORAGE pstg,
7483     const DVTARGETDEVICE* ptd)
7484 {
7485     int i;
7486     HRESULT hRes=S_OK;
7487     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7488
7489     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7490
7491     if(ptd != NULL)
7492     {
7493         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
7494     }
7495
7496     if(pstg == NULL || pOleStream == NULL)
7497     {
7498         hRes = E_INVALIDARG;
7499     }
7500
7501     if(hRes == S_OK)
7502     {
7503         /* Load the OLESTREAM to Memory */
7504         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
7505     }
7506
7507     if(hRes == S_OK)
7508     {
7509         /* Load the OLESTREAM to Memory (part 2)*/
7510         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
7511     }
7512
7513     if(hRes == S_OK)
7514     {
7515
7516         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
7517         {
7518             /* Do we have the IStorage Data in the OLESTREAM */
7519             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
7520             {
7521                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7522                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
7523             }
7524             else
7525             {
7526                 /* It must be an original OLE 1.0 source */
7527                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7528             }
7529         }
7530         else
7531         {
7532             /* It must be an original OLE 1.0 source */
7533             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
7534         }
7535
7536         /* Create CompObj Stream if necessary */
7537         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
7538         if(hRes == S_OK)
7539         {
7540             /*Create the Ole Stream if necessary */
7541             OLECONVERT_CreateOleStream(pstg);
7542         }
7543     }
7544
7545
7546     /* Free allocated memory */
7547     for(i=0; i < 2; i++)
7548     {
7549         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7550         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
7551         pOleStreamData[i].pstrOleObjFileName = NULL;
7552     }
7553     return hRes;
7554 }
7555
7556 /*************************************************************************
7557  * OleConvertIStorageToOLESTREAM [OLE32.@]
7558  *
7559  * Read info on MSDN
7560  *
7561  * Read info on MSDN
7562  *
7563  * TODO
7564  *      Still unsure of some mem fields for OLE 10 Stream
7565  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
7566  *      and "\001OLE" streams.
7567  *
7568  */
7569 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
7570     LPSTORAGE pstg,
7571     LPOLESTREAM pOleStream)
7572 {
7573     int i;
7574     HRESULT hRes = S_OK;
7575     IStream *pStream;
7576     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
7577     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
7578
7579
7580     memset(pOleStreamData, 0, sizeof(pOleStreamData));
7581
7582     if(pstg == NULL || pOleStream == NULL)
7583     {
7584         hRes = E_INVALIDARG;
7585     }
7586     if(hRes == S_OK)
7587     {
7588         /* Get the ProgID */
7589         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
7590         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
7591     }
7592     if(hRes == S_OK)
7593     {
7594         /* Was it originally Ole10 */
7595         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
7596         if(hRes == S_OK)
7597         {
7598             IStream_Release(pStream);
7599             /* Get Presentation Data for Ole10Native */
7600             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
7601         }
7602         else
7603         {
7604             /* Get Presentation Data (OLE20) */
7605             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
7606         }
7607
7608         /* Save OLESTREAM */
7609         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
7610         if(hRes == S_OK)
7611         {
7612             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
7613         }
7614
7615     }
7616
7617     /* Free allocated memory */
7618     for(i=0; i < 2; i++)
7619     {
7620         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
7621     }
7622
7623     return hRes;
7624 }
7625
7626 /***********************************************************************
7627  *              GetConvertStg (OLE32.@)
7628  */
7629 HRESULT WINAPI GetConvertStg(IStorage *stg) {
7630     FIXME("unimplemented stub!\n");
7631     return E_FAIL;
7632 }
7633
7634 /******************************************************************************
7635  * StgIsStorageFile [OLE32.@]
7636  */
7637 HRESULT WINAPI
7638 StgIsStorageFile(LPCOLESTR fn)
7639 {
7640         HANDLE          hf;
7641         BYTE            magic[8];
7642         DWORD           bytes_read;
7643
7644         TRACE("(\'%s\')\n", debugstr_w(fn));
7645         hf = CreateFileW(fn, GENERIC_READ,
7646                          FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
7647                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
7648
7649         if (hf == INVALID_HANDLE_VALUE)
7650                 return STG_E_FILENOTFOUND;
7651
7652         if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
7653         {
7654                 WARN(" unable to read file\n");
7655                 CloseHandle(hf);
7656                 return S_FALSE;
7657         }
7658
7659         CloseHandle(hf);
7660
7661         if (bytes_read != 8) {
7662                 WARN(" too short\n");
7663                 return S_FALSE;
7664         }
7665
7666         if (!memcmp(magic,STORAGE_magic,8)) {
7667                 WARN(" -> YES\n");
7668                 return S_OK;
7669         }
7670
7671         WARN(" -> Invalid header.\n");
7672         return S_FALSE;
7673 }