// @(#)root/hbook:$Name:  $:$Id: THbookFile.cxx,v 1.21 2004/02/19 21:48:06 brun Exp $
// Author: Rene Brun   18/02/2002

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

////////////////////////////////////////////////////////////////////////
//  This class is an interface to the Hbook objects in Hbook files
//  Any Hbook object (1-D, 2-D, Profile, RWN or CWN can be read
//  NB: a THbookFile can only be used in READ mode
//      Use the utility in $ROOTSYS/bin/h2root to convert Hbook to Root
//
// Example of use:
//  gSystem->Load("libHbook");
//  THbookFile f("myfile.hbook");
//  f.ls();
//  TH1F *h1 = (TH1F*)f.Get(1);  //import histogram ID=1 in h1
//  h1->Fit("gaus");
//  THbookTree *T = (THbookTree*)f.Get(111); //import ntuple header
//  T->Print();  //show the Hbook ntuple variables
//  T->Draw("x","y<0"); // as in normal TTree::Draw
//
//  THbookFile can be browsed via TBrowser.
//
////////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "TROOT.h"
#include "THbookFile.h"
#include "TH2.h"
#include "THbookTree.h"
#include "THbookBranch.h"
#include "THbookKey.h"
#include "TGraph.h"
#include "TProfile.h"
#include "TTreeFormula.h"
#include "TLeafI.h"
#include "TBrowser.h"
#include "TSystem.h"

#define PAWC_SIZE 2000000

//  Define the names of the Fortran common blocks for the different OSs

#ifndef WIN32
#  define pawc pawc_
#  define quest quest_
#  define hcbits hcbits_
#  define hcbook hcbook_
#  define rzcl rzcl_
int pawc[PAWC_SIZE];
int quest[100];
int hcbits[37];
int hcbook[51];
int rzcl[11];
#else
#  define pawc   PAWC
#  define quest  QUEST
#  define hcbits HCBITS
#  define hcbook HCBOOK
#  define rzcl   RZCL
extern "C" int pawc[PAWC_SIZE];
extern "C" int quest[100];
extern "C" int hcbits[37];
extern "C" int hcbook[51];
extern "C" int rzcl[11];
#endif

int *iq, *lq;
float *q;
char idname[128];
int nentries;
char chtitl[128];
int ncx,ncy,nwt,idb;
int lcont, lcid, lcdir, ltab;
float xmin,xmax,ymin,ymax;
const Int_t kNRH  = 6;
const Int_t kMIN1 = 7;
const Int_t kMAX1 = 8;

static Int_t lastentry = -1;

//  Define the names of the Fortran subroutine and functions for the different OSs

#ifndef WIN32
# define hlimit  hlimit_
# define hldir   hldir_
# define hropen  hropen_
# define hrend   hrend_
# define hrin    hrin_
# define hnoent  hnoent_
# define hgive   hgive_
# define hgiven  hgiven_
# define hgnpar  hgnpar_
# define hgnf    hgnf_
# define hgnt    hgnt_
# define hgntf   hgntf_
# define hgnt1   hgnt1_
# define rzink   rzink_
# define hdcofl  hdcofl_
# define hmaxim  hmaxim_
# define hminim  hminim_
# define hdelet  hdelet_
# define hntvar2 hntvar2_
# define hntvar3 hntvar3_
# define hbname  hbname_
# define hbnamc  hbnamc_
# define hbnam   hbnam_
# define hi      hi_
# define hie     hie_
# define hif     hif_
# define hij     hij_
# define hix     hix_
# define hijxy   hijxy_
# define hije    hije_
# define hcdir   hcdir_

# define type_of_call
# define DEFCHAR  const char*
# define PASSCHAR(string) string
#else
# define hlimit  HLIMIT
# define hldir   HLDIR
# define hropen  HROPEN
# define hrend   HREND
# define hrin    HRIN
# define hnoent  HNOENT
# define hgive   HGIVE
# define hgiven  HGIVEN
# define hgnpar  HGNPAR
# define hgnf    HGNF
# define hgnt    HGNT
# define hgntf   HGNTF
# define hgnt1   HGNT1
# define rzink   RZINK
# define hdcofl  HDCOFL
# define hmaxim  HMAXIM
# define hminim  HMINIM
# define hdelet  HDELET
# define hntvar2 HNTVAR2
# define hntvar3 HNTVAR3
# define hbname  HBNAME
# define hbnamc  HBNAMC
# define hbnam   HBNAM
# define hi      HI
# define hie     HIE
# define hif     HIF
# define hij     HIJ
# define hix     HIX
# define hijxy   HIJXY
# define hije    HIJE
# define hcdir   HCDIR
# define type_of_call  _stdcall
# define DEFCHAR  const char*, const int
# define PASSCHAR(string) string, strlen(string)
#endif

