    // @(#)root/base:$Name:  $:$Id: TArchiveFile.cxx,v 1.1 2004/07/07 23:25:33 rdm Exp $
    // Author: Fons Rademakers   30/6/04

    /*************************************************************************
     * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TArchiveFile                                                         //
    //                                                                      //
    // This is an abstract class that describes an archive file containing  //
    // multiple sub-files, like a ZIP or TAR archive.                       //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #include "TArchiveFile.h"
    #include "TPluginManager.h"
    #include "TROOT.h"
    #include "TObjArray.h"
    #include "TError.h"

    ClassImp(TArchiveFile)

    //______________________________________________________________________________
    TArchiveFile::TArchiveFile(const char *archive, const char *member, TFile *file)
    {
       // Specify the archive name and member name. The member can be a decimal
       // number which allows to access the n-th sub-file. This method is
       // normally only called via TFile.

       if (!file)
          Error("TArchiveFile", "must specify a valid TFile");

       fFile        = file;
       fArchiveName = archive;
       fMemberName  = member;
       fMemberIndex = -1;
       if (fMemberName.IsDigit())
          fMemberIndex = atoi(fMemberName);
       fMembers     = new TObjArray;
       fMembers->SetOwner();
       fCurMember   = 0;
    }

    //______________________________________________________________________________
    TArchiveFile::~TArchiveFile()
    {
       // Dtor.

       delete fMembers;
    }

    //______________________________________________________________________________
    Long64_t TArchiveFile::GetMemberFilePosition() const
    {
       // Return position in archive of current member.

       return fCurMember ? fCurMember->GetFilePosition() : 0;
    }

    //______________________________________________________________________________
    Int_t TArchiveFile::GetNumberOfMembers() const
    {
       // Returns number of members in archive.

       return fMembers->GetEntriesFast();
    }

    //______________________________________________________________________________
    Int_t TArchiveFile::SetMember(const char *member)
    {
       // Explicitely make the specified member the current member.
       // Returns -1 in case of error, 0 otherwise.

       fMemberName  = member;
       fMemberIndex = -1;

       return SetCurrentMember();
    }

    //______________________________________________________________________________
    Int_t TArchiveFile::SetMember(Int_t idx)
    {
       // Explicitely make the member with the specified index the current member.
       // Returns -1 in case of error, 0 otherwise.

       fMemberName  = "";
       fMemberIndex = idx;

       return SetCurrentMember();
    }

    //______________________________________________________________________________
    TArchiveFile *TArchiveFile::Open(const char *url, TFile *file)
    {
       // Return proper archive file handler depending on passed url.
       // The handler is loaded via the plugin manager and is triggered by
       // the extension of the archive file. In case no handler is found 0
       // is returned. The file argument is used to access the archive.
       // The archive should be specified as url with the member name as the
       // anchor, e.g. "root://pcsalo.cern.ch/alice/event_1.zip#tpc.root",
       // where tpc.root is the file in the archive to be opened.
       // Alternatively the sub-file can be specified via its index number,
       // e.g. "root://pcsalo.cern.ch/alice/event_1.zip#3".
       // This function is normall only called via TFile::Open().

       if (!file) {
          ::Error("TArchiveFile::Open", "must specify a valid TFile");
          return 0;
       }

       TString archive, member;

       if (!ParseUrl(url, archive, member))
          return 0;

       TArchiveFile *f = 0;
       TPluginHandler *h;
       if ((h = gROOT->GetPluginManager()->FindHandler("TArchiveFile", archive))) {
          if (h->LoadPlugin() == -1)
             return 0;
          f = (TArchiveFile*) h->ExecPlugin(3, archive.Data(), member.Data(), file);
       }

       return f;
    }

    //______________________________________________________________________________
    Bool_t TArchiveFile::ParseUrl(const char *url, TString &archive, TString &member)
    {
       // Try to determine if url contains an anchor specifying an archive member.
       // Returns kFALSE in case of an error.

       TString u = url;
       archive   = "";
       member    = "";

       Int_t idx;
       if ((idx = u.Last('#')) == kNPOS) {
          archive = url;
          return kTRUE;
       }

       archive = u(0, idx);
       member  = u(idx+1, u.Length()-1);

       if (archive == "" || member == "") {
          archive = "";
          member  = "";
          return kFALSE;
       }
       return kTRUE;
    }

    ClassImp(TArchiveMember)

    //______________________________________________________________________________
     TArchiveMember::TArchiveMember()
    {
       // Default ctor.

       fName         = "";
       fComment      = "";
       fPosition     = 0;
       fFilePosition = 0;
       fCsize        = 0;
       fDsize        = 0;
       fDirectory    = kFALSE;
    }

    //______________________________________________________________________________
     TArchiveMember::TArchiveMember(const char *name)
    {
       // Create an archive member file.

       fName         = name;
       fComment      = "";
       fPosition     = 0;
       fFilePosition = 0;
       fCsize        = 0;
       fDsize        = 0;
       fDirectory    = kFALSE;
    }

    //______________________________________________________________________________
     TArchiveMember::TArchiveMember(const TArchiveMember &member)
       : TObject(member)
    {
       // Copy ctor.

       fName         = member.fName;
       fComment      = member.fComment;
       fModTime      = member.fModTime;
       fPosition     = member.fPosition;
       fFilePosition = member.fFilePosition;
       fCsize        = member.fCsize;
       fDsize        = member.fDsize;
       fDirectory    = member.fDirectory;
    }

    //______________________________________________________________________________
    TArchiveMember &TArchiveMember::operator=(const TArchiveMember &rhs)
    {
       // Assignment operator.

       if (this != &rhs) {
          TObject::operator=(rhs);
          fName         = rhs.fName;
          fComment      = rhs.fComment;
          fModTime      = rhs.fModTime;
          fPosition     = rhs.fPosition;
          fFilePosition = rhs.fFilePosition;
          fCsize        = rhs.fCsize;
          fDsize        = rhs.fDsize;
          fDirectory    = rhs.fDirectory;
       }
       return *this;
    }