ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

storage32.c
Go to the documentation of this file.
00001 /*
00002  * Compound Storage (32 bit version)
00003  * Storage implementation
00004  *
00005  * This file contains the compound file implementation
00006  * of the storage interface.
00007  *
00008  * Copyright 1999 Francis Beaudet
00009  * Copyright 1999 Sylvain St-Germain
00010  * Copyright 1999 Thuy Nguyen
00011  * Copyright 2005 Mike McCormack
00012  *
00013  * This library is free software; you can redistribute it and/or
00014  * modify it under the terms of the GNU Lesser General Public
00015  * License as published by the Free Software Foundation; either
00016  * version 2.1 of the License, or (at your option) any later version.
00017  *
00018  * This library is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  * Lesser General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU Lesser General Public
00024  * License along with this library; if not, write to the Free Software
00025  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00026  *
00027  * NOTES
00028  *  The compound file implementation of IStorage used for create
00029  *  and manage substorages and streams within a storage object
00030  *  residing in a compound file object.
00031  */
00032 
00033 #include <assert.h>
00034 #include <stdarg.h>
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 
00039 #define COBJMACROS
00040 #define NONAMELESSUNION
00041 #define NONAMELESSSTRUCT
00042 
00043 #include "windef.h"
00044 #include "winbase.h"
00045 #include "winnls.h"
00046 #include "winuser.h"
00047 #include "wine/unicode.h"
00048 #include "wine/debug.h"
00049 
00050 #include "storage32.h"
00051 #include "ole2.h"      /* For Write/ReadClassStm */
00052 
00053 #include "winreg.h"
00054 #include "wine/wingdi16.h"
00055 
00056 WINE_DEFAULT_DEBUG_CHANNEL(storage);
00057 
00058 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
00059 #define OLESTREAM_ID 0x501
00060 #define OLESTREAM_MAX_STR_LEN 255
00061 
00062 /*
00063  * These are signatures to detect the type of Document file.
00064  */
00065 static const BYTE STORAGE_magic[8]    ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
00066 static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
00067 
00068 static const char rootEntryName[] = "Root Entry";
00069 
00070 /****************************************************************************
00071  * Storage32InternalImpl definitions.
00072  *
00073  * Definition of the implementation structure for the IStorage32 interface.
00074  * This one implements the IStorage32 interface for storage that are
00075  * inside another storage.
00076  */
00077 struct StorageInternalImpl
00078 {
00079   struct StorageBaseImpl base;
00080 
00081   /*
00082    * Entry in the parent's stream tracking list
00083    */
00084   struct list ParentListEntry;
00085 
00086   StorageBaseImpl *parentStorage;
00087 };
00088 typedef struct StorageInternalImpl StorageInternalImpl;
00089 
00090 static const IStorageVtbl TransactedSnapshotImpl_Vtbl;
00091 static const IStorageVtbl Storage32InternalImpl_Vtbl;
00092 
00093 /* Method definitions for the Storage32InternalImpl class. */
00094 static StorageInternalImpl* StorageInternalImpl_Construct(StorageBaseImpl* parentStorage,
00095                                                           DWORD openFlags, DirRef storageDirEntry);
00096 static void StorageImpl_Destroy(StorageBaseImpl* iface);
00097 static void StorageImpl_Invalidate(StorageBaseImpl* iface);
00098 static HRESULT StorageImpl_Flush(StorageBaseImpl* iface);
00099 static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
00100 static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, const void* buffer);
00101 static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
00102 static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
00103 static void StorageImpl_SaveFileHeader(StorageImpl* This);
00104 
00105 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex);
00106 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
00107 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex);
00108 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex);
00109 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex);
00110 
00111 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This);
00112 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This);
00113 static ULONG BlockChainStream_GetCount(BlockChainStream* This);
00114 
00115 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
00116 static ULONG SmallBlockChainStream_GetHeadOfChain(SmallBlockChainStream* This);
00117 static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
00118     ULONG blockIndex, ULONG offset, DWORD value);
00119 static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl*  This,
00120     ULONG blockIndex, ULONG offset, DWORD* value);
00121 
00122 static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry);
00123 static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry);
00124 
00125 typedef struct TransactedDirEntry
00126 {
00127   /* If applicable, a reference to the original DirEntry in the transacted
00128    * parent. If this is a newly-created entry, DIRENTRY_NULL. */
00129   DirRef transactedParentEntry;
00130 
00131   /* True if this entry is being used. */
00132   int inuse;
00133 
00134   /* True if data is up to date. */
00135   int read;
00136 
00137   /* True if this entry has been modified. */
00138   int dirty;
00139 
00140   /* True if this entry's stream has been modified. */
00141   int stream_dirty;
00142 
00143   /* True if this entry has been deleted in the transacted storage, but the
00144    * delete has not yet been committed. */
00145   int deleted;
00146 
00147   /* If this entry's stream has been modified, a reference to where the stream
00148    * is stored in the snapshot file. */
00149   DirRef stream_entry;
00150 
00151   /* This directory entry's data, including any changes that have been made. */
00152   DirEntry data;
00153 
00154   /* A reference to the parent of this node. This is only valid while we are
00155    * committing changes. */
00156   DirRef parent;
00157 
00158   /* A reference to a newly-created entry in the transacted parent. This is
00159    * always equal to transactedParentEntry except when committing changes. */
00160   DirRef newTransactedParentEntry;
00161 } TransactedDirEntry;
00162 
00163 /****************************************************************************
00164  * Transacted storage object.
00165  */
00166 typedef struct TransactedSnapshotImpl
00167 {
00168   struct StorageBaseImpl base;
00169 
00170   /*
00171    * Modified streams are temporarily saved to the scratch file.
00172    */
00173   StorageBaseImpl *scratch;
00174 
00175   /* The directory structure is kept here, so that we can track how these
00176    * entries relate to those in the parent storage. */
00177   TransactedDirEntry *entries;
00178   ULONG entries_size;
00179   ULONG firstFreeEntry;
00180 
00181   /*
00182    * Changes are committed to the transacted parent.
00183    */
00184   StorageBaseImpl *transactedParent;
00185 } TransactedSnapshotImpl;
00186 
00187 /* Generic function to create a transacted wrapper for a direct storage object. */
00188 static HRESULT Storage_ConstructTransacted(StorageBaseImpl* parent, StorageBaseImpl** result);
00189 
00190 /* OLESTREAM memory structure to use for Get and Put Routines */
00191 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
00192 typedef struct
00193 {
00194     DWORD dwOleID;
00195     DWORD dwTypeID;
00196     DWORD dwOleTypeNameLength;
00197     CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
00198     CHAR  *pstrOleObjFileName;
00199     DWORD dwOleObjFileNameLength;
00200     DWORD dwMetaFileWidth;
00201     DWORD dwMetaFileHeight;
00202     CHAR  strUnknown[8]; /* don't know what this 8 byte information in OLE stream is. */
00203     DWORD dwDataLength;
00204     BYTE *pData;
00205 }OLECONVERT_OLESTREAM_DATA;
00206 
00207 /* CompObj Stream structure */
00208 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
00209 typedef struct
00210 {
00211     BYTE byUnknown1[12];
00212     CLSID clsid;
00213     DWORD dwCLSIDNameLength;
00214     CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
00215     DWORD dwOleTypeNameLength;
00216     CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
00217     DWORD dwProgIDNameLength;
00218     CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
00219     BYTE byUnknown2[16];
00220 }OLECONVERT_ISTORAGE_COMPOBJ;
00221 
00222 
00223 /* Ole Presentation Stream structure */
00224 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
00225 typedef struct
00226 {
00227     BYTE byUnknown1[28];
00228     DWORD dwExtentX;
00229     DWORD dwExtentY;
00230     DWORD dwSize;
00231     BYTE *pData;
00232 }OLECONVERT_ISTORAGE_OLEPRES;
00233 
00234 
00235 
00236 /***********************************************************************
00237  * Forward declaration of internal functions used by the method DestroyElement
00238  */
00239 static HRESULT deleteStorageContents(
00240   StorageBaseImpl *parentStorage,
00241   DirRef       indexToDelete,
00242   DirEntry     entryDataToDelete);
00243 
00244 static HRESULT deleteStreamContents(
00245   StorageBaseImpl *parentStorage,
00246   DirRef        indexToDelete,
00247   DirEntry      entryDataToDelete);
00248 
00249 static HRESULT removeFromTree(
00250   StorageBaseImpl *This,
00251   DirRef        parentStorageIndex,
00252   DirRef        deletedIndex);
00253 
00254 /***********************************************************************
00255  * Declaration of the functions used to manipulate DirEntry
00256  */
00257 
00258 static HRESULT insertIntoTree(
00259   StorageBaseImpl *This,
00260   DirRef        parentStorageIndex,
00261   DirRef        newEntryIndex);
00262 
00263 static LONG entryNameCmp(
00264     const OLECHAR *name1,
00265     const OLECHAR *name2);
00266 
00267 static DirRef findElement(
00268     StorageBaseImpl *storage,
00269     DirRef storageEntry,
00270     const OLECHAR *name,
00271     DirEntry *data);
00272 
00273 static HRESULT findTreeParent(
00274     StorageBaseImpl *storage,
00275     DirRef storageEntry,
00276     const OLECHAR *childName,
00277     DirEntry *parentData,
00278     DirRef *parentEntry,
00279     ULONG *relation);
00280 
00281 /***********************************************************************
00282  * Declaration of miscellaneous functions...
00283  */
00284 static HRESULT validateSTGM(DWORD stgmValue);
00285 
00286 static DWORD GetShareModeFromSTGM(DWORD stgm);
00287 static DWORD GetAccessModeFromSTGM(DWORD stgm);
00288 static DWORD GetCreationModeFromSTGM(DWORD stgm);
00289 
00290 extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
00291 
00292 
00293 /****************************************************************************
00294  * IEnumSTATSTGImpl definitions.
00295  *
00296  * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
00297  * This class allows iterating through the content of a storage and to find
00298  * specific items inside it.
00299  */
00300 struct IEnumSTATSTGImpl
00301 {
00302   IEnumSTATSTG   IEnumSTATSTG_iface;
00303 
00304   LONG           ref;                   /* Reference count */
00305   StorageBaseImpl* parentStorage;         /* Reference to the parent storage */
00306   DirRef         storageDirEntry;     /* Directory entry of the storage to enumerate */
00307 
00308   WCHAR          name[DIRENTRY_NAME_MAX_LEN]; /* The most recent name visited */
00309 };
00310 
00311 static inline IEnumSTATSTGImpl *impl_from_IEnumSTATSTG(IEnumSTATSTG *iface)
00312 {
00313   return CONTAINING_RECORD(iface, IEnumSTATSTGImpl, IEnumSTATSTG_iface);
00314 }
00315 
00316 
00317 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageBaseImpl* This, DirRef storageDirEntry);
00318 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This);
00319 
00320 /************************************************************************
00321 ** Block Functions
00322 */
00323 
00324 static ULONG StorageImpl_GetBigBlockOffset(StorageImpl* This, ULONG index)
00325 {
00326     return (index+1) * This->bigBlockSize;
00327 }
00328 
00329 /************************************************************************
00330 ** Storage32BaseImpl implementation
00331 */
00332 static HRESULT StorageImpl_ReadAt(StorageImpl* This,
00333   ULARGE_INTEGER offset,
00334   void*          buffer,
00335   ULONG          size,
00336   ULONG*         bytesRead)
00337 {
00338     return ILockBytes_ReadAt(This->lockBytes,offset,buffer,size,bytesRead);
00339 }
00340 
00341 static HRESULT StorageImpl_WriteAt(StorageImpl* This,
00342   ULARGE_INTEGER offset,
00343   const void*    buffer,
00344   const ULONG    size,
00345   ULONG*         bytesWritten)
00346 {
00347     return ILockBytes_WriteAt(This->lockBytes,offset,buffer,size,bytesWritten);
00348 }
00349 
00350 /************************************************************************
00351  * Storage32BaseImpl_QueryInterface (IUnknown)
00352  *
00353  * This method implements the common QueryInterface for all IStorage32
00354  * implementations contained in this file.
00355  *
00356  * See Windows documentation for more details on IUnknown methods.
00357  */
00358 static HRESULT WINAPI StorageBaseImpl_QueryInterface(
00359   IStorage*        iface,
00360   REFIID             riid,
00361   void**             ppvObject)
00362 {
00363   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00364 
00365   if ( (This==0) || (ppvObject==0) )
00366     return E_INVALIDARG;
00367 
00368   *ppvObject = 0;
00369 
00370   if (IsEqualGUID(&IID_IUnknown, riid) ||
00371       IsEqualGUID(&IID_IStorage, riid))
00372   {
00373     *ppvObject = This;
00374   }
00375   else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
00376   {
00377     *ppvObject = &This->pssVtbl;
00378   }
00379 
00380   if ((*ppvObject)==0)
00381     return E_NOINTERFACE;
00382 
00383   IStorage_AddRef(iface);
00384 
00385   return S_OK;
00386 }
00387 
00388 /************************************************************************
00389  * Storage32BaseImpl_AddRef (IUnknown)
00390  *
00391  * This method implements the common AddRef for all IStorage32
00392  * implementations contained in this file.
00393  *
00394  * See Windows documentation for more details on IUnknown methods.
00395  */
00396 static ULONG WINAPI StorageBaseImpl_AddRef(
00397             IStorage* iface)
00398 {
00399   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00400   ULONG ref = InterlockedIncrement(&This->ref);
00401 
00402   TRACE("(%p) AddRef to %d\n", This, ref);
00403 
00404   return ref;
00405 }
00406 
00407 /************************************************************************
00408  * Storage32BaseImpl_Release (IUnknown)
00409  *
00410  * This method implements the common Release for all IStorage32
00411  * implementations contained in this file.
00412  *
00413  * See Windows documentation for more details on IUnknown methods.
00414  */
00415 static ULONG WINAPI StorageBaseImpl_Release(
00416       IStorage* iface)
00417 {
00418   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00419 
00420   ULONG ref = InterlockedDecrement(&This->ref);
00421 
00422   TRACE("(%p) ReleaseRef to %d\n", This, ref);
00423 
00424   if (ref == 0)
00425   {
00426     /*
00427      * Since we are using a system of base-classes, we want to call the
00428      * destructor of the appropriate derived class. To do this, we are
00429      * using virtual functions to implement the destructor.
00430      */
00431     StorageBaseImpl_Destroy(This);
00432   }
00433 
00434   return ref;
00435 }
00436 
00437 /************************************************************************
00438  * Storage32BaseImpl_OpenStream (IStorage)
00439  *
00440  * This method will open the specified stream object from the current storage.
00441  *
00442  * See Windows documentation for more details on IStorage methods.
00443  */
00444 static HRESULT WINAPI StorageBaseImpl_OpenStream(
00445   IStorage*        iface,
00446   const OLECHAR*   pwcsName,  /* [string][in] */
00447   void*            reserved1, /* [unique][in] */
00448   DWORD            grfMode,   /* [in]  */
00449   DWORD            reserved2, /* [in]  */
00450   IStream**        ppstm)     /* [out] */
00451 {
00452   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00453   StgStreamImpl*    newStream;
00454   DirEntry          currentEntry;
00455   DirRef            streamEntryRef;
00456   HRESULT           res = STG_E_UNKNOWN;
00457 
00458   TRACE("(%p, %s, %p, %x, %d, %p)\n",
00459     iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
00460 
00461   if ( (pwcsName==NULL) || (ppstm==0) )
00462   {
00463     res = E_INVALIDARG;
00464     goto end;
00465   }
00466 
00467   *ppstm = NULL;
00468 
00469   if ( FAILED( validateSTGM(grfMode) ) ||
00470        STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
00471   {
00472     res = STG_E_INVALIDFLAG;
00473     goto end;
00474   }
00475 
00476   /*
00477    * As documented.
00478    */
00479   if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) )
00480   {
00481     res = STG_E_INVALIDFUNCTION;
00482     goto end;
00483   }
00484 
00485   if (This->reverted)
00486   {
00487     res = STG_E_REVERTED;
00488     goto end;
00489   }
00490 
00491   /*
00492    * Check that we're compatible with the parent's storage mode, but
00493    * only if we are not in transacted mode
00494    */
00495   if(!(This->openFlags & STGM_TRANSACTED)) {
00496     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
00497     {
00498       res = STG_E_INVALIDFLAG;
00499       goto end;
00500     }
00501   }
00502 
00503   /*
00504    * Search for the element with the given name
00505    */
00506   streamEntryRef = findElement(
00507     This,
00508     This->storageDirEntry,
00509     pwcsName,
00510     &currentEntry);
00511 
00512   /*
00513    * If it was found, construct the stream object and return a pointer to it.
00514    */
00515   if ( (streamEntryRef!=DIRENTRY_NULL) &&
00516        (currentEntry.stgType==STGTY_STREAM) )
00517   {
00518     if (StorageBaseImpl_IsStreamOpen(This, streamEntryRef))
00519     {
00520       /* A single stream cannot be opened a second time. */
00521       res = STG_E_ACCESSDENIED;
00522       goto end;
00523     }
00524 
00525     newStream = StgStreamImpl_Construct(This, grfMode, streamEntryRef);
00526 
00527     if (newStream!=0)
00528     {
00529       newStream->grfMode = grfMode;
00530       *ppstm = (IStream*)newStream;
00531 
00532       IStream_AddRef(*ppstm);
00533 
00534       res = S_OK;
00535       goto end;
00536     }
00537 
00538     res = E_OUTOFMEMORY;
00539     goto end;
00540   }
00541 
00542   res = STG_E_FILENOTFOUND;
00543 
00544 end:
00545   if (res == S_OK)
00546     TRACE("<-- IStream %p\n", *ppstm);
00547   TRACE("<-- %08x\n", res);
00548   return res;
00549 }
00550 
00551 /************************************************************************
00552  * Storage32BaseImpl_OpenStorage (IStorage)
00553  *
00554  * This method will open a new storage object from the current storage.
00555  *
00556  * See Windows documentation for more details on IStorage methods.
00557  */
00558 static HRESULT WINAPI StorageBaseImpl_OpenStorage(
00559   IStorage*        iface,
00560   const OLECHAR*   pwcsName,      /* [string][unique][in] */
00561   IStorage*        pstgPriority,  /* [unique][in] */
00562   DWORD            grfMode,       /* [in] */
00563   SNB              snbExclude,    /* [unique][in] */
00564   DWORD            reserved,      /* [in] */
00565   IStorage**       ppstg)         /* [out] */
00566 {
00567   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00568   StorageInternalImpl*   newStorage;
00569   StorageBaseImpl*       newTransactedStorage;
00570   DirEntry               currentEntry;
00571   DirRef                 storageEntryRef;
00572   HRESULT                res = STG_E_UNKNOWN;
00573 
00574   TRACE("(%p, %s, %p, %x, %p, %d, %p)\n",
00575     iface, debugstr_w(pwcsName), pstgPriority,
00576     grfMode, snbExclude, reserved, ppstg);
00577 
00578   if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
00579   {
00580     res = E_INVALIDARG;
00581     goto end;
00582   }
00583 
00584   if (This->openFlags & STGM_SIMPLE)
00585   {
00586     res = STG_E_INVALIDFUNCTION;
00587     goto end;
00588   }
00589 
00590   /* as documented */
00591   if (snbExclude != NULL)
00592   {
00593     res = STG_E_INVALIDPARAMETER;
00594     goto end;
00595   }
00596 
00597   if ( FAILED( validateSTGM(grfMode) ))
00598   {
00599     res = STG_E_INVALIDFLAG;
00600     goto end;
00601   }
00602 
00603   /*
00604    * As documented.
00605    */
00606   if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
00607         (grfMode & STGM_DELETEONRELEASE) ||
00608         (grfMode & STGM_PRIORITY) )
00609   {
00610     res = STG_E_INVALIDFUNCTION;
00611     goto end;
00612   }
00613 
00614   if (This->reverted)
00615     return STG_E_REVERTED;
00616 
00617   /*
00618    * Check that we're compatible with the parent's storage mode,
00619    * but only if we are not transacted
00620    */
00621   if(!(This->openFlags & STGM_TRANSACTED)) {
00622     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
00623     {
00624       res = STG_E_ACCESSDENIED;
00625       goto end;
00626     }
00627   }
00628 
00629   *ppstg = NULL;
00630 
00631   storageEntryRef = findElement(
00632                          This,
00633                          This->storageDirEntry,
00634                          pwcsName,
00635                          &currentEntry);
00636 
00637   if ( (storageEntryRef!=DIRENTRY_NULL) &&
00638        (currentEntry.stgType==STGTY_STORAGE) )
00639   {
00640     if (StorageBaseImpl_IsStorageOpen(This, storageEntryRef))
00641     {
00642       /* A single storage cannot be opened a second time. */
00643       res = STG_E_ACCESSDENIED;
00644       goto end;
00645     }
00646 
00647     newStorage = StorageInternalImpl_Construct(
00648                    This,
00649                    grfMode,
00650                    storageEntryRef);
00651 
00652     if (newStorage != 0)
00653     {
00654       if (grfMode & STGM_TRANSACTED)
00655       {
00656         res = Storage_ConstructTransacted(&newStorage->base, &newTransactedStorage);
00657 
00658         if (FAILED(res))
00659         {
00660           HeapFree(GetProcessHeap(), 0, newStorage);
00661           goto end;
00662         }
00663 
00664         *ppstg = (IStorage*)newTransactedStorage;
00665       }
00666       else
00667       {
00668         *ppstg = (IStorage*)newStorage;
00669       }
00670 
00671       list_add_tail(&This->storageHead, &newStorage->ParentListEntry);
00672 
00673       res = S_OK;
00674       goto end;
00675     }
00676 
00677     res = STG_E_INSUFFICIENTMEMORY;
00678     goto end;
00679   }
00680 
00681   res = STG_E_FILENOTFOUND;
00682 
00683 end:
00684   TRACE("<-- %08x\n", res);
00685   return res;
00686 }
00687 
00688 /************************************************************************
00689  * Storage32BaseImpl_EnumElements (IStorage)
00690  *
00691  * This method will create an enumerator object that can be used to
00692  * retrieve information about all the elements in the storage object.
00693  *
00694  * See Windows documentation for more details on IStorage methods.
00695  */
00696 static HRESULT WINAPI StorageBaseImpl_EnumElements(
00697   IStorage*       iface,
00698   DWORD           reserved1, /* [in] */
00699   void*           reserved2, /* [size_is][unique][in] */
00700   DWORD           reserved3, /* [in] */
00701   IEnumSTATSTG**  ppenum)    /* [out] */
00702 {
00703   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00704   IEnumSTATSTGImpl* newEnum;
00705 
00706   TRACE("(%p, %d, %p, %d, %p)\n",
00707     iface, reserved1, reserved2, reserved3, ppenum);
00708 
00709   if ( (This==0) || (ppenum==0))
00710     return E_INVALIDARG;
00711 
00712   if (This->reverted)
00713     return STG_E_REVERTED;
00714 
00715   newEnum = IEnumSTATSTGImpl_Construct(
00716               This,
00717               This->storageDirEntry);
00718 
00719   if (newEnum!=0)
00720   {
00721     *ppenum = &newEnum->IEnumSTATSTG_iface;
00722 
00723     IEnumSTATSTG_AddRef(*ppenum);
00724 
00725     return S_OK;
00726   }
00727 
00728   return E_OUTOFMEMORY;
00729 }
00730 
00731 /************************************************************************
00732  * Storage32BaseImpl_Stat (IStorage)
00733  *
00734  * This method will retrieve information about this storage object.
00735  *
00736  * See Windows documentation for more details on IStorage methods.
00737  */
00738 static HRESULT WINAPI StorageBaseImpl_Stat(
00739   IStorage*        iface,
00740   STATSTG*         pstatstg,     /* [out] */
00741   DWORD            grfStatFlag)  /* [in] */
00742 {
00743   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00744   DirEntry       currentEntry;
00745   HRESULT        res = STG_E_UNKNOWN;
00746 
00747   TRACE("(%p, %p, %x)\n",
00748     iface, pstatstg, grfStatFlag);
00749 
00750   if ( (This==0) || (pstatstg==0))
00751   {
00752     res = E_INVALIDARG;
00753     goto end;
00754   }
00755 
00756   if (This->reverted)
00757   {
00758     res = STG_E_REVERTED;
00759     goto end;
00760   }
00761 
00762   res = StorageBaseImpl_ReadDirEntry(
00763                     This,
00764                     This->storageDirEntry,
00765                     &currentEntry);
00766 
00767   if (SUCCEEDED(res))
00768   {
00769     StorageUtl_CopyDirEntryToSTATSTG(
00770       This,
00771       pstatstg,
00772       &currentEntry,
00773       grfStatFlag);
00774 
00775     pstatstg->grfMode = This->openFlags;
00776     pstatstg->grfStateBits = This->stateBits;
00777   }
00778 
00779 end:
00780   if (res == S_OK)
00781   {
00782     TRACE("<-- STATSTG: pwcsName: %s, type: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
00783   }
00784   TRACE("<-- %08x\n", res);
00785   return res;
00786 }
00787 
00788 /************************************************************************
00789  * Storage32BaseImpl_RenameElement (IStorage)
00790  *
00791  * This method will rename the specified element.
00792  *
00793  * See Windows documentation for more details on IStorage methods.
00794  */
00795 static HRESULT WINAPI StorageBaseImpl_RenameElement(
00796             IStorage*        iface,
00797             const OLECHAR*   pwcsOldName,  /* [in] */
00798             const OLECHAR*   pwcsNewName)  /* [in] */
00799 {
00800   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00801   DirEntry          currentEntry;
00802   DirRef            currentEntryRef;
00803 
00804   TRACE("(%p, %s, %s)\n",
00805     iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
00806 
00807   if (This->reverted)
00808     return STG_E_REVERTED;
00809 
00810   currentEntryRef = findElement(This,
00811                                    This->storageDirEntry,
00812                                    pwcsNewName,
00813                                    &currentEntry);
00814 
00815   if (currentEntryRef != DIRENTRY_NULL)
00816   {
00817     /*
00818      * There is already an element with the new name
00819      */
00820     return STG_E_FILEALREADYEXISTS;
00821   }
00822 
00823   /*
00824    * Search for the old element name
00825    */
00826   currentEntryRef = findElement(This,
00827                                    This->storageDirEntry,
00828                                    pwcsOldName,
00829                                    &currentEntry);
00830 
00831   if (currentEntryRef != DIRENTRY_NULL)
00832   {
00833     if (StorageBaseImpl_IsStreamOpen(This, currentEntryRef) ||
00834         StorageBaseImpl_IsStorageOpen(This, currentEntryRef))
00835     {
00836       WARN("Element is already open; cannot rename.\n");
00837       return STG_E_ACCESSDENIED;
00838     }
00839 
00840     /* Remove the element from its current position in the tree */
00841     removeFromTree(This, This->storageDirEntry,
00842         currentEntryRef);
00843 
00844     /* Change the name of the element */
00845     strcpyW(currentEntry.name, pwcsNewName);
00846 
00847     /* Delete any sibling links */
00848     currentEntry.leftChild = DIRENTRY_NULL;
00849     currentEntry.rightChild = DIRENTRY_NULL;
00850 
00851     StorageBaseImpl_WriteDirEntry(This, currentEntryRef,
00852         &currentEntry);
00853 
00854     /* Insert the element in a new position in the tree */
00855     insertIntoTree(This, This->storageDirEntry,
00856         currentEntryRef);
00857   }
00858   else
00859   {
00860     /*
00861      * There is no element with the old name
00862      */
00863     return STG_E_FILENOTFOUND;
00864   }
00865 
00866   return StorageBaseImpl_Flush(This);
00867 }
00868 
00869 /************************************************************************
00870  * Storage32BaseImpl_CreateStream (IStorage)
00871  *
00872  * This method will create a stream object within this storage
00873  *
00874  * See Windows documentation for more details on IStorage methods.
00875  */
00876 static HRESULT WINAPI StorageBaseImpl_CreateStream(
00877             IStorage*        iface,
00878             const OLECHAR*   pwcsName,  /* [string][in] */
00879             DWORD            grfMode,   /* [in] */
00880             DWORD            reserved1, /* [in] */
00881             DWORD            reserved2, /* [in] */
00882             IStream**        ppstm)     /* [out] */
00883 {
00884   StorageBaseImpl *This = (StorageBaseImpl *)iface;
00885   StgStreamImpl*    newStream;
00886   DirEntry          currentEntry, newStreamEntry;
00887   DirRef            currentEntryRef, newStreamEntryRef;
00888   HRESULT hr;
00889 
00890   TRACE("(%p, %s, %x, %d, %d, %p)\n",
00891     iface, debugstr_w(pwcsName), grfMode,
00892     reserved1, reserved2, ppstm);
00893 
00894   if (ppstm == 0)
00895     return STG_E_INVALIDPOINTER;
00896 
00897   if (pwcsName == 0)
00898     return STG_E_INVALIDNAME;
00899 
00900   if (reserved1 || reserved2)
00901     return STG_E_INVALIDPARAMETER;
00902 
00903   if ( FAILED( validateSTGM(grfMode) ))
00904     return STG_E_INVALIDFLAG;
00905 
00906   if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) 
00907     return STG_E_INVALIDFLAG;
00908 
00909   if (This->reverted)
00910     return STG_E_REVERTED;
00911 
00912   /*
00913    * As documented.
00914    */
00915   if ((grfMode & STGM_DELETEONRELEASE) ||
00916       (grfMode & STGM_TRANSACTED))
00917     return STG_E_INVALIDFUNCTION;
00918 
00919   /*
00920    * Don't worry about permissions in transacted mode, as we can always write
00921    * changes; we just can't always commit them.
00922    */
00923   if(!(This->openFlags & STGM_TRANSACTED)) {
00924     /* Can't create a stream on read-only storage */
00925     if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
00926       return STG_E_ACCESSDENIED;
00927 
00928     /* Can't create a stream with greater access than the parent. */
00929     if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
00930       return STG_E_ACCESSDENIED;
00931   }
00932 
00933   if(This->openFlags & STGM_SIMPLE)
00934     if(grfMode & STGM_CREATE) return STG_E_INVALIDFLAG;
00935 
00936   *ppstm = 0;
00937 
00938   currentEntryRef = findElement(This,
00939                                    This->storageDirEntry,
00940                                    pwcsName,
00941                                    &currentEntry);
00942 
00943   if (currentEntryRef != DIRENTRY_NULL)
00944   {
00945     /*
00946      * An element with this name already exists
00947      */
00948     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
00949     {
00950       IStorage_DestroyElement(iface, pwcsName);
00951     }
00952     else
00953       return STG_E_FILEALREADYEXISTS;
00954   }
00955 
00956   /*
00957    * memset the empty entry
00958    */
00959   memset(&newStreamEntry, 0, sizeof(DirEntry));
00960 
00961   newStreamEntry.sizeOfNameString =
00962       ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
00963 
00964   if (newStreamEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN)
00965     return STG_E_INVALIDNAME;
00966 
00967   strcpyW(newStreamEntry.name, pwcsName);
00968 
00969   newStreamEntry.stgType       = STGTY_STREAM;
00970   newStreamEntry.startingBlock = BLOCK_END_OF_CHAIN;
00971   newStreamEntry.size.u.LowPart  = 0;
00972   newStreamEntry.size.u.HighPart = 0;
00973 
00974   newStreamEntry.leftChild        = DIRENTRY_NULL;
00975   newStreamEntry.rightChild       = DIRENTRY_NULL;
00976   newStreamEntry.dirRootEntry     = DIRENTRY_NULL;
00977 
00978   /* call CoFileTime to get the current time
00979   newStreamEntry.ctime
00980   newStreamEntry.mtime
00981   */
00982 
00983   /*  newStreamEntry.clsid */
00984 
00985   /*
00986    * Create an entry with the new data
00987    */
00988   hr = StorageBaseImpl_CreateDirEntry(This, &newStreamEntry, &newStreamEntryRef);
00989   if (FAILED(hr))
00990     return hr;
00991 
00992   /*
00993    * Insert the new entry in the parent storage's tree.
00994    */
00995   hr = insertIntoTree(
00996     This,
00997     This->storageDirEntry,
00998     newStreamEntryRef);
00999   if (FAILED(hr))
01000   {
01001     StorageBaseImpl_DestroyDirEntry(This, newStreamEntryRef);
01002     return hr;
01003   }
01004 
01005   /*
01006    * Open the stream to return it.
01007    */
01008   newStream = StgStreamImpl_Construct(This, grfMode, newStreamEntryRef);
01009 
01010   if (newStream != 0)
01011   {
01012     *ppstm = (IStream*)newStream;
01013 
01014     IStream_AddRef(*ppstm);
01015   }
01016   else
01017   {
01018     return STG_E_INSUFFICIENTMEMORY;
01019   }
01020 
01021   return StorageBaseImpl_Flush(This);
01022 }
01023 
01024 /************************************************************************
01025  * Storage32BaseImpl_SetClass (IStorage)
01026  *
01027  * This method will write the specified CLSID in the directory entry of this
01028  * storage.
01029  *
01030  * See Windows documentation for more details on IStorage methods.
01031  */
01032 static HRESULT WINAPI StorageBaseImpl_SetClass(
01033   IStorage*        iface,
01034   REFCLSID         clsid) /* [in] */
01035 {
01036   StorageBaseImpl *This = (StorageBaseImpl *)iface;
01037   HRESULT hRes;
01038   DirEntry currentEntry;
01039 
01040   TRACE("(%p, %p)\n", iface, clsid);
01041 
01042   if (This->reverted)
01043     return STG_E_REVERTED;
01044 
01045   hRes = StorageBaseImpl_ReadDirEntry(This,
01046                                       This->storageDirEntry,
01047                                       &currentEntry);
01048   if (SUCCEEDED(hRes))
01049   {
01050     currentEntry.clsid = *clsid;
01051 
01052     hRes = StorageBaseImpl_WriteDirEntry(This,
01053                                          This->storageDirEntry,
01054                                          &currentEntry);
01055   }
01056 
01057   if (SUCCEEDED(hRes))
01058     hRes = StorageBaseImpl_Flush(This);
01059 
01060   return hRes;
01061 }
01062 
01063 /************************************************************************
01064 ** Storage32Impl implementation
01065 */
01066 
01067 /************************************************************************
01068  * Storage32BaseImpl_CreateStorage (IStorage)
01069  *
01070  * This method will create the storage object within the provided storage.
01071  *
01072  * See Windows documentation for more details on IStorage methods.
01073  */
01074 static HRESULT WINAPI StorageBaseImpl_CreateStorage(
01075   IStorage*      iface,
01076   const OLECHAR  *pwcsName, /* [string][in] */
01077   DWORD            grfMode,   /* [in] */
01078   DWORD            reserved1, /* [in] */
01079   DWORD            reserved2, /* [in] */
01080   IStorage       **ppstg)   /* [out] */
01081 {
01082   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
01083 
01084   DirEntry         currentEntry;
01085   DirEntry         newEntry;
01086   DirRef           currentEntryRef;
01087   DirRef           newEntryRef;
01088   HRESULT          hr;
01089 
01090   TRACE("(%p, %s, %x, %d, %d, %p)\n",
01091     iface, debugstr_w(pwcsName), grfMode,
01092     reserved1, reserved2, ppstg);
01093 
01094   if (ppstg == 0)
01095     return STG_E_INVALIDPOINTER;
01096 
01097   if (This->openFlags & STGM_SIMPLE)
01098   {
01099     return STG_E_INVALIDFUNCTION;
01100   }
01101 
01102   if (pwcsName == 0)
01103     return STG_E_INVALIDNAME;
01104 
01105   *ppstg = NULL;
01106 
01107   if ( FAILED( validateSTGM(grfMode) ) ||
01108        (grfMode & STGM_DELETEONRELEASE) )
01109   {
01110     WARN("bad grfMode: 0x%x\n", grfMode);
01111     return STG_E_INVALIDFLAG;
01112   }
01113 
01114   if (This->reverted)
01115     return STG_E_REVERTED;
01116 
01117   /*
01118    * Check that we're compatible with the parent's storage mode
01119    */
01120   if ( !(This->openFlags & STGM_TRANSACTED) &&
01121        STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
01122   {
01123     WARN("access denied\n");
01124     return STG_E_ACCESSDENIED;
01125   }
01126 
01127   currentEntryRef = findElement(This,
01128                                    This->storageDirEntry,
01129                                    pwcsName,
01130                                    &currentEntry);
01131 
01132   if (currentEntryRef != DIRENTRY_NULL)
01133   {
01134     /*
01135      * An element with this name already exists
01136      */
01137     if (STGM_CREATE_MODE(grfMode) == STGM_CREATE &&
01138         ((This->openFlags & STGM_TRANSACTED) ||
01139          STGM_ACCESS_MODE(This->openFlags) != STGM_READ))
01140     {
01141       hr = IStorage_DestroyElement(iface, pwcsName);
01142       if (FAILED(hr))
01143         return hr;
01144     }
01145     else
01146     {
01147       WARN("file already exists\n");
01148       return STG_E_FILEALREADYEXISTS;
01149     }
01150   }
01151   else if (!(This->openFlags & STGM_TRANSACTED) &&
01152            STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
01153   {
01154     WARN("read-only storage\n");
01155     return STG_E_ACCESSDENIED;
01156   }
01157 
01158   memset(&newEntry, 0, sizeof(DirEntry));
01159 
01160   newEntry.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
01161 
01162   if (newEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN)
01163   {
01164     FIXME("name too long\n");
01165     return STG_E_INVALIDNAME;
01166   }
01167 
01168   strcpyW(newEntry.name, pwcsName);
01169 
01170   newEntry.stgType       = STGTY_STORAGE;
01171   newEntry.startingBlock = BLOCK_END_OF_CHAIN;
01172   newEntry.size.u.LowPart  = 0;
01173   newEntry.size.u.HighPart = 0;
01174 
01175   newEntry.leftChild        = DIRENTRY_NULL;
01176   newEntry.rightChild       = DIRENTRY_NULL;
01177   newEntry.dirRootEntry     = DIRENTRY_NULL;
01178 
01179   /* call CoFileTime to get the current time
01180   newEntry.ctime
01181   newEntry.mtime
01182   */
01183 
01184   /*  newEntry.clsid */
01185 
01186   /*
01187    * Create a new directory entry for the storage
01188    */
01189   hr = StorageBaseImpl_CreateDirEntry(This, &newEntry, &newEntryRef);
01190   if (FAILED(hr))
01191     return hr;
01192 
01193   /*
01194    * Insert the new directory entry into the parent storage's tree
01195    */
01196   hr = insertIntoTree(
01197     This,
01198     This->storageDirEntry,
01199     newEntryRef);
01200   if (FAILED(hr))
01201   {
01202     StorageBaseImpl_DestroyDirEntry(This, newEntryRef);
01203     return hr;
01204   }
01205 
01206   /*
01207    * Open it to get a pointer to return.
01208    */
01209   hr = IStorage_OpenStorage(iface, pwcsName, 0, grfMode, 0, 0, ppstg);
01210 
01211   if( (hr != S_OK) || (*ppstg == NULL))
01212   {
01213     return hr;
01214   }
01215 
01216   if (SUCCEEDED(hr))
01217     hr = StorageBaseImpl_Flush(This);
01218 
01219   return S_OK;
01220 }
01221 
01222 
01223 /***************************************************************************
01224  *
01225  * Internal Method
01226  *
01227  * Reserve a directory entry in the file and initialize it.
01228  */
01229 static HRESULT StorageImpl_CreateDirEntry(
01230   StorageBaseImpl *base,
01231   const DirEntry *newData,
01232   DirRef *index)
01233 {
01234   StorageImpl *storage = (StorageImpl*)base;
01235   ULONG       currentEntryIndex    = 0;
01236   ULONG       newEntryIndex        = DIRENTRY_NULL;
01237   HRESULT hr = S_OK;
01238   BYTE currentData[RAW_DIRENTRY_SIZE];
01239   WORD sizeOfNameString;
01240 
01241   do
01242   {
01243     hr = StorageImpl_ReadRawDirEntry(storage,
01244                                      currentEntryIndex,
01245                                      currentData);
01246 
01247     if (SUCCEEDED(hr))
01248     {
01249       StorageUtl_ReadWord(
01250         currentData,
01251         OFFSET_PS_NAMELENGTH,
01252         &sizeOfNameString);
01253 
01254       if (sizeOfNameString == 0)
01255       {
01256         /*
01257          * The entry exists and is available, we found it.
01258          */
01259         newEntryIndex = currentEntryIndex;
01260       }
01261     }
01262     else
01263     {
01264       /*
01265        * We exhausted the directory entries, we will create more space below
01266        */
01267       newEntryIndex = currentEntryIndex;
01268     }
01269     currentEntryIndex++;
01270 
01271   } while (newEntryIndex == DIRENTRY_NULL);
01272 
01273   /*
01274    * grow the directory stream
01275    */
01276   if (FAILED(hr))
01277   {
01278     BYTE           emptyData[RAW_DIRENTRY_SIZE];
01279     ULARGE_INTEGER newSize;
01280     ULONG          entryIndex;
01281     ULONG          lastEntry     = 0;
01282     ULONG          blockCount    = 0;
01283 
01284     /*
01285      * obtain the new count of blocks in the directory stream
01286      */
01287     blockCount = BlockChainStream_GetCount(
01288                    storage->rootBlockChain)+1;
01289 
01290     /*
01291      * initialize the size used by the directory stream
01292      */
01293     newSize.u.HighPart = 0;
01294     newSize.u.LowPart  = storage->bigBlockSize * blockCount;
01295 
01296     /*
01297      * add a block to the directory stream
01298      */
01299     BlockChainStream_SetSize(storage->rootBlockChain, newSize);
01300 
01301     /*
01302      * memset the empty entry in order to initialize the unused newly
01303      * created entries
01304      */
01305     memset(emptyData, 0, RAW_DIRENTRY_SIZE);
01306 
01307     /*
01308      * initialize them
01309      */
01310     lastEntry = storage->bigBlockSize / RAW_DIRENTRY_SIZE * blockCount;
01311 
01312     for(
01313       entryIndex = newEntryIndex + 1;
01314       entryIndex < lastEntry;
01315       entryIndex++)
01316     {
01317       StorageImpl_WriteRawDirEntry(
01318         storage,
01319         entryIndex,
01320         emptyData);
01321     }
01322 
01323     StorageImpl_SaveFileHeader(storage);
01324   }
01325 
01326   UpdateRawDirEntry(currentData, newData);
01327 
01328   hr = StorageImpl_WriteRawDirEntry(storage, newEntryIndex, currentData);
01329 
01330   if (SUCCEEDED(hr))
01331     *index = newEntryIndex;
01332 
01333   return hr;
01334 }
01335 
01336 /***************************************************************************
01337  *
01338  * Internal Method
01339  *
01340  * Mark a directory entry in the file as free.
01341  */
01342 static HRESULT StorageImpl_DestroyDirEntry(
01343   StorageBaseImpl *base,
01344   DirRef index)
01345 {
01346   HRESULT hr;
01347   BYTE emptyData[RAW_DIRENTRY_SIZE];
01348   StorageImpl *storage = (StorageImpl*)base;
01349 
01350   memset(emptyData, 0, RAW_DIRENTRY_SIZE);
01351 
01352   hr = StorageImpl_WriteRawDirEntry(storage, index, emptyData);
01353 
01354   return hr;
01355 }
01356 
01357 
01358 /****************************************************************************
01359  *
01360  * Internal Method
01361  *
01362  * Case insensitive comparison of DirEntry.name by first considering
01363  * their size.
01364  *
01365  * Returns <0 when name1 < name2
01366  *         >0 when name1 > name2
01367  *          0 when name1 == name2
01368  */
01369 static LONG entryNameCmp(
01370     const OLECHAR *name1,
01371     const OLECHAR *name2)
01372 {
01373   LONG diff      = lstrlenW(name1) - lstrlenW(name2);
01374 
01375   while (diff == 0 && *name1 != 0)
01376   {
01377     /*
01378      * We compare the string themselves only when they are of the same length
01379      */
01380     diff = toupperW(*name1++) - toupperW(*name2++);
01381   }
01382 
01383   return diff;
01384 }
01385 
01386 /****************************************************************************
01387  *
01388  * Internal Method
01389  *
01390  * Add a directory entry to a storage
01391  */
01392 static HRESULT insertIntoTree(
01393   StorageBaseImpl *This,
01394   DirRef        parentStorageIndex,
01395   DirRef        newEntryIndex)
01396 {
01397   DirEntry currentEntry;
01398   DirEntry newEntry;
01399 
01400   /*
01401    * Read the inserted entry
01402    */
01403   StorageBaseImpl_ReadDirEntry(This,
01404                                newEntryIndex,
01405                                &newEntry);
01406 
01407   /*
01408    * Read the storage entry
01409    */
01410   StorageBaseImpl_ReadDirEntry(This,
01411                                parentStorageIndex,
01412                                &currentEntry);
01413 
01414   if (currentEntry.dirRootEntry != DIRENTRY_NULL)
01415   {
01416     /*
01417      * The root storage contains some element, therefore, start the research
01418      * for the appropriate location.
01419      */
01420     BOOL found = 0;
01421     DirRef current, next, previous, currentEntryId;
01422 
01423     /*
01424      * Keep a reference to the root of the storage's element tree
01425      */
01426     currentEntryId = currentEntry.dirRootEntry;
01427 
01428     /*
01429      * Read
01430      */
01431     StorageBaseImpl_ReadDirEntry(This,
01432                                  currentEntry.dirRootEntry,
01433                                  &currentEntry);
01434 
01435     previous = currentEntry.leftChild;
01436     next     = currentEntry.rightChild;
01437     current  = currentEntryId;
01438 
01439     while (found == 0)
01440     {
01441       LONG diff = entryNameCmp( newEntry.name, currentEntry.name);
01442 
01443       if (diff < 0)
01444       {
01445         if (previous != DIRENTRY_NULL)
01446         {
01447           StorageBaseImpl_ReadDirEntry(This,
01448                                        previous,
01449                                        &currentEntry);
01450           current = previous;
01451         }
01452         else
01453         {
01454           currentEntry.leftChild = newEntryIndex;
01455           StorageBaseImpl_WriteDirEntry(This,
01456                                         current,
01457                                         &currentEntry);
01458           found = 1;
01459         }
01460       }
01461       else if (diff > 0)
01462       {
01463         if (next != DIRENTRY_NULL)
01464         {
01465           StorageBaseImpl_ReadDirEntry(This,
01466                                        next,
01467                                        &currentEntry);
01468           current = next;
01469         }
01470         else
01471         {
01472           currentEntry.rightChild = newEntryIndex;
01473           StorageBaseImpl_WriteDirEntry(This,
01474                                         current,
01475                                         &currentEntry);
01476           found = 1;
01477         }
01478       }
01479       else
01480       {
01481     /*
01482      * Trying to insert an item with the same name in the
01483      * subtree structure.
01484      */
01485     return STG_E_FILEALREADYEXISTS;
01486       }
01487 
01488       previous = currentEntry.leftChild;
01489       next     = currentEntry.rightChild;
01490     }
01491   }
01492   else
01493   {
01494     /*
01495      * The storage is empty, make the new entry the root of its element tree
01496      */
01497     currentEntry.dirRootEntry = newEntryIndex;
01498     StorageBaseImpl_WriteDirEntry(This,
01499                                   parentStorageIndex,
01500                                   &currentEntry);
01501   }
01502 
01503   return S_OK;
01504 }
01505 
01506 /****************************************************************************
01507  *
01508  * Internal Method
01509  *
01510  * Find and read the element of a storage with the given name.
01511  */
01512 static DirRef findElement(StorageBaseImpl *storage, DirRef storageEntry,
01513     const OLECHAR *name, DirEntry *data)
01514 {
01515   DirRef currentEntry;
01516 
01517   /* Read the storage entry to find the root of the tree. */
01518   StorageBaseImpl_ReadDirEntry(storage, storageEntry, data);
01519 
01520   currentEntry = data->dirRootEntry;
01521 
01522   while (currentEntry != DIRENTRY_NULL)
01523   {
01524     LONG cmp;
01525 
01526     StorageBaseImpl_ReadDirEntry(storage, currentEntry, data);
01527 
01528     cmp = entryNameCmp(name, data->name);
01529 
01530     if (cmp == 0)
01531       /* found it */
01532       break;
01533 
01534     else if (cmp < 0)
01535       currentEntry = data->leftChild;
01536 
01537     else if (cmp > 0)
01538       currentEntry = data->rightChild;
01539   }
01540 
01541   return currentEntry;
01542 }
01543 
01544 /****************************************************************************
01545  *
01546  * Internal Method
01547  *
01548  * Find and read the binary tree parent of the element with the given name.
01549  *
01550  * If there is no such element, find a place where it could be inserted and
01551  * return STG_E_FILENOTFOUND.
01552  */
01553 static HRESULT findTreeParent(StorageBaseImpl *storage, DirRef storageEntry,
01554     const OLECHAR *childName, DirEntry *parentData, DirRef *parentEntry,
01555     ULONG *relation)
01556 {
01557   DirRef childEntry;
01558   DirEntry childData;
01559 
01560   /* Read the storage entry to find the root of the tree. */
01561   StorageBaseImpl_ReadDirEntry(storage, storageEntry, parentData);
01562 
01563   *parentEntry = storageEntry;
01564   *relation = DIRENTRY_RELATION_DIR;
01565 
01566   childEntry = parentData->dirRootEntry;
01567 
01568   while (childEntry != DIRENTRY_NULL)
01569   {
01570     LONG cmp;
01571 
01572     StorageBaseImpl_ReadDirEntry(storage, childEntry, &childData);
01573 
01574     cmp = entryNameCmp(childName, childData.name);
01575 
01576     if (cmp == 0)
01577       /* found it */
01578       break;
01579 
01580     else if (cmp < 0)
01581     {
01582       *parentData = childData;
01583       *parentEntry = childEntry;
01584       *relation = DIRENTRY_RELATION_PREVIOUS;
01585 
01586       childEntry = parentData->leftChild;
01587     }
01588 
01589     else if (cmp > 0)
01590     {
01591       *parentData = childData;
01592       *parentEntry = childEntry;
01593       *relation = DIRENTRY_RELATION_NEXT;
01594 
01595       childEntry = parentData->rightChild;
01596     }
01597   }
01598 
01599   if (childEntry == DIRENTRY_NULL)
01600     return STG_E_FILENOTFOUND;
01601   else
01602     return S_OK;
01603 }
01604 
01605 
01606 static HRESULT StorageBaseImpl_CopyStorageEntryTo(StorageBaseImpl *This,
01607     DirRef srcEntry, BOOL skip_storage, BOOL skip_stream,
01608     SNB snbExclude, IStorage *pstgDest);
01609 
01610 static HRESULT StorageBaseImpl_CopyChildEntryTo(StorageBaseImpl *This,
01611     DirRef srcEntry, BOOL skip_storage, BOOL skip_stream,
01612     SNB snbExclude, IStorage *pstgDest)
01613 {
01614   DirEntry data;
01615   HRESULT hr;
01616   BOOL skip = FALSE;
01617   IStorage *pstgTmp;
01618   IStream *pstrChild, *pstrTmp;
01619   STATSTG strStat;
01620 
01621   if (srcEntry == DIRENTRY_NULL)
01622     return S_OK;
01623 
01624   hr = StorageBaseImpl_ReadDirEntry( This, srcEntry, &data );
01625 
01626   if (FAILED(hr))
01627     return hr;
01628 
01629   if ( snbExclude )
01630   {
01631     WCHAR **snb = snbExclude;
01632 
01633     while ( *snb != NULL && !skip )
01634     {
01635       if ( lstrcmpW(data.name, *snb) == 0 )
01636         skip = TRUE;
01637       ++snb;
01638     }
01639   }
01640 
01641   if (!skip)
01642   {
01643     if (data.stgType == STGTY_STORAGE && !skip_storage)
01644     {
01645       /*
01646        * create a new storage in destination storage
01647        */
01648       hr = IStorage_CreateStorage( pstgDest, data.name,
01649                                    STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
01650                                    0, 0,
01651                                    &pstgTmp );
01652 
01653       /*
01654        * if it already exist, don't create a new one use this one
01655        */
01656       if (hr == STG_E_FILEALREADYEXISTS)
01657       {
01658         hr = IStorage_OpenStorage( pstgDest, data.name, NULL,
01659                                    STGM_WRITE|STGM_SHARE_EXCLUSIVE,
01660                                    NULL, 0, &pstgTmp );
01661       }
01662 
01663       if (SUCCEEDED(hr))
01664       {
01665         hr = StorageBaseImpl_CopyStorageEntryTo( This, srcEntry, skip_storage,
01666                                                  skip_stream, NULL, pstgTmp );
01667 
01668         IStorage_Release(pstgTmp);
01669       }
01670     }
01671     else if (data.stgType == STGTY_STREAM && !skip_stream)
01672     {
01673       /*
01674        * create a new stream in destination storage. If the stream already
01675        * exist, it will be deleted and a new one will be created.
01676        */
01677       hr = IStorage_CreateStream( pstgDest, data.name,
01678                                   STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
01679                                   0, 0, &pstrTmp );
01680 
01681       /*
01682        * open child stream storage. This operation must succeed even if the
01683        * stream is already open, so we use internal functions to do it.
01684        */
01685       if (hr == S_OK)
01686       {
01687         pstrChild = (IStream*)StgStreamImpl_Construct(This, STGM_READ|STGM_SHARE_EXCLUSIVE, srcEntry);
01688         if (pstrChild)
01689           IStream_AddRef(pstrChild);
01690         else
01691           hr = E_OUTOFMEMORY;
01692       }
01693 
01694       if (hr == S_OK)
01695       {
01696         /*
01697          * Get the size of the source stream
01698          */
01699         IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
01700 
01701         /*
01702          * Set the size of the destination stream.
01703          */
01704         IStream_SetSize(pstrTmp, strStat.cbSize);
01705 
01706         /*
01707          * do the copy
01708          */
01709         hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
01710                              NULL, NULL );
01711 
01712         IStream_Release( pstrChild );
01713       }
01714 
01715       IStream_Release( pstrTmp );
01716     }
01717   }
01718 
01719   /* copy siblings */
01720   if (SUCCEEDED(hr))
01721     hr = StorageBaseImpl_CopyChildEntryTo( This, data.leftChild, skip_storage,
01722                                            skip_stream, snbExclude, pstgDest );
01723 
01724   if (SUCCEEDED(hr))
01725     hr = StorageBaseImpl_CopyChildEntryTo( This, data.rightChild, skip_storage,
01726                                            skip_stream, snbExclude, pstgDest );
01727 
01728   return hr;
01729 }
01730 
01731 static HRESULT StorageBaseImpl_CopyStorageEntryTo(StorageBaseImpl *This,
01732     DirRef srcEntry, BOOL skip_storage, BOOL skip_stream,
01733     SNB snbExclude, IStorage *pstgDest)
01734 {
01735   DirEntry data;
01736   HRESULT hr;
01737 
01738   hr = StorageBaseImpl_ReadDirEntry( This, srcEntry, &data );
01739 
01740   if (SUCCEEDED(hr))
01741     hr = IStorage_SetClass( pstgDest, &data.clsid );
01742 
01743   if (SUCCEEDED(hr))
01744     hr = StorageBaseImpl_CopyChildEntryTo( This, data.dirRootEntry, skip_storage,
01745       skip_stream, snbExclude, pstgDest );
01746 
01747   return hr;
01748 }
01749 
01750 /*************************************************************************
01751  * CopyTo (IStorage)
01752  */
01753 static HRESULT WINAPI StorageBaseImpl_CopyTo(
01754   IStorage*   iface,
01755   DWORD       ciidExclude,  /* [in] */
01756   const IID*  rgiidExclude, /* [size_is][unique][in] */
01757   SNB         snbExclude,   /* [unique][in] */
01758   IStorage*   pstgDest)     /* [unique][in] */
01759 {
01760   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
01761 
01762   BOOL         skip_storage = FALSE, skip_stream = FALSE;
01763   int          i;
01764 
01765   TRACE("(%p, %d, %p, %p, %p)\n",
01766     iface, ciidExclude, rgiidExclude,
01767     snbExclude, pstgDest);
01768 
01769   if ( pstgDest == 0 )
01770     return STG_E_INVALIDPOINTER;
01771 
01772   for(i = 0; i < ciidExclude; ++i)
01773   {
01774     if(IsEqualGUID(&IID_IStorage, &rgiidExclude[i]))
01775         skip_storage = TRUE;
01776     else if(IsEqualGUID(&IID_IStream, &rgiidExclude[i]))
01777         skip_stream = TRUE;
01778     else
01779         WARN("Unknown excluded GUID: %s\n", debugstr_guid(&rgiidExclude[i]));
01780   }
01781 
01782   if (!skip_storage)
01783   {
01784     /* Give up early if it looks like this would be infinitely recursive.
01785      * Oddly enough, this includes some cases that aren't really recursive, like
01786      * copying to a transacted child. */
01787     IStorage *pstgDestAncestor = pstgDest;
01788     IStorage *pstgDestAncestorChild = NULL;
01789 
01790     /* Go up the chain from the destination until we find the source storage. */
01791     while (pstgDestAncestor != iface) {
01792       pstgDestAncestorChild = pstgDest;
01793 
01794       if (pstgDestAncestor->lpVtbl == &TransactedSnapshotImpl_Vtbl)
01795       {
01796         TransactedSnapshotImpl *impl = (TransactedSnapshotImpl*) pstgDestAncestor;
01797 
01798         pstgDestAncestor = (IStorage*)impl->transactedParent;
01799       }
01800       else if (pstgDestAncestor->lpVtbl == &Storage32InternalImpl_Vtbl)
01801       {
01802         StorageInternalImpl *impl = (StorageInternalImpl*) pstgDestAncestor;
01803 
01804         pstgDestAncestor = (IStorage*)impl->parentStorage;
01805       }
01806       else
01807         break;
01808     }
01809 
01810     if (pstgDestAncestor == iface)
01811     {
01812       BOOL fail = TRUE;
01813 
01814       if (pstgDestAncestorChild && snbExclude)
01815       {
01816         StorageBaseImpl *ancestorChildBase = (StorageBaseImpl*)pstgDestAncestorChild;
01817         DirEntry data;
01818         WCHAR **snb = snbExclude;
01819 
01820         StorageBaseImpl_ReadDirEntry(ancestorChildBase, ancestorChildBase->storageDirEntry, &data);
01821 
01822         while ( *snb != NULL && fail )
01823         {
01824           if ( lstrcmpW(data.name, *snb) == 0 )
01825             fail = FALSE;
01826           ++snb;
01827         }
01828       }
01829 
01830       if (fail)
01831         return STG_E_ACCESSDENIED;
01832     }
01833   }
01834 
01835   return StorageBaseImpl_CopyStorageEntryTo( This, This->storageDirEntry,
01836     skip_storage, skip_stream, snbExclude, pstgDest );
01837 }
01838 
01839 /*************************************************************************
01840  * MoveElementTo (IStorage)
01841  */
01842 static HRESULT WINAPI StorageBaseImpl_MoveElementTo(
01843   IStorage*     iface,
01844   const OLECHAR *pwcsName,   /* [string][in] */
01845   IStorage      *pstgDest,   /* [unique][in] */
01846   const OLECHAR *pwcsNewName,/* [string][in] */
01847   DWORD           grfFlags)    /* [in] */
01848 {
01849   FIXME("(%p %s %p %s %u): stub\n", iface,
01850          debugstr_w(pwcsName), pstgDest,
01851          debugstr_w(pwcsNewName), grfFlags);
01852   return E_NOTIMPL;
01853 }
01854 
01855 /*************************************************************************
01856  * Commit (IStorage)
01857  *
01858  * Ensures that any changes made to a storage object open in transacted mode
01859  * are reflected in the parent storage
01860  *
01861  * In a non-transacted mode, this ensures all cached writes are completed.
01862  */
01863 static HRESULT WINAPI StorageImpl_Commit(
01864   IStorage*   iface,
01865   DWORD         grfCommitFlags)/* [in] */
01866 {
01867   StorageBaseImpl* const base=(StorageBaseImpl*)iface;
01868   TRACE("(%p %d)\n", iface, grfCommitFlags);
01869   return StorageBaseImpl_Flush(base);
01870 }
01871 
01872 /*************************************************************************
01873  * Revert (IStorage)
01874  *
01875  * Discard all changes that have been made since the last commit operation
01876  */
01877 static HRESULT WINAPI StorageImpl_Revert(
01878   IStorage* iface)
01879 {
01880   TRACE("(%p)\n", iface);
01881   return S_OK;
01882 }
01883 
01884 /*************************************************************************
01885  * DestroyElement (IStorage)
01886  *
01887  * Strategy: This implementation is built this way for simplicity not for speed.
01888  *          I always delete the topmost element of the enumeration and adjust
01889  *          the deleted element pointer all the time.  This takes longer to
01890  *          do but allow to reinvoke DestroyElement whenever we encounter a
01891  *          storage object.  The optimisation resides in the usage of another
01892  *          enumeration strategy that would give all the leaves of a storage
01893  *          first. (postfix order)
01894  */
01895 static HRESULT WINAPI StorageBaseImpl_DestroyElement(
01896   IStorage*     iface,
01897   const OLECHAR *pwcsName)/* [string][in] */
01898 {
01899   StorageBaseImpl* const This=(StorageBaseImpl*)iface;
01900 
01901   HRESULT           hr = S_OK;
01902   DirEntry          entryToDelete;
01903   DirRef            entryToDeleteRef;
01904 
01905   TRACE("(%p, %s)\n",
01906     iface, debugstr_w(pwcsName));
01907 
01908   if (pwcsName==NULL)
01909     return STG_E_INVALIDPOINTER;
01910 
01911   if (This->reverted)
01912     return STG_E_REVERTED;
01913 
01914   if ( !(This->openFlags & STGM_TRANSACTED) &&
01915        STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
01916     return STG_E_ACCESSDENIED;
01917 
01918   entryToDeleteRef = findElement(
01919     This,
01920     This->storageDirEntry,
01921     pwcsName,
01922     &entryToDelete);
01923 
01924   if ( entryToDeleteRef == DIRENTRY_NULL )
01925   {
01926     return STG_E_FILENOTFOUND;
01927   }
01928 
01929   if ( entryToDelete.stgType == STGTY_STORAGE )
01930   {
01931     hr = deleteStorageContents(
01932            This,
01933            entryToDeleteRef,
01934            entryToDelete);
01935   }
01936   else if ( entryToDelete.stgType == STGTY_STREAM )
01937   {
01938     hr = deleteStreamContents(
01939            This,
01940            entryToDeleteRef,
01941            entryToDelete);
01942   }
01943 
01944   if (hr!=S_OK)
01945     return hr;
01946 
01947   /*
01948    * Remove the entry from its parent storage
01949    */
01950   hr = removeFromTree(
01951         This,
01952         This->storageDirEntry,
01953         entryToDeleteRef);
01954 
01955   /*
01956    * Invalidate the entry
01957    */
01958   if (SUCCEEDED(hr))
01959     StorageBaseImpl_DestroyDirEntry(This, entryToDeleteRef);
01960 
01961   if (SUCCEEDED(hr))
01962     hr = StorageBaseImpl_Flush(This);
01963 
01964   return hr;
01965 }
01966 
01967 
01968 /******************************************************************************
01969  * Internal stream list handlers
01970  */
01971 
01972 void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm)
01973 {
01974   TRACE("Stream added (stg=%p strm=%p)\n", stg, strm);
01975   list_add_tail(&stg->strmHead,&strm->StrmListEntry);
01976 }
01977 
01978 void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm)
01979 {
01980   TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm);
01981   list_remove(&(strm->StrmListEntry));
01982 }
01983 
01984 static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry)
01985 {
01986   StgStreamImpl *strm;
01987 
01988   LIST_FOR_EACH_ENTRY(strm, &stg->strmHead, StgStreamImpl, StrmListEntry)
01989   {
01990     if (strm->dirEntry == streamEntry)
01991     {
01992       return TRUE;
01993     }
01994   }
01995 
01996   return FALSE;
01997 }
01998 
01999 static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry)
02000 {
02001   StorageInternalImpl *childstg;
02002 
02003   LIST_FOR_EACH_ENTRY(childstg, &stg->storageHead, StorageInternalImpl, ParentListEntry)
02004   {
02005     if (childstg->base.storageDirEntry == storageEntry)
02006     {
02007       return TRUE;
02008     }
02009   }
02010 
02011   return FALSE;
02012 }
02013 
02014 static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg)
02015 {
02016   struct list *cur, *cur2;
02017   StgStreamImpl *strm=NULL;
02018   StorageInternalImpl *childstg=NULL;
02019 
02020   LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) {
02021     strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry);
02022     TRACE("Streams invalidated (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev);
02023     strm->parentStorage = NULL;
02024     list_remove(cur);
02025   }
02026 
02027   LIST_FOR_EACH_SAFE(cur, cur2, &stg->storageHead) {
02028     childstg = LIST_ENTRY(cur,StorageInternalImpl,ParentListEntry);
02029     StorageBaseImpl_Invalidate( &childstg->base );
02030   }
02031 
02032   if (stg->transactedChild)
02033   {
02034     StorageBaseImpl_Invalidate(stg->transactedChild);
02035 
02036     stg->transactedChild = NULL;
02037   }
02038 }
02039 
02040 
02041 /*********************************************************************
02042  *
02043  * Internal Method
02044  *
02045  * Delete the contents of a storage entry.
02046  *
02047  */
02048 static HRESULT deleteStorageContents(
02049   StorageBaseImpl *parentStorage,
02050   DirRef       indexToDelete,
02051   DirEntry     entryDataToDelete)
02052 {
02053   IEnumSTATSTG *elements     = 0;
02054   IStorage   *childStorage = 0;
02055   STATSTG      currentElement;
02056   HRESULT      hr;
02057   HRESULT      destroyHr = S_OK;
02058   StorageInternalImpl *stg, *stg2;
02059 
02060   /* Invalidate any open storage objects. */
02061   LIST_FOR_EACH_ENTRY_SAFE(stg, stg2, &parentStorage->storageHead, StorageInternalImpl, ParentListEntry)
02062   {
02063     if (stg->base.storageDirEntry == indexToDelete)
02064     {
02065       StorageBaseImpl_Invalidate(&stg->base);
02066     }
02067   }
02068 
02069   /*
02070    * Open the storage and enumerate it
02071    */
02072   hr = StorageBaseImpl_OpenStorage(
02073         (IStorage*)parentStorage,
02074         entryDataToDelete.name,
02075         0,
02076         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
02077         0,
02078         0,
02079         &childStorage);
02080 
02081   if (hr != S_OK)
02082   {
02083     return hr;
02084   }
02085 
02086   /*
02087    * Enumerate the elements
02088    */
02089   IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
02090 
02091   do
02092   {
02093     /*
02094      * Obtain the next element
02095      */
02096     hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
02097     if (hr==S_OK)
02098     {
02099       destroyHr = IStorage_DestroyElement(childStorage, currentElement.pwcsName);
02100 
02101       CoTaskMemFree(currentElement.pwcsName);
02102     }
02103 
02104     /*
02105      * We need to Reset the enumeration every time because we delete elements
02106      * and the enumeration could be invalid
02107      */
02108     IEnumSTATSTG_Reset(elements);
02109 
02110   } while ((hr == S_OK) && (destroyHr == S_OK));
02111 
02112   IStorage_Release(childStorage);
02113   IEnumSTATSTG_Release(elements);
02114 
02115   return destroyHr;
02116 }
02117 
02118 /*********************************************************************
02119  *
02120  * Internal Method
02121  *
02122  * Perform the deletion of a stream's data
02123  *
02124  */
02125 static HRESULT deleteStreamContents(
02126   StorageBaseImpl *parentStorage,
02127   DirRef        indexToDelete,
02128   DirEntry      entryDataToDelete)
02129 {
02130   IStream      *pis;
02131   HRESULT        hr;
02132   ULARGE_INTEGER size;
02133   StgStreamImpl *strm, *strm2;
02134 
02135   /* Invalidate any open stream objects. */
02136   LIST_FOR_EACH_ENTRY_SAFE(strm, strm2, &parentStorage->strmHead, StgStreamImpl, StrmListEntry)
02137   {
02138     if (strm->dirEntry == indexToDelete)
02139     {
02140       TRACE("Stream deleted %p\n", strm);
02141       strm->parentStorage = NULL;
02142       list_remove(&strm->StrmListEntry);
02143     }
02144   }
02145 
02146   size.u.HighPart = 0;
02147   size.u.LowPart = 0;
02148 
02149   hr = StorageBaseImpl_OpenStream((IStorage*)parentStorage,
02150         entryDataToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis);
02151 
02152   if (hr!=S_OK)
02153   {
02154     return(hr);
02155   }
02156 
02157   /*
02158    * Zap the stream
02159    */
02160   hr = IStream_SetSize(pis, size);
02161 
02162   if(hr != S_OK)
02163   {
02164     return hr;
02165   }
02166 
02167   /*
02168    * Release the stream object.
02169    */
02170   IStream_Release(pis);
02171 
02172   return S_OK;
02173 }
02174 
02175 static void setEntryLink(DirEntry *entry, ULONG relation, DirRef new_target)
02176 {
02177   switch (relation)
02178   {
02179     case DIRENTRY_RELATION_PREVIOUS:
02180       entry->leftChild = new_target;
02181       break;
02182     case DIRENTRY_RELATION_NEXT:
02183       entry->rightChild = new_target;
02184       break;
02185     case DIRENTRY_RELATION_DIR:
02186       entry->dirRootEntry = new_target;
02187       break;
02188     default:
02189       assert(0);
02190   }
02191 }
02192 
02193 /*************************************************************************
02194  *
02195  * Internal Method
02196  *
02197  * This method removes a directory entry from its parent storage tree without
02198  * freeing any resources attached to it.
02199  */
02200 static HRESULT removeFromTree(
02201   StorageBaseImpl *This,
02202   DirRef        parentStorageIndex,
02203   DirRef        deletedIndex)
02204 {
02205   HRESULT hr                     = S_OK;
02206   DirEntry   entryToDelete;
02207   DirEntry   parentEntry;
02208   DirRef parentEntryRef;
02209   ULONG typeOfRelation;
02210 
02211   hr = StorageBaseImpl_ReadDirEntry(This, deletedIndex, &entryToDelete);
02212 
02213   if (hr != S_OK)
02214     return hr;
02215 
02216   /*
02217    * Find the element that links to the one we want to delete.
02218    */
02219   hr = findTreeParent(This, parentStorageIndex, entryToDelete.name,
02220     &parentEntry, &parentEntryRef, &typeOfRelation);
02221 
02222   if (hr != S_OK)
02223     return hr;
02224 
02225   if (entryToDelete.leftChild != DIRENTRY_NULL)
02226   {
02227     /*
02228      * Replace the deleted entry with its left child
02229      */
02230     setEntryLink(&parentEntry, typeOfRelation, entryToDelete.leftChild);
02231 
02232     hr = StorageBaseImpl_WriteDirEntry(
02233             This,
02234             parentEntryRef,
02235             &parentEntry);
02236     if(FAILED(hr))
02237     {
02238       return hr;
02239     }
02240 
02241     if (entryToDelete.rightChild != DIRENTRY_NULL)
02242     {
02243       /*
02244        * We need to reinsert the right child somewhere. We already know it and
02245        * its children are greater than everything in the left tree, so we
02246        * insert it at the rightmost point in the left tree.
02247        */
02248       DirRef newRightChildParent = entryToDelete.leftChild;
02249       DirEntry newRightChildParentEntry;
02250 
02251       do
02252       {
02253         hr = StorageBaseImpl_ReadDirEntry(
02254                 This,
02255                 newRightChildParent,
02256                 &newRightChildParentEntry);
02257         if (FAILED(hr))
02258         {
02259           return hr;
02260         }
02261 
02262         if (newRightChildParentEntry.rightChild != DIRENTRY_NULL)
02263           newRightChildParent = newRightChildParentEntry.rightChild;
02264       } while (newRightChildParentEntry.rightChild != DIRENTRY_NULL);
02265 
02266       newRightChildParentEntry.rightChild = entryToDelete.rightChild;
02267 
02268       hr = StorageBaseImpl_WriteDirEntry(
02269               This,
02270               newRightChildParent,
02271               &newRightChildParentEntry);
02272       if (FAILED(hr))
02273       {
02274         return hr;
02275       }
02276     }
02277   }
02278   else
02279   {
02280     /*
02281      * Replace the deleted entry with its right child
02282      */
02283     setEntryLink(&parentEntry, typeOfRelation, entryToDelete.rightChild);
02284 
02285     hr = StorageBaseImpl_WriteDirEntry(
02286             This,
02287             parentEntryRef,
02288             &parentEntry);
02289     if(FAILED(hr))
02290     {
02291       return hr;
02292     }
02293   }
02294 
02295   return hr;
02296 }
02297 
02298 
02299 /******************************************************************************
02300  * SetElementTimes (IStorage)
02301  */
02302 static HRESULT WINAPI StorageBaseImpl_SetElementTimes(
02303   IStorage*     iface,
02304   const OLECHAR *pwcsName,/* [string][in] */
02305   const FILETIME  *pctime,  /* [in] */
02306   const FILETIME  *patime,  /* [in] */
02307   const FILETIME  *pmtime)  /* [in] */
02308 {
02309   FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));
02310   return S_OK;
02311 }
02312 
02313 /******************************************************************************
02314  * SetStateBits (IStorage)
02315  */
02316 static HRESULT WINAPI StorageBaseImpl_SetStateBits(
02317   IStorage*   iface,
02318   DWORD         grfStateBits,/* [in] */
02319   DWORD         grfMask)     /* [in] */
02320 {
02321   StorageBaseImpl* const This = (StorageBaseImpl*)iface;
02322 
02323   if (This->reverted)
02324     return STG_E_REVERTED;
02325 
02326   This->stateBits = (This->stateBits & ~grfMask) | (grfStateBits & grfMask);
02327   return S_OK;
02328 }
02329 
02330 static HRESULT StorageImpl_BaseWriteDirEntry(StorageBaseImpl *base,
02331   DirRef index, const DirEntry *data)
02332 {
02333   StorageImpl *This = (StorageImpl*)base;
02334   return StorageImpl_WriteDirEntry(This, index, data);
02335 }
02336 
02337 static HRESULT StorageImpl_BaseReadDirEntry(StorageBaseImpl *base,
02338   DirRef index, DirEntry *data)
02339 {
02340   StorageImpl *This = (StorageImpl*)base;
02341   return StorageImpl_ReadDirEntry(This, index, data);
02342 }
02343 
02344 static BlockChainStream **StorageImpl_GetFreeBlockChainCacheEntry(StorageImpl* This)
02345 {
02346   int i;
02347 
02348   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
02349   {
02350     if (!This->blockChainCache[i])
02351     {
02352       return &This->blockChainCache[i];
02353     }
02354   }
02355 
02356   i = This->blockChainToEvict;
02357 
02358   BlockChainStream_Destroy(This->blockChainCache[i]);
02359   This->blockChainCache[i] = NULL;
02360 
02361   This->blockChainToEvict++;
02362   if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE)
02363     This->blockChainToEvict = 0;
02364 
02365   return &This->blockChainCache[i];
02366 }
02367 
02368 static BlockChainStream **StorageImpl_GetCachedBlockChainStream(StorageImpl *This,
02369     DirRef index)
02370 {
02371   int i, free_index=-1;
02372 
02373   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
02374   {
02375     if (!This->blockChainCache[i])
02376     {
02377       if (free_index == -1) free_index = i;
02378     }
02379     else if (This->blockChainCache[i]->ownerDirEntry == index)
02380     {
02381       return &This->blockChainCache[i];
02382     }
02383   }
02384 
02385   if (free_index == -1)
02386   {
02387     free_index = This->blockChainToEvict;
02388 
02389     BlockChainStream_Destroy(This->blockChainCache[free_index]);
02390     This->blockChainCache[free_index] = NULL;
02391 
02392     This->blockChainToEvict++;
02393     if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE)
02394       This->blockChainToEvict = 0;
02395   }
02396 
02397   This->blockChainCache[free_index] = BlockChainStream_Construct(This, NULL, index);
02398   return &This->blockChainCache[free_index];
02399 }
02400 
02401 static void StorageImpl_DeleteCachedBlockChainStream(StorageImpl *This, DirRef index)
02402 {
02403   int i;
02404 
02405   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
02406   {
02407     if (This->blockChainCache[i] && This->blockChainCache[i]->ownerDirEntry == index)
02408     {
02409       BlockChainStream_Destroy(This->blockChainCache[i]);
02410       This->blockChainCache[i] = NULL;
02411       return;
02412     }
02413   }
02414 }
02415 
02416 static HRESULT StorageImpl_StreamReadAt(StorageBaseImpl *base, DirRef index,
02417   ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
02418 {
02419   StorageImpl *This = (StorageImpl*)base;
02420   DirEntry data;
02421   HRESULT hr;
02422   ULONG bytesToRead;
02423 
02424   hr = StorageImpl_ReadDirEntry(This, index, &data);
02425   if (FAILED(hr)) return hr;
02426 
02427   if (data.size.QuadPart == 0)
02428   {
02429     *bytesRead = 0;
02430     return S_OK;
02431   }
02432 
02433   if (offset.QuadPart + size > data.size.QuadPart)
02434   {
02435     bytesToRead = data.size.QuadPart - offset.QuadPart;
02436   }
02437   else
02438   {
02439     bytesToRead = size;
02440   }
02441 
02442   if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
02443   {
02444     SmallBlockChainStream *stream;
02445 
02446     stream = SmallBlockChainStream_Construct(This, NULL, index);
02447     if (!stream) return E_OUTOFMEMORY;
02448 
02449     hr = SmallBlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead);
02450 
02451     SmallBlockChainStream_Destroy(stream);
02452 
02453     return hr;
02454   }
02455   else
02456   {
02457     BlockChainStream *stream = NULL;
02458 
02459     stream = *StorageImpl_GetCachedBlockChainStream(This, index);
02460     if (!stream) return E_OUTOFMEMORY;
02461 
02462     hr = BlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead);
02463 
02464     return hr;
02465   }
02466 }
02467 
02468 static HRESULT StorageImpl_StreamSetSize(StorageBaseImpl *base, DirRef index,
02469   ULARGE_INTEGER newsize)
02470 {
02471   StorageImpl *This = (StorageImpl*)base;
02472   DirEntry data;
02473   HRESULT hr;
02474   SmallBlockChainStream *smallblock=NULL;
02475   BlockChainStream **pbigblock=NULL, *bigblock=NULL;
02476 
02477   hr = StorageImpl_ReadDirEntry(This, index, &data);
02478   if (FAILED(hr)) return hr;
02479 
02480   /* In simple mode keep the stream size above the small block limit */
02481   if (This->base.openFlags & STGM_SIMPLE)
02482     newsize.QuadPart = max(newsize.QuadPart, LIMIT_TO_USE_SMALL_BLOCK);
02483 
02484   if (data.size.QuadPart == newsize.QuadPart)
02485     return S_OK;
02486 
02487   /* Create a block chain object of the appropriate type */
02488   if (data.size.QuadPart == 0)
02489   {
02490     if (newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
02491     {
02492       smallblock = SmallBlockChainStream_Construct(This, NULL, index);
02493       if (!smallblock) return E_OUTOFMEMORY;
02494     }
02495     else
02496     {
02497       pbigblock = StorageImpl_GetCachedBlockChainStream(This, index);
02498       bigblock = *pbigblock;
02499       if (!bigblock) return E_OUTOFMEMORY;
02500     }
02501   }
02502   else if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
02503   {
02504     smallblock = SmallBlockChainStream_Construct(This, NULL, index);
02505     if (!smallblock) return E_OUTOFMEMORY;
02506   }
02507   else
02508   {
02509     pbigblock = StorageImpl_GetCachedBlockChainStream(This, index);
02510     bigblock = *pbigblock;
02511     if (!bigblock) return E_OUTOFMEMORY;
02512   }
02513 
02514   /* Change the block chain type if necessary. */
02515   if (smallblock && newsize.QuadPart >= LIMIT_TO_USE_SMALL_BLOCK)
02516   {
02517     bigblock = Storage32Impl_SmallBlocksToBigBlocks(This, &smallblock);
02518     if (!bigblock)
02519     {
02520       SmallBlockChainStream_Destroy(smallblock);
02521       return E_FAIL;
02522     }
02523 
02524     pbigblock = StorageImpl_GetFreeBlockChainCacheEntry(This);
02525     *pbigblock = bigblock;
02526   }
02527   else if (bigblock && newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
02528   {
02529     smallblock = Storage32Impl_BigBlocksToSmallBlocks(This, pbigblock, newsize);
02530     if (!smallblock)
02531       return E_FAIL;
02532   }
02533 
02534   /* Set the size of the block chain. */
02535   if (smallblock)
02536   {
02537     SmallBlockChainStream_SetSize(smallblock, newsize);
02538     SmallBlockChainStream_Destroy(smallblock);
02539   }
02540   else
02541   {
02542     BlockChainStream_SetSize(bigblock, newsize);
02543   }
02544 
02545   /* Set the size in the directory entry. */
02546   hr = StorageImpl_ReadDirEntry(This, index, &data);
02547   if (SUCCEEDED(hr))
02548   {
02549     data.size = newsize;
02550 
02551     hr = StorageImpl_WriteDirEntry(This, index, &data);
02552   }
02553   return hr;
02554 }
02555 
02556 static HRESULT StorageImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index,
02557   ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
02558 {
02559   StorageImpl *This = (StorageImpl*)base;
02560   DirEntry data;
02561   HRESULT hr;
02562   ULARGE_INTEGER newSize;
02563 
02564   hr = StorageImpl_ReadDirEntry(This, index, &data);
02565   if (FAILED(hr)) return hr;
02566 
02567   /* Grow the stream if necessary */
02568   newSize.QuadPart = 0;
02569   newSize.QuadPart = offset.QuadPart + size;
02570 
02571   if (newSize.QuadPart > data.size.QuadPart)
02572   {
02573     hr = StorageImpl_StreamSetSize(base, index, newSize);
02574     if (FAILED(hr))
02575       return hr;
02576 
02577     hr = StorageImpl_ReadDirEntry(This, index, &data);
02578     if (FAILED(hr)) return hr;
02579   }
02580 
02581   if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
02582   {
02583     SmallBlockChainStream *stream;
02584 
02585     stream = SmallBlockChainStream_Construct(This, NULL, index);
02586     if (!stream) return E_OUTOFMEMORY;
02587 
02588     hr = SmallBlockChainStream_WriteAt(stream, offset, size, buffer, bytesWritten);
02589 
02590     SmallBlockChainStream_Destroy(stream);
02591 
02592     return hr;
02593   }
02594   else
02595   {
02596     BlockChainStream *stream;
02597 
02598     stream = *StorageImpl_GetCachedBlockChainStream(This, index);
02599     if (!stream) return E_OUTOFMEMORY;
02600 
02601     hr = BlockChainStream_WriteAt(stream, offset, size, buffer, bytesWritten);
02602 
02603     return hr;
02604   }
02605 }
02606 
02607 static HRESULT StorageImpl_StreamLink(StorageBaseImpl *base, DirRef dst,
02608   DirRef src)
02609 {
02610   StorageImpl *This = (StorageImpl*)base;
02611   DirEntry dst_data, src_data;
02612   HRESULT hr;
02613 
02614   hr = StorageImpl_ReadDirEntry(This, dst, &dst_data);
02615 
02616   if (SUCCEEDED(hr))
02617     hr = StorageImpl_ReadDirEntry(This, src, &src_data);
02618 
02619   if (SUCCEEDED(hr))
02620   {
02621     StorageImpl_DeleteCachedBlockChainStream(This, src);
02622     dst_data.startingBlock = src_data.startingBlock;
02623     dst_data.size = src_data.size;
02624 
02625     hr = StorageImpl_WriteDirEntry(This, dst, &dst_data);
02626   }
02627 
02628   return hr;
02629 }
02630 
02631 static HRESULT StorageImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
02632 {
02633   StorageImpl *This = (StorageImpl*) iface;
02634   STATSTG statstg;
02635   HRESULT hr;
02636 
02637   hr = ILockBytes_Stat(This->lockBytes, &statstg, 0);
02638 
02639   *result = statstg.pwcsName;
02640 
02641   return hr;
02642 }
02643 
02644 /*
02645  * Virtual function table for the IStorage32Impl class.
02646  */
02647 static const IStorageVtbl Storage32Impl_Vtbl =
02648 {
02649     StorageBaseImpl_QueryInterface,
02650     StorageBaseImpl_AddRef,
02651     StorageBaseImpl_Release,
02652     StorageBaseImpl_CreateStream,
02653     StorageBaseImpl_OpenStream,
02654     StorageBaseImpl_CreateStorage,
02655     StorageBaseImpl_OpenStorage,
02656     StorageBaseImpl_CopyTo,
02657     StorageBaseImpl_MoveElementTo,
02658     StorageImpl_Commit,
02659     StorageImpl_Revert,
02660     StorageBaseImpl_EnumElements,
02661     StorageBaseImpl_DestroyElement,
02662     StorageBaseImpl_RenameElement,
02663     StorageBaseImpl_SetElementTimes,
02664     StorageBaseImpl_SetClass,
02665     StorageBaseImpl_SetStateBits,
02666     StorageBaseImpl_Stat
02667 };
02668 
02669 static const StorageBaseImplVtbl StorageImpl_BaseVtbl =
02670 {
02671   StorageImpl_Destroy,
02672   StorageImpl_Invalidate,
02673   StorageImpl_Flush,
02674   StorageImpl_GetFilename,
02675   StorageImpl_CreateDirEntry,
02676   StorageImpl_BaseWriteDirEntry,
02677   StorageImpl_BaseReadDirEntry,
02678   StorageImpl_DestroyDirEntry,
02679   StorageImpl_StreamReadAt,
02680   StorageImpl_StreamWriteAt,
02681   StorageImpl_StreamSetSize,
02682   StorageImpl_StreamLink
02683 };
02684 
02685 static HRESULT StorageImpl_Construct(
02686   HANDLE       hFile,
02687   LPCOLESTR    pwcsName,
02688   ILockBytes*  pLkbyt,
02689   DWORD        openFlags,
02690   BOOL         fileBased,
02691   BOOL         create,
02692   ULONG        sector_size,
02693   StorageImpl** result)
02694 {
02695   StorageImpl* This;
02696   HRESULT     hr = S_OK;
02697   DirEntry currentEntry;
02698   DirRef      currentEntryRef;
02699 
02700   if ( FAILED( validateSTGM(openFlags) ))
02701     return STG_E_INVALIDFLAG;
02702 
02703   This = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
02704   if (!This)
02705     return E_OUTOFMEMORY;
02706 
02707   memset(This, 0, sizeof(StorageImpl));
02708 
02709   list_init(&This->base.strmHead);
02710 
02711   list_init(&This->base.storageHead);
02712 
02713   This->base.lpVtbl = &Storage32Impl_Vtbl;
02714   This->base.pssVtbl = &IPropertySetStorage_Vtbl;
02715   This->base.baseVtbl = &StorageImpl_BaseVtbl;
02716   This->base.openFlags = (openFlags & ~STGM_CREATE);
02717   This->base.ref = 1;
02718   This->base.create = create;
02719 
02720   This->base.reverted = 0;
02721 
02722   /*
02723    * Initialize the big block cache.
02724    */
02725   This->bigBlockSize   = sector_size;
02726   This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
02727   if (hFile)
02728     hr = FileLockBytesImpl_Construct(hFile, openFlags, pwcsName, &This->lockBytes);
02729   else
02730   {
02731     This->lockBytes = pLkbyt;
02732     ILockBytes_AddRef(pLkbyt);
02733   }
02734 
02735   if (FAILED(hr))
02736     goto end;
02737 
02738   if (create)
02739   {
02740     ULARGE_INTEGER size;
02741     BYTE bigBlockBuffer[MAX_BIG_BLOCK_SIZE];
02742 
02743     /* Discard any existing data. */
02744     size.QuadPart = 0;
02745     ILockBytes_SetSize(This->lockBytes, size);
02746 
02747     /*
02748      * Initialize all header variables:
02749      * - The big block depot consists of one block and it is at block 0
02750      * - The directory table starts at block 1
02751      * - There is no small block depot
02752      */
02753     memset( This->bigBlockDepotStart,
02754             BLOCK_UNUSED,
02755             sizeof(This->bigBlockDepotStart));
02756 
02757     This->bigBlockDepotCount    = 1;
02758     This->bigBlockDepotStart[0] = 0;
02759     This->rootStartBlock        = 1;
02760     This->smallBlockLimit       = LIMIT_TO_USE_SMALL_BLOCK;
02761     This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
02762     if (sector_size == 4096)
02763       This->bigBlockSizeBits      = MAX_BIG_BLOCK_SIZE_BITS;
02764     else
02765       This->bigBlockSizeBits      = MIN_BIG_BLOCK_SIZE_BITS;
02766     This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
02767     This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
02768     This->extBigBlockDepotCount = 0;
02769 
02770     StorageImpl_SaveFileHeader(This);
02771 
02772     /*
02773      * Add one block for the big block depot and one block for the directory table
02774      */
02775     size.u.HighPart = 0;
02776     size.u.LowPart  = This->bigBlockSize * 3;
02777     ILockBytes_SetSize(This->lockBytes, size);
02778 
02779     /*
02780      * Initialize the big block depot
02781      */
02782     memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
02783     StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
02784     StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
02785     StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
02786   }
02787   else
02788   {
02789     /*
02790      * Load the header for the file.
02791      */
02792     hr = StorageImpl_LoadFileHeader(This);
02793 
02794     if (FAILED(hr))
02795     {
02796       goto end;
02797     }
02798   }
02799 
02800   /*
02801    * There is no block depot cached yet.
02802    */
02803   This->indexBlockDepotCached = 0xFFFFFFFF;
02804   This->indexExtBlockDepotCached = 0xFFFFFFFF;
02805 
02806   /*
02807    * Start searching for free blocks with block 0.
02808    */
02809   This->prevFreeBlock = 0;
02810 
02811   This->firstFreeSmallBlock = 0;
02812 
02813   /* Read the extended big block depot locations. */
02814   if (This->extBigBlockDepotCount != 0)
02815   {
02816     ULONG current_block = This->extBigBlockDepotStart;
02817     ULONG cache_size = This->extBigBlockDepotCount * 2;
02818     int i;
02819 
02820     This->extBigBlockDepotLocations = HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * cache_size);
02821     if (!This->extBigBlockDepotLocations)
02822     {
02823       hr = E_OUTOFMEMORY;
02824       goto end;
02825     }
02826 
02827     This->extBigBlockDepotLocationsSize = cache_size;
02828 
02829     for (i=0; i<This->extBigBlockDepotCount; i++)
02830     {
02831       if (current_block == BLOCK_END_OF_CHAIN)
02832       {
02833         WARN("File has too few extended big block depot blocks.\n");
02834         hr = STG_E_DOCFILECORRUPT;
02835         goto end;
02836       }
02837       This->extBigBlockDepotLocations[i] = current_block;
02838       current_block = Storage32Impl_GetNextExtendedBlock(This, current_block);
02839     }
02840   }
02841   else
02842   {
02843     This->extBigBlockDepotLocations = NULL;
02844     This->extBigBlockDepotLocationsSize = 0;
02845   }
02846 
02847   /*
02848    * Create the block chain abstractions.
02849    */
02850   if(!(This->rootBlockChain =
02851        BlockChainStream_Construct(This, &This->rootStartBlock, DIRENTRY_NULL)))
02852   {
02853     hr = STG_E_READFAULT;
02854     goto end;
02855   }
02856 
02857   if(!(This->smallBlockDepotChain =
02858        BlockChainStream_Construct(This, &This->smallBlockDepotStart,
02859                   DIRENTRY_NULL)))
02860   {
02861     hr = STG_E_READFAULT;
02862     goto end;
02863   }
02864 
02865   /*
02866    * Write the root storage entry (memory only)
02867    */
02868   if (create)
02869   {
02870     DirEntry rootEntry;
02871     /*
02872      * Initialize the directory table
02873      */
02874     memset(&rootEntry, 0, sizeof(rootEntry));
02875     MultiByteToWideChar( CP_ACP, 0, rootEntryName, -1, rootEntry.name,
02876                          sizeof(rootEntry.name)/sizeof(WCHAR) );
02877     rootEntry.sizeOfNameString = (strlenW(rootEntry.name)+1) * sizeof(WCHAR);
02878     rootEntry.stgType          = STGTY_ROOT;
02879     rootEntry.leftChild = DIRENTRY_NULL;
02880     rootEntry.rightChild     = DIRENTRY_NULL;
02881     rootEntry.dirRootEntry     = DIRENTRY_NULL;
02882     rootEntry.startingBlock    = BLOCK_END_OF_CHAIN;
02883     rootEntry.size.u.HighPart    = 0;
02884     rootEntry.size.u.LowPart     = 0;
02885 
02886     StorageImpl_WriteDirEntry(This, 0, &rootEntry);
02887   }
02888 
02889   /*
02890    * Find the ID of the root storage.
02891    */
02892   currentEntryRef = 0;
02893 
02894   do
02895   {
02896     hr = StorageImpl_ReadDirEntry(
02897                       This,
02898                       currentEntryRef,
02899                       &currentEntry);
02900 
02901     if (SUCCEEDED(hr))
02902     {
02903       if ( (currentEntry.sizeOfNameString != 0 ) &&
02904            (currentEntry.stgType          == STGTY_ROOT) )
02905       {
02906         This->base.storageDirEntry = currentEntryRef;
02907       }
02908     }
02909 
02910     currentEntryRef++;
02911 
02912   } while (SUCCEEDED(hr) && (This->base.storageDirEntry == DIRENTRY_NULL) );
02913 
02914   if (FAILED(hr))
02915   {
02916     hr = STG_E_READFAULT;
02917     goto end;
02918   }
02919 
02920   /*
02921    * Create the block chain abstraction for the small block root chain.
02922    */
02923   if(!(This->smallBlockRootChain =
02924        BlockChainStream_Construct(This, NULL, This->base.storageDirEntry)))
02925   {
02926     hr = STG_E_READFAULT;
02927   }
02928 
02929 end:
02930   if (FAILED(hr))
02931   {
02932     IStorage_Release((IStorage*)This);
02933     *result = NULL;
02934   }
02935   else
02936   {
02937     StorageImpl_Flush((StorageBaseImpl*)This);
02938     *result = This;
02939   }
02940 
02941   return hr;
02942 }
02943 
02944 static void StorageImpl_Invalidate(StorageBaseImpl* iface)
02945 {
02946   StorageImpl *This = (StorageImpl*) iface;
02947 
02948   StorageBaseImpl_DeleteAll(&This->base);
02949 
02950   This->base.reverted = 1;
02951 }
02952 
02953 static void StorageImpl_Destroy(StorageBaseImpl* iface)
02954 {
02955   StorageImpl *This = (StorageImpl*) iface;
02956   int i;
02957   TRACE("(%p)\n", This);
02958 
02959   StorageImpl_Flush(iface);
02960 
02961   StorageImpl_Invalidate(iface);
02962 
02963   HeapFree(GetProcessHeap(), 0, This->extBigBlockDepotLocations);
02964 
02965   BlockChainStream_Destroy(This->smallBlockRootChain);
02966   BlockChainStream_Destroy(This->rootBlockChain);
02967   BlockChainStream_Destroy(This->smallBlockDepotChain);
02968 
02969   for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
02970     BlockChainStream_Destroy(This->blockChainCache[i]);
02971 
02972   if (This->lockBytes)
02973     ILockBytes_Release(This->lockBytes);
02974   HeapFree(GetProcessHeap(), 0, This);
02975 }
02976 
02977 static HRESULT StorageImpl_Flush(StorageBaseImpl* iface)
02978 {
02979   StorageImpl *This = (StorageImpl*) iface;
02980   int i;
02981   HRESULT hr;
02982   TRACE("(%p)\n", This);
02983 
02984   hr = BlockChainStream_Flush(This->smallBlockRootChain);
02985 
02986   if (SUCCEEDED(hr))
02987     hr = BlockChainStream_Flush(This->rootBlockChain);
02988 
02989   if (SUCCEEDED(hr))
02990     hr = BlockChainStream_Flush(This->smallBlockDepotChain);
02991 
02992   for (i=0; SUCCEEDED(hr) && i<BLOCKCHAIN_CACHE_SIZE; i++)
02993     if (This->blockChainCache[i])
02994       hr = BlockChainStream_Flush(This->blockChainCache[i]);
02995 
02996   if (SUCCEEDED(hr))
02997     hr = ILockBytes_Flush(This->lockBytes);
02998 
02999   return hr;
03000 }
03001 
03002 /******************************************************************************
03003  *      Storage32Impl_GetNextFreeBigBlock
03004  *
03005  * Returns the index of the next free big block.
03006  * If the big block depot is filled, this method will enlarge it.
03007  *
03008  */
03009 static ULONG StorageImpl_GetNextFreeBigBlock(
03010   StorageImpl* This)
03011 {
03012   ULONG depotBlockIndexPos;
03013   BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
03014   BOOL success;
03015   ULONG depotBlockOffset;
03016   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
03017   ULONG nextBlockIndex    = BLOCK_SPECIAL;
03018   int   depotIndex        = 0;
03019   ULONG freeBlock         = BLOCK_UNUSED;
03020   ULARGE_INTEGER neededSize;
03021   STATSTG statstg;
03022 
03023   depotIndex = This->prevFreeBlock / blocksPerDepot;
03024   depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
03025 
03026   /*
03027    * Scan the entire big block depot until we find a block marked free
03028    */
03029   while (nextBlockIndex != BLOCK_UNUSED)
03030   {
03031     if (depotIndex < COUNT_BBDEPOTINHEADER)
03032     {
03033       depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
03034 
03035       /*
03036        * Grow the primary depot.
03037        */
03038       if (depotBlockIndexPos == BLOCK_UNUSED)
03039       {
03040         depotBlockIndexPos = depotIndex*blocksPerDepot;
03041 
03042         /*
03043          * Add a block depot.
03044          */
03045         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
03046         This->bigBlockDepotCount++;
03047         This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
03048 
03049         /*
03050          * Flag it as a block depot.
03051          */
03052         StorageImpl_SetNextBlockInChain(This,
03053                                           depotBlockIndexPos,
03054                                           BLOCK_SPECIAL);
03055 
03056         /* Save new header information.
03057          */
03058         StorageImpl_SaveFileHeader(This);
03059       }
03060     }
03061     else
03062     {
03063       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
03064 
03065       if (depotBlockIndexPos == BLOCK_UNUSED)
03066       {
03067         /*
03068          * Grow the extended depot.
03069          */
03070         ULONG extIndex       = BLOCK_UNUSED;
03071         ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
03072         ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
03073 
03074         if (extBlockOffset == 0)
03075         {
03076           /* We need an extended block.
03077            */
03078           extIndex = Storage32Impl_AddExtBlockDepot(This);
03079           This->extBigBlockDepotCount++;
03080           depotBlockIndexPos = extIndex + 1;
03081         }
03082         else
03083           depotBlockIndexPos = depotIndex * blocksPerDepot;
03084 
03085         /*
03086          * Add a block depot and mark it in the extended block.
03087          */
03088         Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
03089         This->bigBlockDepotCount++;
03090         Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
03091 
03092         /* Flag the block depot.
03093          */
03094         StorageImpl_SetNextBlockInChain(This,
03095                                           depotBlockIndexPos,
03096                                           BLOCK_SPECIAL);
03097 
03098         /* If necessary, flag the extended depot block.
03099          */
03100         if (extIndex != BLOCK_UNUSED)
03101           StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
03102 
03103         /* Save header information.
03104          */
03105         StorageImpl_SaveFileHeader(This);
03106       }
03107     }
03108 
03109     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
03110 
03111     if (success)
03112     {
03113       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
03114               ( nextBlockIndex != BLOCK_UNUSED))
03115       {
03116         StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
03117 
03118         if (nextBlockIndex == BLOCK_UNUSED)
03119         {
03120           freeBlock = (depotIndex * blocksPerDepot) +
03121                       (depotBlockOffset/sizeof(ULONG));
03122         }
03123 
03124         depotBlockOffset += sizeof(ULONG);
03125       }
03126     }
03127 
03128     depotIndex++;
03129     depotBlockOffset = 0;
03130   }
03131 
03132   /*
03133    * make sure that the block physically exists before using it
03134    */
03135   neededSize.QuadPart = StorageImpl_GetBigBlockOffset(This, freeBlock)+This->bigBlockSize;
03136 
03137   ILockBytes_Stat(This->lockBytes, &statstg, STATFLAG_NONAME);
03138 
03139   if (neededSize.QuadPart > statstg.cbSize.QuadPart)
03140     ILockBytes_SetSize(This->lockBytes, neededSize);
03141 
03142   This->prevFreeBlock = freeBlock;
03143 
03144   return freeBlock;
03145 }
03146 
03147 /******************************************************************************
03148  *      Storage32Impl_AddBlockDepot
03149  *
03150  * This will create a depot block, essentially it is a block initialized
03151  * to BLOCK_UNUSEDs.
03152  */
03153 static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
03154 {
03155   BYTE blockBuffer[MAX_BIG_BLOCK_SIZE];
03156 
03157   /*
03158    * Initialize blocks as free
03159    */
03160   memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
03161   StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
03162 }
03163 
03164 /******************************************************************************
03165  *      Storage32Impl_GetExtDepotBlock
03166  *
03167  * Returns the index of the block that corresponds to the specified depot
03168  * index. This method is only for depot indexes equal or greater than
03169  * COUNT_BBDEPOTINHEADER.
03170  */
03171 static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
03172 {
03173   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
03174   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
03175   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
03176   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
03177   ULONG blockIndex             = BLOCK_UNUSED;
03178   ULONG extBlockIndex;
03179   BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
03180   int index, num_blocks;
03181 
03182   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
03183 
03184   if (extBlockCount >= This->extBigBlockDepotCount)
03185     return BLOCK_UNUSED;
03186 
03187   if (This->indexExtBlockDepotCached != extBlockCount)
03188   {
03189     extBlockIndex = This->extBigBlockDepotLocations[extBlockCount];
03190 
03191     StorageImpl_ReadBigBlock(This, extBlockIndex, depotBuffer);
03192 
03193     num_blocks = This->bigBlockSize / 4;
03194 
03195     for (index = 0; index < num_blocks; index++)
03196     {
03197       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &blockIndex);
03198       This->extBlockDepotCached[index] = blockIndex;
03199     }
03200 
03201     This->indexExtBlockDepotCached = extBlockCount;
03202   }
03203 
03204   blockIndex = This->extBlockDepotCached[extBlockOffset];
03205 
03206   return blockIndex;
03207 }
03208 
03209 /******************************************************************************
03210  *      Storage32Impl_SetExtDepotBlock
03211  *
03212  * Associates the specified block index to the specified depot index.
03213  * This method is only for depot indexes equal or greater than
03214  * COUNT_BBDEPOTINHEADER.
03215  */
03216 static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
03217 {
03218   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
03219   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
03220   ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
03221   ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
03222   ULONG extBlockIndex;
03223 
03224   assert(depotIndex >= COUNT_BBDEPOTINHEADER);
03225 
03226   assert(extBlockCount < This->extBigBlockDepotCount);
03227 
03228   extBlockIndex = This->extBigBlockDepotLocations[extBlockCount];
03229 
03230   if (extBlockIndex != BLOCK_UNUSED)
03231   {
03232     StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
03233                         extBlockOffset * sizeof(ULONG),
03234                         blockIndex);
03235   }
03236 
03237   if (This->indexExtBlockDepotCached == extBlockCount)
03238   {
03239     This->extBlockDepotCached[extBlockOffset] = blockIndex;
03240   }
03241 }
03242 
03243 /******************************************************************************
03244  *      Storage32Impl_AddExtBlockDepot
03245  *
03246  * Creates an extended depot block.
03247  */
03248 static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
03249 {
03250   ULONG numExtBlocks           = This->extBigBlockDepotCount;
03251   ULONG nextExtBlock           = This->extBigBlockDepotStart;
03252   BYTE  depotBuffer[MAX_BIG_BLOCK_SIZE];
03253   ULONG index                  = BLOCK_UNUSED;
03254   ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
03255   ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
03256   ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
03257 
03258   index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
03259           blocksPerDepotBlock;
03260 
03261   if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
03262   {
03263     /*
03264      * The first extended block.
03265      */
03266     This->extBigBlockDepotStart = index;
03267   }
03268   else
03269   {
03270     /*
03271      * Find the last existing extended block.
03272      */
03273     nextExtBlock = This->extBigBlockDepotLocations[This->extBigBlockDepotCount-1];
03274 
03275     /*
03276      * Add the new extended block to the chain.
03277      */
03278     StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
03279                                      index);
03280   }
03281 
03282   /*
03283    * Initialize this block.
03284    */
03285   memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
03286   StorageImpl_WriteBigBlock(This, index, depotBuffer);
03287 
03288   /* Add the block to our cache. */
03289   if (This->extBigBlockDepotLocationsSize == numExtBlocks)
03290   {
03291     ULONG new_cache_size = (This->extBigBlockDepotLocationsSize+1)*2;
03292     ULONG *new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * new_cache_size);
03293 
03294     memcpy(new_cache, This->extBigBlockDepotLocations, sizeof(ULONG) * This->extBigBlockDepotLocationsSize);
03295     HeapFree(GetProcessHeap(), 0, This->extBigBlockDepotLocations);
03296 
03297     This->extBigBlockDepotLocations = new_cache;
03298     This->extBigBlockDepotLocationsSize = new_cache_size;
03299   }
03300   This->extBigBlockDepotLocations[numExtBlocks] = index;
03301 
03302   return index;
03303 }
03304 
03305 /******************************************************************************
03306  *      Storage32Impl_FreeBigBlock
03307  *
03308  * This method will flag the specified block as free in the big block depot.
03309  */
03310 static void StorageImpl_FreeBigBlock(
03311   StorageImpl* This,
03312   ULONG          blockIndex)
03313 {
03314   StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
03315 
03316   if (blockIndex < This->prevFreeBlock)
03317     This->prevFreeBlock = blockIndex;
03318 }
03319 
03320 /************************************************************************
03321  * Storage32Impl_GetNextBlockInChain
03322  *
03323  * This method will retrieve the block index of the next big block in
03324  * in the chain.
03325  *
03326  * Params:  This       - Pointer to the Storage object.
03327  *          blockIndex - Index of the block to retrieve the chain
03328  *                       for.
03329  *          nextBlockIndex - receives the return value.
03330  *
03331  * Returns: This method returns the index of the next block in the chain.
03332  *          It will return the constants:
03333  *              BLOCK_SPECIAL - If the block given was not part of a
03334  *                              chain.
03335  *              BLOCK_END_OF_CHAIN - If the block given was the last in
03336  *                                   a chain.
03337  *              BLOCK_UNUSED - If the block given was not past of a chain
03338  *                             and is available.
03339  *              BLOCK_EXTBBDEPOT - This block is part of the extended
03340  *                                 big block depot.
03341  *
03342  * See Windows documentation for more details on IStorage methods.
03343  */
03344 static HRESULT StorageImpl_GetNextBlockInChain(
03345   StorageImpl* This,
03346   ULONG        blockIndex,
03347   ULONG*       nextBlockIndex)
03348 {
03349   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
03350   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
03351   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
03352   BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
03353   BOOL success;
03354   ULONG depotBlockIndexPos;
03355   int index, num_blocks;
03356 
03357   *nextBlockIndex   = BLOCK_SPECIAL;
03358 
03359   if(depotBlockCount >= This->bigBlockDepotCount)
03360   {
03361     WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
03362      This->bigBlockDepotCount);
03363     return STG_E_READFAULT;
03364   }
03365 
03366   /*
03367    * Cache the currently accessed depot block.
03368    */
03369   if (depotBlockCount != This->indexBlockDepotCached)
03370   {
03371     This->indexBlockDepotCached = depotBlockCount;
03372 
03373     if (depotBlockCount < COUNT_BBDEPOTINHEADER)
03374     {
03375       depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
03376     }
03377     else
03378     {
03379       /*
03380        * We have to look in the extended depot.
03381        */
03382       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
03383     }
03384 
03385     success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
03386 
03387     if (!success)
03388       return STG_E_READFAULT;
03389 
03390     num_blocks = This->bigBlockSize / 4;
03391 
03392     for (index = 0; index < num_blocks; index++)
03393     {
03394       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
03395       This->blockDepotCached[index] = *nextBlockIndex;
03396     }
03397   }
03398 
03399   *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
03400 
03401   return S_OK;
03402 }
03403 
03404 /******************************************************************************
03405  *      Storage32Impl_GetNextExtendedBlock
03406  *
03407  * Given an extended block this method will return the next extended block.
03408  *
03409  * NOTES:
03410  * The last ULONG of an extended block is the block index of the next
03411  * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
03412  * depot.
03413  *
03414  * Return values:
03415  *    - The index of the next extended block
03416  *    - BLOCK_UNUSED: there is no next extended block.
03417  *    - Any other return values denotes failure.
03418  */
03419 static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
03420 {
03421   ULONG nextBlockIndex   = BLOCK_SPECIAL;
03422   ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
03423 
03424   StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
03425                         &nextBlockIndex);
03426 
03427   return nextBlockIndex;
03428 }
03429 
03430 /******************************************************************************
03431  *      Storage32Impl_SetNextBlockInChain
03432  *
03433  * This method will write the index of the specified block's next block
03434  * in the big block depot.
03435  *
03436  * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
03437  *              do the following
03438  *
03439  * Storage32Impl_SetNextBlockInChain(This, 3, 1);
03440  * Storage32Impl_SetNextBlockInChain(This, 1, 7);
03441  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
03442  *
03443  */
03444 static void StorageImpl_SetNextBlockInChain(
03445           StorageImpl* This,
03446           ULONG          blockIndex,
03447           ULONG          nextBlock)
03448 {
03449   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
03450   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
03451   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
03452   ULONG depotBlockIndexPos;
03453 
03454   assert(depotBlockCount < This->bigBlockDepotCount);
03455   assert(blockIndex != nextBlock);
03456 
03457   if (depotBlockCount < COUNT_BBDEPOTINHEADER)
03458   {
03459     depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
03460   }
03461   else
03462   {
03463     /*
03464      * We have to look in the extended depot.
03465      */
03466     depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
03467   }
03468 
03469   StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
03470                         nextBlock);
03471   /*
03472    * Update the cached block depot, if necessary.
03473    */
03474   if (depotBlockCount == This->indexBlockDepotCached)
03475   {
03476     This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
03477   }
03478 }
03479 
03480 /******************************************************************************
03481  *      Storage32Impl_LoadFileHeader
03482  *
03483  * This method will read in the file header
03484  */
03485 static HRESULT StorageImpl_LoadFileHeader(
03486           StorageImpl* This)
03487 {
03488   HRESULT hr;
03489   BYTE    headerBigBlock[HEADER_SIZE];
03490   int     index;
03491   ULARGE_INTEGER offset;
03492   DWORD bytes_read;
03493 
03494   TRACE("\n");
03495   /*
03496    * Get a pointer to the big block of data containing the header.
03497    */
03498   offset.u.HighPart = 0;
03499   offset.u.LowPart = 0;
03500   hr = StorageImpl_ReadAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_read);
03501   if (SUCCEEDED(hr) && bytes_read != HEADER_SIZE)
03502     hr = STG_E_FILENOTFOUND;
03503 
03504   /*
03505    * Extract the information from the header.
03506    */
03507   if (SUCCEEDED(hr))
03508   {
03509     /*
03510      * Check for the "magic number" signature and return an error if it is not
03511      * found.
03512      */
03513     if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
03514     {
03515       return STG_E_OLDFORMAT;
03516     }
03517 
03518     if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
03519     {
03520       return STG_E_INVALIDHEADER;
03521     }
03522 
03523     StorageUtl_ReadWord(
03524       headerBigBlock,
03525       OFFSET_BIGBLOCKSIZEBITS,
03526       &This->bigBlockSizeBits);
03527 
03528     StorageUtl_ReadWord(
03529       headerBigBlock,
03530       OFFSET_SMALLBLOCKSIZEBITS,
03531       &This->smallBlockSizeBits);
03532 
03533     StorageUtl_ReadDWord(
03534       headerBigBlock,
03535       OFFSET_BBDEPOTCOUNT,
03536       &This->bigBlockDepotCount);
03537 
03538     StorageUtl_ReadDWord(
03539       headerBigBlock,
03540       OFFSET_ROOTSTARTBLOCK,
03541       &This->rootStartBlock);
03542 
03543     StorageUtl_ReadDWord(
03544       headerBigBlock,
03545       OFFSET_SMALLBLOCKLIMIT,
03546       &This->smallBlockLimit);
03547 
03548     StorageUtl_ReadDWord(
03549       headerBigBlock,
03550       OFFSET_SBDEPOTSTART,
03551       &This->smallBlockDepotStart);
03552 
03553     StorageUtl_ReadDWord(
03554       headerBigBlock,
03555       OFFSET_EXTBBDEPOTSTART,
03556       &This->extBigBlockDepotStart);
03557 
03558     StorageUtl_ReadDWord(
03559       headerBigBlock,
03560       OFFSET_EXTBBDEPOTCOUNT,
03561       &This->extBigBlockDepotCount);
03562 
03563     for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
03564     {
03565       StorageUtl_ReadDWord(
03566         headerBigBlock,
03567         OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
03568         &(This->bigBlockDepotStart[index]));
03569     }
03570 
03571     /*
03572      * Make the bitwise arithmetic to get the size of the blocks in bytes.
03573      */
03574     This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
03575     This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
03576 
03577     /*
03578      * Right now, the code is making some assumptions about the size of the
03579      * blocks, just make sure they are what we're expecting.
03580      */
03581     if ((This->bigBlockSize != MIN_BIG_BLOCK_SIZE && This->bigBlockSize != MAX_BIG_BLOCK_SIZE) ||
03582     This->smallBlockSize != DEF_SMALL_BLOCK_SIZE ||
03583     This->smallBlockLimit != LIMIT_TO_USE_SMALL_BLOCK)
03584     {
03585     FIXME("Broken OLE storage file? bigblock=0x%x, smallblock=0x%x, sblimit=0x%x\n",
03586         This->bigBlockSize, This->smallBlockSize, This->smallBlockLimit);
03587     hr = STG_E_INVALIDHEADER;
03588     }
03589     else
03590     hr = S_OK;
03591   }
03592 
03593   return hr;
03594 }
03595 
03596 /******************************************************************************
03597  *      Storage32Impl_SaveFileHeader
03598  *
03599  * This method will save to the file the header
03600  */
03601 static void StorageImpl_SaveFileHeader(
03602           StorageImpl* This)
03603 {
03604   BYTE   headerBigBlock[HEADER_SIZE];
03605   int    index;
03606   HRESULT hr;
03607   ULARGE_INTEGER offset;
03608   DWORD bytes_read, bytes_written;
03609   DWORD major_version, dirsectorcount;
03610 
03611   /*
03612    * Get a pointer to the big block of data containing the header.
03613    */
03614   offset.u.HighPart = 0;
03615   offset.u.LowPart = 0;
03616   hr = StorageImpl_ReadAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_read);
03617   if (SUCCEEDED(hr) && bytes_read != HEADER_SIZE)
03618     hr = STG_E_FILENOTFOUND;
03619 
03620   if (This->bigBlockSizeBits == 0x9)
03621     major_version = 3;
03622   else if (This->bigBlockSizeBits == 0xc)
03623     major_version = 4;
03624   else
03625   {
03626     ERR("invalid big block shift 0x%x\n", This->bigBlockSizeBits);
03627     major_version = 4;
03628   }
03629 
03630   /*
03631    * If the block read failed, the file is probably new.
03632    */
03633   if (FAILED(hr))
03634   {
03635     /*
03636      * Initialize for all unknown fields.
03637      */
03638     memset(headerBigBlock, 0, HEADER_SIZE);
03639 
03640     /*
03641      * Initialize the magic number.
03642      */
03643     memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
03644   }
03645 
03646   /*
03647    * Write the information to the header.
03648    */
03649   StorageUtl_WriteWord(
03650     headerBigBlock,
03651     OFFSET_MINORVERSION,
03652     0x3e);
03653 
03654   StorageUtl_WriteWord(
03655     headerBigBlock,
03656     OFFSET_MAJORVERSION,
03657     major_version);
03658 
03659   StorageUtl_WriteWord(
03660     headerBigBlock,
03661     OFFSET_BYTEORDERMARKER,
03662     (WORD)-2);
03663 
03664   StorageUtl_WriteWord(
03665     headerBigBlock,
03666     OFFSET_BIGBLOCKSIZEBITS,
03667     This->bigBlockSizeBits);
03668 
03669   StorageUtl_WriteWord(
03670     headerBigBlock,
03671     OFFSET_SMALLBLOCKSIZEBITS,
03672     This->smallBlockSizeBits);
03673 
03674   if (major_version >= 4)
03675   {
03676     if (This->rootBlockChain)
03677       dirsectorcount = BlockChainStream_GetCount(This->rootBlockChain);
03678     else
03679       /* This file is being created, and it will start out with one block. */
03680       dirsectorcount = 1;
03681   }
03682   else
03683     /* This field must be 0 in versions older than 4 */
03684     dirsectorcount = 0;
03685 
03686   StorageUtl_WriteDWord(
03687     headerBigBlock,
03688     OFFSET_DIRSECTORCOUNT,
03689     dirsectorcount);
03690 
03691   StorageUtl_WriteDWord(
03692     headerBigBlock,
03693     OFFSET_BBDEPOTCOUNT,
03694     This->bigBlockDepotCount);
03695 
03696   StorageUtl_WriteDWord(
03697     headerBigBlock,
03698     OFFSET_ROOTSTARTBLOCK,
03699     This->rootStartBlock);
03700 
03701   StorageUtl_WriteDWord(
03702     headerBigBlock,
03703     OFFSET_SMALLBLOCKLIMIT,
03704     This->smallBlockLimit);
03705 
03706   StorageUtl_WriteDWord(
03707     headerBigBlock,
03708     OFFSET_SBDEPOTSTART,
03709     This->smallBlockDepotStart);
03710 
03711   StorageUtl_WriteDWord(
03712     headerBigBlock,
03713     OFFSET_SBDEPOTCOUNT,
03714     This->smallBlockDepotChain ?
03715      BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
03716 
03717   StorageUtl_WriteDWord(
03718     headerBigBlock,
03719     OFFSET_EXTBBDEPOTSTART,
03720     This->extBigBlockDepotStart);
03721 
03722   StorageUtl_WriteDWord(
03723     headerBigBlock,
03724     OFFSET_EXTBBDEPOTCOUNT,
03725     This->extBigBlockDepotCount);
03726 
03727   for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
03728   {
03729     StorageUtl_WriteDWord(
03730       headerBigBlock,
03731       OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
03732       (This->bigBlockDepotStart[index]));
03733   }
03734 
03735   /*
03736    * Write the big block back to the file.
03737    */
03738   StorageImpl_WriteAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_written);
03739 }
03740 
03741 /******************************************************************************
03742  *      StorageImpl_ReadRawDirEntry
03743  *
03744  * This method will read the raw data from a directory entry in the file.
03745  *
03746  * buffer must be RAW_DIRENTRY_SIZE bytes long.
03747  */
03748 HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer)
03749 {
03750   ULARGE_INTEGER offset;
03751   HRESULT hr;
03752   ULONG bytesRead;
03753 
03754   offset.u.HighPart = 0;
03755   offset.u.LowPart  = index * RAW_DIRENTRY_SIZE;
03756 
03757   hr = BlockChainStream_ReadAt(
03758                     This->rootBlockChain,
03759                     offset,
03760                     RAW_DIRENTRY_SIZE,
03761                     buffer,
03762                     &bytesRead);
03763 
03764   if (bytesRead != RAW_DIRENTRY_SIZE)
03765     return STG_E_READFAULT;
03766 
03767   return hr;
03768 }
03769 
03770 /******************************************************************************
03771  *      StorageImpl_WriteRawDirEntry
03772  *
03773  * This method will write the raw data from a directory entry in the file.
03774  *
03775  * buffer must be RAW_DIRENTRY_SIZE bytes long.
03776  */
03777 HRESULT StorageImpl_WriteRawDirEntry(StorageImpl *This, ULONG index, const BYTE *buffer)
03778 {
03779   ULARGE_INTEGER offset;
03780   HRESULT hr;
03781   ULONG bytesRead;
03782 
03783   offset.u.HighPart = 0;
03784   offset.u.LowPart  = index * RAW_DIRENTRY_SIZE;
03785 
03786   hr = BlockChainStream_WriteAt(
03787                     This->rootBlockChain,
03788                     offset,
03789                     RAW_DIRENTRY_SIZE,
03790                     buffer,
03791                     &bytesRead);
03792 
03793   return hr;
03794 }
03795 
03796 /******************************************************************************
03797  *      UpdateRawDirEntry
03798  *
03799  * Update raw directory entry data from the fields in newData.
03800  *
03801  * buffer must be RAW_DIRENTRY_SIZE bytes long.
03802  */
03803 void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData)
03804 {
03805   memset(buffer, 0, RAW_DIRENTRY_SIZE);
03806 
03807   memcpy(
03808     buffer + OFFSET_PS_NAME,
03809     newData->name,
03810     DIRENTRY_NAME_BUFFER_LEN );
03811 
03812   memcpy(buffer + OFFSET_PS_STGTYPE, &newData->stgType, 1);
03813 
03814   StorageUtl_WriteWord(
03815     buffer,
03816       OFFSET_PS_NAMELENGTH,
03817       newData->sizeOfNameString);
03818 
03819   StorageUtl_WriteDWord(
03820     buffer,
03821       OFFSET_PS_LEFTCHILD,
03822       newData->leftChild);
03823 
03824   StorageUtl_WriteDWord(
03825     buffer,
03826       OFFSET_PS_RIGHTCHILD,
03827       newData->rightChild);
03828 
03829   StorageUtl_WriteDWord(
03830     buffer,
03831       OFFSET_PS_DIRROOT,
03832       newData->dirRootEntry);
03833 
03834   StorageUtl_WriteGUID(
03835     buffer,
03836       OFFSET_PS_GUID,
03837       &newData->clsid);
03838 
03839   StorageUtl_WriteDWord(
03840     buffer,
03841       OFFSET_PS_CTIMELOW,
03842       newData->ctime.dwLowDateTime);
03843 
03844   StorageUtl_WriteDWord(
03845     buffer,
03846       OFFSET_PS_CTIMEHIGH,
03847       newData->ctime.dwHighDateTime);
03848 
03849   StorageUtl_WriteDWord(
03850     buffer,
03851       OFFSET_PS_MTIMELOW,
03852       newData->mtime.dwLowDateTime);
03853 
03854   StorageUtl_WriteDWord(
03855     buffer,
03856       OFFSET_PS_MTIMEHIGH,
03857       newData->ctime.dwHighDateTime);
03858 
03859   StorageUtl_WriteDWord(
03860     buffer,
03861       OFFSET_PS_STARTBLOCK,
03862       newData->startingBlock);
03863 
03864   StorageUtl_WriteDWord(
03865     buffer,
03866       OFFSET_PS_SIZE,
03867       newData->size.u.LowPart);
03868 }
03869 
03870 /******************************************************************************
03871  *      Storage32Impl_ReadDirEntry
03872  *
03873  * This method will read the specified directory entry.
03874  */
03875 HRESULT StorageImpl_ReadDirEntry(
03876   StorageImpl* This,
03877   DirRef         index,
03878   DirEntry*      buffer)
03879 {
03880   BYTE           currentEntry[RAW_DIRENTRY_SIZE];
03881   HRESULT        readRes;
03882 
03883   readRes = StorageImpl_ReadRawDirEntry(This, index, currentEntry);
03884 
03885   if (SUCCEEDED(readRes))
03886   {
03887     memset(buffer->name, 0, sizeof(buffer->name));
03888     memcpy(
03889       buffer->name,
03890       (WCHAR *)currentEntry+OFFSET_PS_NAME,
03891       DIRENTRY_NAME_BUFFER_LEN );
03892     TRACE("storage name: %s\n", debugstr_w(buffer->name));
03893 
03894     memcpy(&buffer->stgType, currentEntry + OFFSET_PS_STGTYPE, 1);
03895 
03896     StorageUtl_ReadWord(
03897       currentEntry,
03898       OFFSET_PS_NAMELENGTH,
03899       &buffer->sizeOfNameString);
03900 
03901     StorageUtl_ReadDWord(
03902       currentEntry,
03903       OFFSET_PS_LEFTCHILD,
03904       &buffer->leftChild);
03905 
03906     StorageUtl_ReadDWord(
03907       currentEntry,
03908       OFFSET_PS_RIGHTCHILD,
03909       &buffer->rightChild);
03910 
03911     StorageUtl_ReadDWord(
03912       currentEntry,
03913       OFFSET_PS_DIRROOT,
03914       &buffer->dirRootEntry);
03915 
03916     StorageUtl_ReadGUID(
03917       currentEntry,
03918       OFFSET_PS_GUID,
03919       &buffer->clsid);
03920 
03921     StorageUtl_ReadDWord(
03922       currentEntry,
03923       OFFSET_PS_CTIMELOW,
03924       &buffer->ctime.dwLowDateTime);
03925 
03926     StorageUtl_ReadDWord(
03927       currentEntry,
03928       OFFSET_PS_CTIMEHIGH,
03929       &buffer->ctime.dwHighDateTime);
03930 
03931     StorageUtl_ReadDWord(
03932       currentEntry,
03933       OFFSET_PS_MTIMELOW,
03934       &buffer->mtime.dwLowDateTime);
03935 
03936     StorageUtl_ReadDWord(
03937       currentEntry,
03938       OFFSET_PS_MTIMEHIGH,
03939       &buffer->mtime.dwHighDateTime);
03940 
03941     StorageUtl_ReadDWord(
03942       currentEntry,
03943       OFFSET_PS_STARTBLOCK,
03944       &buffer->startingBlock);
03945 
03946     StorageUtl_ReadDWord(
03947       currentEntry,
03948       OFFSET_PS_SIZE,
03949       &buffer->size.u.LowPart);
03950 
03951     buffer->size.u.HighPart = 0;
03952   }
03953 
03954   return readRes;
03955 }
03956 
03957 /*********************************************************************
03958  * Write the specified directory entry to the file
03959  */
03960 HRESULT StorageImpl_WriteDirEntry(
03961   StorageImpl*          This,
03962   DirRef                index,
03963   const DirEntry*       buffer)
03964 {
03965   BYTE           currentEntry[RAW_DIRENTRY_SIZE];
03966   HRESULT        writeRes;
03967 
03968   UpdateRawDirEntry(currentEntry, buffer);
03969 
03970   writeRes = StorageImpl_WriteRawDirEntry(This, index, currentEntry);
03971   return writeRes;
03972 }
03973 
03974 static BOOL StorageImpl_ReadBigBlock(
03975   StorageImpl* This,
03976   ULONG          blockIndex,
03977   void*          buffer)
03978 {
03979   ULARGE_INTEGER ulOffset;
03980   DWORD  read=0;
03981 
03982   ulOffset.u.HighPart = 0;
03983   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
03984 
03985   StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
03986 
03987   if (read && read < This->bigBlockSize)
03988   {
03989     /* File ends during this block; fill the rest with 0's. */
03990     memset((LPBYTE)buffer+read, 0, This->bigBlockSize-read);
03991   }
03992 
03993   return (read != 0);
03994 }
03995 
03996 static BOOL StorageImpl_ReadDWordFromBigBlock(
03997   StorageImpl*  This,
03998   ULONG         blockIndex,
03999   ULONG         offset,
04000   DWORD*        value)
04001 {
04002   ULARGE_INTEGER ulOffset;
04003   DWORD  read;
04004   DWORD  tmp;
04005 
04006   ulOffset.u.HighPart = 0;
04007   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
04008   ulOffset.u.LowPart += offset;
04009 
04010   StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
04011   *value = lendian32toh(tmp);
04012   return (read == sizeof(DWORD));
04013 }
04014 
04015 static BOOL StorageImpl_WriteBigBlock(
04016   StorageImpl*  This,
04017   ULONG         blockIndex,
04018   const void*   buffer)
04019 {
04020   ULARGE_INTEGER ulOffset;
04021   DWORD  wrote;
04022 
04023   ulOffset.u.HighPart = 0;
04024   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
04025 
04026   StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
04027   return (wrote == This->bigBlockSize);
04028 }
04029 
04030 static BOOL StorageImpl_WriteDWordToBigBlock(
04031   StorageImpl* This,
04032   ULONG         blockIndex,
04033   ULONG         offset,
04034   DWORD         value)
04035 {
04036   ULARGE_INTEGER ulOffset;
04037   DWORD  wrote;
04038 
04039   ulOffset.u.HighPart = 0;
04040   ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
04041   ulOffset.u.LowPart += offset;
04042 
04043   value = htole32(value);
04044   StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
04045   return (wrote == sizeof(DWORD));
04046 }
04047 
04048 /******************************************************************************
04049  *              Storage32Impl_SmallBlocksToBigBlocks
04050  *
04051  * This method will convert a small block chain to a big block chain.
04052  * The small block chain will be destroyed.
04053  */
04054 BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
04055                       StorageImpl* This,
04056                       SmallBlockChainStream** ppsbChain)
04057 {
04058   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
04059   ULARGE_INTEGER size, offset;
04060   ULONG cbRead, cbWritten;
04061   ULARGE_INTEGER cbTotalRead;
04062   DirRef streamEntryRef;
04063   HRESULT resWrite = S_OK;
04064   HRESULT resRead;
04065   DirEntry streamEntry;
04066   BYTE *buffer;
04067   BlockChainStream *bbTempChain = NULL;
04068   BlockChainStream *bigBlockChain = NULL;
04069 
04070   /*
04071    * Create a temporary big block chain that doesn't have
04072    * an associated directory entry. This temporary chain will be
04073    * used to copy data from small blocks to big blocks.
04074    */
04075   bbTempChain = BlockChainStream_Construct(This,
04076                                            &bbHeadOfChain,
04077                                            DIRENTRY_NULL);
04078   if(!bbTempChain) return NULL;
04079   /*
04080    * Grow the big block chain.
04081    */
04082   size = SmallBlockChainStream_GetSize(*ppsbChain);
04083   BlockChainStream_SetSize(bbTempChain, size);
04084 
04085   /*
04086    * Copy the contents of the small block chain to the big block chain
04087    * by small block size increments.
04088    */
04089   offset.u.LowPart = 0;
04090   offset.u.HighPart = 0;
04091   cbTotalRead.QuadPart = 0;
04092 
04093   buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
04094   do
04095   {
04096     resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
04097                                            offset,
04098                                            min(This->smallBlockSize, size.u.LowPart - offset.u.LowPart),
04099                                            buffer,
04100                                            &cbRead);
04101     if (FAILED(resRead))
04102         break;
04103 
04104     if (cbRead > 0)
04105     {
04106         cbTotalRead.QuadPart += cbRead;
04107 
04108         resWrite = BlockChainStream_WriteAt(bbTempChain,
04109                                             offset,
04110                                             cbRead,
04111                                             buffer,
04112                                             &cbWritten);
04113 
04114         if (FAILED(resWrite))
04115             break;
04116 
04117         offset.u.LowPart += cbRead;
04118     }
04119     else
04120     {
04121         resRead = STG_E_READFAULT;
04122         break;
04123     }
04124   } while (cbTotalRead.QuadPart < size.QuadPart);
04125   HeapFree(GetProcessHeap(),0,buffer);
04126 
04127   size.u.HighPart = 0;
04128   size.u.LowPart  = 0;
04129 
04130   if (FAILED(resRead) || FAILED(resWrite))
04131   {
04132     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
04133     BlockChainStream_SetSize(bbTempChain, size);
04134     BlockChainStream_Destroy(bbTempChain);
04135     return NULL;
04136   }
04137 
04138   /*
04139    * Destroy the small block chain.
04140    */
04141   streamEntryRef = (*ppsbChain)->ownerDirEntry;
04142   SmallBlockChainStream_SetSize(*ppsbChain, size);
04143   SmallBlockChainStream_Destroy(*ppsbChain);
04144   *ppsbChain = 0;
04145 
04146   /*
04147    * Change the directory entry. This chain is now a big block chain
04148    * and it doesn't reside in the small blocks chain anymore.
04149    */
04150   StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
04151 
04152   streamEntry.startingBlock = bbHeadOfChain;
04153 
04154   StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
04155 
04156   /*
04157    * Destroy the temporary entryless big block chain.
04158    * Create a new big block chain associated with this entry.
04159    */
04160   BlockChainStream_Destroy(bbTempChain);
04161   bigBlockChain = BlockChainStream_Construct(This,
04162                                              NULL,
04163                                              streamEntryRef);
04164 
04165   return bigBlockChain;
04166 }
04167 
04168 /******************************************************************************
04169  *              Storage32Impl_BigBlocksToSmallBlocks
04170  *
04171  * This method will convert a big block chain to a small block chain.
04172  * The big block chain will be destroyed on success.
04173  */
04174 SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
04175                            StorageImpl* This,
04176                            BlockChainStream** ppbbChain,
04177                            ULARGE_INTEGER newSize)
04178 {
04179     ULARGE_INTEGER size, offset, cbTotalRead;
04180     ULONG cbRead, cbWritten, sbHeadOfChain = BLOCK_END_OF_CHAIN;
04181     DirRef streamEntryRef;
04182     HRESULT resWrite = S_OK, resRead = S_OK;
04183     DirEntry streamEntry;
04184     BYTE* buffer;
04185     SmallBlockChainStream* sbTempChain;
04186 
04187     TRACE("%p %p\n", This, ppbbChain);
04188 
04189     sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain,
04190             DIRENTRY_NULL);
04191 
04192     if(!sbTempChain)
04193         return NULL;
04194 
04195     SmallBlockChainStream_SetSize(sbTempChain, newSize);
04196     size = BlockChainStream_GetSize(*ppbbChain);
04197     size.QuadPart = min(size.QuadPart, newSize.QuadPart);
04198 
04199     offset.u.HighPart = 0;
04200     offset.u.LowPart = 0;
04201     cbTotalRead.QuadPart = 0;
04202     buffer = HeapAlloc(GetProcessHeap(), 0, This->bigBlockSize);
04203     while(cbTotalRead.QuadPart < size.QuadPart)
04204     {
04205         resRead = BlockChainStream_ReadAt(*ppbbChain, offset,
04206                 min(This->bigBlockSize, size.u.LowPart - offset.u.LowPart),
04207                 buffer, &cbRead);
04208 
04209         if(FAILED(resRead))
04210             break;
04211 
04212         if(cbRead > 0)
04213         {
04214             cbTotalRead.QuadPart += cbRead;
04215 
04216             resWrite = SmallBlockChainStream_WriteAt(sbTempChain, offset,
04217                     cbRead, buffer, &cbWritten);
04218 
04219             if(FAILED(resWrite))
04220                 break;
04221 
04222             offset.u.LowPart += cbRead;
04223         }
04224         else
04225         {
04226             resRead = STG_E_READFAULT;
04227             break;
04228         }
04229     }
04230     HeapFree(GetProcessHeap(), 0, buffer);
04231 
04232     size.u.HighPart = 0;
04233     size.u.LowPart = 0;
04234 
04235     if(FAILED(resRead) || FAILED(resWrite))
04236     {
04237         ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
04238         SmallBlockChainStream_SetSize(sbTempChain, size);
04239         SmallBlockChainStream_Destroy(sbTempChain);
04240         return NULL;
04241     }
04242 
04243     /* destroy the original big block chain */
04244     streamEntryRef = (*ppbbChain)->ownerDirEntry;
04245     BlockChainStream_SetSize(*ppbbChain, size);
04246     BlockChainStream_Destroy(*ppbbChain);
04247     *ppbbChain = NULL;
04248 
04249     StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
04250     streamEntry.startingBlock = sbHeadOfChain;
04251     StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
04252 
04253     SmallBlockChainStream_Destroy(sbTempChain);
04254     return SmallBlockChainStream_Construct(This, NULL, streamEntryRef);
04255 }
04256 
04257 static HRESULT StorageBaseImpl_CopyStream(
04258   StorageBaseImpl *dst, DirRef dst_entry,
04259   StorageBaseImpl *src, DirRef src_entry)
04260 {
04261   HRESULT hr;
04262   BYTE data[4096];
04263   DirEntry srcdata;
04264   ULARGE_INTEGER bytes_copied;
04265   ULONG bytestocopy, bytesread, byteswritten;
04266 
04267   hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &srcdata);
04268 
04269   if (SUCCEEDED(hr))
04270   {
04271     hr = StorageBaseImpl_StreamSetSize(dst, dst_entry, srcdata.size);
04272 
04273     bytes_copied.QuadPart = 0;
04274     while (bytes_copied.QuadPart < srcdata.size.QuadPart && SUCCEEDED(hr))
04275     {
04276       bytestocopy = min(4096, srcdata.size.QuadPart - bytes_copied.QuadPart);
04277 
04278       hr = StorageBaseImpl_StreamReadAt(src, src_entry, bytes_copied, bytestocopy,
04279         data, &bytesread);
04280       if (SUCCEEDED(hr) && bytesread != bytestocopy) hr = STG_E_READFAULT;
04281 
04282       if (SUCCEEDED(hr))
04283         hr = StorageBaseImpl_StreamWriteAt(dst, dst_entry, bytes_copied, bytestocopy,
04284           data, &byteswritten);
04285       if (SUCCEEDED(hr))
04286       {
04287         if (byteswritten != bytestocopy) hr = STG_E_WRITEFAULT;
04288         bytes_copied.QuadPart += byteswritten;
04289       }
04290     }
04291   }
04292 
04293   return hr;
04294 }
04295 
04296 static DirRef TransactedSnapshotImpl_FindFreeEntry(TransactedSnapshotImpl *This)
04297 {
04298   DirRef result=This->firstFreeEntry;
04299 
04300   while (result < This->entries_size && This->entries[result].inuse)
04301     result++;
04302 
04303   if (result == This->entries_size)
04304   {
04305     ULONG new_size = This->entries_size * 2;
04306     TransactedDirEntry *new_entries;
04307 
04308     new_entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * new_size);
04309     if (!new_entries) return DIRENTRY_NULL;
04310 
04311     memcpy(new_entries, This->entries, sizeof(TransactedDirEntry) * This->entries_size);
04312     HeapFree(GetProcessHeap(), 0, This->entries);
04313 
04314     This->entries = new_entries;
04315     This->entries_size = new_size;
04316   }
04317 
04318   This->entries[result].inuse = 1;
04319 
04320   This->firstFreeEntry = result+1;
04321 
04322   return result;
04323 }
04324 
04325 static DirRef TransactedSnapshotImpl_CreateStubEntry(
04326   TransactedSnapshotImpl *This, DirRef parentEntryRef)
04327 {
04328   DirRef stubEntryRef;
04329   TransactedDirEntry *entry;
04330 
04331   stubEntryRef = TransactedSnapshotImpl_FindFreeEntry(This);
04332 
04333   if (stubEntryRef != DIRENTRY_NULL)
04334   {
04335     entry = &This->entries[stubEntryRef];
04336 
04337     entry->newTransactedParentEntry = entry->transactedParentEntry = parentEntryRef;
04338 
04339     entry->read = 0;
04340   }
04341 
04342   return stubEntryRef;
04343 }
04344 
04345 static HRESULT TransactedSnapshotImpl_EnsureReadEntry(
04346   TransactedSnapshotImpl *This, DirRef entry)
04347 {
04348   HRESULT hr=S_OK;
04349   DirEntry data;
04350 
04351   if (!This->entries[entry].read)
04352   {
04353     hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
04354         This->entries[entry].transactedParentEntry,
04355         &data);
04356 
04357     if (SUCCEEDED(hr) && data.leftChild != DIRENTRY_NULL)
04358     {
04359       data.leftChild = TransactedSnapshotImpl_CreateStubEntry(This, data.leftChild);
04360 
04361       if (data.leftChild == DIRENTRY_NULL)
04362         hr = E_OUTOFMEMORY;
04363     }
04364 
04365     if (SUCCEEDED(hr) && data.rightChild != DIRENTRY_NULL)
04366     {
04367       data.rightChild = TransactedSnapshotImpl_CreateStubEntry(This, data.rightChild);
04368 
04369       if (data.rightChild == DIRENTRY_NULL)
04370         hr = E_OUTOFMEMORY;
04371     }
04372 
04373     if (SUCCEEDED(hr) && data.dirRootEntry != DIRENTRY_NULL)
04374     {
04375       data.dirRootEntry = TransactedSnapshotImpl_CreateStubEntry(This, data.dirRootEntry);
04376 
04377       if (data.dirRootEntry == DIRENTRY_NULL)
04378         hr = E_OUTOFMEMORY;
04379     }
04380 
04381     if (SUCCEEDED(hr))
04382     {
04383       memcpy(&This->entries[entry].data, &data, sizeof(DirEntry));
04384       This->entries[entry].read = 1;
04385     }
04386   }
04387 
04388   return hr;
04389 }
04390 
04391 static HRESULT TransactedSnapshotImpl_MakeStreamDirty(
04392   TransactedSnapshotImpl *This, DirRef entry)
04393 {
04394   HRESULT hr = S_OK;
04395 
04396   if (!This->entries[entry].stream_dirty)
04397   {
04398     DirEntry new_entrydata;
04399 
04400     memset(&new_entrydata, 0, sizeof(DirEntry));
04401     new_entrydata.name[0] = 'S';
04402     new_entrydata.sizeOfNameString = 1;
04403     new_entrydata.stgType = STGTY_STREAM;
04404     new_entrydata.startingBlock = BLOCK_END_OF_CHAIN;
04405     new_entrydata.leftChild = DIRENTRY_NULL;
04406     new_entrydata.rightChild = DIRENTRY_NULL;
04407     new_entrydata.dirRootEntry = DIRENTRY_NULL;
04408 
04409     hr = StorageBaseImpl_CreateDirEntry(This->scratch, &new_entrydata,
04410       &This->entries[entry].stream_entry);
04411 
04412     if (SUCCEEDED(hr) && This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
04413     {
04414       hr = StorageBaseImpl_CopyStream(
04415         This->scratch, This->entries[entry].stream_entry,
04416         This->transactedParent, This->entries[entry].transactedParentEntry);
04417 
04418       if (FAILED(hr))
04419         StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[entry].stream_entry);
04420     }
04421 
04422     if (SUCCEEDED(hr))
04423       This->entries[entry].stream_dirty = 1;
04424 
04425     if (This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
04426     {
04427       /* Since this entry is modified, and we aren't using its stream data, we
04428        * no longer care about the original entry. */
04429       DirRef delete_ref;
04430       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[entry].transactedParentEntry);
04431 
04432       if (delete_ref != DIRENTRY_NULL)
04433         This->entries[delete_ref].deleted = 1;
04434 
04435       This->entries[entry].transactedParentEntry = This->entries[entry].newTransactedParentEntry = DIRENTRY_NULL;
04436     }
04437   }
04438 
04439   return hr;
04440 }
04441 
04442 /* Find the first entry in a depth-first traversal. */
04443 static DirRef TransactedSnapshotImpl_FindFirstChild(
04444   TransactedSnapshotImpl* This, DirRef parent)
04445 {
04446   DirRef cursor, prev;
04447   TransactedDirEntry *entry;
04448 
04449   cursor = parent;
04450   entry = &This->entries[cursor];
04451   while (entry->read)
04452   {
04453     if (entry->data.leftChild != DIRENTRY_NULL)
04454     {
04455       prev = cursor;
04456       cursor = entry->data.leftChild;
04457       entry = &This->entries[cursor];
04458       entry->parent = prev;
04459     }
04460     else if (entry->data.rightChild != DIRENTRY_NULL)
04461     {
04462       prev = cursor;
04463       cursor = entry->data.rightChild;
04464       entry = &This->entries[cursor];
04465       entry->parent = prev;
04466     }
04467     else if (entry->data.dirRootEntry != DIRENTRY_NULL)
04468     {
04469       prev = cursor;
04470       cursor = entry->data.dirRootEntry;
04471       entry = &This->entries[cursor];
04472       entry->parent = prev;
04473     }
04474     else
04475       break;
04476   }
04477 
04478   return cursor;
04479 }
04480 
04481 /* Find the next entry in a depth-first traversal. */
04482 static DirRef TransactedSnapshotImpl_FindNextChild(
04483   TransactedSnapshotImpl* This, DirRef current)
04484 {
04485   DirRef parent;
04486   TransactedDirEntry *parent_entry;
04487 
04488   parent = This->entries[current].parent;
04489   parent_entry = &This->entries[parent];
04490 
04491   if (parent != DIRENTRY_NULL && parent_entry->data.dirRootEntry != current)
04492   {
04493     if (parent_entry->data.rightChild != current && parent_entry->data.rightChild != DIRENTRY_NULL)
04494     {
04495       This->entries[parent_entry->data.rightChild].parent = parent;
04496       return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.rightChild);
04497     }
04498 
04499     if (parent_entry->data.dirRootEntry != DIRENTRY_NULL)
04500     {
04501       This->entries[parent_entry->data.dirRootEntry].parent = parent;
04502       return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.dirRootEntry);
04503     }
04504   }
04505 
04506   return parent;
04507 }
04508 
04509 /* Return TRUE if we've made a copy of this entry for committing to the parent. */
04510 static inline BOOL TransactedSnapshotImpl_MadeCopy(
04511   TransactedSnapshotImpl* This, DirRef entry)
04512 {
04513   return entry != DIRENTRY_NULL &&
04514     This->entries[entry].newTransactedParentEntry != This->entries[entry].transactedParentEntry;
04515 }
04516 
04517 /* Destroy the entries created by CopyTree. */
04518 static void TransactedSnapshotImpl_DestroyTemporaryCopy(
04519   TransactedSnapshotImpl* This, DirRef stop)
04520 {
04521   DirRef cursor;
04522   TransactedDirEntry *entry;
04523   ULARGE_INTEGER zero;
04524 
04525   zero.QuadPart = 0;
04526 
04527   if (!This->entries[This->base.storageDirEntry].read)
04528     return;
04529 
04530   cursor = This->entries[This->base.storageDirEntry].data.dirRootEntry;
04531 
04532   if (cursor == DIRENTRY_NULL)
04533     return;
04534 
04535   cursor = TransactedSnapshotImpl_FindFirstChild(This, cursor);
04536 
04537   while (cursor != DIRENTRY_NULL && cursor != stop)
04538   {
04539     if (TransactedSnapshotImpl_MadeCopy(This, cursor))
04540     {
04541       entry = &This->entries[cursor];
04542 
04543       if (entry->stream_dirty)
04544         StorageBaseImpl_StreamSetSize(This->transactedParent,
04545           entry->newTransactedParentEntry, zero);
04546 
04547       StorageBaseImpl_DestroyDirEntry(This->transactedParent,
04548         entry->newTransactedParentEntry);
04549 
04550       entry->newTransactedParentEntry = entry->transactedParentEntry;
04551     }
04552 
04553     cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
04554   }
04555 }
04556 
04557 /* Make a copy of our edited tree that we can use in the parent. */
04558 static HRESULT TransactedSnapshotImpl_CopyTree(TransactedSnapshotImpl* This)
04559 {
04560   DirRef cursor;
04561   TransactedDirEntry *entry;
04562   HRESULT hr = S_OK;
04563 
04564   cursor = This->base.storageDirEntry;
04565   entry = &This->entries[cursor];
04566   entry->parent = DIRENTRY_NULL;
04567   entry->newTransactedParentEntry = entry->transactedParentEntry;
04568 
04569   if (entry->data.dirRootEntry == DIRENTRY_NULL)
04570     return S_OK;
04571 
04572   This->entries[entry->data.dirRootEntry].parent = DIRENTRY_NULL;
04573 
04574   cursor = TransactedSnapshotImpl_FindFirstChild(This, entry->data.dirRootEntry);
04575   entry = &This->entries[cursor];
04576 
04577   while (cursor != DIRENTRY_NULL)
04578   {
04579     /* Make a copy of this entry in the transacted parent. */
04580     if (!entry->read ||
04581         (!entry->dirty && !entry->stream_dirty &&
04582          !TransactedSnapshotImpl_MadeCopy(This, entry->data.leftChild) &&
04583          !TransactedSnapshotImpl_MadeCopy(This, entry->data.rightChild) &&
04584          !TransactedSnapshotImpl_MadeCopy(This, entry->data.dirRootEntry)))
04585       entry->newTransactedParentEntry = entry->transactedParentEntry;
04586     else
04587     {
04588       DirEntry newData;
04589 
04590       memcpy(&newData, &entry->data, sizeof(DirEntry));
04591 
04592       newData.size.QuadPart = 0;
04593       newData.startingBlock = BLOCK_END_OF_CHAIN;
04594 
04595       if (newData.leftChild != DIRENTRY_NULL)
04596         newData.leftChild = This->entries[newData.leftChild].newTransactedParentEntry;
04597 
04598       if (newData.rightChild != DIRENTRY_NULL)
04599         newData.rightChild = This->entries[newData.rightChild].newTransactedParentEntry;
04600 
04601       if (newData.dirRootEntry != DIRENTRY_NULL)
04602         newData.dirRootEntry = This->entries[newData.dirRootEntry].newTransactedParentEntry;
04603 
04604       hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &newData,
04605         &entry->newTransactedParentEntry);
04606       if (FAILED(hr))
04607       {
04608         TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
04609         return hr;
04610       }
04611 
04612       if (entry->stream_dirty)
04613       {
04614         hr = StorageBaseImpl_CopyStream(
04615           This->transactedParent, entry->newTransactedParentEntry,
04616           This->scratch, entry->stream_entry);
04617       }
04618       else if (entry->data.size.QuadPart)
04619       {
04620         hr = StorageBaseImpl_StreamLink(
04621           This->transactedParent, entry->newTransactedParentEntry,
04622           entry->transactedParentEntry);
04623       }
04624 
04625       if (FAILED(hr))
04626       {
04627         cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
04628         TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
04629         return hr;
04630       }
04631     }
04632 
04633     cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
04634     entry = &This->entries[cursor];
04635   }
04636 
04637   return hr;
04638 }
04639 
04640 static HRESULT WINAPI TransactedSnapshotImpl_Commit(
04641   IStorage*            iface,
04642   DWORD                  grfCommitFlags)  /* [in] */
04643 {
04644   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
04645   TransactedDirEntry *root_entry;
04646   DirRef i, dir_root_ref;
04647   DirEntry data;
04648   ULARGE_INTEGER zero;
04649   HRESULT hr;
04650 
04651   zero.QuadPart = 0;
04652 
04653   TRACE("(%p,%x)\n", iface, grfCommitFlags);
04654 
04655   /* Cannot commit a read-only transacted storage */
04656   if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
04657     return STG_E_ACCESSDENIED;
04658 
04659   /* To prevent data loss, we create the new structure in the file before we
04660    * delete the old one, so that in case of errors the old data is intact. We
04661    * shouldn't do this if STGC_OVERWRITE is set, but that flag should only be
04662    * needed in the rare situation where we have just enough free disk space to
04663    * overwrite the existing data. */
04664 
04665   root_entry = &This->entries[This->base.storageDirEntry];
04666 
04667   if (!root_entry->read)
04668     return S_OK;
04669 
04670   hr = TransactedSnapshotImpl_CopyTree(This);
04671   if (FAILED(hr)) return hr;
04672 
04673   if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
04674     dir_root_ref = DIRENTRY_NULL;
04675   else
04676     dir_root_ref = This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
04677 
04678   hr = StorageBaseImpl_Flush(This->transactedParent);
04679 
04680   /* Update the storage to use the new data in one step. */
04681   if (SUCCEEDED(hr))
04682     hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
04683       root_entry->transactedParentEntry, &data);
04684 
04685   if (SUCCEEDED(hr))
04686   {
04687     data.dirRootEntry = dir_root_ref;
04688     data.clsid = root_entry->data.clsid;
04689     data.ctime = root_entry->data.ctime;
04690     data.mtime = root_entry->data.mtime;
04691 
04692     hr = StorageBaseImpl_WriteDirEntry(This->transactedParent,
04693       root_entry->transactedParentEntry, &data);
04694   }
04695 
04696   /* Try to flush after updating the root storage, but if the flush fails, keep
04697    * going, on the theory that it'll either succeed later or the subsequent
04698    * writes will fail. */
04699   StorageBaseImpl_Flush(This->transactedParent);
04700 
04701   if (SUCCEEDED(hr))
04702   {
04703     /* Destroy the old now-orphaned data. */
04704     for (i=0; i<This->entries_size; i++)
04705     {
04706       TransactedDirEntry *entry = &This->entries[i];
04707       if (entry->inuse)
04708       {
04709         if (entry->deleted)
04710         {
04711           StorageBaseImpl_StreamSetSize(This->transactedParent,
04712             entry->transactedParentEntry, zero);
04713           StorageBaseImpl_DestroyDirEntry(This->transactedParent,
04714             entry->transactedParentEntry);
04715           memset(entry, 0, sizeof(TransactedDirEntry));
04716           This->firstFreeEntry = min(i, This->firstFreeEntry);
04717         }
04718         else if (entry->read && entry->transactedParentEntry != entry->newTransactedParentEntry)
04719         {
04720           if (entry->transactedParentEntry != DIRENTRY_NULL)
04721             StorageBaseImpl_DestroyDirEntry(This->transactedParent,
04722               entry->transactedParentEntry);
04723           if (entry->stream_dirty)
04724           {
04725             StorageBaseImpl_StreamSetSize(This->scratch, entry->stream_entry, zero);
04726             StorageBaseImpl_DestroyDirEntry(This->scratch, entry->stream_entry);
04727             entry->stream_dirty = 0;
04728           }
04729           entry->dirty = 0;
04730           entry->transactedParentEntry = entry->newTransactedParentEntry;
04731         }
04732       }
04733     }
04734   }
04735   else
04736   {
04737     TransactedSnapshotImpl_DestroyTemporaryCopy(This, DIRENTRY_NULL);
04738   }
04739 
04740   if (SUCCEEDED(hr))
04741     hr = StorageBaseImpl_Flush(This->transactedParent);
04742 
04743   return hr;
04744 }
04745 
04746 static HRESULT WINAPI TransactedSnapshotImpl_Revert(
04747   IStorage*            iface)
04748 {
04749   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
04750   ULARGE_INTEGER zero;
04751   ULONG i;
04752 
04753   TRACE("(%p)\n", iface);
04754 
04755   /* Destroy the open objects. */
04756   StorageBaseImpl_DeleteAll(&This->base);
04757 
04758   /* Clear out the scratch file. */
04759   zero.QuadPart = 0;
04760   for (i=0; i<This->entries_size; i++)
04761   {
04762     if (This->entries[i].stream_dirty)
04763     {
04764       StorageBaseImpl_StreamSetSize(This->scratch, This->entries[i].stream_entry,
04765         zero);
04766 
04767       StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[i].stream_entry);
04768     }
04769   }
04770 
04771   memset(This->entries, 0, sizeof(TransactedDirEntry) * This->entries_size);
04772 
04773   This->firstFreeEntry = 0;
04774   This->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(This, This->transactedParent->storageDirEntry);
04775 
04776   return S_OK;
04777 }
04778 
04779 static void TransactedSnapshotImpl_Invalidate(StorageBaseImpl* This)
04780 {
04781   if (!This->reverted)
04782   {
04783     TRACE("Storage invalidated (stg=%p)\n", This);
04784 
04785     This->reverted = 1;
04786 
04787     StorageBaseImpl_DeleteAll(This);
04788   }
04789 }
04790 
04791 static void TransactedSnapshotImpl_Destroy( StorageBaseImpl *iface)
04792 {
04793   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
04794 
04795   TransactedSnapshotImpl_Revert((IStorage*)iface);
04796 
04797   IStorage_Release((IStorage*)This->transactedParent);
04798 
04799   IStorage_Release((IStorage*)This->scratch);
04800 
04801   HeapFree(GetProcessHeap(), 0, This->entries);
04802 
04803   HeapFree(GetProcessHeap(), 0, This);
04804 }
04805 
04806 static HRESULT TransactedSnapshotImpl_Flush(StorageBaseImpl* iface)
04807 {
04808   /* We only need to flush when committing. */
04809   return S_OK;
04810 }
04811 
04812 static HRESULT TransactedSnapshotImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
04813 {
04814   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
04815 
04816   return StorageBaseImpl_GetFilename(This->transactedParent, result);
04817 }
04818 
04819 static HRESULT TransactedSnapshotImpl_CreateDirEntry(StorageBaseImpl *base,
04820   const DirEntry *newData, DirRef *index)
04821 {
04822   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
04823   DirRef new_ref;
04824   TransactedDirEntry *new_entry;
04825 
04826   new_ref = TransactedSnapshotImpl_FindFreeEntry(This);
04827   if (new_ref == DIRENTRY_NULL)
04828     return E_OUTOFMEMORY;
04829 
04830   new_entry = &This->entries[new_ref];
04831 
04832   new_entry->newTransactedParentEntry = new_entry->transactedParentEntry = DIRENTRY_NULL;
04833   new_entry->read = 1;
04834   new_entry->dirty = 1;
04835   memcpy(&new_entry->data, newData, sizeof(DirEntry));
04836 
04837   *index = new_ref;
04838 
04839   TRACE("%s l=%x r=%x d=%x <-- %x\n", debugstr_w(newData->name), newData->leftChild, newData->rightChild, newData->dirRootEntry, *index);
04840 
04841   return S_OK;
04842 }
04843 
04844 static HRESULT TransactedSnapshotImpl_WriteDirEntry(StorageBaseImpl *base,
04845   DirRef index, const DirEntry *data)
04846 {
04847   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
04848   HRESULT hr;
04849 
04850   TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
04851 
04852   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
04853   if (FAILED(hr)) return hr;
04854 
04855   memcpy(&This->entries[index].data, data, sizeof(DirEntry));
04856 
04857   if (index != This->base.storageDirEntry)
04858   {
04859     This->entries[index].dirty = 1;
04860 
04861     if (data->size.QuadPart == 0 &&
04862         This->entries[index].transactedParentEntry != DIRENTRY_NULL)
04863     {
04864       /* Since this entry is modified, and we aren't using its stream data, we
04865        * no longer care about the original entry. */
04866       DirRef delete_ref;
04867       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
04868 
04869       if (delete_ref != DIRENTRY_NULL)
04870         This->entries[delete_ref].deleted = 1;
04871 
04872       This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
04873     }
04874   }
04875 
04876   return S_OK;
04877 }
04878 
04879 static HRESULT TransactedSnapshotImpl_ReadDirEntry(StorageBaseImpl *base,
04880   DirRef index, DirEntry *data)
04881 {
04882   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
04883   HRESULT hr;
04884 
04885   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
04886   if (FAILED(hr)) return hr;
04887 
04888   memcpy(data, &This->entries[index].data, sizeof(DirEntry));
04889 
04890   TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
04891 
04892   return S_OK;
04893 }
04894 
04895 static HRESULT TransactedSnapshotImpl_DestroyDirEntry(StorageBaseImpl *base,
04896   DirRef index)
04897 {
04898   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
04899 
04900   if (This->entries[index].transactedParentEntry == DIRENTRY_NULL ||
04901       This->entries[index].data.size.QuadPart != 0)
04902   {
04903     /* If we deleted this entry while it has stream data. We must have left the
04904      * data because some other entry is using it, and we need to leave the
04905      * original entry alone. */
04906     memset(&This->entries[index], 0, sizeof(TransactedDirEntry));
04907     This->firstFreeEntry = min(index, This->firstFreeEntry);
04908   }
04909   else
04910   {
04911     This->entries[index].deleted = 1;
04912   }
04913 
04914   return S_OK;
04915 }
04916 
04917 static HRESULT TransactedSnapshotImpl_StreamReadAt(StorageBaseImpl *base,
04918   DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
04919 {
04920   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
04921 
04922   if (This->entries[index].stream_dirty)
04923   {
04924     return StorageBaseImpl_StreamReadAt(This->scratch,
04925         This->entries[index].stream_entry, offset, size, buffer, bytesRead);
04926   }
04927   else if (This->entries[index].transactedParentEntry == DIRENTRY_NULL)
04928   {
04929     /* This stream doesn't live in the parent, and we haven't allocated storage
04930      * for it yet */
04931     *bytesRead = 0;
04932     return S_OK;
04933   }
04934   else
04935   {
04936     return StorageBaseImpl_StreamReadAt(This->transactedParent,
04937         This->entries[index].transactedParentEntry, offset, size, buffer, bytesRead);
04938   }
04939 }
04940 
04941 static HRESULT TransactedSnapshotImpl_StreamWriteAt(StorageBaseImpl *base,
04942   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
04943 {
04944   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
04945   HRESULT hr;
04946 
04947   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
04948   if (FAILED(hr)) return hr;
04949 
04950   hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
04951   if (FAILED(hr)) return hr;
04952 
04953   hr = StorageBaseImpl_StreamWriteAt(This->scratch,
04954     This->entries[index].stream_entry, offset, size, buffer, bytesWritten);
04955 
04956   if (SUCCEEDED(hr) && size != 0)
04957     This->entries[index].data.size.QuadPart = max(
04958         This->entries[index].data.size.QuadPart,
04959         offset.QuadPart + size);
04960 
04961   return hr;
04962 }
04963 
04964 static HRESULT TransactedSnapshotImpl_StreamSetSize(StorageBaseImpl *base,
04965   DirRef index, ULARGE_INTEGER newsize)
04966 {
04967   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
04968   HRESULT hr;
04969 
04970   hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
04971   if (FAILED(hr)) return hr;
04972 
04973   if (This->entries[index].data.size.QuadPart == newsize.QuadPart)
04974     return S_OK;
04975 
04976   if (newsize.QuadPart == 0)
04977   {
04978     /* Destroy any parent references or entries in the scratch file. */
04979     if (This->entries[index].stream_dirty)
04980     {
04981       ULARGE_INTEGER zero;
04982       zero.QuadPart = 0;
04983       StorageBaseImpl_StreamSetSize(This->scratch,
04984         This->entries[index].stream_entry, zero);
04985       StorageBaseImpl_DestroyDirEntry(This->scratch,
04986         This->entries[index].stream_entry);
04987       This->entries[index].stream_dirty = 0;
04988     }
04989     else if (This->entries[index].transactedParentEntry != DIRENTRY_NULL)
04990     {
04991       DirRef delete_ref;
04992       delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
04993 
04994       if (delete_ref != DIRENTRY_NULL)
04995         This->entries[delete_ref].deleted = 1;
04996 
04997       This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
04998     }
04999   }
05000   else
05001   {
05002     hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
05003     if (FAILED(hr)) return hr;
05004 
05005     hr = StorageBaseImpl_StreamSetSize(This->scratch,
05006       This->entries[index].stream_entry, newsize);
05007   }
05008 
05009   if (SUCCEEDED(hr))
05010     This->entries[index].data.size = newsize;
05011 
05012   return hr;
05013 }
05014 
05015 static HRESULT TransactedSnapshotImpl_StreamLink(StorageBaseImpl *base,
05016   DirRef dst, DirRef src)
05017 {
05018   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
05019   HRESULT hr;
05020   TransactedDirEntry *dst_entry, *src_entry;
05021 
05022   hr = TransactedSnapshotImpl_EnsureReadEntry(This, src);
05023   if (FAILED(hr)) return hr;
05024 
05025   hr = TransactedSnapshotImpl_EnsureReadEntry(This, dst);
05026   if (FAILED(hr)) return hr;
05027 
05028   dst_entry = &This->entries[dst];
05029   src_entry = &This->entries[src];
05030 
05031   dst_entry->stream_dirty = src_entry->stream_dirty;
05032   dst_entry->stream_entry = src_entry->stream_entry;
05033   dst_entry->transactedParentEntry = src_entry->transactedParentEntry;
05034   dst_entry->newTransactedParentEntry = src_entry->newTransactedParentEntry;
05035   dst_entry->data.size = src_entry->data.size;
05036 
05037   return S_OK;
05038 }
05039 
05040 static const IStorageVtbl TransactedSnapshotImpl_Vtbl =
05041 {
05042     StorageBaseImpl_QueryInterface,
05043     StorageBaseImpl_AddRef,
05044     StorageBaseImpl_Release,
05045     StorageBaseImpl_CreateStream,
05046     StorageBaseImpl_OpenStream,
05047     StorageBaseImpl_CreateStorage,
05048     StorageBaseImpl_OpenStorage,
05049     StorageBaseImpl_CopyTo,
05050     StorageBaseImpl_MoveElementTo,
05051     TransactedSnapshotImpl_Commit,
05052     TransactedSnapshotImpl_Revert,
05053     StorageBaseImpl_EnumElements,
05054     StorageBaseImpl_DestroyElement,
05055     StorageBaseImpl_RenameElement,
05056     StorageBaseImpl_SetElementTimes,
05057     StorageBaseImpl_SetClass,
05058     StorageBaseImpl_SetStateBits,
05059     StorageBaseImpl_Stat
05060 };
05061 
05062 static const StorageBaseImplVtbl TransactedSnapshotImpl_BaseVtbl =
05063 {
05064   TransactedSnapshotImpl_Destroy,
05065   TransactedSnapshotImpl_Invalidate,
05066   TransactedSnapshotImpl_Flush,
05067   TransactedSnapshotImpl_GetFilename,
05068   TransactedSnapshotImpl_CreateDirEntry,
05069   TransactedSnapshotImpl_WriteDirEntry,
05070   TransactedSnapshotImpl_ReadDirEntry,
05071   TransactedSnapshotImpl_DestroyDirEntry,
05072   TransactedSnapshotImpl_StreamReadAt,
05073   TransactedSnapshotImpl_StreamWriteAt,
05074   TransactedSnapshotImpl_StreamSetSize,
05075   TransactedSnapshotImpl_StreamLink
05076 };
05077 
05078 static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage,
05079   TransactedSnapshotImpl** result)
05080 {
05081   HRESULT hr;
05082 
05083   *result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedSnapshotImpl));
05084   if (*result)
05085   {
05086     (*result)->base.lpVtbl = &TransactedSnapshotImpl_Vtbl;
05087 
05088     /* This is OK because the property set storage functions use the IStorage functions. */
05089     (*result)->base.pssVtbl = parentStorage->pssVtbl;
05090 
05091     (*result)->base.baseVtbl = &TransactedSnapshotImpl_BaseVtbl;
05092 
05093     list_init(&(*result)->base.strmHead);
05094 
05095     list_init(&(*result)->base.storageHead);
05096 
05097     (*result)->base.ref = 1;
05098 
05099     (*result)->base.openFlags = parentStorage->openFlags;
05100 
05101     /* Create a new temporary storage to act as the scratch file. */
05102     hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_DELETEONRELEASE,
05103         0, (IStorage**)&(*result)->scratch);
05104 
05105     if (SUCCEEDED(hr))
05106     {
05107         ULONG num_entries = 20;
05108 
05109         (*result)->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * num_entries);
05110 
05111         (*result)->entries_size = num_entries;
05112 
05113         (*result)->firstFreeEntry = 0;
05114 
05115         if ((*result)->entries)
05116         {
05117             /* parentStorage already has 1 reference, which we take over here. */
05118             (*result)->transactedParent = parentStorage;
05119 
05120             parentStorage->transactedChild = (StorageBaseImpl*)*result;
05121 
05122             (*result)->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(*result, parentStorage->storageDirEntry);
05123         }
05124         else
05125         {
05126             IStorage_Release((IStorage*)(*result)->scratch);
05127 
05128             hr = E_OUTOFMEMORY;
05129         }
05130     }
05131 
05132     if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, (*result));
05133 
05134     return hr;
05135   }
05136   else
05137     return E_OUTOFMEMORY;
05138 }
05139 
05140 static HRESULT Storage_ConstructTransacted(StorageBaseImpl *parentStorage,
05141   StorageBaseImpl** result)
05142 {
05143   static int fixme=0;
05144 
05145   if (parentStorage->openFlags & (STGM_NOSCRATCH|STGM_NOSNAPSHOT) && !fixme++)
05146   {
05147     FIXME("Unimplemented flags %x\n", parentStorage->openFlags);
05148   }
05149 
05150   return TransactedSnapshotImpl_Construct(parentStorage,
05151     (TransactedSnapshotImpl**)result);
05152 }
05153 
05154 static HRESULT Storage_Construct(
05155   HANDLE       hFile,
05156   LPCOLESTR    pwcsName,
05157   ILockBytes*  pLkbyt,
05158   DWORD        openFlags,
05159   BOOL         fileBased,
05160   BOOL         create,
05161   ULONG        sector_size,
05162   StorageBaseImpl** result)
05163 {
05164   StorageImpl *newStorage;
05165   StorageBaseImpl *newTransactedStorage;
05166   HRESULT hr;
05167 
05168   hr = StorageImpl_Construct(hFile, pwcsName, pLkbyt, openFlags, fileBased, create, sector_size, &newStorage);
05169   if (FAILED(hr)) goto end;
05170 
05171   if (openFlags & STGM_TRANSACTED)
05172   {
05173     hr = Storage_ConstructTransacted(&newStorage->base, &newTransactedStorage);
05174     if (FAILED(hr))
05175       IStorage_Release((IStorage*)newStorage);
05176     else
05177       *result = newTransactedStorage;
05178   }
05179   else
05180     *result = &newStorage->base;
05181 
05182 end:
05183   return hr;
05184 }
05185 
05186 static void StorageInternalImpl_Invalidate( StorageBaseImpl *base )
05187 {
05188   StorageInternalImpl* This = (StorageInternalImpl*) base;
05189 
05190   if (!This->base.reverted)
05191   {
05192     TRACE("Storage invalidated (stg=%p)\n", This);
05193 
05194     This->base.reverted = 1;
05195 
05196     This->parentStorage = NULL;
05197 
05198     StorageBaseImpl_DeleteAll(&This->base);
05199 
05200     list_remove(&This->ParentListEntry);
05201   }
05202 }
05203 
05204 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
05205 {
05206   StorageInternalImpl* This = (StorageInternalImpl*) iface;
05207 
05208   StorageInternalImpl_Invalidate(&This->base);
05209 
05210   HeapFree(GetProcessHeap(), 0, This);
05211 }
05212 
05213 static HRESULT StorageInternalImpl_Flush(StorageBaseImpl* iface)
05214 {
05215   StorageInternalImpl* This = (StorageInternalImpl*) iface;
05216 
05217   return StorageBaseImpl_Flush(This->parentStorage);
05218 }
05219 
05220 static HRESULT StorageInternalImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
05221 {
05222   StorageInternalImpl* This = (StorageInternalImpl*) iface;
05223 
05224   return StorageBaseImpl_GetFilename(This->parentStorage, result);
05225 }
05226 
05227 static HRESULT StorageInternalImpl_CreateDirEntry(StorageBaseImpl *base,
05228   const DirEntry *newData, DirRef *index)
05229 {
05230   StorageInternalImpl* This = (StorageInternalImpl*) base;
05231 
05232   return StorageBaseImpl_CreateDirEntry(This->parentStorage,
05233     newData, index);
05234 }
05235 
05236 static HRESULT StorageInternalImpl_WriteDirEntry(StorageBaseImpl *base,
05237   DirRef index, const DirEntry *data)
05238 {
05239   StorageInternalImpl* This = (StorageInternalImpl*) base;
05240 
05241   return StorageBaseImpl_WriteDirEntry(This->parentStorage,
05242     index, data);
05243 }
05244 
05245 static HRESULT StorageInternalImpl_ReadDirEntry(StorageBaseImpl *base,
05246   DirRef index, DirEntry *data)
05247 {
05248   StorageInternalImpl* This = (StorageInternalImpl*) base;
05249 
05250   return StorageBaseImpl_ReadDirEntry(This->parentStorage,
05251     index, data);
05252 }
05253 
05254 static HRESULT StorageInternalImpl_DestroyDirEntry(StorageBaseImpl *base,
05255   DirRef index)
05256 {
05257   StorageInternalImpl* This = (StorageInternalImpl*) base;
05258 
05259   return StorageBaseImpl_DestroyDirEntry(This->parentStorage,
05260     index);
05261 }
05262 
05263 static HRESULT StorageInternalImpl_StreamReadAt(StorageBaseImpl *base,
05264   DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
05265 {
05266   StorageInternalImpl* This = (StorageInternalImpl*) base;
05267 
05268   return StorageBaseImpl_StreamReadAt(This->parentStorage,
05269     index, offset, size, buffer, bytesRead);
05270 }
05271 
05272 static HRESULT StorageInternalImpl_StreamWriteAt(StorageBaseImpl *base,
05273   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
05274 {
05275   StorageInternalImpl* This = (StorageInternalImpl*) base;
05276 
05277   return StorageBaseImpl_StreamWriteAt(This->parentStorage,
05278     index, offset, size, buffer, bytesWritten);
05279 }
05280 
05281 static HRESULT StorageInternalImpl_StreamSetSize(StorageBaseImpl *base,
05282   DirRef index, ULARGE_INTEGER newsize)
05283 {
05284   StorageInternalImpl* This = (StorageInternalImpl*) base;
05285 
05286   return StorageBaseImpl_StreamSetSize(This->parentStorage,
05287     index, newsize);
05288 }
05289 
05290 static HRESULT StorageInternalImpl_StreamLink(StorageBaseImpl *base,
05291   DirRef dst, DirRef src)
05292 {
05293   StorageInternalImpl* This = (StorageInternalImpl*) base;
05294 
05295   return StorageBaseImpl_StreamLink(This->parentStorage,
05296     dst, src);
05297 }
05298 
05299 /******************************************************************************
05300 **
05301 ** Storage32InternalImpl_Commit
05302 **
05303 */
05304 static HRESULT WINAPI StorageInternalImpl_Commit(
05305   IStorage*            iface,
05306   DWORD                  grfCommitFlags)  /* [in] */
05307 {
05308   StorageBaseImpl* base = (StorageBaseImpl*) iface;
05309   TRACE("(%p,%x)\n", iface, grfCommitFlags);
05310   return StorageBaseImpl_Flush(base);
05311 }
05312 
05313 /******************************************************************************
05314 **
05315 ** Storage32InternalImpl_Revert
05316 **
05317 */
05318 static HRESULT WINAPI StorageInternalImpl_Revert(
05319   IStorage*            iface)
05320 {
05321   FIXME("(%p): stub\n", iface);
05322   return S_OK;
05323 }
05324 
05325 static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
05326 {
05327   IStorage_Release((IStorage*)This->parentStorage);
05328   HeapFree(GetProcessHeap(), 0, This);
05329 }
05330 
05331 static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
05332   IEnumSTATSTG*     iface,
05333   REFIID            riid,
05334   void**            ppvObject)
05335 {
05336   IEnumSTATSTGImpl* const This = impl_from_IEnumSTATSTG(iface);
05337 
05338   if (ppvObject==0)
05339     return E_INVALIDARG;
05340 
05341   *ppvObject = 0;
05342 
05343   if (IsEqualGUID(&IID_IUnknown, riid) ||
05344       IsEqualGUID(&IID_IEnumSTATSTG, riid))
05345   {
05346     *ppvObject = This;
05347     IEnumSTATSTG_AddRef(&This->IEnumSTATSTG_iface);
05348     return S_OK;
05349   }
05350 
05351   return E_NOINTERFACE;
05352 }
05353 
05354 static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
05355   IEnumSTATSTG* iface)
05356 {
05357   IEnumSTATSTGImpl* const This = impl_from_IEnumSTATSTG(iface);
05358   return InterlockedIncrement(&This->ref);
05359 }
05360 
05361 static ULONG   WINAPI IEnumSTATSTGImpl_Release(
05362   IEnumSTATSTG* iface)
05363 {
05364   IEnumSTATSTGImpl* const This = impl_from_IEnumSTATSTG(iface);
05365 
05366   ULONG newRef;
05367 
05368   newRef = InterlockedDecrement(&This->ref);
05369 
05370   if (newRef==0)
05371   {
05372     IEnumSTATSTGImpl_Destroy(This);
05373   }
05374 
05375   return newRef;
05376 }
05377 
05378 static HRESULT IEnumSTATSTGImpl_GetNextRef(
05379   IEnumSTATSTGImpl* This,
05380   DirRef *ref)
05381 {
05382   DirRef result = DIRENTRY_NULL;
05383   DirRef searchNode;
05384   DirEntry entry;
05385   HRESULT hr;
05386   WCHAR result_name[DIRENTRY_NAME_MAX_LEN];
05387 
05388   hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
05389     This->parentStorage->storageDirEntry, &entry);
05390   searchNode = entry.dirRootEntry;
05391 
05392   while (SUCCEEDED(hr) && searchNode != DIRENTRY_NULL)
05393   {
05394     hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, searchNode, &entry);
05395 
05396     if (SUCCEEDED(hr))
05397     {
05398       LONG diff = entryNameCmp( entry.name, This->name);
05399 
05400       if (diff <= 0)
05401       {
05402         searchNode = entry.rightChild;
05403       }
05404       else
05405       {
05406         result = searchNode;
05407         memcpy(result_name, entry.name, sizeof(result_name));
05408         searchNode = entry.leftChild;
05409       }
05410     }
05411   }
05412 
05413   if (SUCCEEDED(hr))
05414   {
05415     *ref = result;
05416     if (result != DIRENTRY_NULL)
05417       memcpy(This->name, result_name, sizeof(result_name));
05418   }
05419 
05420   return hr;
05421 }
05422 
05423 static HRESULT WINAPI IEnumSTATSTGImpl_Next(
05424   IEnumSTATSTG* iface,
05425   ULONG             celt,
05426   STATSTG*          rgelt,
05427   ULONG*            pceltFetched)
05428 {
05429   IEnumSTATSTGImpl* const This = impl_from_IEnumSTATSTG(iface);
05430 
05431   DirEntry    currentEntry;
05432   STATSTG*    currentReturnStruct = rgelt;
05433   ULONG       objectFetched       = 0;
05434   DirRef      currentSearchNode;
05435   HRESULT     hr=S_OK;
05436 
05437   if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
05438     return E_INVALIDARG;
05439 
05440   if (This->parentStorage->reverted)
05441     return STG_E_REVERTED;
05442 
05443   /*
05444    * To avoid the special case, get another pointer to a ULONG value if
05445    * the caller didn't supply one.
05446    */
05447   if (pceltFetched==0)
05448     pceltFetched = &objectFetched;
05449 
05450   /*
05451    * Start the iteration, we will iterate until we hit the end of the
05452    * linked list or until we hit the number of items to iterate through
05453    */
05454   *pceltFetched = 0;
05455 
05456   while ( *pceltFetched < celt )
05457   {
05458     hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
05459 
05460     if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
05461       break;
05462 
05463     /*
05464      * Read the entry from the storage.
05465      */
05466     StorageBaseImpl_ReadDirEntry(This->parentStorage,
05467       currentSearchNode,
05468       &currentEntry);
05469 
05470     /*
05471      * Copy the information to the return buffer.
05472      */
05473     StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
05474       currentReturnStruct,
05475       &currentEntry,
05476       STATFLAG_DEFAULT);
05477 
05478     /*
05479      * Step to the next item in the iteration
05480      */
05481     (*pceltFetched)++;
05482     currentReturnStruct++;
05483   }
05484 
05485   if (SUCCEEDED(hr) && *pceltFetched != celt)
05486     hr = S_FALSE;
05487 
05488   return hr;
05489 }
05490 
05491 
05492 static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
05493   IEnumSTATSTG* iface,
05494   ULONG             celt)
05495 {
05496   IEnumSTATSTGImpl* const This = impl_from_IEnumSTATSTG(iface);
05497 
05498   ULONG       objectFetched = 0;
05499   DirRef      currentSearchNode;
05500   HRESULT     hr=S_OK;
05501 
05502   if (This->parentStorage->reverted)
05503     return STG_E_REVERTED;
05504 
05505   while ( (objectFetched < celt) )
05506   {
05507     hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
05508 
05509     if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
05510       break;
05511 
05512     objectFetched++;
05513   }
05514 
05515   if (SUCCEEDED(hr) && objectFetched != celt)
05516     return S_FALSE;
05517 
05518   return hr;
05519 }
05520 
05521 static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
05522   IEnumSTATSTG* iface)
05523 {
05524   IEnumSTATSTGImpl* const This = impl_from_IEnumSTATSTG(iface);
05525 
05526   if (This->parentStorage->reverted)
05527     return STG_E_REVERTED;
05528 
05529   This->name[0] = 0;
05530 
05531   return S_OK;
05532 }
05533 
05534 static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
05535   IEnumSTATSTG* iface,
05536   IEnumSTATSTG**    ppenum)
05537 {
05538   IEnumSTATSTGImpl* const This = impl_from_IEnumSTATSTG(iface);
05539 
05540   IEnumSTATSTGImpl* newClone;
05541 
05542   if (This->parentStorage->reverted)
05543     return STG_E_REVERTED;
05544 
05545   /*
05546    * Perform a sanity check on the parameters.
05547    */
05548   if (ppenum==0)
05549     return E_INVALIDARG;
05550 
05551   newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
05552                This->storageDirEntry);
05553 
05554 
05555   /*
05556    * The new clone enumeration must point to the same current node as
05557    * the ole one.
05558    */
05559   memcpy(newClone->name, This->name, sizeof(newClone->name));
05560 
05561   *ppenum = &newClone->IEnumSTATSTG_iface;
05562 
05563   /*
05564    * Don't forget to nail down a reference to the clone before
05565    * returning it.
05566    */
05567   IEnumSTATSTGImpl_AddRef(*ppenum);
05568 
05569   return S_OK;
05570 }
05571 
05572 /*
05573  * Virtual function table for the IEnumSTATSTGImpl class.
05574  */
05575 static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
05576 {
05577     IEnumSTATSTGImpl_QueryInterface,
05578     IEnumSTATSTGImpl_AddRef,
05579     IEnumSTATSTGImpl_Release,
05580     IEnumSTATSTGImpl_Next,
05581     IEnumSTATSTGImpl_Skip,
05582     IEnumSTATSTGImpl_Reset,
05583     IEnumSTATSTGImpl_Clone
05584 };
05585 
05586 /******************************************************************************
05587 ** IEnumSTATSTGImpl implementation
05588 */
05589 
05590 static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
05591   StorageBaseImpl* parentStorage,
05592   DirRef         storageDirEntry)
05593 {
05594   IEnumSTATSTGImpl* newEnumeration;
05595 
05596   newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
05597 
05598   if (newEnumeration!=0)
05599   {
05600     /*
05601      * Set-up the virtual function table and reference count.
05602      */
05603     newEnumeration->IEnumSTATSTG_iface.lpVtbl = &IEnumSTATSTGImpl_Vtbl;
05604     newEnumeration->ref       = 0;
05605 
05606     /*
05607      * We want to nail-down the reference to the storage in case the
05608      * enumeration out-lives the storage in the client application.
05609      */
05610     newEnumeration->parentStorage = parentStorage;
05611     IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
05612 
05613     newEnumeration->storageDirEntry   = storageDirEntry;
05614 
05615     /*
05616      * Make sure the current node of the iterator is the first one.
05617      */
05618     IEnumSTATSTGImpl_Reset(&newEnumeration->IEnumSTATSTG_iface);
05619   }
05620 
05621   return newEnumeration;
05622 }
05623 
05624 /*
05625  * Virtual function table for the Storage32InternalImpl class.
05626  */
05627 static const IStorageVtbl Storage32InternalImpl_Vtbl =
05628 {
05629     StorageBaseImpl_QueryInterface,
05630     StorageBaseImpl_AddRef,
05631     StorageBaseImpl_Release,
05632     StorageBaseImpl_CreateStream,
05633     StorageBaseImpl_OpenStream,
05634     StorageBaseImpl_CreateStorage,
05635     StorageBaseImpl_OpenStorage,
05636     StorageBaseImpl_CopyTo,
05637     StorageBaseImpl_MoveElementTo,
05638     StorageInternalImpl_Commit,
05639     StorageInternalImpl_Revert,
05640     StorageBaseImpl_EnumElements,
05641     StorageBaseImpl_DestroyElement,
05642     StorageBaseImpl_RenameElement,
05643     StorageBaseImpl_SetElementTimes,
05644     StorageBaseImpl_SetClass,
05645     StorageBaseImpl_SetStateBits,
05646     StorageBaseImpl_Stat
05647 };
05648 
05649 static const StorageBaseImplVtbl StorageInternalImpl_BaseVtbl =
05650 {
05651   StorageInternalImpl_Destroy,
05652   StorageInternalImpl_Invalidate,
05653   StorageInternalImpl_Flush,
05654   StorageInternalImpl_GetFilename,
05655   StorageInternalImpl_CreateDirEntry,
05656   StorageInternalImpl_WriteDirEntry,
05657   StorageInternalImpl_ReadDirEntry,
05658   StorageInternalImpl_DestroyDirEntry,
05659   StorageInternalImpl_StreamReadAt,
05660   StorageInternalImpl_StreamWriteAt,
05661   StorageInternalImpl_StreamSetSize,
05662   StorageInternalImpl_StreamLink
05663 };
05664 
05665 /******************************************************************************
05666 ** Storage32InternalImpl implementation
05667 */
05668 
05669 static StorageInternalImpl* StorageInternalImpl_Construct(
05670   StorageBaseImpl* parentStorage,
05671   DWORD        openFlags,
05672   DirRef       storageDirEntry)
05673 {
05674   StorageInternalImpl* newStorage;
05675 
05676   newStorage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StorageInternalImpl));
05677 
05678   if (newStorage!=0)
05679   {
05680     list_init(&newStorage->base.strmHead);
05681 
05682     list_init(&newStorage->base.storageHead);
05683 
05684     /*
05685      * Initialize the virtual function table.
05686      */
05687     newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
05688     newStorage->base.pssVtbl = &IPropertySetStorage_Vtbl;
05689     newStorage->base.baseVtbl = &StorageInternalImpl_BaseVtbl;
05690     newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
05691 
05692     newStorage->base.reverted = 0;
05693 
05694     newStorage->base.ref = 1;
05695 
05696     newStorage->parentStorage = parentStorage;
05697 
05698     /*
05699      * Keep a reference to the directory entry of this storage
05700      */
05701     newStorage->base.storageDirEntry = storageDirEntry;
05702 
05703     newStorage->base.create = 0;
05704 
05705     return newStorage;
05706   }
05707 
05708   return 0;
05709 }
05710 
05711 /******************************************************************************
05712 ** StorageUtl implementation
05713 */
05714 
05715 void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
05716 {
05717   WORD tmp;
05718 
05719   memcpy(&tmp, buffer+offset, sizeof(WORD));
05720   *value = lendian16toh(tmp);
05721 }
05722 
05723 void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
05724 {
05725   value = htole16(value);
05726   memcpy(buffer+offset, &value, sizeof(WORD));
05727 }
05728 
05729 void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
05730 {
05731   DWORD tmp;
05732 
05733   memcpy(&tmp, buffer+offset, sizeof(DWORD));
05734   *value = lendian32toh(tmp);
05735 }
05736 
05737 void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
05738 {
05739   value = htole32(value);
05740   memcpy(buffer+offset, &value, sizeof(DWORD));
05741 }
05742 
05743 void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
05744  ULARGE_INTEGER* value)
05745 {
05746 #ifdef WORDS_BIGENDIAN
05747     ULARGE_INTEGER tmp;
05748 
05749     memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
05750     value->u.LowPart = htole32(tmp.u.HighPart);
05751     value->u.HighPart = htole32(tmp.u.LowPart);
05752 #else
05753     memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
05754 #endif
05755 }
05756 
05757 void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
05758  const ULARGE_INTEGER *value)
05759 {
05760 #ifdef WORDS_BIGENDIAN
05761     ULARGE_INTEGER tmp;
05762 
05763     tmp.u.LowPart = htole32(value->u.HighPart);
05764     tmp.u.HighPart = htole32(value->u.LowPart);
05765     memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
05766 #else
05767     memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
05768 #endif
05769 }
05770 
05771 void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
05772 {
05773   StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
05774   StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
05775   StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
05776 
05777   memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
05778 }
05779 
05780 void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
05781 {
05782   StorageUtl_WriteDWord(buffer, offset,   value->Data1);
05783   StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
05784   StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
05785 
05786   memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
05787 }
05788 
05789 void StorageUtl_CopyDirEntryToSTATSTG(
05790   StorageBaseImpl*      storage,
05791   STATSTG*              destination,
05792   const DirEntry*       source,
05793   int                   statFlags)
05794 {
05795   /*
05796    * The copy of the string occurs only when the flag is not set
05797    */
05798   if (!(statFlags & STATFLAG_NONAME) && source->stgType == STGTY_ROOT)
05799   {
05800     /* Use the filename for the root storage. */
05801     destination->pwcsName = 0;
05802     StorageBaseImpl_GetFilename(storage, &destination->pwcsName);
05803   }
05804   else if( ((statFlags & STATFLAG_NONAME) != 0) ||
05805        (source->name[0] == 0) )
05806   {
05807     destination->pwcsName = 0;
05808   }
05809   else
05810   {
05811     destination->pwcsName =
05812       CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
05813 
05814     strcpyW(destination->pwcsName, source->name);
05815   }
05816 
05817   switch (source->stgType)
05818   {
05819     case STGTY_STORAGE:
05820     case STGTY_ROOT:
05821       destination->type = STGTY_STORAGE;
05822       break;
05823     case STGTY_STREAM:
05824       destination->type = STGTY_STREAM;
05825       break;
05826     default:
05827       destination->type = STGTY_STREAM;
05828       break;
05829   }
05830 
05831   destination->cbSize            = source->size;
05832 /*
05833   currentReturnStruct->mtime     = {0}; TODO
05834   currentReturnStruct->ctime     = {0};
05835   currentReturnStruct->atime     = {0};
05836 */
05837   destination->grfMode           = 0;
05838   destination->grfLocksSupported = 0;
05839   destination->clsid             = source->clsid;
05840   destination->grfStateBits      = 0;
05841   destination->reserved          = 0;
05842 }
05843 
05844 /******************************************************************************
05845 ** BlockChainStream implementation
05846 */
05847 
05848 /* Read and save the index of all blocks in this stream. */
05849 HRESULT BlockChainStream_UpdateIndexCache(BlockChainStream* This)
05850 {
05851   ULONG  next_sector, next_offset;
05852   HRESULT hr;
05853   struct BlockChainRun *last_run;
05854 
05855   if (This->indexCacheLen == 0)
05856   {
05857     last_run = NULL;
05858     next_offset = 0;
05859     next_sector = BlockChainStream_GetHeadOfChain(This);
05860   }
05861   else
05862   {
05863     last_run = &This->indexCache[This->indexCacheLen-1];
05864     next_offset = last_run->lastOffset+1;
05865     hr = StorageImpl_GetNextBlockInChain(This->parentStorage,
05866         last_run->firstSector + last_run->lastOffset - last_run->firstOffset,
05867         &next_sector);
05868     if (FAILED(hr)) return hr;
05869   }
05870 
05871   while (next_sector != BLOCK_END_OF_CHAIN)
05872   {
05873     if (!last_run || next_sector != last_run->firstSector + next_offset - last_run->firstOffset)
05874     {
05875       /* Add the current block to the cache. */
05876       if (This->indexCacheSize == 0)
05877       {
05878         This->indexCache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*16);
05879         if (!This->indexCache) return E_OUTOFMEMORY;
05880         This->indexCacheSize = 16;
05881       }
05882       else if (This->indexCacheSize == This->indexCacheLen)
05883       {
05884         struct BlockChainRun *new_cache;
05885         ULONG new_size;
05886 
05887         new_size = This->indexCacheSize * 2;
05888         new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*new_size);
05889         if (!new_cache) return E_OUTOFMEMORY;
05890         memcpy(new_cache, This->indexCache, sizeof(struct BlockChainRun)*This->indexCacheLen);
05891 
05892         HeapFree(GetProcessHeap(), 0, This->indexCache);
05893         This->indexCache = new_cache;
05894         This->indexCacheSize = new_size;
05895       }
05896 
05897       This->indexCacheLen++;
05898       last_run = &This->indexCache[This->indexCacheLen-1];
05899       last_run->firstSector = next_sector;
05900       last_run->firstOffset = next_offset;
05901     }
05902 
05903     last_run->lastOffset = next_offset;
05904 
05905     /* Find the next block. */
05906     next_offset++;
05907     hr = StorageImpl_GetNextBlockInChain(This->parentStorage, next_sector, &next_sector);
05908     if (FAILED(hr)) return hr;
05909   }
05910 
05911   if (This->indexCacheLen)
05912   {
05913     This->tailIndex = last_run->firstSector + last_run->lastOffset - last_run->firstOffset;
05914     This->numBlocks = last_run->lastOffset+1;
05915   }
05916   else
05917   {
05918     This->tailIndex = BLOCK_END_OF_CHAIN;
05919     This->numBlocks = 0;
05920   }
05921 
05922   return S_OK;
05923 }
05924 
05925 /* Locate the nth block in this stream. */
05926 ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset)
05927 {
05928   ULONG min_offset = 0, max_offset = This->numBlocks-1;
05929   ULONG min_run = 0, max_run = This->indexCacheLen-1;
05930 
05931   if (offset >= This->numBlocks)
05932     return BLOCK_END_OF_CHAIN;
05933 
05934   while (min_run < max_run)
05935   {
05936     ULONG run_to_check = min_run + (offset - min_offset) * (max_run - min_run) / (max_offset - min_offset);
05937     if (offset < This->indexCache[run_to_check].firstOffset)
05938     {
05939       max_offset = This->indexCache[run_to_check].firstOffset-1;
05940       max_run = run_to_check-1;
05941     }
05942     else if (offset > This->indexCache[run_to_check].lastOffset)
05943     {
05944       min_offset = This->indexCache[run_to_check].lastOffset+1;
05945       min_run = run_to_check+1;
05946     }
05947     else
05948       /* Block is in this run. */
05949       min_run = max_run = run_to_check;
05950   }
05951 
05952   return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset;
05953 }
05954 
05955 HRESULT BlockChainStream_GetBlockAtOffset(BlockChainStream *This,
05956     ULONG index, BlockChainBlock **block, ULONG *sector, BOOL create)
05957 {
05958   BlockChainBlock *result=NULL;
05959   int i;
05960 
05961   for (i=0; i<2; i++)
05962     if (This->cachedBlocks[i].index == index)
05963     {
05964       *sector = This->cachedBlocks[i].sector;
05965       *block = &This->cachedBlocks[i];
05966       return S_OK;
05967     }
05968 
05969   *sector = BlockChainStream_GetSectorOfOffset(This, index);
05970   if (*sector == BLOCK_END_OF_CHAIN)
05971     return STG_E_DOCFILECORRUPT;
05972 
05973   if (create)
05974   {
05975     if (This->cachedBlocks[0].index == 0xffffffff)
05976       result = &This->cachedBlocks[0];
05977     else if (This->cachedBlocks[1].index == 0xffffffff)
05978       result = &This->cachedBlocks[1];
05979     else
05980     {
05981       result = &This->cachedBlocks[This->blockToEvict++];
05982       if (This->blockToEvict == 2)
05983         This->blockToEvict = 0;
05984     }
05985 
05986     if (result->dirty)
05987     {
05988       if (!StorageImpl_WriteBigBlock(This->parentStorage, result->sector, result->data))
05989         return STG_E_WRITEFAULT;
05990       result->dirty = 0;
05991     }
05992 
05993     result->read = 0;
05994     result->index = index;
05995     result->sector = *sector;
05996   }
05997 
05998   *block = result;
05999   return S_OK;
06000 }
06001 
06002 BlockChainStream* BlockChainStream_Construct(
06003   StorageImpl* parentStorage,
06004   ULONG*         headOfStreamPlaceHolder,
06005   DirRef         dirEntry)
06006 {
06007   BlockChainStream* newStream;
06008 
06009   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
06010 
06011   newStream->parentStorage           = parentStorage;
06012   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
06013   newStream->ownerDirEntry           = dirEntry;
06014   newStream->indexCache              = NULL;
06015   newStream->indexCacheLen           = 0;
06016   newStream->indexCacheSize          = 0;
06017   newStream->cachedBlocks[0].index = 0xffffffff;
06018   newStream->cachedBlocks[0].dirty = 0;
06019   newStream->cachedBlocks[1].index = 0xffffffff;
06020   newStream->cachedBlocks[1].dirty = 0;
06021   newStream->blockToEvict          = 0;
06022 
06023   if (FAILED(BlockChainStream_UpdateIndexCache(newStream)))
06024   {
06025     HeapFree(GetProcessHeap(), 0, newStream->indexCache);
06026     HeapFree(GetProcessHeap(), 0, newStream);
06027     return NULL;
06028   }
06029 
06030   return newStream;
06031 }
06032 
06033 HRESULT BlockChainStream_Flush(BlockChainStream* This)
06034 {
06035   int i;
06036   if (!This) return S_OK;
06037   for (i=0; i<2; i++)
06038   {
06039     if (This->cachedBlocks[i].dirty)
06040     {
06041       if (StorageImpl_WriteBigBlock(This->parentStorage, This->cachedBlocks[i].sector, This->cachedBlocks[i].data))
06042         This->cachedBlocks[i].dirty = 0;
06043       else
06044         return STG_E_WRITEFAULT;
06045     }
06046   }
06047   return S_OK;
06048 }
06049 
06050 void BlockChainStream_Destroy(BlockChainStream* This)
06051 {
06052   if (This)
06053   {
06054     BlockChainStream_Flush(This);
06055     HeapFree(GetProcessHeap(), 0, This->indexCache);
06056   }
06057   HeapFree(GetProcessHeap(), 0, This);
06058 }
06059 
06060 /******************************************************************************
06061  *      BlockChainStream_GetHeadOfChain
06062  *
06063  * Returns the head of this stream chain.
06064  * Some special chains don't have directory entries, their heads are kept in
06065  * This->headOfStreamPlaceHolder.
06066  *
06067  */
06068 static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
06069 {
06070   DirEntry  chainEntry;
06071   HRESULT   hr;
06072 
06073   if (This->headOfStreamPlaceHolder != 0)
06074     return *(This->headOfStreamPlaceHolder);
06075 
06076   if (This->ownerDirEntry != DIRENTRY_NULL)
06077   {
06078     hr = StorageImpl_ReadDirEntry(
06079                       This->parentStorage,
06080                       This->ownerDirEntry,
06081                       &chainEntry);
06082 
06083     if (SUCCEEDED(hr))
06084     {
06085       return chainEntry.startingBlock;
06086     }
06087   }
06088 
06089   return BLOCK_END_OF_CHAIN;
06090 }
06091 
06092 /******************************************************************************
06093  *       BlockChainStream_GetCount
06094  *
06095  * Returns the number of blocks that comprises this chain.
06096  * This is not the size of the stream as the last block may not be full!
06097  */
06098 static ULONG BlockChainStream_GetCount(BlockChainStream* This)
06099 {
06100   return This->numBlocks;
06101 }
06102 
06103 /******************************************************************************
06104  *      BlockChainStream_ReadAt
06105  *
06106  * Reads a specified number of bytes from this chain at the specified offset.
06107  * bytesRead may be NULL.
06108  * Failure will be returned if the specified number of bytes has not been read.
06109  */
06110 HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
06111   ULARGE_INTEGER offset,
06112   ULONG          size,
06113   void*          buffer,
06114   ULONG*         bytesRead)
06115 {
06116   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
06117   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
06118   ULONG bytesToReadInBuffer;
06119   ULONG blockIndex;
06120   BYTE* bufferWalker;
06121   ULARGE_INTEGER stream_size;
06122   HRESULT hr;
06123   BlockChainBlock *cachedBlock;
06124 
06125   TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
06126 
06127   /*
06128    * Find the first block in the stream that contains part of the buffer.
06129    */
06130   blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
06131 
06132   *bytesRead   = 0;
06133 
06134   stream_size = BlockChainStream_GetSize(This);
06135   if (stream_size.QuadPart > offset.QuadPart)
06136     size = min(stream_size.QuadPart - offset.QuadPart, size);
06137   else
06138     return S_OK;
06139 
06140   /*
06141    * Start reading the buffer.
06142    */
06143   bufferWalker = buffer;
06144 
06145   while (size > 0)
06146   {
06147     ULARGE_INTEGER ulOffset;
06148     DWORD bytesReadAt;
06149 
06150     /*
06151      * Calculate how many bytes we can copy from this big block.
06152      */
06153     bytesToReadInBuffer =
06154       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
06155 
06156     hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToReadInBuffer);
06157 
06158     if (FAILED(hr))
06159       return hr;
06160 
06161     if (!cachedBlock)
06162     {
06163       /* Not in cache, and we're going to read past the end of the block. */
06164       ulOffset.u.HighPart = 0;
06165       ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
06166                                offsetInBlock;
06167 
06168       StorageImpl_ReadAt(This->parentStorage,
06169            ulOffset,
06170            bufferWalker,
06171            bytesToReadInBuffer,
06172            &bytesReadAt);
06173     }
06174     else
06175     {
06176       if (!cachedBlock->read)
06177       {
06178         if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
06179           return STG_E_READFAULT;
06180 
06181         cachedBlock->read = 1;
06182       }
06183 
06184       memcpy(bufferWalker, cachedBlock->data+offsetInBlock, bytesToReadInBuffer);
06185       bytesReadAt = bytesToReadInBuffer;
06186     }
06187 
06188     blockNoInSequence++;
06189     bufferWalker += bytesReadAt;
06190     size         -= bytesReadAt;
06191     *bytesRead   += bytesReadAt;
06192     offsetInBlock = 0;  /* There is no offset on the next block */
06193 
06194     if (bytesToReadInBuffer != bytesReadAt)
06195         break;
06196   }
06197 
06198   return S_OK;
06199 }
06200 
06201 /******************************************************************************
06202  *      BlockChainStream_WriteAt
06203  *
06204  * Writes the specified number of bytes to this chain at the specified offset.
06205  * Will fail if not all specified number of bytes have been written.
06206  */
06207 HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
06208   ULARGE_INTEGER    offset,
06209   ULONG             size,
06210   const void*       buffer,
06211   ULONG*            bytesWritten)
06212 {
06213   ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
06214   ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
06215   ULONG bytesToWrite;
06216   ULONG blockIndex;
06217   const BYTE* bufferWalker;
06218   HRESULT hr;
06219   BlockChainBlock *cachedBlock;
06220 
06221   *bytesWritten   = 0;
06222   bufferWalker = buffer;
06223 
06224   while (size > 0)
06225   {
06226     ULARGE_INTEGER ulOffset;
06227     DWORD bytesWrittenAt;
06228 
06229     /*
06230      * Calculate how many bytes we can copy to this big block.
06231      */
06232     bytesToWrite =
06233       min(This->parentStorage->bigBlockSize - offsetInBlock, size);
06234 
06235     hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToWrite);
06236 
06237     /* BlockChainStream_SetSize should have already been called to ensure we have
06238      * enough blocks in the chain to write into */
06239     if (FAILED(hr))
06240     {
06241       ERR("not enough blocks in chain to write data\n");
06242       return hr;
06243     }
06244 
06245     if (!cachedBlock)
06246     {
06247       /* Not in cache, and we're going to write past the end of the block. */
06248       ulOffset.u.HighPart = 0;
06249       ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
06250                                offsetInBlock;
06251 
06252       StorageImpl_WriteAt(This->parentStorage,
06253            ulOffset,
06254            bufferWalker,
06255            bytesToWrite,
06256            &bytesWrittenAt);
06257     }
06258     else
06259     {
06260       if (!cachedBlock->read && bytesToWrite != This->parentStorage->bigBlockSize)
06261       {
06262         if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
06263           return STG_E_READFAULT;
06264       }
06265 
06266       memcpy(cachedBlock->data+offsetInBlock, bufferWalker, bytesToWrite);
06267       bytesWrittenAt = bytesToWrite;
06268       cachedBlock->read = 1;
06269       cachedBlock->dirty = 1;
06270     }
06271 
06272     blockNoInSequence++;
06273     bufferWalker  += bytesWrittenAt;
06274     size          -= bytesWrittenAt;
06275     *bytesWritten += bytesWrittenAt;
06276     offsetInBlock  = 0;      /* There is no offset on the next block */
06277 
06278     if (bytesWrittenAt != bytesToWrite)
06279       break;
06280   }
06281 
06282   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
06283 }
06284 
06285 /******************************************************************************
06286  *      BlockChainStream_Shrink
06287  *
06288  * Shrinks this chain in the big block depot.
06289  */
06290 static BOOL BlockChainStream_Shrink(BlockChainStream* This,
06291                                     ULARGE_INTEGER    newSize)
06292 {
06293   ULONG blockIndex;
06294   ULONG numBlocks;
06295   int i;
06296 
06297   /*
06298    * Figure out how many blocks are needed to contain the new size
06299    */
06300   numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
06301 
06302   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
06303     numBlocks++;
06304 
06305   if (numBlocks)
06306   {
06307     /*
06308      * Go to the new end of chain
06309      */
06310     blockIndex = BlockChainStream_GetSectorOfOffset(This, numBlocks-1);
06311 
06312     /* Mark the new end of chain */
06313     StorageImpl_SetNextBlockInChain(
06314       This->parentStorage,
06315       blockIndex,
06316       BLOCK_END_OF_CHAIN);
06317 
06318     This->tailIndex = blockIndex;
06319   }
06320   else
06321   {
06322     if (This->headOfStreamPlaceHolder != 0)
06323     {
06324       *This->headOfStreamPlaceHolder = BLOCK_END_OF_CHAIN;
06325     }
06326     else
06327     {
06328       DirEntry chainEntry;
06329       assert(This->ownerDirEntry != DIRENTRY_NULL);
06330 
06331       StorageImpl_ReadDirEntry(
06332         This->parentStorage,
06333         This->ownerDirEntry,
06334         &chainEntry);
06335 
06336       chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
06337 
06338       StorageImpl_WriteDirEntry(
06339         This->parentStorage,
06340         This->ownerDirEntry,
06341         &chainEntry);
06342     }
06343 
06344     This->tailIndex = BLOCK_END_OF_CHAIN;
06345   }
06346 
06347   This->numBlocks = numBlocks;
06348 
06349   /*
06350    * Mark the extra blocks as free
06351    */
06352   while (This->indexCacheLen && This->indexCache[This->indexCacheLen-1].lastOffset >= numBlocks)
06353   {
06354     struct BlockChainRun *last_run = &This->indexCache[This->indexCacheLen-1];
06355     StorageImpl_FreeBigBlock(This->parentStorage,
06356       last_run->firstSector + last_run->lastOffset - last_run->firstOffset);
06357     if (last_run->lastOffset == last_run->firstOffset)
06358       This->indexCacheLen--;
06359     else
06360       last_run->lastOffset--;
06361   }
06362 
06363   /*
06364    * Reset the last accessed block cache.
06365    */
06366   for (i=0; i<2; i++)
06367   {
06368     if (This->cachedBlocks[i].index >= numBlocks)
06369     {
06370       This->cachedBlocks[i].index = 0xffffffff;
06371       This->cachedBlocks[i].dirty = 0;
06372     }
06373   }
06374 
06375   return TRUE;
06376 }
06377 
06378 /******************************************************************************
06379  *      BlockChainStream_Enlarge
06380  *
06381  * Grows this chain in the big block depot.
06382  */
06383 static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
06384                                      ULARGE_INTEGER    newSize)
06385 {
06386   ULONG blockIndex, currentBlock;
06387   ULONG newNumBlocks;
06388   ULONG oldNumBlocks = 0;
06389 
06390   blockIndex = BlockChainStream_GetHeadOfChain(This);
06391 
06392   /*
06393    * Empty chain. Create the head.
06394    */
06395   if (blockIndex == BLOCK_END_OF_CHAIN)
06396   {
06397     blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
06398     StorageImpl_SetNextBlockInChain(This->parentStorage,
06399                                       blockIndex,
06400                                       BLOCK_END_OF_CHAIN);
06401 
06402     if (This->headOfStreamPlaceHolder != 0)
06403     {
06404       *(This->headOfStreamPlaceHolder) = blockIndex;
06405     }
06406     else
06407     {
06408       DirEntry chainEntry;
06409       assert(This->ownerDirEntry != DIRENTRY_NULL);
06410 
06411       StorageImpl_ReadDirEntry(
06412         This->parentStorage,
06413         This->ownerDirEntry,
06414         &chainEntry);
06415 
06416       chainEntry.startingBlock = blockIndex;
06417 
06418       StorageImpl_WriteDirEntry(
06419         This->parentStorage,
06420         This->ownerDirEntry,
06421         &chainEntry);
06422     }
06423 
06424     This->tailIndex = blockIndex;
06425     This->numBlocks = 1;
06426   }
06427 
06428   /*
06429    * Figure out how many blocks are needed to contain this stream
06430    */
06431   newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
06432 
06433   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
06434     newNumBlocks++;
06435 
06436   /*
06437    * Go to the current end of chain
06438    */
06439   if (This->tailIndex == BLOCK_END_OF_CHAIN)
06440   {
06441     currentBlock = blockIndex;
06442 
06443     while (blockIndex != BLOCK_END_OF_CHAIN)
06444     {
06445       This->numBlocks++;
06446       currentBlock = blockIndex;
06447 
06448       if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
06449                         &blockIndex)))
06450     return FALSE;
06451     }
06452 
06453     This->tailIndex = currentBlock;
06454   }
06455 
06456   currentBlock = This->tailIndex;
06457   oldNumBlocks = This->numBlocks;
06458 
06459   /*
06460    * Add new blocks to the chain
06461    */
06462   if (oldNumBlocks < newNumBlocks)
06463   {
06464     while (oldNumBlocks < newNumBlocks)
06465     {
06466       blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
06467 
06468       StorageImpl_SetNextBlockInChain(
06469     This->parentStorage,
06470     currentBlock,
06471     blockIndex);
06472 
06473       StorageImpl_SetNextBlockInChain(
06474         This->parentStorage,
06475     blockIndex,
06476     BLOCK_END_OF_CHAIN);
06477 
06478       currentBlock = blockIndex;
06479       oldNumBlocks++;
06480     }
06481 
06482     This->tailIndex = blockIndex;
06483     This->numBlocks = newNumBlocks;
06484   }
06485 
06486   if (FAILED(BlockChainStream_UpdateIndexCache(This)))
06487     return FALSE;
06488 
06489   return TRUE;
06490 }
06491 
06492 /******************************************************************************
06493  *      BlockChainStream_SetSize
06494  *
06495  * Sets the size of this stream. The big block depot will be updated.
06496  * The file will grow if we grow the chain.
06497  *
06498  * TODO: Free the actual blocks in the file when we shrink the chain.
06499  *       Currently, the blocks are still in the file. So the file size
06500  *       doesn't shrink even if we shrink streams.
06501  */
06502 BOOL BlockChainStream_SetSize(
06503   BlockChainStream* This,
06504   ULARGE_INTEGER    newSize)
06505 {
06506   ULARGE_INTEGER size = BlockChainStream_GetSize(This);
06507 
06508   if (newSize.u.LowPart == size.u.LowPart)
06509     return TRUE;
06510 
06511   if (newSize.u.LowPart < size.u.LowPart)
06512   {
06513     BlockChainStream_Shrink(This, newSize);
06514   }
06515   else
06516   {
06517     BlockChainStream_Enlarge(This, newSize);
06518   }
06519 
06520   return TRUE;
06521 }
06522 
06523 /******************************************************************************
06524  *      BlockChainStream_GetSize
06525  *
06526  * Returns the size of this chain.
06527  * Will return the block count if this chain doesn't have a directory entry.
06528  */
06529 static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
06530 {
06531   DirEntry chainEntry;
06532 
06533   if(This->headOfStreamPlaceHolder == NULL)
06534   {
06535     /*
06536      * This chain has a directory entry so use the size value from there.
06537      */
06538     StorageImpl_ReadDirEntry(
06539       This->parentStorage,
06540       This->ownerDirEntry,
06541       &chainEntry);
06542 
06543     return chainEntry.size;
06544   }
06545   else
06546   {
06547     /*
06548      * this chain is a chain that does not have a directory entry, figure out the
06549      * size by making the product number of used blocks times the
06550      * size of them
06551      */
06552     ULARGE_INTEGER result;
06553     result.u.HighPart = 0;
06554 
06555     result.u.LowPart  =
06556       BlockChainStream_GetCount(This) *
06557       This->parentStorage->bigBlockSize;
06558 
06559     return result;
06560   }
06561 }
06562 
06563 /******************************************************************************
06564 ** SmallBlockChainStream implementation
06565 */
06566 
06567 SmallBlockChainStream* SmallBlockChainStream_Construct(
06568   StorageImpl* parentStorage,
06569   ULONG*         headOfStreamPlaceHolder,
06570   DirRef         dirEntry)
06571 {
06572   SmallBlockChainStream* newStream;
06573 
06574   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
06575 
06576   newStream->parentStorage      = parentStorage;
06577   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
06578   newStream->ownerDirEntry      = dirEntry;
06579 
06580   return newStream;
06581 }
06582 
06583 void SmallBlockChainStream_Destroy(
06584   SmallBlockChainStream* This)
06585 {
06586   HeapFree(GetProcessHeap(), 0, This);
06587 }
06588 
06589 /******************************************************************************
06590  *      SmallBlockChainStream_GetHeadOfChain
06591  *
06592  * Returns the head of this chain of small blocks.
06593  */
06594 static ULONG SmallBlockChainStream_GetHeadOfChain(
06595   SmallBlockChainStream* This)
06596 {
06597   DirEntry  chainEntry;
06598   HRESULT   hr;
06599 
06600   if (This->headOfStreamPlaceHolder != NULL)
06601     return *(This->headOfStreamPlaceHolder);
06602 
06603   if (This->ownerDirEntry)
06604   {
06605     hr = StorageImpl_ReadDirEntry(
06606                       This->parentStorage,
06607                       This->ownerDirEntry,
06608                       &chainEntry);
06609 
06610     if (SUCCEEDED(hr))
06611     {
06612       return chainEntry.startingBlock;
06613     }
06614 
06615   }
06616 
06617   return BLOCK_END_OF_CHAIN;
06618 }
06619 
06620 /******************************************************************************
06621  *      SmallBlockChainStream_GetNextBlockInChain
06622  *
06623  * Returns the index of the next small block in this chain.
06624  *
06625  * Return Values:
06626  *    - BLOCK_END_OF_CHAIN: end of this chain
06627  *    - BLOCK_UNUSED: small block 'blockIndex' is free
06628  */
06629 static HRESULT SmallBlockChainStream_GetNextBlockInChain(
06630   SmallBlockChainStream* This,
06631   ULONG                  blockIndex,
06632   ULONG*                 nextBlockInChain)
06633 {
06634   ULARGE_INTEGER offsetOfBlockInDepot;
06635   DWORD  buffer;
06636   ULONG  bytesRead;
06637   HRESULT res;
06638 
06639   *nextBlockInChain = BLOCK_END_OF_CHAIN;
06640 
06641   offsetOfBlockInDepot.u.HighPart = 0;
06642   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
06643 
06644   /*
06645    * Read those bytes in the buffer from the small block file.
06646    */
06647   res = BlockChainStream_ReadAt(
06648               This->parentStorage->smallBlockDepotChain,
06649               offsetOfBlockInDepot,
06650               sizeof(DWORD),
06651               &buffer,
06652               &bytesRead);
06653 
06654   if (SUCCEEDED(res) && bytesRead != sizeof(DWORD))
06655     res = STG_E_READFAULT;
06656 
06657   if (SUCCEEDED(res))
06658   {
06659     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
06660     return S_OK;
06661   }
06662 
06663   return res;
06664 }
06665 
06666 /******************************************************************************
06667  *       SmallBlockChainStream_SetNextBlockInChain
06668  *
06669  * Writes the index of the next block of the specified block in the small
06670  * block depot.
06671  * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
06672  * To flag a block as free use BLOCK_UNUSED as nextBlock.
06673  */
06674 static void SmallBlockChainStream_SetNextBlockInChain(
06675   SmallBlockChainStream* This,
06676   ULONG                  blockIndex,
06677   ULONG                  nextBlock)
06678 {
06679   ULARGE_INTEGER offsetOfBlockInDepot;
06680   DWORD  buffer;
06681   ULONG  bytesWritten;
06682 
06683   offsetOfBlockInDepot.u.HighPart = 0;
06684   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
06685 
06686   StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
06687 
06688   /*
06689    * Read those bytes in the buffer from the small block file.
06690    */
06691   BlockChainStream_WriteAt(
06692     This->parentStorage->smallBlockDepotChain,
06693     offsetOfBlockInDepot,
06694     sizeof(DWORD),
06695     &buffer,
06696     &bytesWritten);
06697 }
06698 
06699 /******************************************************************************
06700  *      SmallBlockChainStream_FreeBlock
06701  *
06702  * Flag small block 'blockIndex' as free in the small block depot.
06703  */
06704 static void SmallBlockChainStream_FreeBlock(
06705   SmallBlockChainStream* This,
06706   ULONG                  blockIndex)
06707 {
06708   SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
06709 }
06710 
06711 /******************************************************************************
06712  *      SmallBlockChainStream_GetNextFreeBlock
06713  *
06714  * Returns the index of a free small block. The small block depot will be
06715  * enlarged if necessary. The small block chain will also be enlarged if
06716  * necessary.
06717  */
06718 static ULONG SmallBlockChainStream_GetNextFreeBlock(
06719   SmallBlockChainStream* This)
06720 {
06721   ULARGE_INTEGER offsetOfBlockInDepot;
06722   DWORD buffer;
06723   ULONG bytesRead;
06724   ULONG blockIndex = This->parentStorage->firstFreeSmallBlock;
06725   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
06726   HRESULT res = S_OK;
06727   ULONG smallBlocksPerBigBlock;
06728   DirEntry rootEntry;
06729   ULONG blocksRequired;
06730   ULARGE_INTEGER old_size, size_required;
06731 
06732   offsetOfBlockInDepot.u.HighPart = 0;
06733 
06734   /*
06735    * Scan the small block depot for a free block
06736    */
06737   while (nextBlockIndex != BLOCK_UNUSED)
06738   {
06739     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
06740 
06741     res = BlockChainStream_ReadAt(
06742                 This->parentStorage->smallBlockDepotChain,
06743                 offsetOfBlockInDepot,
06744                 sizeof(DWORD),
06745                 &buffer,
06746                 &bytesRead);
06747 
06748     /*
06749      * If we run out of space for the small block depot, enlarge it
06750      */
06751     if (SUCCEEDED(res) && bytesRead == sizeof(DWORD))
06752     {
06753       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
06754 
06755       if (nextBlockIndex != BLOCK_UNUSED)
06756         blockIndex++;
06757     }
06758     else
06759     {
06760       ULONG count =
06761         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
06762 
06763       BYTE smallBlockDepot[MAX_BIG_BLOCK_SIZE];
06764       ULARGE_INTEGER newSize, offset;
06765       ULONG bytesWritten;
06766 
06767       newSize.QuadPart = (count + 1) * This->parentStorage->bigBlockSize;
06768       BlockChainStream_Enlarge(This->parentStorage->smallBlockDepotChain, newSize);
06769 
06770       /*
06771        * Initialize all the small blocks to free
06772        */
06773       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
06774       offset.QuadPart = count * This->parentStorage->bigBlockSize;
06775       BlockChainStream_WriteAt(This->parentStorage->smallBlockDepotChain,
06776         offset, This->parentStorage->bigBlockSize, smallBlockDepot, &bytesWritten);
06777 
06778       StorageImpl_SaveFileHeader(This->parentStorage);
06779     }
06780   }
06781 
06782   This->parentStorage->firstFreeSmallBlock = blockIndex+1;
06783 
06784   smallBlocksPerBigBlock =
06785     This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
06786 
06787   /*
06788    * Verify if we have to allocate big blocks to contain small blocks
06789    */
06790   blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
06791 
06792   size_required.QuadPart = blocksRequired * This->parentStorage->bigBlockSize;
06793 
06794   old_size = BlockChainStream_GetSize(This->parentStorage->smallBlockRootChain);
06795 
06796   if (size_required.QuadPart > old_size.QuadPart)
06797   {
06798     BlockChainStream_SetSize(
06799       This->parentStorage->smallBlockRootChain,
06800       size_required);
06801 
06802     StorageImpl_ReadDirEntry(
06803       This->parentStorage,
06804       This->parentStorage->base.storageDirEntry,
06805       &rootEntry);
06806 
06807     rootEntry.size = size_required;
06808 
06809     StorageImpl_WriteDirEntry(
06810       This->parentStorage,
06811       This->parentStorage->base.storageDirEntry,
06812       &rootEntry);
06813   }
06814 
06815   return blockIndex;
06816 }
06817 
06818 /******************************************************************************
06819  *      SmallBlockChainStream_ReadAt
06820  *
06821  * Reads a specified number of bytes from this chain at the specified offset.
06822  * bytesRead may be NULL.
06823  * Failure will be returned if the specified number of bytes has not been read.
06824  */
06825 HRESULT SmallBlockChainStream_ReadAt(
06826   SmallBlockChainStream* This,
06827   ULARGE_INTEGER         offset,
06828   ULONG                  size,
06829   void*                  buffer,
06830   ULONG*                 bytesRead)
06831 {
06832   HRESULT rc = S_OK;
06833   ULARGE_INTEGER offsetInBigBlockFile;
06834   ULONG blockNoInSequence =
06835     offset.u.LowPart / This->parentStorage->smallBlockSize;
06836 
06837   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
06838   ULONG bytesToReadInBuffer;
06839   ULONG blockIndex;
06840   ULONG bytesReadFromBigBlockFile;
06841   BYTE* bufferWalker;
06842   ULARGE_INTEGER stream_size;
06843 
06844   /*
06845    * This should never happen on a small block file.
06846    */
06847   assert(offset.u.HighPart==0);
06848 
06849   *bytesRead   = 0;
06850 
06851   stream_size = SmallBlockChainStream_GetSize(This);
06852   if (stream_size.QuadPart > offset.QuadPart)
06853     size = min(stream_size.QuadPart - offset.QuadPart, size);
06854   else
06855     return S_OK;
06856 
06857   /*
06858    * Find the first block in the stream that contains part of the buffer.
06859    */
06860   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
06861 
06862   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
06863   {
06864     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
06865     if(FAILED(rc))
06866       return rc;
06867     blockNoInSequence--;
06868   }
06869 
06870   /*
06871    * Start reading the buffer.
06872    */
06873   bufferWalker = buffer;
06874 
06875   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
06876   {
06877     /*
06878      * Calculate how many bytes we can copy from this small block.
06879      */
06880     bytesToReadInBuffer =
06881       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
06882 
06883     /*
06884      * Calculate the offset of the small block in the small block file.
06885      */
06886     offsetInBigBlockFile.u.HighPart  = 0;
06887     offsetInBigBlockFile.u.LowPart   =
06888       blockIndex * This->parentStorage->smallBlockSize;
06889 
06890     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
06891 
06892     /*
06893      * Read those bytes in the buffer from the small block file.
06894      * The small block has already been identified so it shouldn't fail
06895      * unless the file is corrupt.
06896      */
06897     rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
06898       offsetInBigBlockFile,
06899       bytesToReadInBuffer,
06900       bufferWalker,
06901       &bytesReadFromBigBlockFile);
06902 
06903     if (FAILED(rc))
06904       return rc;
06905 
06906     if (!bytesReadFromBigBlockFile)
06907       return STG_E_DOCFILECORRUPT;
06908 
06909     /*
06910      * Step to the next big block.
06911      */
06912     rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
06913     if(FAILED(rc))
06914       return STG_E_DOCFILECORRUPT;
06915 
06916     bufferWalker += bytesReadFromBigBlockFile;
06917     size         -= bytesReadFromBigBlockFile;
06918     *bytesRead   += bytesReadFromBigBlockFile;
06919     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
06920   }
06921 
06922   return S_OK;
06923 }
06924 
06925 /******************************************************************************
06926  *       SmallBlockChainStream_WriteAt
06927  *
06928  * Writes the specified number of bytes to this chain at the specified offset.
06929  * Will fail if not all specified number of bytes have been written.
06930  */
06931 HRESULT SmallBlockChainStream_WriteAt(
06932   SmallBlockChainStream* This,
06933   ULARGE_INTEGER offset,
06934   ULONG          size,
06935   const void*    buffer,
06936   ULONG*         bytesWritten)
06937 {
06938   ULARGE_INTEGER offsetInBigBlockFile;
06939   ULONG blockNoInSequence =
06940     offset.u.LowPart / This->parentStorage->smallBlockSize;
06941 
06942   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
06943   ULONG bytesToWriteInBuffer;
06944   ULONG blockIndex;
06945   ULONG bytesWrittenToBigBlockFile;
06946   const BYTE* bufferWalker;
06947   HRESULT res;
06948 
06949   /*
06950    * This should never happen on a small block file.
06951    */
06952   assert(offset.u.HighPart==0);
06953 
06954   /*
06955    * Find the first block in the stream that contains part of the buffer.
06956    */
06957   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
06958 
06959   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
06960   {
06961     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
06962       return STG_E_DOCFILECORRUPT;
06963     blockNoInSequence--;
06964   }
06965 
06966   /*
06967    * Start writing the buffer.
06968    */
06969   *bytesWritten   = 0;
06970   bufferWalker = buffer;
06971   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
06972   {
06973     /*
06974      * Calculate how many bytes we can copy to this small block.
06975      */
06976     bytesToWriteInBuffer =
06977       min(This->parentStorage->smallBlockSize - offsetInBlock, size);
06978 
06979     /*
06980      * Calculate the offset of the small block in the small block file.
06981      */
06982     offsetInBigBlockFile.u.HighPart  = 0;
06983     offsetInBigBlockFile.u.LowPart   =
06984       blockIndex * This->parentStorage->smallBlockSize;
06985 
06986     offsetInBigBlockFile.u.LowPart  += offsetInBlock;
06987 
06988     /*
06989      * Write those bytes in the buffer to the small block file.
06990      */
06991     res = BlockChainStream_WriteAt(
06992       This->parentStorage->smallBlockRootChain,
06993       offsetInBigBlockFile,
06994       bytesToWriteInBuffer,
06995       bufferWalker,
06996       &bytesWrittenToBigBlockFile);
06997     if (FAILED(res))
06998       return res;
06999 
07000     /*
07001      * Step to the next big block.
07002      */
07003     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
07004                             &blockIndex)))
07005       return FALSE;
07006     bufferWalker  += bytesWrittenToBigBlockFile;
07007     size          -= bytesWrittenToBigBlockFile;
07008     *bytesWritten += bytesWrittenToBigBlockFile;
07009     offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
07010   }
07011 
07012   return (size == 0) ? S_OK : STG_E_WRITEFAULT;
07013 }
07014 
07015 /******************************************************************************
07016  *       SmallBlockChainStream_Shrink
07017  *
07018  * Shrinks this chain in the small block depot.
07019  */
07020 static BOOL SmallBlockChainStream_Shrink(
07021   SmallBlockChainStream* This,
07022   ULARGE_INTEGER newSize)
07023 {
07024   ULONG blockIndex, extraBlock;
07025   ULONG numBlocks;
07026   ULONG count = 0;
07027 
07028   numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
07029 
07030   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
07031     numBlocks++;
07032 
07033   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
07034 
07035   /*
07036    * Go to the new end of chain
07037    */
07038   while (count < numBlocks)
07039   {
07040     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
07041                             &blockIndex)))
07042       return FALSE;
07043     count++;
07044   }
07045 
07046   /*
07047    * If the count is 0, we have a special case, the head of the chain was
07048    * just freed.
07049    */
07050   if (count == 0)
07051   {
07052     DirEntry chainEntry;
07053 
07054     StorageImpl_ReadDirEntry(This->parentStorage,
07055                  This->ownerDirEntry,
07056                  &chainEntry);
07057 
07058     chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
07059 
07060     StorageImpl_WriteDirEntry(This->parentStorage,
07061                   This->ownerDirEntry,
07062                   &chainEntry);
07063 
07064     /*
07065      * We start freeing the chain at the head block.
07066      */
07067     extraBlock = blockIndex;
07068   }
07069   else
07070   {
07071     /* Get the next block before marking the new end */
07072     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
07073                             &extraBlock)))
07074       return FALSE;
07075 
07076     /* Mark the new end of chain */
07077     SmallBlockChainStream_SetNextBlockInChain(
07078       This,
07079       blockIndex,
07080       BLOCK_END_OF_CHAIN);
07081   }
07082 
07083   /*
07084    * Mark the extra blocks as free
07085    */
07086   while (extraBlock != BLOCK_END_OF_CHAIN)
07087   {
07088     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
07089                             &blockIndex)))
07090       return FALSE;
07091     SmallBlockChainStream_FreeBlock(This, extraBlock);
07092     This->parentStorage->firstFreeSmallBlock = min(This->parentStorage->firstFreeSmallBlock, extraBlock);
07093     extraBlock = blockIndex;
07094   }
07095 
07096   return TRUE;
07097 }
07098 
07099 /******************************************************************************
07100  *      SmallBlockChainStream_Enlarge
07101  *
07102  * Grows this chain in the small block depot.
07103  */
07104 static BOOL SmallBlockChainStream_Enlarge(
07105   SmallBlockChainStream* This,
07106   ULARGE_INTEGER newSize)
07107 {
07108   ULONG blockIndex, currentBlock;
07109   ULONG newNumBlocks;
07110   ULONG oldNumBlocks = 0;
07111 
07112   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
07113 
07114   /*
07115    * Empty chain. Create the head.
07116    */
07117   if (blockIndex == BLOCK_END_OF_CHAIN)
07118   {
07119     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
07120     SmallBlockChainStream_SetNextBlockInChain(
07121         This,
07122         blockIndex,
07123         BLOCK_END_OF_CHAIN);
07124 
07125     if (This->headOfStreamPlaceHolder != NULL)
07126     {
07127       *(This->headOfStreamPlaceHolder) = blockIndex;
07128     }
07129     else
07130     {
07131       DirEntry chainEntry;
07132 
07133       StorageImpl_ReadDirEntry(This->parentStorage, This->ownerDirEntry,
07134                                    &chainEntry);
07135 
07136       chainEntry.startingBlock = blockIndex;
07137 
07138       StorageImpl_WriteDirEntry(This->parentStorage, This->ownerDirEntry,
07139                                   &chainEntry);
07140     }
07141   }
07142 
07143   currentBlock = blockIndex;
07144 
07145   /*
07146    * Figure out how many blocks are needed to contain this stream
07147    */
07148   newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
07149 
07150   if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
07151     newNumBlocks++;
07152 
07153   /*
07154    * Go to the current end of chain
07155    */
07156   while (blockIndex != BLOCK_END_OF_CHAIN)
07157   {
07158     oldNumBlocks++;
07159     currentBlock = blockIndex;
07160     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
07161       return FALSE;
07162   }
07163 
07164   /*
07165    * Add new blocks to the chain
07166    */
07167   while (oldNumBlocks < newNumBlocks)
07168   {
07169     blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
07170     SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
07171 
07172     SmallBlockChainStream_SetNextBlockInChain(
07173       This,
07174       blockIndex,
07175       BLOCK_END_OF_CHAIN);
07176 
07177     currentBlock = blockIndex;
07178     oldNumBlocks++;
07179   }
07180 
07181   return TRUE;
07182 }
07183 
07184 /******************************************************************************
07185  *      SmallBlockChainStream_SetSize
07186  *
07187  * Sets the size of this stream.
07188  * The file will grow if we grow the chain.
07189  *
07190  * TODO: Free the actual blocks in the file when we shrink the chain.
07191  *       Currently, the blocks are still in the file. So the file size
07192  *       doesn't shrink even if we shrink streams.
07193  */
07194 BOOL SmallBlockChainStream_SetSize(
07195                 SmallBlockChainStream* This,
07196                 ULARGE_INTEGER    newSize)
07197 {
07198   ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
07199 
07200   if (newSize.u.LowPart == size.u.LowPart)
07201     return TRUE;
07202 
07203   if (newSize.u.LowPart < size.u.LowPart)
07204   {
07205     SmallBlockChainStream_Shrink(This, newSize);
07206   }
07207   else
07208   {
07209     SmallBlockChainStream_Enlarge(This, newSize);
07210   }
07211 
07212   return TRUE;
07213 }
07214 
07215 /******************************************************************************
07216  *       SmallBlockChainStream_GetCount
07217  *
07218  * Returns the number of small blocks that comprises this chain.
07219  * This is not the size of the stream as the last block may not be full!
07220  *
07221  */
07222 static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
07223 {
07224     ULONG blockIndex;
07225     ULONG count = 0;
07226 
07227     blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
07228 
07229     while(blockIndex != BLOCK_END_OF_CHAIN)
07230     {
07231         count++;
07232 
07233         if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This,
07234                         blockIndex, &blockIndex)))
07235             return 0;
07236     }
07237 
07238     return count;
07239 }
07240 
07241 /******************************************************************************
07242  *      SmallBlockChainStream_GetSize
07243  *
07244  * Returns the size of this chain.
07245  */
07246 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
07247 {
07248   DirEntry chainEntry;
07249 
07250   if(This->headOfStreamPlaceHolder != NULL)
07251   {
07252     ULARGE_INTEGER result;
07253     result.u.HighPart = 0;
07254 
07255     result.u.LowPart = SmallBlockChainStream_GetCount(This) *
07256         This->parentStorage->smallBlockSize;
07257 
07258     return result;
07259   }
07260 
07261   StorageImpl_ReadDirEntry(
07262     This->parentStorage,
07263     This->ownerDirEntry,
07264     &chainEntry);
07265 
07266   return chainEntry.size;
07267 }
07268 
07269 static HRESULT create_storagefile(
07270   LPCOLESTR pwcsName,
07271   DWORD       grfMode,
07272   DWORD       grfAttrs,
07273   STGOPTIONS* pStgOptions,
07274   REFIID      riid,
07275   void**      ppstgOpen)
07276 {
07277   StorageBaseImpl* newStorage = 0;
07278   HANDLE       hFile      = INVALID_HANDLE_VALUE;
07279   HRESULT        hr         = STG_E_INVALIDFLAG;
07280   DWORD          shareMode;
07281   DWORD          accessMode;
07282   DWORD          creationMode;
07283   DWORD          fileAttributes;
07284   WCHAR          tempFileName[MAX_PATH];
07285 
07286   if (ppstgOpen == 0)
07287     return STG_E_INVALIDPOINTER;
07288 
07289   if (pStgOptions->ulSectorSize != MIN_BIG_BLOCK_SIZE && pStgOptions->ulSectorSize != MAX_BIG_BLOCK_SIZE)
07290     return STG_E_INVALIDPARAMETER;
07291 
07292   /* if no share mode given then DENY_NONE is the default */
07293   if (STGM_SHARE_MODE(grfMode) == 0)
07294       grfMode |= STGM_SHARE_DENY_NONE;
07295 
07296   if ( FAILED( validateSTGM(grfMode) ))
07297     goto end;
07298 
07299   /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
07300   switch(STGM_ACCESS_MODE(grfMode))
07301   {
07302   case STGM_WRITE:
07303   case STGM_READWRITE:
07304     break;
07305   default:
07306     goto end;
07307   }
07308 
07309   /* in direct mode, can only use SHARE_EXCLUSIVE */
07310   if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
07311     goto end;
07312 
07313   /* but in transacted mode, any share mode is valid */
07314 
07315   /*
07316    * Generate a unique name.
07317    */
07318   if (pwcsName == 0)
07319   {
07320     WCHAR tempPath[MAX_PATH];
07321     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
07322 
07323     memset(tempPath, 0, sizeof(tempPath));
07324     memset(tempFileName, 0, sizeof(tempFileName));
07325 
07326     if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
07327       tempPath[0] = '.';
07328 
07329     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
07330       pwcsName = tempFileName;
07331     else
07332     {
07333       hr = STG_E_INSUFFICIENTMEMORY;
07334       goto end;
07335     }
07336 
07337     creationMode = TRUNCATE_EXISTING;
07338   }
07339   else
07340   {
07341     creationMode = GetCreationModeFromSTGM(grfMode);
07342   }
07343 
07344   /*
07345    * Interpret the STGM value grfMode
07346    */
07347   shareMode    = FILE_SHARE_READ | FILE_SHARE_WRITE;
07348   accessMode   = GetAccessModeFromSTGM(grfMode);
07349 
07350   if (grfMode & STGM_DELETEONRELEASE)
07351     fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
07352   else
07353     fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
07354 
07355   if (STGM_SHARE_MODE(grfMode) && !(grfMode & STGM_SHARE_DENY_NONE))
07356   {
07357     static int fixme;
07358     if (!fixme++)
07359       FIXME("Storage share mode not implemented.\n");
07360   }
07361 
07362   *ppstgOpen = 0;
07363 
07364   hFile = CreateFileW(pwcsName,
07365                         accessMode,
07366                         shareMode,
07367                         NULL,
07368                         creationMode,
07369                         fileAttributes,
07370                         0);
07371 
07372   if (hFile == INVALID_HANDLE_VALUE)
07373   {
07374     if(GetLastError() == ERROR_FILE_EXISTS)
07375       hr = STG_E_FILEALREADYEXISTS;
07376     else
07377       hr = E_FAIL;
07378     goto end;
07379   }
07380 
07381   /*
07382    * Allocate and initialize the new IStorage32object.
07383    */
07384   hr = Storage_Construct(
07385          hFile,
07386         pwcsName,
07387          NULL,
07388          grfMode,
07389          TRUE,
07390          TRUE,
07391          pStgOptions->ulSectorSize,
07392          &newStorage);
07393 
07394   if (FAILED(hr))
07395   {
07396     goto end;
07397   }
07398 
07399   hr = IStorage_QueryInterface((IStorage*)newStorage, riid, ppstgOpen);
07400 
07401   IStorage_Release((IStorage*)newStorage);
07402 
07403 end:
07404   TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
07405 
07406   return hr;
07407 }
07408 
07409 /******************************************************************************
07410  *    StgCreateDocfile  [OLE32.@]
07411  * Creates a new compound file storage object
07412  *
07413  * PARAMS
07414  *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
07415  *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
07416  *  reserved  [ ?] unused?, usually 0
07417  *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
07418  *
07419  * RETURNS
07420  *  S_OK if the file was successfully created
07421  *  some STG_E_ value if error
07422  * NOTES
07423  *  if pwcsName is NULL, create file with new unique name
07424  *  the function can returns
07425  *  STG_S_CONVERTED if the specified file was successfully converted to storage format
07426  *  (unrealized now)
07427  */
07428 HRESULT WINAPI StgCreateDocfile(
07429   LPCOLESTR pwcsName,
07430   DWORD       grfMode,
07431   DWORD       reserved,
07432   IStorage  **ppstgOpen)
07433 {
07434   STGOPTIONS stgoptions = {1, 0, 512};
07435 
07436   TRACE("(%s, %x, %d, %p)\n",
07437     debugstr_w(pwcsName), grfMode,
07438     reserved, ppstgOpen);
07439 
07440   if (ppstgOpen == 0)
07441     return STG_E_INVALIDPOINTER;
07442   if (reserved != 0)
07443     return STG_E_INVALIDPARAMETER;
07444 
07445   return create_storagefile(pwcsName, grfMode, 0, &stgoptions, &IID_IStorage, (void**)ppstgOpen);
07446 }
07447 
07448 /******************************************************************************
07449  *              StgCreateStorageEx        [OLE32.@]
07450  */
07451 HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
07452 {
07453     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
07454           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
07455 
07456     if (stgfmt != STGFMT_FILE && grfAttrs != 0)
07457     {
07458         ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
07459         return STG_E_INVALIDPARAMETER;  
07460     }
07461 
07462     if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
07463     {
07464         ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
07465         return STG_E_INVALIDPARAMETER;  
07466     }
07467 
07468     if (stgfmt == STGFMT_FILE)
07469     {
07470         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
07471         return STG_E_INVALIDPARAMETER;
07472     }
07473 
07474     if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
07475     {
07476         STGOPTIONS defaultOptions = {1, 0, 512};
07477 
07478         if (!pStgOptions) pStgOptions = &defaultOptions;
07479         return create_storagefile(pwcsName, grfMode, grfAttrs, pStgOptions, riid, ppObjectOpen);
07480     }
07481 
07482 
07483     ERR("Invalid stgfmt argument\n");
07484     return STG_E_INVALIDPARAMETER;
07485 }
07486 
07487 /******************************************************************************
07488  *              StgCreatePropSetStg       [OLE32.@]
07489  */
07490 HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
07491  IPropertySetStorage **ppPropSetStg)
07492 {
07493     HRESULT hr;
07494 
07495     TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
07496     if (reserved)
07497         hr = STG_E_INVALIDPARAMETER;
07498     else
07499         hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
07500          (void**)ppPropSetStg);
07501     return hr;
07502 }
07503 
07504 /******************************************************************************
07505  *              StgOpenStorageEx      [OLE32.@]
07506  */
07507 HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
07508 {
07509     TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
07510           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
07511 
07512     if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
07513     {
07514         ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
07515         return STG_E_INVALIDPARAMETER;  
07516     }
07517 
07518     switch (stgfmt)
07519     {
07520     case STGFMT_FILE:
07521         ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
07522         return STG_E_INVALIDPARAMETER;
07523         
07524     case STGFMT_STORAGE:
07525         break;
07526 
07527     case STGFMT_DOCFILE:
07528         if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
07529         {
07530             ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
07531             return STG_E_INVALIDPARAMETER;  
07532         }
07533         FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
07534         break;
07535 
07536     case STGFMT_ANY:
07537         WARN("STGFMT_ANY assuming storage\n");
07538         break;
07539 
07540     default:
07541         return STG_E_INVALIDPARAMETER;
07542     }
07543 
07544     return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
07545 }
07546 
07547 
07548 /******************************************************************************
07549  *              StgOpenStorage        [OLE32.@]
07550  */
07551 HRESULT WINAPI StgOpenStorage(
07552   const OLECHAR *pwcsName,
07553   IStorage      *pstgPriority,
07554   DWORD          grfMode,
07555   SNB            snbExclude,
07556   DWORD          reserved,
07557   IStorage     **ppstgOpen)
07558 {
07559   StorageBaseImpl* newStorage = 0;
07560   HRESULT        hr = S_OK;
07561   HANDLE         hFile = 0;
07562   DWORD          shareMode;
07563   DWORD          accessMode;
07564 
07565   TRACE("(%s, %p, %x, %p, %d, %p)\n",
07566     debugstr_w(pwcsName), pstgPriority, grfMode,
07567     snbExclude, reserved, ppstgOpen);
07568 
07569   if (pwcsName == 0)
07570   {
07571     hr = STG_E_INVALIDNAME;
07572     goto end;
07573   }
07574 
07575   if (ppstgOpen == 0)
07576   {
07577     hr = STG_E_INVALIDPOINTER;
07578     goto end;
07579   }
07580 
07581   if (reserved)
07582   {
07583     hr = STG_E_INVALIDPARAMETER;
07584     goto end;
07585   }
07586 
07587   if (grfMode & STGM_PRIORITY)
07588   {
07589     if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
07590       return STG_E_INVALIDFLAG;
07591     if (grfMode & STGM_DELETEONRELEASE)
07592       return STG_E_INVALIDFUNCTION;
07593     if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
07594       return STG_E_INVALIDFLAG;
07595     grfMode &= ~0xf0; /* remove the existing sharing mode */
07596     grfMode |= STGM_SHARE_DENY_NONE;
07597 
07598     /* STGM_PRIORITY stops other IStorage objects on the same file from
07599      * committing until the STGM_PRIORITY IStorage is closed. it also
07600      * stops non-transacted mode StgOpenStorage calls with write access from
07601      * succeeding. obviously, both of these cannot be achieved through just
07602      * file share flags */
07603     FIXME("STGM_PRIORITY mode not implemented correctly\n");
07604   }
07605 
07606   /*
07607    * Validate the sharing mode
07608    */
07609   if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
07610     switch(STGM_SHARE_MODE(grfMode))
07611     {
07612       case STGM_SHARE_EXCLUSIVE:
07613       case STGM_SHARE_DENY_WRITE:
07614         break;
07615       default:
07616         hr = STG_E_INVALIDFLAG;
07617         goto end;
07618     }
07619 
07620   if ( FAILED( validateSTGM(grfMode) ) ||
07621        (grfMode&STGM_CREATE))
07622   {
07623     hr = STG_E_INVALIDFLAG;
07624     goto end;
07625   }
07626 
07627   /* shared reading requires transacted mode */
07628   if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
07629       STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
07630      !(grfMode&STGM_TRANSACTED) )
07631   {
07632     hr = STG_E_INVALIDFLAG;
07633     goto end;
07634   }
07635 
07636   /*
07637    * Interpret the STGM value grfMode
07638    */
07639   shareMode    = GetShareModeFromSTGM(grfMode);
07640   accessMode   = GetAccessModeFromSTGM(grfMode);
07641 
07642   *ppstgOpen = 0;
07643 
07644   hFile = CreateFileW( pwcsName,
07645                        accessMode,
07646                        shareMode,
07647                        NULL,
07648                        OPEN_EXISTING,
07649                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
07650                        0);
07651 
07652   if (hFile==INVALID_HANDLE_VALUE)
07653   {
07654     DWORD last_error = GetLastError();
07655 
07656     hr = E_FAIL;
07657 
07658     switch (last_error)
07659     {
07660       case ERROR_FILE_NOT_FOUND:
07661         hr = STG_E_FILENOTFOUND;
07662         break;
07663 
07664       case ERROR_PATH_NOT_FOUND:
07665         hr = STG_E_PATHNOTFOUND;
07666         break;
07667 
07668       case ERROR_ACCESS_DENIED:
07669       case ERROR_WRITE_PROTECT:
07670         hr = STG_E_ACCESSDENIED;
07671         break;
07672 
07673       case ERROR_SHARING_VIOLATION:
07674         hr = STG_E_SHAREVIOLATION;
07675         break;
07676 
07677       default:
07678         hr = E_FAIL;
07679     }
07680 
07681     goto end;
07682   }
07683 
07684   /*
07685    * Refuse to open the file if it's too small to be a structured storage file
07686    * FIXME: verify the file when reading instead of here
07687    */
07688   if (GetFileSize(hFile, NULL) < 0x100)
07689   {
07690     CloseHandle(hFile);
07691     hr = STG_E_FILEALREADYEXISTS;
07692     goto end;
07693   }
07694 
07695   /*
07696    * Allocate and initialize the new IStorage32object.
07697    */
07698   hr = Storage_Construct(
07699          hFile,
07700          pwcsName,
07701          NULL,
07702          grfMode,
07703          TRUE,
07704          FALSE,
07705          512,
07706          &newStorage);
07707 
07708   if (FAILED(hr))
07709   {
07710     /*
07711      * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
07712      */
07713     if(hr == STG_E_INVALIDHEADER)
07714     hr = STG_E_FILEALREADYEXISTS;
07715     goto end;
07716   }
07717 
07718   /*
07719    * Get an "out" pointer for the caller.
07720    */
07721   *ppstgOpen = (IStorage*)newStorage;
07722 
07723 end:
07724   TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
07725   return hr;
07726 }
07727 
07728 /******************************************************************************
07729  *    StgCreateDocfileOnILockBytes    [OLE32.@]
07730  */
07731 HRESULT WINAPI StgCreateDocfileOnILockBytes(
07732       ILockBytes *plkbyt,
07733       DWORD grfMode,
07734       DWORD reserved,
07735       IStorage** ppstgOpen)
07736 {
07737   StorageBaseImpl* newStorage = 0;
07738   HRESULT        hr         = S_OK;
07739 
07740   if ((ppstgOpen == 0) || (plkbyt == 0))
07741     return STG_E_INVALIDPOINTER;
07742 
07743   /*
07744    * Allocate and initialize the new IStorage object.
07745    */
07746   hr = Storage_Construct(
07747          0,
07748         0,
07749          plkbyt,
07750          grfMode,
07751          FALSE,
07752          TRUE,
07753          512,
07754          &newStorage);
07755 
07756   if (FAILED(hr))
07757   {
07758     return hr;
07759   }
07760 
07761   /*
07762    * Get an "out" pointer for the caller.
07763    */
07764   *ppstgOpen = (IStorage*)newStorage;
07765 
07766   return hr;
07767 }
07768 
07769 /******************************************************************************
07770  *    StgOpenStorageOnILockBytes    [OLE32.@]
07771  */
07772 HRESULT WINAPI StgOpenStorageOnILockBytes(
07773       ILockBytes *plkbyt,
07774       IStorage *pstgPriority,
07775       DWORD grfMode,
07776       SNB snbExclude,
07777       DWORD reserved,
07778       IStorage **ppstgOpen)
07779 {
07780   StorageBaseImpl* newStorage = 0;
07781   HRESULT        hr = S_OK;
07782 
07783   if ((plkbyt == 0) || (ppstgOpen == 0))
07784     return STG_E_INVALIDPOINTER;
07785 
07786   if ( FAILED( validateSTGM(grfMode) ))
07787     return STG_E_INVALIDFLAG;
07788 
07789   *ppstgOpen = 0;
07790 
07791   /*
07792    * Allocate and initialize the new IStorage object.
07793    */
07794   hr = Storage_Construct(
07795          0,
07796          0,
07797          plkbyt,
07798          grfMode,
07799          FALSE,
07800          FALSE,
07801          512,
07802          &newStorage);
07803 
07804   if (FAILED(hr))
07805   {
07806     return hr;
07807   }
07808 
07809   /*
07810    * Get an "out" pointer for the caller.
07811    */
07812   *ppstgOpen = (IStorage*)newStorage;
07813 
07814   return hr;
07815 }
07816 
07817 /******************************************************************************
07818  *              StgSetTimes [ole32.@]
07819  *              StgSetTimes [OLE32.@]
07820  *
07821  *
07822  */
07823 HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
07824                            FILETIME const *patime, FILETIME const *pmtime)
07825 {
07826   IStorage *stg = NULL;
07827   HRESULT r;
07828  
07829   TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
07830 
07831   r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
07832                      0, 0, &stg);
07833   if( SUCCEEDED(r) )
07834   {
07835     r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
07836     IStorage_Release(stg);
07837   }
07838 
07839   return r;
07840 }
07841 
07842 /******************************************************************************
07843  *              StgIsStorageILockBytes        [OLE32.@]
07844  *
07845  * Determines if the ILockBytes contains a storage object.
07846  */
07847 HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
07848 {
07849   BYTE sig[sizeof(STORAGE_magic)];
07850   ULARGE_INTEGER offset;
07851   ULONG read = 0;
07852 
07853   offset.u.HighPart = 0;
07854   offset.u.LowPart  = 0;
07855 
07856   ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), &read);
07857 
07858   if (read == sizeof(sig) && memcmp(sig, STORAGE_magic, sizeof(sig)) == 0)
07859     return S_OK;
07860 
07861   return S_FALSE;
07862 }
07863 
07864 /******************************************************************************
07865  *              WriteClassStg        [OLE32.@]
07866  *
07867  * This method will store the specified CLSID in the specified storage object
07868  */
07869 HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
07870 {
07871   HRESULT hRes;
07872 
07873   if(!pStg)
07874     return E_INVALIDARG;
07875 
07876   if(!rclsid)
07877     return STG_E_INVALIDPOINTER;
07878 
07879   hRes = IStorage_SetClass(pStg, rclsid);
07880 
07881   return hRes;
07882 }
07883 
07884 /***********************************************************************
07885  *    ReadClassStg (OLE32.@)
07886  *
07887  * This method reads the CLSID previously written to a storage object with
07888  * the WriteClassStg.
07889  *
07890  * PARAMS
07891  *  pstg    [I] IStorage pointer
07892  *  pclsid  [O] Pointer to where the CLSID is written
07893  *
07894  * RETURNS
07895  *  Success: S_OK.
07896  *  Failure: HRESULT code.
07897  */
07898 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
07899 
07900     STATSTG pstatstg;
07901     HRESULT hRes;
07902 
07903     TRACE("(%p, %p)\n", pstg, pclsid);
07904 
07905     if(!pstg || !pclsid)
07906         return E_INVALIDARG;
07907 
07908    /*
07909     * read a STATSTG structure (contains the clsid) from the storage
07910     */
07911     hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_NONAME);
07912 
07913     if(SUCCEEDED(hRes))
07914         *pclsid=pstatstg.clsid;
07915 
07916     return hRes;
07917 }
07918 
07919 /***********************************************************************
07920  *    OleLoadFromStream (OLE32.@)
07921  *
07922  * This function loads an object from stream
07923  */
07924 HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
07925 {
07926     CLSID   clsid;
07927     HRESULT res;
07928     LPPERSISTSTREAM xstm;
07929 
07930     TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
07931 
07932     res=ReadClassStm(pStm,&clsid);
07933     if (FAILED(res))
07934     return res;
07935     res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
07936     if (FAILED(res))
07937     return res;
07938     res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
07939     if (FAILED(res)) {
07940     IUnknown_Release((IUnknown*)*ppvObj);
07941     return res;
07942     }
07943     res=IPersistStream_Load(xstm,pStm);
07944     IPersistStream_Release(xstm);
07945     /* FIXME: all refcounts ok at this point? I think they should be:
07946      *      pStm    : unchanged
07947      *      ppvObj  : 1
07948      *      xstm    : 0 (released)
07949      */
07950     return res;
07951 }
07952 
07953 /***********************************************************************
07954  *    OleSaveToStream (OLE32.@)
07955  *
07956  * This function saves an object with the IPersistStream interface on it
07957  * to the specified stream.
07958  */
07959 HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
07960 {
07961 
07962     CLSID clsid;
07963     HRESULT res;
07964 
07965     TRACE("(%p,%p)\n",pPStm,pStm);
07966 
07967     res=IPersistStream_GetClassID(pPStm,&clsid);
07968 
07969     if (SUCCEEDED(res)){
07970 
07971         res=WriteClassStm(pStm,&clsid);
07972 
07973         if (SUCCEEDED(res))
07974 
07975             res=IPersistStream_Save(pPStm,pStm,TRUE);
07976     }
07977 
07978     TRACE("Finished Save\n");
07979     return res;
07980 }
07981 
07982 /****************************************************************************
07983  * This method validate a STGM parameter that can contain the values below
07984  *
07985  * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
07986  * The stgm values contained in 0xffff0000 are bitmasks.
07987  *
07988  * STGM_DIRECT               0x00000000
07989  * STGM_TRANSACTED           0x00010000
07990  * STGM_SIMPLE               0x08000000
07991  *
07992  * STGM_READ                 0x00000000
07993  * STGM_WRITE                0x00000001
07994  * STGM_READWRITE            0x00000002
07995  *
07996  * STGM_SHARE_DENY_NONE      0x00000040
07997  * STGM_SHARE_DENY_READ      0x00000030
07998  * STGM_SHARE_DENY_WRITE     0x00000020
07999  * STGM_SHARE_EXCLUSIVE      0x00000010
08000  *
08001  * STGM_PRIORITY             0x00040000
08002  * STGM_DELETEONRELEASE      0x04000000
08003  *
08004  * STGM_CREATE               0x00001000
08005  * STGM_CONVERT              0x00020000
08006  * STGM_FAILIFTHERE          0x00000000
08007  *
08008  * STGM_NOSCRATCH            0x00100000
08009  * STGM_NOSNAPSHOT           0x00200000
08010  */
08011 static HRESULT validateSTGM(DWORD stgm)
08012 {
08013   DWORD access = STGM_ACCESS_MODE(stgm);
08014   DWORD share  = STGM_SHARE_MODE(stgm);
08015   DWORD create = STGM_CREATE_MODE(stgm);
08016 
08017   if (stgm&~STGM_KNOWN_FLAGS)
08018   {
08019     ERR("unknown flags %08x\n", stgm);
08020     return E_FAIL;
08021   }
08022 
08023   switch (access)
08024   {
08025   case STGM_READ:
08026   case STGM_WRITE:
08027   case STGM_READWRITE:
08028     break;
08029   default:
08030     return E_FAIL;
08031   }
08032 
08033   switch (share)
08034   {
08035   case STGM_SHARE_DENY_NONE:
08036   case STGM_SHARE_DENY_READ:
08037   case STGM_SHARE_DENY_WRITE:
08038   case STGM_SHARE_EXCLUSIVE:
08039     break;
08040   default:
08041     return E_FAIL;
08042   }
08043 
08044   switch (create)
08045   {
08046   case STGM_CREATE:
08047   case STGM_FAILIFTHERE:
08048     break;
08049   default:
08050     return E_FAIL;
08051   }
08052 
08053   /*
08054    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
08055    */
08056   if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
08057       return E_FAIL;
08058 
08059   /*
08060    * STGM_CREATE | STGM_CONVERT
08061    * if both are false, STGM_FAILIFTHERE is set to TRUE
08062    */
08063   if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
08064     return E_FAIL;
08065 
08066   /*
08067    * STGM_NOSCRATCH requires STGM_TRANSACTED
08068    */
08069   if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
08070     return E_FAIL;
08071 
08072   /*
08073    * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
08074    * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
08075    */
08076   if ( (stgm & STGM_NOSNAPSHOT) &&
08077         (!(stgm & STGM_TRANSACTED) ||
08078          share == STGM_SHARE_EXCLUSIVE ||
08079          share == STGM_SHARE_DENY_WRITE) )
08080     return E_FAIL;
08081 
08082   return S_OK;
08083 }
08084 
08085 /****************************************************************************
08086  *      GetShareModeFromSTGM
08087  *
08088  * This method will return a share mode flag from a STGM value.
08089  * The STGM value is assumed valid.
08090  */
08091 static DWORD GetShareModeFromSTGM(DWORD stgm)
08092 {
08093   switch (STGM_SHARE_MODE(stgm))
08094   {
08095   case STGM_SHARE_DENY_NONE:
08096     return FILE_SHARE_READ | FILE_SHARE_WRITE;
08097   case STGM_SHARE_DENY_READ:
08098     return FILE_SHARE_WRITE;
08099   case STGM_SHARE_DENY_WRITE:
08100     return FILE_SHARE_READ;
08101   case STGM_SHARE_EXCLUSIVE:
08102     return 0;
08103   }
08104   ERR("Invalid share mode!\n");
08105   assert(0);
08106   return 0;
08107 }
08108 
08109 /****************************************************************************
08110  *      GetAccessModeFromSTGM
08111  *
08112  * This method will return an access mode flag from a STGM value.
08113  * The STGM value is assumed valid.
08114  */
08115 static DWORD GetAccessModeFromSTGM(DWORD stgm)
08116 {
08117   switch (STGM_ACCESS_MODE(stgm))
08118   {
08119   case STGM_READ:
08120     return GENERIC_READ;
08121   case STGM_WRITE:
08122   case STGM_READWRITE:
08123     return GENERIC_READ | GENERIC_WRITE;
08124   }
08125   ERR("Invalid access mode!\n");
08126   assert(0);
08127   return 0;
08128 }
08129 
08130 /****************************************************************************
08131  *      GetCreationModeFromSTGM
08132  *
08133  * This method will return a creation mode flag from a STGM value.
08134  * The STGM value is assumed valid.
08135  */
08136 static DWORD GetCreationModeFromSTGM(DWORD stgm)
08137 {
08138   switch(STGM_CREATE_MODE(stgm))
08139   {
08140   case STGM_CREATE:
08141     return CREATE_ALWAYS;
08142   case STGM_CONVERT:
08143     FIXME("STGM_CONVERT not implemented!\n");
08144     return CREATE_NEW;
08145   case STGM_FAILIFTHERE:
08146     return CREATE_NEW;
08147   }
08148   ERR("Invalid create mode!\n");
08149   assert(0);
08150   return 0;
08151 }
08152 
08153 
08154 /*************************************************************************
08155  * OLECONVERT_LoadOLE10 [Internal]
08156  *
08157  * Loads the OLE10 STREAM to memory
08158  *
08159  * PARAMS
08160  *     pOleStream   [I] The OLESTREAM
08161  *     pData        [I] Data Structure for the OLESTREAM Data
08162  *
08163  * RETURNS
08164  *     Success:  S_OK
08165  *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
08166  *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalid
08167  *
08168  * NOTES
08169  *     This function is used by OleConvertOLESTREAMToIStorage only.
08170  *
08171  *     Memory allocated for pData must be freed by the caller
08172  */
08173 static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
08174 {
08175     DWORD dwSize;
08176     HRESULT hRes = S_OK;
08177     int nTryCnt=0;
08178     int max_try = 6;
08179 
08180     pData->pData = NULL;
08181     pData->pstrOleObjFileName = NULL;
08182 
08183     for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
08184     {
08185     /* Get the OleID */
08186     dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
08187     if(dwSize != sizeof(pData->dwOleID))
08188     {
08189         hRes = CONVERT10_E_OLESTREAM_GET;
08190     }
08191     else if(pData->dwOleID != OLESTREAM_ID)
08192     {
08193         hRes = CONVERT10_E_OLESTREAM_FMT;
08194     }
08195         else
08196         {
08197             hRes = S_OK;
08198             break;
08199         }
08200     }
08201 
08202     if(hRes == S_OK)
08203     {
08204         /* Get the TypeID... more info needed for this field */
08205         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
08206         if(dwSize != sizeof(pData->dwTypeID))
08207         {
08208             hRes = CONVERT10_E_OLESTREAM_GET;
08209         }
08210     }
08211     if(hRes == S_OK)
08212     {
08213         if(pData->dwTypeID != 0)
08214         {
08215             /* Get the length of the OleTypeName */
08216             dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
08217             if(dwSize != sizeof(pData->dwOleTypeNameLength))
08218             {
08219                 hRes = CONVERT10_E_OLESTREAM_GET;
08220             }
08221 
08222             if(hRes == S_OK)
08223             {
08224                 if(pData->dwOleTypeNameLength > 0)
08225                 {
08226                     /* Get the OleTypeName */
08227                     dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
08228                     if(dwSize != pData->dwOleTypeNameLength)
08229                     {
08230                         hRes = CONVERT10_E_OLESTREAM_GET;
08231                     }
08232                 }
08233             }
08234             if(bStrem1)
08235             {
08236                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
08237                 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
08238                 {
08239                     hRes = CONVERT10_E_OLESTREAM_GET;
08240                 }
08241             if(hRes == S_OK)
08242             {
08243                     if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
08244                         pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
08245                     pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
08246                     if(pData->pstrOleObjFileName)
08247                     {
08248                         dwSize = pOleStream->lpstbl->Get(pOleStream, pData->pstrOleObjFileName, pData->dwOleObjFileNameLength);
08249                         if(dwSize != pData->dwOleObjFileNameLength)
08250                         {
08251                             hRes = CONVERT10_E_OLESTREAM_GET;
08252                         }
08253                     }
08254                     else
08255                         hRes = CONVERT10_E_OLESTREAM_GET;
08256                 }
08257             }
08258             else
08259             {
08260                 /* Get the Width of the Metafile */
08261                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
08262                 if(dwSize != sizeof(pData->dwMetaFileWidth))
08263                 {
08264                     hRes = CONVERT10_E_OLESTREAM_GET;
08265                 }
08266             if(hRes == S_OK)
08267             {
08268                 /* Get the Height of the Metafile */
08269                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
08270                 if(dwSize != sizeof(pData->dwMetaFileHeight))
08271                 {
08272                     hRes = CONVERT10_E_OLESTREAM_GET;
08273                 }
08274             }
08275             }
08276             if(hRes == S_OK)
08277             {
08278                 /* Get the Length of the Data */
08279                 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
08280                 if(dwSize != sizeof(pData->dwDataLength))
08281                 {
08282                     hRes = CONVERT10_E_OLESTREAM_GET;
08283                 }
08284             }
08285 
08286             if(hRes == S_OK) /* I don't know what this 8 byte information is. We have to figure out */
08287             {
08288                 if(!bStrem1) /* if it is a second OLE stream data */
08289                 {
08290                     pData->dwDataLength -= 8;
08291                     dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strUnknown, sizeof(pData->strUnknown));
08292                     if(dwSize != sizeof(pData->strUnknown))
08293                     {
08294                         hRes = CONVERT10_E_OLESTREAM_GET;
08295                     }
08296                 }
08297             }
08298             if(hRes == S_OK)
08299             {
08300                 if(pData->dwDataLength > 0)
08301                 {
08302                     pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
08303 
08304                     /* Get Data (ex. IStorage, Metafile, or BMP) */
08305                     if(pData->pData)
08306                     {
08307                         dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
08308                         if(dwSize != pData->dwDataLength)
08309                         {
08310                             hRes = CONVERT10_E_OLESTREAM_GET;
08311                         }
08312                     }
08313                     else
08314                     {
08315                         hRes = CONVERT10_E_OLESTREAM_GET;
08316                     }
08317                 }
08318             }
08319         }
08320     }
08321     return hRes;
08322 }
08323 
08324 /*************************************************************************
08325  * OLECONVERT_SaveOLE10 [Internal]
08326  *
08327  * Saves the OLE10 STREAM From memory
08328  *
08329  * PARAMS
08330  *     pData        [I] Data Structure for the OLESTREAM Data
08331  *     pOleStream   [I] The OLESTREAM to save
08332  *
08333  * RETURNS
08334  *     Success:  S_OK
08335  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
08336  *
08337  * NOTES
08338  *     This function is used by OleConvertIStorageToOLESTREAM only.
08339  *
08340  */
08341 static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
08342 {
08343     DWORD dwSize;
08344     HRESULT hRes = S_OK;
08345 
08346 
08347    /* Set the OleID */
08348     dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
08349     if(dwSize != sizeof(pData->dwOleID))
08350     {
08351         hRes = CONVERT10_E_OLESTREAM_PUT;
08352     }
08353 
08354     if(hRes == S_OK)
08355     {
08356         /* Set the TypeID */
08357         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
08358         if(dwSize != sizeof(pData->dwTypeID))
08359         {
08360             hRes = CONVERT10_E_OLESTREAM_PUT;
08361         }
08362     }
08363 
08364     if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
08365     {
08366         /* Set the Length of the OleTypeName */
08367         dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
08368         if(dwSize != sizeof(pData->dwOleTypeNameLength))
08369         {
08370             hRes = CONVERT10_E_OLESTREAM_PUT;
08371         }
08372 
08373         if(hRes == S_OK)
08374         {
08375             if(pData->dwOleTypeNameLength > 0)
08376             {
08377                 /* Set the OleTypeName */
08378                 dwSize = pOleStream->lpstbl->Put(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
08379                 if(dwSize != pData->dwOleTypeNameLength)
08380                 {
08381                     hRes = CONVERT10_E_OLESTREAM_PUT;
08382                 }
08383             }
08384         }
08385 
08386         if(hRes == S_OK)
08387         {
08388             /* Set the width of the Metafile */
08389             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
08390             if(dwSize != sizeof(pData->dwMetaFileWidth))
08391             {
08392                 hRes = CONVERT10_E_OLESTREAM_PUT;
08393             }
08394         }
08395 
08396         if(hRes == S_OK)
08397         {
08398             /* Set the height of the Metafile */
08399             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
08400             if(dwSize != sizeof(pData->dwMetaFileHeight))
08401             {
08402                 hRes = CONVERT10_E_OLESTREAM_PUT;
08403             }
08404         }
08405 
08406         if(hRes == S_OK)
08407         {
08408             /* Set the length of the Data */
08409             dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
08410             if(dwSize != sizeof(pData->dwDataLength))
08411             {
08412                 hRes = CONVERT10_E_OLESTREAM_PUT;
08413             }
08414         }
08415 
08416         if(hRes == S_OK)
08417         {
08418             if(pData->dwDataLength > 0)
08419             {
08420                 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
08421                 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
08422                 if(dwSize != pData->dwDataLength)
08423                 {
08424                     hRes = CONVERT10_E_OLESTREAM_PUT;
08425                 }
08426             }
08427         }
08428     }
08429     return hRes;
08430 }
08431 
08432 /*************************************************************************
08433  * OLECONVERT_GetOLE20FromOLE10[Internal]
08434  *
08435  * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
08436  * opens it, and copies the content to the dest IStorage for
08437  * OleConvertOLESTREAMToIStorage
08438  *
08439  *
08440  * PARAMS
08441  *     pDestStorage  [I] The IStorage to copy the data to
08442  *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
08443  *     nBufferLength [I] The size of the buffer
08444  *
08445  * RETURNS
08446  *     Nothing
08447  *
08448  * NOTES
08449  *
08450  *
08451  */
08452 static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
08453 {
08454     HRESULT hRes;
08455     HANDLE hFile;
08456     IStorage *pTempStorage;
08457     DWORD dwNumOfBytesWritten;
08458     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
08459     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
08460 
08461     /* Create a temp File */
08462     GetTempPathW(MAX_PATH, wstrTempDir);
08463     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
08464     hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
08465 
08466     if(hFile != INVALID_HANDLE_VALUE)
08467     {
08468         /* Write IStorage Data to File */
08469         WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
08470         CloseHandle(hFile);
08471 
08472         /* Open and copy temp storage to the Dest Storage */
08473         hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
08474         if(hRes == S_OK)
08475         {
08476             hRes = IStorage_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
08477             IStorage_Release(pTempStorage);
08478         }
08479         DeleteFileW(wstrTempFile);
08480     }
08481 }
08482 
08483 
08484 /*************************************************************************
08485  * OLECONVERT_WriteOLE20ToBuffer [Internal]
08486  *
08487  * Saves the OLE10 STREAM From memory
08488  *
08489  * PARAMS
08490  *     pStorage  [I] The Src IStorage to copy
08491  *     pData     [I] The Dest Memory to write to.
08492  *
08493  * RETURNS
08494  *     The size in bytes allocated for pData
08495  *
08496  * NOTES
08497  *     Memory allocated for pData must be freed by the caller
08498  *
08499  *     Used by OleConvertIStorageToOLESTREAM only.
08500  *
08501  */
08502 static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
08503 {
08504     HANDLE hFile;
08505     HRESULT hRes;
08506     DWORD nDataLength = 0;
08507     IStorage *pTempStorage;
08508     WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
08509     static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
08510 
08511     *pData = NULL;
08512 
08513     /* Create temp Storage */
08514     GetTempPathW(MAX_PATH, wstrTempDir);
08515     GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
08516     hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
08517 
08518     if(hRes == S_OK)
08519     {
08520         /* Copy Src Storage to the Temp Storage */
08521         IStorage_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
08522         IStorage_Release(pTempStorage);
08523 
08524         /* Open Temp Storage as a file and copy to memory */
08525         hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
08526         if(hFile != INVALID_HANDLE_VALUE)
08527         {
08528             nDataLength = GetFileSize(hFile, NULL);
08529             *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
08530             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
08531             CloseHandle(hFile);
08532         }
08533         DeleteFileW(wstrTempFile);
08534     }
08535     return nDataLength;
08536 }
08537 
08538 /*************************************************************************
08539  * OLECONVERT_CreateOleStream [Internal]
08540  *
08541  * Creates the "\001OLE" stream in the IStorage if necessary.
08542  *
08543  * PARAMS
08544  *     pStorage     [I] Dest storage to create the stream in
08545  *
08546  * RETURNS
08547  *     Nothing
08548  *
08549  * NOTES
08550  *     This function is used by OleConvertOLESTREAMToIStorage only.
08551  *
08552  *     This stream is still unknown, MS Word seems to have extra data
08553  *     but since the data is stored in the OLESTREAM there should be
08554  *     no need to recreate the stream.  If the stream is manually
08555  *     deleted it will create it with this default data.
08556  *
08557  */
08558 void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
08559 {
08560     HRESULT hRes;
08561     IStream *pStream;
08562     static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
08563     BYTE pOleStreamHeader [] =
08564     {
08565         0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
08566         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
08567         0x00, 0x00, 0x00, 0x00
08568     };
08569 
08570     /* Create stream if not present */
08571     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
08572         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
08573 
08574     if(hRes == S_OK)
08575     {
08576         /* Write default Data */
08577         hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
08578         IStream_Release(pStream);
08579     }
08580 }
08581 
08582 /* write a string to a stream, preceded by its length */
08583 static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
08584 {
08585     HRESULT r;
08586     LPSTR str;
08587     DWORD len = 0;
08588 
08589     if( string )
08590         len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
08591     r = IStream_Write( stm, &len, sizeof(len), NULL);
08592     if( FAILED( r ) )
08593         return r;
08594     if(len == 0)
08595         return r;
08596     str = CoTaskMemAlloc( len );
08597     WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
08598     r = IStream_Write( stm, str, len, NULL);
08599     CoTaskMemFree( str );
08600     return r;
08601 }
08602 
08603 /* read a string preceded by its length from a stream */
08604 static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
08605 {
08606     HRESULT r;
08607     DWORD len, count = 0;
08608     LPSTR str;
08609     LPWSTR wstr;
08610 
08611     r = IStream_Read( stm, &len, sizeof(len), &count );
08612     if( FAILED( r ) )
08613         return r;
08614     if( count != sizeof(len) )
08615         return E_OUTOFMEMORY;
08616 
08617     TRACE("%d bytes\n",len);
08618     
08619     str = CoTaskMemAlloc( len );
08620     if( !str )
08621         return E_OUTOFMEMORY;
08622     count = 0;
08623     r = IStream_Read( stm, str, len, &count );
08624     if( FAILED( r ) )
08625         return r;
08626     if( count != len )
08627     {
08628         CoTaskMemFree( str );
08629         return E_OUTOFMEMORY;
08630     }
08631 
08632     TRACE("Read string %s\n",debugstr_an(str,len));
08633 
08634     len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
08635     wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
08636     if( wstr )
08637          MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
08638     CoTaskMemFree( str );
08639 
08640     *string = wstr;
08641 
08642     return r;
08643 }
08644 
08645 
08646 static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
08647     LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
08648 {
08649     IStream *pstm;
08650     HRESULT r = S_OK;
08651     static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
08652 
08653     static const BYTE unknown1[12] =
08654        { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
08655          0xFF, 0xFF, 0xFF, 0xFF};
08656     static const BYTE unknown2[16] =
08657        { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
08658          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
08659 
08660     TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
08661            debugstr_w(lpszUserType), debugstr_w(szClipName),
08662            debugstr_w(szProgIDName));
08663 
08664     /*  Create a CompObj stream */
08665     r = IStorage_CreateStream(pstg, szwStreamName,
08666         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
08667     if( FAILED (r) )
08668         return r;
08669 
08670     /* Write CompObj Structure to stream */
08671     r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
08672 
08673     if( SUCCEEDED( r ) )
08674         r = WriteClassStm( pstm, clsid );
08675 
08676     if( SUCCEEDED( r ) )
08677         r = STREAM_WriteString( pstm, lpszUserType );
08678     if( SUCCEEDED( r ) )
08679         r = STREAM_WriteString( pstm, szClipName );
08680     if( SUCCEEDED( r ) )
08681         r = STREAM_WriteString( pstm, szProgIDName );
08682     if( SUCCEEDED( r ) )
08683         r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
08684 
08685     IStream_Release( pstm );
08686 
08687     return r;
08688 }
08689 
08690 /***********************************************************************
08691  *               WriteFmtUserTypeStg (OLE32.@)
08692  */
08693 HRESULT WINAPI WriteFmtUserTypeStg(
08694       LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
08695 {
08696     HRESULT r;
08697     WCHAR szwClipName[0x40];
08698     CLSID clsid = CLSID_NULL;
08699     LPWSTR wstrProgID = NULL;
08700     DWORD n;
08701 
08702     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
08703 
08704     /* get the clipboard format name */
08705     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName)/sizeof(szwClipName[0]) );
08706     szwClipName[n]=0;
08707 
08708     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
08709 
08710     /* FIXME: There's room to save a CLSID and its ProgID, but
08711        the CLSID is not looked up in the registry and in all the
08712        tests I wrote it was CLSID_NULL.  Where does it come from?
08713     */
08714 
08715     /* get the real program ID.  This may fail, but that's fine */
08716     ProgIDFromCLSID(&clsid, &wstrProgID);
08717 
08718     TRACE("progid is %s\n",debugstr_w(wstrProgID));
08719 
08720     r = STORAGE_WriteCompObj( pstg, &clsid, 
08721                               lpszUserType, szwClipName, wstrProgID );
08722 
08723     CoTaskMemFree(wstrProgID);
08724 
08725     return r;
08726 }
08727 
08728 
08729 /******************************************************************************
08730  *              ReadFmtUserTypeStg        [OLE32.@]
08731  */
08732 HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
08733 {
08734     HRESULT r;
08735     IStream *stm = 0;
08736     static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
08737     unsigned char unknown1[12];
08738     unsigned char unknown2[16];
08739     DWORD count;
08740     LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
08741     CLSID clsid;
08742 
08743     TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
08744 
08745     r = IStorage_OpenStream( pstg, szCompObj, NULL, 
08746                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
08747     if( FAILED ( r ) )
08748     {
08749         WARN("Failed to open stream r = %08x\n", r);
08750         return r;
08751     }
08752 
08753     /* read the various parts of the structure */
08754     r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
08755     if( FAILED( r ) || ( count != sizeof(unknown1) ) )
08756         goto end;
08757     r = ReadClassStm( stm, &clsid );
08758     if( FAILED( r ) )
08759         goto end;
08760 
08761     r = STREAM_ReadString( stm, &szCLSIDName );
08762     if( FAILED( r ) )
08763         goto end;
08764 
08765     r = STREAM_ReadString( stm, &szOleTypeName );
08766     if( FAILED( r ) )
08767         goto end;
08768 
08769     r = STREAM_ReadString( stm, &szProgIDName );
08770     if( FAILED( r ) )
08771         goto end;
08772 
08773     r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
08774     if( FAILED( r ) || ( count != sizeof(unknown2) ) )
08775         goto end;
08776 
08777     /* ok, success... now we just need to store what we found */
08778     if( pcf )
08779         *pcf = RegisterClipboardFormatW( szOleTypeName );
08780     CoTaskMemFree( szOleTypeName );
08781 
08782     if( lplpszUserType )
08783         *lplpszUserType = szCLSIDName;
08784     CoTaskMemFree( szProgIDName );
08785 
08786 end:
08787     IStream_Release( stm );
08788 
08789     return r;
08790 }
08791 
08792 
08793 /*************************************************************************
08794  * OLECONVERT_CreateCompObjStream [Internal]
08795  *
08796  * Creates a "\001CompObj" is the destination IStorage if necessary.
08797  *
08798  * PARAMS
08799  *     pStorage       [I] The dest IStorage to create the CompObj Stream
08800  *                        if necessary.
08801  *     strOleTypeName [I] The ProgID
08802  *
08803  * RETURNS
08804  *     Success:  S_OK
08805  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
08806  *
08807  * NOTES
08808  *     This function is used by OleConvertOLESTREAMToIStorage only.
08809  *
08810  *     The stream data is stored in the OLESTREAM and there should be
08811  *     no need to recreate the stream.  If the stream is manually
08812  *     deleted it will attempt to create it by querying the registry.
08813  *
08814  *
08815  */
08816 HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
08817 {
08818     IStream *pStream;
08819     HRESULT hStorageRes, hRes = S_OK;
08820     OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
08821     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
08822     WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
08823 
08824     BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
08825     BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
08826 
08827     /* Initialize the CompObj structure */
08828     memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
08829     memcpy(IStorageCompObj.byUnknown1, pCompObjUnknown1, sizeof(pCompObjUnknown1));
08830     memcpy(IStorageCompObj.byUnknown2, pCompObjUnknown2, sizeof(pCompObjUnknown2));
08831 
08832 
08833     /*  Create a CompObj stream if it doesn't exist */
08834     hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
08835         STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
08836     if(hStorageRes == S_OK)
08837     {
08838         /* copy the OleTypeName to the compobj struct */
08839         IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
08840         strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
08841 
08842         /* copy the OleTypeName to the compobj struct */
08843         /* Note: in the test made, these were Identical      */
08844         IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
08845         strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
08846 
08847         /* Get the CLSID */
08848         MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
08849                              bufferW, OLESTREAM_MAX_STR_LEN );
08850         hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
08851 
08852         if(hRes == S_OK)
08853         {
08854             HKEY hKey;
08855             LONG hErr;
08856             /* Get the CLSID Default Name from the Registry */
08857             hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
08858             if(hErr == ERROR_SUCCESS)
08859             {
08860                 char strTemp[OLESTREAM_MAX_STR_LEN];
08861                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
08862                 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
08863                 if(hErr == ERROR_SUCCESS)
08864                 {
08865                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
08866                 }
08867                 RegCloseKey(hKey);
08868             }
08869         }
08870 
08871         /* Write CompObj Structure to stream */
08872         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
08873 
08874         WriteClassStm(pStream,&(IStorageCompObj.clsid));
08875 
08876         hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
08877         if(IStorageCompObj.dwCLSIDNameLength > 0)
08878         {
08879             hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
08880         }
08881         hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
08882         if(IStorageCompObj.dwOleTypeNameLength > 0)
08883         {
08884             hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
08885         }
08886         hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
08887         if(IStorageCompObj.dwProgIDNameLength > 0)
08888         {
08889             hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
08890         }
08891         hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
08892         IStream_Release(pStream);
08893     }
08894     return hRes;
08895 }
08896 
08897 
08898 /*************************************************************************
08899  * OLECONVERT_CreateOlePresStream[Internal]
08900  *
08901  * Creates the "\002OlePres000" Stream with the Metafile data
08902  *
08903  * PARAMS
08904  *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
08905  *     dwExtentX    [I] Width of the Metafile
08906  *     dwExtentY    [I] Height of the Metafile
08907  *     pData        [I] Metafile data
08908  *     dwDataLength [I] Size of the Metafile data
08909  *
08910  * RETURNS
08911  *     Success:  S_OK
08912  *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
08913  *
08914  * NOTES
08915  *     This function is used by OleConvertOLESTREAMToIStorage only.
08916  *
08917  */
08918 static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
08919 {
08920     HRESULT hRes;
08921     IStream *pStream;
08922     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
08923     BYTE pOlePresStreamHeader [] =
08924     {
08925         0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
08926         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
08927         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
08928         0x00, 0x00, 0x00, 0x00
08929     };
08930 
08931     BYTE pOlePresStreamHeaderEmpty [] =
08932     {
08933         0x00, 0x00, 0x00, 0x00,
08934         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
08935         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
08936         0x00, 0x00, 0x00, 0x00
08937     };
08938 
08939     /* Create the OlePres000 Stream */
08940     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
08941         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
08942 
08943     if(hRes == S_OK)
08944     {
08945         DWORD nHeaderSize;
08946         OLECONVERT_ISTORAGE_OLEPRES OlePres;
08947 
08948         memset(&OlePres, 0, sizeof(OlePres));
08949         /* Do we have any metafile data to save */
08950         if(dwDataLength > 0)
08951         {
08952             memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
08953             nHeaderSize = sizeof(pOlePresStreamHeader);
08954         }
08955         else
08956         {
08957             memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
08958             nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
08959         }
08960         /* Set width and height of the metafile */
08961         OlePres.dwExtentX = dwExtentX;
08962         OlePres.dwExtentY = -dwExtentY;
08963 
08964         /* Set Data and Length */
08965         if(dwDataLength > sizeof(METAFILEPICT16))
08966         {
08967             OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
08968             OlePres.pData = &(pData[8]);
08969         }
08970         /* Save OlePres000 Data to Stream */
08971         hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
08972         hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
08973         hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
08974         hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
08975         if(OlePres.dwSize > 0)
08976         {
08977             hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
08978         }
08979         IStream_Release(pStream);
08980     }
08981 }
08982 
08983 /*************************************************************************
08984  * OLECONVERT_CreateOle10NativeStream [Internal]
08985  *
08986  * Creates the "\001Ole10Native" Stream (should contain a BMP)
08987  *
08988  * PARAMS
08989  *     pStorage     [I] Dest storage to create the stream in
08990  *     pData        [I] Ole10 Native Data (ex. bmp)
08991  *     dwDataLength [I] Size of the Ole10 Native Data
08992  *
08993  * RETURNS
08994  *     Nothing
08995  *
08996  * NOTES
08997  *     This function is used by OleConvertOLESTREAMToIStorage only.
08998  *
08999  *     Might need to verify the data and return appropriate error message
09000  *
09001  */
09002 static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
09003 {
09004     HRESULT hRes;
09005     IStream *pStream;
09006     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
09007 
09008     /* Create the Ole10Native Stream */
09009     hRes = IStorage_CreateStream(pStorage, wstrStreamName,
09010         STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
09011 
09012     if(hRes == S_OK)
09013     {
09014         /* Write info to stream */
09015         hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
09016         hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
09017         IStream_Release(pStream);
09018     }
09019 
09020 }
09021 
09022 /*************************************************************************
09023  * OLECONVERT_GetOLE10ProgID [Internal]
09024  *
09025  * Finds the ProgID (or OleTypeID) from the IStorage
09026  *
09027  * PARAMS
09028  *     pStorage        [I] The Src IStorage to get the ProgID
09029  *     strProgID       [I] the ProgID string to get
09030  *     dwSize          [I] the size of the string
09031  *
09032  * RETURNS
09033  *     Success:  S_OK
09034  *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
09035  *
09036  * NOTES
09037  *     This function is used by OleConvertIStorageToOLESTREAM only.
09038  *
09039  *
09040  */
09041 static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
09042 {
09043     HRESULT hRes;
09044     IStream *pStream;
09045     LARGE_INTEGER iSeekPos;
09046     OLECONVERT_ISTORAGE_COMPOBJ CompObj;
09047     static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
09048 
09049     /* Open the CompObj Stream */
09050     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
09051         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
09052     if(hRes == S_OK)
09053     {
09054 
09055         /*Get the OleType from the CompObj Stream */
09056         iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
09057         iSeekPos.u.HighPart = 0;
09058 
09059         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
09060         IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
09061         iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
09062         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
09063         IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
09064         iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
09065         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
09066 
09067         IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
09068         if(*dwSize > 0)
09069         {
09070             IStream_Read(pStream, strProgID, *dwSize, NULL);
09071         }
09072         IStream_Release(pStream);
09073     }
09074     else
09075     {
09076         STATSTG stat;
09077         LPOLESTR wstrProgID;
09078 
09079         /* Get the OleType from the registry */
09080         REFCLSID clsid = &(stat.clsid);
09081         IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
09082         hRes = ProgIDFromCLSID(clsid, &wstrProgID);
09083         if(hRes == S_OK)
09084         {
09085             *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
09086         }
09087 
09088     }
09089     return hRes;
09090 }
09091 
09092 /*************************************************************************
09093  * OLECONVERT_GetOle10PresData [Internal]
09094  *
09095  * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
09096  *
09097  * PARAMS
09098  *     pStorage     [I] Src IStroage
09099  *     pOleStream   [I] Dest OleStream Mem Struct
09100  *
09101  * RETURNS
09102  *     Nothing
09103  *
09104  * NOTES
09105  *     This function is used by OleConvertIStorageToOLESTREAM only.
09106  *
09107  *     Memory allocated for pData must be freed by the caller
09108  *
09109  *
09110  */
09111 static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
09112 {
09113 
09114     HRESULT hRes;
09115     IStream *pStream;
09116     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
09117 
09118     /* Initialize Default data for OLESTREAM */
09119     pOleStreamData[0].dwOleID = OLESTREAM_ID;
09120     pOleStreamData[0].dwTypeID = 2;
09121     pOleStreamData[1].dwOleID = OLESTREAM_ID;
09122     pOleStreamData[1].dwTypeID = 0;
09123     pOleStreamData[0].dwMetaFileWidth = 0;
09124     pOleStreamData[0].dwMetaFileHeight = 0;
09125     pOleStreamData[0].pData = NULL;
09126     pOleStreamData[1].pData = NULL;
09127 
09128     /* Open Ole10Native Stream */
09129     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
09130         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
09131     if(hRes == S_OK)
09132     {
09133 
09134         /* Read Size and Data */
09135         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
09136         if(pOleStreamData->dwDataLength > 0)
09137         {
09138             pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
09139             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
09140         }
09141         IStream_Release(pStream);
09142     }
09143 
09144 }
09145 
09146 
09147 /*************************************************************************
09148  * OLECONVERT_GetOle20PresData[Internal]
09149  *
09150  * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
09151  *
09152  * PARAMS
09153  *     pStorage         [I] Src IStroage
09154  *     pOleStreamData   [I] Dest OleStream Mem Struct
09155  *
09156  * RETURNS
09157  *     Nothing
09158  *
09159  * NOTES
09160  *     This function is used by OleConvertIStorageToOLESTREAM only.
09161  *
09162  *     Memory allocated for pData must be freed by the caller
09163  */
09164 static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
09165 {
09166     HRESULT hRes;
09167     IStream *pStream;
09168     OLECONVERT_ISTORAGE_OLEPRES olePress;
09169     static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
09170 
09171     /* Initialize Default data for OLESTREAM */
09172     pOleStreamData[0].dwOleID = OLESTREAM_ID;
09173     pOleStreamData[0].dwTypeID = 2;
09174     pOleStreamData[0].dwMetaFileWidth = 0;
09175     pOleStreamData[0].dwMetaFileHeight = 0;
09176     pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
09177     pOleStreamData[1].dwOleID = OLESTREAM_ID;
09178     pOleStreamData[1].dwTypeID = 0;
09179     pOleStreamData[1].dwOleTypeNameLength = 0;
09180     pOleStreamData[1].strOleTypeName[0] = 0;
09181     pOleStreamData[1].dwMetaFileWidth = 0;
09182     pOleStreamData[1].dwMetaFileHeight = 0;
09183     pOleStreamData[1].pData = NULL;
09184     pOleStreamData[1].dwDataLength = 0;
09185 
09186 
09187     /* Open OlePress000 stream */
09188     hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
09189         STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
09190     if(hRes == S_OK)
09191     {
09192         LARGE_INTEGER iSeekPos;
09193         METAFILEPICT16 MetaFilePict;
09194         static const char strMetafilePictName[] = "METAFILEPICT";
09195 
09196         /* Set the TypeID for a Metafile */
09197         pOleStreamData[1].dwTypeID = 5;
09198 
09199         /* Set the OleTypeName to Metafile */
09200         pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
09201         strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
09202 
09203         iSeekPos.u.HighPart = 0;
09204         iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
09205 
09206         /* Get Presentation Data */
09207         IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
09208         IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
09209         IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
09210         IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
09211 
09212         /*Set width and Height */
09213         pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
09214         pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
09215         if(olePress.dwSize > 0)
09216         {
09217             /* Set Length */
09218             pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
09219 
09220             /* Set MetaFilePict struct */
09221             MetaFilePict.mm = 8;
09222             MetaFilePict.xExt = olePress.dwExtentX;
09223             MetaFilePict.yExt = olePress.dwExtentY;
09224             MetaFilePict.hMF = 0;
09225 
09226             /* Get Metafile Data */
09227             pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
09228             memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
09229             IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
09230         }
09231         IStream_Release(pStream);
09232     }
09233 }
09234 
09235 /*************************************************************************
09236  * OleConvertOLESTREAMToIStorage [OLE32.@]
09237  *
09238  * Read info on MSDN
09239  *
09240  * TODO
09241  *      DVTARGETDEVICE parameter is not handled
09242  *      Still unsure of some mem fields for OLE 10 Stream
09243  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
09244  *      and "\001OLE" streams
09245  *
09246  */
09247 HRESULT WINAPI OleConvertOLESTREAMToIStorage (
09248     LPOLESTREAM pOleStream,
09249     LPSTORAGE pstg,
09250     const DVTARGETDEVICE* ptd)
09251 {
09252     int i;
09253     HRESULT hRes=S_OK;
09254     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
09255 
09256     TRACE("%p %p %p\n", pOleStream, pstg, ptd);
09257 
09258     memset(pOleStreamData, 0, sizeof(pOleStreamData));
09259 
09260     if(ptd != NULL)
09261     {
09262         FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
09263     }
09264 
09265     if(pstg == NULL || pOleStream == NULL)
09266     {
09267         hRes = E_INVALIDARG;
09268     }
09269 
09270     if(hRes == S_OK)
09271     {
09272         /* Load the OLESTREAM to Memory */
09273         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
09274     }
09275 
09276     if(hRes == S_OK)
09277     {
09278         /* Load the OLESTREAM to Memory (part 2)*/
09279         hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
09280     }
09281 
09282     if(hRes == S_OK)
09283     {
09284 
09285         if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
09286         {
09287             /* Do we have the IStorage Data in the OLESTREAM */
09288             if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
09289             {
09290                 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
09291                 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
09292             }
09293             else
09294             {
09295                 /* It must be an original OLE 1.0 source */
09296                 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
09297             }
09298         }
09299         else
09300         {
09301             /* It must be an original OLE 1.0 source */
09302             OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
09303         }
09304 
09305         /* Create CompObj Stream if necessary */
09306         hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
09307         if(hRes == S_OK)
09308         {
09309             /*Create the Ole Stream if necessary */
09310             OLECONVERT_CreateOleStream(pstg);
09311         }
09312     }
09313 
09314 
09315     /* Free allocated memory */
09316     for(i=0; i < 2; i++)
09317     {
09318         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
09319         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
09320         pOleStreamData[i].pstrOleObjFileName = NULL;
09321     }
09322     return hRes;
09323 }
09324 
09325 /*************************************************************************
09326  * OleConvertIStorageToOLESTREAM [OLE32.@]
09327  *
09328  * Read info on MSDN
09329  *
09330  * Read info on MSDN
09331  *
09332  * TODO
09333  *      Still unsure of some mem fields for OLE 10 Stream
09334  *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
09335  *      and "\001OLE" streams.
09336  *
09337  */
09338 HRESULT WINAPI OleConvertIStorageToOLESTREAM (
09339     LPSTORAGE pstg,
09340     LPOLESTREAM pOleStream)
09341 {
09342     int i;
09343     HRESULT hRes = S_OK;
09344     IStream *pStream;
09345     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
09346     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
09347 
09348     TRACE("%p %p\n", pstg, pOleStream);
09349 
09350     memset(pOleStreamData, 0, sizeof(pOleStreamData));
09351 
09352     if(pstg == NULL || pOleStream == NULL)
09353     {
09354         hRes = E_INVALIDARG;
09355     }
09356     if(hRes == S_OK)
09357     {
09358         /* Get the ProgID */
09359         pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
09360         hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
09361     }
09362     if(hRes == S_OK)
09363     {
09364         /* Was it originally Ole10 */
09365         hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
09366         if(hRes == S_OK)
09367         {
09368             IStream_Release(pStream);
09369             /* Get Presentation Data for Ole10Native */
09370             OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
09371         }
09372         else
09373         {
09374             /* Get Presentation Data (OLE20) */
09375             OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
09376         }
09377 
09378         /* Save OLESTREAM */
09379         hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
09380         if(hRes == S_OK)
09381         {
09382             hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
09383         }
09384 
09385     }
09386 
09387     /* Free allocated memory */
09388     for(i=0; i < 2; i++)
09389     {
09390         HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
09391     }
09392 
09393     return hRes;
09394 }
09395 
09396 /***********************************************************************
09397  *      GetConvertStg (OLE32.@)
09398  */
09399 HRESULT WINAPI GetConvertStg(IStorage *stg) {
09400     FIXME("unimplemented stub!\n");
09401     return E_FAIL;
09402 }
09403 
09404 /******************************************************************************
09405  * StgIsStorageFile [OLE32.@]
09406  * Verify if the file contains a storage object
09407  *
09408  * PARAMS
09409  *  fn      [ I] Filename
09410  *
09411  * RETURNS
09412  *  S_OK    if file has magic bytes as a storage object
09413  *  S_FALSE if file is not storage
09414  */
09415 HRESULT WINAPI
09416 StgIsStorageFile(LPCOLESTR fn)
09417 {
09418     HANDLE      hf;
09419     BYTE        magic[8];
09420     DWORD       bytes_read;
09421 
09422     TRACE("%s\n", debugstr_w(fn));
09423     hf = CreateFileW(fn, GENERIC_READ,
09424                      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
09425                      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
09426 
09427     if (hf == INVALID_HANDLE_VALUE)
09428         return STG_E_FILENOTFOUND;
09429 
09430     if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
09431     {
09432         WARN(" unable to read file\n");
09433         CloseHandle(hf);
09434         return S_FALSE;
09435     }
09436 
09437     CloseHandle(hf);
09438 
09439     if (bytes_read != 8) {
09440         TRACE(" too short\n");
09441         return S_FALSE;
09442     }
09443 
09444     if (!memcmp(magic,STORAGE_magic,8)) {
09445         TRACE(" -> YES\n");
09446         return S_OK;
09447     }
09448 
09449     TRACE(" -> Invalid header.\n");
09450     return S_FALSE;
09451 }
09452 
09453 /***********************************************************************
09454  *      WriteClassStm (OLE32.@)
09455  *
09456  * Writes a CLSID to a stream.
09457  *
09458  * PARAMS
09459  *  pStm   [I] Stream to write to.
09460  *  rclsid [I] CLSID to write.
09461  *
09462  * RETURNS
09463  *  Success: S_OK.
09464  *  Failure: HRESULT code.
09465  */
09466 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
09467 {
09468     TRACE("(%p,%p)\n",pStm,rclsid);
09469 
09470     if (!pStm || !rclsid)
09471         return E_INVALIDARG;
09472 
09473     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
09474 }
09475 
09476 /***********************************************************************
09477  *      ReadClassStm (OLE32.@)
09478  *
09479  * Reads a CLSID from a stream.
09480  *
09481  * PARAMS
09482  *  pStm   [I] Stream to read from.
09483  *  rclsid [O] CLSID to read.
09484  *
09485  * RETURNS
09486  *  Success: S_OK.
09487  *  Failure: HRESULT code.
09488  */
09489 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
09490 {
09491     ULONG nbByte;
09492     HRESULT res;
09493 
09494     TRACE("(%p,%p)\n",pStm,pclsid);
09495 
09496     if (!pStm || !pclsid)
09497         return E_INVALIDARG;
09498 
09499     /* clear the output args */
09500     *pclsid = CLSID_NULL;
09501 
09502     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
09503 
09504     if (FAILED(res))
09505         return res;
09506 
09507     if (nbByte != sizeof(CLSID))
09508         return STG_E_READFAULT;
09509     else
09510         return S_OK;
09511 }

Generated on Sat May 26 2012 04:24:14 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.