Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TKeyXML.cxx
Go to the documentation of this file.
1 // @(#)root/xml:$Id$
2 // Author: Sergey Linev, Rene Brun 10.05.2004
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //________________________________________________________________________
13 //
14 // TKeyXML is represents one block of data in TXMLFile
15 // Normally this block corresponds to data of single object like histogram,
16 // TObjArray and so on.
17 //________________________________________________________________________
18 
19 #include "TKeyXML.h"
20 
21 #include "TBufferXML.h"
22 #include "TXMLFile.h"
23 #include "TClass.h"
24 #include "TROOT.h"
25 
26 ClassImp(TKeyXML);
27 
28 ////////////////////////////////////////////////////////////////////////////////
29 /// Creates TKeyXML and convert object data to xml structures
30 
31 TKeyXML::TKeyXML(TDirectory *mother, Long64_t keyid, const TObject *obj, const char *name, const char *title)
32  : TKey(mother), fKeyNode(nullptr), fKeyId(keyid), fSubdir(kFALSE)
33 {
34  if (name) {
35  SetName(name);
36  } else if (obj) {
37  SetName(obj->GetName());
38  fClassName = obj->ClassName();
39  } else
40  SetName("Noname");
41 
42  if (title)
43  SetTitle(title);
44 
45  fCycle = GetMotherDir()->AppendKey(this);
46 
47  TXMLEngine *xml = XMLEngine();
48  if (xml)
49  fKeyNode = xml->NewChild(nullptr, nullptr, xmlio::Xmlkey);
50 
51  fDatime.Set();
52 
53  StoreObject(obj, nullptr, kTRUE);
54 }
55 
56 ////////////////////////////////////////////////////////////////////////////////
57 /// Creates TKeyXML and convert object data to xml structures
58 
59 TKeyXML::TKeyXML(TDirectory *mother, Long64_t keyid, const void *obj, const TClass *cl, const char *name,
60  const char *title)
61  : TKey(mother), fKeyNode(nullptr), fKeyId(keyid), fSubdir(kFALSE)
62 {
63  if (name && *name)
64  SetName(name);
65  else
66  SetName(cl ? cl->GetName() : "Noname");
67 
68  if (title)
69  SetTitle(title);
70 
71  fCycle = GetMotherDir()->AppendKey(this);
72 
73  TXMLEngine *xml = XMLEngine();
74  if (xml)
75  fKeyNode = xml->NewChild(nullptr, nullptr, xmlio::Xmlkey);
76 
77  fDatime.Set();
78 
79  StoreObject(obj, cl, kFALSE);
80 }
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 /// Creates TKeyXML and takes ownership over xml node, from which object can be restored
84 
85 TKeyXML::TKeyXML(TDirectory *mother, Long64_t keyid, XMLNodePointer_t keynode)
86  : TKey(mother), fKeyNode(keynode), fKeyId(keyid), fSubdir(kFALSE)
87 {
88  TXMLEngine *xml = XMLEngine();
89 
90  SetName(xml->GetAttr(keynode, xmlio::Name));
91 
92  if (xml->HasAttr(keynode, xmlio::Title))
93  SetTitle(xml->GetAttr(keynode, xmlio::Title));
94 
95  fCycle = xml->GetIntAttr(keynode, xmlio::Cycle);
96 
97  if (xml->HasAttr(keynode, xmlio::CreateTm)) {
98  TDatime tm(xml->GetAttr(keynode, xmlio::CreateTm));
99  fDatime = tm;
100  }
101 
102  XMLNodePointer_t objnode = xml->GetChild(keynode);
103  xml->SkipEmpty(objnode);
104 
105  fClassName = xml->GetAttr(objnode, xmlio::ObjClass);
106 }
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// TKeyXML destructor
110 
111 TKeyXML::~TKeyXML()
112 {
113  if (fKeyNode) {
114  TXMLEngine *xml = XMLEngine();
115  if (xml) {
116  xml->FreeNode(fKeyNode);
117  } else {
118  TXMLEngine xml_;
119  xml_.FreeNode(fKeyNode);
120  }
121  }
122 }
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 /// Delete key from current directory
126 /// Note: TKeyXML object is not deleted. You still have to call "delete key"
127 
128 void TKeyXML::Delete(Option_t * /*option*/)
129 {
130  TXMLEngine *xml = XMLEngine();
131  if (fKeyNode && xml) {
132  xml->FreeNode(fKeyNode);
133  fKeyNode = nullptr;
134  }
135 
136  fMotherDir->GetListOfKeys()->Remove(this);
137 }
138 
139 ////////////////////////////////////////////////////////////////////////////////
140 /// Stores keys attributes in key node
141 
142 void TKeyXML::StoreKeyAttributes()
143 {
144  TXMLEngine *xml = XMLEngine();
145  TXMLFile *f = (TXMLFile *)GetFile();
146  if (!f || !xml || !fKeyNode)
147  return;
148 
149  xml->NewAttr(fKeyNode, nullptr, xmlio::Name, GetName());
150 
151  xml->NewIntAttr(fKeyNode, xmlio::Cycle, fCycle);
152 
153  if (f->GetIOVersion() > 1) {
154  if (strlen(GetTitle()) > 0)
155  xml->NewAttr(fKeyNode, nullptr, xmlio::Title, GetTitle());
156  if (f->TestBit(TFile::kReproducible))
157  xml->NewAttr(fKeyNode, nullptr, xmlio::CreateTm, TDatime((UInt_t) 1).AsSQLString());
158  else
159  xml->NewAttr(fKeyNode, nullptr, xmlio::CreateTm, fDatime.AsSQLString());
160  }
161 }
162 
163 ////////////////////////////////////////////////////////////////////////////////
164 /// convert object to xml structure and keep this structure in key
165 
166 void TKeyXML::StoreObject(const void *obj, const TClass *cl, Bool_t check_tobj)
167 {
168  TXMLFile *f = (TXMLFile *)GetFile();
169  TXMLEngine *xml = XMLEngine();
170  if (!f || !xml || !fKeyNode)
171  return;
172 
173  if (obj && check_tobj) {
174  TClass *actual = TObject::Class()->GetActualClass((TObject *)obj);
175  if (!actual) {
176  actual = TObject::Class();
177  } else if (actual != TObject::Class())
178  obj = (void *)((Long_t)obj - actual->GetBaseClassOffset(TObject::Class()));
179  cl = actual;
180  }
181 
182  StoreKeyAttributes();
183 
184  TBufferXML buffer(TBuffer::kWrite, f);
185  buffer.InitMap();
186  if (f->GetIOVersion() == 1)
187  buffer.SetBit(TBuffer::kCannotHandleMemberWiseStreaming, kFALSE);
188 
189  XMLNodePointer_t node = buffer.XmlWriteAny(obj, cl);
190 
191  if (node)
192  xml->AddChildFirst(fKeyNode, node);
193 
194  buffer.XmlWriteBlock(fKeyNode);
195 
196  if (cl)
197  fClassName = cl->GetName();
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// update key attributes in key node
202 
203 void TKeyXML::UpdateAttributes()
204 {
205  TXMLEngine *xml = XMLEngine();
206  if (!xml || !fKeyNode)
207  return;
208 
209  xml->FreeAllAttr(fKeyNode);
210 
211  StoreKeyAttributes();
212 }
213 
214 ////////////////////////////////////////////////////////////////////////////////
215 /// updates object, stored in the node
216 /// Used for TDirectory data update
217 
218 void TKeyXML::UpdateObject(TObject *obj)
219 {
220  TXMLFile *f = (TXMLFile *)GetFile();
221  TXMLEngine *xml = XMLEngine();
222  if (!f || !xml || !obj || !fKeyNode)
223  return;
224 
225  XMLNodePointer_t objnode = xml->GetChild(fKeyNode);
226  xml->SkipEmpty(objnode);
227 
228  if (!objnode)
229  return;
230 
231  xml->UnlinkNode(objnode);
232  xml->FreeNode(objnode);
233 
234  xml->FreeAllAttr(fKeyNode);
235 
236  StoreObject(obj, nullptr, kTRUE);
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// To read an object from the file.
241 /// The object associated to this key is read from the file into memory.
242 /// Before invoking this function, obj has been created via the
243 /// default constructor.
244 
245 Int_t TKeyXML::Read(TObject *tobj)
246 {
247  if (!tobj)
248  return 0;
249 
250  void *res = XmlReadAny(tobj, nullptr);
251 
252  return !res ? 0 : 1;
253 }
254 
255 ////////////////////////////////////////////////////////////////////////////////
256 /// read object derived from TObject class, from key
257 /// if it is not TObject or in case of error, return nullptr
258 
259 TObject *TKeyXML::ReadObj()
260 {
261  TObject *tobj = (TObject *)XmlReadAny(nullptr, TObject::Class());
262 
263  if (tobj) {
264  if (gROOT->GetForceStyle())
265  tobj->UseCurrentStyle();
266  if (tobj->IsA() == TDirectoryFile::Class()) {
267  TDirectoryFile *dir = (TDirectoryFile *)tobj;
268  dir->SetName(GetName());
269  dir->SetTitle(GetTitle());
270  dir->SetSeekDir(GetKeyId());
271  // set mother before reading keys
272  dir->SetMother(fMotherDir);
273  dir->ReadKeys();
274  fMotherDir->Append(dir);
275  fSubdir = kTRUE;
276  }
277  }
278 
279  return tobj;
280 }
281 
282 ////////////////////////////////////////////////////////////////////////////////
283 /// read object derived from TObject class, from key
284 /// if it is not TObject or in case of error, return nullptr
285 
286 TObject *TKeyXML::ReadObjWithBuffer(char * /*bufferRead*/)
287 {
288  TObject *tobj = (TObject *)XmlReadAny(nullptr, TObject::Class());
289 
290  if (tobj) {
291  if (gROOT->GetForceStyle())
292  tobj->UseCurrentStyle();
293  if (tobj->IsA() == TDirectoryFile::Class()) {
294  TDirectoryFile *dir = (TDirectoryFile *)tobj;
295  dir->SetName(GetName());
296  dir->SetTitle(GetTitle());
297  dir->SetSeekDir(GetKeyId());
298  // set mother before reading keys
299  dir->SetMother(fMotherDir);
300  dir->ReadKeys();
301  fMotherDir->Append(dir);
302  fSubdir = kTRUE;
303  }
304  }
305 
306  return tobj;
307 }
308 
309 ////////////////////////////////////////////////////////////////////////////////
310 /// read object of any type
311 
312 void *TKeyXML::ReadObjectAny(const TClass *expectedClass)
313 {
314  void *res = XmlReadAny(nullptr, expectedClass);
315 
316  if (res && (expectedClass == TDirectoryFile::Class())) {
317  TDirectoryFile *dir = (TDirectoryFile *)res;
318  dir->SetName(GetName());
319  dir->SetTitle(GetTitle());
320  dir->SetSeekDir(GetKeyId());
321  // set mother before reading keys
322  dir->SetMother(fMotherDir);
323  dir->ReadKeys();
324  fMotherDir->Append(dir);
325  fSubdir = kTRUE;
326  }
327 
328  return res;
329 }
330 
331 ////////////////////////////////////////////////////////////////////////////////
332 /// read object from key and cast to expected class
333 
334 void *TKeyXML::XmlReadAny(void *obj, const TClass *expectedClass)
335 {
336  if (!fKeyNode)
337  return obj;
338 
339  TXMLFile *f = (TXMLFile *)GetFile();
340  TXMLEngine *xml = XMLEngine();
341  if (!f || !xml)
342  return obj;
343 
344  TBufferXML buffer(TBuffer::kRead, f);
345  buffer.InitMap();
346  if (f->GetIOVersion() == 1)
347  buffer.SetBit(TBuffer::kCannotHandleMemberWiseStreaming, kFALSE);
348 
349  XMLNodePointer_t blocknode = xml->GetChild(fKeyNode);
350  xml->SkipEmpty(blocknode);
351  while (blocknode) {
352  if (strcmp(xml->GetNodeName(blocknode), xmlio::XmlBlock) == 0)
353  break;
354  xml->ShiftToNext(blocknode);
355  }
356  buffer.XmlReadBlock(blocknode);
357 
358  XMLNodePointer_t objnode = xml->GetChild(fKeyNode);
359  xml->SkipEmpty(objnode);
360 
361  TClass *cl = nullptr;
362  void *res = buffer.XmlReadAny(objnode, obj, &cl);
363 
364  if (!cl || !res)
365  return obj;
366 
367  Int_t delta = 0;
368 
369  if (expectedClass) {
370  delta = cl->GetBaseClassOffset(expectedClass);
371  if (delta < 0) {
372  if (!obj)
373  cl->Destructor(res);
374  return nullptr;
375  }
376  if (cl->GetState() > TClass::kEmulated && expectedClass->GetState() <= TClass::kEmulated) {
377  // we cannot mix a compiled class with an emulated class in the inheritance
378  Warning("XmlReadAny", "Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
379  cl->GetName(), expectedClass->GetName());
380  }
381  }
382 
383  return ((char *)res) + delta;
384 }
385 
386 ////////////////////////////////////////////////////////////////////////////////
387 /// return pointer on TXMLEngine object, used for xml conversion
388 
389 TXMLEngine *TKeyXML::XMLEngine()
390 {
391  TXMLFile *f = (TXMLFile *)GetFile();
392  return f ? f->XML() : nullptr;
393 }