Re: Problem with the Streamer function of a class derived from TDirectory...

From: Pierre-Luc Drouin <pldrouin_at_physics.carleton.ca>
Date: Wed, 19 Mar 2008 21:20:49 -0400


Hi,

I got it mostly to work now by overloading Streamer, FillBuffer and WriteDirHeader functions. The only thing that is not working right now is that the name, the title and the mother of instances of my class are not set when loaded from a file. For TDirectoryFile instances, I have seen that these are set in the TKey::ReadObj function:

if (cl == TDirectoryFile <http://root.cern.ch/root/html/TDirectoryFile.html>::Class <http://root.cern.ch/root/html/TDirectoryFile.html#TDirectoryFile:Class>()) {

      TDirectory <http://root.cern.ch/root/html/TDirectory.html> *dir = dynamic_cast<TDirectoryFile <http://root.cern.ch/root/html/TDirectoryFile.html>*>(tobj);
      dir->SetName <http://root.cern.ch/root/html/TNamed.html#TNamed:SetName>(GetName <http://root.cern.ch/root/html/TNamed.html#TNamed:GetName>());
      dir->SetTitle <http://root.cern.ch/root/html/TNamed.html#TNamed:SetTitle>(GetTitle <http://root.cern.ch/root/html/TKey.html#TKey:GetTitle>());
      dir->SetMother(fMotherDir <http://root.cern.ch/root/html/TKey.html#TKey:fMotherDir>);
      fMotherDir <http://root.cern.ch/root/html/TKey.html#TKey:fMotherDir>->Append <http://root.cern.ch/root/html/TDirectory.html#TDirectory:Append>(dir);
   }

Is there a particular reason why this block of code is executed only for the TDirectoryFile class and not also for classes that are derived from TDirectoryFile? Because right now I don't see how else I could get a pointer to the mother directory...

Thanks!
Pierre-Luc

Philippe Canal wrote:
> Hi Pierre-Luc,
>
> The Streamer is not called when writing (it is done via FillBuffer
> instead).
>
>
>> What I want to do is to index the objects contined in a TDirectory
>> using a TObjArray in addition to the THashList.
>>
>
> Humm ... why? :) ... It might be easier to write an adapter class
> that is either created on the fly at read time and/or save in
> the TDirectory.
>
> Cheers,
> Philippe.
>
> -----Original Message-----
> From: Pierre-Luc Drouin [mailto:pldrouin_at_physics.carleton.ca]
> Sent: Wednesday, March 19, 2008 1:56 PM
> To: Philippe Canal
> Cc: 'Rene Brun'; roottalk_at_root.cern.ch
> Subject: Re: [ROOT] Problem with the Streamer function of a class derived
> from TDirectory...
>
> What I want to do is to index the objects contained in a TDirectory
> using a TObjArray in addition to the THashList.
>
> I have tried to implement my own Streamer function in my simple class
> (QMyDir), but for some reason it does not seam to be called when I open
> a file, create an instance of my class and then save the file. How is
> the Streamer function of TDirectoryFile called exactly (for writing)?
> When I look at the constructor of TDirectoryFile and at
> TDirectoryFile::Write, it seams that it is always FillBuffer that is
> called...
>
> Philippe Canal wrote:
>
>> Hi Pierre-Luc,
>>
>> Actually (sorry for the confusion) TDirectory(File) is very special
>> and overloading it require more updates that just the Streamer.
>> In your case, think are likely to work if you write a custom streamer
>> (i.e #pragma link C++ class QMyDir-; and implement the Streamer
>> function by hand) which _only_ forward the call to
>>
> TDirectoryFile::Streamer
>
>> (which should work somewhat since you do not have any member).
>>
>> Assumingly your intent is to add some member, in which case you would
>> have to at least overload FillBuffer and ReadKeys to take in consideration
>> the extra members.
>>
>> So, this begs the question :), what are you trying to achieve by
>>
> overloading
>
>> TDirectoryFile and is there a simplier mean to achieve it?
>>
>> Cheers,
>> Philippe.
>>
>> -----Original Message-----
>> From: Pierre-Luc Drouin [mailto:pldrouin_at_physics.carleton.ca]
>> Sent: Tuesday, March 18, 2008 10:50 AM
>> To: Philippe Canal
>> Cc: 'Rene Brun'; roottalk_at_root.cern.ch
>> Subject: Re: [ROOT] Problem with the Streamer function of a class derived
>> from TDirectory...
>>
>> I have modified my LinkDef file, recompiled everything, regenerated the
>> root file and I got the same error:
>>
>> Error in <TBufferFile::ReadBuffer2>: class: TUUID, attempting to access
>> a wrong version: 127, object skipped at offset 87
>> Error in <TFile::ReadBuffer>: error reading all requested bytes from
>> file file.root, got 0 of 2687036
>> (class TObject*)0x8346328
>>
>> The autogenerated code for the Streamer function is the following:
>>
>> void QMyDir::Streamer(TBuffer &R__b)
>> {
>> // Stream an object of class QMyDir.
>>
>> if (R__b.IsReading()) {
>> R__b.ReadClassBuffer(QMyDir::Class(),this);
>> } else {
>> R__b.WriteClassBuffer(QMyDir::Class(),this);
>> }
>> }
>>
>> Thank you
>> Pierre-Luc Drouin
>>
>> Philippe Canal wrote:
>>
>>
>>> Hi Pierre-Luc,
>>>
>>> Can you try after enabling the new I/O?
>>> i.e:
>>> #pragma link C++ class QMyDir+;
>>>
>>>
>>> Cheers,
>>> Philippe.
>>>
>>> -----Original Message-----
>>> From: owner-roottalk_at_root.cern.ch [mailto:owner-roottalk_at_root.cern.ch] On
>>> Behalf Of Pierre-Luc Drouin
>>> Sent: Tuesday, March 18, 2008 10:27 AM
>>> To: Rene Brun
>>> Cc: roottalk_at_root.cern.ch
>>> Subject: Re: [ROOT] Problem with the Streamer function of a class derived
>>> from TDirectory...
>>>
>>> Hi,
>>>
>>> I have installed 5.18/00 (I was using 5.14/00e before) and I have
>>> derived my class from TDirectoryFile. The code of my class is now the
>>> following:
>>>
>>> #include "Rtypes.h"
>>> #include "TObject.h"
>>> #include "TDirectoryFile.h"
>>>
>>> class QMyDir: public TDirectoryFile
>>> {
>>> public:
>>> QMyDir():TDirectoryFile(){}
>>>
>>> QMyDir(const QMyDir& newqds):TDirectoryFile(){}
>>>
>>> QMyDir(const char *name, const char *title, TDirectory* motherDir =
>>> 0):TDirectoryFile(name,title,"QMyDir",motherDir){}
>>>
>>> virtual ~QMyDir(){}
>>>
>>> QMyDir& operator=(const QMyDir &rhs){fprintf(stderr,"Warning:
>>> TDirectoryFile::operator= cannot be called from derived class
>>> QMyDir\n"); return *this;}
>>>
>>> private:
>>>
>>> ClassDef(QMyDir,1) //QSigEx Data Structure Class
>>> };
>>>
>>> I still get an error when I try to load the instance from the file. I
>>> have stored and have tried to load the instance using the code I have
>>> shown in my previous email. Here is the error I get:
>>>
>>> _file0->Get("dir")
>>> Error in <TBufferFile::ReadBuffer2>: class: TUUID, attempting to access
>>> a wrong version: 127, object skipped at offset 87
>>> Error in <TFile::ReadBuffer>: error reading all requested bytes from
>>> file file.root, got 0 of 2687036
>>> (class TObject*)0x8345fa8
>>>
>>> Thank you
>>> Pierre-Luc Drouin
>>>
>>> Rene Brun wrote:
>>>
>>>
>>>
>>>> Pierre-Luc,
>>>>
>>>> Instead of TDirectory, you should derive from TDirectoryFile. In
>>>> version 5.16, TDirectory
>>>> became an abstract interface. See 5.16 Release Notes at:
>>>> http://root.cern.ch/root/Version516.news.html
>>>>
>>>> Rene Brun
>>>>
>>>> Pierre-Luc Drouin wrote:
>>>>
>>>>
>>>>
>>>>> Hi,
>>>>>
>>>>> I have derived a class from TDirectory and I am trying to store and
>>>>> retrieve an instance of this class to/from a ROOT file.
>>>>>
>>>>> I am using the autogenerated Streamer function and when I call
>>>>> TDirectory
>>>>> <http://root.cern.ch/root/html514/src/TDirectory.cxx.html#OUS8P>(const
>>>>> char *name, const char *title, Option_t
>>>>> <http://root.cern.ch/root/html514/ListOfTypes.html#Option_t>
>>>>> *classname, TDirectory
>>>>> <http://root.cern.ch/root/html514/TDirectory.html>* initMotherDir)
>>>>> from the constructor of my class, I set classname to the name of my
>>>>> class.
>>>>>
>>>>> I do not get any warning/error message when I Write the instance in
>>>>> the root file, but I get the following error when I try to load the
>>>>> instance using TFile::Get:
>>>>>
>>>>> Error in <TBuffer::ReadVersion>: Could not find the StreamerInfo with
>>>>> a checksum of 0 for the class "TUUID" in file.root.
>>>>> Error in <TBuffer::CheckByteCount>: object of class TUUID read too
>>>>> few bytes: 22 instead of 898023151
>>>>> Error in <TBuffer::CheckByteCount>: Byte count probably corrupted
>>>>> around buffer position 85:
>>>>> 898023151 for a possible maximum of 17
>>>>> SysError in <TFile::Seek>: cannot seek to position 60235645022633984
>>>>> in file file.root, retpos=-1 (Invalid argument)
>>>>> Error in <TFile::ReadBuffer>: error reading all requested bytes from
>>>>> file file.root, got 186 of 2687036
>>>>>
>>>>> Here is the code of a class that allows to reproduce the problem:
>>>>>
>>>>> class QMyDir: public TDirectory
>>>>> {
>>>>> public:
>>>>> QMyDir():TDirectory(){}
>>>>>
>>>>> QMyDir(const QMyDir& newqds):TDirectory(){*this=newqds; }
>>>>>
>>>>> QMyDir(const char *name, const char *title, TDirectory* motherDir
>>>>> = 0):TDirectory(name,title,"QMyDir",motherDir){}
>>>>>
>>>>> virtual ~QMyDir(){}
>>>>>
>>>>> QMyDir& operator=(const QMyDir &rhs){fprintf(stderr,"Warning:
>>>>> TDirectory::operator= function is private and cannot be called by
>>>>> derived class QMyDir\n"); return *this;}
>>>>>
>>>>> private:
>>>>>
>>>>> ClassDef(QMyDir,1) //QSigEx Data Structure Class
>>>>> };
>>>>>
>>>>> Here is the code of the autogenerated Streamer function:
>>>>>
>>>>> void QMyDir::Streamer(TBuffer &R__b)
>>>>> {
>>>>> // Stream an object of class QMyDir.
>>>>>
>>>>> UInt_t R__s, R__c;
>>>>> if (R__b.IsReading()) {
>>>>> Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
>>>>> TDirectory::Streamer(R__b);
>>>>> R__b.CheckByteCount(R__s, R__c, QMyDir::IsA());
>>>>> } else {
>>>>> R__c = R__b.WriteVersion(QMyDir::IsA(), kTRUE);
>>>>> TDirectory::Streamer(R__b);
>>>>> R__b.SetByteCount(R__c, kTRUE);
>>>>> } }
>>>>>
>>>>> Now how I get the error in CINT:
>>>>>
>>>>> root [0] TFile file("file.root","recreate")
>>>>> root [1] QMyDir* dir=new QMyDir("dir","dir")
>>>>> root [2] file.ls()
>>>>> TFile** file.root
>>>>> TFile* file.root
>>>>> QMyDir* dir dir
>>>>> KEY: QMyDir dir;1 dir
>>>>> root [3] file.Write()
>>>>> (Int_t)0
>>>>> root [4] file.Close()
>>>>> root [5] .q
>>>>>
>>>>> root [0] TFile file("file.root","read")
>>>>> root [1] file.ls()
>>>>> TFile** file.root
>>>>> TFile* file.root
>>>>> KEY: QMyDir dir;1 dir
>>>>> root [2] QMyDir *dir=file.Get("dir")
>>>>> Error in <TBuffer::ReadVersion>: Could not find the StreamerInfo with
>>>>> a checksum of 0 for the class "TUUID" in file.root.
>>>>> Error in <TBuffer::CheckByteCount>: object of class TUUID read too
>>>>> few bytes: 22 instead of 898023151
>>>>> Error in <TBuffer::CheckByteCount>: Byte count probably corrupted
>>>>> around buffer position 85:
>>>>> 898023151 for a possible maximum of 17
>>>>> SysError in <TFile::Seek>: cannot seek to position 60235645022633984
>>>>> in file file.root, retpos=-1 (Invalid argument)
>>>>> Error in <TFile::ReadBuffer>: error reading all requested bytes from
>>>>> file file.root, got 186 of 2687036
>>>>>
>>>>>
>>>>> Thanks!
>>>>> Pierre-Luc Drouin
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>
>>>
>>>
>>
>>
>
>
>
Received on Thu Mar 20 2008 - 02:21:08 CET

This archive was generated by hypermail 2.2.0 : Thu Mar 20 2008 - 11:50:01 CET