// @(#)root/xml:$Name: $:$Id: TXMLPlayer.cxx,v 1.8 2005/09/06 09:34:48 brun Exp $
// Author: Sergey Linev, Rene Brun 10.05.2004
/*************************************************************************
* 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. *
*************************************************************************/
//________________________________________________________________________
//
// Class for xml code generation
// It should be used for generation of xml steramers, which could be used outside root
// enviroment. This means, that with help of such streamers user can read and write
// objects from/to xml file, which later can be accepted by ROOT.
//
// At the moment supported only classes, which are not inherited from TObject
// and which not contains any TObject members.
//
// To generate xml code:
//
// 1. ROOT library with required classes should be created.
// In general, without such library non of user objects can be stored and
// retrived from any ROOT file
//
// 2. Generate xml streamers by root script like:
//
// void generate() {
// gSystem->Load("libRXML.so"); // load ROOT xml library
// gSystem->Load("libuser.so"); // load user ROOT library
//
// TList lst;
// lst.Add(gROOT->GetClass("TUserClass1"));
// lst.Add(gROOT->GetClass("TUserClass2"));
// ...
// TXMLPlayer player;
// player.ProduceCode(&lst, "streamers"); // create xml streamers
// }
//
// 3. Copy "streamers.h", "streamers.cxx", "TXmlFile.h", "TXmlFile.cxx" files
// to user project and compile them. TXmlFile class implementation can be taken
// from http://www-linux.gsi.de/~linev/xmlfile.tar.gz
//
// TXMLPlayer class generates one function per class, which called class streamer.
// Name of such function for class TExample will be TExample_streamer.
//
// Following data members for streamed classes are supported:
// - simple data types (int, double, float)
// - array of simple types (int[5], double[5][6])
// - dynamic array of simple types (int* with comment field // [fSize])
// - const char*
// - object of any nonROOT class
// - pointer on object
// - array of objects
// - array of pointers on objects
// - stl string
// - stl vector, list, deque, set, multiset, map, multimap
// - allowed arguments for stl containers are: simple data types, string, object, pointer on object
// Any other data member can not be (yet) read from xml file and write to xml file.
//
// If data member of class is private or protected, it can not be accessed via
// member name. Two alternative way is supported. First, if for class member fValue
// exists function GetValue(), it will be used to get value from the class, and if
// exists SetValue(), it will be used to set apropriate data member. Names of setter
// and getter methods can be specified in comments filed like:
//
// int fValue; // *OPTION={GetMethod="GetV";SetMethod="SetV"}
//
// If getter or setter methods does not available, address to data member will be
// calculated as predefined offeset to object start address. In that case generated code
// should be used only on the same platform (OS + compiler), where it was generated.
//
// Generated streamers resolve inheritance tree for given class. This allows to have
// array (or vector) of object pointers on some basic class, while objects of derived
// class(es) are used.
//
// To access data from xml files, user should use TXmlFile class, which is different from
// ROOT TXMLFile, but provides very similar functionality. For example, to read
// object from xml file:
//
// TXmlFile file("test.xml"); // open xml file
// file.ls(); // show list of keys in file
// TExample* ex1 = (TExample*) file.Get("ex1", TExample_streamer); // get object
// file.Close();
//
// To write object to file:
//
// TXmlFile outfile("test2.xml", "recreate"); // create xml file
// TExample* ex1 = new TExample;
// outfile.Write(ex1, "ex1", TExample_streamer); // write object to file
// outfile.Close();
//
// Complete example for generating and using of external xml streamers can be taken from
// http://www-linux.gsi.de/~linev/xmlreader.tar.gz
//
// Any bug reports and requests for additional functionality are welcome.
//
// Sergey Linev, S.Linev@gsi.de
//
//________________________________________________________________________
#include "TXMLPlayer.h"
#include "Riostream.h"
#include "TClass.h"
#include "TStreamerInfo.h"
#include "TStreamerElement.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TDataMember.h"
#include "TMethod.h"
#include "TDataType.h"
#include "TMethodCall.h"
#include "TFunction.h"
#include "TVirtualCollectionProxy.h"
#include "TClassEdit.h"
#include <string>
#include <vector>
const char* tab1 = " ";
const char* tab2 = " ";
const char* tab3 = " ";
const char* tab4 = " ";
const char* names_xmlfileclass = "TXmlFile";
ClassImp(TXMLPlayer);
//______________________________________________________________________________
TXMLPlayer::TXMLPlayer() : TObject()
{
// default constructor
}
//______________________________________________________________________________
TXMLPlayer::~TXMLPlayer()
{
// destructor of TXMLPlayer object
}
//______________________________________________________________________________
TString TXMLPlayer::GetStreamerName(TClass* cl)
{
// returns streamer function name for given class
if (cl==0) return "";
TString res = cl->GetName();
res += "_streamer";
return res;
}
//______________________________________________________________________________
Bool_t TXMLPlayer::ProduceCode(TList* cllist, const char* filename)
{
// Produce streamers for provide class list
// TList should include list of classes, for which code should be generated.
// filename specify name of file (without extension), where streamers should be
// created. Function produces two files: header file and source file.
// For instance, if filename is "streamers", files "streamers.h" and "streamers.cxx"
// will be created.
if ((cllist==0) || (filename==0)) return kFALSE;
ofstream fh(TString(filename)+".h");
ofstream fs(TString(filename)+".cxx");
fh << "// generated header file" << endl << endl;
fh << "#ifndef " << filename << "_h" << endl;
fh << "#define " << filename << "_h" << endl << endl;
fh << "#include \"" << names_xmlfileclass << ".h\"" << endl << endl;
fs << "// generated source file" << endl << endl;
fs << "#include \"" << filename << ".h\"" << endl << endl;
// produce appropriate include for all classes
TObjArray inclfiles;
TIter iter(cllist);
TClass* cl = 0;
while ((cl = (TClass*) iter()) != 0) {
if (inclfiles.FindObject(cl->GetDeclFileName())==0) {
fs << "#include \"" << cl->GetDeclFileName() << "\"" << endl;
inclfiles.Add(new TNamed(cl->GetDeclFileName(),""));
}
}
inclfiles.Delete();
fh << endl;
fs << endl;
// produce streamers declarations and implementations
iter.Reset();
while ((cl = (TClass*) iter()) != 0) {
fh << "extern void* " << GetStreamerName(cl) << "("
<< names_xmlfileclass << " &buf, void* ptr = 0, bool checktypes = true);" << endl << endl;
ProduceStreamerSource(fs, cl, cllist);
}
fh << "#endif" << endl << endl;
fs << endl << endl;
return kTRUE;
}
//______________________________________________________________________________
TString TXMLPlayer::GetMemberTypeName(TDataMember* member)
{
// returns name of simple data type for given data member
if (member==0) return "int";
if (member->IsBasic())
switch (member->GetDataType()->GetType()) {
case kChar_t: return "char";
case kShort_t: return "short";
case kInt_t: return "int";
case kLong_t: return "long";
case kLong64_t: return "long long";
case kFloat_t: return "float";
case kDouble32_t:
case kDouble_t: return "double";
case kUChar_t: {
char first = member->GetDataType()->GetTypeName()[0];
if ((first=='B') || (first=='b')) return "bool";
else return "unsigned char";
}
case kBool_t: return "bool";
case kUShort_t: return "unsigned short";
case kUInt_t: return "unsigned int";
case kULong_t: return "unsigned long";
case kULong64_t: return "unsigned long long";
}
if (member->IsEnum()) return "int";
return member->GetTypeName();
}
//______________________________________________________________________________
TString TXMLPlayer::GetBasicTypeName(TStreamerElement* el)
{
// return simple data types for given TStreamerElement object
if (el->GetType() == TStreamerInfo::kCounter) return "int";
switch (el->GetType() % 20) {
case TStreamerInfo::kChar: return "char";
case TStreamerInfo::kShort: return "short";
case TStreamerInfo::kInt: return "int";
case TStreamerInfo::kLong: return "long";
case TStreamerInfo::kLong64: return "long long";
case TStreamerInfo::kFloat: return "float";
case TStreamerInfo::kDouble32:
case TStreamerInfo::kDouble: return "double";
case TStreamerInfo::kUChar: {
char first = el->GetTypeNameBasic()[0];
if ((first=='B') || (first=='b')) return "bool";
else return "unsigned char";
}
case TStreamerInfo::kBool: return "bool";
case TStreamerInfo::kUShort: return "unsigned short";
case TStreamerInfo::kUInt: return "unsigned int";
case TStreamerInfo::kULong: return "unsigned long";
case TStreamerInfo::kULong64: return "unsigned long long";
}
return "int";
}
//______________________________________________________________________________
TString TXMLPlayer::GetBasicTypeReaderMethodName(Int_t type, const char* realname)
{
// return functions name to read simple data type from xml file
if (type == TStreamerInfo::kCounter) return "ReadInt";
switch (type % 20) {
case TStreamerInfo::kChar: return "ReadChar";
case TStreamerInfo::kShort: return "ReadShort";
case TStreamerInfo::kInt: return "ReadInt";
case TStreamerInfo::kLong: return "ReadLong";
case TStreamerInfo::kLong64: return "ReadLong64";
case TStreamerInfo::kFloat: return "ReadFloat";
case TStreamerInfo::kDouble32:
case TStreamerInfo::kDouble: return "ReadDouble";
case TStreamerInfo::kUChar: {
Bool_t isbool = false;
if (realname!=0)
isbool = (TString(realname).Index("bool",0, TString::kIgnoreCase)>=0);
if (isbool) return "ReadBool";
else return "ReadUChar";
}
case TStreamerInfo::kBool: return "ReadBool";
case TStreamerInfo::kUShort: return "ReadUShort";
case TStreamerInfo::kUInt: return "ReadUInt";
case TStreamerInfo::kULong: return "ReadULong";
case TStreamerInfo::kULong64: return "ReadULong64";
}
return "ReadValue";
}
//______________________________________________________________________________
const char* TXMLPlayer::ElementGetter(TClass* cl, const char* membername, int specials)
{
// produce code to access member of given class.
// Parameter specials has following meaning:
// 0 - nothing special
// 1 - cast to data type
// 2 - produce pointer on given member
// 3 - skip casting when produce pointer by buf.P() function
TClass* membercl = cl ? cl->GetBaseDataMember(membername) : 0;
TDataMember* member = membercl ? membercl->GetDataMember(membername) : 0;
TMethodCall* mgetter = member ? member->GetterMethod(0) : 0;
if ((mgetter!=0) && (mgetter->GetMethod()->Property() & kIsPublic)) {
fGetterName = "obj->";
fGetterName += mgetter->GetMethodName();
fGetterName += "()";
} else
if ((member==0) || ((member->Property() & kIsPublic) != 0)) {
fGetterName = "obj->";
fGetterName += membername;
} else {
fGetterName = "";
Bool_t deref = (member->GetArrayDim()==0) && (specials!=2);
if (deref) fGetterName += "*(";
if (specials!=3) {
fGetterName += "(";
if (member->Property() & kIsConstant) fGetterName += "const ";
fGetterName += GetMemberTypeName(member);
if (member->IsaPointer()) fGetterName+="*";
fGetterName += "*) ";
}
fGetterName += "buf.P(obj,";
fGetterName += member->GetOffset();
fGetterName += ")";
if (deref) fGetterName += ")";
specials = 0;
}
if ((specials==1) && (member!=0)) {
TString cast = "(";
cast += GetMemberTypeName(member);
if (member->IsaPointer() || (member->GetArrayDim()>0)) cast += "*";
cast += ") ";
cast += fGetterName;
fGetterName = cast;
}
if ((specials==2) && (member!=0)) {
TString buf = "&(";
buf += fGetterName;
buf += ")";
fGetterName = buf;
}
return fGetterName.Data();
}
//______________________________________________________________________________
const char* TXMLPlayer::ElementSetter(TClass* cl, const char* membername, char* endch)
{
// Produce code to set value to given data member.
// endch should be output after value is specified.
strcpy(endch,"");
TClass* membercl = cl ? cl->GetBaseDataMember(membername) : 0;
TDataMember* member = membercl ? membercl->GetDataMember(membername) : 0;
TMethodCall* msetter = member ? member->SetterMethod(cl) : 0;
if ((msetter!=0) && (msetter->GetMethod()->Property() & kIsPublic)) {
fSetterName = "obj->";
fSetterName += msetter->GetMethodName();
fSetterName += "(";
strcpy(endch,")");
} else
if ((member==0) || (member->Property() & kIsPublic) != 0) {
fSetterName = "obj->";
fSetterName += membername;
fSetterName += " = ";
} else {
fSetterName = "";
if (member->GetArrayDim()==0) fSetterName += "*";
fSetterName += "((";
if (member->Property() & kIsConstant) fSetterName += "const ";
fSetterName += GetMemberTypeName(member);
if (member->IsaPointer()) fSetterName += "*";
fSetterName += "*) buf.P(obj,";
fSetterName += member->GetOffset();
fSetterName += ")) = ";
}
return fSetterName.Data();
}
//______________________________________________________________________________
void TXMLPlayer::ProduceStreamerSource(ostream& fs, TClass* cl, TList* cllist)
{
// Produce source code of streamer function for specified class
if (cl==0) return;
TStreamerInfo* info = cl->GetStreamerInfo();
TObjArray* elements = info->GetElements();
if (elements==0) return;
fs << "//__________________________________________________________________________" << endl;
fs << "void* " << GetStreamerName(cl) << "("
<< names_xmlfileclass << " &buf, void* ptr, bool checktypes)" << endl;
fs << "{" << endl;
fs << tab1 << cl->GetName() << " *obj = (" << cl->GetName() << "*) ptr;" << endl;
fs << tab1 << "if (buf.IsReading()) { " << endl;
TIter iter(cllist);
TClass* c1 = 0;
Bool_t firstchild = true;
while ((c1 = (TClass*) iter()) != 0) {
if (c1==cl) continue;
if (c1->GetListOfBases()->FindObject(cl->GetName())==0) continue;
if (firstchild) {
fs << tab2 << "if (checktypes) {" << endl;
fs << tab3 << "void* ";
firstchild = false;
} else
fs << tab3;
fs << "res = " << GetStreamerName(c1)
<< "(buf, dynamic_cast<" << c1->GetName() << "*>(obj));" << endl;
fs << tab3 << "if (res) return dynamic_cast<" << cl->GetName()
<< "*>(("<< c1->GetName() << " *) res);" << endl;
}
if (!firstchild) fs << tab2 << "}" << endl;
fs << tab2 << "if (!buf.CheckClassNode(\"" << cl->GetName() << "\", "
<< info->GetClassVersion() << ")) return 0;" << endl;
fs << tab2 << "if (obj==0) obj = new " << cl->GetName() << ";" << endl;
int n;
for (n=0;n<=elements->GetLast();n++) {
TStreamerElement* el = dynamic_cast<TStreamerElement*> (elements->At(n));
if (el==0) continue;
Int_t typ = el->GetType();
switch (typ) {
// basic types
case TStreamerInfo::kBool:
case TStreamerInfo::kChar:
case TStreamerInfo::kShort:
case TStreamerInfo::kInt:
case TStreamerInfo::kLong:
case TStreamerInfo::kLong64:
case TStreamerInfo::kFloat:
case TStreamerInfo::kDouble:
case TStreamerInfo::kUChar:
case TStreamerInfo::kUShort:
case TStreamerInfo::kUInt:
case TStreamerInfo::kULong:
case TStreamerInfo::kULong64:
case TStreamerInfo::kDouble32:
case TStreamerInfo::kCounter: {
char endch[5];
fs << tab2 << ElementSetter(cl, el->GetName(), endch);
fs << "buf." << GetBasicTypeReaderMethodName(el->GetType(), 0)
<< "(\"" << el->GetName() << "\")" << endch << ";" << endl;
continue;
}
// array of basic types like bool[10]
case TStreamerInfo::kOffsetL + TStreamerInfo::kBool:
case TStreamerInfo::kOffsetL + TStreamerInfo::kChar:
case TStreamerInfo::kOffsetL + TStreamerInfo::kShort:
case TStreamerInfo::kOffsetL + TStreamerInfo::kInt:
case TStreamerInfo::kOffsetL + TStreamerInfo::kLong:
case TStreamerInfo::kOffsetL + TStreamerInfo::kLong64:
case TStreamerInfo::kOffsetL + TStreamerInfo::kFloat:
case TStreamerInfo::kOffsetL + TStreamerInfo::kDouble:
case TStreamerInfo::kOffsetL + TStreamerInfo::kUChar:
case TStreamerInfo::kOffsetL + TStreamerInfo::kUShort:
case TStreamerInfo::kOffsetL + TStreamerInfo::kUInt:
case TStreamerInfo::kOffsetL + TStreamerInfo::kULong:
case TStreamerInfo::kOffsetL + TStreamerInfo::kULong64:
case TStreamerInfo::kOffsetL + TStreamerInfo::kDouble32: {
fs << tab2 << "buf.ReadArray("
<< ElementGetter(cl, el->GetName(), (el->GetArrayDim()>1) ? 1 : 0);
fs << ", " << el->GetArrayLength()
<< ", \"" << el->GetName() << "\");" << endl;
continue;
}
// array of basic types like bool[n]
case TStreamerInfo::kOffsetP + TStreamerInfo::kBool:
case TStreamerInfo::kOffsetP + TStreamerInfo::kChar:
case TStreamerInfo::kOffsetP + TStreamerInfo::kShort:
case TStreamerInfo::kOffsetP + TStreamerInfo::kInt:
case TStreamerInfo::kOffsetP + TStreamerInfo::kLong:
case TStreamerInfo::kOffsetP + TStreamerInfo::kLong64:
case TStreamerInfo::kOffsetP + TStreamerInfo::kFloat:
case TStreamerInfo::kOffsetP + TStreamerInfo::kDouble:
case TStreamerInfo::kOffsetP + TStreamerInfo::kUChar:
case TStreamerInfo::kOffsetP + TStreamerInfo::kUShort:
case TStreamerInfo::kOffsetP + TStreamerInfo::kUInt:
case TStreamerInfo::kOffsetP + TStreamerInfo::kULong:
case TStreamerInfo::kOffsetP + TStreamerInfo::kULong64:
case TStreamerInfo::kOffsetP + TStreamerInfo::kDouble32: {
TStreamerBasicPointer* elp = dynamic_cast<TStreamerBasicPointer*> (el);
if (elp==0) {
cout << "fatal error with TStreamerBasicPointer" << endl;
continue;
}
char endch[5];
fs << tab2 << ElementSetter(cl, el->GetName(), endch);
fs << "buf.ReadArray(" << ElementGetter(cl, el->GetName());
fs << ", " << ElementGetter(cl, elp->GetCountName());
fs << ", \"" << el->GetName() << "\", true)" << endch << ";" << endl;
continue;
}
case TStreamerInfo::kCharStar: {
char endch[5];
fs << tab2 << ElementSetter(cl, el->GetName(), endch);
fs << "buf.ReadCharStar(" << ElementGetter(cl, el->GetName());
fs << ", \"" << el->GetName() << "\")" << endch << ";" << endl;
continue;
}
case TStreamerInfo::kBase: {
fs << tab2 << GetStreamerName(el->GetClassPointer())
<< "(buf, dynamic_cast<" << el->GetClassPointer()->GetName()
<< "*>(obj), false);" << endl;
continue;
}
// Class* Class not derived from TObject and with comment field //->
case TStreamerInfo::kAnyp:
case TStreamerInfo::kAnyp + TStreamerInfo::kOffsetL: {
if (el->GetArrayLength()>0) {
fs << tab2 << "buf.ReadObjectArr(" << ElementGetter(cl, el->GetName());
fs << ", " << el->GetArrayLength() << ", -1"
<< ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
} else {
fs << tab2 << "buf.ReadObject(" << ElementGetter(cl, el->GetName());
fs << ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
}
continue;
}
// Class* Class not derived from TObject and no comment
case TStreamerInfo::kAnyP:
case TStreamerInfo::kAnyP + TStreamerInfo::kOffsetL: {
if (el->GetArrayLength()>0) {
fs << tab2 << "for (int n=0;n<" << el->GetArrayLength() << ";n++) "
<< "delete (" << ElementGetter(cl, el->GetName()) << ")[n];" << endl;
fs << tab2 << "buf.ReadObjectPtrArr((void**) " << ElementGetter(cl, el->GetName(), 3);
fs << ", " << el->GetArrayLength()
<< ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
} else {
char endch[5];
fs << tab2 << "delete " << ElementGetter(cl, el->GetName()) << ";" << endl;
fs << tab2 << ElementSetter(cl, el->GetName(), endch);
fs << "(" << el->GetClassPointer()->GetName()
<< "*) buf.ReadObjectPtr(\"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer())
<< ")" <<endch << ";" << endl;
}
continue;
}
// Class NOT derived from TObject
case TStreamerInfo::kAny: {
fs << tab2 << "buf.ReadObject(" << ElementGetter(cl, el->GetName(), 2);
fs << ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
continue;
}
// Class NOT derived from TObject, array
case TStreamerInfo::kAny + TStreamerInfo::kOffsetL: {
fs << tab2 << "buf.ReadObjectArr(" << ElementGetter(cl, el->GetName());
fs << ", " << el->GetArrayLength()
<< ", sizeof(" << el->GetClassPointer()->GetName()
<< "), \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
continue;
}
// container with no virtual table (stl) and no comment
case TStreamerInfo::kSTLp:
case TStreamerInfo::kSTL:
case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL:
case TStreamerInfo::kSTL + TStreamerInfo::kOffsetL: {
TStreamerSTL* elstl = dynamic_cast<TStreamerSTL*> (el);
if (elstl==0) break; // to make skip
if (ProduceSTLstreamer(fs, cl, elstl, false)) continue;
fs << tab2 << "// STL type = " << elstl->GetSTLtype() << endl;
break;
}
}
fs << tab2 << "buf.SkipMember(\"" << el->GetName()
<< "\"); // sinfo type " << el->GetType()
<< " of class " << el->GetClassPointer()->GetName()
<< " not supported" << endl;
}
fs << tab2 << "buf.EndClassNode();" << endl;
fs << tab1 << "} else {" << endl;
// generation of writing part of class streamer
fs << tab2 << "if (obj==0) return 0;" << endl;
firstchild = true;
iter.Reset();
while ((c1 = (TClass*) iter()) != 0) {
if (c1==cl) continue;
if (c1->GetListOfBases()->FindObject(cl->GetName())==0) continue;
if (firstchild) {
firstchild = false;
fs << tab2 << "if (checktypes) {" << endl;
}
fs << tab3 << "if (dynamic_cast<" << c1->GetName() << "*>(obj))" << endl;
fs << tab4 << "return " << GetStreamerName(c1) << "(buf, dynamic_cast<" << c1->GetName() << "*>(obj));" << endl;
}
if (!firstchild) fs << tab2 << "}" << endl;
fs << tab2 << "buf.StartClassNode(\"" << cl->GetName() << "\", "
<< info->GetClassVersion() << ");" << endl;
for (n=0;n<=elements->GetLast();n++) {
TStreamerElement* el = dynamic_cast<TStreamerElement*> (elements->At(n));
if (el==0) continue;
Int_t typ = el->GetType();
switch (typ) {
// write basic types
case TStreamerInfo::kBool:
case TStreamerInfo::kChar:
case TStreamerInfo::kShort:
case TStreamerInfo::kInt:
case TStreamerInfo::kLong:
case TStreamerInfo::kLong64:
case TStreamerInfo::kFloat:
case TStreamerInfo::kDouble:
case TStreamerInfo::kUChar:
case TStreamerInfo::kUShort:
case TStreamerInfo::kUInt:
case TStreamerInfo::kULong:
case TStreamerInfo::kULong64:
case TStreamerInfo::kDouble32:
case TStreamerInfo::kCounter: {
fs << tab2 << "buf.WriteValue(";
if (typ==TStreamerInfo::kUChar)
fs <<"(unsigned char) " << ElementGetter(cl, el->GetName());
else
fs << ElementGetter(cl, el->GetName());
fs << ", \"" << el->GetName() << "\");" << endl;
continue;
}
// array of basic types
case TStreamerInfo::kOffsetL + TStreamerInfo::kBool:
case TStreamerInfo::kOffsetL + TStreamerInfo::kChar:
case TStreamerInfo::kOffsetL + TStreamerInfo::kShort:
case TStreamerInfo::kOffsetL + TStreamerInfo::kInt:
case TStreamerInfo::kOffsetL + TStreamerInfo::kLong:
case TStreamerInfo::kOffsetL + TStreamerInfo::kLong64:
case TStreamerInfo::kOffsetL + TStreamerInfo::kFloat:
case TStreamerInfo::kOffsetL + TStreamerInfo::kDouble:
case TStreamerInfo::kOffsetL + TStreamerInfo::kUChar:
case TStreamerInfo::kOffsetL + TStreamerInfo::kUShort:
case TStreamerInfo::kOffsetL + TStreamerInfo::kUInt:
case TStreamerInfo::kOffsetL + TStreamerInfo::kULong:
case TStreamerInfo::kOffsetL + TStreamerInfo::kULong64:
case TStreamerInfo::kOffsetL + TStreamerInfo::kDouble32: {
fs << tab2 << "buf.WriteArray("
<< ElementGetter(cl, el->GetName(), (el->GetArrayDim()>1) ? 1 : 0);
fs << ", " << el->GetArrayLength()
<< ", \"" << el->GetName() << "\");" << endl;
continue;
}
case TStreamerInfo::kOffsetP + TStreamerInfo::kBool:
case TStreamerInfo::kOffsetP + TStreamerInfo::kChar:
case TStreamerInfo::kOffsetP + TStreamerInfo::kShort:
case TStreamerInfo::kOffsetP + TStreamerInfo::kInt:
case TStreamerInfo::kOffsetP + TStreamerInfo::kLong:
case TStreamerInfo::kOffsetP + TStreamerInfo::kLong64:
case TStreamerInfo::kOffsetP + TStreamerInfo::kFloat:
case TStreamerInfo::kOffsetP + TStreamerInfo::kDouble:
case TStreamerInfo::kOffsetP + TStreamerInfo::kUChar:
case TStreamerInfo::kOffsetP + TStreamerInfo::kUShort:
case TStreamerInfo::kOffsetP + TStreamerInfo::kUInt:
case TStreamerInfo::kOffsetP + TStreamerInfo::kULong:
case TStreamerInfo::kOffsetP + TStreamerInfo::kULong64:
case TStreamerInfo::kOffsetP + TStreamerInfo::kDouble32: {
TStreamerBasicPointer* elp = dynamic_cast<TStreamerBasicPointer*> (el);
if (elp==0) {
cout << "fatal error with TStreamerBasicPointer" << endl;
continue;
}
fs << tab2 << "buf.WriteArray(" << ElementGetter(cl, el->GetName());
fs << ", " << ElementGetter(cl, elp->GetCountName())
<< ", \"" << el->GetName() << "\", true);" << endl;
continue;
}
case TStreamerInfo::kCharStar: {
fs << tab2 << "buf.WriteCharStar(" << ElementGetter(cl, el->GetName())
<< ", \"" << el->GetName() << "\");" << endl;
continue;
}
case TStreamerInfo::kBase: {
fs << tab2 << GetStreamerName(el->GetClassPointer())
<< "(buf, dynamic_cast<" << el->GetClassPointer()->GetName()
<< "*>(obj), false);" << endl;
continue;
}
// Class* Class not derived from TObject and with comment field //->
case TStreamerInfo::kAnyp:
case TStreamerInfo::kAnyp + TStreamerInfo::kOffsetL: {
if (el->GetArrayLength()>0) {
fs << tab2 << "buf.WriteObjectArr(" << ElementGetter(cl, el->GetName());
fs << ", " << el->GetArrayLength() << ", -1"
<< ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
} else {
fs << tab2 << "buf.WriteObject(" << ElementGetter(cl, el->GetName());
fs << ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
}
continue;
}
// Class* Class not derived from TObject and no comment
case TStreamerInfo::kAnyP:
case TStreamerInfo::kAnyP + TStreamerInfo::kOffsetL: {
if (el->GetArrayLength()>0) {
fs << tab2 << "buf.WriteObjectPtrArr((void**) " << ElementGetter(cl, el->GetName(), 3);
fs << ", " << el->GetArrayLength()
<< ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
} else {
fs << tab2 << "buf.WriteObjectPtr(" << ElementGetter(cl, el->GetName());
fs << ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
}
continue;
}
case TStreamerInfo::kAny: { // Class NOT derived from TObject
fs << tab2 << "buf.WriteObject(" << ElementGetter(cl, el->GetName(), 2);
fs << ", \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
continue;
}
case TStreamerInfo::kAny + TStreamerInfo::kOffsetL: {
fs << tab2 << "buf.WriteObjectArr(" << ElementGetter(cl, el->GetName());
fs << ", " << el->GetArrayLength()
<< ", sizeof(" << el->GetClassPointer()->GetName()
<< "), \"" << el->GetName() << "\", "
<< GetStreamerName(el->GetClassPointer()) << ");" << endl;
continue;
}
// container with no virtual table (stl) and no comment
case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL:
case TStreamerInfo::kSTL + TStreamerInfo::kOffsetL:
case TStreamerInfo::kSTLp:
case TStreamerInfo::kSTL: {
TStreamerSTL* elstl = dynamic_cast<TStreamerSTL*> (el);
if (elstl==0) break; // to make skip
if (ProduceSTLstreamer(fs, cl, elstl, true)) continue;
fs << tab2 << "// STL type = " << elstl->GetSTLtype() << endl;
break;
}
}
fs << tab2 << "buf.MakeEmptyMember(\"" << el->GetName()
<< "\"); // sinfo type " << el->GetType()
<< " of class " << el->GetClassPointer()->GetName()
<< " not supported" << endl;
}
fs << tab2 << "buf.EndClassNode();" << endl;
fs << tab1 << "}" << endl;
fs << tab1 << "return obj;" << endl;
fs << "}" << endl << endl;
}
//______________________________________________________________________________
void TXMLPlayer::ReadSTLarg(ostream& fs,
TString& argname,
int argtyp,
Bool_t isargptr,
TClass* argcl,
TString& tname,
TString& ifcond)
{
// Produce code to read argument of stl container from xml file
switch(argtyp) {
case TStreamerInfo::kBool:
case TStreamerInfo::kChar:
case TStreamerInfo::kShort:
case TStreamerInfo::kInt:
case TStreamerInfo::kLong:
case TStreamerInfo::kLong64:
case TStreamerInfo::kFloat:
case TStreamerInfo::kDouble:
case TStreamerInfo::kUChar:
case TStreamerInfo::kUShort:
case TStreamerInfo::kUInt:
case TStreamerInfo::kULong:
case TStreamerInfo::kULong64:
case TStreamerInfo::kDouble32:
case TStreamerInfo::kCounter: {
fs << tname << " " << argname << " = buf."
<< GetBasicTypeReaderMethodName(argtyp, tname.Data()) << "(0);" << endl;
break;
}
case TStreamerInfo::kObject: {
fs << tname << (isargptr ? " ": " *") << argname << " = "
<< "(" << argcl->GetName() << "*)"
<< "buf.ReadObjectPtr(0, "
<< GetStreamerName(argcl) << ");" << endl;
if (!isargptr) {
if (ifcond.Length()>0) ifcond+=" && ";
ifcond += argname;
TString buf = "*";
buf += argname;
argname = buf;
}
break;
}
case TStreamerInfo::kSTLstring: {
fs << "string *" << argname << " = "
<< "buf.ReadSTLstring();" << endl;
if (!isargptr) {
if (ifcond.Length()>0) ifcond+=" && ";
ifcond += argname;
TString buf = "*";
buf += argname;
argname = buf;
}
break;
}
default:
fs << "/* argument " << argname << " not supported */";
}
}
//______________________________________________________________________________
void TXMLPlayer::WriteSTLarg(ostream& fs, const char* accname, int argtyp, Bool_t isargptr, TClass* argcl)
{
// Produce code to write argument of stl container to xml file
switch(argtyp) {
case TStreamerInfo::kBool:
case TStreamerInfo::kChar:
case TStreamerInfo::kShort:
case TStreamerInfo::kInt:
case TStreamerInfo::kLong:
case TStreamerInfo::kLong64:
case TStreamerInfo::kFloat:
case TStreamerInfo::kDouble:
case TStreamerInfo::kUChar:
case TStreamerInfo::kUShort:
case TStreamerInfo::kUInt:
case TStreamerInfo::kULong:
case TStreamerInfo::kULong64:
case TStreamerInfo::kDouble32:
case TStreamerInfo::kCounter: {
fs << "buf.WriteValue(" << accname << ", 0);" << endl;
break;
}
case TStreamerInfo::kObject: {
fs << "buf.WriteObjectPtr(";
if (isargptr) fs << accname;
else fs << "&(" << accname << ")";
fs << ", 0, " << GetStreamerName(argcl) << ");" << endl;
break;
}
case TStreamerInfo::kSTLstring: {
fs << "buf.WriteSTLstring(";
if (isargptr) fs << accname;
else fs << "&(" << accname << ")";
fs << ");" << endl;
break;
}
default:
fs << "/* argument not supported */" << endl;
}
}
//______________________________________________________________________________
Bool_t TXMLPlayer::ProduceSTLstreamer(ostream& fs, TClass* cl, TStreamerSTL* el, Bool_t isWriting)
{
// Produce code of xml streamer for data member of stl type
if ((cl==0) || (el==0)) return false;
TClass* contcl = el->GetClassPointer();
// fs << tab2 << "// class " << contcl->GetName() << endl;
Bool_t isstr = (el->GetSTLtype() == TStreamerElement::kSTLstring);
Bool_t isptr = el->IsaPointer();
Bool_t isarr = (el->GetArrayLength()>0);
Bool_t isparent = (strcmp(el->GetName(), contcl->GetName())==0);
int stltyp = -1;
int narg = 0;
int argtype[2];
Bool_t isargptr[2];
TClass* argcl[2];
TString argtname[2];
if (isstr) stltyp = TStreamerElement::kSTLstring; else
if (TClassEdit::IsSTLCont(contcl->GetName())) {
string shortTypeName = TClassEdit::ShortType(contcl->GetName(),
TClassEdit::kDropStlDefault);
int nestedLoc = 0;
vector<string> splitName;
TClassEdit::GetSplit(shortTypeName.c_str(), splitName, nestedLoc);
stltyp = TClassEdit::STLKind(splitName[0].c_str());
switch (stltyp) {
case TClassEdit::kVector : narg = 1; break;
case TClassEdit::kList : narg = 1; break;
case TClassEdit::kDeque : narg = 1; break;
case TClassEdit::kMap : narg = 2; break;
case TClassEdit::kMultiMap : narg = 2; break;
case TClassEdit::kSet : narg = 1; break;
case TClassEdit::kMultiSet : narg = 1; break;
default: return false;
}
for(int n=0;n<narg;n++) {
argtype[n] = -1;
isargptr[n] = false;
argcl[n] = 0;
argtname[n] = "";
// if (splitName.size()<=n) return false;
TString buf = splitName[n+1];
argtname[n] = buf;
// nested STL containers not yet supported
if (TClassEdit::IsSTLCont(buf.Data())) return false;
int pstar = buf.Index("*");
if (pstar>0) {
isargptr[n] = true;
pstar--;
while ((pstar>0) && (buf[pstar]==' ')) pstar--;
buf.Remove(pstar+1);
} else
isargptr[n] = false;
if (buf.Index("const ")==0) {
buf.Remove(0,6);
while ((buf.Length()>0) && (buf[0]==' ')) buf.Remove(0,1);
}
TDataType *dt = (TDataType*)gROOT->GetListOfTypes()->FindObject(buf);
if (dt) argtype[n] = dt->GetType(); else
if (buf=="string") argtype[n] = TStreamerInfo::kSTLstring; else {
argcl[n] = gROOT->GetClass(buf);
if (argcl[n]!=0) argtype[n]=TStreamerInfo::kObject;
}
if (argtype[n]<0) stltyp = -1;
// fs << tab2 << "// arg " << n << " name = /" << argtname[n] << "/ typ = " << argtype[n]
// << " isptr = " << isargptr[n] << " class = " << (argcl[n] ? argcl[n]->GetName() : "null") << endl;
}
if (stltyp<0) return false;
}
Bool_t akaarrayaccess = (narg==1) && (argtype[0]<20);
char tabs[30], tabs2[30];
if (isWriting) {
fs << tab2 << "if (buf.StartSTLnode(\""
<< fXmlSetup.XmlGetElementName(el) << "\")) {" << endl;
fs << tab3 << contcl->GetName() << " ";
TString accname;
if (isptr) {
if (isarr) { fs << "**cont"; accname = "(*cont)->"; }
else { fs << "*cont"; accname = "cont->"; }
} else
if (isarr) { fs << "*cont"; accname = "cont->"; }
else { fs << "&cont"; accname = "cont."; }
fs << " = ";
if (isparent)
fs << "*dynamic_cast<" << contcl->GetName() << "*>(obj);" << endl;
else
fs << ElementGetter(cl, el->GetName()) << ";" << endl;
if (isarr && el->GetArrayLength()) {
strcpy(tabs, tab4);
fs << tab3 << "for(int n=0;n<" << el->GetArrayLength() << ";n++) {" << endl;
} else strcpy(tabs, tab3);
strcpy(tabs2, tabs);
if (isptr) {
strcat(tabs2, tab1);
fs << tabs << "if (" << (isarr ? "*cont" : "cont") << "==0) {" << endl;
fs << tabs2 << "buf.WriteSTLsize(0" << (isstr ? ",true);" : ");") << endl;
fs << tabs << "} else {" << endl;
}
fs << tabs2 << "buf.WriteSTLsize(" << accname
<< (isstr ? "length(), true);" : "size());") << endl;
if (isstr) {
fs << tabs2 << "buf.WriteSTLstringData(" << accname << "c_str());" << endl;
} else {
if (akaarrayaccess) {
fs << tabs2 << argtname[0] << "* arr = new " << argtname[0]
<< "[" << accname << "size()];" << endl;
fs << tabs2 << "int k = 0;" << endl;
}
fs << tabs2 << contcl->GetName() << "::const_iterator iter;" << endl;
fs << tabs2 << "for (iter = " << accname << "begin(); iter != "
<< accname << "end(); iter++)";
if (akaarrayaccess) {
fs << endl << tabs2 << tab1 << "arr[k++] = *iter;" << endl;
fs << tabs2 << "buf.WriteArray(arr, " << accname << "size(), 0, false);" << endl;
fs << tabs2 << "delete[] arr;" << endl;
} else
if (narg==1) {
fs << endl << tabs2 << tab1;
WriteSTLarg(fs, "*iter", argtype[0], isargptr[0], argcl[0]);
} else
if (narg==2) {
fs << " {" << endl;
fs << tabs2 << tab1;
WriteSTLarg(fs, "iter->first", argtype[0], isargptr[0], argcl[0]);
fs << tabs2 << tab1;
WriteSTLarg(fs, "iter->second", argtype[1], isargptr[1], argcl[1]);
fs << tabs2 << "}" << endl;
}
} // if (isstr)
if (isptr) fs << tabs << "}" << endl;
if (isarr && el->GetArrayLength()) {
if (isptr) fs << tabs << "cont++;" << endl;
else fs << tabs << "(void*) cont = (char*) cont + sizeof(" << contcl->GetName() << ");" << endl;
fs << tab3 << "}" << endl;
}
fs << tab3 << "buf.EndSTLnode();" << endl;
fs << tab2 << "}" << endl;
} else {
fs << tab2 << "if (buf.VerifySTLnode(\""
<< fXmlSetup.XmlGetElementName(el) << "\")) {" << endl;
fs << tab3 << contcl->GetName() << " ";
TString accname, accptr;
if (isptr) {
if (isarr) { fs << "**cont"; accname = "(*cont)->"; accptr = "*cont"; }
else { fs << "*cont"; accname = "cont->"; accptr = "cont"; }
} else
if (isarr) { fs << "*cont"; accname = "cont->"; }
else { fs << "&cont"; accname = "cont."; }
fs << " = ";
if (isparent)
fs << "*dynamic_cast<" << contcl->GetName() << "*>(obj);" << endl;
else
fs << ElementGetter(cl, el->GetName()) << ";" << endl;
if (isarr && el->GetArrayLength()) {
strcpy(tabs, tab4);
fs << tab3 << "for(int n=0;n<" << el->GetArrayLength() << ";n++) {" << endl;
} else strcpy(tabs, tab3);
fs << tabs << "int size = buf.ReadSTLsize(" << (isstr ? "true);" : ");") << endl;
if (isptr) {
fs << tabs << "delete " << accptr << ";" << endl;
fs << tabs << "if (size==0) " << accptr << " = 0;" << endl;
fs << tabs << " else " << accptr << " = new " << contcl->GetName() << ";" << endl;
if (!isarr) {
char endch[5];
fs << tabs << ElementSetter(cl, el->GetName(), endch);
fs << "cont" << endch << ";" << endl;
}
} else {
fs << tabs << accname << (isstr ? "erase();" : "clear();") << endl;
}
if (isstr) {
fs << tabs << "if (size>0) " << accname << "assign(buf.ReadSTLstringData(size));" << endl;
} else {
if (akaarrayaccess) {
fs << tabs << argtname[0] << "* arr = new " << argtname[0] << "[size];" << endl;
fs << tabs << "buf.ReadArray(arr, size, 0, false);" << endl;
}
fs << tabs << "for(int k=0;k<size;k++)";
if (akaarrayaccess) {
fs << endl << tabs << tab1 << accname;
if ((stltyp==TClassEdit::kSet) || (stltyp==TClassEdit::kMultiSet))
fs << "insert"; else fs << "push_back";
fs << "(arr[k]);" << endl;
fs << tabs << "delete[] arr;" << endl;
} else
if (narg==1) {
TString arg1("arg"), ifcond;
fs << " {" << endl << tabs << tab1;
ReadSTLarg(fs, arg1, argtype[0], isargptr[0], argcl[0], argtname[0], ifcond);
fs << tabs << tab1;
if (ifcond.Length()>0) fs << "if (" << ifcond << ") ";
fs << accname;
if ((stltyp==TClassEdit::kSet) || (stltyp==TClassEdit::kMultiSet))
fs << "insert"; else fs << "push_back";
fs << "(" << arg1 << ");" << endl;
fs << tabs << "}" << endl;
}
else
if (narg==2) {
TString arg1("arg1"), arg2("arg2"), ifcond;
fs << " {" << endl << tabs << tab1;
ReadSTLarg(fs, arg1, argtype[0], isargptr[0], argcl[0], argtname[0], ifcond);
fs << tabs << tab1;
ReadSTLarg(fs, arg2, argtype[1], isargptr[1], argcl[1], argtname[1], ifcond);
fs << tabs << tab1;
if (ifcond.Length()>0) fs << "if (" << ifcond << ") ";
fs << accname << "insert(make_pair("
<< arg1 << ", " << arg2 << "));" << endl;
fs << tabs << "}" << endl;
}
}
if (isarr && el->GetArrayLength()) {
if (isptr) fs << tabs << "cont++;" << endl;
else fs << tabs << "(void*) cont = (char*) cont + sizeof(" << contcl->GetName() << ");" << endl;
fs << tab3 << "}" << endl;
}
fs << tab3 << "buf.EndSTLnode();" << endl;
fs << tab2 << "}" << endl;
}
return true;
}
ROOT page - Class index - Class Hierarchy - Top of the page
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.