extern "C" void  type_of_call hlimit(const int&);
#ifndef WIN32
extern "C" void  type_of_call hropen(const int&,DEFCHAR,DEFCHAR,DEFCHAR,
                        const int&,const int&,const int,const int,const int);
extern "C" void  type_of_call hrend(DEFCHAR,const int);
#else
extern "C" void  type_of_call hropen(const int&,DEFCHAR,DEFCHAR,DEFCHAR,
                        const int&,const int&);
extern "C" void  type_of_call hrend(DEFCHAR);
#endif

extern "C" void  type_of_call hrin(const int&,const int&,const int&);
extern "C" void  type_of_call hnoent(const int&,const int&);
#ifndef WIN32
extern "C" void  type_of_call hgive(const int&,DEFCHAR,const int&,const float&,const float&,
   const int&,const float&,const float&,const int&,const int&,const int);
#else
extern "C" void  type_of_call hgive(const int&,DEFCHAR,const int&,const float&,const float&,
   const int&,const float&,const float&,const int&,const int&);
#endif

  //SUBROUTINE HGNT1(IDD,BLKNA1,VAR,IOFFST,NVAR,IDNEVT,IERROR)
#ifndef WIN32
extern "C" void  type_of_call hgiven(const int&,DEFCHAR,const int&,DEFCHAR,
   const float&,const float&,const int,const int);
extern "C" void  type_of_call hgnt1(const int&,DEFCHAR,DEFCHAR,const int&,const int&,const int&,const int&,const int,const int);
#else
extern "C" void  type_of_call hgiven(const int&,DEFCHAR,const int&,DEFCHAR,
   const float&,const float&);
extern "C" void  type_of_call hgnt1(const int&,DEFCHAR,DEFCHAR,const int&,const int&,const int&,const int&);
#endif

#ifndef WIN32
extern "C" void  type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&,const int,const int, const int);
extern "C" void  type_of_call hntvar3(const int&,const int&,DEFCHAR, const int);
#else
extern "C" void  type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&);
extern "C" void  type_of_call hntvar3(const int&,const int&,DEFCHAR);
#endif

#ifndef WIN32
extern "C" void  type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&,const int, const int);
#else
extern "C" void  type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&);
#endif

extern "C" void  type_of_call hgnpar(const int&,const char *,const int);
extern "C" void  type_of_call hgnf(const int&,const int&,const float&,const int&);
extern "C" void  type_of_call hgnt(const int&,const int&,const int&);
extern "C" void  type_of_call hgntf(const int&,const int&,const int&);
extern "C" void  type_of_call rzink(const int&,const int&,const char *,const int);
extern "C" void  type_of_call hdcofl();
extern "C" void  type_of_call hmaxim(const int&,const float&);
extern "C" void  type_of_call hminim(const int&,const float&);
extern "C" void  type_of_call hdelet(const int&);
extern "C" float type_of_call hi(const int&,const int&);
extern "C" float type_of_call hie(const int&,const int&);
extern "C" float type_of_call hif(const int&,const int&);
extern "C" float type_of_call hij(const int&,const int&,const int&);
extern "C" void  type_of_call hix(const int&,const int&,const float&);
extern "C" void  type_of_call hijxy(const int&,const int&,const int&,const float&,const float&);
extern "C" float type_of_call hije(const int&,const int&,const int&);
#ifndef WIN32
extern "C" void  type_of_call hcdir(DEFCHAR,DEFCHAR ,const int,const int);
extern "C" void  type_of_call hldir(DEFCHAR,DEFCHAR ,const int,const int);
#else
extern "C" void  type_of_call hcdir(DEFCHAR,DEFCHAR);
extern "C" void  type_of_call hldir(DEFCHAR,DEFCHAR);
#endif

Bool_t THbookFile::fgPawInit = kFALSE;
Int_t  *THbookFile::fgLuns   = 0;
R__EXTERN TTree *gTree;

ClassImp(THbookFile)

//______________________________________________________________________________
THbookFile::THbookFile() : TNamed()
{
   fList = new TList();
   fKeys = new TList();
}

