//  ----------------------------------------------------------------------------
//  MODULE    : OLEStorages.cpp
//  LANGUAGE  : C++
//  AUTHOR    : Yue Zhang
//  DATE    : Tuesday, Janurary 23, 1996
//  DESCRIPTION : This file defines an enhanced OLE storage object
//  COMMENT   : Enhanced OLE objects are platform independent
//      SCCSID        : @(#)olestorg.cpp  1.3 12:37:38 08 Jul 1997
//  ----------------------------------------------------------------------------
//  Copyright (c) 1999 Digital Imaging Group, Inc.
//  For conditions of distribution and use, see copyright notice
//  in Flashpix.h

  #include  <stdio.h>

#if defined(USE_LEGACY_INCLUDES)
#  include <iostream.h>
#  include <fstream.h>
#else
#  include <iostream>
#  include <fstream>
   using namespace std;
#endif

#ifndef OLECommun_h
  #include "olecomm.h"
#endif

#ifndef OLECore_h
  #include "olecore.h"
#endif

#ifndef OLEStorages_h
  #include  "olestorg.h"
#endif

#ifndef OLEEnumStatstg_h
  #include  "olestats.h"
#endif

#ifndef OLEFiles_h
  #include  "olefiles.h"
#endif
#ifndef OLEStreams_h
  #include  "olestrm.h"
#endif

#ifndef OLEPropertySet_h
  #include  "oleprops.h"
#endif

#ifndef OLECustomLink_h
  #include  "oleclink.h"
#endif

//  Constants
//  ---------

//  Variables
//  ---------

//  ----------------------------------------------------------------------------

//  ----------------------------------------------------------------------------

//  ----------------------------------------------------------------------------
//  Functions 'intern'
//  ----------------------------------------------------------------------------

//  ----------------------------------------------------------------------------
//  Methods of OLEStorage
//  ----------------------------------------------------------------------------


OLEStorage::OLEStorage(OLEStorage * parentStorage, IStorage * currentStorage)
{
  oleStorage = currentStorage;
  parStorage = parentStorage;
  parFile    = NULL;
  customLink = NULL;
  clsID    = BlankGUID;

  openOLEObjList = new List;
  if ( oleStorage )
    oleStorage->AddRef();
}


OLEStorage::OLEStorage(const CLSID& classID, OLEStorage * parentStorage, IStorage * currentStorage)
{
  oleStorage = currentStorage;
  parStorage = parentStorage;
  parFile    = NULL;
  customLink = NULL;
  clsID    = classID;
  if (oleStorage) {
    oleStorage->AddRef();
    oleStorage->SetClass(clsID);
  }

  openOLEObjList = new List;
}


OLEStorage::OLEStorage(OLEStorage * parentStorage, IStorage * currentStorage, List *theOpenOLEObjList)
{
  oleStorage = currentStorage;
  parStorage = parentStorage;
  parFile    = NULL;
  customLink = NULL;
  clsID    = BlankGUID;

  openOLEObjList = theOpenOLEObjList;
  if ( openOLEObjList )
    openOLEObjList->AddRef();
  else
    openOLEObjList = new List;

  if ( oleStorage )
    oleStorage->AddRef();
}

OLEStorage::OLEStorage(OLEStorage * parentStorage, IStorage * currentStorage, OLECustomLink * theCustomLink)
{
  oleStorage = currentStorage;
  parStorage = parentStorage;
  parFile    = NULL;
  customLink = theCustomLink;
  clsID    = BlankGUID;

  openOLEObjList = new List;
  if ( oleStorage )
    oleStorage->AddRef();
}

OLEStorage::OLEStorage(OLEFile  * parentFile, IStorage * currentStorage)
{
  oleStorage = currentStorage;
  parStorage = NULL;
  parFile    = parentFile;
  customLink = NULL;
  clsID    = BlankGUID;

  openOLEObjList = new List;
  if ( oleStorage )
    oleStorage->AddRef();
}


