// ///////////////////////////////////////////////////////////////////
//
//  File:      TFIOElement.cpp
//
//  Version:   1.0
//
//  Author:    Reiner Rohlfs
//
//  History:
//
// ///////////////////////////////////////////////////////////////////
#include <fcntl.h>
#include <unistd.h>

#include "TClass.h"

#include "TFIOElement.h"
#include "TFRootIO.h"
#include "TFAsroIO.h"
#include "TFFitsIO.h"
#include "TFError.h"

ClassImp(TFIOElement)
ClassImp(TFFileIter)


static const char * errmsg_io[] = {
"Cannot write element %s to file %s opened as readonly.",
"Cannot delete element %s to file %s opened as readonly."
};


//_____________________________________________________________________________
// TFIOElement:
//    The TFIOElement class is the base class to save data structures into a 
//    ASRO, a ROOT or a FITS file. The file extension define the used file type:
//    *.fits, *.fts, *fit and *.fits.gz define a FITS file.
//    *.root define a ROOT file and 
//    *.asro define a ASRO file. 
//    If the filename has none of the above file extensions .asro is 
//    automatically added to the file name and a ASRO file is opened or created.
//
//    The TFIOElement class does not have data itself, but a header to store 
//    header information and always a name. Most of the time derived classes 
//    are used to write data into a file and read data from a file. For example 
//    tables or images.
//
//    To create a new element either in memory or in a ASRO in a ROOT or in a
//    FITS file the constructors can be used. To create an element in memory 
//    that reads its data and header from a file the global function
//    TFRead has to be used. Beside TFIOElements this function can read 
//    also any derived class from TFIOElement.
//
//    All changes of a TFIOElement or its derived classes are done only in 
//    memory and not automatically updated in the associated file. To 
//    save the changes the member function SaveElement() has to be called.
//
//
// TFFileIter:
//    The TFFileIter can be used to iterate through all extensions in a 
//    ASRO file, in a ROOT file and in the FITS file. 



//_____________________________________________________________________________
static int FileType(TString & flName, bool create)
{
// depending on the extension of the file name this function determins the
// file type:
//    *.fits, *.fts, *fit and *.fits.gz is a FITS file.  return value: 1
//    *.root is a ROOT file                              return value: 0
//    *.asro is a ASRO file                              return value: 2
//  else:
//    if create == true assume it is an FITS file        return value: 1
//    else
//      try to read the first 4 bytes:
//        if file starts with "root"  it is a ROOT file  return value: 0
//        if file starts with "ASRO" it is an ASRO file  return value: 2
//        else  assume it an FITS file                   return value: 1
//

   if ( flName.EndsWith(".asro") ) 
      return 2;

   if ( flName.EndsWith(".root") ) 
      return 0;
   
   if ( flName.EndsWith(".fits")    ||
        flName.EndsWith(".fts")     ||
        flName.EndsWith(".fit")     ||
        flName.EndsWith(".fits.gz")    )
      return 1;

   if (create)
   // everything else is a FITS file
      return 1;

   // try to open the file and read the first 4 bytes
   int fl = open(flName.Data(), O_RDONLY);
   if (fl >= 0)
      {
      char id[4];
      int numRead = read(fl, id, 4);
      close(fl);
      if (numRead == 4)
         {
         if (strncmp("root", id, 4) == 0)
            return 0;
         if (strncmp("ASRO", id, 4) == 0)
            return 2;
         }
      }

   // everything else is a FITS file
   return 1;
}

