artdaq_node_server  v1_01_01c
JSRootIOEvolution.js
Go to the documentation of this file.
1 
4 (function(){
5 
6  if (typeof JSROOT != "object") {
7  var e1 = new Error("This extension requires JSRootCore.js");
8  e1.source = "JSRootIOEvolution.js";
9  throw e1;
10  }
11 
12  if (typeof JSROOT.IO == "object") {
13  var e1 = new Error("This JSROOT IO already loaded");
14  e1.source = "JSRootIOEvolution.js";
15  throw e1;
16  }
17 
18  JSROOT.IO = {
19  kBase : 0, kOffsetL : 20, kOffsetP : 40, kCounter : 6, kCharStar : 7,
20  kChar : 1, kShort : 2, kInt : 3, kLong : 4, kFloat : 5,
21  kDouble : 8, kDouble32 : 9, kLegacyChar : 10, kUChar : 11, kUShort : 12,
22  kUInt : 13, kULong : 14, kBits : 15, kLong64 : 16, kULong64 : 17, kBool : 18,
23  kFloat16 : 19,
24  kObject : 61, kAny : 62, kObjectp : 63, kObjectP : 64, kTString : 65,
25  kTObject : 66, kTNamed : 67, kAnyp : 68, kAnyP : 69, kAnyPnoVT : 70,
26  kSTLp : 71,
27  kSkip : 100, kSkipL : 120, kSkipP : 140,
28  kConv : 200, kConvL : 220, kConvP : 240,
29  kSTL : 300, kSTLstring : 365,
30  kStreamer : 500, kStreamLoop : 501,
31  kMapOffset : 2,
32  kByteCountMask : 0x40000000,
33  kNewClassTag : 0xFFFFFFFF,
34  kClassMask : 0x80000000,
35  Z_DEFLATED : 8,
36  Z_HDRSIZE : 9
37  };
38 
39  JSROOT.fUserStreamers = null; // map of user-streamer function like func(buf,obj,prop,streamerinfo)
40 
41  JSROOT.addUserStreamer = function(type, user_streamer)
42  {
43  if (JSROOT.fUserStreamers == null) JSROOT.fUserStreamers = {};
44  JSROOT.fUserStreamers[type] = user_streamer;
45  }
46 
47  JSROOT.R__unzip_header = function(str, off, noalert) {
48  // Reads header envelope, and determines target size.
49 
50  if (off + JSROOT.IO.Z_HDRSIZE > str.length) {
51  if (!noalert) alert("Error R__unzip_header: header size exceeds buffer size");
52  return -1;
53  }
54 
55  /* C H E C K H E A D E R */
56  if (!(str.charAt(off) == 'Z' && str.charAt(off+1) == 'L' && str.charCodeAt(off+2) == JSROOT.IO.Z_DEFLATED) &&
57  !(str.charAt(off) == 'C' && str.charAt(off+1) == 'S' && str.charCodeAt(off+2) == JSROOT.IO.Z_DEFLATED) &&
58  !(str.charAt(off) == 'X' && str.charAt(off+1) == 'Z' && str.charCodeAt(off+2) == 0)) {
59  if (!noalert) alert("Error R__unzip_header: error in header");
60  return -1;
61  }
62  return JSROOT.IO.Z_HDRSIZE +
63  ((str.charCodeAt(off+3) & 0xff) |
64  ((str.charCodeAt(off+4) & 0xff) << 8) |
65  ((str.charCodeAt(off+5) & 0xff) << 16));
66  }
67 
68  JSROOT.R__unzip = function(srcsize, str, off, noalert) {
69 
70  /* C H E C K H E A D E R */
71  if (srcsize < JSROOT.IO.Z_HDRSIZE) {
72  if (!noalert) alert("R__unzip: too small source");
73  return null;
74  }
75 
76  /* C H E C K H E A D E R */
77  if (!(str.charAt(off) == 'Z' && str.charAt(off+1) == 'L' && str.charCodeAt(off+2) == JSROOT.IO.Z_DEFLATED) &&
78  !(str.charAt(off) == 'C' && str.charAt(off+1) == 'S' && str.charCodeAt(off+2) == JSROOT.IO.Z_DEFLATED) &&
79  !(str.charAt(off) == 'X' && str.charAt(off+1) == 'Z' && str.charCodeAt(off+2) == 0)) {
80  if (!noalert) alert("Error R__unzip: error in header");
81  return null;
82  }
83  var ibufcnt = ((str.charCodeAt(off+3) & 0xff) |
84  ((str.charCodeAt(off+4) & 0xff) << 8) |
85  ((str.charCodeAt(off+5) & 0xff) << 16));
86  if (ibufcnt + JSROOT.IO.Z_HDRSIZE != srcsize) {
87  if (!noalert) alert("R__unzip: discrepancy in source length");
88  return null;
89  }
90 
91  /* D E C O M P R E S S D A T A */
92  if (str.charAt(off) == 'Z' && str.charAt(off+1) == 'L') {
93  /* New zlib format */
94  var data = str.substr(off + JSROOT.IO.Z_HDRSIZE + 2, srcsize);
95  return RawInflate.inflate(data);
96  }
97  /* Old zlib format */
98  else {
99  if (!noalert) alert("R__unzip: Old zlib format is not supported!");
100  return null;
101  }
102  return null;
103  };
104 
105 
106  JSROOT.ReconstructObject = function(class_name, obj_rawdata, sinfo_rawdata) {
107  // method can be used to reconstruct ROOT object from binary buffer
108  // Buffer can be requested from online server with request like:
109  // http://localhost:8080/Files/job1.root/hpx/root.bin
110  // One also requires buffer with streamer infos, reqeusted with command
111  // http://localhost:8080/StreamerInfo/root.bin
112  // And one should provide class name of the object
113  //
114  // Method provided for convenience only to see how binary JSROOT.IO works.
115  // It is strongly recommended to use JSON representation:
116  // http://localhost:8080/Files/job1.root/hpx/root.json
117 
118  var file = new JSROOT.TFile;
119  var buf = new JSROOT.TBuffer(sinfo_rawdata, 0, file);
120  file.ExtractStreamerInfos(buf);
121 
122  var obj = {};
123 
124  buf = new JSROOT.TBuffer(obj_rawdata, 0, file);
125  buf.MapObject(obj, 1);
126  buf.ClassStreamer(obj, class_name);
127 
128  return obj;
129  }
130 
131  JSROOT.TBuffer = function(_str, _o, _file) {
132  this._typename = "TBuffer";
133  this.b = _str;
134  this.o = (_o==null) ? 0 : _o;
135  this.fFile = _file;
136  this.ClearObjectMap();
137  this.fTagOffset = 0;
138  return this;
139  }
140 
141  JSROOT.TBuffer.prototype.locate = function(pos) {
142  this.o = pos;
143  }
144 
145  JSROOT.TBuffer.prototype.shift = function(cnt) {
146  this.o += cnt;
147  }
148 
149  JSROOT.TBuffer.prototype.ntou1 = function() {
150  return (this.b.charCodeAt(this.o++) & 0xff) >>> 0;
151  }
152 
153  JSROOT.TBuffer.prototype.ntou2 = function() {
154  // convert (read) two bytes of buffer b into a UShort_t
155  var n = ((this.b.charCodeAt(this.o) & 0xff) << 8) >>> 0;
156  n += (this.b.charCodeAt(this.o+1) & 0xff) >>> 0;
157  this.o += 2;
158  return n;
159  };
160 
161  JSROOT.TBuffer.prototype.ntou4 = function() {
162  // convert (read) four bytes of buffer b into a UInt_t
163  var n = ((this.b.charCodeAt(this.o) & 0xff) << 24) >>> 0;
164  n += ((this.b.charCodeAt(this.o+1) & 0xff) << 16) >>> 0;
165  n += ((this.b.charCodeAt(this.o+2) & 0xff) << 8) >>> 0;
166  n += (this.b.charCodeAt(this.o+3) & 0xff) >>> 0;
167  this.o += 4;
168  return n;
169  };
170 
171  JSROOT.TBuffer.prototype.ntou8 = function() {
172  // convert (read) eight bytes of buffer b into a ULong_t
173  var n = ((this.b.charCodeAt(this.o) & 0xff) << 56) >>> 0;
174  n += ((this.b.charCodeAt(this.o+1) & 0xff) << 48) >>> 0;
175  n += ((this.b.charCodeAt(this.o+2) & 0xff) << 40) >>> 0;
176  n += ((this.b.charCodeAt(this.o+3) & 0xff) << 32) >>> 0;
177  n += ((this.b.charCodeAt(this.o+4) & 0xff) << 24) >>> 0;
178  n += ((this.b.charCodeAt(this.o+5) & 0xff) << 16) >>> 0;
179  n += ((this.b.charCodeAt(this.o+6) & 0xff) << 8) >>> 0;
180  n += (this.b.charCodeAt(this.o+7) & 0xff) >>> 0;
181  this.op += 8;
182  return n;
183  };
184 
185  JSROOT.TBuffer.prototype.ntoi1 = function() {
186  return (this.b.charCodeAt(this.o++) & 0xff);
187  }
188 
189  JSROOT.TBuffer.prototype.ntoi2 = function() {
190  // convert (read) two bytes of buffer b into a Short_t
191  var n = (this.b.charCodeAt(this.o) & 0xff) << 8;
192  n += (this.b.charCodeAt(this.o+1) & 0xff);
193  this.o += 2;
194  return n;
195  };
196 
197  JSROOT.TBuffer.prototype.ntoi4 = function() {
198  // convert (read) four bytes of buffer b into a Int_t
199  var n = ((this.b.charCodeAt(this.o) & 0xff) << 24) +
200  ((this.b.charCodeAt(this.o+1) & 0xff) << 16) +
201  ((this.b.charCodeAt(this.o+2) & 0xff) << 8) +
202  ((this.b.charCodeAt(this.o+3) & 0xff));
203  this.o += 4;
204  return n;
205  };
206 
207  JSROOT.TBuffer.prototype.ntoi8 = function(b, o) {
208  // convert (read) eight bytes of buffer b into a Long_t
209  var n = (this.b.charCodeAt(this.o) & 0xff) << 56;
210  n += (this.b.charCodeAt(this.o+1) & 0xff) << 48;
211  n += (this.b.charCodeAt(this.o+2) & 0xff) << 40;
212  n += (this.b.charCodeAt(this.o+3) & 0xff) << 32;
213  n += (this.b.charCodeAt(this.o+4) & 0xff) << 24;
214  n += (this.b.charCodeAt(this.o+5) & 0xff) << 16;
215  n += (this.b.charCodeAt(this.o+6) & 0xff) << 8;
216  n += (this.b.charCodeAt(this.o+7) & 0xff);
217  this.o += 8;
218  return n;
219  };
220 
221  JSROOT.TBuffer.prototype.ntof = function() {
222  // IEEE-754 Floating-Point Conversion (single precision - 32 bits)
223  var inString = this.b.substring(this.o, this.o + 4); this.o+=4;
224  if (inString.length < 4) return Number.NaN;
225  var bits = "";
226  for (var i=0; i<4; i++) {
227  var curByte = (inString.charCodeAt(i) & 0xff).toString(2);
228  var byteLen = curByte.length;
229  if (byteLen < 8) {
230  for (var bit=0; bit<(8-byteLen); bit++)
231  curByte = '0' + curByte;
232  }
233  bits = bits + curByte;
234  }
235  //var bsign = parseInt(bits[0]) ? -1 : 1;
236  var bsign = (bits.charAt(0) == '1') ? -1 : 1;
237  var bexp = parseInt(bits.substring(1, 9), 2) - 127;
238  var bman;
239  if (bexp == -127)
240  bman = 0;
241  else {
242  bman = 1;
243  for (var i=0; i<23; i++) {
244  if (parseInt(bits.substr(9+i, 1)) == 1)
245  bman = bman + 1 / Math.pow(2, i+1);
246  }
247  }
248  return (bsign * Math.pow(2, bexp) * bman);
249  };
250 
251  JSROOT.TBuffer.prototype.ntod = function() {
252  // IEEE-754 Floating-Point Conversion (double precision - 64 bits)
253  var inString = this.b.substring(this.o, this.o + 8); this.o+=8;
254  if (inString.length < 8) return Number.NaN;
255  var bits = "";
256  for (var i=0; i<8; i++) {
257  var curByte = (inString.charCodeAt(i) & 0xff).toString(2);
258  var byteLen = curByte.length;
259  if (byteLen < 8) {
260  for (var bit=0; bit<(8-byteLen); bit++)
261  curByte = '0' + curByte;
262  }
263  bits = bits + curByte;
264  }
265  //var bsign = parseInt(bits[0]) ? -1 : 1;
266  var bsign = (bits.charAt(0) == '1') ? -1 : 1;
267  var bexp = parseInt(bits.substring(1, 12), 2) - 1023;
268  var bman;
269  if (bexp == -127)
270  bman = 0;
271  else {
272  bman = 1;
273  for (var i=0; i<52; i++) {
274  if (parseInt(bits.substr(12+i, 1)) == 1)
275  bman = bman + 1 / Math.pow(2, i+1);
276  }
277  }
278  return (bsign * Math.pow(2, bexp) * bman);
279  };
280 
281 
282  JSROOT.TBuffer.prototype.ReadFastArray = function(n, array_type) {
283  // read array of n integers from the I/O buffer
284  var array = new Array();
285  switch (array_type) {
286  case 'D':
287  for (var i = 0; i < n; ++i) {
288  array[i] = this.ntod();
289  if (Math.abs(array[i]) < 1e-300) array[i] = 0.0;
290  }
291  break;
292  case 'F':
293  for (var i = 0; i < n; ++i) {
294  array[i] = this.ntof();
295  if (Math.abs(array[i]) < 1e-300) array[i] = 0.0;
296  }
297  break;
298  case 'L':
299  for (var i = 0; i < n; ++i)
300  array[i] = this.ntoi8();
301  break;
302  case 'LU':
303  for (var i = 0; i < n; ++i)
304  array[i] = this.ntou8();
305  break;
306  case 'I':
307  for (var i = 0; i < n; ++i)
308  array[i] = this.ntoi4();
309  break;
310  case 'U':
311  for (var i = 0; i < n; ++i)
312  array[i] = this.ntou4();
313  break;
314  case 'S':
315  for (var i = 0; i < n; ++i)
316  array[i] = this.ntoi2();
317  break;
318  case 'C':
319  for (var i = 0; i < n; ++i)
320  array[i] = this.b.charCodeAt(this.o++) & 0xff;
321  break;
322  case 'TString':
323  for (var i = 0; i < n; ++i)
324  array[i] = this.ReadTString();
325  break;
326  default:
327  for (var i = 0; i < n; ++i)
328  array[i] = this.ntou4();
329  break;
330  }
331  return array;
332  };
333 
334 
335  JSROOT.TBuffer.prototype.ReadBasicPointer = function(len, array_type) {
336  var isArray = this.b.charCodeAt(this.o++) & 0xff;
337  if (isArray)
338  return this.ReadFastArray(len, array_type);
339 
340  if (len==0) return new Array();
341 
342  this.o--;
343  return this.ReadFastArray(len, array_type);
344  };
345 
346 
347  JSROOT.TBuffer.prototype.ReadString = function(max_len) {
348  // stream a string from buffer
349  max_len = typeof(max_len) != 'undefined' ? max_len : 0;
350  var len = 0;
351  var pos0 = this.o;
352  while ((max_len==0) || (len<max_len)) {
353  if ((this.b.charCodeAt(this.o++) & 0xff) == 0) break;
354  len++;
355  }
356 
357  return (len == 0) ? "" : this.b.substring(pos0, pos0 + len);
358  };
359 
360  JSROOT.TBuffer.prototype.ReadTString = function() {
361  // stream a TString object from buffer
362  var len = this.b.charCodeAt(this.o++) & 0xff;
363  // large strings
364  if (len == 255) len = this.ntou4();
365 
366  var pos = this.o;
367  this.o += len;
368 
369  return (this.b.charCodeAt(pos) == 0) ? '' : this.b.substring(pos, pos + len);
370  };
371 
372 
373  JSROOT.TBuffer.prototype.GetMappedObject = function(tag) {
374  return this.fObjectMap[tag];
375  };
376 
377  JSROOT.TBuffer.prototype.MapObject = function(tag, obj) {
378  if (obj==null) return;
379  this.fObjectMap[tag] = obj;
380  };
381 
382  JSROOT.TBuffer.prototype.MapClass = function(tag, classname) {
383  this.fClassMap[tag] = classname;
384  };
385 
386  JSROOT.TBuffer.prototype.GetMappedClass = function(tag) {
387  if (tag in this.fClassMap) return this.fClassMap[tag];
388  return -1;
389  };
390 
391  JSROOT.TBuffer.prototype.ClearObjectMap = function() {
392  this.fObjectMap = {};
393  this.fClassMap = {};
394  this.fObjectMap[0] = null;
395  };
396 
397  JSROOT.TBuffer.prototype.ReadVersion = function() {
398  // read class version from I/O buffer
399  var ver = {};
400  var bytecnt = this.ntou4(); // byte count
401  if (bytecnt & JSROOT.IO.kByteCountMask)
402  ver['bytecnt'] = bytecnt - JSROOT.IO.kByteCountMask - 2; // one can check between Read version and end of streamer
403  ver['val'] = this.ntou2();
404  ver['off'] = this.o;
405  return ver;
406  };
407 
408  JSROOT.TBuffer.prototype.CheckBytecount = function(ver, where) {
409  if (('bytecnt' in ver) && (ver['off'] + ver['bytecnt'] != this.o)) {
410  if (where!=null)
411  alert("Missmatch in " + where + " bytecount expected = " + ver['bytecnt'] + " got = " + (this.o-ver['off']));
412  this.o = ver['off'] + ver['bytecnt'];
413  return false;
414  }
415  return true;
416  }
417 
418  JSROOT.TBuffer.prototype.ReadTObject = function(tobj) {
419  this.o += 2; // skip version
420  if ((!'_typename' in tobj) || (tobj['_typename'] == ''))
421  tobj['_typename'] = "TObject";
422 
423  tobj['fUniqueID'] = this.ntou4();
424  tobj['fBits'] = this.ntou4();
425  return true;
426  }
427 
428  JSROOT.TBuffer.prototype.ReadTNamed = function(tobj) {
429  // read a TNamed class definition from I/O buffer
430  var ver = this.ReadVersion();
431  this.ReadTObject(tobj);
432  tobj['fName'] = this.ReadTString();
433  tobj['fTitle'] = this.ReadTString();
434  return this.CheckBytecount(ver, "ReadTNamed");
435  };
436 
437  JSROOT.TBuffer.prototype.ReadTObjString = function(tobj) {
438  // read a TObjString definition from I/O buffer
439  var ver = this.ReadVersion();
440  this.ReadTObject(tobj);
441  tobj['fString'] = this.ReadTString();
442  return this.CheckBytecount(ver, "ReadTObjString");
443  }
444 
445  JSROOT.TBuffer.prototype.ReadTList = function(list) {
446  // stream all objects in the list from the I/O buffer
447  list['_typename'] = "TList";
448  list['name'] = "";
449  list['arr'] = new Array;
450  list['opt'] = new Array;
451  var ver = this.ReadVersion();
452  if (ver['val'] > 3) {
453  this.ReadTObject(list);
454  list['name'] = this.ReadTString();
455  var nobjects = this.ntou4();
456  for (var i = 0; i < nobjects; ++i) {
457 
458  var obj = this.ReadObjectAny();
459  list['arr'].push(obj);
460 
461  var opt = this.ReadTString();
462  list['opt'].push(opt);
463  }
464  }
465 
466  return this.CheckBytecount(ver);
467  }
468 
469  JSROOT.TBuffer.prototype.ReadTObjArray = function(list) {
470  list['_typename'] = "TObjArray";
471  list['name'] = "";
472  list['arr'] = new Array();
473  var ver = this.ReadVersion();
474  if (ver['val'] > 2)
475  this.ReadTObject(list);
476  if (ver['val'] > 1)
477  list['name'] = this.ReadTString();
478  var nobjects = this.ntou4();
479  var lowerbound = this.ntou4();
480  for (var i = 0; i < nobjects; i++) {
481  var obj = this.ReadObjectAny();
482  list['arr'].push(obj);
483  }
484  return this.CheckBytecount(ver, "ReadTObjArray");
485  };
486 
487  JSROOT.TBuffer.prototype.ReadTClonesArray = function(list) {
488  list['_typename'] = "TClonesArray";
489  list['name'] = "";
490  list['arr'] = new Array();
491  var ver = this.ReadVersion();
492  if (ver['val'] > 2)
493  this.ReadTObject(list);
494  if (ver['val'] > 1)
495  list['name'] = this.ReadTString();
496  var s = this.ReadTString();
497  var classv = s;
498  var clv = 0;
499  var pos = s.indexOf(";");
500  if (pos != -1) {
501  classv = s.slice(0, pos);
502  s = s.slice(pos+1, s.length()-pos-1);
503  clv = parseInt(s);
504  }
505  var nobjects = this.ntou4();
506  if (nobjects < 0) nobjects = -nobjects; // for backward compatibility
507  var lowerbound = this.ntou4();
508  for (var i = 0; i < nobjects; i++) {
509  var obj = {};
510 
511  this.ClassStreamer(obj, classv);
512 
513  list['arr'].push(obj);
514  }
515  return this.CheckBytecount(ver, "ReadTClonesArray");
516  }
517 
518  JSROOT.TBuffer.prototype.ReadTPolyMarker3D = function(marker) {
519  var ver = this.ReadVersion();
520 
521  this.ReadTObject(marker);
522 
523  this.ClassStreamer(marker, "TAttMarker");
524 
525  marker['fN'] = this.ntoi4();
526 
527  marker['fP'] = this.ReadFastArray(marker['fN']*3, 'F');
528 
529  marker['fOption'] = this.ReadTString();
530 
531  if (ver['val'] > 1)
532  marker['fName'] = this.ReadTString();
533  else
534  marker['fName'] = "TPolyMarker3D";
535 
536  return this.CheckBytecount(ver, "ReadTPolyMarker3D");
537  }
538 
539  JSROOT.TBuffer.prototype.ReadTCollection = function(list, str, o) {
540  list['_typename'] = "TCollection";
541  list['name'] = "";
542  list['arr'] = new Array();
543  var ver = this.ReadVersion();
544  if (ver['val'] > 2)
545  this.ReadTObject(list);
546  if (ver['val'] > 1)
547  list['name'] = this.ReadTString();
548  var nobjects = this.ntou4();
549  for (var i = 0; i < nobjects; i++) {
550  o += 10; // skip object bits & unique id
551  list['arr'].push(null);
552  }
553  return this.CheckBytecount(ver,"ReadTCollection");
554  }
555 
556  JSROOT.TBuffer.prototype.ReadTCanvas = function(obj) {
557  // stream all objects in the list from the I/O buffer
558  var ver = this.ReadVersion();
559 
560  this.ClassStreamer(obj, "TPad");
561 
562  obj['fDISPLAY'] = this.ReadTString();
563  obj['fDoubleBuffer'] = this.ntoi4();
564  obj['fRetained'] = this.ntou1()!=0;
565  obj['fXsizeUser'] = this.ntoi4();
566  obj['fYsizeUser'] = this.ntoi4();
567  obj['fXsizeReal'] = this.ntoi4();
568  obj['fYsizeReal'] = this.ntoi4();
569  obj['fWindowTopX'] = this.ntoi4();
570  obj['fWindowTopY'] = this.ntoi4();
571  obj['fWindowWidth'] = this.ntoi4();
572  obj['fWindowHeight'] = this.ntoi4();
573  obj['fCw'] = this.ntou4();
574  obj['fCh'] = this.ntou4();
575 
576  obj['fCatt'] = {};
577  this.ClassStreamer(obj['fCatt'], "TAttCanvas");
578  this.ntou1(); // ignore b << TestBit(kMoveOpaque);
579  this.ntou1(); // ignore b << TestBit(kResizeOpaque);
580  obj['fHighLightColor'] = this.ntoi2();
581  obj['fBatch'] = this.ntou1()!=0;
582  this.ntou1(); // ignore b << TestBit(kShowEventStatus);
583  this.ntou1(); // ignore b << TestBit(kAutoExec);
584  this.ntou1(); // ignore b << TestBit(kMenuBar);
585 
586  // now TCanvas streamer should be complete - verify that bytecount is correct
587  return this.CheckBytecount(ver, "TCanvas");
588  }
589 
590 
591  JSROOT.TBuffer.prototype.ReadTStreamerInfo = function(streamerinfo) {
592  // stream an object of class TStreamerInfo from the I/O buffer
593 
594  var R__v = this.ReadVersion();
595  if (R__v['val'] > 1) {
596  this.ReadTNamed(streamerinfo);
597 
598  streamerinfo['fCheckSum'] = this.ntou4();
599  streamerinfo['fClassVersion'] = this.ntou4();
600 
601  streamerinfo['fElements'] = this.ReadObjectAny();
602  }
603  return this.CheckBytecount(R__v, "ReadTStreamerInfo");
604  };
605 
606  JSROOT.TBuffer.prototype.ReadStreamerElement = function(element) {
607  // stream an object of class TStreamerElement
608 
609  var R__v = this.ReadVersion();
610  this.ReadTNamed(element);
611  element['type'] = this.ntou4();
612  element['size'] = this.ntou4();
613  element['length'] = this.ntou4();
614  element['dim'] = this.ntou4();
615  if (R__v['val'] == 1) {
616  var n = this.ntou4();
617  element['maxindex'] = this.ReadFastArray(n, 'U');
618  } else {
619  element['maxindex'] = this.ReadFastArray(5, 'U');
620  }
621  element['fTypeName'] = this.ReadTString();
622  element['typename'] = element['fTypeName']; // TODO - should be removed
623  if ((element['type'] == 11) && (element['typename'] == "Bool_t" ||
624  element['typename'] == "bool"))
625  element['type'] = 18;
626  if (R__v['val'] > 1) {
627  element['uuid'] = 0;
628  }
629  if (R__v['val'] <= 2) {
630  // In TStreamerElement v2, fSize was holding the size of
631  // the underlying data type. In later version it contains
632  // the full length of the data member.
633  }
634  if (R__v['val'] == 3) {
635  element['xmin'] = this.ntou4();
636  element['xmax'] = this.ntou4();
637  element['factor'] = this.ntou4();
638  //if (element['factor'] > 0) SetBit(kHasRange);
639  }
640  if (R__v['val'] > 3) {
641  //if (TestBit(kHasRange)) GetRange(GetTitle(),fXmin,fXmax,fFactor);
642  }
643  return this.CheckBytecount(R__v, "ReadStreamerElement");
644  };
645 
646 
647  JSROOT.TBuffer.prototype.ReadStreamerBase = function(streamerbase) {
648  // stream an object of class TStreamerBase
649 
650  var R__v = this.ReadVersion();
651  this.ReadStreamerElement(streamerbase);
652  if (R__v['val'] > 2) {
653  streamerbase['baseversion'] = this.ntou4();
654  }
655  return this.CheckBytecount(R__v, "ReadStreamerBase");
656  };
657 
658  JSROOT.TBuffer.prototype.ReadStreamerBasicType = function(streamerbase) {
659  // stream an object of class TStreamerBasicType
660  var R__v = this.ReadVersion();
661  if (R__v['val'] > 1) {
662  this.ReadStreamerElement(streamerbase);
663  }
664  return this.CheckBytecount(R__v, "ReadStreamerBasicType");
665  };
666 
667  JSROOT.TBuffer.prototype.ReadStreamerBasicPointer = function(streamerbase) {
668  // stream an object of class TStreamerBasicPointer
669  var R__v = this.ReadVersion();
670  if (R__v['val'] > 1) {
671  this.ReadStreamerElement(streamerbase);
672  streamerbase['countversion'] = this.ntou4();
673  streamerbase['countName'] = this.ReadTString();
674  streamerbase['countClass'] = this.ReadTString();
675  }
676  return this.CheckBytecount(R__v, "ReadStreamerBasicPointer");
677  };
678 
679  JSROOT.TBuffer.prototype.ReadStreamerSTL = function(streamerSTL) {
680  // stream an object of class TStreamerSTL
681 
682  var R__v = this.ReadVersion();
683  if (R__v['val'] > 2) {
684  this.ReadStreamerElement(streamerSTL);
685  streamerSTL['stltype'] = this.ntou4();
686  streamerSTL['ctype'] = this.ntou4();
687  }
688  return this.CheckBytecount(R__v, "ReadStreamerSTL");
689  };
690 
691  JSROOT.TBuffer.prototype.ReadTStreamerObject = function(streamerbase) {
692  // stream an object of class TStreamerObject
693  var R__v = this.ReadVersion();
694  if (R__v['val'] > 1) {
695  this.ReadStreamerElement(streamerbase);
696  }
697  return this.CheckBytecount(R__v, "ReadTStreamerObject");
698  };
699 
700 
701  JSROOT.TBuffer.prototype.ReadClass = function() {
702  // read class definition from I/O buffer
703  var classInfo = {};
704  classInfo['name'] = -1;
705  var tag = 0;
706  var bcnt = this.ntou4();
707 
708  var startpos = this.o;
709  if (!(bcnt & JSROOT.IO.kByteCountMask) || (bcnt == JSROOT.IO.kNewClassTag)) {
710  tag = bcnt;
711  bcnt = 0;
712  } else {
713  // classInfo['fVersion'] = 1;
714  tag = this.ntou4();
715  }
716  if (!(tag & JSROOT.IO.kClassMask)) {
717  classInfo['objtag'] = tag; // indicate that we have deal with objects tag
718  return classInfo;
719  }
720  if (tag == JSROOT.IO.kNewClassTag) {
721  // got a new class description followed by a new object
722  classInfo['name'] = this.ReadString();
723 
724  if (this.GetMappedClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset)==-1)
725  this.MapClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset, classInfo['name']);
726  }
727  else {
728  // got a tag to an already seen class
729  var clTag = (tag & ~JSROOT.IO.kClassMask);
730  classInfo['name'] = this.GetMappedClass(clTag);
731 
732  if (classInfo['name']==-1) {
733  alert("Did not found class with tag " + clTag);
734  }
735 
736  }
737  // classInfo['cnt'] = (bcnt & ~JSROOT.IO.kByteCountMask);
738 
739  return classInfo;
740  };
741 
742  JSROOT.TBuffer.prototype.ReadObjectAny = function() {
743  var startpos = this.o;
744  var clRef = this.ReadClass();
745 
746  // class identified as object and should be handled so
747  if ('objtag' in clRef)
748  return this.GetMappedObject(clRef['objtag']);
749 
750  if (clRef['name'] == -1) return null;
751 
752  var obj = {};
753 
754  this.MapObject(this.fTagOffset + startpos + JSROOT.IO.kMapOffset, obj);
755 
756  this.ClassStreamer(obj, clRef['name']);
757 
758  return obj;
759  };
760 
761  JSROOT.TBuffer.prototype.ClassStreamer = function(obj, classname) {
762  // console.log("Start streaming of class " + classname);
763 
764  if (! ('_typename' in obj)) obj['_typename'] = classname;
765 
766  if (classname == 'TObject' || classname == 'TMethodCall') {
767  this.ReadTObject(obj);
768  }
769  else if (classname == 'TQObject') {
770  // skip TQObject
771  }
772  else if (classname == 'TObjString') {
773  this.ReadTObjString(obj);
774  }
775  else if (classname == 'TObjArray') {
776  this.ReadTObjArray(obj);
777  }
778  else if (classname == 'TClonesArray') {
779  this.ReadTClonesArray(obj);
780  }
781  else if ((classname == 'TList') || (classname == 'THashList')) {
782  this.ReadTList(obj);
783  }
784  else if (classname == 'TCollection') {
785  this.ReadTCollection(obj);
786  alert("Trying to read TCollection - wrong!!!");
787  }
788  else if (classname == 'TCanvas') {
789  this.ReadTCanvas(obj);
790  }
791  else if (classname == 'TPolyMarker3D') {
792  this.ReadTPolyMarker3D(obj);
793  }
794  else if (classname == "TStreamerInfo") {
795  this.ReadTStreamerInfo(obj);
796  }
797  else if (classname == "TStreamerBase") {
798  this.ReadStreamerBase(obj);
799  }
800  else if (classname == "TStreamerBasicType") {
801  this.ReadStreamerBasicType(obj);
802  }
803  else if ((classname == "TStreamerBasicPointer") || (classname == "TStreamerLoop")) {
804  this.ReadStreamerBasicPointer(obj);
805  } else if (classname == "TStreamerSTL") {
806  this.ReadStreamerSTL(obj);
807  } else if (classname == "TStreamerObject" ||
808  classname == "TStreamerObjectAny" ||
809  classname == "TStreamerString" ||
810  classname == "TStreamerObjectPointer" ) {
811  this.ReadTStreamerObject(obj);
812  }
813  else {
814  var streamer = this.fFile.GetStreamer(classname);
815  if (streamer != null)
816  streamer.Stream(obj, this);
817  else {
818  console.log("Did not found streamer for class " + classname + " try to skip data");
819  var ver = this.ReadVersion();
820  this.CheckBytecount(ver);
821  }
822  }
823 
824  JSROOT.addMethods(obj);
825  }
826 
827 
828  // ==============================================================================
829 
830  // ctor
831  JSROOT.TStreamer = function(file) {
832  this.fFile = file;
833  this._typename = "TStreamer";
834  return this;
835  };
836 
837 
838  JSROOT.TStreamer.prototype.ReadBasicType = function(buf, obj, prop) {
839 
840  // read basic types (known from the streamer info)
841  switch (this[prop]['type']) {
842  case JSROOT.IO.kBase:
843  break;
844  case JSROOT.IO.kOffsetL:
845  break;
846  case JSROOT.IO.kOffsetP:
847  break;
848  case JSROOT.IO.kCharStar:
849  var n_el = obj[this[prop]['cntname']];
850  obj[prop] = buf.ReadBasicPointer(n_el, 'C');
851  break;
852  case JSROOT.IO.kChar:
853  case JSROOT.IO.kLegacyChar:
854  obj[prop] = buf.b.charCodeAt(buf.o++) & 0xff;
855  break;
856  case JSROOT.IO.kShort:
857  obj[prop] = buf.ntoi2();
858  break;
859  case JSROOT.IO.kInt:
860  case JSROOT.IO.kCounter:
861  obj[prop] = buf.ntoi4();
862  break;
863  case JSROOT.IO.kLong:
864  obj[prop] = buf.ntoi8();
865  break;
866  case JSROOT.IO.kFloat:
867  case JSROOT.IO.kDouble32:
868  obj[prop] = buf.ntof();
869  if (Math.abs(obj[prop]) < 1e-300) obj[prop] = 0.0;
870  break;
871  case JSROOT.IO.kDouble:
872  obj[prop] = buf.ntod();
873  if (Math.abs(obj[prop]) < 1e-300) obj[prop] = 0.0;
874  break;
875  case JSROOT.IO.kUChar:
876  obj[prop] = (buf.b.charCodeAt(buf.o++) & 0xff) >>> 0;
877  break;
878  case JSROOT.IO.kUShort:
879  obj[prop] = buf.ntou2();
880  break;
881  case JSROOT.IO.kUInt:
882  obj[prop] = buf.ntou4();
883  break;
884  case JSROOT.IO.kULong:
885  obj[prop] = buf.ntou8();
886  break;
887  case JSROOT.IO.kBits:
888  alert('failed to stream ' + prop + ' (' + this[prop]['typename'] + ')');
889  break;
890  case JSROOT.IO.kLong64:
891  obj[prop] = buf.ntoi8();
892  break;
893  case JSROOT.IO.kULong64:
894  obj[prop] = buf.ntou8();
895  break;
896  case JSROOT.IO.kBool:
897  obj[prop] = (buf.b.charCodeAt(buf.o++) & 0xff) != 0;
898  break;
899  case JSROOT.IO.kFloat16:
900  obj[prop] = 0;
901  buf.o += 2;
902  break;
903  case JSROOT.IO.kAny:
904  case JSROOT.IO.kAnyp:
905  case JSROOT.IO.kObjectp:
906  case JSROOT.IO.kObject:
907  var classname = this[prop]['typename'];
908  if (classname.charAt(classname.length-1) == "*")
909  classname = classname.substr(0, classname.length - 1);
910 
911  obj[prop] = {};
912  buf.ClassStreamer(obj[prop], classname);
913  break;
914 
915  case JSROOT.IO.kAnyP:
916  case JSROOT.IO.kObjectP:
917  obj[prop] = buf.ReadObjectAny();
918  break;
919  case JSROOT.IO.kTString:
920  obj[prop] = buf.ReadTString();
921  break;
922  case JSROOT.IO.kTObject:
923  buf.ReadTObject(obj);
924  break;
925  case JSROOT.IO.kTNamed:
926  buf.ReadTNamed(obj);
927  break;
928  case JSROOT.IO.kAnyPnoVT:
929  case JSROOT.IO.kSTLp:
930  case JSROOT.IO.kSkip:
931  case JSROOT.IO.kSkipL:
932  case JSROOT.IO.kSkipP:
933  case JSROOT.IO.kConv:
934  case JSROOT.IO.kConvL:
935  case JSROOT.IO.kConvP:
936  case JSROOT.IO.kSTL:
937  case JSROOT.IO.kSTLstring:
938  case JSROOT.IO.kStreamer:
939  case JSROOT.IO.kStreamLoop:
940  alert('failed to stream ' + prop + ' (' + this[prop]['typename'] + ')');
941  break;
942  case JSROOT.IO.kOffsetL+JSROOT.IO.kShort:
943  case JSROOT.IO.kOffsetL+JSROOT.IO.kUShort:
944  alert("Strange code was here????"); // var n_el = str.charCodeAt(o) & 0xff;
945  var n_el = this[prop]['length'];
946  obj[prop] = buf.ReadFastArray(n_el, 'S');
947  break;
948  case JSROOT.IO.kOffsetL+JSROOT.IO.kInt:
949  var n_el = this[prop]['length'];
950  obj[prop] = buf.ReadFastArray(n_el, 'I');
951  break;
952  case JSROOT.IO.kOffsetL+JSROOT.IO.kUInt:
953  var n_el = this[prop]['length'];
954  obj[prop] = buf.ReadFastArray(n_el, 'U');
955  break;
956  case JSROOT.IO.kOffsetL+JSROOT.IO.kULong:
957  case JSROOT.IO.kOffsetL+JSROOT.IO.kULong64:
958  var n_el = this[prop]['length'];
959  obj[prop] = buf.ReadFastArray(n_el, 'LU');
960  break;
961  case JSROOT.IO.kOffsetL+JSROOT.IO.kLong:
962  case JSROOT.IO.kOffsetL+JSROOT.IO.kLong64:
963  var n_el = this[prop]['length'];
964  obj[prop] = buf.ReadFastArray(n_el, 'L');
965  break;
966  case JSROOT.IO.kOffsetL+JSROOT.IO.kFloat:
967  case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble32:
968  //var n_el = str.charCodeAt(o) & 0xff;
969  var n_el = this[prop]['length'];
970  obj[prop] = buf.ReadFastArray(n_el, 'F');
971  break;
972  case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble:
973  //var n_el = str.charCodeAt(o) & 0xff;
974  var n_el = this[prop]['length'];
975  obj[prop] = buf.ReadFastArray(n_el, 'D');
976  break;
977  case JSROOT.IO.kOffsetP+JSROOT.IO.kChar:
978  var n_el = obj[this[prop]['cntname']];
979  obj[prop] = buf.ReadBasicPointer(n_el, 'C');
980  break;
981  case JSROOT.IO.kOffsetP+JSROOT.IO.kShort:
982  case JSROOT.IO.kOffsetP+JSROOT.IO.kUShort:
983  var n_el = obj[this[prop]['cntname']];
984  obj[prop] = buf.ReadBasicPointer(n_el, 'S');
985  break;
986  case JSROOT.IO.kOffsetP+JSROOT.IO.kInt:
987  var n_el = obj[this[prop]['cntname']];
988  obj[prop] = buf.ReadBasicPointer(n_el, 'I');
989  break;
990  case JSROOT.IO.kOffsetP+JSROOT.IO.kUInt:
991  var n_el = obj[this[prop]['cntname']];
992  obj[prop] = buf.ReadBasicPointer(n_el, 'U');
993  break;
994  case JSROOT.IO.kOffsetP+JSROOT.IO.kULong:
995  case JSROOT.IO.kOffsetP+JSROOT.IO.kULong64:
996  var n_el = obj[this[prop]['cntname']];
997  obj[prop] = buf.ReadBasicPointer(n_el, 'LU');
998  break;
999  case JSROOT.IO.kOffsetP+JSROOT.IO.kLong:
1000  case JSROOT.IO.kOffsetP+JSROOT.IO.kLong64:
1001  var n_el = obj[this[prop]['cntname']];
1002  obj[prop] = buf.ReadBasicPointer(n_el, 'L');
1003  break;
1004  case JSROOT.IO.kOffsetP+JSROOT.IO.kFloat:
1005  case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble32:
1006  var n_el = obj[this[prop]['cntname']];
1007  obj[prop] = buf.ReadBasicPointer(n_el, 'F');
1008  break;
1009  case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble:
1010  var n_el = obj[this[prop]['cntname']];
1011  obj[prop] = buf.ReadBasicPointer(n_el, 'D');
1012  break;
1013  default:
1014  alert('failed to stream ' + prop + ' (' + this[prop]['typename'] + ')');
1015  break;
1016  }
1017  };
1018 
1019  JSROOT.TStreamer.prototype.Stream = function(obj, buf) {
1020 
1021  var ver = buf.ReadVersion();
1022 
1023  // first base classes
1024  for (var prop in this) {
1025  if (!this[prop] || typeof(this[prop]) === "function")
1026  continue;
1027  if (this[prop]['typename'] === 'BASE') {
1028  var clname = this[prop]['class'];
1029  if (this[prop]['class'].indexOf("TArray") == 0) {
1030  var array_type = this[prop]['class'].charAt(6);
1031  obj['fN'] = buf.ntou4();
1032  obj['fArray'] = buf.ReadFastArray(obj['fN'], array_type);
1033  } else {
1034  buf.ClassStreamer(obj, this[prop]['class']);
1035  }
1036  }
1037  }
1038  // then class members
1039  for (var prop in this) {
1040 
1041  if (!this[prop] || typeof(this[prop]) === "function") continue;
1042 
1043  var prop_typename = this[prop]['typename'];
1044 
1045  if (typeof(prop_typename) === "undefined" || prop_typename === "BASE") continue;
1046 
1047  if (JSROOT.fUserStreamers !== null) {
1048  var user_func = JSROOT.fUserStreamers[prop_typename];
1049 
1050  if (user_func !== undefined) {
1051  user_func(buf, obj, prop, this);
1052  continue;
1053  }
1054  }
1055 
1056  // special classes (custom streamers)
1057  switch (prop_typename) {
1058  case "TString*":
1059  // TODO: check how and when it used
1060  var r__v = buf.ReadVersion();
1061  obj[prop] = new Array();
1062  for (var i = 0; i<obj[this[prop]['cntname']]; ++i )
1063  obj[prop][i] = buf.ReadTString();
1064  buf.CheckBytecount(r__v, "TString* array");
1065  break;
1066  case "TArrayC":
1067  case "TArrayD":
1068  case "TArrayF":
1069  case "TArrayI":
1070  case "TArrayL":
1071  case "TArrayL64":
1072  case "TArrayS":
1073  var array_type = this[prop]['typename'].charAt(6);
1074  var n = buf.ntou4();
1075  obj[prop] = buf.ReadFastArray(n, array_type);
1076  break;
1077  case "TObject":
1078  // TODO: check why it is here
1079  buf.ReadTObject(obj);
1080  break;
1081  case "TQObject":
1082  // TODO: check why it is here
1083  // skip TQObject...
1084  break;
1085  default:
1086  // basic types and standard streamers
1087  this.ReadBasicType(buf, obj, prop);
1088  break;
1089  }
1090  }
1091  if (('fBits' in obj) && !('TestBit' in obj)) {
1092  obj['TestBit'] = function (f) {
1093  return ((obj['fBits'] & f) != 0);
1094  };
1095  }
1096 
1097  buf.CheckBytecount(ver, "TStreamer.Stream");
1098 
1099  return buf.o;
1100 
1101  };
1102 
1103 
1104 
1105  // ==============================================================================
1106 
1107  // A class that reads a TDirectory from a buffer.
1108 
1109  // ctor
1110  JSROOT.TDirectory = function(file, dirname, cycle) {
1111  if (! (this instanceof arguments.callee) ) {
1112  var error = new Error("you must use new to instantiate this class");
1113  error.source = "JSROOT.TDirectory.ctor";
1114  throw error;
1115  }
1116 
1117  this.fFile = file;
1118  this._typename = "TDirectory";
1119  this['dir_name'] = dirname;
1120  this['dir_cycle'] = cycle;
1121  this.fKeys = new Array();
1122  return this;
1123  };
1124 
1125 
1126  JSROOT.TDirectory.prototype.GetKey = function(keyname, cycle, call_back) {
1127  // retrieve a key by its name and cycle in the list of keys
1128  for (var i in this.fKeys) {
1129  if (this.fKeys[i]['fName'] == keyname && this.fKeys[i]['fCycle'] == cycle) {
1130  if (typeof call_back == 'function') call_back(this.fKeys[i]);
1131  return this.fKeys[i];
1132  }
1133  }
1134 
1135  var pos = keyname.lastIndexOf("/");
1136  // try to handle situation when object name contains slashed (bad practice anyway)
1137  while (pos > 0) {
1138  var dirname = keyname.substr(0, pos);
1139  var subname = keyname.substr(pos+1);
1140 
1141  var dirkey = this.GetKey(dirname, 1);
1142  if ((dirkey!=null) && (typeof call_back == 'function') &&
1143  (dirkey['fClassName'].indexOf("TDirectory")==0)) {
1144 
1145  this.fFile.ReadObject(this['dir_name'] + "/" + dirname, 1, function(newdir) {
1146  if (newdir) newdir.GetKey(subname, cycle, call_back);
1147  });
1148  return null;
1149  }
1150 
1151  pos = keyname.lastIndexOf("/", pos-1);
1152  }
1153 
1154  if (typeof call_back == 'function') call_back(null);
1155  return null;
1156  }
1157 
1158  JSROOT.TDirectory.prototype.ReadKeys = function(readkeys_callback) {
1159 
1160  if (typeof readkeys_callback != 'function')
1161  readkeys_callback = function() {};
1162 
1163  var thisdir = this;
1164  var file = this.fFile;
1165 
1166  //*-*-------------Read directory info
1167  var nbytes = this.fNbytesName + 22;
1168  nbytes += 4; // fDatimeC.Sizeof();
1169  nbytes += 4; // fDatimeM.Sizeof();
1170  nbytes += 18; // fUUID.Sizeof();
1171  // assume that the file may be above 2 Gbytes if file version is > 4
1172  if (file.fVersion >= 40000) nbytes += 12;
1173 
1174  file.Seek(this.fSeekDir, this.fFile.ERelativeTo.kBeg);
1175  file.ReadBuffer(nbytes, function(blob1) {
1176  if (blob1==null) return readkeys_callback(null);
1177  var buf = new JSROOT.TBuffer(blob1, thisdir.fNbytesName, file);
1178 
1179  thisdir.StreamHeader(buf);
1180 
1181  //*-*---------read TKey::FillBuffer info
1182  buf.locate(4); // Skip NBytes;
1183  var keyversion = buf.ntoi2();
1184  // Skip ObjLen, DateTime, KeyLen, Cycle, SeekKey, SeekPdir
1185  if (keyversion > 1000) buf.shift(28); // Large files
1186  else buf.shift(20);
1187  buf.ReadTString();
1188  buf.ReadTString();
1189  thisdir.fTitle = buf.ReadTString();
1190  if (thisdir.fNbytesName < 10 || thisdir.fNbytesName > 10000) {
1191  console.log("Cannot read directory info of file " + file.fURL);
1192  return readkeys_callback(null);
1193  }
1194  //*-* -------------Read keys of the top directory
1195 
1196  if (thisdir.fSeekKeys <=0)
1197  return readkeys_callback(null);
1198 
1199  file.Seek(thisdir.fSeekKeys, file.ERelativeTo.kBeg);
1200  file.ReadBuffer(thisdir.fNbytesKeys, function(blob2) {
1201  if (blob2 == null) readkeys_callback(null);
1202 
1203  var buf = new JSROOT.TBuffer(blob2, 0, file);
1204 
1205  var key = file.ReadKey(buf);
1206 
1207  var nkeys = buf.ntoi4();
1208  for (var i = 0; i < nkeys; i++) {
1209  key = file.ReadKey(buf);
1210  thisdir.fKeys.push(key);
1211  }
1212  file.fDirectories.push(thisdir);
1213  delete buf;
1214 
1215  readkeys_callback(thisdir);
1216  });
1217 
1218  delete buf;
1219  });
1220  };
1221 
1222  JSROOT.TDirectory.prototype.StreamHeader = function(buf) {
1223  var version = buf.ntou2();
1224  var versiondir = version%1000;
1225  buf.shift(8); // skip fDatimeC and fDatimeM
1226  this.fNbytesKeys = buf.ntou4();
1227  this.fNbytesName = buf.ntou4();
1228  this.fSeekDir = (version > 1000) ? buf.ntou8() : buf.ntou4();
1229  this.fSeekParent = (version > 1000) ? buf.ntou8() : buf.ntou4();
1230  this.fSeekKeys = (version > 1000) ? buf.ntou8() : buf.ntou4();
1231  if (versiondir > 2) buf.shift(18); // skip fUUID
1232  };
1233 
1234 
1235  // ==============================================================================
1236  // A class that reads ROOT files.
1237  //
1239  // A ROOT file is a suite of consecutive data records (TKey's) with
1240  // the following format (see also the TKey class). If the key is
1241  // located past the 32 bit file limit (> 2 GB) then some fields will
1242  // be 8 instead of 4 bytes:
1243  // 1->4 Nbytes = Length of compressed object (in bytes)
1244  // 5->6 Version = TKey version identifier
1245  // 7->10 ObjLen = Length of uncompressed object
1246  // 11->14 Datime = Date and time when object was written to file
1247  // 15->16 KeyLen = Length of the key structure (in bytes)
1248  // 17->18 Cycle = Cycle of key
1249  // 19->22 [19->26] SeekKey = Pointer to record itself (consistency check)
1250  // 23->26 [27->34] SeekPdir = Pointer to directory header
1251  // 27->27 [35->35] lname = Number of bytes in the class name
1252  // 28->.. [36->..] ClassName = Object Class Name
1253  // ..->.. lname = Number of bytes in the object name
1254  // ..->.. Name = lName bytes with the name of the object
1255  // ..->.. lTitle = Number of bytes in the object title
1256  // ..->.. Title = Title of the object
1257  // -----> DATA = Data bytes associated to the object
1258  //
1259 
1260 
1261  // ctor
1262  JSROOT.TFile = function(url, newfile_callback) {
1263  if (! (this instanceof arguments.callee) ) {
1264  var error = new Error("you must use new to instantiate this class");
1265  error.source = "JSROOT.TFile.ctor";
1266  throw error;
1267  }
1268 
1269  this._typename = "TFile";
1270  this.fOffset = 0;
1271  this.fEND = 0;
1272  this.fURL = url;
1273  this.fAcceptRanges = true; // when disabled ('+' at the end of file name), complete file content read with single operation
1274  this.fFullFileContent = ""; // this can be full content of the file (if ranges are not supported)
1275 
1276  this.ERelativeTo = { kBeg : 0, kCur : 1, kEnd : 2 };
1277  this.fDirectories = new Array();
1278  this.fKeys = new Array();
1279  this.fSeekInfo = 0;
1280  this.fNbytesInfo = 0;
1281  this.fTagOffset = 0;
1282  this.fStreamers = 0;
1283  this.fStreamerInfos = null;
1284  this.fFileName = "";
1285  this.fStreamers = new Array;
1286 
1287  if (typeof this.fURL != 'string') return this;
1288 
1289  if (this.fURL.charAt(this.fURL.length-1) == "+") {
1290  this.fURL = this.fURL.substr(0, this.fURL.length-1);
1291  this.fAcceptRanges = false;
1292  }
1293 
1294  var pos = Math.max(this.fURL.lastIndexOf("/"), this.fURL.lastIndexOf("\\"));
1295  this.fFileName = pos>=0 ? this.fURL.substr(pos+1) : this.fURL;
1296 
1297  if (!this.fAcceptRanges) {
1298  this.ReadKeys(newfile_callback);
1299  } else {
1300  var file = this;
1301 
1302  var xhr = JSROOT.NewHttpRequest(this.fURL, "head", function(res) {
1303  if (res==null) {
1304  if (typeof newfile_callback == 'function')
1305  newfile_callback(null);
1306  return;
1307  }
1308 
1309  var accept_ranges = res.getResponseHeader("Accept-Ranges");
1310  if (accept_ranges==null) file.fAcceptRanges = false;
1311  var len = res.getResponseHeader("Content-Length");
1312  if (len!=null) file.fEND = parseInt(len);
1313  else file.fAcceptRanges = false;
1314  file.ReadKeys(newfile_callback);
1315  });
1316 
1317  xhr.send(null);
1318  }
1319 
1320  return this;
1321  }
1322 
1323  JSROOT.TFile.prototype.ReadBuffer = function(len, callback) {
1324 
1325  if (!this.fAcceptRanges && (this.fFullFileContent.length>0))
1326  return callback(this.fFullFileContent.substr(this.fOffset, len));
1327 
1328  var file = this;
1329 
1330  var url = this.fURL;
1331  if (this.fAcceptRanges) {
1332  // only when server accept ranges we could also try to avoid caching
1333  if (url.indexOf('?')>0) url+="&stamp="; else url += "?stamp=";
1334  var d = new Date;
1335  url += d.getTime();
1336  }
1337 
1338  var xhr = JSROOT.NewHttpRequest(url, "bin", function(res) {
1339  if ((res!=null) && !file.fAcceptRanges && (file.fFullFileContent.length == 0)) {
1340  // special case - read content all at once
1341  file.fFullFileContent = res;
1342  file.fEND = res.length;
1343  res = file.fFullFileContent.substr(file.fOffset, len);
1344  }
1345 
1346  callback(res);
1347  });
1348 
1349  if (this.fAcceptRanges)
1350  xhr.setRequestHeader("Range", "bytes=" + this.fOffset + "-" + (this.fOffset + len - 1));
1351  // does not work when used with CORS requests
1352  // xhr.setRequestHeader("If-Modified-Since", "Wed, 31 Dec 1980 00:00:00 GMT");
1353  xhr.send(null);
1354  };
1355 
1356  JSROOT.TFile.prototype.Seek = function(offset, pos) {
1357  // Set position from where to start reading.
1358  switch (pos) {
1359  case this.ERelativeTo.kBeg:
1360  this.fOffset = offset;
1361  break;
1362  case this.ERelativeTo.kCur:
1363  this.fOffset += offset;
1364  break;
1365  case this.ERelativeTo.kEnd:
1366  // this option is not used currently in the ROOT code
1367  if (this.fEND == 0)
1368  throw "Seek : seeking from end in file with fEND==0 is not supported";
1369  this.fOffset = this.fEND - offset;
1370  break;
1371  default:
1372  throw "Seek : unknown seek option (" + pos + ")";
1373  break;
1374  }
1375  };
1376 
1377  JSROOT.TFile.prototype.ReadHeader = function(str) {
1378  // read the Root header file informations
1379  if (str.substring(0, 4) != "root") {
1380  //alert("NOT A ROOT FILE!");
1381  return null;
1382  }
1383  var header = {};
1384 
1385  var buf = new JSROOT.TBuffer(str, 4, this); // skip root
1386  header['version'] = buf.ntou4();
1387  header['begin'] = buf.ntou4();
1388  var largeFile = header['version'] >= 1000000;
1389  header['end'] = largeFile ? buf.ntou8() : buf.ntou4();
1390  header['seekFree'] = largeFile ? buf.ntou8() : buf.ntou4();
1391  buf.shift(12); // skip fNBytesFree, nfree, fNBytesName
1392  header['units'] = buf.ntoi1();
1393  header['fCompress'] = buf.ntou4();
1394  header['seekInfo'] = largeFile ? buf.ntou8() : buf.ntou4();
1395  header['nbytesInfo'] = buf.ntou4();
1396 
1397  if (!header['seekInfo'] && !header['nbytesInfo']) {
1398  // empty file
1399  return null;
1400  }
1401  this.fSeekInfo = header['seekInfo'];
1402  this.fNbytesInfo = header['nbytesInfo'];
1403  return header;
1404  };
1405 
1406  JSROOT.TFile.prototype.ReadKey = function(buf) {
1407  // read key from buffer
1408  var key = {};
1409 
1410  key['fNbytes'] = buf.ntoi4();
1411  key['fVersion'] = buf.ntoi2();
1412  key['fObjlen'] = buf.ntou4();
1413  var datime = buf.ntou4();
1414  key['fDatime'] = new Date();
1415  key['fDatime'].setFullYear((datime >>> 26) + 1995);
1416  key['fDatime'].setMonth((datime << 6) >>> 28);
1417  key['fDatime'].setDate((datime << 10) >>> 27);
1418  key['fDatime'].setHours((datime << 15) >>> 27);
1419  key['fDatime'].setMinutes((datime << 20) >>> 26);
1420  key['fDatime'].setSeconds((datime << 26) >>> 26);
1421  key['fDatime'].setMilliseconds(0);
1422  key['fKeylen'] = buf.ntou2();
1423  key['fCycle'] = buf.ntou2();
1424  if (key['fVersion'] > 1000) {
1425  key['fSeekKey'] = buf.ntou8();
1426  buf.shift(8); // skip seekPdir
1427  } else {
1428  key['fSeekKey'] = buf.ntou4();
1429  buf.shift(4); // skip seekPdir
1430  }
1431  key['fClassName'] = buf.ReadTString();
1432  key['fName'] = buf.ReadTString();
1433  key['fTitle'] = buf.ReadTString();
1434 
1435  var name = key['fName'].replace(/['"]/g,'');
1436 
1437  if (name != key['fName']) {
1438  key['fRealName'] = key['fName'];
1439  key['fName'] = name;
1440  }
1441 
1442  return key;
1443  };
1444 
1445  JSROOT.TFile.prototype.GetDir = function(dirname, cycle) {
1446  // check first that directory with such name exists
1447  for (var j in this.fDirectories) {
1448  var dir = this.fDirectories[j];
1449  if (dir['dir_name'] != dirname) continue;
1450  if ((cycle!=null) && (dir['dir_cycle']!=cycle)) continue;
1451  return dir;
1452  }
1453  return null;
1454  }
1455 
1456  JSROOT.TFile.prototype.GetKey = function(keyname, cycle, getkey_callback) {
1457  // retrieve a key by its name and cycle in the list of keys
1458  // one should call_back when keys must be read first from the directory
1459 
1460  for (var i in this.fKeys) {
1461  if (this.fKeys[i]['fName'] == keyname && this.fKeys[i]['fCycle'] == cycle) {
1462  if (typeof getkey_callback == 'function') getkey_callback(this.fKeys[i]);
1463  return this.fKeys[i];
1464  }
1465  }
1466 
1467  var pos = keyname.lastIndexOf("/");
1468  // try to handle situation when object name contains slashed (bad practice anyway)
1469  while (pos > 0) {
1470  var dirname = keyname.substr(0, pos);
1471  var subname = keyname.substr(pos+1);
1472 
1473  var dir = this.GetDir(dirname);
1474  if (dir!=null) return dir.GetKey(subname, cycle, getkey_callback);
1475 
1476  var dirkey = this.GetKey(dirname, 1);
1477  if ((dirkey!=null) && (typeof getkey_callback == 'function') &&
1478  (dirkey['fClassName'].indexOf("TDirectory")==0)) {
1479 
1480  this.ReadObject(dirname, function(newdir) {
1481  if (newdir) newdir.GetKey(subname, cycle, getkey_callback);
1482  });
1483  return null;
1484  }
1485 
1486  pos = keyname.lastIndexOf("/", pos-1);
1487  }
1488 
1489  if (typeof call_back == 'function') call_back(null);
1490  return null;
1491  };
1492 
1493  JSROOT.TFile.prototype.ReadObjBuffer = function(key, callback) {
1494  // read and inflate object buffer described by its key
1495 
1496  var file = this;
1497 
1498  this.Seek(key['fSeekKey'] + key['fKeylen'], this.ERelativeTo.kBeg);
1499  this.ReadBuffer(key['fNbytes'] - key['fKeylen'], function(blob1) {
1500 
1501  if (blob1==null) callback(null);
1502 
1503  var buf = null;
1504 
1505  if (key['fObjlen'] <= key['fNbytes']-key['fKeylen']) {
1506  buf = new JSROOT.TBuffer(blob1, 0, file);
1507  } else {
1508  var hdrsize = JSROOT.R__unzip_header(blob1, 0);
1509  if (hdrsize<0) return callback(null);
1510  var objbuf = JSROOT.R__unzip(hdrsize, blob1, 0);
1511  buf = new JSROOT.TBuffer(objbuf, 0, file);
1512  }
1513 
1514  buf.fTagOffset = key.fKeylen;
1515  callback(buf);
1516  delete buf;
1517  });
1518  };
1519 
1520  JSROOT.TFile.prototype.ReadObject = function(obj_name, cycle, user_call_back) {
1521  // Read any object from a root file
1522  // One could specify cycle number in the object name or as separate argument
1523  // Last argument should be callback function, while data reading from file is asynchron
1524 
1525  if (typeof cycle == 'function') { user_call_back = cycle; cycle = 1; }
1526 
1527  var pos = obj_name.lastIndexOf(";");
1528  if (pos>0) {
1529  cycle = parseInt(obj_name.slice(pos+1));
1530  obj_name = obj_name.slice(0, pos);
1531  }
1532 
1533  if ((typeof cycle != 'number') || (cycle<0)) cycle = 1;
1534 
1535  var file = this;
1536 
1537  // we use callback version while in some cases we need to
1538  // read sub-directory to get list of keys
1539  // in such situation calls are asynchrone
1540  this.GetKey(obj_name, cycle, function(key) {
1541 
1542  if (key == null) {
1543  if (typeof user_call_back == 'function') user_call_back(null);
1544  return;
1545  }
1546 
1547  var isdir = false;
1548  if ((key['fClassName'] == 'TDirectory' || key['fClassName'] == 'TDirectoryFile')) {
1549  isdir = true;
1550  var dir = file.GetDir(obj_name, cycle);
1551  if (dir!=null) {
1552  if (typeof user_call_back == 'function') user_call_back(dir);
1553  return;
1554  }
1555  }
1556 
1557  file.ReadObjBuffer(key, function(buf) {
1558  if (!buf) {
1559  if (typeof user_call_back == 'function') user_call_back(null);
1560  return;
1561  }
1562 
1563  if (isdir) {
1564  var dir = new JSROOT.TDirectory(file, obj_name, cycle);
1565  dir.StreamHeader(buf);
1566  if (dir.fSeekKeys) {
1567  dir.ReadKeys(user_call_back);
1568  } else {
1569  if (typeof user_call_back == 'function') user_call_back(dir);
1570  }
1571 
1572  return;
1573  }
1574 
1575  var obj = {};
1576  buf.MapObject(1, obj); // tag object itself with id==1
1577  buf.ClassStreamer(obj, key['fClassName']);
1578 
1579  if (typeof user_call_back == 'function') user_call_back(obj);
1580  }); // end of ReadObjBuffer callback
1581  }); // end of GetKey callback
1582  };
1583 
1584  JSROOT.TFile.prototype.ExtractStreamerInfos = function(buf)
1585  {
1586  if (!buf) return;
1587 
1588  var lst = {};
1589  buf.MapObject(1, lst);
1590  buf.ClassStreamer(lst, 'TList');
1591 
1592  lst['_typename'] = "TStreamerInfoList";
1593 
1594  this.fStreamerInfos = lst;
1595  }
1596 
1597  JSROOT.TFile.prototype.ReadFormulas = function()
1598  {
1599  for (var i in this.fKeys)
1600  if (this.fKeys[i]['fClassName'] == 'TFormula')
1601  this.ReadObject(this.fKeys[i]['fName'], this.fKeys[i]['fCycle'], function(obj) {
1602  JSROOT.addFormula(obj);
1603  });
1604  }
1605 
1606  JSROOT.TFile.prototype.ReadStreamerInfos = function(si_callback)
1607  {
1608  if (this.fSeekInfo == 0 || this.fNbytesInfo == 0) return si_callback(null);
1609  this.Seek(this.fSeekInfo, this.ERelativeTo.kBeg);
1610 
1611  var file = this;
1612 
1613  file.ReadBuffer(file.fNbytesInfo, function(blob1) {
1614  var buf = new JSROOT.TBuffer(blob1, 0, file);
1615  var key = file.ReadKey(buf);
1616  if (key == null) return si_callback(null);
1617  file.fKeys.push(key);
1618 
1619  file.ReadObjBuffer(key, function(blob2) {
1620  if (blob2==null) return si_callback(null);
1621  file.ExtractStreamerInfos(blob2);
1622  file.ReadFormulas();
1623  si_callback(file);
1624  });
1625  });
1626  };
1627 
1628  JSROOT.TFile.prototype.ReadKeys = function(readkeys_callback) {
1629  // read keys only in the root file
1630 
1631  if (typeof readkeys_callback != 'function')
1632  readkeys_callback = function() {};
1633 
1634  var file = this;
1635 
1636  this.ReadBuffer(256, function(blob1) {
1637  var header = file.ReadHeader(blob1);
1638  if (header == null) return readkeys_callback(null);
1639 
1640  file.ReadBuffer(300, function(blob2) {
1641  if (blob2==null) return readkeys_callback(null);
1642 
1643  var buf = new JSROOT.TBuffer(blob2, 4, file); // skip the "root" file identifier
1644  file.fVersion = buf.ntou4();
1645  var headerLength = buf.ntou4();
1646  file.fBEGIN = headerLength;
1647  if (file.fVersion < 1000000) { //small file
1648  file.fEND = buf.ntou4();
1649  file.fSeekFree = buf.ntou4();
1650  file.fNbytesFree = buf.ntou4();
1651  var nfree = buf.ntoi4();
1652  file.fNbytesName = buf.ntou4();
1653  file.fUnits = buf.ntou1();
1654  file.fCompress = buf.ntou4();
1655  file.fSeekInfo = buf.ntou4();
1656  file.fNbytesInfo = buf.ntou4();
1657  } else { // new format to support large files
1658  file.fEND = buf.ntou8();
1659  file.fSeekFree = buf.ntou8();
1660  file.fNbytesFree = buf.ntou4();
1661  var nfree = buf.ntou4();
1662  file.fNbytesName = buf.ntou4();
1663  file.fUnits = buf.ntou1();
1664  file.fCompress = buf.ntou4();
1665  file.fSeekInfo = buf.ntou8();
1666  file.fNbytesInfo = buf.ntou4();
1667  }
1668  file.fSeekDir = file.fBEGIN;
1669 
1670  //*-*-------------Read directory info
1671 
1672  var nbytes = file.fNbytesName + 22;
1673  nbytes += 4; // fDatimeC.Sizeof();
1674  nbytes += 4; // fDatimeM.Sizeof();
1675  nbytes += 18; // fUUID.Sizeof();
1676  // assume that the file may be above 2 Gbytes if file version is > 4
1677  if (file.fVersion >= 40000) nbytes += 12;
1678 
1679  file.Seek(file.fBEGIN, file.ERelativeTo.kBeg);
1680  file.ReadBuffer(Math.max(300, nbytes), function(blob3) {
1681  if (blob3==null) return readkeys_callback(null);
1682 
1683  var buf = new JSROOT.TBuffer(blob3, file.fNbytesName, file);
1684  var version = buf.ntou2();
1685  var versiondir = version%1000;
1686  buf.shift(8); // skip fDatimeC and fDatimeM
1687  file.fNbytesKeys = buf.ntou4();
1688  file.fNbytesName = buf.ntou4();
1689  if (version > 1000) {
1690  file.fSeekDir = buf.ntou8();
1691  file.fSeekParent = buf.ntou8();
1692  file.fSeekKeys = buf.ntou8();
1693  } else {
1694  file.fSeekDir = buf.ntou4();
1695  file.fSeekParent = buf.ntou4();
1696  file.fSeekKeys = buf.ntou4();
1697  }
1698  if (versiondir > 1) buf.o += 18; // skip fUUID
1699 
1700  //*-*---------read TKey::FillBuffer info
1701  buf.o = 4; // Skip NBytes;
1702  var keyversion = buf.ntoi2();
1703  // Skip ObjLen, DateTime, KeyLen, Cycle, SeekKey, SeekPdir
1704  if (keyversion > 1000) buf.shift(28); // Large files
1705  else buf.shift(20);
1706  buf.ReadTString();
1707  buf.ReadTString();
1708  file.fTitle = buf.ReadTString();
1709  if (file.fNbytesName < 10 || this.fNbytesName > 10000) {
1710  console.log("Init : cannot read directory info of file " + file.fURL);
1711  return readkeys_callback(null);
1712  }
1713  //*-* -------------Read keys of the top directory
1714 
1715  if (file.fSeekKeys <= 0) {
1716  console.log("Empty keys list - not supported" + file.fURL);
1717  return readkeys_callback(null);
1718  }
1719 
1720  file.Seek(file.fSeekKeys, file.ERelativeTo.kBeg);
1721  file.ReadBuffer(file.fNbytesKeys, function(blob4) {
1722  if (blob4==null) return readkeys_callback(null);
1723 
1724  var buf = new JSROOT.TBuffer(blob4, 0, file);
1725 
1726  var key = file.ReadKey(buf);
1727 
1728  var nkeys = buf.ntoi4();
1729  for (var i = 0; i < nkeys; i++) {
1730  key = file.ReadKey(buf);
1731  file.fKeys.push(key);
1732  }
1733  file.ReadStreamerInfos(readkeys_callback);
1734  delete buf;
1735  });
1736  delete buf;
1737  });
1738  delete buf;
1739  });
1740  delete buf;
1741  });
1742  };
1743 
1744  JSROOT.TFile.prototype.ReadDirectory = function(dir_name, cycle, readdir_callback) {
1745  // read the directory content from a root file
1746  // do not read directory if it is already exists
1747 
1748  return this.ReadObject(dir_name, cycle, readdir_callback);
1749  }
1750 
1751 
1752  JSROOT.TFile.prototype.GetStreamer = function(clname) {
1753  // return the streamer for the class 'clname', from the list of streamers
1754  // or generate it from the streamer infos and add it to the list
1755 
1756  var streamer = this.fStreamers[clname];
1757  if (typeof(streamer) != 'undefined') return streamer;
1758 
1759  var s_i;
1760 
1761  if (this.fStreamerInfos)
1762  for (var i in this.fStreamerInfos.arr)
1763  if (this.fStreamerInfos.arr[i].fName == clname) {
1764  s_i = this.fStreamerInfos.arr[i];
1765  break;
1766  }
1767  if (typeof s_i == 'undefined') return null;
1768 
1769  this.fStreamers[clname] = new JSROOT.TStreamer(this);
1770  if (typeof(s_i['fElements']) != 'undefined') {
1771  var n_el = s_i['fElements']['arr'].length;
1772  for (var j=0;j<n_el;++j) {
1773  var element = s_i['fElements']['arr'][j];
1774  if (element['typename'] === 'BASE') {
1775  // generate streamer for the base classes
1776  this.GetStreamer(element['fName']);
1777  }
1778  }
1779  }
1780  if (typeof(s_i['fElements']) != 'undefined') {
1781  var n_el = s_i['fElements']['arr'].length;
1782  for (var j=0;j<n_el;++j) {
1783  // extract streamer info for each class member
1784  var element = s_i['fElements']['arr'][j];
1785  var streamer = {};
1786  streamer['typename'] = element['typename'];
1787  streamer['class'] = element['fName'];
1788  streamer['cntname'] = element['countName'];
1789  streamer['type'] = element['type'];
1790  streamer['length'] = element['length'];
1791 
1792  this.fStreamers[clname][element['fName']] = streamer;
1793  }
1794  }
1795  return this.fStreamers[clname];
1796  };
1797 
1798  JSROOT.TFile.prototype.Delete = function() {
1799  if (this.fDirectories) this.fDirectories.splice(0, this.fDirectories.length);
1800  this.fDirectories = null;
1801  if (this.fKeys) this.fKeys.splice(0, this.fKeys.length);
1802  this.fKeys = null;
1803  if (this.fStreamers) this.fStreamers.splice(0, this.fStreamers.length);
1804  this.fStreamers = null;
1805  this.fSeekInfo = 0;
1806  this.fNbytesInfo = 0;
1807  this.fTagOffset = 0;
1808  };
1809 
1810 })();
1811 
1812 // JSRootIOEvolution.js ends
1813