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