TFIOElement *  TFRead(const char * fileName, const char * name,  
                      UInt_t cycle, FMode mode, TClass * classType)
{
// This global functions reads a TFIOElement or a derived object from a 
// ASRO file, a ROOT file or a FITS file, depending on the file extension 
// and returns its pointer. The returned element has to be deleted by the 
// calling function.
//
// fileName: defines the file. Absolute path, relative path or just a 
//       filename are accepted names.
//       If mode == kFRead the file has to have read permission. If mode ==
//       kFReadWrite it also has to have write permission.
// name: Is the identifier of the element. If more than one element with
//       the same name exist in the file the first is returned if 
//       cycle is set to the default value of 0. Otherwise the element with
//       the specified cycle number is looked for in the file.
// cycle: If it is not the default value of 0 only the element with the 
//       specified  cycle number will be read.
// mode: has to be either kFRead or kFReadWrite. 
//       kfRead: The file and the required element must already exist. The
//               element cannot be updated.
//       kfReadWrite: The file and the required element must already exist.
//               The element can be updated with the member function 
//               SaveElement()
// classType: If this parameter is defined (not NULL) only elements with the 
//       specified classType are returned. Use the static member function
//       Class() to pass the required value.
//
// If there is an error during opening or reading the file or if the required
// element is not in the file the functions will throw a TFFileException or 
// will return a NULL pointer.
//
   TString flName = fileName;

   int fileType = FileType(flName, false);

   if (fileType == 0)
      return TFRootIO::TFRead(name, flName, mode, classType, cycle);     
   else if (fileType == 1)
      return TFFitsIO::TFRead(flName, name, cycle, mode, classType);
   else 
      return TFAsroIO::TFRead(flName, name, cycle, mode, classType);

}

//_____________________________________________________________________________
TFFileIter::TFFileIter(const char * fileName, FMode mode)
{
// File iterator to open all extension in a file, one after the other. 
// As soon as the next extension is opened with the Next() function the
// previous element is closed and cannot be accessed any more.

   TString flName = fileName;
   int fileType = FileType(flName, false);

   if (fileType == 0)
      fIter = new TFRootFileIter(flName, mode);     
   else if (fileType == 1)
      fIter = new TFFitsFileIter(flName, mode);
   else if (fileType == 2)
      fIter = new TFAsroFileIter(flName, mode);
   else
      fIter = NULL; 

}