//1_____________________________________________________________________________
THbookFile::THbookFile(const char *fname, Int_t lrecl)
           :TNamed(fname,"")
{
//  Constructor for an HBook file object

  // Initialize the Hbook/Zebra store
   Int_t i;
   if (!fgPawInit) {
     fgPawInit = kTRUE;
     lq = &pawc[9];
     iq = &pawc[17];
     void *qq = iq;
     q = (float*)qq;
     int pawc_size = PAWC_SIZE;
     hlimit(pawc_size);
     fgLuns = new Int_t[10];
     for (i=0;i<10;i++) fgLuns[i] = 0;
  }

  //find a free logical unit (max 10)
  fLun = 0;
  for (i=0;i<10;i++) {
     if (fgLuns[i] == 0) {
        fLun = 10+i;
        fgLuns[i] = 1;
        break;
     }
  }
  if (fLun == 0) {
     Error("THbookFile","Too many HbookFiles\n");
     return;
  }
  char topdir[20];
  sprintf(topdir,"lun%d",fLun);

  Int_t ier;
#ifndef WIN32
  hropen(fLun,PASSCHAR(topdir),PASSCHAR(fname),PASSCHAR("p"),lrecl,ier,strlen(topdir),strlen(fname),1);
#else
  hropen(fLun,PASSCHAR(topdir),PASSCHAR(fname),PASSCHAR("p"),lrecl,ier);
#endif
  fLrecl = lrecl;
  SetTitle(topdir);
  sprintf(topdir,"//lun%d",fLun);
  fCurDir = topdir;

  if (ier) printf (" Error on hropen was %d \n", ier);
  if (quest[0]) {
     printf("Error cannot open input file: %s\n",fname);
  }
  if (ier || quest[0]) {
     fgLuns[fLun-10]=0; 
     fLun  = 0;
     fList = 0;
     fKeys = 0;
     MakeZombie();
     return;
  }

  gROOT->GetListOfBrowsables()->Add(this,fname);

  fList = new TList();
  fKeys = new TList();
  for (Int_t key=1;key<1000000;key++) {
     int z0 = 0;
     rzink(key,z0,"S",1);
     if (quest[0]) break;
     if (quest[13] & 8) continue;
     Int_t id = quest[20];
     THbookKey *akey = new THbookKey(id,this);
     fKeys->Add(akey);
  }
}

//______________________________________________________________________________
THbookFile::~THbookFile()
{

   if (!fList) return;
   Close();
   delete fList;
   delete fKeys;
}

//______________________________________________________________________________
void THbookFile::Browse(TBrowser *b)
{
// to be implemented

   if( b ) {
        b->Add(fList, "memory");
        b->Add(fKeys, "IDs on disk");
   }
   cd();
}

//______________________________________________________________________________
Bool_t THbookFile::cd(const char *dirname)
{
// change directory to dirname

   Int_t nch = strlen(dirname);
   if (nch == 0) {
#ifndef WIN32
       hcdir(PASSCHAR(fCurDir.Data()),PASSCHAR(" "),fCurDir.Length(),1);
#else
       hcdir(PASSCHAR(fCurDir.Data()),PASSCHAR(" "));
#endif
       return kTRUE;
   }

   char cdir[512];
   Int_t i;
   for (i=0;i<512;i++) cdir[i] = ' ';
   cdir[511] = 0;
#ifndef WIN32
  hcdir(PASSCHAR(dirname),PASSCHAR(" "),nch,1);
  hcdir(PASSCHAR(cdir),PASSCHAR("R"),511,1);
#else
  hcdir(PASSCHAR(dirname),PASSCHAR(" "));
  hcdir(PASSCHAR(cdir),PASSCHAR("R"));
#endif
  for (i=510;i>=0;i--) {
     if (cdir[i] != ' ') break;
     cdir[i] = 0;
  }
  fCurDir = cdir;
  printf("fCurdir=%s\n",fCurDir.Data());

  return kTRUE;
}

//______________________________________________________________________________
void THbookFile::Close(Option_t *)
{
// Close the Hbook file

   if(!IsOpen()) return;
   if (!fList) return;
   
   gROOT->GetListOfBrowsables()->Remove(this);

   cd();

   fList->Delete();
   fKeys->Delete();
   if (fgLuns) fgLuns[fLun-10] = 0;
   hdelet(0);
#ifndef WIN32
  hrend(PASSCHAR(GetTitle()),strlen(GetTitle()));
#else
  hrend(PASSCHAR(GetTitle()));
#endif
}