OLEStorage::OLEStorage(OLEFile  * parentFile, IStorage * currentStorage, List * theOpenOLEObjList)
{
  oleStorage = currentStorage;
  parStorage = NULL;
  parFile    = parentFile;
  customLink = NULL;
  clsID    = BlankGUID;

  openOLEObjList = theOpenOLEObjList;
  if ( openOLEObjList )
    openOLEObjList->AddRef();
  else
    openOLEObjList = new List;

  if ( oleStorage )
    oleStorage->AddRef();
}


OLEStorage::OLEStorage(const CLSID& classID, OLEFile  * parentFile, IStorage * currentStorage)
{
  oleStorage = currentStorage;
  parStorage = NULL;
  parFile    = parentFile;
  customLink = NULL;
  clsID    = classID;
  if (oleStorage)
    oleStorage->SetClass(clsID);

  openOLEObjList = new List;
  if ( oleStorage )
    oleStorage->AddRef();
}


OLEStorage::~OLEStorage()
{
  Release();
}


// Check if it is referenced by others
int OLEStorage::IsReferenced ()
{
  int count;
  if (openOLEObjList == NULL || (count = openOLEObjList->GetUserCount()) <= 1)
    return 0;
  else
    return count;
}


void OLEStorage::GetFileName (FicNom* fileName)
{
  if (parStorage)
    parStorage->GetFileName(fileName);
  else
    parFile->GetFileName(fileName);
}


// Add reference to the IStorage object contained in the OLEStorage
void OLEStorage::AddRef()
{
  OLECore::AddRef();

  if (oleStorage)
    oleStorage->AddRef();

  if (openOLEObjList)
    openOLEObjList->AddRef();
}


// Release the IStorage object contained in the OLEStorage
void OLEStorage::Release()
{
  if (customLink) {
    delete customLink;
    customLink = NULL;
  }
  else if (oleStorage)
    oleStorage->Release();

  OLECore::Release();
  if (openOLEObjList->GetUserCount() <= 1)
     delete openOLEObjList; /* we created it */
  else
     openOLEObjList->Release();
}