//_____________________________________________________________________________
TFIOElement::TFIOElement()
{
// Default constructor. The element is not associated with a element 
// in a file.
// Don't use this constructor. The element should have at least a name.

   fio            = NULL;
   fFileAccess    = kFUndefined;
}
//_____________________________________________________________________________
TFIOElement::TFIOElement(const char * name) 
        : TNamed(name, "") 
{
// The element is not associated with an element in a file.
// It exist only in memory. name is the id of the new element.

   fio            = NULL;
   fFileAccess    = kFUndefined;
}
//_____________________________________________________________________________
TFIOElement::TFIOElement(const char * name, const char * fileName) 
        : TNamed(name, "") 
{
// A new element is created. It is associated with an element in a 
// file. name is the id of the new element. 
// fileName is the file name of the ASRO, ROOT or FITS file with this new 
// element. The file  may already exist or will be created. Other objects 
// with the same name can exist without problem in the same file. Each object 
// with the same name has a unique cycle number. Use GetCycle() to ask for 
// this cycle number. Use the function TFRead() to read and update an already 
// existing element from a ASRO, a ROOT or a FITS file.

   NewFile(fileName);
}
//_____________________________________________________________________________
TFIOElement::TFIOElement(const TFIOElement & ioelement)
      : TNamed(ioelement), TFHeader(ioelement) 
{
// Copy constructor. But even if the input element is associated with an 
// element in a file, this new table is NOT associated with this or 
// an other element in a file. It will exist only in memory, but can be
// saved in a new file using the SaveElement() method. 

   fio            = NULL;
   fFileAccess    = kFUndefined;
}
//_____________________________________________________________________________
TFIOElement & TFIOElement::operator = (const TFIOElement & ioelement)
{  
// Even if the input element is associated with an element
// in a  file, this element is NOT associated with this or an other
// element in a file. If this element was associates with an element 
// in a file before this function the file is closed without update.

   if (this != &ioelement)
      {
      TNamed::operator=(ioelement);
      TFHeader::operator =(ioelement);

      // close the old file
      CloseElement();

      fio      = NULL;
      }

   return *this;
}
//_____________________________________________________________________________
bool TFIOElement::operator == (const TFHeader & ioelement) const
{  
// Two elements are identical if their names are identical and their header 
// are identical. The order of the attributes in the header may be different 
// and the elements are still considered to be identical.

   return IsA() == ioelement.IsA()                 &&
          fName == ((TFIOElement&)ioelement).fName &&
          TFHeader::operator==(ioelement);
}
//_____________________________________________________________________________
TFIOElement::~TFIOElement()
{
// The associated file is closed, the element is NOT updated. Use
// SaveElement() to update the changes in the file.

   CloseElement();
}
//_____________________________________________________________________________
void TFIOElement::NewFile(const char * fileName)
{
// protected function to create a new element in a file 

   TString flName = fileName;

   int fileType = FileType(flName, true);

   if (fileType == 0)
      fio = new TFRootIO(this, flName);     
   else if (fileType == 1)
      fio = new TFFitsIO(this, flName);
   else if (fileType == 2)
      fio = new TFAsroIO(this, flName);

   if (!fio->IsOpen())
      CloseElement();
   else
      fFileAccess    = kFReadWrite;

}
//_____________________________________________________________________________
Int_t TFIOElement::SaveElement(const char * fileName, Int_t compLevel)
{
// Updates the element in the file with the data of this element in
// memory. If fileName is defined the old file is closed and the element
// is written into this new file named fileName.
// compLevel defines the compression level in the ASRO or ROOT file. To set
// compLevel and to update the element in the same file set fileName 
// to an empty string "".
// This function without any parameter has to be used to update the
// file with any change of the element in memory.

   if (fileName && fileName[0] != 0)
      {
      // read everything from the old file and close it
      UpdateMemory();
      CloseElement();

      NewFile(fileName);

      if (!fio || !fio->IsOpen())
         return -1;

      fio->CreateElement();
      }

   if (!fio || !fio->IsOpen())
      return 0;

   Int_t err = 0;
   if (fFileAccess == kFRead)
      {
      TFError::SetError("TFIOElement::SaveElement", errmsg_io[0], 
                        GetName(), fio->GetFileName());
      return -1;
      }

   else if (fFileAccess == kFReadWrite)
      err = fio->SaveElement(compLevel);

   return err;
}
//_____________________________________________________________________________
void TFIOElement::CloseElement()
{
// Closes the element in the associated file. It does not update the
// element in the file. The element still exist in memory after
// a call of this function.

   delete fio;
   fio    = NULL;

   fFileAccess    = kFUndefined;
}
//_____________________________________________________________________________
Int_t TFIOElement::DeleteElement(Bool_t updateMemory)
{
// Deletes the element in the file, but not in memory.
// Closes the file and deletes the file if this element is the
// last element in the file.
// Updated the element in memory before the file is deleted if
// updateMemory is set to kTRUE. The default is kFALSE.

   if (fio == NULL)
      return 0;

   if (updateMemory)
     UpdateMemory();

   Int_t err = 0;
   if (fFileAccess == kFRead)
      {
      TFError::SetError("TFIOElement::DeleteElement", errmsg_io[1], 
                        GetName(), fio->GetFileName());
      return -1;
      }
   else if (fFileAccess == kFReadWrite)
      err = fio->DeleteElement();

   CloseElement();

   return err;
}
//_____________________________________________________________________________
void TFIOElement::Print(const Option_t* option) const
{
//  Prints Class name, name of object and file name and cycle number 
//  of object if if is connected to a file.
//  Calls Print function of TFHeader to print the header attributes

   printf("Container type: %s         Name: %s\n", 
          IsA()->GetName(), GetName());
   if (IsFileConnected())
      printf("File name:      %s Cycle Number: %u\n", 
             GetFileName(), GetCycle());

   TFHeader::PrintH(option);
}


Last update: Fri Mar 14 13:55:16 2008

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.