//______________________________________________________________________________
void THbookFile::DeleteID(Int_t id)
{
   hdelet(id);
}

//______________________________________________________________________________
TObject *THbookFile::FindObject(const char *name) const
{
// return object with name in fList in memory
   return fList->FindObject(name);
}

//______________________________________________________________________________
TObject *THbookFile::FindObject(const TObject *obj) const
{
// return object with pointer obj in fList in memory
   return fList->FindObject(obj);
}

//______________________________________________________________________________
TObject *THbookFile::Get(Int_t idd)
{
// import Hbook object with identifier idd in memory

  Int_t id = 0;
  for (Int_t key=1;key<1000000;key++) {
     int z0 = 0;
     rzink(key,z0,"S",1);
     if (quest[0]) break;
     if (quest[13] & 8)  continue;
     id = quest[20];
     if (id == idd) break;
  }
  if (id == 0) return 0;
  if (id != idd) {
     printf("Error cannot find ID = %d\n",idd);
     return 0;
  }

  int i999 = 999;
  // must delete any previous object with the same ID !!
  lcdir = hcbook[6];
  ltab  = hcbook[9];
  for (Int_t i=1;i<=iq[lcdir+kNRH];i++) {
     if (iq[ltab+i] == id) {
        printf("WARNING, previous ID=%d is replaced\n",id);
        hdelet(id);
        break;
     }
  }
  hrin(id,i999,0);
  if (quest[0]) {
     printf("Error cannot read ID = %d\n",id);
     return 0;
  }
  hdcofl();
  lcid  = hcbook[10];
  lcont = lq[lcid-1];
  TObject *obj = 0;
  if (hcbits[3]) {
     if (iq[lcid-2] == 2) obj = ConvertRWN(id);
     else                 obj = ConvertCWN(id);
     //hdelet(id); //cannot be deleted here since used in GetEntry
     if (obj) {
        fList->Add(obj);
        ((THbookTree *)obj)->SetTitle(GetName());
     }
     return obj;
  }
  if (hcbits[0] && hcbits[7]) {
     obj = ConvertProfile(id);
     hdelet(id);
     if (obj) fList->Add(obj);
     return obj;
  }
  if (hcbits[0]) {
     obj = Convert1D(id);
     hdelet(id);
     if (obj) fList->Add(obj);
     return obj;
  }
  if (hcbits[1] || hcbits[2]) {
     obj = Convert2D(id);
     hdelet(id);
     if (obj) fList->Add(obj);
     return obj;
  }
  return obj;
}


//______________________________________________________________________________
Int_t THbookFile::GetEntry(Int_t entry, Int_t id, Int_t atype, Float_t *x)
{
// Read in memory all columns of entry number of ntuple id from the Hbook file

   Int_t ier = 0;
   if (atype == 0) {
      hgnf(id,entry+1,x[0],ier);
   } else {
      hgnt(id,entry+1,ier);
   }
   return 0;
}

//______________________________________________________________________________
Int_t THbookFile::GetEntryBranch(Int_t entry, Int_t id)
{
// Read in memory only the branch bname

   if (entry == lastentry) return 0;
   lastentry = entry;
   Int_t ier = 0;
   //uses the fast read method using the Hbook tables computed in InitLeaves
   hgntf(id,entry+1,ier);
   //old alternative slow method
//#ifndef WIN32
//   hgnt1(id,PASSCHAR(blockname),PASSCHAR(branchname),0,-1,entry+1,ier,strlen(blockname),strlen(branchname));
//#else
//   hgnt1(id,PASSCHAR(blockname),PASSCHAR(branchname),0,-1,entry+1,ier);
//#endif
   return 0;
}


//______________________________________________________________________________
void THbookFile::InitLeaves(Int_t id, Int_t var, TTreeFormula *formula)
{
// This function is called from the first entry in TTreePlayer::InitLoop
// It analyzes the list of variables involved in the current query
// and pre-process the internal Hbook tables to speed-up the search
// at the next entries.

  if (!formula) return;
   Int_t ncodes = formula->GetNcodes();
   for (Int_t i=1;i<=ncodes;i++) {
      TLeaf *leaf = formula->GetLeaf(i-1);
      if (!leaf) continue;
      if (var == 5) {
         //leafcount may be null in case of a fix size array
         if (leaf->GetLeafCount()) leaf = leaf->GetLeafCount();
      }
      Int_t last = 0;
      if (var == 1 && i == ncodes) last = 1;
#ifndef WIN32
      hntvar3(id,last,PASSCHAR(leaf->GetName()),strlen(leaf->GetName()));
#else
      hntvar3(id,last,PASSCHAR(leaf->GetName()));
#endif
   }
}