// Open a stream within current storage
Boolean OLEStorage::OpenStream(const char * name, OLEStream ** currentStream, DWORD mode)
{
  HRESULT err = NOERROR;
  if (oleStorage) {

    LPSTREAM ppStm;

    if ( !openOLEObjList )
      return FALSE;

    // Search the opened object list, if the object already open just add its reference
    if ( (ppStm = (IStream *)openOLEObjList->Search((char *)name)) == NULL ) {

      err = oleStorage->OpenStream(OLE_STR(name), 0, mode, 0, &ppStm);
#ifdef macintosh
  #ifndef powerc
      if( (ppStm == NULL) && (mode == OLE_READWRITE_MODE))
  #else
      if (FAILED(err) && (mode == OLE_READWRITE_MODE))
  #endif
#else
      if (FAILED(err) && (mode == OLE_READWRITE_MODE))
#endif
        // Try to open at least in read mode if the read/write failed
        err = oleStorage->OpenStream(OLE_STR(name), 0, OLE_READ_ONLY_MODE, 0, &ppStm);

      if ( !FAILED(err) )
        // Add stream to the list
        openOLEObjList->Add(ppStm, name);
    }

    if (FAILED(err)) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      // Create an OLEStream
      if ( (*currentStream = new OLEStream(this, ppStm)) != NULL )
        return true;
      else {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  }
  else
    return false;
}


// Create a stream within current storage
Boolean OLEStorage::CreateStream(const char * name, OLEStream ** newStream)
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    LPSTREAM ppStm;
    if (FAILED(err = oleStorage->CreateStream(OLE_STR(name), OLE_CREATE_MODE, 0, 0, &ppStm))) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      if ( !openOLEObjList )
        return FALSE;

      // Add the object to the list
      openOLEObjList->Add(ppStm, name);

      // Create an OLEStream
      if (( *newStream = new OLEStream(this, ppStm)) != NULL )
        return true;
      else {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;
}


Boolean OLEStorage::OpenStorage(const char * name, OLEStorage ** currentStorage, DWORD mode)
{
  HRESULT        err         = NOERROR;
  LPSTORAGE      ppStg       = NULL;
  LPSTORAGE      ppLStg      = NULL;
  OLECustomLink* customLink  = NULL;
  OLEStorage*    openStorage = NULL;
  List *         theList     = NULL;

  if (!oleStorage || !openOLEObjList)
    return FALSE;

  // Search the opened object list, if the object already open just add its reference
  if ( (openStorage = (OLEStorage *)openOLEObjList->Search((char *)name)) == NULL ) {

    // Open the names storage
    err = oleStorage->OpenStorage(OLE_STR(name), 0, mode, NULL, 0, &ppStg);
#ifdef macintosh
#ifndef powerc
    if( (ppStg == NULL) && (mode == OLE_READWRITE_MODE))
#else
      if (FAILED(err) && (mode == OLE_READWRITE_MODE))
#endif
#else
        if (FAILED(err) && (mode == OLE_READWRITE_MODE))
#endif
          // Try to open at least in read mode if the read/write failed
          err = oleStorage->OpenStorage(OLE_STR(name), 0, OLE_READ_ONLY_MODE, NULL, 0, &ppStg);

    // Exit if error
    if (FAILED(err) || ppStg == NULL)
      goto error;

    // Read the classID of the newly opened storage
    STATSTG statstg;
    err = ppStg->Stat(&statstg, STATFLAG_NONAME);

    if (FAILED(err))
      goto error;

    CLSID idCustomMoniker = ID_CustomMoniker;
    if (statstg.clsid == idCustomMoniker) {

      // Create a custom link handle
      {
        OLEStorage oleStorage(this,ppStg);
        customLink = new OLECustomLink(&oleStorage);
        if (customLink == 0)
          {
            lastError = (short) STG_E_INSUFFICIENTMEMORY;
            fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
            goto error_set;       // CHG_FILE_ERR - jump past re-set of error value
          }
      }

      // Release the current storage (useless now we've read the custom link inside...)
      // For the moment, this leads to an exception in OLE.
      // ppStg->Release();
      // ppStg = NULL;

      // Get the pointer to the linked OLE IStorage
      ppLStg = customLink->GetLinkedIStorage();

      if (ppLStg != NULL) {
        // Create a storage object
        if (( *currentStorage = new OLEStorage(this, ppLStg, customLink)) == NULL) {
          lastError = (short) STG_E_INSUFFICIENTMEMORY;
          fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
          goto error_set;     // CHG_FILE_ERR - jump past re-set of error value
        }
        // Add object to the list
        openOLEObjList->Add(*currentStorage, name);
      } else {
        // We can't open the link to the source storage
        lastError = (short) OLE_E_CANT_BINDTOSOURCE;
        fpxStatus = FPX_OLE_FILE_ERROR;
        goto error_set;       // CHG_FILE_ERR - jump past re-set of error value
      }
    }
    else {
      // Treat like a normal storage
      if (( *currentStorage = new OLEStorage(this, ppStg)) == NULL) {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        goto error_set;       // CHG_FILE_ERR - jump past re-set of error value
      }

      // Add object to the list
      openOLEObjList->Add(*currentStorage, name);
    }
    ppStg->Release();
  } else {
    // Create a new storage from current ole storage
    theList   = openStorage->GetList();
    ppStg     = openStorage->GetStorage();
    if (( *currentStorage = new OLEStorage(this, ppStg, theList)) == NULL) {
      lastError = (short) STG_E_INSUFFICIENTMEMORY;
      fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
      goto error_set;         // CHG_FILE_ERR - jump past re-set of error value
    }
  }

 return TRUE;

 error:
  // Handle all the error cases at once
  if (FAILED(err)) {
    lastError = TranslateOLEError(err);
    fpxStatus = OLEtoFPXError(err);
  }
 error_set:                    // CHG_FILE_ERR - jump here to preserve error value
  if (ppStg)
    ppStg->Release();
  if (customLink)
    delete customLink;
  return FALSE;
}


Boolean OLEStorage::OpenStorage(const CLSID& , const char * name, OLEStorage ** currentStorage, DWORD mode)
{
  // We do nothing with the class ID for now but we should compare it with the one included
  // in the open storage using IStorage::Stat()
  return OpenStorage(name,currentStorage,mode);
}


// Create a storage within current storage
Boolean OLEStorage::CreateStorage(const CLSID& classID, const char * name, OLEStorage ** newStorage)
{
  HRESULT err = NOERROR;
  if (oleStorage) {

    LPSTORAGE ppStg;
    if (FAILED(err = oleStorage->CreateStorage(OLE_STR(name), OLE_CREATE_MODE, 0, 0, &ppStg)) ) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      if ( !openOLEObjList )
        return FALSE;

      // Add the object to the list
      openOLEObjList->Add(ppStg, name);

      // Create an OLEStorage
      if (( *newStorage = new OLEStorage(classID, this, ppStg)) != NULL )
        return true;
      else {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;
}


// Create a storage within current storage
Boolean OLEStorage::CreateStorage(const char * name, OLEStorage ** newStorage)
{
  CLSID classID = BlankGUID;
  return CreateStorage(classID,name,newStorage);
}


// This function creates a property set specified by its name and a CLSID provided by the user
Boolean OLEStorage::CreatePropertySet(const CLSID& classID, const char *name, OLEPropertySet ** newPropertySet)
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    LPSTREAM ppStm;
    if (FAILED(err = oleStorage->CreateStream(OLE_STR(name), OLE_CREATE_MODE, 0, 0, &ppStm)) ) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      if ( !openOLEObjList )
        return FALSE;

      // Add the property set to the list
      openOLEObjList->Add(ppStm, name);

      // Create an OLEPropertySet
      if (( *newPropertySet = new OLEPropertySet(classID, this, ppStm)) != NULL )
        return true;
      else {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;
}


// This function creates a property set specified by its name within an open OLE storage.
// using a default CLSID
Boolean OLEStorage::CreatePropertySet(const char *name, OLEPropertySet ** newPropertySet)
{
  CLSID classID = BlankGUID;
  return CreatePropertySet(classID,name,newPropertySet);
}


// This function opens a property set specified by its name and a CLSID provided by the user
Boolean OLEStorage::OpenPropertySet(const CLSID& classID, const char *name, OLEPropertySet ** curPropertySet, DWORD mode)
{
  HRESULT err = NOERROR;
  if (oleStorage) {

    LPSTREAM ppStm;
    if ( !openOLEObjList )  return FALSE;

    // Search the opened object list, if the object already open just add its reference
    // NOTE: property set is a special kind of stream
    if ( (ppStm = (IStream *)openOLEObjList->Search(name)) == NULL ) {

      err = oleStorage->OpenStream(OLE_STR(name), 0, mode, 0, &ppStm);
#ifdef macintosh
  #ifndef powerc
      if( (ppStm == NULL) && (mode == OLE_READWRITE_MODE))
  #else
      if (FAILED(err) && (mode == OLE_READWRITE_MODE))
  #endif
#else
      if (FAILED(err) && (mode == OLE_READWRITE_MODE))
#endif
        // Try to open at least in read mode if the read/write failed
        err = oleStorage->OpenStream(OLE_STR(name), 0, OLE_READ_ONLY_MODE, 0, &ppStm);

      if ( !FAILED(err) || ppStm != NULL) {
        // Add stream to the list
        openOLEObjList->Add(ppStm, name, true);
      }
    }

    if (FAILED(err) || ppStm == NULL) {
      lastError = TranslateOLEError(err);
      if (err != NOERROR)
        fpxStatus = OLEtoFPXError(err);
      else
        fpxStatus = FPX_OLE_FILE_ERROR;
      return false;
    }
    else {
      // Create an OLEPropertySet
      if (( *curPropertySet = new OLEPropertySet(classID, this, ppStm)) != NULL )
        return true;
      else {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;
}


// This function opens a property set specified by its name within a open OLE storage
// using a default CLSID
Boolean OLEStorage::OpenPropertySet(const char *name, OLEPropertySet ** curPropertySet, DWORD mode)
{
  CLSID classID = BlankGUID;
  return OpenPropertySet(classID,name, curPropertySet, mode);
}


// This function creates a header stream specified by its name and a CLSID provided by the user
Boolean OLEStorage::CreateHeaderStream(const CLSID& classID, const char *name, OLEHeaderStream ** newHeaderStream)
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    LPSTREAM ppStm;
    if (FAILED(err = oleStorage->CreateStream(OLE_STR(name), OLE_CREATE_MODE, 0, 0, &ppStm)) ) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      if ( !openOLEObjList )
        return FALSE;

      // Add the stream to the list
      openOLEObjList->Add(ppStm, name);

      // Create an OLEHeaderStream
      if (( *newHeaderStream = new OLEHeaderStream(classID, this, ppStm)) != NULL ) {
        // write 28byte FPX header when creating a FPX stream
        (*newHeaderStream)->WriteHeader();

        return true;
      }
      else {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;
}


// This function creates a header stream specified by its name within an open OLE storage.
// using a default CLSID
Boolean OLEStorage::CreateHeaderStream(const char *name, OLEHeaderStream ** newHeaderStream)
{
  CLSID classID = BlankGUID;
  return CreateHeaderStream(classID,name,newHeaderStream);
}


// This function opens a header stream specified by its name and a CLSID provided by the user
Boolean OLEStorage::OpenHeaderStream(const CLSID& classID, const char *name, OLEHeaderStream ** curHeaderStream, DWORD mode)
{
  HRESULT err = NOERROR;
  if (oleStorage) {

    LPSTREAM ppStm;
    if ( !openOLEObjList )  return FALSE;

    // Search the opened object list, if the object already open just add its reference
    if ( (ppStm = (IStream *)openOLEObjList->Search(name)) == NULL ) {

      err = oleStorage->OpenStream(OLE_STR(name), 0, mode, 0, &ppStm);
#ifdef macintosh
  #ifndef powerc
      if( (ppStm == NULL) && (mode == OLE_READWRITE_MODE))
  #else
      if (FAILED(err) && (mode == OLE_READWRITE_MODE))
  #endif
#else
      if (FAILED(err) && (mode == OLE_READWRITE_MODE))
#endif
        // Try to open at least in read mode if the read/write failed
        err = oleStorage->OpenStream(OLE_STR(name), 0, OLE_READ_ONLY_MODE, 0, &ppStm);

      if ( !FAILED(err) )
        // Add stream to the list
        openOLEObjList->Add(ppStm, name);
    }

    if (FAILED(err)) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      // Create an OLEHeaderStream
      if (( *curHeaderStream = new OLEHeaderStream(classID, this, ppStm)) != NULL )
        return true;
      else {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;
}


// This function opens a header stream specified by its name within an open OLE storage
// using a default CLSID
Boolean OLEStorage::OpenHeaderStream(const char *name, OLEHeaderStream ** curHeaderStream, DWORD mode)
{
  CLSID classID = BlankGUID;
  return OpenHeaderStream(classID,name,curHeaderStream,mode);
}

// This function dumps the stats of all objects within an open stroage to a stream
Boolean OLEStorage::DumpStats( ofstream& statStream )
{
#if   defined(__GNUC__)
  // This function is only used for debugging the contents of a storage so
  // it is not *STRICTLY* necessary.
  return false;
#else
  // The number of indentation in the embedding storages
  static long level = 0;

  OLEEnumStatstg* pEnumStatstg;
  STATSTG     statstg;
  HRESULT     err = NOERROR;
  char      str[512];
  LPMALLOC    pMalloc = NULL;

  CoGetMalloc(MEMCTX_TASK, &pMalloc);

  if ( !EnumElements(&pEnumStatstg) )
    return false;

  while (pEnumStatstg->Next(&statstg)) {
    long i = level;
    while (i--)
      statStream.put('\t');

    if (pEnumStatstg->IsStorage(&statstg))
      sprintf(str, "This object is a storage, its name is %s, ", statstg.pwcsName);
    if (pEnumStatstg->IsStream(&statstg))
      sprintf(str, "This object is a stream, its name is %s, ", statstg.pwcsName);
    if (pEnumStatstg->IsPropertySet(&statstg))
      sprintf(str, "This object is a property set, its name is %s, ", statstg.pwcsName);
    statStream.write(str, strlen(str));
    sprintf(str, "its size is %lu%lu\n", statstg.cbSize.HighPart, statstg.cbSize.LowPart);
    statStream.write(str, strlen(str));

    if (pEnumStatstg->IsStorage(&statstg)) {
      LPSTORAGE pStg;

      if (FAILED(err = oleStorage->OpenStorage(OLE_STR(statstg.pwcsName), 0, OLE_READWRITE_MODE, NULL, 0, &pStg)) ) {
        if (FAILED(err = oleStorage->OpenStorage(OLE_STR(statstg.pwcsName), 0, OLE_READ_ONLY_MODE, NULL, 0, &pStg)) ) {
          lastError = TranslateOLEError(err);
          fpxStatus = OLEtoFPXError(err);
          return false;
        }
      }

      OLEStorage *currentStorage = new OLEStorage(this, pStg);
      if (currentStorage==NULL) {
        lastError = SEVERITY_ERROR;
        fpxStatus = FPX_OLE_FILE_ERROR;
        return false;
      }
      level++;
      currentStorage->DumpStats(statStream);
      level--;
      delete currentStorage;
    }
    pMalloc->Free(statstg.pwcsName);
  }

  pMalloc->Release();
  delete pEnumStatstg;

  return true;
#endif // __GNUC__
}

// The following functions are the same as the one defined for IStream's

Boolean OLEStorage::Commit( )
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    if (FAILED(err = oleStorage->Commit(0)) ) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }

    return true;
  } else
    return false;
}


Boolean OLEStorage::Revert( )
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    if (FAILED(err = oleStorage->Revert()) ) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    return true;
  } else
    return false;
}


Boolean OLEStorage::EnumElements( OLEEnumStatstg ** ppEnumStatstg)
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    IEnumSTATSTG * oleEnumStatstg;
    if (FAILED(err = oleStorage->EnumElements( 0, NULL, 0, &oleEnumStatstg))) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      *ppEnumStatstg = new OLEEnumStatstg(this, oleEnumStatstg);
      if ( !*ppEnumStatstg) {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;

  return true;
}


Boolean OLEStorage::Stat( STATSTG* pStatstg )
{
  HRESULT err = NOERROR;

  if (oleStorage) {
    if (FAILED(err = oleStorage->Stat(pStatstg, STATFLAG_NONAME))) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    } else
      return true;
  } else
    return false;
}


Boolean OLEStorage::GetSize( unsigned long *size )
{
  Boolean ok = TRUE;
  STATSTG stat;
  *size = 0;

  ok = Stat(&stat);
  if (ok)
    *size = (unsigned long)(stat.cbSize.LowPart);

  return ok;
}


// Rename an element under a storage
Boolean OLEStorage::RenameElement( const char *oldName, const char *newName )
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    if (FAILED(err = oleStorage->RenameElement(OLE_STR(oldName), OLE_STR(newName)))) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      return true;
    }
  } else
    return false;
}


