00001
00002
00003
00004 (function( factory ) {
00005 if ( typeof define === "function" && define.amd ) {
00006
00007 define( ['JSRootCore', 'rawinflate'], factory );
00008 } else {
00009 if (typeof JSROOT == 'undefined')
00010 throw new Error("This extension requires JSRootCore.js", "JSRootIOEvolution.js");
00011
00012 if (typeof JSROOT.IO == "object")
00013 throw new Error("This JSROOT IO already loaded", "JSRootIOEvolution.js");
00014
00015 factory(JSROOT);
00016 }
00017 } (function(JSROOT) {
00018
00019 JSROOT.IO = {
00020 kBase : 0, kOffsetL : 20, kOffsetP : 40, kCounter : 6, kCharStar : 7,
00021 kChar : 1, kShort : 2, kInt : 3, kLong : 4, kFloat : 5,
00022 kDouble : 8, kDouble32 : 9, kLegacyChar : 10, kUChar : 11, kUShort : 12,
00023 kUInt : 13, kULong : 14, kBits : 15, kLong64 : 16, kULong64 : 17, kBool : 18,
00024 kFloat16 : 19,
00025 kObject : 61, kAny : 62, kObjectp : 63, kObjectP : 64, kTString : 65,
00026 kTObject : 66, kTNamed : 67, kAnyp : 68, kAnyP : 69, kAnyPnoVT : 70,
00027 kSTLp : 71,
00028 kSkip : 100, kSkipL : 120, kSkipP : 140,
00029 kConv : 200, kConvL : 220, kConvP : 240,
00030 kSTL : 300, kSTLstring : 365,
00031 kStreamer : 500, kStreamLoop : 501,
00032 kMapOffset : 2,
00033 kByteCountMask : 0x40000000,
00034 kNewClassTag : 0xFFFFFFFF,
00035 kClassMask : 0x80000000,
00036 Z_DEFLATED : 8,
00037 Z_HDRSIZE : 9,
00038 Mode : "array",
00039 NativeArray : true
00040 };
00041
00042 JSROOT.fUserStreamers = null;
00043
00044 JSROOT.addUserStreamer = function(type, user_streamer) {
00045 if (JSROOT.fUserStreamers == null) JSROOT.fUserStreamers = {};
00046 JSROOT.fUserStreamers[type] = user_streamer;
00047 }
00048
00049 JSROOT.R__unzip = function(str, tgtsize, noalert) {
00050
00051
00052 var isarr = (typeof str != 'string') && ('byteLength' in str),
00053 totallen = isarr ? str.byteLength : str.length,
00054 curr = 0, fullres = 0, tgtbuf = null;
00055
00056 function getChar(o) {
00057 return isarr ? String.fromCharCode(str.getUint8(o)) : str.charAt(o);
00058 }
00059
00060 function getCode(o) {
00061 return isarr ? str.getUint8(o) : str.charCodeAt(o);
00062 }
00063
00064 while (fullres < tgtsize) {
00065
00066 if (curr + JSROOT.IO.Z_HDRSIZE >= totallen) {
00067 if (!noalert) alert("Error R__unzip: header size exceeds buffer size");
00068 return null;
00069 }
00070
00071
00072 if (!((getChar(curr) == 'Z' && getChar(curr+1) == 'L' && getCode(curr+2) == JSROOT.IO.Z_DEFLATED))) {
00073 if (!noalert) alert("R__unzip: Old zlib format is not supported!");
00074 return null;
00075 }
00076
00077 var srcsize = JSROOT.IO.Z_HDRSIZE +
00078 ((getCode(curr+3) & 0xff) | ((getCode(curr+4) & 0xff) << 8) | ((getCode(curr+5) & 0xff) << 16));
00079
00080 if (isarr) {
00081
00082 var uint8arr = new Uint8Array(str.buffer, str.byteOffset + curr + JSROOT.IO.Z_HDRSIZE + 2, str.byteLength - curr - JSROOT.IO.Z_HDRSIZE - 2);
00083
00084
00085 if (tgtbuf===null) tgtbuf = new ArrayBuffer(tgtsize);
00086
00087 var reslen = window.RawInflate.arr_inflate(uint8arr, new Uint8Array(tgtbuf, fullres));
00088 if (reslen<=0) break;
00089
00090 fullres += reslen;
00091 } else {
00092
00093 var unpacked = window.RawInflate.inflate(str.substr(JSROOT.IO.Z_HDRSIZE + 2 + curr, srcsize));
00094 if ((unpacked === null) || (unpacked.length===0)) break;
00095 if (tgtbuf===null) tgtbuf = unpacked; else tgtbuf += unpacked;
00096 fullres += unpacked.length;
00097 }
00098
00099 curr += srcsize;
00100 }
00101
00102 if (fullres !== tgtsize) {
00103 if (!noalert) alert("R__unzip: fail to unzip data expacts " + tgtsize + " , got " + fullres);
00104 return null;
00105 }
00106
00107 return isarr ? new DataView(tgtbuf) : tgtbuf;
00108 }
00109
00110
00111
00112 JSROOT.TBuffer = function(_o, _file) {
00113 this._typename = "TBuffer";
00114 this.o = (_o==null) ? 0 : _o;
00115 this.fFile = _file;
00116 this.ClearObjectMap();
00117 this.fTagOffset = 0;
00118 this.last_read_version = 0;
00119 return this;
00120 }
00121
00122 JSROOT.TBuffer.prototype.locate = function(pos) {
00123 this.o = pos;
00124 }
00125
00126 JSROOT.TBuffer.prototype.shift = function(cnt) {
00127 this.o += cnt;
00128 }
00129
00130 JSROOT.TBuffer.prototype.GetMappedObject = function(tag) {
00131 return this.fObjectMap[tag];
00132 }
00133
00134 JSROOT.TBuffer.prototype.MapObject = function(tag, obj) {
00135 if (obj!==null)
00136 this.fObjectMap[tag] = obj;
00137 }
00138
00139 JSROOT.TBuffer.prototype.MapClass = function(tag, classname) {
00140 this.fClassMap[tag] = classname;
00141 }
00142
00143 JSROOT.TBuffer.prototype.GetMappedClass = function(tag) {
00144 if (tag in this.fClassMap) return this.fClassMap[tag];
00145 return -1;
00146 }
00147
00148 JSROOT.TBuffer.prototype.ClearObjectMap = function() {
00149 this.fObjectMap = {};
00150 this.fClassMap = {};
00151 this.fObjectMap[0] = null;
00152 }
00153
00154 JSROOT.TBuffer.prototype.ReadVersion = function() {
00155
00156 var ver = {};
00157 var bytecnt = this.ntou4();
00158 if (bytecnt & JSROOT.IO.kByteCountMask)
00159 ver.bytecnt = bytecnt - JSROOT.IO.kByteCountMask - 2;
00160 else
00161 this.o -= 4;
00162
00163 this.last_read_version = ver.val = this.ntou2();
00164 ver.off = this.o;
00165 return ver;
00166 }
00167
00168 JSROOT.TBuffer.prototype.CheckBytecount = function(ver, where) {
00169 if (('bytecnt' in ver) && (ver.off + ver.bytecnt !== this.o)) {
00170 if (where!=null)
00171 alert("Missmatch in " + where + " bytecount expected = " + ver['bytecnt'] + " got = " + (this.o-ver['off']));
00172 this.o = ver.off + ver.bytecnt;
00173 return false;
00174 }
00175 return true;
00176 }
00177
00178 JSROOT.TBuffer.prototype.ReadString = function() {
00179
00180 var pos0 = this.o, len = this.totalLength();
00181 while (this.o < len) {
00182 if (this.codeAt(this.o++) == 0) break;
00183 }
00184 return (this.o > pos0) ? this.substring(pos0, this.o-1) : "";
00185 }
00186
00187 JSROOT.TBuffer.prototype.ReadTString = function() {
00188
00189 var len = this.ntou1();
00190
00191 if (len == 255) len = this.ntou4();
00192 if (len==0) return "";
00193
00194 var pos = this.o;
00195 this.o += len;
00196
00197 return (this.codeAt(pos) == 0) ? '' : this.substring(pos, pos + len);
00198 }
00199
00200 JSROOT.TBuffer.prototype.ReadFastArray = function(n, array_type) {
00201
00202
00203 var array = null;
00204 switch (array_type) {
00205 case JSROOT.IO.kDouble:
00206 array = JSROOT.IO.NativeArray ? new Float64Array(n) : new Array(n);
00207 for (var i = 0; i < n; ++i)
00208 array[i] = this.ntod();
00209 break;
00210 case JSROOT.IO.kFloat:
00211 case JSROOT.IO.kDouble32:
00212 array = JSROOT.IO.NativeArray ? new Float32Array(n) : new Array(n);
00213 for (var i = 0; i < n; ++i)
00214 array[i] = this.ntof();
00215 break;
00216 case JSROOT.IO.kLong:
00217 case JSROOT.IO.kLong64:
00218 array = JSROOT.IO.NativeArray ? new Float64Array(n) : new Array(n);
00219 for (var i = 0; i < n; ++i)
00220 array[i] = this.ntoi8();
00221 break;
00222 case JSROOT.IO.kULong:
00223 case JSROOT.IO.kULong64:
00224 array = JSROOT.IO.NativeArray ? new Float64Array(n) : new Array(n);
00225 for (var i = 0; i < n; ++i)
00226 array[i] = this.ntou8();
00227 break;
00228 case JSROOT.IO.kInt:
00229 array = JSROOT.IO.NativeArray ? new Int32Array(n) : new Array(n);
00230 for (var i = 0; i < n; ++i)
00231 array[i] = this.ntoi4();
00232 break;
00233 case JSROOT.IO.kUInt:
00234 array = JSROOT.IO.NativeArray ? new Uint32Array(n) : new Array(n);
00235 for (var i = 0; i < n; ++i)
00236 array[i] = this.ntou4();
00237 break;
00238 case JSROOT.IO.kShort:
00239 array = JSROOT.IO.NativeArray ? new Int16Array(n) : new Array(n);
00240 for (var i = 0; i < n; ++i)
00241 array[i] = this.ntoi2();
00242 break;
00243 case JSROOT.IO.kUShort:
00244 array = JSROOT.IO.NativeArray ? new Uint16Array(n) : new Array(n);
00245 for (var i = 0; i < n; ++i)
00246 array[i] = this.ntou2();
00247 break;
00248 case JSROOT.IO.kChar:
00249 array = JSROOT.IO.NativeArray ? new Int8Array(n) : new Array(n);
00250 for (var i = 0; i < n; ++i)
00251 array[i] = this.ntoi1();
00252 break;
00253 case JSROOT.IO.kUChar:
00254 array = JSROOT.IO.NativeArray ? new Uint8Array(n) : new Array(n);
00255 for (var i = 0; i < n; ++i)
00256 array[i] = this.ntoi1();
00257 break;
00258 case JSROOT.IO.kTString:
00259 array = new Array(n);
00260 for (var i = 0; i < n; ++i)
00261 array[i] = this.ReadTString();
00262 break;
00263 default:
00264 array = new Array(n);
00265 for (var i = 0; i < n; ++i)
00266 array[i] = this.ntou4();
00267 break;
00268 }
00269 return array;
00270 }
00271
00272 JSROOT.IO.GetArrayKind = function(type_name) {
00273 if (type_name.length < 7) return -1;
00274 if (type_name.indexOf("TArray")!=0) return -1;
00275 if (type_name.length == 7)
00276 switch (type_name.charAt(6)) {
00277 case 'I': return JSROOT.IO.kInt;
00278 case 'D': return JSROOT.IO.kDouble;
00279 case 'F': return JSROOT.IO.kFloat;
00280 case 'S': return JSROOT.IO.kShort;
00281 case 'C': return JSROOT.IO.kChar;
00282 case 'L': return JSROOT.IO.kLong;
00283 default: return -1;
00284 }
00285
00286 return type_name == "TArrayL64" ? JSROOT.IO.kLong64 : -1;
00287 }
00288
00289 JSROOT.TBuffer.prototype.ReadTKey = function(key) {
00290 key.fNbytes = this.ntoi4();
00291 key.fVersion = this.ntoi2();
00292 key.fObjlen = this.ntou4();
00293 var datime = this.ntou4();
00294 key.fDatime = new Date();
00295 key.fDatime.setFullYear((datime >>> 26) + 1995);
00296 key.fDatime.setMonth((datime << 6) >>> 28);
00297 key.fDatime.setDate((datime << 10) >>> 27);
00298 key.fDatime.setHours((datime << 15) >>> 27);
00299 key.fDatime.setMinutes((datime << 20) >>> 26);
00300 key.fDatime.setSeconds((datime << 26) >>> 26);
00301 key.fDatime.setMilliseconds(0);
00302 key.fKeylen = this.ntou2();
00303 key.fCycle = this.ntou2();
00304 if (key.fVersion > 1000) {
00305 key.fSeekKey = this.ntou8();
00306 this.shift(8);
00307 } else {
00308 key.fSeekKey = this.ntou4();
00309 this.shift(4);
00310 }
00311 key.fClassName = this.ReadTString();
00312 key.fName = this.ReadTString();
00313 key.fTitle = this.ReadTString();
00314
00315 var name = key.fName.replace(/['"]/g,'');
00316
00317 if (name !== key.fName) {
00318 key.fRealName = key.fName;
00319 key.fName = name;
00320 }
00321
00322 return true;
00323 }
00324
00325 JSROOT.TBuffer.prototype.ReadTBasket = function(obj) {
00326 this.ReadTKey(obj);
00327 var ver = this.ReadVersion();
00328 obj.fBufferSize = this.ntoi4();
00329 obj.fNevBufSize = this.ntoi4();
00330 obj.fNevBuf = this.ntoi4();
00331 obj.fLast = this.ntoi4();
00332 var flag = this.ntoi1();
00333 // here we implement only data skipping, no real I/O for TBasket is performed
00334 if ((flag % 10) != 2) {
00335 var sz = this.ntoi4(); this.shift(sz*4); // fEntryOffset
00336 if (flag>40) { sz = this.ntoi4(); this.shift(sz*4); } // fDisplacement
00337 }
00338
00339 if (flag == 1 || flag > 10) {
00340 var sz = obj.fLast;
00341 if (ver.val <= 1) sz = this.ntoi4();
00342 this.o += sz; // fBufferRef
00343 }
00344 return this.CheckBytecount(ver,"ReadTBasket");
00345 }
00346
00347 JSROOT.TBuffer.prototype.ReadClass = function() {
00348 // read class definition from I/O buffer
00349 var classInfo = { name: -1 };
00350 var tag = 0;
00351 var bcnt = this.ntou4();
00352
00353 var startpos = this.o;
00354 if (!(bcnt & JSROOT.IO.kByteCountMask) || (bcnt == JSROOT.IO.kNewClassTag)) {
00355 tag = bcnt;
00356 bcnt = 0;
00357 } else {
00358 tag = this.ntou4();
00359 }
00360 if (!(tag & JSROOT.IO.kClassMask)) {
00361 classInfo.objtag = tag; // indicate that we have deal with objects tag
00362 return classInfo;
00363 }
00364 if (tag == JSROOT.IO.kNewClassTag) {
00365 // got a new class description followed by a new object
00366 classInfo.name = this.ReadString();
00367
00368 if (this.GetMappedClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset) === -1)
00369 this.MapClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset, classInfo.name);
00370 }
00371 else {
00372 // got a tag to an already seen class
00373 var clTag = (tag & ~JSROOT.IO.kClassMask);
00374 classInfo.name = this.GetMappedClass(clTag);
00375
00376 if (classInfo.name === -1) {
00377 alert("Did not found class with tag " + clTag);
00378 }
00379
00380 }
00381
00382 return classInfo;
00383 }
00384
00385 JSROOT.TBuffer.prototype.ReadObjectAny = function() {
00386 var objtag = this.fTagOffset + this.o + JSROOT.IO.kMapOffset;
00387
00388 var clRef = this.ReadClass();
00389
00390 // class identified as object and should be handled so
00391 if ('objtag' in clRef)
00392 return this.GetMappedObject(clRef.objtag);
00393
00394 if (clRef.name === -1) return null;
00395
00396 var arrkind = JSROOT.IO.GetArrayKind(clRef.name);
00397
00398 var obj = {};
00399
00400 if (arrkind > 0) {
00401 // reading array, can map array only afterwards
00402 obj = this.ReadFastArray(this.ntou4(), arrkind);
00403 this.MapObject(objtag, obj);
00404 } else {
00405 // reading normal object, should map before to
00406 this.MapObject(objtag, obj);
00407 this.ClassStreamer(obj, clRef.name);
00408 }
00409
00410 return obj;
00411 }
00412
00413 JSROOT.TBuffer.prototype.ClassStreamer = function(obj, classname) {
00414
00415 if (! ('_typename' in obj)) obj._typename = classname;
00416
00417 var streamer = this.fFile.GetStreamer(classname);
00418
00419 if (streamer !== null) {
00420 var ver = this.ReadVersion();
00421
00422 for (var n = 0; n < streamer.length; ++n)
00423 streamer[n].func(this, obj);
00424
00425 this.CheckBytecount(ver, classname);
00426 // methods will be assigned by last entry in the streamer
00427 }
00428 else if (classname == 'TQObject') {
00429 // skip TQObject
00430 }
00431 else if (classname == "TBasket") {
00432 this.ReadTBasket(obj);
00433 JSROOT.addMethods(obj);
00434 } else {
00435 // just skip bytes belonging to not-recognized object
00436 var ver = this.ReadVersion();
00437 this.CheckBytecount(ver);
00438 JSROOT.addMethods(obj);
00439 }
00440
00441
00442 return obj;
00443 }
00444
00445 // =================================================================================
00446
00447 JSROOT.TStrBuffer = function(str, pos, file) {
00448 JSROOT.TBuffer.call(this, pos, file);
00449 this.b = str;
00450 }
00451
00452 JSROOT.TStrBuffer.prototype = Object.create(JSROOT.TBuffer.prototype);
00453
00454 JSROOT.TStrBuffer.prototype.totalLength = function() {
00455 return this.b ? this.b.length : 0;
00456 }
00457
00458 JSROOT.TStrBuffer.prototype.extract = function(off,len) {
00459 return this.b.substr(off, len);
00460 }
00461
00462 JSROOT.TStrBuffer.prototype.ntou1 = function() {
00463 return (this.b.charCodeAt(this.o++) & 0xff) >>> 0;
00464 }
00465
00466 JSROOT.TStrBuffer.prototype.ntou2 = function() {
00467 // convert (read) two bytes of buffer b into a UShort_t
00468 var n = ((this.b.charCodeAt(this.o++) & 0xff) << 8) >>> 0;
00469 n += (this.b.charCodeAt(this.o++) & 0xff) >>> 0;
00470 return n;
00471 }
00472
00473 JSROOT.TStrBuffer.prototype.ntou4 = function() {
00474 // convert (read) four bytes of buffer b into a UInt_t
00475 var n = ((this.b.charCodeAt(this.o++) & 0xff) << 24) >>> 0;
00476 n += ((this.b.charCodeAt(this.o++) & 0xff) << 16) >>> 0;
00477 n += ((this.b.charCodeAt(this.o++) & 0xff) << 8) >>> 0;
00478 n += (this.b.charCodeAt(this.o++) & 0xff) >>> 0;
00479 return n;
00480 }
00481
00482 JSROOT.TStrBuffer.prototype.ntou8 = function() {
00483 // convert (read) eight bytes of buffer b into a ULong_t
00484 var n = ((this.b.charCodeAt(this.o++) & 0xff) << 56) >>> 0;
00485 n += ((this.b.charCodeAt(this.o++) & 0xff) << 48) >>> 0;
00486 n += ((this.b.charCodeAt(this.o++) & 0xff) << 40) >>> 0;
00487 n += ((this.b.charCodeAt(this.o++) & 0xff) << 32) >>> 0;
00488 n += ((this.b.charCodeAt(this.o++) & 0xff) << 24) >>> 0;
00489 n += ((this.b.charCodeAt(this.o++) & 0xff) << 16) >>> 0;
00490 n += ((this.b.charCodeAt(this.o++) & 0xff) << 8) >>> 0;
00491 n += (this.b.charCodeAt(this.o++) & 0xff) >>> 0;
00492 return n;
00493 }
00494
00495 JSROOT.TStrBuffer.prototype.ntoi1 = function() {
00496 return (this.b.charCodeAt(this.o++) & 0xff);
00497 }
00498
00499 JSROOT.TStrBuffer.prototype.ntoi2 = function() {
00500 // convert (read) two bytes of buffer b into a Short_t
00501 var n = ((this.b.charCodeAt(this.o++) & 0xff) << 8);
00502 n += ((this.b.charCodeAt(this.o++) & 0xff));
00503 return (n < 0x8000) ? n : -1 - (~n &0xFFFF);
00504 }
00505
00506 JSROOT.TStrBuffer.prototype.ntoi4 = function() {
00507 // convert (read) four bytes of buffer b into a Int_t
00508 var n = ((this.b.charCodeAt(this.o++) & 0xff) << 24);
00509 n += ((this.b.charCodeAt(this.o++) & 0xff) << 16);
00510 n += ((this.b.charCodeAt(this.o++) & 0xff) << 8);
00511 n += ((this.b.charCodeAt(this.o++) & 0xff));
00512 return n;
00513 }
00514
00515 JSROOT.TStrBuffer.prototype.ntoi8 = function(b, o) {
00516 // convert (read) eight bytes of buffer b into a Long_t
00517 var n = (this.b.charCodeAt(this.o++) & 0xff) << 56;
00518 n += (this.b.charCodeAt(this.o++) & 0xff) << 48;
00519 n += (this.b.charCodeAt(this.o++) & 0xff) << 40;
00520 n += (this.b.charCodeAt(this.o++) & 0xff) << 32;
00521 n += (this.b.charCodeAt(this.o++) & 0xff) << 24;
00522 n += (this.b.charCodeAt(this.o++) & 0xff) << 16;
00523 n += (this.b.charCodeAt(this.o++) & 0xff) << 8;
00524 n += (this.b.charCodeAt(this.o++) & 0xff);
00525 return n;
00526 }
00527
00528 JSROOT.TStrBuffer.prototype.ntof = function() {
00529 // IEEE-754 Floating-Point Conversion (single precision - 32 bits)
00530 var inString = this.b.substring(this.o, this.o + 4); this.o+=4;
00531 if (inString.length < 4) return Number.NaN;
00532 var bits = "";
00533 for (var i=0; i<4; ++i) {
00534 var curByte = (inString.charCodeAt(i) & 0xff).toString(2);
00535 var byteLen = curByte.length;
00536 if (byteLen < 8) {
00537 for (var bit=0; bit<(8-byteLen); ++bit)
00538 curByte = '0' + curByte;
00539 }
00540 bits = bits + curByte;
00541 }
00542 //var bsign = parseInt(bits[0]) ? -1 : 1;
00543 var bsign = (bits.charAt(0) == '1') ? -1 : 1;
00544 var bexp = parseInt(bits.substring(1, 9), 2) - 127;
00545 var bman;
00546 if (bexp == -127)
00547 bman = 0;
00548 else {
00549 bman = 1;
00550 for (var i=0; i<23; ++i) {
00551 if (parseInt(bits.substr(9+i, 1)) == 1)
00552 bman = bman + 1 / Math.pow(2, i+1);
00553 }
00554 }
00555 var res = bsign * Math.pow(2, bexp) * bman;
00556 return (Math.abs(res) < 1e-300) ? 0.0 : res;
00557 }
00558
00559 JSROOT.TStrBuffer.prototype.ntod = function() {
00560 // IEEE-754 Floating-Point Conversion (double precision - 64 bits)
00561 var inString = this.b.substring(this.o, this.o + 8); this.o+=8;
00562 if (inString.length < 8) return Number.NaN;
00563 var bits = "";
00564 for (var i=0; i<8; ++i) {
00565 var curByte = (inString.charCodeAt(i) & 0xff).toString(2);
00566 var byteLen = curByte.length;
00567 if (byteLen < 8) {
00568 for (var bit=0; bit<(8-byteLen); ++bit)
00569 curByte = '0' + curByte;
00570 }
00571 bits = bits + curByte;
00572 }
00573 //var bsign = parseInt(bits[0]) ? -1 : 1;
00574 var bsign = (bits.charAt(0) == '1') ? -1 : 1;
00575 var bexp = parseInt(bits.substring(1, 12), 2) - 1023;
00576 var bman;
00577 if (bexp == -127)
00578 bman = 0;
00579 else {
00580 bman = 1;
00581 for (var i=0; i<52; ++i) {
00582 if (parseInt(bits.substr(12+i, 1)) == 1)
00583 bman = bman + 1 / Math.pow(2, i+1);
00584 }
00585 }
00586 var res = (bsign * Math.pow(2, bexp) * bman);
00587 return (Math.abs(res) < 1e-300) ? 0.0 : res;
00588 }
00589
00590 JSROOT.TStrBuffer.prototype.codeAt = function(pos) {
00591 return this.b.charCodeAt(pos) & 0xff;
00592 }
00593
00594 JSROOT.TStrBuffer.prototype.substring = function(beg, end) {
00595 return this.b.substring(beg, end);
00596 }
00597
00598 // =======================================================================
00599
00600 JSROOT.TArrBuffer = function(arr, pos, file) {
00601 // buffer should work with DataView as first argument
00602 JSROOT.TBuffer.call(this, pos, file);
00603 this.arr = arr;
00604 }
00605
00606 JSROOT.TArrBuffer.prototype = Object.create(JSROOT.TBuffer.prototype);
00607
00608 JSROOT.TArrBuffer.prototype.totalLength = function() {
00609 return this.arr && this.arr.buffer ? this.arr.buffer.byteLength : 0;
00610 }
00611
00612 JSROOT.TArrBuffer.prototype.extract = function(off,len) {
00613 if (!this.arr || !this.arr.buffer || (this.arr.buffer.byteLength < off+len)) return null;
00614 return new DataView(this.arr.buffer, off, len);
00615 }
00616
00617 JSROOT.TArrBuffer.prototype.codeAt = function(pos) {
00618 return this.arr.getUint8(pos);
00619 }
00620
00621 JSROOT.TArrBuffer.prototype.substring = function(beg, end) {
00622 var res = "";
00623 for (var n=beg;n<end;++n)
00624 res += String.fromCharCode(this.arr.getUint8(n));
00625 return res;
00626 }
00627
00628 JSROOT.TArrBuffer.prototype.ntou1 = function() {
00629 return this.arr.getUint8(this.o++);
00630 }
00631
00632 JSROOT.TArrBuffer.prototype.ntou2 = function() {
00633 var o = this.o; this.o+=2;
00634 return this.arr.getUint16(o);
00635 }
00636
00637 JSROOT.TArrBuffer.prototype.ntou4 = function() {
00638 var o = this.o; this.o+=4;
00639 return this.arr.getUint32(o);
00640 }
00641
00642 JSROOT.TArrBuffer.prototype.ntou8 = function() {
00643 var high = this.arr.getUint32(this.o); this.o+=4;
00644 var low = this.arr.getUint32(this.o); this.o+=4;
00645 return high * 0x100000000 + low;
00646 }
00647
00648 JSROOT.TArrBuffer.prototype.ntoi1 = function() {
00649 return this.arr.getInt8(this.o++);
00650 }
00651
00652 JSROOT.TArrBuffer.prototype.ntoi2 = function() {
00653 var o = this.o; this.o+=2;
00654 return this.arr.getInt16(o);
00655 }
00656
00657 JSROOT.TArrBuffer.prototype.ntoi4 = function() {
00658 var o = this.o; this.o+=4;
00659 return this.arr.getInt32(o);
00660 }
00661
00662 JSROOT.TArrBuffer.prototype.ntoi8 = function() {
00663 var high = this.arr.getUint32(this.o); this.o+=4;
00664 var low = this.arr.getUint32(this.o); this.o+=4;
00665 if (high < 0x80000000) return high * 0x100000000 + low;
00666 return -1 - ((~high) * 0x100000000 + ~low);
00667 }
00668
00669 JSROOT.TArrBuffer.prototype.ntof = function() {
00670 var o = this.o; this.o+=4;
00671 return this.arr.getFloat32(o);
00672 }
00673
00674 JSROOT.TArrBuffer.prototype.ntod = function() {
00675 var o = this.o; this.o+=8;
00676 return this.arr.getFloat64(o);
00677 }
00678
00679 // =======================================================================
00680
00681 JSROOT.CreateTBuffer = function(blob, pos, file) {
00682 if ((blob==null) || (typeof(blob) == 'string'))
00683 return new JSROOT.TStrBuffer(blob, pos, file);
00684
00685 return new JSROOT.TArrBuffer(blob, pos, file);
00686 }
00687
00688 JSROOT.ReconstructObject = function(class_name, obj_rawdata, sinfo_rawdata) {
00689 // method can be used to reconstruct ROOT object from binary buffer
00690 // Buffer can be requested from online server with request like:
00691 // http://localhost:8080/Files/job1.root/hpx/root.bin
00692 // One also requires buffer with streamer infos, reqeusted with command
00693 // http://localhost:8080/StreamerInfo/root.bin
00694 // And one should provide class name of the object
00695 //
00696 // Method provided for convenience only to see how binary JSROOT.IO works.
00697 // It is strongly recommended to use JSON representation:
00698 // http://localhost:8080/Files/job1.root/hpx/root.json
00699
00700 var file = new JSROOT.TFile;
00701 var buf = JSROOT.CreateTBuffer(sinfo_rawdata, 0, file);
00702 file.ExtractStreamerInfos(buf);
00703
00704 var obj = {};
00705
00706 buf = JSROOT.CreateTBuffer(obj_rawdata, 0, file);
00707 buf.MapObject(obj, 1);
00708 buf.ClassStreamer(obj, class_name);
00709
00710 return obj;
00711 }
00712
00713 // ==============================================================================
00714
00715 // A class that reads a TDirectory from a buffer.
00716
00717 // ctor
00718 JSROOT.TDirectory = function(file, dirname, cycle) {
00719 if (! (this instanceof arguments.callee) )
00720 throw new Error("you must use new to instantiate this class", "JSROOT.TDirectory.ctor");
00721
00722 this.fFile = file;
00723 this._typename = "TDirectory";
00724 this.dir_name = dirname;
00725 this.dir_cycle = cycle;
00726 this.fKeys = new Array();
00727 return this;
00728 }
00729
00730 JSROOT.TDirectory.prototype.GetKey = function(keyname, cycle, call_back) {
00731 // retrieve a key by its name and cycle in the list of keys
00732 for (var i=0; i < this.fKeys.length; ++i) {
00733 if (this.fKeys[i].fName == keyname && this.fKeys[i].fCycle == cycle) {
00734 JSROOT.CallBack(call_back, this.fKeys[i]);
00735 return this.fKeys[i];
00736 }
00737 }
00738
00739 var pos = keyname.lastIndexOf("/");
00740 // try to handle situation when object name contains slashed (bad practice anyway)
00741 while (pos > 0) {
00742 var dirname = keyname.substr(0, pos);
00743 var subname = keyname.substr(pos+1);
00744
00745 var dirkey = this.GetKey(dirname, 1);
00746 if ((dirkey!==null) && (typeof call_back == 'function') &&
00747 (dirkey.fClassName.indexOf("TDirectory")==0)) {
00748
00749 this.fFile.ReadObject(this.dir_name + "/" + dirname, 1, function(newdir) {
00750 if (newdir) newdir.GetKey(subname, cycle, call_back);
00751 });
00752 return null;
00753 }
00754
00755 pos = keyname.lastIndexOf("/", pos-1);
00756 }
00757
00758
00759 JSROOT.CallBack(call_back, null);
00760 return null;
00761 }
00762
00763 JSROOT.TDirectory.prototype.ReadKeys = function(readkeys_callback) {
00764 var thisdir = this;
00765 var file = this.fFile;
00766
00767 //*-*-------------Read directory info
00768 var nbytes = this.fNbytesName + 22;
00769 nbytes += 4; // fDatimeC.Sizeof();
00770 nbytes += 4; // fDatimeM.Sizeof();
00771 nbytes += 18; // fUUID.Sizeof();
00772 // assume that the file may be above 2 Gbytes if file version is > 4
00773 if (file.fVersion >= 40000) nbytes += 12;
00774
00775 file.Seek(this.fSeekDir, this.fFile.ERelativeTo.kBeg);
00776 file.ReadBuffer(nbytes, function(blob1) {
00777 if (blob1==null) return JSROOT.CallBack(readkeys_callback,null);
00778 var buf = JSROOT.CreateTBuffer(blob1, thisdir.fNbytesName, file);
00779
00780 thisdir.StreamHeader(buf);
00781
00782 //*-*---------read TKey::FillBuffer info
00783 buf.locate(4); // Skip NBytes;
00784 var keyversion = buf.ntoi2();
00785 // Skip ObjLen, DateTime, KeyLen, Cycle, SeekKey, SeekPdir
00786 if (keyversion > 1000) buf.shift(28); // Large files
00787 else buf.shift(20);
00788 buf.ReadTString();
00789 buf.ReadTString();
00790 thisdir.fTitle = buf.ReadTString();
00791 if (thisdir.fNbytesName < 10 || thisdir.fNbytesName > 10000) {
00792 JSROOT.console("Cannot read directory info of file " + file.fURL);
00793 return JSROOT.CallBack(readkeys_callback, null);
00794 }
00795 //*-* -------------Read keys of the top directory
00796
00797 if (thisdir.fSeekKeys <=0)
00798 return JSROOT.CallBack(readkeys_callback, null);
00799
00800 file.Seek(thisdir.fSeekKeys, file.ERelativeTo.kBeg);
00801 file.ReadBuffer(thisdir.fNbytesKeys, function(blob2) {
00802 if (blob2 == null) return JSROOT.CallBack(readkeys_callback, null);
00803 var buf = JSROOT.CreateTBuffer(blob2, 0, file);
00804
00805 var key = file.ReadKey(buf);
00806
00807 var nkeys = buf.ntoi4();
00808 for (var i = 0; i < nkeys; ++i) {
00809 key = file.ReadKey(buf);
00810 thisdir.fKeys.push(key);
00811 }
00812 file.fDirectories.push(thisdir);
00813 delete buf;
00814
00815 JSROOT.CallBack(readkeys_callback, thisdir);
00816 });
00817
00818 delete buf;
00819 });
00820 }
00821
00822 JSROOT.TDirectory.prototype.StreamHeader = function(buf) {
00823 var version = buf.ntou2();
00824 var versiondir = version % 1000;
00825 buf.shift(8); // skip fDatimeC and fDatimeM
00826 this.fNbytesKeys = buf.ntou4();
00827 this.fNbytesName = buf.ntou4();
00828 this.fSeekDir = (version > 1000) ? buf.ntou8() : buf.ntou4();
00829 this.fSeekParent = (version > 1000) ? buf.ntou8() : buf.ntou4();
00830 this.fSeekKeys = (version > 1000) ? buf.ntou8() : buf.ntou4();
00831 if (versiondir > 2) buf.shift(18); // skip fUUID
00832 }
00833
00834
00835 // ==============================================================================
00836 // A class that reads ROOT files.
00837 //
00839 // A ROOT file is a suite of consecutive data records (TKey's) with
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861 JSROOT.TFile = function(url, newfile_callback) {
00862 if (! (this instanceof arguments.callee) )
00863 throw new Error("you must use new to instantiate this class", "JSROOT.TFile.ctor");
00864
00865 this._typename = "TFile";
00866 this.fOffset = 0;
00867 this.fEND = 0;
00868 this.fFullURL = url;
00869 this.fURL = url;
00870 this.fAcceptRanges = true;
00871 this.fUseStampPar = new Date;
00872 this.fFileContent = null;
00873
00874
00875 this.ERelativeTo = { kBeg : 0, kCur : 1, kEnd : 2 };
00876 this.fDirectories = new Array();
00877 this.fKeys = new Array();
00878 this.fSeekInfo = 0;
00879 this.fNbytesInfo = 0;
00880 this.fTagOffset = 0;
00881 this.fStreamers = 0;
00882 this.fStreamerInfos = null;
00883 this.fFileName = "";
00884 this.fStreamers = new Array;
00885
00886 if (typeof this.fURL != 'string') return this;
00887
00888 if (this.fURL.charAt(this.fURL.length-1) == "+") {
00889 this.fURL = this.fURL.substr(0, this.fURL.length-1);
00890 this.fAcceptRanges = false;
00891 }
00892
00893 var pos = Math.max(this.fURL.lastIndexOf("/"), this.fURL.lastIndexOf("\\"));
00894 this.fFileName = pos>=0 ? this.fURL.substr(pos+1) : this.fURL;
00895
00896 if (!this.fAcceptRanges) {
00897 this.ReadKeys(newfile_callback);
00898 } else {
00899 var file = this;
00900
00901 var xhr = JSROOT.NewHttpRequest(this.fURL, "head", function(res) {
00902 if (res==null)
00903 return JSROOT.CallBack(newfile_callback, null);
00904
00905 var accept_ranges = res.getResponseHeader("Accept-Ranges");
00906 if (accept_ranges==null) file.fAcceptRanges = false;
00907 var len = res.getResponseHeader("Content-Length");
00908 if (len!=null) file.fEND = parseInt(len);
00909 else file.fAcceptRanges = false;
00910 file.ReadKeys(newfile_callback);
00911 });
00912
00913 xhr.send(null);
00914 }
00915
00916 return this;
00917 }
00918
00919 JSROOT.TFile.prototype.ReadBuffer = function(len, callback) {
00920
00921 if ((this.fFileContent!=null) && (!this.fAcceptRanges || (this.fOffset+len <= this.fFileContent.totalLength())))
00922 return callback(this.fFileContent.extract(this.fOffset, len));
00923
00924 var file = this;
00925
00926 var url = this.fURL;
00927 if (this.fUseStampPar) {
00928
00929 if (url.indexOf('?')>0) url+="&stamp="; else url += "?stamp=";
00930 url += this.fUseStampPar.getTime();
00931 }
00932
00933 function read_callback(res) {
00934
00935 if ((res==null) && file.fUseStampPar && (file.fOffset==0)) {
00936
00937 file.fUseStampPar = false;
00938 var xhr2 = JSROOT.NewHttpRequest(this.fURL, ((JSROOT.IO.Mode == "array") ? "buf" : "bin"), read_callback);
00939 if (this.fAcceptRanges)
00940 xhr2.setRequestHeader("Range", "bytes=" + this.fOffset + "-" + (this.fOffset + len - 1));
00941 xhr2.send(null);
00942 return;
00943 } else
00944 if ((res!=null) && (file.fOffset==0) && (file.fFileContent == null)) {
00945
00946
00947 file.fFileContent = JSROOT.CreateTBuffer((typeof res == 'string') ? res : new DataView(res));
00948
00949 if (!this.fAcceptRanges)
00950 file.fEND = file.fFileContent.totalLength();
00951
00952 return callback(file.fFileContent.extract(file.fOffset, len));
00953 }
00954
00955 if ((res==null) || (res === undefined) || (typeof res == 'string'))
00956 return callback(res);
00957
00958
00959 callback(new DataView(res));
00960 }
00961
00962 var xhr = JSROOT.NewHttpRequest(url, ((JSROOT.IO.Mode == "array") ? "buf" : "bin"), read_callback);
00963 if (this.fAcceptRanges)
00964 xhr.setRequestHeader("Range", "bytes=" + this.fOffset + "-" + (this.fOffset + len - 1));
00965 xhr.send(null);
00966 }
00967
00968 JSROOT.TFile.prototype.Seek = function(offset, pos) {
00969
00970 switch (pos) {
00971 case this.ERelativeTo.kBeg:
00972 this.fOffset = offset;
00973 break;
00974 case this.ERelativeTo.kCur:
00975 this.fOffset += offset;
00976 break;
00977 case this.ERelativeTo.kEnd:
00978
00979 if (this.fEND == 0)
00980 throw new Error("Seek : seeking from end in file with fEND==0 is not supported");
00981 this.fOffset = this.fEND - offset;
00982 break;
00983 default:
00984 throw new Error("Seek : unknown seek option (" + pos + ")");
00985 break;
00986 }
00987 }
00988
00989 JSROOT.TFile.prototype.ReadKey = function(buf) {
00990
00991 var key = {};
00992 buf.ReadTKey(key);
00993 return key;
00994 }
00995
00996 JSROOT.TFile.prototype.GetDir = function(dirname, cycle) {
00997
00998
00999 if ((cycle==null) && (typeof dirname == 'string')) {
01000 var pos = dirname.lastIndexOf(';');
01001 if (pos>0) { cycle = dirname.substr(pos+1); dirname = dirname.substr(0,pos); }
01002 }
01003
01004 for (var j=0; j < this.fDirectories.length; ++j) {
01005 var dir = this.fDirectories[j];
01006 if (dir.dir_name != dirname) continue;
01007 if ((cycle !== undefined) && (dir.dir_cycle !== cycle)) continue;
01008 return dir;
01009 }
01010 return null;
01011 }
01012
01013 JSROOT.TFile.prototype.GetKey = function(keyname, cycle, getkey_callback) {
01014
01015
01016
01017 for (var i=0; i < this.fKeys.length; ++i) {
01018 if (this.fKeys[i].fName === keyname && this.fKeys[i].fCycle === cycle) {
01019 JSROOT.CallBack(getkey_callback, this.fKeys[i]);
01020 return this.fKeys[i];
01021 }
01022 }
01023
01024 var pos = keyname.lastIndexOf("/");
01025
01026 while (pos > 0) {
01027 var dirname = keyname.substr(0, pos);
01028 var subname = keyname.substr(pos+1);
01029
01030 var dir = this.GetDir(dirname);
01031 if (dir!=null) return dir.GetKey(subname, cycle, getkey_callback);
01032
01033 var dirkey = this.GetKey(dirname, 1);
01034 if ((dirkey !== null) && (getkey_callback != null) &&
01035 (dirkey.fClassName.indexOf("TDirectory")==0)) {
01036
01037 this.ReadObject(dirname, function(newdir) {
01038 if (newdir) newdir.GetKey(subname, cycle, getkey_callback);
01039 });
01040 return null;
01041 }
01042
01043 pos = keyname.lastIndexOf("/", pos-1);
01044 }
01045
01046 JSROOT.CallBack(getkey_callback, null);
01047 return null;
01048 }
01049
01050 JSROOT.TFile.prototype.ReadObjBuffer = function(key, callback) {
01051
01052
01053 var file = this;
01054
01055 this.Seek(key.fSeekKey + key.fKeylen, this.ERelativeTo.kBeg);
01056
01057 this.ReadBuffer(key.fNbytes - key.fKeylen, function(blob1) {
01058
01059 if (blob1==null) callback(null);
01060
01061 var buf = null;
01062
01063 if (key.fObjlen <= key.fNbytes - key.fKeylen) {
01064 buf = JSROOT.CreateTBuffer(blob1, 0, file);
01065 } else {
01066 var objbuf = JSROOT.R__unzip(blob1, key.fObjlen);
01067 if (objbuf==null) return callback(null);
01068 buf = JSROOT.CreateTBuffer(objbuf, 0, file);
01069 }
01070
01071 buf.fTagOffset = key.fKeylen;
01072
01073 callback(buf);
01074 });
01075 }
01076
01077 JSROOT.TFile.prototype.ReadObject = function(obj_name, cycle, user_call_back) {
01078
01079
01080
01081
01082 if (typeof cycle == 'function') { user_call_back = cycle; cycle = 1; }
01083
01084 var pos = obj_name.lastIndexOf(";");
01085 if (pos>0) {
01086 cycle = parseInt(obj_name.slice(pos+1));
01087 obj_name = obj_name.slice(0, pos);
01088 }
01089
01090 if ((typeof cycle != 'number') || (cycle<0)) cycle = 1;
01091
01092 while ((obj_name.length>0) && (obj_name[0] == "/")) obj_name = obj_name.substr(1);
01093
01094 var file = this;
01095
01096
01097
01098
01099 this.GetKey(obj_name, cycle, function(key) {
01100
01101 if (key == null)
01102 return JSROOT.CallBack(user_call_back, null);
01103
01104 if ((obj_name=="StreamerInfo") && (key.fClassName=="TList"))
01105 return file.fStreamerInfos;
01106
01107 var isdir = false;
01108 if ((key.fClassName == 'TDirectory' || key.fClassName == 'TDirectoryFile')) {
01109 isdir = true;
01110 var dir = file.GetDir(obj_name, cycle);
01111 if (dir!=null)
01112 return JSROOT.CallBack(user_call_back, dir);
01113 }
01114
01115 file.ReadObjBuffer(key, function(buf) {
01116 if (!buf) return JSROOT.CallBack(user_call_back, null);
01117
01118 if (isdir) {
01119 var dir = new JSROOT.TDirectory(file, obj_name, cycle);
01120 dir.StreamHeader(buf);
01121 if (dir.fSeekKeys) {
01122 dir.ReadKeys(user_call_back);
01123 } else {
01124 JSROOT.CallBack(user_call_back,dir);
01125 }
01126
01127 return;
01128 }
01129
01130 var obj = {};
01131 buf.MapObject(1, obj);
01132 buf.ClassStreamer(obj, key.fClassName);
01133
01134 if (key.fClassName==='TF1')
01135 return file.ReadFormulas(obj, user_call_back, -1);
01136
01137 JSROOT.CallBack(user_call_back, obj);
01138 });
01139 });
01140 }
01141
01142 JSROOT.TFile.prototype.ReadFormulas = function(tf1, user_call_back, cnt) {
01143
01144 var indx = cnt;
01145 while (++indx < this.fKeys.length) {
01146 if (this.fKeys[indx].fClassName == 'TFormula') break;
01147 }
01148
01149 if (indx >= this.fKeys.length)
01150 return JSROOT.CallBack(user_call_back, tf1);
01151
01152 var file = this;
01153
01154 this.ReadObject(this.fKeys[indx].fName, this.fKeys[indx].fCycle, function(formula) {
01155 tf1.addFormula(formula);
01156 file.ReadFormulas(tf1, user_call_back, indx);
01157 });
01158 }
01159
01160 JSROOT.TFile.prototype.ExtractStreamerInfos = function(buf) {
01161 if (!buf) return;
01162
01163 var lst = {};
01164 buf.MapObject(1, lst);
01165 buf.ClassStreamer(lst, 'TList');
01166
01167 lst._typename = "TStreamerInfoList";
01168
01169 this.fStreamerInfos = lst;
01170
01171 if (typeof JSROOT.addStreamerInfos === 'function')
01172 JSROOT.addStreamerInfos(lst);
01173 }
01174
01175
01176 JSROOT.TFile.prototype.ReadStreamerInfos = function(si_callback) {
01177 if (this.fSeekInfo == 0 || this.fNbytesInfo == 0) return si_callback(null);
01178 this.Seek(this.fSeekInfo, this.ERelativeTo.kBeg);
01179
01180 var file = this;
01181
01182 file.ReadBuffer(file.fNbytesInfo, function(blob1) {
01183 var buf = JSROOT.CreateTBuffer(blob1, 0, file);
01184 var key = file.ReadKey(buf);
01185 if (key == null) return si_callback(null);
01186 file.fKeys.push(key);
01187
01188 file.ReadObjBuffer(key, function(blob2) {
01189 if (blob2==null) return si_callback(null);
01190 file.ExtractStreamerInfos(blob2);
01191 si_callback(file);
01192 });
01193 });
01194 }
01195
01196 JSROOT.TFile.prototype.ReadKeys = function(readkeys_callback) {
01197
01198
01199 var file = this;
01200
01201
01202 this.ReadBuffer(1024, function(blob) {
01203 if (blob==null) return JSROOT.CallBack(readkeys_callback, null);
01204
01205 var buf = JSROOT.CreateTBuffer(blob, 0, file);
01206
01207 if (buf.substring(0, 4) !== 'root') {
01208 alert("NOT A ROOT FILE! " + file.fURL);
01209 return JSROOT.CallBack(readkeys_callback, null);
01210 }
01211 buf.shift(4);
01212
01213 file.fVersion = buf.ntou4();
01214 file.fBEGIN = buf.ntou4();
01215 if (file.fVersion < 1000000) {
01216 file.fEND = buf.ntou4();
01217 file.fSeekFree = buf.ntou4();
01218 file.fNbytesFree = buf.ntou4();
01219 var nfree = buf.ntoi4();
01220 file.fNbytesName = buf.ntou4();
01221 file.fUnits = buf.ntou1();
01222 file.fCompress = buf.ntou4();
01223 file.fSeekInfo = buf.ntou4();
01224 file.fNbytesInfo = buf.ntou4();
01225 } else {
01226 file.fEND = buf.ntou8();
01227 file.fSeekFree = buf.ntou8();
01228 file.fNbytesFree = buf.ntou4();
01229 var nfree = buf.ntou4();
01230 file.fNbytesName = buf.ntou4();
01231 file.fUnits = buf.ntou1();
01232 file.fCompress = buf.ntou4();
01233 file.fSeekInfo = buf.ntou8();
01234 file.fNbytesInfo = buf.ntou4();
01235 }
01236
01237
01238 if (!file.fSeekInfo && !file.fNbytesInfo)
01239 return JSROOT.CallBack(readkeys_callback, null);
01240
01241
01242 var nbytes = file.fNbytesName + 22;
01243 nbytes += 4;
01244 nbytes += 4;
01245 nbytes += 18;
01246
01247 if (file.fVersion >= 40000) nbytes += 12;
01248
01249 file.Seek(file.fBEGIN, file.ERelativeTo.kBeg);
01250
01251 file.ReadBuffer(Math.max(300, nbytes), function(blob3) {
01252 if (blob3==null) return JSROOT.CallBack(readkeys_callback, null);
01253
01254 var buf3 = JSROOT.CreateTBuffer(blob3, file.fNbytesName, file);
01255
01256
01257 JSROOT.TDirectory.prototype.StreamHeader.call(file, buf3);
01258
01259
01260 buf3.o = 4;
01261 var keyversion = buf3.ntoi2();
01262
01263 if (keyversion > 1000) buf3.shift(28);
01264 else buf3.shift(20);
01265 buf3.ReadTString();
01266 buf3.ReadTString();
01267 file.fTitle = buf3.ReadTString();
01268 if (file.fNbytesName < 10 || this.fNbytesName > 10000) {
01269 JSROOT.console("Init : cannot read directory info of file " + file.fURL);
01270 return JSROOT.CallBack(readkeys_callback, null);
01271 }
01272
01273
01274 if (file.fSeekKeys <= 0) {
01275 JSROOT.console("Empty keys list - not supported" + file.fURL);
01276 return JSROOT.CallBack(readkeys_callback, null);
01277 }
01278
01279 file.Seek(file.fSeekKeys, file.ERelativeTo.kBeg);
01280 file.ReadBuffer(file.fNbytesKeys, function(blob4) {
01281
01282 if (blob4==null) return JSROOT.CallBack(readkeys_callback, null);
01283
01284 var buf4 = JSROOT.CreateTBuffer(blob4, 0, file);
01285 var key = file.ReadKey(buf4);
01286 var nkeys = buf4.ntoi4();
01287 for (var i = 0; i < nkeys; ++i) {
01288 key = file.ReadKey(buf4);
01289 file.fKeys.push(key);
01290 }
01291 file.ReadStreamerInfos(readkeys_callback);
01292 delete buf4;
01293 });
01294 delete buf3;
01295 });
01296 delete buf;
01297 });
01298 };
01299
01300 JSROOT.TFile.prototype.ReadDirectory = function(dir_name, cycle, readdir_callback) {
01301
01302
01303
01304 return this.ReadObject(dir_name, cycle, readdir_callback);
01305 };
01306
01307 JSROOT.TFile.prototype.AddMethods = function(clname, streamer) {
01308
01309
01310 if (streamer === null) return streamer;
01311
01312 var methods = JSROOT.getMethods(clname);
01313 if (methods !== null)
01314 for (var key in methods)
01315 if ((typeof methods[key] === 'function') || (key.indexOf("_")==0))
01316 streamer.push({
01317 name: key,
01318 method: methods[key],
01319 func: function(buf,obj) { obj[this.name] = this.method; }
01320 });
01321
01322 return streamer;
01323 }
01324
01325 JSROOT.TFile.prototype.GetStreamer = function(clname) {
01326
01327
01328
01329 var streamer = this.fStreamers[clname];
01330 if (streamer !== undefined) return streamer;
01331
01332 if (clname == 'TQObject' || clname == "TBasket") {
01333
01334 this.fStreamers[clname] = null;
01335 return null;
01336 }
01337
01338 this.fStreamers[clname] = streamer = new Array;
01339
01340 if (clname == 'TObject'|| clname == 'TMethodCall') {
01341 streamer.push({ func: function(buf,obj) {
01342 obj.fUniqueID = buf.ntou4();
01343 obj.fBits = buf.ntou4();
01344 } });
01345 return this.AddMethods(clname, streamer);
01346 }
01347
01348 if (clname == 'TNamed') {
01349 streamer.push({ func : function(buf,obj) {
01350 buf.ReadVersion();
01351 obj.fUniqueID = buf.ntou4();
01352 obj.fBits = buf.ntou4();
01353 obj.fName = buf.ReadTString();
01354 obj.fTitle = buf.ReadTString();
01355 } });
01356 return this.AddMethods(clname, streamer);
01357 }
01358
01359 if ((clname == 'TList') || (clname == 'THashList')) {
01360 streamer.push({ classname: clname,
01361 func : function(buf, obj) {
01362
01363 obj._typename = this.classname;
01364 obj.name = "";
01365 obj.arr = new Array;
01366 obj.opt = new Array;
01367 if (buf.last_read_version > 3) {
01368 buf.ClassStreamer(obj, "TObject");
01369 obj.name = buf.ReadTString();
01370 var nobjects = buf.ntou4();
01371 for (var i = 0; i < nobjects; ++i) {
01372 obj.arr.push(buf.ReadObjectAny());
01373 obj.opt.push(buf.ReadTString());
01374 }
01375 }
01376 } });
01377 return this.AddMethods(clname, streamer);
01378 }
01379
01380 if (clname == 'TClonesArray') {
01381 streamer.push({ func : function(buf, list) {
01382 list._typename = "TClonesArray";
01383 list.name = "";
01384 list.arr = new Array();
01385 var ver = buf.last_read_version;
01386 if (ver > 2)
01387 buf.buf.ClassStreamer(list, "TObject");
01388 if (ver > 1)
01389 list.name = buf.ReadTString();
01390 var s = buf.ReadTString();
01391 var classv = s;
01392 var clv = 0;
01393 var pos = s.indexOf(";");
01394 if (pos != -1) {
01395 classv = s.slice(0, pos);
01396 s = s.slice(pos+1, s.length-pos-1);
01397 clv = parseInt(s);
01398 }
01399
01400 var nobjects = buf.ntou4();
01401 if (nobjects < 0) nobjects = -nobjects;
01402 var lowerbound = buf.ntou4();
01403
01404
01405
01406
01407
01408
01409
01410 }});
01411 return this.AddMethods(clname, streamer);
01412 }
01413
01414 if (clname == 'TCanvas') {
01415 streamer.push({ func : function(buf, obj) {
01416
01417 obj._typename = "TCanvas";
01418
01419 buf.ClassStreamer(obj, "TPad");
01420
01421 obj.fDISPLAY = buf.ReadTString();
01422 obj.fDoubleBuffer = buf.ntoi4();
01423 obj.fRetained = (buf.ntou1() !== 0);
01424 obj.fXsizeUser = buf.ntoi4();
01425 obj.fYsizeUser = buf.ntoi4();
01426 obj.fXsizeReal = buf.ntoi4();
01427 obj.fYsizeReal = buf.ntoi4();
01428 obj.fWindowTopX = buf.ntoi4();
01429 obj.fWindowTopY = buf.ntoi4();
01430 obj.fWindowWidth = buf.ntoi4();
01431 obj.fWindowHeight = buf.ntoi4();
01432 obj.fCw = buf.ntou4();
01433 obj.fCh = buf.ntou4();
01434
01435 obj.fCatt = buf.ClassStreamer({}, "TAttCanvas");
01436
01437 buf.ntou1();
01438 buf.ntou1();
01439 obj.fHighLightColor = buf.ntoi2();
01440 obj.fBatch = (buf.ntou1() !== 0);
01441 buf.ntou1();
01442 buf.ntou1();
01443 buf.ntou1();
01444 }});
01445 return this.AddMethods(clname, streamer);
01446 }
01447
01448 if (clname == 'TObjArray') {
01449 streamer.push({ func : function(buf, list) {
01450 list._typename = "TObjArray";
01451 list.name = "";
01452 list.arr = new Array();
01453 var ver = buf.last_read_version;
01454 if (ver > 2)
01455 buf.ClassStreamer(list, "TObject");
01456 if (ver > 1)
01457 list.name = buf.ReadTString();
01458 var nobjects = buf.ntou4();
01459 var lowerbound = buf.ntou4();
01460 for (var i = 0; i < nobjects; ++i)
01461 list.arr.push(buf.ReadObjectAny());
01462 }});
01463 return this.AddMethods(clname, streamer);
01464 }
01465
01466 if (clname == 'TPolyMarker3D') {
01467 streamer.push({ func : function(buf, marker) {
01468 var ver = buf.last_read_version;
01469
01470 buf.ClassStreamer(marker, "TObject");
01471
01472 buf.ClassStreamer(marker, "TAttMarker");
01473
01474 marker.fN = buf.ntoi4();
01475
01476 marker.fP = buf.ReadFastArray(marker.fN*3, JSROOT.IO.kFloat);
01477
01478 marker.fOption = buf.ReadTString();
01479
01480 if (ver > 1)
01481 marker.fName = buf.ReadTString();
01482 else
01483 marker.fName = "TPolyMarker3D";
01484 }});
01485 return this.AddMethods(clname, streamer);
01486 }
01487
01488 if (clname == "TStreamerInfo") {
01489 streamer.push({ func : function(buf, streamerinfo) {
01490
01491 if (buf.last_read_version > 1) {
01492 buf.ClassStreamer(streamerinfo, "TNamed");
01493
01494 streamerinfo.fCheckSum = buf.ntou4();
01495 streamerinfo.fClassVersion = buf.ntou4();
01496 streamerinfo.fElements = buf.ReadObjectAny();
01497 }
01498 }});
01499 return this.AddMethods(clname, streamer);
01500 }
01501
01502 if (clname == "TStreamerElement") {
01503 streamer.push({ func : function(buf, element) {
01504
01505
01506 var ver = buf.last_read_version;
01507 buf.ClassStreamer(element, "TNamed");
01508 element.fType = buf.ntou4();
01509 element.fSize = buf.ntou4();
01510 element.fArrayLength = buf.ntou4();
01511 element.fArrayDim = buf.ntou4();
01512 element.fMaxIndex = buf.ReadFastArray((ver == 1) ? buf.ntou4() : 5, JSROOT.IO.kUInt);
01513 element.fTypeName = buf.ReadTString();
01514
01515 if ((element.fType == JSROOT.IO.kUChar) && (element.fTypeName == "Bool_t" ||
01516 element.fTypeName == "bool"))
01517 element.fType = JSROOT.IO.kBool;
01518 if (ver > 1) {
01519 }
01520 if (ver <= 2) {
01521
01522
01523
01524 }
01525 if (ver == 3) {
01526 element.fXmin = buf.ntod();
01527 element.fXmax = buf.ntod();
01528 element.fFactor = buf.ntod();
01529 }
01530 if (ver > 3) {
01531 }
01532 }});
01533 return this.AddMethods(clname, streamer);
01534 }
01535
01536 if (clname == "TStreamerBase") {
01537 streamer.push({ func : function(buf, elem) {
01538
01539
01540 var ver = buf.last_read_version;
01541 buf.ClassStreamer(elem, "TStreamerElement");
01542 if (ver > 2) {
01543 elem.fBaseVersion = buf.ntou4();
01544 }
01545 }});
01546 return this.AddMethods(clname, streamer);
01547 }
01548
01549 if ((clname == "TStreamerBasicPointer") || (clname == "TStreamerLoop")) {
01550 streamer.push({ func : function(buf,elem) {
01551
01552 if (buf.last_read_version > 1) {
01553 buf.ClassStreamer(elem, "TStreamerElement");
01554 elem.fCountVersion = buf.ntou4();
01555 elem.fCountName = buf.ReadTString();
01556 elem.fCountClass = buf.ReadTString();
01557 }
01558 }});
01559 return this.AddMethods(clname, streamer);
01560 }
01561
01562 if (clname == "TStreamerSTL") {
01563 streamer.push({ func : function(buf, elem) {
01564 if (buf.last_read_version > 1) {
01565 buf.ClassStreamer(elem, "TStreamerElement");
01566 elem.fSTLtype = buf.ntou4();
01567 elem.fCtype = buf.ntou4();
01568 }
01569 }});
01570 return streamer;
01571 }
01572
01573 if (clname == "TStreamerObject" || clname == "TStreamerBasicType" ||
01574 clname == "TStreamerObjectAny" || clname == "TStreamerString" ||
01575 clname == "TStreamerObjectPointer") {
01576 streamer.push({ func: function(buf, elem) {
01577 if (buf.last_read_version > 1)
01578 buf.ClassStreamer(elem, "TStreamerElement");
01579 }});
01580 return this.AddMethods(clname, streamer);
01581 }
01582
01583 if (clname == "TStreamerObjectAnyPointer") {
01584 streamer.push({ func: function(buf, elem) {
01585 if (buf.last_read_version > 0)
01586 buf.ClassStreamer(elem, "TStreamerElement");
01587 }});
01588 return this.AddMethods(clname, streamer);
01589 }
01590
01591 var s_i = null;
01592 if (this.fStreamerInfos)
01593 for (var i=0; i < this.fStreamerInfos.arr.length; ++i)
01594 if (this.fStreamerInfos.arr[i].fName == clname) {
01595 s_i = this.fStreamerInfos.arr[i]; break;
01596 }
01597 if (s_i == null) {
01598 delete this.fStreamers[clname];
01599 return null;
01600 }
01601
01602 if (s_i.fElements === null)
01603 return this.AddMethods(clname, streamer);
01604
01605
01606 for (var j=0; j<s_i.fElements.arr.length; ++j) {
01607
01608 var element = s_i.fElements.arr[j];
01609
01610 var member = { name: element.fName, type: element.fType };
01611
01612 if (element.fTypeName === 'BASE') {
01613 if (JSROOT.IO.GetArrayKind(member.name) > 0) {
01614
01615
01616 member.name = 'fArray';
01617 member.type = JSROOT.IO.kAny;
01618 } else {
01619
01620 member.type = JSROOT.IO.kBase;
01621 this.GetStreamer(element.fName);
01622 }
01623 }
01624
01625 switch (member.type) {
01626 case JSROOT.IO.kBase:
01627 member.func = function(buf, obj) {
01628 buf.ClassStreamer(obj, this.name);
01629 };
01630 break;
01631 case JSROOT.IO.kTString:
01632 member.func = function(buf,obj) { obj[this.name] = buf.ReadTString(); }; break;
01633 case JSROOT.IO.kAnyP:
01634 case JSROOT.IO.kObjectP:
01635 member.func = function(buf,obj) { obj[this.name] = buf.ReadObjectAny(); }; break;
01636 case JSROOT.IO.kOffsetL+JSROOT.IO.kInt:
01637 case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble:
01638 case JSROOT.IO.kOffsetL+JSROOT.IO.kShort:
01639 case JSROOT.IO.kOffsetL+JSROOT.IO.kUShort:
01640 case JSROOT.IO.kOffsetL+JSROOT.IO.kUInt:
01641 case JSROOT.IO.kOffsetL+JSROOT.IO.kULong:
01642 case JSROOT.IO.kOffsetL+JSROOT.IO.kULong64:
01643 case JSROOT.IO.kOffsetL+JSROOT.IO.kLong:
01644 case JSROOT.IO.kOffsetL+JSROOT.IO.kLong64:
01645 case JSROOT.IO.kOffsetL+JSROOT.IO.kFloat:
01646 case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble32:
01647 if (element.fArrayDim === 1) {
01648 member.arrlength = element.fArrayLength;
01649 member.func = function(buf, obj) {
01650 obj[this.name] = buf.ReadFastArray(this.arrlength, this.type - JSROOT.IO.kOffsetL);
01651 };
01652 } else
01653 if (element.fArrayDim === 2) {
01654 member.arrlength = element.fMaxIndex[1];
01655 member.maxindx = element.fMaxIndex[0];
01656 member.func = function(buf, obj) {
01657 obj[this.name] = [];
01658 for (var n=0;n<this.maxindx;++n)
01659 obj[this.name].push(buf.ReadFastArray(this.arrlength, this.type - JSROOT.IO.kOffsetL));
01660 };
01661 } else {
01662 member.maxdim = element.fArrayDim - 1;
01663 member.maxindx = element.fMaxIndex;
01664 member.arrlength = element.fArrayLength;
01665 member.func = function(buf, obj) {
01666 var tmp = buf.ReadFastArray(this.arrlength, this.type - JSROOT.IO.kOffsetL),
01667 indx = [], arr = [], i, k;
01668 for (i=0; i<=this.maxdim; ++i) { indx[i] = 0; arr[i] = []; }
01669 for (i=0;i<tmp.length;++i) {
01670 arr[this.maxdim].push(tmp[i]);
01671 ++indx[this.maxdim];
01672 k = this.maxdim;
01673 while ((indx[k] === this.maxindx[k]) && (k>0)) {
01674 indx[k] = 0;
01675 arr[k-1].push(arr[k]);
01676 arr[k] = [];
01677 ++indx[--k];
01678 }
01679 }
01680 obj[this.name] = arr[0];
01681 };
01682 }
01683 break;
01684 case JSROOT.IO.kOffsetP+JSROOT.IO.kInt:
01685 case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble:
01686 case JSROOT.IO.kOffsetP+JSROOT.IO.kUChar:
01687 case JSROOT.IO.kOffsetP+JSROOT.IO.kChar:
01688 case JSROOT.IO.kOffsetP+JSROOT.IO.kShort:
01689 case JSROOT.IO.kOffsetP+JSROOT.IO.kUShort:
01690 case JSROOT.IO.kOffsetP+JSROOT.IO.kUInt:
01691 case JSROOT.IO.kOffsetP+JSROOT.IO.kULong:
01692 case JSROOT.IO.kOffsetP+JSROOT.IO.kULong64:
01693 case JSROOT.IO.kOffsetP+JSROOT.IO.kLong:
01694 case JSROOT.IO.kOffsetP+JSROOT.IO.kLong64:
01695 case JSROOT.IO.kOffsetP+JSROOT.IO.kFloat:
01696 case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble32:
01697 member.cntname = element.fCountName;
01698 member.func = function(buf, obj) {
01699 if (buf.ntou1() === 1)
01700 obj[this.name] = buf.ReadFastArray(obj[this.cntname], this.type - JSROOT.IO.kOffsetP);
01701 else
01702 obj[this.name] = new Array();
01703 };
01704 break;
01705 case JSROOT.IO.kAny:
01706 case JSROOT.IO.kAnyp:
01707 case JSROOT.IO.kObjectp:
01708 case JSROOT.IO.kObject:
01709 var classname = (element.fTypeName === 'BASE') ? element.fName : element.fTypeName;
01710 if (classname.charAt(classname.length-1) == "*")
01711 classname = classname.substr(0, classname.length - 1);
01712
01713 var arrkind = JSROOT.IO.GetArrayKind(classname);
01714
01715 if (arrkind > 0) {
01716 member.arrkind = arrkind;
01717 member.func = function(buf, obj) {
01718 obj[this.name] = buf.ReadFastArray(buf.ntou4(), this.arrkind);
01719 };
01720 } else {
01721 member.classname = classname;
01722 member.func = function(buf, obj) {
01723 obj[this.name] = buf.ClassStreamer({}, this.classname);
01724 };
01725 }
01726 break;
01727 case JSROOT.IO.kOffsetL + JSROOT.IO.kObject:
01728 case JSROOT.IO.kOffsetL + JSROOT.IO.kAny:
01729 case JSROOT.IO.kOffsetL + JSROOT.IO.kAnyp:
01730 case JSROOT.IO.kOffsetL + JSROOT.IO.kObjectp:
01731 member.arrlength = element.fArrayLength;
01732 var classname = element.fTypeName;
01733 if (classname.charAt(classname.length-1) == "*")
01734 classname = classname.substr(0, classname.length - 1);
01735
01736 var arrkind = JSROOT.IO.GetArrayKind(classname);
01737
01738 if (arrkind > 0) {
01739 member.arrkind = arrkind;
01740 member.func = function(buf, obj) {
01741 obj[this.name] = [];
01742 for (var k=0;k<this.arrlength;++k)
01743 obj[this.name].push(buf.ReadFastArray(buf.ntou4(), this.arrkind));
01744 };
01745 } else {
01746 member.classname = classname;
01747 member.func = function(buf, obj) {
01748 obj[this.name] = [];
01749 for (var k=0;k<this.arrlength;++k)
01750 obj[this.name].push(buf.ClassStreamer({}, this.classname));
01751 };
01752 }
01753 break;
01754 case JSROOT.IO.kChar:
01755 member.func = function(buf,obj) { obj[this.name] = buf.ntoi1(); }; break;
01756 case JSROOT.IO.kShort:
01757 member.func = function(buf,obj) { obj[this.name] = buf.ntoi2(); }; break;
01758 case JSROOT.IO.kInt:
01759 case JSROOT.IO.kCounter:
01760 member.func = function(buf,obj) { obj[this.name] = buf.ntoi4(); }; break;
01761 case JSROOT.IO.kLong:
01762 case JSROOT.IO.kLong64:
01763 member.func = function(buf,obj) { obj[this.name] = buf.ntoi8(); }; break;
01764 case JSROOT.IO.kDouble:
01765 member.func = function(buf,obj) { obj[this.name] = buf.ntod(); }; break;
01766 case JSROOT.IO.kFloat:
01767 case JSROOT.IO.kDouble32:
01768 member.func = function(buf,obj) { obj[this.name] = buf.ntof(); }; break;
01769 case JSROOT.IO.kLegacyChar:
01770 case JSROOT.IO.kUChar:
01771 member.func = function(buf,obj) { obj[this.name] = buf.ntou1(); }; break;
01772 case JSROOT.IO.kUShort:
01773 member.func = function(buf,obj) { obj[this.name] = buf.ntou2(); }; break;
01774 case JSROOT.IO.kUInt:
01775 member.func = function(buf,obj) { obj[this.name] = buf.ntou4(); }; break;
01776 case JSROOT.IO.kULong64:
01777 case JSROOT.IO.kULong:
01778 member.func = function(buf,obj) { obj[this.name] = buf.ntou8(); }; break;
01779
01780 case JSROOT.IO.kBool:
01781 member.func = function(buf,obj) { obj[this.name] = buf.ntou1() != 0; }; break;
01782 case JSROOT.IO.kStreamLoop:
01783 case JSROOT.IO.kStreamer:
01784 member.cntname = element.fCountName;
01785 member.typename = element.fTypeName;
01786 member.func = function(buf,obj) {
01787 var ver = buf.ReadVersion();
01788 var res = null;
01789
01790 if (this.typename == "TString*") {
01791 var cnt = obj[this.cntname];
01792 res = new Array(cnt);
01793 for (var i = 0; i < cnt; ++i )
01794 res[i] = buf.ReadTString();
01795 } else
01796 if (this.typename == "vector<double>") res = buf.ReadFastArray(buf.ntoi4(),JSROOT.IO.kDouble); else
01797 if (this.typename == "vector<int>") res = buf.ReadFastArray(buf.ntoi4(),JSROOT.IO.kInt); else
01798 if (this.typename == "vector<float>") res = buf.ReadFastArray(buf.ntoi4(),JSROOT.IO.kFloat); else
01799 if (this.typename == "vector<TObject*>") {
01800 var n = buf.ntoi4();
01801 res = [];
01802 for (var i=0;i<n;++i) res.push(buf.ReadObjectAny());
01803 } else
01804 if (this.typename.indexOf("map<TString,int")==0) {
01805 var n = buf.ntoi4();
01806 res = [];
01807 for (var i=0;i<n;++i) {
01808 var str = buf.ReadTString();
01809 var val = buf.ntoi4();
01810 res.push({ first: str, second: val});
01811 }
01812 } else {
01813 JSROOT.console('failed to stream element of type ' + this.typename);
01814 }
01815
01816 if (!buf.CheckBytecount(ver, this.typename)) res = null;
01817
01818 obj[this.name] = res;
01819 };
01820 break;
01821 default:
01822 if (JSROOT.fUserStreamers !== null)
01823 member.func = JSROOT.fUserStreamers[element.fTypeName];
01824
01825 if (typeof member.func !== 'function') {
01826 alert('failed to provide function for ' + element.fName + ' (' + element.fTypeName + ') typ = ' + element.fType);
01827 member.func = function(buf,obj) {};
01828 }
01829 }
01830
01831 streamer.push(member);
01832 }
01833
01834 return this.AddMethods(clname, streamer);
01835 };
01836
01837 JSROOT.TFile.prototype.Delete = function() {
01838 if (this.fDirectories) this.fDirectories.splice(0, this.fDirectories.length);
01839 this.fDirectories = null;
01840 this.fKeys = null;
01841 this.fStreamers = null;
01842 this.fSeekInfo = 0;
01843 this.fNbytesInfo = 0;
01844 this.fTagOffset = 0;
01845 };
01846
01847
01848
01849 (function() {
01850 var iomode = JSROOT.GetUrlOption("iomode");
01851 if ((iomode=="str") || (iomode=="string")) JSROOT.IO.Mode = "string"; else
01852 if ((iomode=="bin") || (iomode=="arr") || (iomode=="array")) JSROOT.IO.Mode = "array";
01853 JSROOT.IO.NativeArray = ('Float64Array' in window);
01854 })();
01855
01856 return JSROOT;
01857
01858 }));
01859
01860
01861
01862