//______________________________________________________________________________
Bool_t THbookFile::IsOpen() const
{
   // Returns kTRUE in case file is open and kFALSE if file is not open.

   return fLun == 0 ? kFALSE : kTRUE;
}


//______________________________________________________________________________
void THbookFile::SetBranchAddress(Int_t id, const char *bname, void *add)
{
//
#ifndef WIN32
  hbnam(id,PASSCHAR(bname),(Int_t&)add,PASSCHAR("$SET"),0,strlen(bname),4);
#else
  hbnam(id,PASSCHAR(bname),(Int_t&)add,PASSCHAR("$SET"),0);
#endif
}

//______________________________________________________________________________
TFile *THbookFile::Convert2root(const char *rootname, Int_t /*lrecl*/,
                                Option_t *option)
{
// Convert this Hbook file to a Root file with name rootname.
// if rootname="', rootname = hbook file name with .root instead of .hbook
// By default, the Root file is connected and returned
// option:
//       - "NO" do not connect the Root file
//       - "C"  do not compress file (default is to compress)
//       - "L"  do not convert names to lower case (default is to convert)

   TString opt = option;
   opt.ToLower();

   char cmd[512];
   char rfile[512];
   Int_t nch = strlen(rootname);
   if (nch) {
      strcpy(rfile,rootname);
   } else {
      strcpy(rfile,GetName());
      char *dot = strrchr(rfile,'.');
      if (dot) strcpy(dot+1,"root");
      else     strcat(rfile,".root");
   }

   sprintf(cmd,"h2root %s %s",GetName(),rfile);
   if (opt.Contains("c")) strcat (cmd," 0");
   if (opt.Contains("l")) strcat (cmd," 0");

   gSystem->Exec(cmd);

   if (opt.Contains("no")) return 0;
   TFile *f = new TFile(rfile);
   if (f->IsZombie()) {delete f; f = 0;}
   return f;
}