// Remove an element under a storage
Boolean OLEStorage::DestroyElement( const char *name )
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    if (FAILED(err = oleStorage->DestroyElement(OLE_STR(name)))) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else {
      return true;
    }
  } else
    return false;
}


// Copy an OLEStorage to another OLEStorage
Boolean OLEStorage::CopyTo( OLEStorage ** ppStorage )
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    LPSTORAGE pStg = NULL;
    if (FAILED(err = oleStorage->CopyTo(0, NULL, NULL, pStg))) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
    else
    {
      *ppStorage = new OLEStorage(this, pStg);
      if ( !*ppStorage) {
        lastError = (short) STG_E_INSUFFICIENTMEMORY;
        fpxStatus = FPX_MEMORY_ALLOCATION_FAILED;
        return false;
      }
    }
  } else
    return false;

  return true;
}


// Copy an OLEStorage to IStorage
Boolean OLEStorage::CopyTo( IStorage * pStorage )
{
  HRESULT err = NOERROR;
  if (oleStorage) {
    if ( FAILED(err = oleStorage->CopyTo(0, NULL, NULL, pStorage)) ) {
      lastError = TranslateOLEError(err);
      fpxStatus = OLEtoFPXError(err);
      return false;
    }
  }
  else
    return false;

  return true;
}
