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