otsdaq_utilities  v2_05_02_indev
JSRootIOEvolution.js
1 
4 (function( factory ) {
5  if ( typeof define === "function" && define.amd ) {
6  define( ['JSRootCore', 'rawinflate'], factory );
7  } else if (typeof exports === 'object' && typeof module !== 'undefined') {
8  require("./rawinflate.min.js");
9  factory(require("./JSRootCore.js"));
10  } else {
11  if (typeof JSROOT == 'undefined')
12  throw new Error("JSROOT I/O requires JSRootCore.js", "JSRootIOEvolution.js");
13  if (typeof JSROOT.ZIP == 'undefined')
14  throw new Error("JSROOT I/O requires rawinflate.js", "JSRootIOEvolution.js");
15  if (typeof JSROOT.IO == "object")
16  throw new Error("This JSROOT IO already loaded", "JSRootIOEvolution.js");
17  factory(JSROOT);
18  }
19 } (function(JSROOT) {
20 
21  "use strict";
22 
23  JSROOT.sources.push("io");
24 
25  JSROOT.IO = {
26  kBase: 0, kOffsetL: 20, kOffsetP: 40,
27  kChar: 1, kShort: 2, kInt: 3, kLong: 4, kFloat: 5, kCounter: 6, kCharStar: 7, kDouble: 8, kDouble32: 9, kLegacyChar : 10,
28  kUChar: 11, kUShort: 12, kUInt: 13, kULong: 14, kBits: 15, kLong64: 16, kULong64: 17, kBool: 18, kFloat16: 19,
29  kObject: 61, kAny: 62, kObjectp: 63, kObjectP: 64, kTString: 65,
30  kTObject: 66, kTNamed: 67, kAnyp: 68, kAnyP: 69, kAnyPnoVT: 70, kSTLp: 71,
31  kSkip: 100, kSkipL: 120, kSkipP: 140, kConv: 200, kConvL: 220, kConvP: 240,
32  kSTL: 300, kSTLstring: 365, kStreamer: 500, kStreamLoop: 501,
33  kMapOffset: 2,
34  kByteCountMask: 0x40000000,
35  kNewClassTag: 0xFFFFFFFF,
36  kClassMask: 0x80000000,
37  Mode: "array", // could be string or array, enable usage of ArrayBuffer in http requests
38  NativeArray: true, // when true, native arrays like Int32Array or Float64Array are used
39 
40  TypeNames : ["BASE", "char", "short", "int", "long", "float", "int", "const char*", "double", "Double32_t",
41  "char", "unsigned char", "unsigned short", "unsigned", "unsigned long", "unsigned", "Long64_t", "ULong64_t", "bool", "Float16_t"],
42 
43  // constants used for coding type of STL container
44  kNotSTL: 0, kSTLvector: 1, kSTLlist: 2, kSTLdeque: 3, kSTLmap: 4, kSTLmultimap: 5,
45  kSTLset: 6, kSTLmultiset: 7, kSTLbitset: 8, kSTLforwardlist: 9,
46  kSTLunorderedset : 10, kSTLunorderedmultiset : 11, kSTLunorderedmap : 12,
47  kSTLunorderedmultimap : 13, kSTLend : 14,
48 
49  // names of STL containers
50  StlNames: [ "", "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset"],
51 
52  // constants of bits in version
53  kStreamedMemberWise: JSROOT.BIT(14),
54 
55  kSplitCollectionOfPointers: 100,
56 
57  // map of user-streamer function like func(buf,obj)
58  // or alias (classname) which can be used to read that function
59  // or list of read functions
60  CustomStreamers: {},
61 
62  // these are streamers which do not handle version regularly
63  // used for special classes like TRef or TBasket
64  DirectStreamers: {},
65 
66  // TOBject bits
67  kIsReferenced: JSROOT.BIT(4),
68  kHasUUID: JSROOT.BIT(5),
69 
70  IsInteger: function(typ) { return ((typ>=this.kChar) && (typ<=this.kLong)) || (typ===this.kCounter) ||
71  ((typ>=this.kLegacyChar) && (typ<=this.kBool)); },
72 
73  IsNumeric: function(typ) { return (typ>0) && (typ<=this.kBool) && (typ!==this.kCharStar); },
74 
75  GetTypeId: function(typname, norecursion) {
76  switch (typname) {
77  case "bool":
78  case "Bool_t": return JSROOT.IO.kBool;
79  case "char":
80  case "signed char":
81  case "Char_t": return JSROOT.IO.kChar;
82  case "Color_t":
83  case "Style_t":
84  case "Width_t":
85  case "short":
86  case "Short_t": return JSROOT.IO.kShort;
87  case "int":
88  case "EErrorType":
89  case "Int_t": return JSROOT.IO.kInt;
90  case "long":
91  case "Long_t": return JSROOT.IO.kLong;
92  case "float":
93  case "Float_t": return JSROOT.IO.kFloat;
94  case "double":
95  case "Double_t": return JSROOT.IO.kDouble;
96  case "unsigned char":
97  case "UChar_t": return JSROOT.IO.kUChar;
98  case "unsigned short":
99  case "UShort_t": return JSROOT.IO.kUShort;
100  case "unsigned":
101  case "unsigned int":
102  case "UInt_t": return JSROOT.IO.kUInt;
103  case "unsigned long":
104  case "ULong_t": return JSROOT.IO.kULong;
105  case "int64_t":
106  case "long long":
107  case "Long64_t": return JSROOT.IO.kLong64;
108  case "uint64_t":
109  case "unsigned long long":
110  case "ULong64_t": return JSROOT.IO.kULong64;
111  case "Double32_t": return JSROOT.IO.kDouble32;
112  case "Float16_t": return JSROOT.IO.kFloat16;
113  case "char*":
114  case "const char*":
115  case "const Char_t*": return JSROOT.IO.kCharStar;
116  }
117 
118  if (!norecursion) {
119  var replace = JSROOT.IO.CustomStreamers[typname];
120  if (typeof replace === "string") return JSROOT.IO.GetTypeId(replace, true);
121  }
122 
123  return -1;
124  },
125 
126  GetTypeSize: function(typname) {
127  switch (typname) {
128  case JSROOT.IO.kBool: return 1;
129  case JSROOT.IO.kChar: return 1;
130  case JSROOT.IO.kShort : return 2;
131  case JSROOT.IO.kInt: return 4;
132  case JSROOT.IO.kLong: return 8;
133  case JSROOT.IO.kFloat: return 4;
134  case JSROOT.IO.kDouble: return 8;
135  case JSROOT.IO.kUChar: return 1;
136  case JSROOT.IO.kUShort: return 2;
137  case JSROOT.IO.kUInt: return 4;
138  case JSROOT.IO.kULong: return 8;
139  case JSROOT.IO.kLong64: return 8;
140  case JSROOT.IO.kULong64: return 8;
141  }
142  return -1;
143  }
144 
145  };
146 
147  JSROOT.addUserStreamer = function(type, user_streamer) {
148  JSROOT.IO.CustomStreamers[type] = user_streamer;
149  }
150 
151  JSROOT.R__unzip = function(arr, tgtsize, noalert, src_shift) {
152  // Reads header envelope, determines zipped size and unzip content
153 
154  var totallen = arr.byteLength, curr = src_shift || 0, fullres = 0, tgtbuf = null, HDRSIZE = 9;
155 
156  function getChar(o) { return String.fromCharCode(arr.getUint8(o)); }
157 
158  function getCode(o) { return arr.getUint8(o); }
159 
160  while (fullres < tgtsize) {
161 
162  var fmt = "unknown", off = 0, CHKSUM = 0;
163 
164  if (curr + HDRSIZE >= totallen) {
165  if (!noalert) JSROOT.alert("Error R__unzip: header size exceeds buffer size");
166  return null;
167  }
168 
169  if (getChar(curr) == 'Z' && getChar(curr+1) == 'L' && getCode(curr+2) == 8) { fmt = "new"; off = 2; } else
170  if (getChar(curr) == 'C' && getChar(curr+1) == 'S' && getCode(curr+2) == 8) { fmt = "old"; off = 0; } else
171  if (getChar(curr) == 'X' && getChar(curr+1) == 'Z') fmt = "LZMA"; else
172  if (getChar(curr) == 'L' && getChar(curr+1) == '4') { fmt = "LZ4"; off = 0; CHKSUM = 8; }
173 
174 /*
175  if (fmt == "LZMA") {
176  console.log('find LZMA');
177  console.log('chars', getChar(curr), getChar(curr+1), getChar(curr+2));
178 
179  for(var n=0;n<20;++n)
180  console.log('codes',n,getCode(curr+n));
181 
182  var srcsize = HDRSIZE + ((getCode(curr+3) & 0xff) | ((getCode(curr+4) & 0xff) << 8) | ((getCode(curr+5) & 0xff) << 16));
183 
184  var tgtsize0 = ((getCode(curr+6) & 0xff) | ((getCode(curr+7) & 0xff) << 8) | ((getCode(curr+8) & 0xff) << 16));
185 
186 
187  console.log('srcsize',srcsize, tgtsize0, tgtsize);
188 
189  off = 0;
190 
191  var uint8arr = new Uint8Array(arr.buffer, arr.byteOffset + curr + HDRSIZE + off, arr.byteLength - curr - HDRSIZE - off);
192 
193  JSROOT.LZMA.decompress(uint8arr, function on_decompress_complete(result) {
194  console.log("Decompressed done", typeof result, result);
195  }, function on_decompress_progress_update(percent) {
197  console.log("Decompressing: " + (percent * 100) + "%");
198  });
199 
200  return null;
201  }
202 */
203 
204  /* C H E C K H E A D E R */
205  if ((fmt !== "new") && (fmt !== "old") && (fmt !== "LZ4")) {
206  if (!noalert) JSROOT.alert("R__unzip: " + fmt + " format is not supported!");
207  return null;
208  }
209 
210  var srcsize = HDRSIZE + ((getCode(curr+3) & 0xff) | ((getCode(curr+4) & 0xff) << 8) | ((getCode(curr+5) & 0xff) << 16));
211 
212  var uint8arr = new Uint8Array(arr.buffer, arr.byteOffset + curr + HDRSIZE + off + CHKSUM, Math.min(arr.byteLength - curr - HDRSIZE - off - CHKSUM, srcsize - HDRSIZE - CHKSUM));
213 
214  // place for unpacking
215  if (!tgtbuf) tgtbuf = new ArrayBuffer(tgtsize);
216 
217  var tgt8arr = new Uint8Array(tgtbuf, fullres);
218 
219  var reslen = (fmt === "LZ4") ? JSROOT.LZ4.uncompress(uint8arr, tgt8arr)
220  : JSROOT.ZIP.inflate(uint8arr, tgt8arr);
221  if (reslen<=0) break;
222 
223  fullres += reslen;
224  curr += srcsize;
225  }
226 
227  if (fullres !== tgtsize) {
228  if (!noalert) JSROOT.alert("R__unzip: fail to unzip data expects " + tgtsize + " , got " + fullres);
229  return null;
230  }
231 
232  return new DataView(tgtbuf);
233  }
234 
235  // =================================================================================
236 
237  function TBuffer(arr, pos, file, length) {
238  // buffer takes with DataView as first argument
239  this._typename = "TBuffer";
240  this.arr = arr;
241  this.o = pos || 0;
242  this.fFile = file;
243  this.length = length || (arr ? arr.byteLength : 0); // use size of array view, blob buffer can be much bigger
244  this.ClearObjectMap();
245  this.fTagOffset = 0;
246  this.last_read_version = 0;
247  return this;
248  }
249 
250  TBuffer.prototype.locate = function(pos) {
251  this.o = pos;
252  }
253 
254  TBuffer.prototype.shift = function(cnt) {
255  this.o += cnt;
256  }
257 
258  TBuffer.prototype.remain = function() {
259  return this.length - this.o;
260  }
261 
262  TBuffer.prototype.GetMappedObject = function(tag) {
263  return this.fObjectMap[tag];
264  }
265 
266  TBuffer.prototype.MapObject = function(tag, obj) {
267  if (obj!==null)
268  this.fObjectMap[tag] = obj;
269  }
270 
271  TBuffer.prototype.MapClass = function(tag, classname) {
272  this.fClassMap[tag] = classname;
273  }
274 
275  TBuffer.prototype.GetMappedClass = function(tag) {
276  if (tag in this.fClassMap) return this.fClassMap[tag];
277  return -1;
278  }
279 
280  TBuffer.prototype.ClearObjectMap = function() {
281  this.fObjectMap = {};
282  this.fClassMap = {};
283  this.fObjectMap[0] = null;
284  this.fDisplacement = 0;
285  }
286 
287  TBuffer.prototype.ReadVersion = function() {
288  // read class version from I/O buffer
289  var ver = {}, bytecnt = this.ntou4(); // byte count
290 
291  if (bytecnt & JSROOT.IO.kByteCountMask)
292  ver.bytecnt = bytecnt - JSROOT.IO.kByteCountMask - 2; // one can check between Read version and end of streamer
293  else
294  this.o -= 4; // rollback read bytes, this is old buffer without byte count
295 
296  this.last_read_version = ver.val = this.ntoi2();
297  this.last_read_checksum = 0;
298  ver.off = this.o;
299 
300  if ((ver.val <= 0) && ver.bytecnt && (ver.bytecnt>=4)) {
301  ver.checksum = this.ntou4();
302  if (!this.fFile.FindSinfoCheckum(ver.checksum)) {
303  // JSROOT.console('Fail to find streamer info with check sum ' + ver.checksum + ' version ' + ver.val);
304  this.o-=4; // not found checksum in the list
305  delete ver.checksum; // remove checksum
306  } else {
307  this.last_read_checksum = ver.checksum;
308  }
309  }
310  return ver;
311  }
312 
313  TBuffer.prototype.CheckBytecount = function(ver, where) {
314  if ((ver.bytecnt !== undefined) && (ver.off + ver.bytecnt !== this.o)) {
315  if (where!=null) {
316  // alert("Missmatch in " + where + " bytecount expected = " + ver.bytecnt + " got = " + (this.o-ver.off));
317  console.log("Missmatch in " + where + " bytecount expected = " + ver.bytecnt + " got = " + (this.o-ver.off));
318  }
319  this.o = ver.off + ver.bytecnt;
320  return false;
321  }
322  return true;
323  }
324 
325  TBuffer.prototype.ReadTString = function() {
326  // stream a TString object from buffer
327  // std::string uses similar binary format
328  var len = this.ntou1();
329  // large strings
330  if (len == 255) len = this.ntou4();
331  if (len==0) return "";
332 
333  var pos = this.o;
334  this.o += len;
335 
336  return (this.codeAt(pos) == 0) ? '' : this.substring(pos, pos + len);
337  }
338 
339  TBuffer.prototype.ReadFastString = function(n) {
340  // read Char_t array as string
341  // string either contains all symbols or until 0 symbol
342 
343  var res = "", code, closed = false;
344  for (var i = 0; (n < 0) || (i < n); ++i) {
345  code = this.ntou1();
346  if (code==0) { closed = true; if (n<0) break; }
347  if (!closed) res += String.fromCharCode(code);
348  }
349 
350  return res;
351  }
352 
353  TBuffer.prototype.ntou1 = function() {
354  return this.arr.getUint8(this.o++);
355  }
356 
357  TBuffer.prototype.ntou2 = function() {
358  var o = this.o; this.o+=2;
359  return this.arr.getUint16(o);
360  }
361 
362  TBuffer.prototype.ntou4 = function() {
363  var o = this.o; this.o+=4;
364  return this.arr.getUint32(o);
365  }
366 
367  TBuffer.prototype.ntou8 = function() {
368  var high = this.arr.getUint32(this.o); this.o+=4;
369  var low = this.arr.getUint32(this.o); this.o+=4;
370  return high * 0x100000000 + low;
371  }
372 
373  TBuffer.prototype.ntoi1 = function() {
374  return this.arr.getInt8(this.o++);
375  }
376 
377  TBuffer.prototype.ntoi2 = function() {
378  var o = this.o; this.o+=2;
379  return this.arr.getInt16(o);
380  }
381 
382  TBuffer.prototype.ntoi4 = function() {
383  var o = this.o; this.o+=4;
384  return this.arr.getInt32(o);
385  }
386 
387  TBuffer.prototype.ntoi8 = function() {
388  var high = this.arr.getUint32(this.o); this.o+=4;
389  var low = this.arr.getUint32(this.o); this.o+=4;
390  if (high < 0x80000000) return high * 0x100000000 + low;
391  return -1 - ((~high) * 0x100000000 + ~low);
392  }
393 
394  TBuffer.prototype.ntof = function() {
395  var o = this.o; this.o+=4;
396  return this.arr.getFloat32(o);
397  }
398 
399  TBuffer.prototype.ntod = function() {
400  var o = this.o; this.o+=8;
401  return this.arr.getFloat64(o);
402  }
403 
404  TBuffer.prototype.ReadFastArray = function(n, array_type) {
405  // read array of n values from the I/O buffer
406 
407  var array, i = 0, o = this.o, view = this.arr;
408  switch (array_type) {
409  case JSROOT.IO.kDouble:
410  array = new Float64Array(n);
411  for (; i < n; ++i, o+=8)
412  array[i] = view.getFloat64(o);
413  break;
414  case JSROOT.IO.kFloat:
415  array = new Float32Array(n);
416  for (; i < n; ++i, o+=4)
417  array[i] = view.getFloat32(o);
418  break;
419  case JSROOT.IO.kLong:
420  case JSROOT.IO.kLong64:
421  array = new Float64Array(n);
422  for (; i < n; ++i)
423  array[i] = this.ntoi8();
424  return array; // exit here to avoid conflicts
425  case JSROOT.IO.kULong:
426  case JSROOT.IO.kULong64:
427  array = new Float64Array(n);
428  for (; i < n; ++i)
429  array[i] = this.ntou8();
430  return array; // exit here to avoid conflicts
431  case JSROOT.IO.kInt:
432  case JSROOT.IO.kCounter:
433  array = new Int32Array(n);
434  for (; i < n; ++i, o+=4)
435  array[i] = view.getInt32(o);
436  break;
437  case JSROOT.IO.kBits:
438  case JSROOT.IO.kUInt:
439  array = new Uint32Array(n);
440  for (; i < n; ++i, o+=4)
441  array[i] = view.getUint32(o);
442  break;
443  case JSROOT.IO.kShort:
444  array = new Int16Array(n);
445  for (; i < n; ++i, o+=2)
446  array[i] = view.getInt16(o);
447  break;
448  case JSROOT.IO.kUShort:
449  array = new Uint16Array(n);
450  for (; i < n; ++i, o+=2)
451  array[i] = view.getUint16(o);
452  break;
453  case JSROOT.IO.kChar:
454  array = new Int8Array(n);
455  for (; i < n; ++i)
456  array[i] = view.getInt8(o++);
457  break;
458  case JSROOT.IO.kBool:
459  case JSROOT.IO.kUChar:
460  array = new Uint8Array(n);
461  for (; i < n; ++i)
462  array[i] = view.getUint8(o++);
463  break;
464  case JSROOT.IO.kTString:
465  array = new Array(n);
466  for (; i < n; ++i)
467  array[i] = this.ReadTString();
468  return array; // exit here to avoid conflicts
469  case JSROOT.IO.kDouble32:
470  throw new Error('kDouble32 should not be used in ReadFastArray');
471  case JSROOT.IO.kFloat16:
472  throw new Error('kFloat16 should not be used in ReadFastArray');
473  default:
474  array = new Uint32Array(n);
475  for (; i < n; ++i, o+=4)
476  array[i] = view.getUint32(o);
477  break;
478  }
479 
480  this.o = o;
481 
482  return array;
483  }
484 
485  TBuffer.prototype.can_extract = function(place) {
486  for (var n=0;n<place.length;n+=2)
487  if (place[n] + place[n+1] > this.length) return false;
488  return true;
489  }
490 
491  TBuffer.prototype.extract = function(place) {
492  if (!this.arr || !this.arr.buffer || !this.can_extract(place)) return null;
493  if (place.length===2) return new DataView(this.arr.buffer, this.arr.byteOffset + place[0], place[1]);
494 
495  var res = new Array(place.length/2);
496 
497  for (var n=0;n<place.length;n+=2)
498  res[n/2] = new DataView(this.arr.buffer, this.arr.byteOffset + place[n], place[n+1]);
499 
500  return res; // return array of buffers
501  }
502 
503  TBuffer.prototype.codeAt = function(pos) {
504  return this.arr.getUint8(pos);
505  }
506 
507  TBuffer.prototype.substring = function(beg, end) {
508  var res = "";
509  for (var n=beg;n<end;++n)
510  res += String.fromCharCode(this.arr.getUint8(n));
511  return res;
512  }
513 
514 
515  JSROOT.IO.GetArrayKind = function(type_name) {
516  // returns type of array
517  // 0 - if TString (or equivalent)
518  // -1 - if any other kind
519  if ((type_name === "TString") || (type_name === "string") ||
520  (JSROOT.IO.CustomStreamers[type_name] === 'TString')) return 0;
521  if ((type_name.length < 7) || (type_name.indexOf("TArray")!==0)) return -1;
522  if (type_name.length == 7)
523  switch (type_name[6]) {
524  case 'I': return JSROOT.IO.kInt;
525  case 'D': return JSROOT.IO.kDouble;
526  case 'F': return JSROOT.IO.kFloat;
527  case 'S': return JSROOT.IO.kShort;
528  case 'C': return JSROOT.IO.kChar;
529  case 'L': return JSROOT.IO.kLong;
530  default: return -1;
531  }
532 
533  return type_name == "TArrayL64" ? JSROOT.IO.kLong64 : -1;
534  }
535 
536  TBuffer.prototype.ReadNdimArray = function(handle, func) {
537  var ndim = handle.fArrayDim, maxindx = handle.fMaxIndex, res;
538  if ((ndim<1) && (handle.fArrayLength>0)) { ndim = 1; maxindx = [handle.fArrayLength]; }
539  if (handle.minus1) --ndim;
540 
541  if (ndim<1) return func(this, handle);
542 
543  if (ndim===1) {
544  res = new Array(maxindx[0]);
545  for (var n=0;n<maxindx[0];++n)
546  res[n] = func(this, handle);
547  } else
548  if (ndim===2) {
549  res = new Array(maxindx[0]);
550  for (var n=0;n<maxindx[0];++n) {
551  var res2 = new Array(maxindx[1]);
552  for (var k=0;k<maxindx[1];++k)
553  res2[k] = func(this, handle);
554  res[n] = res2;
555  }
556  } else {
557  var indx = [], arr = [], k;
558  for (k=0; k<ndim; ++k) { indx[k] = 0; arr[k] = []; }
559  res = arr[0];
560  while (indx[0] < maxindx[0]) {
561  k = ndim-1;
562  arr[k].push(func(this, handle));
563  ++indx[k];
564  while ((indx[k] === maxindx[k]) && (k>0)) {
565  indx[k] = 0;
566  arr[k-1].push(arr[k]);
567  arr[k] = [];
568  ++indx[--k];
569  }
570  }
571  }
572 
573  return res;
574  }
575 
576  TBuffer.prototype.ReadTKey = function(key) {
577  if (!key) key = {};
578  this.ClassStreamer(key, 'TKey');
579  var name = key.fName.replace(/['"]/g,'');
580  if (name !== key.fName) {
581  key.fRealName = key.fName;
582  key.fName = name;
583  }
584  return key;
585  }
586 
587  TBuffer.prototype.ReadBasketEntryOffset = function(basket, offset) {
588  // this is remaining part of TBasket streamer to decode fEntryOffset
589  // after unzipping of the TBasket data
590 
591  this.locate(basket.fLast - offset);
592 
593  if (this.remain() <= 0) {
594  if (!basket.fEntryOffset && (basket.fNevBuf <= 1)) basket.fEntryOffset = [ basket.fKeylen ];
595  if (!basket.fEntryOffset) console.warn("No fEntryOffset when expected for basket with", basket.fNevBuf, "entries");
596  return;
597  }
598 
599  var nentries = this.ntoi4();
600  // there is error in file=reco_103.root&item=Events;2/PCaloHits_g4SimHits_EcalHitsEE_Sim.&opt=dump;num:10;first:101
601  // it is workaround, but normally I/O should fail here
602  if ((nentries < 0) || (nentries > this.remain()*4)) {
603  console.error("Error when reading entries offset from basket fNevBuf", basket.fNevBuf, "remains", this.remain(), "want to read", nentries);
604  if (basket.fNevBuf <= 1) basket.fEntryOffset = [ basket.fKeylen ];
605  return;
606  }
607 
608  basket.fEntryOffset = this.ReadFastArray(nentries, JSROOT.IO.kInt);
609  if (!basket.fEntryOffset) basket.fEntryOffset = [ basket.fKeylen ];
610 
611  if (this.remain() > 0)
612  basket.fDisplacement = this.ReadFastArray(this.ntoi4(), JSROOT.IO.kInt);
613  else
614  basket.fDisplacement = undefined;
615  }
616 
617  TBuffer.prototype.ReadClass = function() {
618  // read class definition from I/O buffer
619  var classInfo = { name: -1 },
620  tag = 0,
621  bcnt = this.ntou4(),
622  startpos = this.o;
623 
624  if (!(bcnt & JSROOT.IO.kByteCountMask) || (bcnt == JSROOT.IO.kNewClassTag)) {
625  tag = bcnt;
626  bcnt = 0;
627  } else {
628  tag = this.ntou4();
629  }
630  if (!(tag & JSROOT.IO.kClassMask)) {
631  classInfo.objtag = tag + this.fDisplacement; // indicate that we have deal with objects tag
632  return classInfo;
633  }
634  if (tag == JSROOT.IO.kNewClassTag) {
635  // got a new class description followed by a new object
636  classInfo.name = this.ReadFastString(-1);
637 
638  if (this.GetMappedClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset) === -1)
639  this.MapClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset, classInfo.name);
640  } else {
641  // got a tag to an already seen class
642  var clTag = (tag & ~JSROOT.IO.kClassMask) + this.fDisplacement;
643  classInfo.name = this.GetMappedClass(clTag);
644 
645  if (classInfo.name === -1)
646  JSROOT.alert("Did not found class with tag " + clTag);
647  }
648 
649  return classInfo;
650  }
651 
652  TBuffer.prototype.ReadObjectAny = function() {
653  var objtag = this.fTagOffset + this.o + JSROOT.IO.kMapOffset,
654  clRef = this.ReadClass();
655 
656  // class identified as object and should be handled so
657  if ('objtag' in clRef)
658  return this.GetMappedObject(clRef.objtag);
659 
660  if (clRef.name === -1) return null;
661 
662  var arrkind = JSROOT.IO.GetArrayKind(clRef.name), obj;
663 
664  if (arrkind === 0) {
665  obj = this.ReadTString();
666  } else
667  if (arrkind > 0) {
668  // reading array, can map array only afterwards
669  obj = this.ReadFastArray(this.ntou4(), arrkind);
670  this.MapObject(objtag, obj);
671  } else {
672  // reading normal object, should map before to
673  obj = {};
674  this.MapObject(objtag, obj);
675  this.ClassStreamer(obj, clRef.name);
676  }
677 
678  return obj;
679  }
680 
681  TBuffer.prototype.ClassStreamer = function(obj, classname) {
682 
683  if (obj._typename === undefined) obj._typename = classname;
684 
685  var direct = JSROOT.IO.DirectStreamers[classname];
686  if (direct) {
687  direct(this, obj);
688  return obj;
689  }
690 
691  var ver = this.ReadVersion();
692 
693  var streamer = this.fFile.GetStreamer(classname, ver);
694 
695  if (streamer !== null) {
696 
697  for (var n = 0; n < streamer.length; ++n)
698  streamer[n].func(this, obj);
699 
700  } else {
701  // just skip bytes belonging to not-recognized object
702  // console.warn('skip object ', classname);
703 
704  JSROOT.addMethods(obj);
705  }
706 
707  this.CheckBytecount(ver, classname);
708 
709  return obj;
710  }
711 
712 
713  // =======================================================================
714 
715  JSROOT.CreateTBuffer = function(blob, pos, file, length) {
716  return new TBuffer(blob, pos, file, length);
717  }
718 
719  JSROOT.ReconstructObject = function(class_name, obj_rawdata, sinfo_rawdata) {
720  // method can be used to reconstruct ROOT object from binary buffer
721  // Buffer can be requested from online server with request like:
722  // http://localhost:8080/Files/job1.root/hpx/root.bin
723  // One also requires buffer with streamer infos, requested with command
724  // http://localhost:8080/StreamerInfo/root.bin
725  // And one should provide class name of the object
726  //
727  // Method provided for convenience only to see how binary JSROOT.IO works.
728  // It is strongly recommended to use JSON representation:
729  // http://localhost:8080/Files/job1.root/hpx/root.json
730 
731  var file = new TFile;
732  var buf = JSROOT.CreateTBuffer(sinfo_rawdata, 0, file);
733  file.ExtractStreamerInfos(buf);
734 
735  var obj = {};
736 
737  buf = JSROOT.CreateTBuffer(obj_rawdata, 0, file);
738  buf.MapObject(obj, 1);
739  buf.ClassStreamer(obj, class_name);
740 
741  return obj;
742  }
743 
744  // ==============================================================================
745 
746  // A class that reads a TDirectory from a buffer.
747 
748  // ctor
749  function TDirectory(file, dirname, cycle) {
750  this.fFile = file;
751  this._typename = "TDirectory";
752  this.dir_name = dirname;
753  this.dir_cycle = cycle;
754  this.fKeys = [];
755  return this;
756  }
757 
758  TDirectory.prototype.GetKey = function(keyname, cycle, call_back) {
759  // retrieve a key by its name and cycle in the list of keys
760 
761  if (typeof cycle != 'number') cycle = -1;
762  var bestkey = null;
763  for (var i = 0; i < this.fKeys.length; ++i) {
764  var key = this.fKeys[i];
765  if (!key || (key.fName!==keyname)) continue;
766  if (key.fCycle == cycle) { bestkey = key; break; }
767  if ((cycle < 0) && (!bestkey || (key.fCycle > bestkey.fCycle))) bestkey = key;
768  }
769  if (bestkey) {
770  JSROOT.CallBack(call_back, bestkey);
771  return bestkey;
772  }
773 
774  var pos = keyname.lastIndexOf("/");
775  // try to handle situation when object name contains slashed (bad practice anyway)
776  while (pos > 0) {
777  var dirname = keyname.substr(0, pos),
778  subname = keyname.substr(pos+1),
779  dirkey = this.GetKey(dirname);
780 
781  if ((dirkey!==null) && (typeof call_back == 'function') &&
782  (dirkey.fClassName.indexOf("TDirectory")==0)) {
783 
784  this.fFile.ReadObject(this.dir_name + "/" + dirname, 1, function(newdir) {
785  if (newdir) newdir.GetKey(subname, cycle, call_back);
786  });
787  return null;
788  }
789 
790  pos = keyname.lastIndexOf("/", pos-1);
791  }
792 
793  JSROOT.CallBack(call_back, null);
794  return null;
795  }
796 
797  TDirectory.prototype.ReadObject = function(obj_name, cycle, user_call_back) {
798  this.fFile.ReadObject(this.dir_name + "/" + obj_name, cycle, user_call_back);
799  }
800 
801  TDirectory.prototype.ReadKeys = function(objbuf, readkeys_callback) {
802 
803  objbuf.ClassStreamer(this, 'TDirectory');
804 
805  if ((this.fSeekKeys <= 0) || (this.fNbytesKeys <= 0))
806  return JSROOT.CallBack(readkeys_callback, this);
807 
808  var dir = this, file = this.fFile;
809 
810  file.ReadBuffer([this.fSeekKeys, this.fNbytesKeys], function(blob) {
811  if (!blob) return JSROOT.CallBack(readkeys_callback,null);
812 
813  //*-* -------------Read keys of the top directory
814 
815  var buf = JSROOT.CreateTBuffer(blob, 0, file);
816 
817  buf.ReadTKey();
818  var nkeys = buf.ntoi4();
819 
820  for (var i = 0; i < nkeys; ++i)
821  dir.fKeys.push(buf.ReadTKey());
822 
823  file.fDirectories.push(dir);
824 
825  JSROOT.CallBack(readkeys_callback, dir);
826  });
827  }
828 
829  // ==============================================================================
830  // A class that reads ROOT files.
831  //
833  // A ROOT file is a suite of consecutive data records (TKey's) with
834  // the following format (see also the TKey class). If the key is
835  // located past the 32 bit file limit (> 2 GB) then some fields will
836  // be 8 instead of 4 bytes:
837  // 1->4 Nbytes = Length of compressed object (in bytes)
838  // 5->6 Version = TKey version identifier
839  // 7->10 ObjLen = Length of uncompressed object
840  // 11->14 Datime = Date and time when object was written to file
841  // 15->16 KeyLen = Length of the key structure (in bytes)
842  // 17->18 Cycle = Cycle of key
843  // 19->22 [19->26] SeekKey = Pointer to record itself (consistency check)
844  // 23->26 [27->34] SeekPdir = Pointer to directory header
845  // 27->27 [35->35] lname = Number of bytes in the class name
846  // 28->.. [36->..] ClassName = Object Class Name
847  // ..->.. lname = Number of bytes in the object name
848  // ..->.. Name = lName bytes with the name of the object
849  // ..->.. lTitle = Number of bytes in the object title
850  // ..->.. Title = Title of the object
851  // -----> DATA = Data bytes associated to the object
852  //
853 
863  function TFile(url, newfile_callback) {
864  this._typename = "TFile";
865  this.fEND = 0;
866  this.fFullURL = url;
867  this.fURL = url;
868  this.fAcceptRanges = true; // when disabled ('+' at the end of file name), complete file content read with single operation
869  this.fUseStampPar = "stamp="+(new Date).getTime(); // use additional time stamp parameter for file name to avoid browser caching problem
870  this.fFileContent = null; // this can be full or partial content of the file (if ranges are not supported or if 1K header read from file)
871  // stored as TBuffer instance
872  this.fMaxRanges = 200; // maximal number of file ranges requested at once
873  this.fDirectories = [];
874  this.fKeys = [];
875  this.fSeekInfo = 0;
876  this.fNbytesInfo = 0;
877  this.fTagOffset = 0;
878  this.fStreamers = 0;
879  this.fStreamerInfos = null;
880  this.fFileName = "";
881  this.fStreamers = [];
882  this.fBasicTypes = {}; // custom basic types, in most case enumerations
883 
884  if (typeof this.fURL != 'string') return this;
885 
886  if (this.fURL[this.fURL.length-1] === "+") {
887  this.fURL = this.fURL.substr(0, this.fURL.length-1);
888  this.fAcceptRanges = false;
889  }
890 
891  if (this.fURL[this.fURL.length-1] === "-") {
892  this.fURL = this.fURL.substr(0, this.fURL.length-1);
893  this.fUseStampPar = false;
894  }
895 
896  if (this.fURL.indexOf("file://")==0) {
897  this.fUseStampPar = false;
898  this.fAcceptRanges = false;
899  }
900 
901  var pos = Math.max(this.fURL.lastIndexOf("/"), this.fURL.lastIndexOf("\\"));
902  this.fFileName = pos>=0 ? this.fURL.substr(pos+1) : this.fURL;
903 
904  if (!this.fAcceptRanges) {
905  this.ReadKeys(newfile_callback);
906  } else {
907  var file = this;
908  JSROOT.NewHttpRequest(this.fURL, "head", function(res) {
909  if (!res)
910  return JSROOT.CallBack(newfile_callback, null);
911 
912  var accept_ranges = res.getResponseHeader("Accept-Ranges");
913  if (!accept_ranges) file.fAcceptRanges = false;
914  var len = res.getResponseHeader("Content-Length");
915  if (len) file.fEND = parseInt(len);
916  else file.fAcceptRanges = false;
917  file.ReadKeys(newfile_callback);
918  }).send(null);
919  }
920 
921  return this;
922  }
923 
926  TFile.prototype.ReadBuffer = function(place, result_callback, filename, progress_callback) {
927 
928  if ((this.fFileContent!==null) && !filename && (!this.fAcceptRanges || this.fFileContent.can_extract(place)))
929  return result_callback(this.fFileContent.extract(place));
930 
931  var file = this, fileurl = file.fURL,
932  first = 0, last = 0, blobs = [], read_callback; // array of requested segments
933 
934  if (filename && (typeof filename === 'string') && (filename.length>0)) {
935  var pos = fileurl.lastIndexOf("/");
936  fileurl = (pos<0) ? filename : fileurl.substr(0,pos+1) + filename;
937  }
938 
939  function send_new_request(increment) {
940 
941  if (increment) {
942  first = last;
943  last = Math.min(first + file.fMaxRanges*2, place.length);
944  if (first>=place.length) return result_callback(blobs);
945  }
946 
947  var fullurl = fileurl, ranges = "bytes", totalsz = 0;
948  // try to avoid browser caching by adding stamp parameter to URL
949  if (file.fUseStampPar) fullurl += ((fullurl.indexOf('?')<0) ? "?" : "&") + file.fUseStampPar;
950 
951  for (var n=first;n<last;n+=2) {
952  ranges += (n>first ? "," : "=") + (place[n] + "-" + (place[n] + place[n+1] - 1));
953  totalsz += place[n+1]; // accumulated total size
954  }
955  if (last-first>2) totalsz += (last-first)*60; // for multi-range ~100 bytes/per request
956 
957  var xhr = JSROOT.NewHttpRequest(fullurl, "buf", read_callback);
958 
959  if (file.fAcceptRanges) {
960  xhr.setRequestHeader("Range", ranges);
961  xhr.expected_size = Math.max(Math.round(1.1*totalsz), totalsz+200); // 200 if offset for the potential gzip
962  }
963 
964  if (progress_callback && (typeof xhr.addEventListener === 'function')) {
965  var sum1 = 0, sum2 = 0, sum_total = 0;
966  for (var n=1;n<place.length;n+=2) {
967  sum_total+=place[n];
968  if (n<first) sum1+=place[n];
969  if (n<last) sum2+=place[n];
970  }
971  if (!sum_total) sum_total = 1;
972 
973  var progress_offest = sum1/sum_total, progress_this = (sum2-sum1)/sum_total;
974  xhr.addEventListener("progress", function(oEvent) {
975  if (oEvent.lengthComputable)
976  progress_callback(progress_offest + progress_this*oEvent.loaded/oEvent.total);
977  });
978  }
979 
980  xhr.send(null);
981  }
982 
983  read_callback = function(res) {
984 
985  if (!res && file.fUseStampPar && (place[0]===0) && (place.length===2)) {
986  // if fail to read file with stamp parameter, try once again without it
987  file.fUseStampPar = false;
988  return send_new_request();
989  }
990 
991  if (res && (place[0]===0) && (place.length===2) && !file.fFileContent) {
992  // special case - keep content of first request (could be complete file) in memory
993 
994  file.fFileContent = JSROOT.CreateTBuffer((typeof res == 'string') ? res : new DataView(res));
995 
996  if (!file.fAcceptRanges)
997  file.fEND = file.fFileContent.length;
998 
999  return result_callback(file.fFileContent.extract(place));
1000  }
1001 
1002  if (!res) {
1003  if ((first===0) && (last > 2) && (file.fMaxRanges>1)) {
1004  // server return no response with multi request - try to decrease ranges count or fail
1005 
1006  if (last/2 > 200) file.fMaxRanges = 200; else
1007  if (last/2 > 50) file.fMaxRanges = 50; else
1008  if (last/2 > 20) file.fMaxRanges = 20; else
1009  if (last/2 > 5) file.fMaxRanges = 5; else file.fMaxRanges = 1;
1010  last = Math.min(last, file.fMaxRanges*2);
1011  // console.log('Change maxranges to ', file.fMaxRanges, 'last', last);
1012  return send_new_request();
1013  }
1014 
1015  return result_callback(null);
1016  }
1017 
1018  // if only single segment requested, return result as is
1019  if (last - first === 2) {
1020  var b = new DataView(res);
1021  if (place.length===2) return result_callback(b);
1022  blobs.push(b);
1023  return send_new_request(true);
1024  }
1025 
1026  // object to access response data
1027  var hdr = this.getResponseHeader('Content-Type'),
1028  ismulti = (typeof hdr === 'string') && (hdr.indexOf('multipart')>=0),
1029  view = new DataView(res);
1030 
1031  if (!ismulti) {
1032  // server may returns simple buffer, which combines all segments together
1033 
1034  var hdr_range = this.getResponseHeader('Content-Range'), segm_start = 0, segm_last = -1;
1035 
1036  if (hdr_range && hdr_range.indexOf("bytes")>=0) {
1037  var parts = hdr_range.substr(hdr_range.indexOf("bytes") + 6).split(/[\s-\/]+/);
1038  if (parts.length===3) {
1039  segm_start = parseInt(parts[0]);
1040  segm_last = parseInt(parts[1]);
1041  if (isNaN(segm_start) || isNaN(segm_last) || (segm_start > segm_last)) {
1042  segm_start = 0; segm_last = -1;
1043  }
1044  }
1045  }
1046 
1047  var canbe_single_segment = (segm_start<=segm_last);
1048  for(var n=first;n<last;n+=2)
1049  if ((place[n]<segm_start) || (place[n] + place[n+1] -1 > segm_last))
1050  canbe_single_segment = false;
1051 
1052  if (canbe_single_segment) {
1053  for (var n=first;n<last;n+=2)
1054  blobs.push(new DataView(res, place[n]-segm_start, place[n+1]));
1055  return send_new_request(true);
1056  }
1057 
1058  console.error('Server returns normal response when multipart was requested, disable multirange support');
1059 
1060  if ((file.fMaxRanges === 1) || (first!==0)) return result_callback(null);
1061 
1062  file.fMaxRanges = 1;
1063  last = Math.min(last, file.fMaxRanges*2);
1064 
1065  return send_new_request();
1066  }
1067 
1068  // multipart messages requires special handling
1069 
1070  var indx = hdr.indexOf("boundary="), boundary = "", n = first, o = 0;
1071  if (indx > 0) {
1072  boundary = hdr.substr(indx+9);
1073  if ((boundary[0] == '"') && (boundary[boundary.length-1] == '"'))
1074  boundary = boundary.substr(1, boundary.length-2);
1075  boundary = "--" + boundary;
1076  } else console.error('Did not found boundary id in the response header');
1077 
1078  while (n<last) {
1079 
1080  var code1, code2 = view.getUint8(o), nline = 0, line = "",
1081  finish_header = false, segm_start = 0, segm_last = -1;
1082 
1083  while((o < view.byteLength-1) && !finish_header && (nline<5)) {
1084  code1 = code2;
1085  code2 = view.getUint8(o+1);
1086 
1087  if ((code1==13) && (code2==10)) {
1088  if ((line.length>2) && (line.substr(0,2)=='--') && (line !== boundary)) {
1089  console.error('Decode multipart message, expect boundary ', boundary, 'got ', line);
1090  return result_callback(null);
1091  }
1092 
1093  line = line.toLowerCase();
1094 
1095  if ((line.indexOf("content-range")>=0) && (line.indexOf("bytes") > 0)) {
1096  var parts = line.substr(line.indexOf("bytes") + 6).split(/[\s-\/]+/);
1097  if (parts.length===3) {
1098  segm_start = parseInt(parts[0]);
1099  segm_last = parseInt(parts[1]);
1100  if (isNaN(segm_start) || isNaN(segm_last) || (segm_start > segm_last)) {
1101  segm_start = 0; segm_last = -1;
1102  }
1103  } else {
1104  console.error('Fail to decode content-range', line, parts);
1105  }
1106  }
1107 
1108  if ((nline > 1) && (line.length===0)) finish_header = true;
1109 
1110  o++; nline++; line = "";
1111  code2 = view.getUint8(o+1);
1112  } else {
1113  line += String.fromCharCode(code1);
1114  }
1115  o++;
1116  }
1117 
1118  if (!finish_header) {
1119  console.error('Cannot decode header in multipart message ');
1120  return result_callback(null);
1121  }
1122 
1123  if (segm_start > segm_last) {
1124  // fall-back solution, believe that segments same as requested
1125  blobs.push(new DataView(res, o, place[n+1]));
1126  o += place[n+1];
1127  n += 2;
1128  } else {
1129  while ((n<last) && (place[n] >= segm_start) && (place[n] + place[n+1] - 1 <= segm_last)) {
1130  blobs.push(new DataView(res, o + place[n] - segm_start, place[n+1]));
1131  n += 2;
1132  }
1133 
1134  o += (segm_last-segm_start+1);
1135  }
1136  }
1137 
1138  send_new_request(true);
1139  }
1140 
1141  send_new_request(true);
1142  }
1143 
1147  TFile.prototype.GetDir = function(dirname, cycle) {
1148 
1149  if ((cycle === undefined) && (typeof dirname == 'string')) {
1150  var pos = dirname.lastIndexOf(';');
1151  if (pos>0) { cycle = parseInt(dirname.substr(pos+1)); dirname = dirname.substr(0,pos); }
1152  }
1153 
1154  for (var j=0; j < this.fDirectories.length; ++j) {
1155  var dir = this.fDirectories[j];
1156  if (dir.dir_name != dirname) continue;
1157  if ((cycle !== undefined) && (dir.dir_cycle !== cycle)) continue;
1158  return dir;
1159  }
1160  return null;
1161  }
1162 
1166  TFile.prototype.GetKey = function(keyname, cycle, getkey_callback) {
1167 
1168  if (typeof cycle != 'number') cycle = -1;
1169  var bestkey = null;
1170  for (var i = 0; i < this.fKeys.length; ++i) {
1171  var key = this.fKeys[i];
1172  if (!key || (key.fName!==keyname)) continue;
1173  if (key.fCycle == cycle) { bestkey = key; break; }
1174  if ((cycle < 0) && (!bestkey || (key.fCycle > bestkey.fCycle))) bestkey = key;
1175  }
1176  if (bestkey) {
1177  JSROOT.CallBack(getkey_callback, bestkey);
1178  return bestkey;
1179  }
1180 
1181  var pos = keyname.lastIndexOf("/");
1182  // try to handle situation when object name contains slashed (bad practice anyway)
1183  while (pos > 0) {
1184  var dirname = keyname.substr(0, pos),
1185  subname = keyname.substr(pos+1),
1186  dir = this.GetDir(dirname);
1187 
1188  if (dir) return dir.GetKey(subname, cycle, getkey_callback);
1189 
1190  var dirkey = this.GetKey(dirname);
1191  if (dirkey && getkey_callback && (dirkey.fClassName.indexOf("TDirectory")==0)) {
1192  this.ReadObject(dirname, function(newdir) {
1193  if (newdir) newdir.GetKey(subname, cycle, getkey_callback);
1194  });
1195  return null;
1196  }
1197 
1198  pos = keyname.lastIndexOf("/", pos-1);
1199  }
1200 
1201  JSROOT.CallBack(getkey_callback, null);
1202  return null;
1203  }
1204 
1207  TFile.prototype.ReadObjBuffer = function(key, callback) {
1208 
1209  var file = this;
1210 
1211  this.ReadBuffer([key.fSeekKey + key.fKeylen, key.fNbytes - key.fKeylen], function(blob1) {
1212 
1213  if (!blob1) return callback(null);
1214 
1215  var buf = null;
1216 
1217  if (key.fObjlen <= key.fNbytes - key.fKeylen) {
1218  buf = JSROOT.CreateTBuffer(blob1, 0, file);
1219  } else {
1220  var objbuf = JSROOT.R__unzip(blob1, key.fObjlen);
1221  if (!objbuf) return callback(null);
1222  buf = JSROOT.CreateTBuffer(objbuf, 0, file);
1223  }
1224 
1225  buf.fTagOffset = key.fKeylen;
1226 
1227  callback(buf);
1228  });
1229  }
1230 
1233  TFile.prototype.AddReadTree = function(obj) {
1234 
1235  if (JSROOT.TreeMethods)
1236  return JSROOT.extend(obj, JSROOT.TreeMethods);
1237 
1238  if (this.readTrees===undefined) this.readTrees = [];
1239 
1240  if (this.readTrees.indexOf(obj)<0) this.readTrees.push(obj);
1241  }
1242 
1251  TFile.prototype.ReadObject = function(obj_name, cycle, user_call_back, only_dir) {
1252  if (typeof cycle == 'function') { user_call_back = cycle; cycle = -1; }
1253 
1254  var pos = obj_name.lastIndexOf(";");
1255  if (pos>0) {
1256  cycle = parseInt(obj_name.slice(pos+1));
1257  obj_name = obj_name.slice(0, pos);
1258  }
1259 
1260  if (typeof cycle != 'number') cycle = -1;
1261  // remove leading slashes
1262  while (obj_name.length && (obj_name[0] == "/")) obj_name = obj_name.substr(1);
1263 
1264  var file = this;
1265 
1266  // we use callback version while in some cases we need to
1267  // read sub-directory to get list of keys
1268  // in such situation calls are asynchrone
1269  this.GetKey(obj_name, cycle, function(key) {
1270 
1271  if (!key)
1272  return JSROOT.CallBack(user_call_back, null);
1273 
1274  if ((obj_name=="StreamerInfo") && (key.fClassName=="TList"))
1275  return file.fStreamerInfos;
1276 
1277  var isdir = false;
1278  if ((key.fClassName == 'TDirectory' || key.fClassName == 'TDirectoryFile')) {
1279  isdir = true;
1280  var dir = file.GetDir(obj_name, cycle);
1281  if (dir) return JSROOT.CallBack(user_call_back, dir);
1282  }
1283 
1284  if (!isdir && only_dir)
1285  return JSROOT.CallBack(user_call_back, null);
1286 
1287  file.ReadObjBuffer(key, function(buf) {
1288  if (!buf) return JSROOT.CallBack(user_call_back, null);
1289 
1290  if (isdir) {
1291  var dir = new TDirectory(file, obj_name, cycle);
1292  dir.fTitle = key.fTitle;
1293  return dir.ReadKeys(buf, user_call_back);
1294  }
1295 
1296  var obj = {};
1297  buf.MapObject(1, obj); // tag object itself with id==1
1298  buf.ClassStreamer(obj, key.fClassName);
1299 
1300  if ((key.fClassName==='TF1') || (key.fClassName==='TF2'))
1301  return file.ReadFormulas(obj, user_call_back, -1);
1302 
1303  if (file.readTrees)
1304  return JSROOT.AssertPrerequisites('tree', function() {
1305  if (file.readTrees) {
1306  file.readTrees.forEach(function(t) { JSROOT.extend(t, JSROOT.TreeMethods); })
1307  delete file.readTrees;
1308  }
1309  JSROOT.CallBack(user_call_back, obj);
1310  });
1311 
1312  JSROOT.CallBack(user_call_back, obj);
1313  }); // end of ReadObjBuffer callback
1314  }); // end of GetKey callback
1315  }
1316 
1319  TFile.prototype.ReadFormulas = function(tf1, user_call_back, cnt) {
1320 
1321  var indx = cnt;
1322  while (++indx < this.fKeys.length) {
1323  if (this.fKeys[indx].fClassName == 'TFormula') break;
1324  }
1325 
1326  if (indx >= this.fKeys.length)
1327  return JSROOT.CallBack(user_call_back, tf1);
1328 
1329  var file = this;
1330 
1331  this.ReadObject(this.fKeys[indx].fName, this.fKeys[indx].fCycle, function(formula) {
1332  tf1.addFormula(formula);
1333  file.ReadFormulas(tf1, user_call_back, indx);
1334  });
1335  }
1336 
1339  TFile.prototype.ExtractStreamerInfos = function(buf) {
1340  if (!buf) return;
1341 
1342  var lst = {};
1343  buf.MapObject(1, lst);
1344  buf.ClassStreamer(lst, 'TList');
1345 
1346  lst._typename = "TStreamerInfoList";
1347 
1348  this.fStreamerInfos = lst;
1349 
1350  if (typeof JSROOT.addStreamerInfos === 'function')
1351  JSROOT.addStreamerInfos(lst);
1352 
1353  for (var k=0;k<lst.arr.length;++k) {
1354  var si = lst.arr[k];
1355  if (!si.fElements) continue;
1356  for (var l=0;l<si.fElements.arr.length;++l) {
1357  var elem = si.fElements.arr[l];
1358 
1359  if (!elem.fTypeName || !elem.fType) continue;
1360 
1361  var typ = elem.fType, typname = elem.fTypeName;
1362 
1363  if (typ >= 60) {
1364  if ((typ===JSROOT.IO.kStreamer) && (elem._typename=="TStreamerSTL") && elem.fSTLtype && elem.fCtype && (elem.fCtype<20)) {
1365  var prefix = (JSROOT.IO.StlNames[elem.fSTLtype] || "undef") + "<";
1366  if ((typname.indexOf(prefix)===0) && (typname[typname.length-1] == ">")) {
1367  typ = elem.fCtype;
1368  typname = typname.substr(prefix.length, typname.length-prefix.length-1).trim();
1369 
1370  if ((elem.fSTLtype === JSROOT.IO.kSTLmap) || (elem.fSTLtype === JSROOT.IO.kSTLmultimap))
1371  if (typname.indexOf(",")>0) typname = typname.substr(0, typname.indexOf(",")).trim();
1372  else continue;
1373  }
1374  }
1375  if (typ>=60) continue;
1376  } else {
1377  if ((typ>20) && (typname[typname.length-1]=="*")) typname = typname.substr(0,typname.length-1);
1378  typ = typ % 20;
1379  }
1380 
1381  var kind = JSROOT.IO.GetTypeId(typname);
1382  if (kind === typ) continue;
1383 
1384  if ((typ === JSROOT.IO.kBits) && (kind===JSROOT.IO.kUInt)) continue;
1385  if ((typ === JSROOT.IO.kCounter) && (kind===JSROOT.IO.kInt)) continue;
1386 
1387  if (typname && typ && (this.fBasicTypes[typname]!==typ)) {
1388  this.fBasicTypes[typname] = typ;
1389  if (!JSROOT.BatchMode) console.log('Extract basic data type', typ, typname);
1390  }
1391  }
1392  }
1393  }
1394 
1397  TFile.prototype.ReadKeys = function(readkeys_callback) {
1398 
1399  var file = this;
1400 
1401  // with the first readbuffer we read bigger amount to create header cache
1402  this.ReadBuffer([0, 1024], function(blob) {
1403  if (!blob) return JSROOT.CallBack(readkeys_callback, null);
1404 
1405  var buf = JSROOT.CreateTBuffer(blob, 0, file);
1406 
1407  if (buf.substring(0, 4) !== 'root') {
1408  JSROOT.alert("NOT A ROOT FILE! " + file.fURL);
1409  return JSROOT.CallBack(readkeys_callback, null);
1410  }
1411  buf.shift(4);
1412 
1413  file.fVersion = buf.ntou4();
1414  file.fBEGIN = buf.ntou4();
1415  if (file.fVersion < 1000000) { //small file
1416  file.fEND = buf.ntou4();
1417  file.fSeekFree = buf.ntou4();
1418  file.fNbytesFree = buf.ntou4();
1419  buf.shift(4); // var nfree = buf.ntoi4();
1420  file.fNbytesName = buf.ntou4();
1421  file.fUnits = buf.ntou1();
1422  file.fCompress = buf.ntou4();
1423  file.fSeekInfo = buf.ntou4();
1424  file.fNbytesInfo = buf.ntou4();
1425  } else { // new format to support large files
1426  file.fEND = buf.ntou8();
1427  file.fSeekFree = buf.ntou8();
1428  file.fNbytesFree = buf.ntou4();
1429  buf.shift(4); // var nfree = buf.ntou4();
1430  file.fNbytesName = buf.ntou4();
1431  file.fUnits = buf.ntou1();
1432  file.fCompress = buf.ntou4();
1433  file.fSeekInfo = buf.ntou8();
1434  file.fNbytesInfo = buf.ntou4();
1435  }
1436 
1437  // empty file
1438  if (!file.fSeekInfo || !file.fNbytesInfo)
1439  return JSROOT.CallBack(readkeys_callback, null);
1440 
1441  // extra check to prevent reading of corrupted data
1442  if (!file.fNbytesName || file.fNbytesName > 100000) {
1443  JSROOT.console("Init : cannot read directory info of file " + file.fURL);
1444  return JSROOT.CallBack(readkeys_callback, null);
1445  }
1446 
1447  //*-*-------------Read directory info
1448  var nbytes = file.fNbytesName + 22;
1449  nbytes += 4; // fDatimeC.Sizeof();
1450  nbytes += 4; // fDatimeM.Sizeof();
1451  nbytes += 18; // fUUID.Sizeof();
1452  // assume that the file may be above 2 Gbytes if file version is > 4
1453  if (file.fVersion >= 40000) nbytes += 12;
1454 
1455  // this part typically read from the header, no need to optimize
1456  file.ReadBuffer([file.fBEGIN, Math.max(300, nbytes)], function(blob3) {
1457  if (!blob3) return JSROOT.CallBack(readkeys_callback, null);
1458 
1459  var buf3 = JSROOT.CreateTBuffer(blob3, 0, file);
1460 
1461  // keep only title from TKey data
1462  file.fTitle = buf3.ReadTKey().fTitle;
1463 
1464  buf3.locate(file.fNbytesName);
1465 
1466  // we read TDirectory part of TFile
1467  buf3.ClassStreamer(file,'TDirectory');
1468 
1469  if (!file.fSeekKeys) {
1470  JSROOT.console("Empty keys list in " + file.fURL);
1471  return JSROOT.CallBack(readkeys_callback, null);
1472  }
1473 
1474  // read with same request keys and streamer infos
1475  file.ReadBuffer([file.fSeekKeys, file.fNbytesKeys, file.fSeekInfo, file.fNbytesInfo], function(blobs) {
1476 
1477  if (!blobs) return JSROOT.CallBack(readkeys_callback, null);
1478 
1479  var buf4 = JSROOT.CreateTBuffer(blobs[0], 0, file);
1480 
1481  buf4.ReadTKey(); //
1482  var nkeys = buf4.ntoi4();
1483  for (var i = 0; i < nkeys; ++i)
1484  file.fKeys.push(buf4.ReadTKey());
1485 
1486  var buf5 = JSROOT.CreateTBuffer(blobs[1], 0, file),
1487  si_key = buf5.ReadTKey();
1488  if (!si_key) return JSROOT.CallBack(readkeys_callback, null);
1489 
1490  file.fKeys.push(si_key);
1491  file.ReadObjBuffer(si_key, function(blob6) {
1492  if (blob6) file.ExtractStreamerInfos(blob6);
1493 
1494  return JSROOT.CallBack(readkeys_callback, file);
1495  });
1496  });
1497  });
1498  });
1499  }
1500 
1507  TFile.prototype.ReadDirectory = function(dir_name, cycle, readdir_callback) {
1508  this.ReadObject(dir_name, cycle, readdir_callback, true);
1509  }
1510 
1511  JSROOT.IO.AddClassMethods = function(clname, streamer) {
1512  // create additional entries in the streamer, which sets all methods of the class
1513 
1514  if (streamer === null) return streamer;
1515 
1516  var methods = JSROOT.getMethods(clname);
1517 
1518  if (methods !== null)
1519  for (var key in methods)
1520  if ((typeof methods[key] === 'function') || (key.indexOf("_")==0))
1521  streamer.push({
1522  name: key,
1523  method: methods[key],
1524  func: function(buf,obj) { obj[this.name] = this.method; }
1525  });
1526 
1527  return streamer;
1528  }
1529 
1532  TFile.prototype.FindStreamerInfo = function(clname, clversion, clchecksum) {
1533  if (this.fStreamerInfos)
1534  for (var i=0; i < this.fStreamerInfos.arr.length; ++i) {
1535  var si = this.fStreamerInfos.arr[i];
1536 
1537  // checksum is enough to identify class
1538  if ((clchecksum !== undefined) && (si.fCheckSum === clchecksum)) return si;
1539 
1540  if (si.fName !== clname) continue;
1541 
1542  // checksum should match
1543  if (clchecksum !== undefined) continue;
1544 
1545  if ((clversion !== undefined) && (si.fClassVersion !== clversion)) continue;
1546 
1547  return si;
1548  }
1549 
1550  return null;
1551  }
1552 
1553  TFile.prototype.FindSinfoCheckum = function(checksum) {
1554  if (!this.fStreamerInfos) return null;
1555 
1556  var cache = this.fStreamerInfos.cache,
1557  arr = this.fStreamerInfos.arr;
1558  if (!cache) cache = this.fStreamerInfos.cache = {};
1559 
1560  var si = cache[checksum];
1561  if (si !== undefined) return si;
1562 
1563  for (var i=0; i < arr.length; ++i) {
1564  si = arr[i];
1565  if (si.fCheckSum === checksum) {
1566  cache[checksum] = si;
1567  return si;
1568  }
1569  }
1570 
1571  cache[checksum] = null; // checksum didnot found, not try again
1572  return null;
1573  }
1574 
1575  JSROOT.IO.GetPairStreamer = function(si, typname, file) {
1576 
1577  if (!si) {
1578  if (typname.indexOf("pair")!==0) return null;
1579 
1580  si = file.FindStreamerInfo(typname);
1581 
1582  if (!si) {
1583  var p1 = typname.indexOf("<"), p2 = typname.lastIndexOf(">");
1584  function GetNextName() {
1585  var res = "", p = p1+1, cnt = 0;
1586  while ((p<p2) && (cnt>=0)) {
1587  switch (typname[p]) {
1588  case "<": cnt++; break;
1589  case ",": if (cnt===0) cnt--; break;
1590  case ">": cnt--; break;
1591  }
1592  if (cnt>=0) res+=typname[p];
1593  p++;
1594  }
1595  p1 = p-1;
1596  return res.trim();
1597  }
1598  si = { _typename: 'TStreamerInfo', fVersion: 1, fName: typname, fElements: JSROOT.Create("TList") };
1599  si.fElements.Add(JSROOT.IO.CreateStreamerElement("first", GetNextName(), file));
1600  si.fElements.Add(JSROOT.IO.CreateStreamerElement("second", GetNextName(), file));
1601  }
1602  }
1603 
1604  var streamer = file.GetStreamer(typname, null, si);
1605 
1606  if (!streamer) return null;
1607 
1608  if (streamer.length!==2) {
1609  console.error('Streamer for pair class contains ', streamer.length,'elements');
1610  return null;
1611 
1612  }
1613 
1614  for (var nn=0;nn<2;++nn)
1615  if (streamer[nn].readelem && !streamer[nn].pair_name) {
1616  streamer[nn].pair_name = (nn==0) ? "first" : "second";
1617  streamer[nn].func = function(buf, obj) {
1618  obj[this.pair_name] = this.readelem(buf);
1619  }
1620  }
1621 
1622  return streamer;
1623  }
1624 
1625  JSROOT.IO.CreateMember = function(element, file) {
1626  // create member entry for streamer element, which is used for reading of such data
1627 
1628  var member = { name: element.fName, type: element.fType,
1629  fArrayLength: element.fArrayLength,
1630  fArrayDim: element.fArrayDim,
1631  fMaxIndex: element.fMaxIndex };
1632 
1633  if (element.fTypeName === 'BASE') {
1634  if (JSROOT.IO.GetArrayKind(member.name) > 0) {
1635  // this is workaround for arrays as base class
1636  // we create 'fArray' member, which read as any other data member
1637  member.name = 'fArray';
1638  member.type = JSROOT.IO.kAny;
1639  } else {
1640  // create streamer for base class
1641  member.type = JSROOT.IO.kBase;
1642  // this.GetStreamer(element.fName);
1643  }
1644  }
1645 
1646  switch (member.type) {
1647  case JSROOT.IO.kBase:
1648  member.base = element.fBaseVersion; // indicate base class
1649  member.basename = element.fName; // keep class name
1650  member.func = function(buf, obj) { buf.ClassStreamer(obj, this.basename); };
1651  break;
1652  case JSROOT.IO.kShort:
1653  member.func = function(buf,obj) { obj[this.name] = buf.ntoi2(); }; break;
1654  case JSROOT.IO.kInt:
1655  case JSROOT.IO.kCounter:
1656  member.func = function(buf,obj) { obj[this.name] = buf.ntoi4(); }; break;
1657  case JSROOT.IO.kLong:
1658  case JSROOT.IO.kLong64:
1659  member.func = function(buf,obj) { obj[this.name] = buf.ntoi8(); }; break;
1660  case JSROOT.IO.kDouble:
1661  member.func = function(buf,obj) { obj[this.name] = buf.ntod(); }; break;
1662  case JSROOT.IO.kFloat:
1663  member.func = function(buf,obj) { obj[this.name] = buf.ntof(); }; break;
1664  case JSROOT.IO.kLegacyChar:
1665  case JSROOT.IO.kUChar:
1666  member.func = function(buf,obj) { obj[this.name] = buf.ntou1(); }; break;
1667  case JSROOT.IO.kUShort:
1668  member.func = function(buf,obj) { obj[this.name] = buf.ntou2(); }; break;
1669  case JSROOT.IO.kBits:
1670  case JSROOT.IO.kUInt:
1671  member.func = function(buf,obj) { obj[this.name] = buf.ntou4(); }; break;
1672  case JSROOT.IO.kULong64:
1673  case JSROOT.IO.kULong:
1674  member.func = function(buf,obj) { obj[this.name] = buf.ntou8(); }; break;
1675  case JSROOT.IO.kBool:
1676  member.func = function(buf,obj) { obj[this.name] = buf.ntou1() != 0; }; break;
1677  case JSROOT.IO.kOffsetL+JSROOT.IO.kBool:
1678  case JSROOT.IO.kOffsetL+JSROOT.IO.kInt:
1679  case JSROOT.IO.kOffsetL+JSROOT.IO.kCounter:
1680  case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble:
1681  case JSROOT.IO.kOffsetL+JSROOT.IO.kUChar:
1682  case JSROOT.IO.kOffsetL+JSROOT.IO.kShort:
1683  case JSROOT.IO.kOffsetL+JSROOT.IO.kUShort:
1684  case JSROOT.IO.kOffsetL+JSROOT.IO.kBits:
1685  case JSROOT.IO.kOffsetL+JSROOT.IO.kUInt:
1686  case JSROOT.IO.kOffsetL+JSROOT.IO.kULong:
1687  case JSROOT.IO.kOffsetL+JSROOT.IO.kULong64:
1688  case JSROOT.IO.kOffsetL+JSROOT.IO.kLong:
1689  case JSROOT.IO.kOffsetL+JSROOT.IO.kLong64:
1690  case JSROOT.IO.kOffsetL+JSROOT.IO.kFloat:
1691  if (element.fArrayDim < 2) {
1692  member.arrlength = element.fArrayLength;
1693  member.func = function(buf, obj) {
1694  obj[this.name] = buf.ReadFastArray(this.arrlength, this.type - JSROOT.IO.kOffsetL);
1695  };
1696  } else {
1697  member.arrlength = element.fMaxIndex[element.fArrayDim-1];
1698  member.minus1 = true;
1699  member.func = function(buf, obj) {
1700  obj[this.name] = buf.ReadNdimArray(this, function(buf,handle) {
1701  return buf.ReadFastArray(handle.arrlength, handle.type - JSROOT.IO.kOffsetL);
1702  });
1703  };
1704  }
1705  break;
1706  case JSROOT.IO.kOffsetL+JSROOT.IO.kChar:
1707  if (element.fArrayDim < 2) {
1708  member.arrlength = element.fArrayLength;
1709  member.func = function(buf, obj) {
1710  obj[this.name] = buf.ReadFastString(this.arrlength);
1711  };
1712  } else {
1713  member.minus1 = true; // one dimension used for char*
1714  member.arrlength = element.fMaxIndex[element.fArrayDim-1];
1715  member.func = function(buf, obj) {
1716  obj[this.name] = buf.ReadNdimArray(this, function(buf,handle) {
1717  return buf.ReadFastString(handle.arrlength);
1718  });
1719  };
1720  }
1721  break;
1722  case JSROOT.IO.kOffsetP+JSROOT.IO.kBool:
1723  case JSROOT.IO.kOffsetP+JSROOT.IO.kInt:
1724  case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble:
1725  case JSROOT.IO.kOffsetP+JSROOT.IO.kUChar:
1726  case JSROOT.IO.kOffsetP+JSROOT.IO.kShort:
1727  case JSROOT.IO.kOffsetP+JSROOT.IO.kUShort:
1728  case JSROOT.IO.kOffsetP+JSROOT.IO.kBits:
1729  case JSROOT.IO.kOffsetP+JSROOT.IO.kUInt:
1730  case JSROOT.IO.kOffsetP+JSROOT.IO.kULong:
1731  case JSROOT.IO.kOffsetP+JSROOT.IO.kULong64:
1732  case JSROOT.IO.kOffsetP+JSROOT.IO.kLong:
1733  case JSROOT.IO.kOffsetP+JSROOT.IO.kLong64:
1734  case JSROOT.IO.kOffsetP+JSROOT.IO.kFloat:
1735  member.cntname = element.fCountName;
1736  member.func = function(buf, obj) {
1737  if (buf.ntou1() === 1)
1738  obj[this.name] = buf.ReadFastArray(obj[this.cntname], this.type - JSROOT.IO.kOffsetP);
1739  else
1740  obj[this.name] = new Array();
1741  };
1742  break;
1743  case JSROOT.IO.kOffsetP+JSROOT.IO.kChar:
1744  member.cntname = element.fCountName;
1745  member.func = function(buf, obj) {
1746  if (buf.ntou1() === 1)
1747  obj[this.name] = buf.ReadFastString(obj[this.cntname]);
1748  else
1749  obj[this.name] = null;
1750  };
1751  break;
1752  case JSROOT.IO.kDouble32:
1753  case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble32:
1754  case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble32:
1755  member.double32 = true;
1756  case JSROOT.IO.kFloat16:
1757  case JSROOT.IO.kOffsetL+JSROOT.IO.kFloat16:
1758  case JSROOT.IO.kOffsetP+JSROOT.IO.kFloat16:
1759  if (element.fFactor!==0) {
1760  member.factor = 1./element.fFactor;
1761  member.min = element.fXmin;
1762  member.read = function(buf) { return buf.ntou4() * this.factor + this.min; };
1763  } else
1764  if ((element.fXmin===0) && member.double32) {
1765  member.read = function(buf) { return buf.ntof(); };
1766  } else {
1767  member.nbits = Math.round(element.fXmin);
1768  if (member.nbits===0) member.nbits = 12;
1769  member.dv = new DataView(new ArrayBuffer(8), 0); // used to cast from uint32 to float32
1770  member.read = function(buf) {
1771  var theExp = buf.ntou1(), theMan = buf.ntou2();
1772  this.dv.setUint32(0, (theExp << 23) | ((theMan & ((1<<(this.nbits+1))-1)) << (23-this.nbits)));
1773  return ((1<<(this.nbits+1) & theMan) ? -1 : 1) * this.dv.getFloat32(0);
1774  };
1775  }
1776 
1777  member.readarr = function(buf,len) {
1778  var arr = this.double32 ? new Float64Array(len) : new Float32Array(len);
1779  for (var n=0;n<len;++n) arr[n] = this.read(buf);
1780  return arr;
1781  }
1782 
1783  if (member.type < JSROOT.IO.kOffsetL) {
1784  member.func = function(buf,obj) { obj[this.name] = this.read(buf); }
1785  } else
1786  if (member.type > JSROOT.IO.kOffsetP) {
1787  member.cntname = element.fCountName;
1788  member.func = function(buf, obj) {
1789  if (buf.ntou1() === 1) {
1790  obj[this.name] = this.readarr(buf, obj[this.cntname]);
1791  } else {
1792  obj[this.name] = null;
1793  }
1794  };
1795  } else
1796  if (element.fArrayDim < 2) {
1797  member.arrlength = element.fArrayLength;
1798  member.func = function(buf, obj) { obj[this.name] = this.readarr(buf, this.arrlength); };
1799  } else {
1800  member.arrlength = element.fMaxIndex[element.fArrayDim-1];
1801  member.minus1 = true;
1802  member.func = function(buf, obj) {
1803  obj[this.name] = buf.ReadNdimArray(this, function(buf,handle) { return handle.readarr(buf, handle.arrlength); });
1804  };
1805  }
1806  break;
1807 
1808  case JSROOT.IO.kAnyP:
1809  case JSROOT.IO.kObjectP:
1810  member.func = function(buf, obj) {
1811  obj[this.name] = buf.ReadNdimArray(this, function(buf) {
1812  return buf.ReadObjectAny();
1813  });
1814  };
1815  break;
1816 
1817  case JSROOT.IO.kAny:
1818  case JSROOT.IO.kAnyp:
1819  case JSROOT.IO.kObjectp:
1820  case JSROOT.IO.kObject:
1821  var classname = (element.fTypeName === 'BASE') ? element.fName : element.fTypeName;
1822  if (classname[classname.length-1] == "*")
1823  classname = classname.substr(0, classname.length - 1);
1824 
1825  var arrkind = JSROOT.IO.GetArrayKind(classname);
1826 
1827  if (arrkind > 0) {
1828  member.arrkind = arrkind;
1829  member.func = function(buf, obj) {
1830  obj[this.name] = buf.ReadFastArray(buf.ntou4(), this.arrkind);
1831  };
1832  } else
1833  if (arrkind === 0) {
1834  member.func = function(buf,obj) { obj[this.name] = buf.ReadTString(); };
1835  } else {
1836  member.classname = classname;
1837 
1838  if (element.fArrayLength>1) {
1839  member.func = function(buf, obj) {
1840  obj[this.name] = buf.ReadNdimArray(this, function(buf, handle) {
1841  return buf.ClassStreamer({}, handle.classname);
1842  });
1843  };
1844  } else {
1845  member.func = function(buf, obj) {
1846  obj[this.name] = buf.ClassStreamer({}, this.classname);
1847  };
1848  }
1849  }
1850  break;
1851  case JSROOT.IO.kOffsetL + JSROOT.IO.kObject:
1852  case JSROOT.IO.kOffsetL + JSROOT.IO.kAny:
1853  case JSROOT.IO.kOffsetL + JSROOT.IO.kAnyp:
1854  case JSROOT.IO.kOffsetL + JSROOT.IO.kObjectp:
1855  var classname = element.fTypeName;
1856  if (classname[classname.length-1] == "*")
1857  classname = classname.substr(0, classname.length - 1);
1858 
1859  member.arrkind = JSROOT.IO.GetArrayKind(classname);
1860  if (member.arrkind < 0) member.classname = classname;
1861  member.func = function(buf, obj) {
1862  obj[this.name] = buf.ReadNdimArray(this, function(buf, handle) {
1863  if (handle.arrkind>0) return buf.ReadFastArray(buf.ntou4(), handle.arrkind);
1864  if (handle.arrkind===0) return buf.ReadTString();
1865  return buf.ClassStreamer({}, handle.classname);
1866  });
1867  }
1868  break;
1869  case JSROOT.IO.kChar:
1870  member.func = function(buf,obj) { obj[this.name] = buf.ntoi1(); }; break;
1871  case JSROOT.IO.kCharStar:
1872  member.func = function(buf,obj) {
1873  var len = buf.ntoi4();
1874  obj[this.name] = buf.substring(buf.o, buf.o + len);
1875  buf.o += len;
1876  };
1877  break;
1878  case JSROOT.IO.kTString:
1879  member.func = function(buf,obj) { obj[this.name] = buf.ReadTString(); };
1880  break;
1881  case JSROOT.IO.kTObject:
1882  case JSROOT.IO.kTNamed:
1883  member.typename = element.fTypeName;
1884  member.func = function(buf,obj) { obj[this.name] = buf.ClassStreamer({}, this.typename); };
1885  break;
1886  case JSROOT.IO.kOffsetL+JSROOT.IO.kTString:
1887  case JSROOT.IO.kOffsetL+JSROOT.IO.kTObject:
1888  case JSROOT.IO.kOffsetL+JSROOT.IO.kTNamed:
1889  member.typename = element.fTypeName;
1890  member.func = function(buf, obj) {
1891  var ver = buf.ReadVersion();
1892  obj[this.name] = buf.ReadNdimArray(this, function(buf, handle) {
1893  if (handle.typename === 'TString') return buf.ReadTString();
1894  return buf.ClassStreamer({}, handle.typename);
1895  });
1896  buf.CheckBytecount(ver, this.typename + "[]");
1897  };
1898  break;
1899  case JSROOT.IO.kStreamLoop:
1900  case JSROOT.IO.kOffsetL+JSROOT.IO.kStreamLoop:
1901  member.typename = element.fTypeName;
1902  member.cntname = element.fCountName;
1903 
1904  if (member.typename.lastIndexOf("**")>0) {
1905  member.typename = member.typename.substr(0, member.typename.lastIndexOf("**"));
1906  member.isptrptr = true;
1907  } else {
1908  member.typename = member.typename.substr(0, member.typename.lastIndexOf("*"));
1909  member.isptrptr = false;
1910  }
1911 
1912  if (member.isptrptr) {
1913  member.readitem = function(buf) { return buf.ReadObjectAny(); }
1914  } else {
1915  member.arrkind = JSROOT.IO.GetArrayKind(member.typename);
1916  if (member.arrkind > 0)
1917  member.readitem = function(buf) { return buf.ReadFastArray(buf.ntou4(), this.arrkind); }
1918  else if (member.arrkind === 0)
1919  member.readitem = function(buf) { return buf.ReadTString(); }
1920  else
1921  member.readitem = function(buf) { return buf.ClassStreamer({}, this.typename); }
1922  }
1923 
1924  if (member.readitem !== undefined) {
1925  member.read_loop = function(buf,cnt) {
1926  return buf.ReadNdimArray(this, function(buf2,member2) {
1927  var itemarr = new Array(cnt);
1928  for (var i = 0; i < cnt; ++i )
1929  itemarr[i] = member2.readitem(buf2);
1930  return itemarr;
1931  });
1932  }
1933 
1934  member.func = function(buf,obj) {
1935  var ver = buf.ReadVersion();
1936  var res = this.read_loop(buf, obj[this.cntname]);
1937  if (!buf.CheckBytecount(ver, this.typename)) res = null;
1938  obj[this.name] = res;
1939  }
1940  member.branch_func = function(buf,obj) {
1941  // this is special functions, used by branch in the STL container
1942 
1943  var ver = buf.ReadVersion(), sz0 = obj[this.stl_size], res = new Array(sz0);
1944 
1945  for (var loop0=0;loop0<sz0;++loop0) {
1946  var cnt = obj[this.cntname][loop0];
1947  res[loop0] = this.read_loop(buf, cnt);
1948  }
1949  if (!buf.CheckBytecount(ver, this.typename)) res = null;
1950  obj[this.name] = res;
1951  }
1952 
1953  member.objs_branch_func = function(buf,obj) {
1954  // special function when branch read as part of complete object
1955  // objects already preallocated and only appropriate member must be set
1956  // see code in JSRootTree.js for reference
1957 
1958  var ver = buf.ReadVersion(), arr = obj[this.name0]; // objects array where reading is done
1959 
1960  for (var loop0=0;loop0<arr.length;++loop0) {
1961  var obj1 = this.get(arr,loop0), cnt = obj1[this.cntname];
1962  obj1[this.name] = this.read_loop(buf, cnt);
1963  }
1964 
1965  buf.CheckBytecount(ver, this.typename);
1966  }
1967 
1968  } else {
1969  JSROOT.console('fail to provide function for ' + element.fName + ' (' + element.fTypeName + ') typ = ' + element.fType);
1970  member.func = function(buf,obj) {
1971  var ver = buf.ReadVersion();
1972  buf.CheckBytecount(ver);
1973  obj[this.name] = ull;
1974  };
1975  }
1976 
1977  break;
1978 
1979  case JSROOT.IO.kStreamer:
1980  member.typename = element.fTypeName;
1981 
1982  var stl = (element.fSTLtype || 0) % 40;
1983 
1984  if ((element._typename === 'TStreamerSTLstring') ||
1985  (member.typename == "string") || (member.typename == "string*")) {
1986  member.readelem = function(buf) { return buf.ReadTString(); };
1987  } else
1988  if ((stl === JSROOT.IO.kSTLvector) || (stl === JSROOT.IO.kSTLlist) ||
1989  (stl === JSROOT.IO.kSTLdeque) || (stl === JSROOT.IO.kSTLset) ||
1990  (stl === JSROOT.IO.kSTLmultiset)) {
1991  var p1 = member.typename.indexOf("<"),
1992  p2 = member.typename.lastIndexOf(">");
1993 
1994  member.conttype = member.typename.substr(p1+1,p2-p1-1).trim();
1995 
1996  member.typeid = JSROOT.IO.GetTypeId(member.conttype);
1997  if ((member.typeid<0) && file.fBasicTypes[member.conttype]) {
1998  member.typeid = file.fBasicTypes[member.conttype];
1999  console.log('!!! Reuse basic type', member.conttype, 'from file streamer infos');
2000  }
2001 
2002  // check
2003  if (element.fCtype && (element.fCtype < 20) && (element.fCtype !== member.typeid)) {
2004  console.warn('Contained type', member.conttype, 'not recognized as basic type', element.fCtype, 'FORCE');
2005  member.typeid = element.fCtype;
2006  }
2007 
2008  if (member.typeid > 0) {
2009  member.readelem = function(buf) {
2010  return buf.ReadFastArray(buf.ntoi4(), this.typeid);
2011  };
2012  } else {
2013  member.isptr = false;
2014 
2015  if (member.conttype.lastIndexOf("*") === member.conttype.length-1) {
2016  member.isptr = true;
2017  member.conttype = member.conttype.substr(0,member.conttype.length-1);
2018  }
2019 
2020  if (element.fCtype === JSROOT.IO.kObjectp) member.isptr = true;
2021 
2022  member.arrkind = JSROOT.IO.GetArrayKind(member.conttype);
2023 
2024  member.readelem = JSROOT.IO.ReadVectorElement;
2025 
2026  if (!member.isptr && (member.arrkind<0)) {
2027 
2028  var subelem = JSROOT.IO.CreateStreamerElement("temp", member.conttype);
2029 
2030  if (subelem.fType === JSROOT.IO.kStreamer) {
2031  subelem.$fictional = true;
2032  member.submember = JSROOT.IO.CreateMember(subelem, file);
2033  }
2034  }
2035  }
2036  } else
2037  if ((stl === JSROOT.IO.kSTLmap) || (stl === JSROOT.IO.kSTLmultimap)) {
2038 
2039  var p1 = member.typename.indexOf("<"),
2040  p2 = member.typename.lastIndexOf(">");
2041 
2042  member.pairtype = "pair<" + member.typename.substr(p1+1,p2-p1-1) + ">";
2043 
2044  // remember found streamer info from the file -
2045  // most probably it is the only one which should be used
2046  member.si = file.FindStreamerInfo(member.pairtype);
2047 
2048  member.streamer = JSROOT.IO.GetPairStreamer(member.si, member.pairtype, file);
2049 
2050  if (!member.streamer || (member.streamer.length!==2)) {
2051  JSROOT.console('Fail to build streamer for pair ' + member.pairtype);
2052  delete member.streamer;
2053  }
2054 
2055  if (member.streamer) member.readelem = JSROOT.IO.ReadMapElement;
2056  } else
2057  if (stl === JSROOT.IO.kSTLbitset) {
2058  member.readelem = function(buf,obj) {
2059  return buf.ReadFastArray(buf.ntou4(), JSROOT.IO.kBool);
2060  }
2061  }
2062 
2063  if (!member.readelem) {
2064  JSROOT.console('failed to create streamer for element ' + member.typename + ' ' + member.name + ' element ' + element._typename + ' STL type ' + element.fSTLtype);
2065  member.func = function(buf,obj) {
2066  var ver = buf.ReadVersion();
2067  buf.CheckBytecount(ver);
2068  obj[this.name] = null;
2069  }
2070  } else
2071  if (!element.$fictional) {
2072 
2073  member.read_version = function(buf, cnt) {
2074  if (cnt===0) return null;
2075  var o = buf.o, ver = buf.ReadVersion();
2076  this.member_wise = ((ver.val & JSROOT.IO.kStreamedMemberWise) !== 0);
2077  this.stl_version = undefined;
2078  if (this.member_wise) {
2079  this.stl_version = { val: buf.ntoi2() };
2080  if (this.stl_version.val<=0) this.stl_version.checksum = buf.ntou4();
2081  }
2082  return ver;
2083  }
2084 
2085  member.func = function(buf,obj) {
2086  var ver = this.read_version(buf);
2087 
2088  var res = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); });
2089 
2090  if (!buf.CheckBytecount(ver, this.typename)) res = null;
2091  obj[this.name] = res;
2092  }
2093 
2094  member.branch_func = function(buf,obj) {
2095  // special function to read data from STL branch
2096  var cnt = obj[this.stl_size], arr = new Array(cnt);
2097 
2098  var ver = this.read_version(buf, cnt);
2099 
2100  for (var n=0;n<cnt;++n)
2101  arr[n] = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); });
2102 
2103  if (ver) buf.CheckBytecount(ver, "branch " + this.typename);
2104 
2105  obj[this.name] = arr;
2106  }
2107  member.split_func = function(buf, arr, n) {
2108  // function to read array from member-wise streaming
2109  var ver = this.read_version(buf);
2110  for (var i=0;i<n;++i)
2111  arr[i][this.name] = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); });
2112  buf.CheckBytecount(ver, this.typename);
2113  }
2114  member.objs_branch_func = function(buf,obj) {
2115  // special function when branch read as part of complete object
2116  // objects already preallocated and only appropriate member must be set
2117  // see code in JSRootTree.js for reference
2118 
2119  var arr = obj[this.name0]; // objects array where reading is done
2120 
2121  var ver = this.read_version(buf, arr.length);
2122 
2123  for (var n=0;n<arr.length;++n) {
2124  var obj1 = this.get(arr,n);
2125  obj1[this.name] = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); });
2126  }
2127 
2128  if (ver) buf.CheckBytecount(ver, "branch " + this.typename);
2129  }
2130  }
2131  break;
2132 
2133  default:
2134  JSROOT.console('fail to provide function for ' + element.fName + ' (' + element.fTypeName + ') typ = ' + element.fType);
2135 
2136  member.func = function(buf,obj) {}; // do nothing, fix in the future
2137  }
2138 
2139  return member;
2140  }
2141 
2145  TFile.prototype.GetStreamer = function(clname, ver, s_i) {
2146 
2147  // these are special cases, which are handled separately
2148  if (clname == 'TQObject' || clname == "TBasket") return null;
2149 
2150  var streamer, fullname = clname;
2151 
2152  if (ver) {
2153  fullname += (ver.checksum ? ("$chksum" + ver.checksum) : ("$ver" + ver.val));
2154  streamer = this.fStreamers[fullname];
2155  if (streamer !== undefined) return streamer;
2156  }
2157 
2158  var custom = JSROOT.IO.CustomStreamers[clname];
2159 
2160  // one can define in the user streamers just aliases
2161  if (typeof custom === 'string')
2162  return this.GetStreamer(custom, ver, s_i);
2163 
2164  // streamer is just separate function
2165  if (typeof custom === 'function') {
2166  streamer = [{ typename: clname, func: custom }];
2167  return JSROOT.IO.AddClassMethods(clname, streamer);
2168  }
2169 
2170  streamer = [];
2171 
2172  if (typeof custom === 'object') {
2173  if (!custom.name && !custom.func) return custom;
2174  streamer.push(custom); // special read entry, add in the beginning of streamer
2175  }
2176 
2177  // check element in streamer infos, one can have special cases
2178  if (!s_i) s_i = this.FindStreamerInfo(clname, ver.val, ver.checksum);
2179 
2180  if (!s_i) {
2181  delete this.fStreamers[fullname];
2182  if (!ver.nowarning)
2183  console.warn("Not found streamer for", clname, "ver", ver.val, "checksum", ver.checksum, fullname);
2184  return null;
2185  }
2186 
2187  // for each entry in streamer info produce member function
2188 
2189  if (s_i.fElements)
2190  for (var j=0; j < s_i.fElements.arr.length; ++j)
2191  streamer.push(JSROOT.IO.CreateMember(s_i.fElements.arr[j], this));
2192 
2193  this.fStreamers[fullname] = streamer;
2194 
2195  return JSROOT.IO.AddClassMethods(clname, streamer);
2196  }
2197 
2200  TFile.prototype.GetSplittedStreamer = function(streamer, tgt) {
2201  if (!streamer) return tgt;
2202 
2203  if (!tgt) tgt = [];
2204 
2205  for (var n=0;n<streamer.length;++n) {
2206  var elem = streamer[n];
2207 
2208  if (elem.base === undefined) {
2209  tgt.push(elem);
2210  continue;
2211  }
2212 
2213  if (elem.basename == 'TObject') {
2214  tgt.push({ func: function(buf,obj) {
2215  buf.ntoi2(); // read version, why it here??
2216  obj.fUniqueID = buf.ntou4();
2217  obj.fBits = buf.ntou4();
2218  if (obj.fBits & JSROOT.IO.kIsReferenced) buf.ntou2(); // skip pid
2219  } });
2220  continue;
2221  }
2222 
2223  var ver = { val: elem.base };
2224 
2225  if (ver.val === 4294967295) {
2226  // this is -1 and indicates foreign class, need more workarounds
2227  ver.val = 1; // need to search version 1 - that happens when several versions of foreign class exists ???
2228  }
2229 
2230  var parent = this.GetStreamer(elem.basename, ver);
2231  if (parent) this.GetSplittedStreamer(parent, tgt);
2232  }
2233 
2234  return tgt;
2235  }
2236 
2237  TFile.prototype.Delete = function() {
2238  this.fDirectories = null;
2239  this.fKeys = null;
2240  this.fStreamers = null;
2241  this.fSeekInfo = 0;
2242  this.fNbytesInfo = 0;
2243  this.fTagOffset = 0;
2244  }
2245 
2246  // =============================================================
2247 
2248  function TLocalFile(file, newfile_callback) {
2249  TFile.call(this, null);
2250  this.fUseStampPar = false;
2251  this.fLocalFile = file;
2252  this.fEND = file.size;
2253  this.fFullURL = file.name;
2254  this.fURL = file.name;
2255  this.fFileName = file.name;
2256  this.ReadKeys(newfile_callback);
2257  return this;
2258  }
2259 
2260  TLocalFile.prototype = Object.create(TFile.prototype);
2261 
2262  TLocalFile.prototype.ReadBuffer = function(place, result_callback, filename, progress_callback) {
2263 
2264  if (filename)
2265  throw new Error("Cannot access other local file "+filename)
2266 
2267  var reader = new FileReader(), cnt = 0, blobs = [], file = this.fLocalFile;
2268 
2269  reader.onload = function(evnt) {
2270  var res = new DataView(evnt.target.result);
2271  if (place.length===2) return result_callback(res);
2272 
2273  blobs.push(res);
2274  cnt+=2;
2275  if (cnt >= place.length) return result_callback(blobs);
2276  reader.readAsArrayBuffer(file.slice(place[cnt], place[cnt]+place[cnt+1]));
2277  }
2278 
2279  reader.readAsArrayBuffer(file.slice(place[0], place[0]+place[1]));
2280  }
2281 
2282  // =============================================================
2283 
2284  function TNodejsFile(filename, newfile_callback) {
2285  TFile.call(this, null);
2286  this.fUseStampPar = false;
2287  this.fEND = 0;
2288  this.fFullURL = filename;
2289  this.fURL = filename;
2290  this.fFileName = filename;
2291 
2292  var pthis = this;
2293 
2294  pthis.fs = require('fs');
2295 
2296  pthis.fs.open(filename, 'r', function(status, fd) {
2297  if (status) {
2298  console.log(status.message);
2299  return JSROOT.CallBack(newfile_callback, null);
2300  }
2301  var stats = pthis.fs.fstatSync(fd);
2302 
2303  pthis.fEND = stats.size;
2304 
2305  pthis.fd = fd;
2306 
2307  // return JSROOT.CallBack(newfile_callback, pthis);
2308 
2309  pthis.ReadKeys(newfile_callback);
2310 
2311  //var buffer = new Buffer(100);
2312  //fs.read(fd, buffer, 0, 100, 0, function(err, num) {
2313  // console.log(buffer.toString('utf8', 0, num));
2314  //});
2315  });
2316  return this;
2317  }
2318 
2319  TNodejsFile.prototype = Object.create(TFile.prototype);
2320 
2321  TNodejsFile.prototype.ReadBuffer = function(place, result_callback, filename, progress_callback) {
2322 
2323  if (filename)
2324  throw new Error("Cannot access other local file "+filename);
2325 
2326  if (!this.fs || !this.fd)
2327  throw new Error("File is not opened " + this.fFileName);
2328 
2329  var cnt = 0, blobs = [], file = this;
2330 
2331  function readfunc(err, bytesRead, buf) {
2332 
2333  var res = new DataView(buf.buffer, buf.byteOffset, place[cnt+1]);
2334  if (place.length===2) return result_callback(res);
2335 
2336  blobs.push(res);
2337  cnt+=2;
2338  if (cnt >= place.length) return result_callback(blobs);
2339  file.fs.read(file.fd, new Buffer(place[cnt+1]), 0, place[cnt+1], place[cnt], readfunc);
2340  }
2341 
2342  file.fs.read(file.fd, new Buffer(place[1]), 0, place[1], place[0], readfunc);
2343  }
2344 
2345  // =========================================
2346 
2347 
2348  JSROOT.IO.ProduceCustomStreamers = function() {
2349  var cs = JSROOT.IO.CustomStreamers;
2350 
2351  cs['TObject'] = cs['TMethodCall'] = function(buf,obj) {
2352  obj.fUniqueID = buf.ntou4();
2353  obj.fBits = buf.ntou4();
2354  if (obj.fBits & JSROOT.IO.kIsReferenced) buf.ntou2(); // skip pid
2355  };
2356 
2357  cs['TNamed'] = [
2358  { basename: 'TObject', base: 1, func: function(buf,obj) {
2359  if (!obj._typename) obj._typename = 'TNamed';
2360  buf.ClassStreamer(obj, "TObject"); }
2361  },
2362  { name: 'fName', func: function(buf,obj) { obj.fName = buf.ReadTString(); } },
2363  { name: 'fTitle', func: function(buf,obj) { obj.fTitle = buf.ReadTString(); } }
2364  ];
2365  JSROOT.IO.AddClassMethods('TNamed', cs['TNamed']);
2366 
2367  cs['TObjString'] = [
2368  { basename: 'TObject', base: 1, func: function(buf,obj) {
2369  if (!obj._typename) obj._typename = 'TObjString';
2370  buf.ClassStreamer(obj, "TObject"); }
2371  },
2372  { name: 'fString', func: function(buf, obj) { obj.fString = buf.ReadTString(); } }
2373  ];
2374 
2375  JSROOT.IO.AddClassMethods('TObjString', cs['TObjString']);
2376 
2377  cs['TList'] = cs['THashList'] = function(buf, obj) {
2378  // stream all objects in the list from the I/O buffer
2379  if (!obj._typename) obj._typename = this.typename;
2380  obj.$kind = "TList"; // all derived classes will be marked as well
2381  if (buf.last_read_version > 3) {
2382  buf.ClassStreamer(obj, "TObject");
2383  obj.name = buf.ReadTString();
2384  var nobjects = buf.ntou4(), i = 0;
2385  obj.arr = new Array(nobjects);
2386  obj.opt = new Array(nobjects);
2387  for (; i<nobjects; ++i) {
2388  obj.arr[i] = buf.ReadObjectAny();
2389  obj.opt[i] = buf.ReadTString();
2390  }
2391  } else {
2392  obj.name = "";
2393  obj.arr = [];
2394  obj.opt = [];
2395  }
2396  };
2397 
2398  cs['TClonesArray'] = function(buf, list) {
2399  if (!list._typename) list._typename = "TClonesArray";
2400  list.$kind = "TClonesArray";
2401  list.name = "";
2402  var ver = buf.last_read_version;
2403  if (ver > 2) buf.ClassStreamer(list, "TObject");
2404  if (ver > 1) list.name = buf.ReadTString();
2405  var classv = buf.ReadTString(), clv = 0,
2406  pos = classv.lastIndexOf(";");
2407 
2408  if (pos > 0) {
2409  clv = parseInt(classv.substr(pos+1));
2410  classv = classv.substr(0, pos);
2411  }
2412 
2413  var nobjects = buf.ntou4();
2414  if (nobjects < 0) nobjects = -nobjects; // for backward compatibility
2415 
2416  list.arr = new Array(nobjects);
2417  list.fLast = nobjects-1;
2418  list.fLowerBound = buf.ntou4();
2419 
2420  var streamer = buf.fFile.GetStreamer(classv, { val: clv });
2421  streamer = buf.fFile.GetSplittedStreamer(streamer);
2422 
2423  if (!streamer) {
2424  console.log('Cannot get member-wise streamer for', classv, clv);
2425  } else {
2426  // create objects
2427  for (var n=0;n<nobjects;++n)
2428  list.arr[n] = { _typename: classv };
2429 
2430  // call streamer for all objects member-wise
2431  for (var k=0;k<streamer.length;++k)
2432  for (var n=0;n<nobjects;++n)
2433  streamer[k].func(buf, list.arr[n]);
2434  }
2435  };
2436 
2437  cs['TMap'] = function(buf, map) {
2438  if (!map._typename) map._typename = "TMap";
2439  map.name = "";
2440  map.arr = new Array();
2441  var ver = buf.last_read_version;
2442  if (ver > 2) buf.ClassStreamer(map, "TObject");
2443  if (ver > 1) map.name = buf.ReadTString();
2444 
2445  var nobjects = buf.ntou4();
2446  // create objects
2447  for (var n=0;n<nobjects;++n) {
2448  var obj = { _typename: "TPair" };
2449  obj.first = buf.ReadObjectAny();
2450  obj.second = buf.ReadObjectAny();
2451  if (obj.first) map.arr.push(obj);
2452  }
2453  };
2454 
2455  cs['TTreeIndex'] = function(buf, obj) {
2456  var ver = buf.last_read_version;
2457  obj._typename = "TTreeIndex";
2458  buf.ClassStreamer(obj, "TVirtualIndex");
2459  obj.fMajorName = buf.ReadTString();
2460  obj.fMinorName = buf.ReadTString();
2461  obj.fN = buf.ntoi8();
2462  obj.fIndexValues = buf.ReadFastArray(obj.fN, JSROOT.IO.kLong64);
2463  if (ver>1) obj.fIndexValuesMinor = buf.ReadFastArray(obj.fN, JSROOT.IO.kLong64);
2464  obj.fIndex = buf.ReadFastArray(obj.fN, JSROOT.IO.kLong64);
2465  };
2466 
2467  cs['TRefArray'] = function(buf, obj) {
2468  obj._typename = "TRefArray";
2469  buf.ClassStreamer(obj, "TObject");
2470  obj.name = buf.ReadTString();
2471  var nobj = buf.ntoi4();
2472  obj.fLast = nobj-1;
2473  obj.fLowerBound = buf.ntoi4();
2474  var pidf = buf.ntou2();
2475  obj.fUIDs = buf.ReadFastArray(nobj, JSROOT.IO.kUInt);
2476  };
2477 
2478  cs['TCanvas'] = function(buf, obj) {
2479  obj._typename = "TCanvas";
2480  buf.ClassStreamer(obj, "TPad");
2481  obj.fDISPLAY = buf.ReadTString();
2482  obj.fDoubleBuffer = buf.ntoi4();
2483  obj.fRetained = (buf.ntou1() !== 0);
2484  obj.fXsizeUser = buf.ntoi4();
2485  obj.fYsizeUser = buf.ntoi4();
2486  obj.fXsizeReal = buf.ntoi4();
2487  obj.fYsizeReal = buf.ntoi4();
2488  obj.fWindowTopX = buf.ntoi4();
2489  obj.fWindowTopY = buf.ntoi4();
2490  obj.fWindowWidth = buf.ntoi4();
2491  obj.fWindowHeight = buf.ntoi4();
2492  obj.fCw = buf.ntou4();
2493  obj.fCh = buf.ntou4();
2494  obj.fCatt = buf.ClassStreamer({}, "TAttCanvas");
2495  buf.ntou1(); // ignore b << TestBit(kMoveOpaque);
2496  buf.ntou1(); // ignore b << TestBit(kResizeOpaque);
2497  obj.fHighLightColor = buf.ntoi2();
2498  obj.fBatch = (buf.ntou1() !== 0);
2499  buf.ntou1(); // ignore b << TestBit(kShowEventStatus);
2500  buf.ntou1(); // ignore b << TestBit(kAutoExec);
2501  buf.ntou1(); // ignore b << TestBit(kMenuBar);
2502  };
2503 
2504  cs['TObjArray'] = function(buf, list) {
2505  if (!list._typename) list._typename = "TObjArray";
2506  list.$kind = "TObjArray";
2507  list.name = "";
2508  var ver = buf.last_read_version;
2509  if (ver > 2)
2510  buf.ClassStreamer(list, "TObject");
2511  if (ver > 1)
2512  list.name = buf.ReadTString();
2513  var nobjects = buf.ntou4(), i = 0;
2514  list.arr = new Array(nobjects);
2515  list.fLast = nobjects-1;
2516  list.fLowerBound = buf.ntou4();
2517  while (i < nobjects)
2518  list.arr[i++] = buf.ReadObjectAny();
2519  };
2520 
2521  cs['TPolyMarker3D'] = function(buf, marker) {
2522  var ver = buf.last_read_version;
2523  buf.ClassStreamer(marker, "TObject");
2524  buf.ClassStreamer(marker, "TAttMarker");
2525  marker.fN = buf.ntoi4();
2526  marker.fP = buf.ReadFastArray(marker.fN*3, JSROOT.IO.kFloat);
2527  marker.fOption = buf.ReadTString();
2528  marker.fName = (ver > 1) ? buf.ReadTString() : "TPolyMarker3D";
2529  };
2530 
2531  cs['TPolyLine3D'] = function(buf, obj) {
2532  buf.ClassStreamer(obj, "TObject");
2533  buf.ClassStreamer(obj, "TAttLine");
2534  obj.fN = buf.ntoi4();
2535  obj.fP = buf.ReadFastArray(obj.fN*3, JSROOT.IO.kFloat);
2536  obj.fOption = buf.ReadTString();
2537  };
2538 
2539  cs['TStreamerInfo'] = function(buf, obj) {
2540  // stream an object of class TStreamerInfo from the I/O buffer
2541  buf.ClassStreamer(obj, "TNamed");
2542  obj.fCheckSum = buf.ntou4();
2543  obj.fClassVersion = buf.ntou4();
2544  obj.fElements = buf.ReadObjectAny();
2545  };
2546 
2547  cs['TStreamerElement'] = function(buf, element) {
2548  // stream an object of class TStreamerElement
2549 
2550  var ver = buf.last_read_version;
2551  buf.ClassStreamer(element, "TNamed");
2552  element.fType = buf.ntou4();
2553  element.fSize = buf.ntou4();
2554  element.fArrayLength = buf.ntou4();
2555  element.fArrayDim = buf.ntou4();
2556  element.fMaxIndex = buf.ReadFastArray((ver == 1) ? buf.ntou4() : 5, JSROOT.IO.kUInt);
2557  element.fTypeName = buf.ReadTString();
2558 
2559  if ((element.fType === JSROOT.IO.kUChar) && ((element.fTypeName == "Bool_t") || (element.fTypeName == "bool")))
2560  element.fType = JSROOT.IO.kBool;
2561 
2562  element.fXmin = element.fXmax = element.fFactor = 0;
2563  if (ver === 3) {
2564  element.fXmin = buf.ntod();
2565  element.fXmax = buf.ntod();
2566  element.fFactor = buf.ntod();
2567  } else
2568  if ((ver > 3) && (element.fBits & JSROOT.BIT(6))) { // kHasRange
2569 
2570  var p1 = element.fTitle.indexOf("[");
2571  if ((p1>=0) && (element.fType>JSROOT.IO.kOffsetP)) p1 = element.fTitle.indexOf("[", p1+1);
2572  var p2 = element.fTitle.indexOf("]", p1+1);
2573 
2574  if ((p1>=0) && (p2>=p1+2)) {
2575  var arr = JSROOT.ParseAsArray(element.fTitle.substr(p1, p2-p1+1)), nbits = 32;
2576 
2577  if (arr.length===3) nbits = parseInt(arr[2]);
2578  if (isNaN(nbits) || (nbits<2) || (nbits>32)) nbits = 32;
2579 
2580  function parse_range(val) {
2581  if (!val) return 0;
2582  if (val.indexOf("pi")<0) return parseFloat(val);
2583  val = val.trim();
2584  var sign = 1.;
2585  if (val[0] == "-") { sign = -1; val = val.substr(1); }
2586  switch(val) {
2587  case "2pi":
2588  case "2*pi":
2589  case "twopi": return sign*2*Math.PI;
2590  case "pi/2": return sign*Math.PI/2;
2591  case "pi/4": return sign*Math.PI/4;
2592  }
2593  return sign*Math.PI;
2594  }
2595 
2596  element.fXmin = parse_range(arr[0]);
2597  element.fXmax = parse_range(arr[1]);
2598 
2599  var bigint = (nbits < 32) ? (1<<nbits) : 0xffffffff;
2600  if (element.fXmin < element.fXmax) element.fFactor = bigint/(element.fXmax - element.fXmin);
2601  else if (nbits<15) element.fXmin = nbits;
2602  }
2603  }
2604  };
2605 
2606  cs['TStreamerBase'] = function(buf, elem) {
2607  var ver = buf.last_read_version;
2608  buf.ClassStreamer(elem, "TStreamerElement");
2609  if (ver > 2) elem.fBaseVersion = buf.ntou4();
2610  };
2611 
2612  cs['TStreamerBasicPointer'] = cs['TStreamerLoop'] = function(buf,elem) {
2613  if (buf.last_read_version > 1) {
2614  buf.ClassStreamer(elem, "TStreamerElement");
2615  elem.fCountVersion = buf.ntou4();
2616  elem.fCountName = buf.ReadTString();
2617  elem.fCountClass = buf.ReadTString();
2618  }
2619  };
2620 
2621  cs['TStreamerSTL'] = function(buf, elem) {
2622  buf.ClassStreamer(elem, "TStreamerElement");
2623  elem.fSTLtype = buf.ntou4();
2624  elem.fCtype = buf.ntou4();
2625 
2626  if ((elem.fSTLtype === JSROOT.IO.kSTLmultimap) &&
2627  ((elem.fTypeName.indexOf("std::set")===0) ||
2628  (elem.fTypeName.indexOf("set")==0))) elem.fSTLtype = JSROOT.IO.kSTLset;
2629 
2630  if ((elem.fSTLtype === JSROOT.IO.kSTLset) &&
2631  ((elem.fTypeName.indexOf("std::multimap")===0) ||
2632  (elem.fTypeName.indexOf("multimap")===0))) elem.fSTLtype = JSROOT.IO.kSTLmultimap;
2633  };
2634 
2635  cs['TStreamerSTLstring'] = function(buf, elem) {
2636  if (buf.last_read_version > 0)
2637  buf.ClassStreamer(elem, "TStreamerSTL");
2638  };
2639 
2640  cs['TStreamerObject'] = cs['TStreamerBasicType'] = cs['TStreamerObjectAny'] =
2641  cs['TStreamerString'] = cs['TStreamerObjectPointer'] = function(buf, elem) {
2642  if (buf.last_read_version > 1)
2643  buf.ClassStreamer(elem, "TStreamerElement");
2644  }
2645 
2646  cs['TStreamerObjectAnyPointer'] = function(buf, elem) {
2647  if (buf.last_read_version > 0)
2648  buf.ClassStreamer(elem, "TStreamerElement");
2649  }
2650 
2651  cs['TTree'] = {
2652  name: '$file',
2653  func: function(buf,obj) { obj.$kind = "TTree"; obj.$file = buf.fFile; buf.fFile.AddReadTree(obj); }
2654  }
2655 
2656  cs['TVirtualPerfStats'] = "TObject"; // use directly TObject streamer
2657 
2658  cs['RooRealVar'] = function(buf,obj) {
2659  var v = buf.last_read_version;
2660  buf.ClassStreamer(obj, "RooAbsRealLValue");
2661  if (v==1) { buf.ntod(); buf.ntod(); buf.ntoi4(); } // skip fitMin, fitMax, fitBins
2662  obj._error = buf.ntod();
2663  obj._asymErrLo = buf.ntod();
2664  obj._asymErrHi = buf.ntod();
2665  if (v>=2) obj._binning = buf.ReadObjectAny();
2666  if (v==3) obj._sharedProp = buf.ReadObjectAny();
2667  if (v>=4) obj._sharedProp = buf.ClassStreamer({}, "RooRealVarSharedProperties");
2668  };
2669 
2670  cs['RooAbsBinning'] = function(buf,obj) {
2671  buf.ClassStreamer(obj, (buf.last_read_version==1) ? "TObject" : "TNamed");
2672  buf.ClassStreamer(obj, "RooPrintable");
2673  }
2674 
2675  cs['RooCategory'] = function(buf,obj) {
2676  var v = buf.last_read_version;
2677  buf.ClassStreamer(obj, "RooAbsCategoryLValue");
2678  obj._sharedProp = (v===1) ? buf.ReadObjectAny() : buf.ClassStreamer({}, "RooCategorySharedProperties");
2679  };
2680 
2681  cs['RooWorkspace::CodeRepo'] = function(buf,obj) {
2682  var sz = (buf.last_read_version == 2) ? 3 : 2;
2683  for (var i=0;i<sz;++i) {
2684  var cnt = buf.ntoi4() * ((i==0) ? 4 : 3);
2685  while (cnt--) buf.ReadTString();
2686  }
2687  }
2688 
2689  cs['RooLinkedList'] = function(buf,obj) {
2690  var v = buf.last_read_version;
2691  buf.ClassStreamer(obj, "TObject");
2692  var size = buf.ntoi4();
2693  obj.arr = JSROOT.Create("TList");
2694  while(size--)
2695  obj.arr.Add(buf.ReadObjectAny());
2696  if (v>1) obj._name = buf.ReadTString();
2697  };
2698 
2699  cs['TASImage'] = function(buf,obj) {
2700  if ((buf.last_read_version==1) && (buf.fFile.fVersion>0) && (buf.fFile.fVersion<50000)) {
2701  return console.warn("old TASImage version - not yet supported");
2702  }
2703 
2704  buf.ClassStreamer(obj, "TNamed");
2705 
2706  if (buf.ntou1() != 0) {
2707  var size = buf.ntoi4();
2708  obj.fPngBuf = buf.ReadFastArray(size, JSROOT.IO.kUChar);
2709  } else {
2710  buf.ClassStreamer(obj, "TAttImage");
2711  obj.fWidth = buf.ntoi4();
2712  obj.fHeight = buf.ntoi4();
2713  obj.fImgBuf = buf.ReadFastArray(obj.fWidth*obj.fHeight, JSROOT.IO.kDouble);
2714  }
2715  }
2716 
2717  cs['TMaterial'] = function(buf,obj) {
2718  var v = buf.last_read_version;
2719  buf.ClassStreamer(obj, "TNamed");
2720  obj.fNumber = buf.ntoi4();
2721  obj.fA = buf.ntof();
2722  obj.fZ = buf.ntof();
2723  obj.fDensity = buf.ntof();
2724  if (v>2) {
2725  buf.ClassStreamer(obj, "TAttFill");
2726  obj.fRadLength = buf.ntof();
2727  obj.fInterLength = buf.ntof();
2728  } else {
2729  obj.fRadLength = obj.fInterLength = 0;
2730  }
2731  }
2732 
2733  cs['TMixture'] = function(buf,obj) {
2734  buf.ClassStreamer(obj, "TMaterial");
2735  obj.fNmixt = buf.ntoi4();
2736  obj.fAmixt = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kFloat);
2737  obj.fZmixt = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kFloat);
2738  obj.fWmixt = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kFloat);
2739  }
2740 
2741  // these are direct streamers - not follow version/checksum logic
2742 
2743  var ds = JSROOT.IO.DirectStreamers;
2744 
2745  ds['TQObject'] = ds['TGraphStruct'] = ds['TGraphNode'] = ds['TGraphEdge'] = function(buf,obj) {
2746  // do nothing
2747  }
2748 
2749  ds['TDatime'] = function(buf,obj) {
2750  obj.fDatime = buf.ntou4();
2751 // obj.GetDate = function() {
2752 // var res = new Date();
2753 // res.setFullYear((this.fDatime >>> 26) + 1995);
2754 // res.setMonth((this.fDatime << 6) >>> 28);
2755 // res.setDate((this.fDatime << 10) >>> 27);
2756 // res.setHours((this.fDatime << 15) >>> 27);
2757 // res.setMinutes((this.fDatime << 20) >>> 26);
2758 // res.setSeconds((this.fDatime << 26) >>> 26);
2759 // res.setMilliseconds(0);
2760 // return res;
2761 // }
2762  }
2763 
2764  ds['TKey'] = function(buf,key) {
2765  key.fNbytes = buf.ntoi4();
2766  key.fVersion = buf.ntoi2();
2767  key.fObjlen = buf.ntou4();
2768  key.fDatime = buf.ClassStreamer({}, 'TDatime');
2769  key.fKeylen = buf.ntou2();
2770  key.fCycle = buf.ntou2();
2771  if (key.fVersion > 1000) {
2772  key.fSeekKey = buf.ntou8();
2773  buf.shift(8); // skip seekPdir
2774  } else {
2775  key.fSeekKey = buf.ntou4();
2776  buf.shift(4); // skip seekPdir
2777  }
2778  key.fClassName = buf.ReadTString();
2779  key.fName = buf.ReadTString();
2780  key.fTitle = buf.ReadTString();
2781  }
2782 
2783  ds['TDirectory'] = function(buf, dir) {
2784  var version = buf.ntou2();
2785  dir.fDatimeC = buf.ClassStreamer({}, 'TDatime');
2786  dir.fDatimeM = buf.ClassStreamer({}, 'TDatime');
2787  dir.fNbytesKeys = buf.ntou4();
2788  dir.fNbytesName = buf.ntou4();
2789  dir.fSeekDir = (version > 1000) ? buf.ntou8() : buf.ntou4();
2790  dir.fSeekParent = (version > 1000) ? buf.ntou8() : buf.ntou4();
2791  dir.fSeekKeys = (version > 1000) ? buf.ntou8() : buf.ntou4();
2792  // if ((version % 1000) > 2) buf.shift(18); // skip fUUID
2793  }
2794 
2795  ds['TBasket'] = function(buf,obj) {
2796  buf.ClassStreamer(obj, 'TKey');
2797  var ver = buf.ReadVersion();
2798  obj.fBufferSize = buf.ntoi4();
2799  obj.fNevBufSize = buf.ntoi4();
2800  obj.fNevBuf = buf.ntoi4();
2801  obj.fLast = buf.ntoi4();
2802  if (obj.fLast > obj.fBufferSize) obj.fBufferSize = obj.fLast;
2803  var flag = buf.ntoi1();
2804 
2805  if (flag===0) return;
2806 
2807  if ((flag % 10) != 2) {
2808  if (obj.fNevBuf) {
2809  obj.fEntryOffset = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kInt);
2810  if ((20<flag) && (flag<40))
2811  for(var i=0, kDisplacementMask = 0xFF000000; i<obj.fNevBuf; ++i)
2812  obj.fEntryOffset[i] &= ~kDisplacementMask;
2813  }
2814 
2815  if (flag>40)
2816  obj.fDisplacement = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kInt);
2817  }
2818 
2819  if ((flag === 1) || (flag > 10)) {
2820  // here is reading of raw data
2821  var sz = (ver.val <= 1) ? buf.ntoi4() : obj.fLast;
2822 
2823  if (sz > obj.fKeylen) {
2824  // buffer includes again complete TKey data - exclude it
2825  var blob = buf.extract([buf.o + obj.fKeylen, sz - obj.fKeylen]);
2826 
2827  obj.fBufferRef = JSROOT.CreateTBuffer(blob, 0, buf.fFile, sz - obj.fKeylen);
2828  obj.fBufferRef.fTagOffset = obj.fKeylen;
2829  }
2830 
2831  buf.shift(sz);
2832  }
2833  }
2834 
2835  ds['TRef'] = function(buf,obj) {
2836  buf.ClassStreamer(obj, "TObject");
2837  if (obj.fBits & JSROOT.IO.kHasUUID)
2838  obj.fUUID = buf.ReadTString();
2839  else
2840  obj.fPID = buf.ntou2();
2841  }
2842 
2843  ds['TMatrixTSym<float>'] = function(buf,obj) {
2844  buf.ClassStreamer(obj, "TMatrixTBase<float>");
2845  obj.fElements = new Float32Array(obj.fNelems);
2846  var arr = buf.ReadFastArray((obj.fNrows * (obj.fNcols + 1))/2, JSROOT.IO.kFloat), cnt = 0;
2847  for (var i=0;i<obj.fNrows;++i)
2848  for (var j=i;j<obj.fNcols;++j)
2849  obj.fElements[j*obj.fNcols+i] = obj.fElements[i*obj.fNcols+j] = arr[cnt++];
2850  }
2851 
2852  ds['TMatrixTSym<double>'] = function(buf,obj) {
2853  buf.ClassStreamer(obj, "TMatrixTBase<double>");
2854  obj.fElements = new Float64Array(obj.fNelems);
2855  var arr = buf.ReadFastArray((obj.fNrows * (obj.fNcols + 1))/2, JSROOT.IO.kDouble), cnt = 0;
2856  for (var i=0;i<obj.fNrows;++i)
2857  for (var j=i;j<obj.fNcols;++j)
2858  obj.fElements[j*obj.fNcols+i] = obj.fElements[i*obj.fNcols+j] = arr[cnt++];
2859  }
2860 
2861  }
2862 
2863  JSROOT.IO.CreateStreamerElement = function(name, typename, file) {
2864  // return function, which could be used for element of the map
2865 
2866  var elem = { _typename: 'TStreamerElement', fName: name, fTypeName: typename,
2867  fType: 0, fSize: 0, fArrayLength: 0, fArrayDim: 0, fMaxIndex: [0,0,0,0,0],
2868  fXmin: 0, fXmax: 0, fFactor: 0 };
2869 
2870  if (typeof typename === "string") {
2871  elem.fType = JSROOT.IO.GetTypeId(typename);
2872  if ((elem.fType<0) && file && file.fBasicTypes[typename])
2873  elem.fType = file.fBasicTypes[typename];
2874  } else {
2875  elem.fType = typename;
2876  typename = elem.fTypeName = JSROOT.IO.TypeNames[elem.fType] || "int";
2877  }
2878 
2879  if (elem.fType > 0) return elem; // basic type
2880 
2881  // check if there are STL containers
2882  var stltype = JSROOT.IO.kNotSTL, pos = typename.indexOf("<");
2883  if ((pos>0) && (typename.indexOf(">") > pos+2))
2884  for (var stl=1;stl<JSROOT.IO.StlNames.length;++stl)
2885  if (typename.substr(0, pos) === JSROOT.IO.StlNames[stl]) {
2886  stltype = stl; break;
2887  }
2888 
2889  if (stltype !== JSROOT.IO.kNotSTL) {
2890  elem._typename = 'TStreamerSTL';
2891  elem.fType = JSROOT.IO.kStreamer;
2892  elem.fSTLtype = stltype;
2893  elem.fCtype = 0;
2894  return elem;
2895  }
2896 
2897  var isptr = false;
2898 
2899  if (typename.lastIndexOf("*") === typename.length-1) {
2900  isptr = true;
2901  elem.fTypeName = typename = typename.substr(0,typename.length-1);
2902  }
2903 
2904  var arrkind = JSROOT.IO.GetArrayKind(typename);
2905 
2906  if (arrkind == 0) {
2907  elem.fType = JSROOT.IO.kTString;
2908  return elem;
2909  }
2910 
2911  elem.fType = isptr ? JSROOT.IO.kAnyP : JSROOT.IO.kAny;
2912 
2913  return elem;
2914  }
2915 
2916  JSROOT.IO.ReadVectorElement = function(buf) {
2917 
2918  if (this.member_wise) {
2919 
2920  var n = buf.ntou4(), streamer = null, ver = this.stl_version;
2921 
2922  if (n===0) return []; // for empty vector no need to search split streamers
2923 
2924  if (n > 1000000) {
2925  throw new Error('member-wise streaming of ' + this.conttype + " num " + n + ' member ' + this.name);
2926  // return [];
2927  }
2928 
2929  if ((ver.val === this.member_ver) && (ver.checksum === this.member_checksum)) {
2930  streamer = this.member_streamer;
2931  } else {
2932  streamer = buf.fFile.GetStreamer(this.conttype, ver);
2933 
2934  this.member_streamer = streamer = buf.fFile.GetSplittedStreamer(streamer);
2935  this.member_ver = ver.val;
2936  this.member_checksum = ver.checksum;
2937  }
2938 
2939  var res = new Array(n), i, k, member;
2940 
2941  for (i=0;i<n;++i)
2942  res[i] = { _typename: this.conttype }; // create objects
2943  if (!streamer) {
2944  console.error('Fail to create split streamer for', this.conttype, 'need to read ', n, 'objects version', ver );
2945  } else {
2946  for (k=0;k<streamer.length;++k) {
2947  member = streamer[k];
2948  if (member.split_func) {
2949  member.split_func(buf, res, n);
2950  } else {
2951  for (i=0;i<n;++i)
2952  member.func(buf, res[i]);
2953  }
2954  }
2955  }
2956  return res;
2957  }
2958 
2959  var n = buf.ntou4(), res = new Array(n), i = 0;
2960 
2961  if (n>200000) { console.error('vector streaming for of', this.conttype, n); return res; }
2962 
2963  if (this.arrkind > 0) { while (i<n) res[i++] = buf.ReadFastArray(buf.ntou4(), this.arrkind); }
2964  else if (this.arrkind===0) { while (i<n) res[i++] = buf.ReadTString(); }
2965  else if (this.isptr) { while (i<n) res[i++] = buf.ReadObjectAny(); }
2966  else if (this.submember) { while (i<n) res[i++] = this.submember.readelem(buf); }
2967  else { while (i<n) res[i++] = buf.ClassStreamer({}, this.conttype); }
2968 
2969  return res;
2970  }
2971 
2972  JSROOT.IO.ReadMapElement = function(buf) {
2973  var streamer = this.streamer;
2974 
2975  if (this.member_wise) {
2976  // when member-wise streaming is used, version is written
2977  var ver = this.stl_version;
2978 
2979  if (this.si) {
2980  var si = buf.fFile.FindStreamerInfo(this.pairtype, ver.val, ver.checksum);
2981 
2982  if (this.si !== si) {
2983  streamer = JSROOT.IO.GetPairStreamer(si, this.pairtype, buf.fFile);
2984  if (!streamer || streamer.length!==2) {
2985  console.log('Fail to produce streamer for ', this.pairtype);
2986  return null;
2987  }
2988  }
2989  }
2990  }
2991 
2992  var i, n = buf.ntoi4(), res = new Array(n);
2993 
2994  for (i=0;i<n;++i) {
2995  res[i] = { _typename: this.pairtype };
2996  streamer[0].func(buf, res[i]);
2997  if (!this.member_wise) streamer[1].func(buf, res[i]);
2998  }
2999 
3000  // due-to member-wise streaming second element read after first is completed
3001  if (this.member_wise)
3002  for (i=0;i<n;++i) streamer[1].func(buf, res[i]);
3003 
3004  return res;
3005  }
3006 
3022  JSROOT.OpenFile = function(filename, callback) {
3023  if (JSROOT.nodejs) {
3024  if (filename.indexOf("file://")==0)
3025  return new TNodejsFile(filename.substr(7), callback);
3026 
3027  if (filename.indexOf("http")!==0)
3028  return new TNodejsFile(filename, callback);
3029  }
3030 
3031  if (typeof filename === 'object' && filename.size && filename.name)
3032  return new TLocalFile(filename, callback);
3033 
3034  return new TFile(filename, callback);
3035  }
3036 
3037  JSROOT.IO.NativeArray = JSROOT.nodejs || (window && ('Float64Array' in window));
3038 
3039  JSROOT.IO.ProduceCustomStreamers();
3040 
3041  JSROOT.TBuffer = TBuffer;
3042  JSROOT.TDirectory = TDirectory;
3043  JSROOT.TFile = TFile;
3044  JSROOT.TLocalFile = TLocalFile;
3045  JSROOT.TNodejsFile = TNodejsFile;
3046 
3047  return JSROOT;
3048 
3049 }));
3050 
3051 
3052 // JSRootIOEvolution.js ends
3053