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