//______________________________________________________________________________
TObject *THbookFile::ConvertCWN(Int_t id)
{
// Convert the Column-Wise-Ntuple id to a Root Tree

  const int Nchar=9;
  int nvar;
  int i,j;
  int nsub,itype,isize,ielem;
  char *chtag_out;
  float rmin[1000], rmax[1000];

  if (id > 0) sprintf(idname,"h%d",id);
  else        sprintf(idname,"h_%d",-id);
  hnoent(id,nentries);
  //printf(" Converting CWN with ID= %d, nentries = %d\n",id,nentries);
  nvar=0;
#ifndef WIN32
  hgiven(id,chtitl,nvar,PASSCHAR(""),rmin[0],rmax[0],80,0);
#else
  hgiven(id,chtitl,80,nvar,PASSCHAR(""),rmin[0],rmax[0]);
#endif
  chtag_out = new char[nvar*Nchar+1];
  Int_t *charflag = new Int_t[nvar];
  Int_t *lenchar  = new Int_t[nvar];
  Int_t *boolflag = new Int_t[nvar];
  Int_t *lenbool  = new Int_t[nvar];
  UChar_t *boolarr = new UChar_t[10000];

  chtag_out[nvar*Nchar]=0;
  for (i=0;i<80;i++)chtitl[i]=0;
#ifndef WIN32
  hgiven(id,chtitl,nvar,chtag_out,rmin[0],rmax[0],80,Nchar);
#else
  hgiven(id,chtitl,80,nvar,chtag_out,Nchar,rmin[0],rmax[0]);
#endif

  Int_t bufpos = 0;
  Int_t isachar = 0;
  Int_t isabool = 0;
  char fullname[64];
  char name[32];
  char block[32];
  char oldblock[32];
  strcpy(oldblock,"OLDBLOCK");
  Int_t oldischar = -1;
  for (i=80;i>0;i--) {if (chtitl[i] == ' ') chtitl[i] = 0; }
  THbookTree *tree = new THbookTree(idname,id);
  tree->SetHbookFile(this);
  tree->SetType(1);

  char *bigbuf = tree->MakeX(500000);

  gTree = tree;
#ifndef WIN32
  hbnam(id,PASSCHAR(" "),bigbuf[0],PASSCHAR("$CLEAR"),0,1,6);
#else
  hbnam(id,PASSCHAR(" "),bigbuf[0],PASSCHAR("$CLEAR"),0);
#endif

  UInt_t varNumber = 0;
  Int_t golower  = 1;
  Int_t nbits = 0;
  for(i=0; i<nvar;i++) {
     memset(name,' ',sizeof(name));
     name[sizeof(name)-1] = 0;
     memset(block,' ',sizeof(block));
     block[sizeof(block)-1] = 0;
     memset(fullname,' ',sizeof(fullname));
     fullname[sizeof(fullname)-1]=0;
#ifndef WIN32
     hntvar2(id,i+1,PASSCHAR(name),PASSCHAR(fullname),PASSCHAR(block),nsub,itype,isize,nbits,ielem,32,64,32);
#else
     hntvar2(id,i+1,PASSCHAR(name),PASSCHAR(fullname),PASSCHAR(block),nsub,itype,isize,nbits,ielem);
#endif
     TString HbookName = name;

     for (j=30;j>0;j--) {
        if(golower) name[j] = tolower(name[j]);
        if (name[j] == ' ') name[j] = 0;
     }
     if (golower == 2) name[0] = tolower(name[0]);

     for (j=62;j>0;j--) {
        if(golower && fullname[j-1] != '[') fullname[j] = tolower(fullname[j]);
        // convert also character after [, if golower == 2
        if (golower == 2) fullname[j] = tolower(fullname[j]);
        if (fullname[j] == ' ') fullname[j] = 0;
     }
     // convert also first character, if golower == 2
     if (golower == 2) fullname[0] = tolower(fullname[0]);
     for (j=30;j>0;j--) {
        if (block[j] == ' ') block[j] = 0;
        else break;
     }
     if (itype == 1 && isize == 4) strcat(fullname,"/F");
     if (itype == 1 && isize == 8) strcat(fullname,"/D");
     if (itype == 2) strcat(fullname,"/I");
     if (itype == 3) strcat(fullname,"/i");
//     if (itype == 4) strcat(fullname,"/i");
     if (itype == 4) strcat(fullname,"/b");
     if (itype == 5) strcat(fullname,"/C");
//printf("Creating branch:%s, block:%s, fullname:%s, nsub=%d, itype=%d, isize=%d, ielem=%d, bufpos=%d\n",name,block,fullname,nsub,itype,isize,ielem,bufpos);
     Int_t ischar;
     if (itype == 5) ischar = 1;
     else            ischar = 0;

     if (ischar != oldischar || strcmp(oldblock,block) != 0) {
        varNumber = 0;
        strcpy(oldblock,block);
        oldischar = ischar;
        Long_t add= (Long_t)&bigbuf[bufpos];
        Int_t lblock   = strlen(block);
#ifndef WIN32
        hbnam(id,PASSCHAR(block),add,PASSCHAR("$SET"),ischar,lblock,4);
#else
        hbnam(id,PASSCHAR(block),add,PASSCHAR("$SET"),ischar);
#endif

     }

     Int_t bufsize = 8000;
     THbookBranch *branch = new THbookBranch(name,(void*)&bigbuf[bufpos],fullname,bufsize);
     tree->GetListOfBranches()->Add(branch);
     branch->SetBlockName(block);
     branch->SetUniqueID(varNumber);
     varNumber++;

     //NB: the information about isachar should be saved in the branch
     // to be done
     boolflag[i] = -10;
     charflag[i] = 0;
     if (itype == 4) {isabool++; boolflag[i] = bufpos; lenbool[i] = ielem;}
     bufpos += isize*ielem;
     if (ischar) {isachar++; charflag[i] = bufpos-1; lenchar[i] = isize*ielem;}
     TObjArray *ll= branch->GetListOfLeaves();
     TLeaf *leaf = (TLeaf*)ll->UncheckedAt(0);
     if (!leaf) continue;
     TLeafI *leafcount = (TLeafI*)leaf->GetLeafCount();
     if (leafcount) {
        if (leafcount->GetMaximum() <= 0) leafcount->SetMaximum(ielem);
     }
  }
  tree->SetEntries(nentries);
  delete [] charflag;
  delete [] lenchar;
  delete [] boolflag;
  delete [] lenbool;
  delete [] boolarr;
  delete [] chtag_out;

  return tree;
}

