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