//______________________________________________________________________________
TObject *THbookFile::ConvertRWN(Int_t id)
{
// Convert the Row-Wise-Ntuple id to a Root Tree

  const int Nchar=9;
  int nvar;
  int i,j;
  char *chtag_out;
  float rmin[1000], rmax[1000];

  if (id > 0) sprintf(idname,"h%d",id);
  else        sprintf(idname,"h_%d",-id);
  hnoent(id,nentries);
  //printf(" Converting RWN with ID= %d, nentries = %d\n",id,nentries);
  nvar=0;
#ifndef WIN32
  hgiven(id,chtitl,nvar,PASSCHAR(""),rmin[0],rmax[0],80,0);
#else
  hgiven(id,chtitl,80,nvar,PASSCHAR(""),rmin[0],rmax[0]);
#endif

  chtag_out = new char[nvar*Nchar+1];

  Int_t golower  = 1;
  chtag_out[nvar*Nchar]=0;
  for (i=0;i<80;i++)chtitl[i]=0;
#ifndef WIN32
  hgiven(id,chtitl,nvar,chtag_out,rmin[0],rmax[0],80,Nchar);
#else
  hgiven(id,chtitl,80,nvar,chtag_out,Nchar,rmin[0],rmax[0]);
#endif
  hgnpar(id,"?",1);
  char *name = chtag_out;
  for (i=80;i>0;i--) {if (chtitl[i] == ' ') chtitl[i] = 0; }
  THbookTree *tree = new THbookTree(idname,id);
  tree->SetHbookFile(this);
  tree->SetType(0);
  gTree = tree;
  Float_t *x = (Float_t*)tree->MakeX(nvar*4);

  Int_t first,last;
  for(i=0; i<nvar;i++) {
    name[Nchar-1] = 0;
    first = last = 0;
    TString HbookName = name;
    // suppress trailing blanks
    for (j=Nchar-2;j>0;j--) {
       if(golower) name[j] = tolower(name[j]);
       if (name[j] == ' ' && last == 0) name[j] = 0;
       else last = j;
    }
    if (golower == 2) name[0] = tolower(name[0]);

    // suppress heading blanks
    for (j=0;j<Nchar;j++) {
       if (name[j] != ' ') break;
       first = j+1;
    }
    Int_t bufsize = 8000;
    //tree->Branch(&name[first],&x[i],&name[first],bufsize);
    THbookBranch *branch = new THbookBranch(&name[first],&x[4*i],&name[first],bufsize);
    branch->SetAddress(&x[i]);
    branch->SetBlockName(HbookName.Data());
    tree->GetListOfBranches()->Add(branch);
    name += Nchar;
  }
  tree->SetEntries(nentries);
  return tree;
}

//______________________________________________________________________________
TObject *THbookFile::ConvertProfile(Int_t id)
{
// Convert an Hbook profile histogram into a Root TProfile
//
// the following structure is used in Hbook
//    lcid points to the profile in array iq
//    lcont = lq(lcid-1)
//    lw    = lq(lcont)
//    ln    = lq(lw)
//      if option S jbyt(iq(lw),1,2) = 1
//      if option I jbyt(iq(lw),1,2) = 2

  if (id > 0) sprintf(idname,"h%d",id);
  else        sprintf(idname,"h_%d",-id);
  hnoent(id,nentries);
  Int_t lw = lq[lcont];
  Int_t ln = lq[lw];
#ifndef WIN32
  hgive(id,chtitl,ncx,xmin,xmax,ncy,ymin,ymax,nwt,idb,80);
#else
  hgive(id,chtitl,80,ncx,xmin,xmax,ncy,ymin,ymax,nwt,idb);
#endif
  Float_t offsetx = 0.5*(xmax-xmin)/ncx;
  chtitl[4*nwt] = 0;
  const char *option= " ";
  if (iq[lw] == 1) option = "S";
  if (iq[lw] == 2) option = "I";
  TProfile *p = new TProfile(idname,chtitl,ncx,xmin,xmax,ymin,ymax,option);

  const Int_t kCON1 = 9;
  Int_t i;
  Float_t x;
  Float_t y = 0.5*(ymin+ymax);
  for (i=1;i<=ncx;i++) {
     Int_t n = Int_t(q[ln+i]);
     hix(id,i,x);
     for (Int_t j=0;j<n;j++) {
        p->Fill(x+offsetx,y);
     }
     Float_t content = q[lcont+kCON1+i];
     Float_t error   = TMath::Sqrt(q[lw+i]);
     p->SetBinContent(i,content);
     p->SetBinError(i,error);
  }
  p->SetEntries(nentries);
  return p;
}

//______________________________________________________________________________
TObject *THbookFile::Convert1D(Int_t id)
{
// Convert an Hbook 1-d histogram into a Root TH1F

  if (id > 0) sprintf(idname,"h%d",id);
  else        sprintf(idname,"h_%d",-id);
  hnoent(id,nentries);
#ifndef WIN32
  hgive(id,chtitl,ncx,xmin,xmax,ncy,ymin,ymax,nwt,idb,80);
#else
  hgive(id,chtitl,80,ncx,xmin,xmax,ncy,ymin,ymax,nwt,idb);
#endif
  chtitl[4*nwt] = 0;
  TH1F *h1;
  Int_t i;
  if (hcbits[5]) {
     Int_t lbins = lq[lcid-2];
     Double_t *xbins = new Double_t[ncx+1];
     for (i=0;i<=ncx;i++) xbins[i] = q[lbins+i+1];
     h1 = new TH1F(idname,chtitl,ncx,xbins);
     delete [] xbins;
  } else {
     h1 = new TH1F(idname,chtitl,ncx,xmin,xmax);
  }
  if (hcbits[8]) h1->Sumw2();
  TGraph *gr = 0;
  if (hcbits[11]) {
     gr = new TGraph(ncx);
     h1->GetListOfFunctions()->Add(gr);
  }

  Float_t x;
  for (i=0;i<=ncx+1;i++) {
     x = h1->GetBinCenter(i);
     h1->Fill(x,hi(id,i));
     if (hcbits[8]) h1->SetBinError(i,hie(id,i));
     if (gr && i>0 && i<=ncx) gr->SetPoint(i,x,hif(id,i));
  }
  Float_t ymin, ymax;
  if (hcbits[19]) {
     ymax = q[lcid+kMAX1];
     h1->SetMaximum(ymax);
  }
  if (hcbits[20]) {
     ymin = q[lcid+kMIN1];
     h1->SetMinimum(ymin);
  }
  h1->SetEntries(nentries);
  return h1;
}

//______________________________________________________________________________
TObject *THbookFile::Convert2D(Int_t id)
{
// Convert an Hbook 2-d histogram into a Root TH2F

  if (id > 0) sprintf(idname,"h%d",id);
  else        sprintf(idname,"h_%d",-id);
  hnoent(id,nentries);
#ifndef WIN32
  hgive(id,chtitl,ncx,xmin,xmax,ncy,ymin,ymax,nwt,idb,80);
#else
  hgive(id,chtitl,80,ncx,xmin,xmax,ncy,ymin,ymax,nwt,idb);
#endif
  chtitl[4*nwt] = 0;
  TH2F *h2 = new TH2F(idname,chtitl,ncx,xmin,xmax,ncy,ymin,ymax);
  Float_t offsetx = 0.5*(xmax-xmin)/ncx;
  Float_t offsety = 0.5*(ymax-ymin)/ncy;
  Int_t lw = lq[lcont];
  if (lw) h2->Sumw2();

  Float_t x,y;
  for (Int_t j=0;j<=ncy+1;j++) {
     for (Int_t i=0;i<=ncx+1;i++) {
        hijxy(id,i,j,x,y);
        h2->Fill(x+offsetx,y+offsety,hij(id,i,j));
        if (lw) {
           Double_t err2 = hije(id,i,j);
           h2->SetCellError(i,j,err2);
        }
     }
  }
  h2->SetEntries(nentries);
  return h2;
}

//______________________________________________________________________________
void THbookFile::ls(const char *path) const
{
// List contents of Hbook directory

   Int_t nch = strlen(path);
   if (nch == 0) {
#ifndef WIN32
       hldir(PASSCHAR(fCurDir.Data()),PASSCHAR("T"),fCurDir.Length(),1);
#else
       hldir(PASSCHAR(fCurDir.Data()),PASSCHAR("T"));
#endif
       return;
   }

#ifndef WIN32
  hldir(PASSCHAR(path),PASSCHAR("T"),strlen(path),1);
#else
  hldir(PASSCHAR(path),PASSCHAR("T"));
#endif
}
