hdf5.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  1. /* jshint esversion: 6 */
  2. /* eslint "indent": [ "error", 4, { "SwitchCase": 1 } ] */
  3. // Experimental H5/HDF5 JavaScript reader
  4. var hdf5 = hdf5 || {};
  5. hdf5.File = class {
  6. constructor(buffer) {
  7. var reader = new hdf5.Reader(buffer, 0);
  8. this._globalHeap = new hdf5.GlobalHeap(reader);
  9. if (!reader.match('\x89HDF\r\n\x1A\n')) {
  10. throw new hdf5.Error('Not a valid HDF5 file.');
  11. }
  12. var version = reader.byte();
  13. switch (version) {
  14. case 0:
  15. case 1:
  16. this._freeSpaceStorageVersion = reader.byte();
  17. this._rootGroupEntryVersion = reader.byte();
  18. reader.seek(1);
  19. this._sharedHeaderMessageVersionFormat = reader.byte();
  20. reader.initialize();
  21. reader.seek(1);
  22. this._groupLeafNodeK = reader.uint16(); // 0x04?
  23. this._groupInternalNodeK = reader.uint16(); // 0x10?
  24. reader.seek(4);
  25. if (version > 0) {
  26. this._indexedStorageInternalNodeK = reader.uint16();
  27. this.seek(2); // Reserved
  28. }
  29. this._baseAddress = reader.offset();
  30. reader.offset(); // Address of File Free space Info
  31. this._endOfFileAddress = reader.offset();
  32. reader.offset(); // Driver Information Block Address
  33. if (this._baseAddress != 0) {
  34. throw new hdf5.Error('Base address is not zero.');
  35. }
  36. var rootGroupEntry = new hdf5.SymbolTableEntry(reader);
  37. this._rootGroup = new hdf5.Group(reader, rootGroupEntry, null, this._globalHeap, '', '');
  38. break;
  39. case 2:
  40. case 3:
  41. reader.initialize();
  42. reader.byte();
  43. this._baseAddress = reader.offset();
  44. this._superBlockExtensionAddress = reader.offset();
  45. this._endOfFileAddress = reader.offset();
  46. var rootGroupObjectHeader = new hdf5.DataObjectHeader(reader.move(reader.offset()));
  47. this._rootGroup = new hdf5.Group(reader, null, rootGroupObjectHeader, this._globalHeap, '', '');
  48. break;
  49. default:
  50. throw new hdf5.Error('Unsupported Superblock version ' + version + '.');
  51. }
  52. }
  53. get rootGroup() {
  54. return this._rootGroup;
  55. }
  56. };
  57. hdf5.Group = class {
  58. constructor(reader, entry, objectHeader, globalHeap, parentPath, name) {
  59. this._reader = reader;
  60. this._entry = entry;
  61. this._dataObjectHeader = objectHeader;
  62. this._globalHeap = globalHeap;
  63. this._name = name;
  64. this._path = parentPath == '/' ? (parentPath + name) : (parentPath + '/' + name);
  65. }
  66. get name() {
  67. return this._name;
  68. }
  69. get path() {
  70. return this._path;
  71. }
  72. group(path) {
  73. this.decodeGroups();
  74. var index = path.indexOf('/');
  75. if (index != -1) {
  76. var childPath = path.substring(index + 1);
  77. var subPath = path.substring(0, index);
  78. var subGroup = this.group(subPath);
  79. if (subGroup != null) {
  80. return subGroup.group(childPath);
  81. }
  82. }
  83. else {
  84. var group = this._groupMap[path];
  85. if (group) {
  86. return group;
  87. }
  88. }
  89. return null;
  90. }
  91. get groups() {
  92. this.decodeGroups();
  93. return this._groups;
  94. }
  95. attribute(name) {
  96. this.decodeDataObject();
  97. return this._attributes[name];
  98. }
  99. get attributes() {
  100. this.decodeDataObject();
  101. return this._attributes;
  102. }
  103. get value() {
  104. this.decodeDataObject();
  105. return this._value;
  106. }
  107. decodeDataObject() {
  108. if (!this._dataObjectHeader) {
  109. this._dataObjectHeader = new hdf5.DataObjectHeader(this._reader.move(this._entry.objectHeaderAddress));
  110. }
  111. if (!this._attributes) {
  112. this._attributes = {};
  113. this._dataObjectHeader.attributes.forEach((attribute) => {
  114. var name = attribute.name;
  115. var value = attribute.decodeValue(this._globalHeap);
  116. this._attributes[name] = value;
  117. });
  118. this._value = null;
  119. var datatype = this._dataObjectHeader.datatype;
  120. var dataspace = this._dataObjectHeader.dataspace;
  121. var dataLayout = this._dataObjectHeader.dataLayout;
  122. if (datatype && dataspace && dataLayout) {
  123. this._value = new hdf5.Variable(this._reader, this._globalHeap, datatype, dataspace, dataLayout);
  124. }
  125. }
  126. }
  127. decodeGroups() {
  128. if (!this._groups) {
  129. this._groupMap = {};
  130. this._groups = [];
  131. if (this._entry) {
  132. if (this._entry.treeAddress || this._entry.heapAddress) {
  133. var heap = new hdf5.Heap(this._reader.move(this._entry.heapAddress));
  134. var tree = new hdf5.Tree(this._reader.move(this._entry.treeAddress));
  135. tree.nodes.forEach((node) => {
  136. node.entries.forEach((entry) => {
  137. var name = heap.getString(entry.linkNameOffset);
  138. var group = new hdf5.Group(this._reader, entry, null, this._globalHeap, this._path, name);
  139. this._groups.push(group);
  140. this._groupMap[name] = group;
  141. });
  142. });
  143. }
  144. }
  145. else {
  146. this.decodeDataObject();
  147. this._dataObjectHeader.links.forEach((link) => {
  148. if (link.hasOwnProperty('objectHeaderAddress')) {
  149. var name = link.name;
  150. var objectHeader = new hdf5.DataObjectHeader(this._reader.move(link.objectHeaderAddress));
  151. var group = new hdf5.Group(this._reader, null, objectHeader, this._globalHeap, this._path, name);
  152. this._groups.push(group);
  153. this._groupMap[name] = group;
  154. }
  155. });
  156. }
  157. }
  158. }
  159. };
  160. hdf5.Variable = class {
  161. constructor(reader, globalHeap, datatype, dataspace, dataLayout) {
  162. this._reader = reader;
  163. this._globalHeap = globalHeap;
  164. this._datatype = datatype;
  165. this._dataspace = dataspace;
  166. this._dataLayout = dataLayout;
  167. }
  168. get type () {
  169. return this._datatype.type;
  170. }
  171. get shape() {
  172. return this._dataspace.shape;
  173. }
  174. get value() {
  175. if (this._dataLayout.address) {
  176. var reader = this._reader.move(this._dataLayout.address);
  177. var data = this._dataspace.read(this._datatype, reader);
  178. var value = this._dataspace.decode(this._datatype, data, data, this._globalHeap);
  179. return value;
  180. }
  181. return null;
  182. }
  183. get rawData() {
  184. if (this._dataLayout.address) {
  185. var reader = this._reader.move(this._dataLayout.address);
  186. return reader.bytes(this._dataLayout.size);
  187. }
  188. return null;
  189. }
  190. };
  191. hdf5.Reader = class {
  192. constructor(buffer) {
  193. if (buffer) {
  194. this._buffer = buffer;
  195. this._dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  196. this._position = 0;
  197. this._offset = 0;
  198. }
  199. }
  200. initialize() {
  201. this._offsetSize = this.byte();
  202. this._lengthSize = this.byte();
  203. }
  204. int8() {
  205. var value = this._dataView.getInt8(this._position + this._offset);
  206. this._offset++;
  207. return value;
  208. }
  209. byte() {
  210. var value = this._dataView.getUint8(this._position + this._offset);
  211. this._offset++;
  212. return value;
  213. }
  214. seek(offset) {
  215. this._offset += offset;
  216. }
  217. bytes(length) {
  218. var data = this._buffer.subarray(this._position + this._offset, this._position + this._offset + length);
  219. this._offset += length;
  220. return data;
  221. }
  222. int16() {
  223. var value = this._dataView.getInt16(this._position + this._offset, true);
  224. this._offset += 2;
  225. return value;
  226. }
  227. uint16() {
  228. var value = this._dataView.getUint16(this._position + this._offset, true);
  229. this._offset += 2;
  230. return value;
  231. }
  232. int32() {
  233. var value = this._dataView.getInt32(this._position + this._offset, true);
  234. this._offset += 4;
  235. return value;
  236. }
  237. uint32() {
  238. var value = this._dataView.getUint32(this._position + this._offset, true);
  239. this._offset += 4;
  240. return value;
  241. }
  242. int64() {
  243. var lo = this._dataView.getInt32(this._position + this._offset, true);
  244. var hi = this._dataView.getUint32(this._position + this._offset + 4, true);
  245. this._offset += 8;
  246. if (hi != 0) {
  247. throw new hdf5.Error('uint32 outside 32-bit range.');
  248. }
  249. return lo;
  250. }
  251. uint64() {
  252. var lo = this._dataView.getUint32(this._position + this._offset, true);
  253. var hi = this._dataView.getUint32(this._position + this._offset + 4, true);
  254. this._offset += 8;
  255. if (lo == 4294967295 && hi == lo) { // Undefined
  256. return -1;
  257. }
  258. if (hi != 0) {
  259. throw new hdf5.Error('uint64 outside 32-bit range.');
  260. }
  261. return lo;
  262. }
  263. uint(type) {
  264. switch (type) {
  265. case 0: return this.byte();
  266. case 1: return this.uint16();
  267. case 2: return this.uint32();
  268. case 3: return this.uint64();
  269. }
  270. }
  271. float16() {
  272. var value = this._dataView.getUint16(this._position + this._offset, true);
  273. this._offset += 2;
  274. // decode float16 value
  275. var s = (value & 0x8000) >> 15;
  276. var e = (value & 0x7C00) >> 10;
  277. var f = value & 0x03FF;
  278. if(e == 0) {
  279. return (s ? -1 : 1) * Math.pow(2, -14) * (f / Math.pow(2, 10));
  280. }
  281. else if (e == 0x1F) {
  282. return f ? NaN : ((s ? -1 : 1) * Infinity);
  283. }
  284. return (s ? -1 : 1) * Math.pow(2, e-15) * (1 + (f / Math.pow(2, 10)));
  285. }
  286. float32() {
  287. var value = this._dataView.getFloat32(this._position + this._offset, true);
  288. this._offset += 4;
  289. return value;
  290. }
  291. float64() {
  292. var value = this._dataView.getFloat64(this._position + this._offset, true);
  293. this._offset += 8;
  294. return value;
  295. }
  296. string(size, encoding) {
  297. if (!size || size == -1) {
  298. var position = this._position + this._offset;
  299. while (this._buffer[position] != 0) {
  300. position++;
  301. }
  302. size = position - this._position + this._offset + 1;
  303. }
  304. var data = this.bytes(size);
  305. return hdf5.Reader.decode(data, encoding);
  306. }
  307. static decode(data, encoding) {
  308. var text = '';
  309. if (encoding == 'utf-8') {
  310. if (!hdf5.Reader._utf8Decoder) {
  311. hdf5.Reader._utf8Decoder = new TextDecoder('utf-8');
  312. }
  313. text = hdf5.Reader._utf8Decoder.decode(data);
  314. }
  315. else {
  316. if (!hdf5.Reader._asciiDecoder) {
  317. hdf5.Reader._asciiDecoder = new TextDecoder('ascii');
  318. }
  319. text = hdf5.Reader._asciiDecoder.decode(data);
  320. }
  321. return text.replace(/\0/g, '');
  322. }
  323. offset() {
  324. switch (this._offsetSize) {
  325. case 8:
  326. return this.uint64();
  327. case 4:
  328. return this.uint32();
  329. }
  330. throw new hdf5.Error('Unsupported offset size \'' + this._offsetSize + '\'.');
  331. }
  332. length() {
  333. switch (this._lengthSize) {
  334. case 8:
  335. return this.uint64();
  336. case 4:
  337. return this.uint32();
  338. }
  339. throw new hdf5.Error('Unsupported length size \'' + this._lengthSize + '\'.');
  340. }
  341. move(position) {
  342. var reader = new hdf5.Reader(null);
  343. reader._buffer = this._buffer;
  344. reader._dataView = this._dataView;
  345. reader._position = position;
  346. reader._offset = 0;
  347. reader._offsetSize = this._offsetSize;
  348. reader._lengthSize = this._lengthSize;
  349. return reader;
  350. }
  351. clone() {
  352. var reader = new hdf5.Reader(this._buffer, this._position);
  353. reader._buffer = this._buffer;
  354. reader._dataView = this._dataView;
  355. reader._position = this._position;
  356. reader._offset = this._offset;
  357. reader._offsetSize = this._offsetSize;
  358. reader._lengthSize = this._lengthSize;
  359. return reader;
  360. }
  361. align(mod) {
  362. if (this._offset % mod != 0) {
  363. this._offset = (Math.floor(this._offset / mod) + 1) * mod;
  364. }
  365. }
  366. match(text) {
  367. if (this._position + this._offset + text.length > this._buffer.length) {
  368. throw new hdf5.Error("Invalid buffer offset while matching '" + text.replace(/[^\x20-\x7F]/g, '') + "'.");
  369. }
  370. var offset = this._offset;
  371. var buffer = this.bytes(text.length);
  372. for (var i = 0; i < text.length; i++) {
  373. if (text.charCodeAt(i) != buffer[i]) {
  374. this._offset = offset;
  375. return false;
  376. }
  377. }
  378. return true;
  379. }
  380. get position() {
  381. return this._position + this._offset;
  382. }
  383. get size() {
  384. return this._buffer.length;
  385. }
  386. };
  387. hdf5.SymbolTableNode = class {
  388. constructor(reader) {
  389. if (!reader.match('SNOD')) {
  390. throw new hdf5.Error("Not a valid 'SNOD' block.");
  391. }
  392. var version = reader.byte();
  393. if (version == 1) {
  394. reader.seek(1);
  395. var entriesUsed = reader.uint16();
  396. this.entries = [];
  397. for (var i = 0; i < entriesUsed; i++) {
  398. this.entries.push(new hdf5.SymbolTableEntry(reader));
  399. }
  400. }
  401. else {
  402. throw new hdf5.Error('Unsupported symbol table node version \'' + version + '\'.');
  403. }
  404. }
  405. };
  406. hdf5.SymbolTableEntry = class {
  407. constructor(reader) {
  408. this.linkNameOffset = reader.offset();
  409. this.objectHeaderAddress = reader.offset();
  410. var cacheType = reader.uint32();
  411. reader.seek(4); // Reserved
  412. switch (cacheType) {
  413. case 0:
  414. break;
  415. case 1:
  416. var scratchReader = reader.clone();
  417. this.treeAddress = scratchReader.offset();
  418. this.heapAddress = scratchReader.offset();
  419. break;
  420. default:
  421. throw new hdf5.Error('Unsupported cache type \'' + cacheType + '\'.');
  422. }
  423. reader.seek(16); // Scratch-pad space
  424. }
  425. };
  426. hdf5.DataObjectHeader = class {
  427. constructor(reader) {
  428. this.attributes = [];
  429. this.links = [];
  430. this.continuations = [];
  431. var version = reader.match('OHDR') ? reader.byte() : reader.byte();
  432. switch (version) {
  433. case 1:
  434. this.constructor_v1(reader);
  435. break;
  436. case 2:
  437. this.constructor_v2(reader);
  438. break;
  439. default:
  440. throw new hdf5.Error('Unsupported data object header version \'' + version + '\'.');
  441. }
  442. }
  443. constructor_v1(reader) {
  444. reader.seek(1);
  445. var messageCount = reader.uint16();
  446. reader.uint32();
  447. var objectHeaderSize = reader.uint32();
  448. reader.align(8);
  449. var end = reader.position + objectHeaderSize;
  450. for (var i = 0; i < messageCount; i++) {
  451. var messageType = reader.uint16();
  452. var messageSize = reader.uint16();
  453. var messageFlags = reader.byte();
  454. reader.seek(3);
  455. reader.align(8);
  456. var next = this.readMessage(reader, messageType, messageSize, messageFlags);
  457. if ((!next || reader.position >= end) && this.continuations.length > 0) {
  458. var continuation = this.continuations.shift();
  459. reader = reader.move(continuation.offset);
  460. end = continuation.offset + continuation.length;
  461. }
  462. else {
  463. reader.align(8);
  464. }
  465. }
  466. }
  467. constructor_v2(reader) {
  468. var flags = reader.byte();
  469. if ((flags & 0x20) != 0) {
  470. reader.uint32();
  471. reader.uint32();
  472. reader.uint32();
  473. reader.uint32();
  474. }
  475. if ((flags & 0x10) != 0) {
  476. reader.uint16();
  477. reader.uint16();
  478. }
  479. var size = reader.uint(flags & 0x03);
  480. var next = true;
  481. var end = reader.position + size;
  482. while (next && reader.position < end) {
  483. var messageType = reader.byte();
  484. var messageSize = reader.uint16();
  485. var messageFlags = reader.byte();
  486. if (reader.position < end) {
  487. if ((flags & 0x04) != 0) {
  488. reader.uint16();
  489. }
  490. next = this.readMessage(reader, messageType, messageSize, messageFlags);
  491. }
  492. if ((!next || reader.position >= end) && this.continuations.length > 0) {
  493. var continuation = this.continuations.shift();
  494. reader = reader.move(continuation.offset);
  495. end = continuation.offset + continuation.length;
  496. if (!reader.match('OCHK')) {
  497. throw new hdf5.Error("Invalid continuation block signature.");
  498. }
  499. next = true;
  500. }
  501. }
  502. }
  503. readMessage(reader, type, size, flags) {
  504. switch(type) {
  505. case 0x0000: // NIL
  506. return false;
  507. case 0x0001: // Dataspace
  508. this.dataspace = (size != 4 || flags != 1) ? new hdf5.Dataspace(reader.clone()) : null;
  509. break;
  510. case 0x0002: // Link Info
  511. this.linkInfo = new hdf5.LinkInfo(reader.clone());
  512. break;
  513. case 0x0003: // Datatype
  514. this.datatype = new hdf5.Datatype(reader.clone());
  515. break;
  516. case 0x0005: // Fill Value
  517. this.fillValue = new hdf5.FillValue(reader.clone());
  518. break;
  519. case 0x0006: // Link
  520. this.links.push(new hdf5.Link(reader.clone()));
  521. break;
  522. case 0x0008: // Data Layout
  523. this.dataLayout = new hdf5.DataLayout(reader.clone());
  524. break;
  525. case 0x000A: // Group Info
  526. this.groupInfo = new hdf5.GroupInfo(reader.clone());
  527. break;
  528. case 0x000C: // Attribute
  529. this.attributes.push(new hdf5.Attribute(reader.clone()));
  530. break;
  531. case 0x000D: // Object Comment Message
  532. this.comment = reader.string(-1, 'ascii');
  533. break;
  534. case 0x0010: // Object Header Continuation
  535. this.continuations.push(new hdf5.ObjectHeaderContinuation(reader.clone()));
  536. break;
  537. case 0x0011: // Symbol Table
  538. this.symbolTable = new hdf5.SymbolTable(reader.clone());
  539. break;
  540. case 0x0012: // Object Modification Time
  541. reader.seek(size);
  542. reader.align(8);
  543. break;
  544. case 0x0015: // Attribute Info
  545. this.attributeInfo = new hdf5.AttributeInfo(reader.clone());
  546. break;
  547. default:
  548. throw new hdf5.Error('Unsupported message type \'' + type + '\'.');
  549. }
  550. reader.seek(size);
  551. return true;
  552. }
  553. };
  554. hdf5.Message = class {
  555. constructor(type, data, flags) {
  556. this._type = type;
  557. this._data = data;
  558. this._flags = flags;
  559. }
  560. };
  561. hdf5.Datatype = class {
  562. constructor(reader) {
  563. var format = reader.byte();
  564. var version = format >> 4;
  565. this._class = format & 0xf;
  566. switch (version) {
  567. case 1:
  568. case 2:
  569. this._flags = reader.byte() | reader.byte() << 8 | reader.byte() << 16;
  570. this._size = reader.uint32();
  571. break;
  572. default:
  573. throw new hdf5.Error('Unsupported datatype version \'' + version + '\'.');
  574. }
  575. }
  576. get type() {
  577. switch (this._class) {
  578. case 0: // fixed-point
  579. throw new hdf5.Error("Unsupported datatype (class=0, size=" + this._size + ", flags=" + this._flags + ").");
  580. case 1: // floating-point
  581. if (this._size == 2 && this._flags == 0x0f20) {
  582. return 'float16';
  583. }
  584. else if (this._size == 4 && this._flags == 0x1f20) {
  585. return 'float32';
  586. }
  587. else if (this._size == 8 && this._flags == 0x3f20) {
  588. return 'float64';
  589. }
  590. break;
  591. case 3: // string
  592. return 'string';
  593. case 5: // opaque
  594. return 'uint8[]';
  595. case 9: // variable-length
  596. if ((this._flags & 0x0f) == 1) { // type
  597. return 'char[]';
  598. }
  599. break;
  600. }
  601. throw new hdf5.Error('Unsupported datatype class \'' + this._class + '\'.');
  602. }
  603. read(reader) {
  604. switch (this._class) {
  605. case 0: // fixed-point
  606. if (this._size == 1) {
  607. return ((this._flags & 0x8) != 0) ? reader.int8() : reader.byte();
  608. }
  609. else if (this._size == 2) {
  610. return ((this._flags & 0x8) != 0) ? reader.int16() : reader.uint16();
  611. }
  612. else if (this._size == 4) {
  613. return ((this._flags & 0x8) != 0) ? reader.int32() : reader.uint32();
  614. }
  615. else if (this._size == 8) {
  616. return ((this._flags & 0x8) != 0) ? reader.int64() : reader.uint64();
  617. }
  618. throw new hdf5.Error('Unsupported fixed-point datatype.');
  619. case 1: // floating-point
  620. if (this._size == 2 && this._flags == 0x0f20) {
  621. return reader.float16();
  622. }
  623. else if (this._size == 4 && this._flags == 0x1f20) {
  624. return reader.float32();
  625. }
  626. else if (this._size == 8 && this._flags == 0x3f20) {
  627. return reader.float64();
  628. }
  629. throw new hdf5.Error('Unsupported floating-point datatype.');
  630. case 3: // string
  631. switch ((this._flags >> 8) & 0x0f) { // character set
  632. case 0:
  633. return hdf5.Reader.decode(reader.bytes(this._size), 'ascii');
  634. case 1:
  635. return hdf5.Reader.decode(reader.bytes(this._size), 'utf-8');
  636. }
  637. throw new hdf5.Error('Unsupported character encoding.');
  638. case 5: // opaque
  639. return reader.bytes(this._size);
  640. case 9: // variable-length
  641. return {
  642. length: reader.uint32(),
  643. globalHeapID: new hdf5.GlobalHeapID(reader)
  644. };
  645. }
  646. throw new hdf5.Error('Unsupported datatype class \'' + this._class + '\'.');
  647. }
  648. decode(data, globalHeap) {
  649. switch (this._class) {
  650. case 0: // fixed-point
  651. return data;
  652. case 1: // floating-point
  653. return data;
  654. case 3: // string
  655. return data;
  656. case 5: // opaque
  657. return data;
  658. case 9: // variable-length
  659. var globalHeapObject = globalHeap.get(data.globalHeapID);
  660. if (globalHeapObject != null) {
  661. var characterSet = (this._flags >> 8) & 0x0f;
  662. switch (characterSet) {
  663. case 0:
  664. return hdf5.Reader.decode(globalHeapObject.data, 'ascii');
  665. case 1:
  666. return hdf5.Reader.decode(globalHeapObject.data, 'utf-8');
  667. }
  668. throw new hdf5.Error('Unsupported character encoding.');
  669. }
  670. break;
  671. default:
  672. throw new hdf5.Error('Unsupported datatype class \'' + this._class + '\'.');
  673. }
  674. return null;
  675. }
  676. };
  677. hdf5.Dataspace = class {
  678. constructor(reader) {
  679. this._sizes = [];
  680. var version = reader.byte();
  681. switch (version) {
  682. case 1:
  683. this._dimensions = reader.byte();
  684. this._flags = reader.byte();
  685. reader.seek(1);
  686. reader.seek(4);
  687. for (var i = 0; i < this._dimensions; i++) {
  688. this._sizes.push(reader.length());
  689. }
  690. if ((this._flags & 0x01) != 0) {
  691. this._maxSizes = [];
  692. for (var j = 0; j < this._dimensions; j++) {
  693. this._maxSizes.push(reader.length());
  694. if (this._maxSizes[j] != this._sizes[j]) {
  695. throw new hdf5.Error('Max size is not supported.');
  696. }
  697. }
  698. }
  699. if ((this._flags & 0x02) != 0) {
  700. throw new hdf5.Error('Permutation indices not supported.');
  701. }
  702. break;
  703. case 2:
  704. this._dimensions = reader.byte();
  705. this._flags = reader.byte();
  706. this._type = reader.byte(); // 0 scalar, 1 simple, 2 null
  707. for (var k = 0; k < this._dimensions; k++) {
  708. this._sizes.push(reader.length());
  709. }
  710. if ((this._flags & 0x01) != 0) {
  711. this._maxSizes = [];
  712. for (var l = 0; l < this._dimensions; l++) {
  713. this._maxSizes.push(reader.length());
  714. }
  715. }
  716. break;
  717. default:
  718. throw new hdf5.Error("Unsupported dataspace message version '" + version + "'.");
  719. }
  720. }
  721. get shape() {
  722. return this._sizes;
  723. }
  724. read(datatype, reader) {
  725. if (this._dimensions == 0) {
  726. return datatype.read(reader);
  727. }
  728. return this.readArray(datatype, reader, this._sizes, 0);
  729. }
  730. readArray(datatype, reader, shape, dimension) {
  731. var array = [];
  732. var size = shape[dimension];
  733. if (dimension == shape.length - 1) {
  734. for (var i = 0; i < size; i++) {
  735. array.push(datatype.read(reader));
  736. }
  737. }
  738. else {
  739. for (var j = 0; j < size; j++) {
  740. array.push(this.readArray(datatype, reader, shape, dimension + 1));
  741. }
  742. }
  743. return array;
  744. }
  745. decode(datatype, data, globalHeap) {
  746. if (this._dimensions == 0) {
  747. return datatype.decode(data, globalHeap);
  748. }
  749. return this.decodeArray(datatype, data, globalHeap, this._sizes, 0);
  750. }
  751. decodeArray(datatype, data, globalHeap, shape, dimension) {
  752. var size = shape[dimension];
  753. if (dimension == shape.length - 1) {
  754. for (var i = 0; i < size; i++) {
  755. data[i] = datatype.decode(data[i], globalHeap);
  756. }
  757. }
  758. else {
  759. for (var j = 0; j < size; j++) {
  760. data[j] = this.decodeArray(datatype, data[j], shape, dimension + 1);
  761. }
  762. }
  763. return data;
  764. }
  765. };
  766. hdf5.LinkInfo = class {
  767. constructor(reader) {
  768. var version = reader.byte();
  769. switch (version) {
  770. case 0:
  771. var flags = reader.byte();
  772. if ((flags & 1) != 0) {
  773. this.maxCreationIndex = reader.uint64();
  774. }
  775. this.fractalHeapAddress = reader.offset();
  776. this.nameIndexTreeAddress = reader.offset();
  777. if ((flags & 2) != 0) {
  778. this.creationOrderIndexTreeAddress = reader.offset();
  779. }
  780. break;
  781. default:
  782. throw new hdf5.Error("Unsupported link info message version '" + version + "'.");
  783. }
  784. }
  785. };
  786. hdf5.FillValue = class {
  787. constructor(reader) {
  788. var version = reader.byte();
  789. switch (version) {
  790. case 2:
  791. reader.byte();
  792. reader.byte();
  793. var valueDefined = reader.byte();
  794. if (valueDefined == 1) {
  795. var size = reader.uint32();
  796. this.data = reader.bytes(size);
  797. }
  798. break;
  799. case 3:
  800. // var flags = reader.byte();
  801. // if ((flags & 0x20) != 0) {
  802. // }
  803. break;
  804. default:
  805. throw new hdf5.Error('Unsupported fill value version \'' + version + '\'.');
  806. }
  807. }
  808. };
  809. hdf5.Link = class {
  810. constructor(reader) {
  811. var version = reader.byte();
  812. switch (version) {
  813. case 1:
  814. var flags = reader.byte();
  815. this.type = (flags & 0x08) != 0 ? reader.byte() : 0;
  816. if ((flags & 0x04) != 0) {
  817. this.creationOrder = reader.uint32();
  818. }
  819. var linkNameEncoding = ((flags & 0x10) != 0 && reader.byte() == 1) ? 'utf-8' : 'ascii';
  820. this.name = reader.string(reader.uint(flags & 0x03), linkNameEncoding);
  821. switch (this.type) {
  822. case 0: // hard link
  823. this.objectHeaderAddress = reader.offset();
  824. break;
  825. case 1: // soft link
  826. break;
  827. }
  828. break;
  829. default:
  830. throw new hdf5.Error('Unsupported link message version \'' + version + '\'.');
  831. }
  832. }
  833. };
  834. hdf5.DataLayout = class {
  835. constructor(reader) {
  836. var version = reader.byte();
  837. switch (version) {
  838. case 3:
  839. var layoutClass = reader.byte();
  840. switch (layoutClass) {
  841. case 1: // Contiguous Storage
  842. this.address = reader.offset();
  843. this.size = reader.length();
  844. break;
  845. default:
  846. throw new hdf5.Error('Unsupported data layout class \'' + layoutClass + '\'.');
  847. }
  848. break;
  849. default:
  850. throw new hdf5.Error('Unsupported data layout version \'' + version + '\'.');
  851. }
  852. }
  853. };
  854. hdf5.GroupInfo = class {
  855. constructor(reader) {
  856. var version = reader.byte();
  857. switch (version) {
  858. case 0:
  859. var flags = reader.byte();
  860. if ((flags & 0x01) != 0) {
  861. this.maxCompactLinks = reader.uint16();
  862. this.minDenseLinks = reader.uint16();
  863. }
  864. if ((flags & 0x02) != 0) {
  865. this.estimatedEntriesNumber = reader.uint16();
  866. this.estimatedLinkNameLengthEntires = reader.uint16();
  867. }
  868. break;
  869. default:
  870. throw new hdf5.Error('Unsupported group info version \'' + version + '\'.');
  871. }
  872. }
  873. };
  874. hdf5.Attribute = class {
  875. constructor(reader) {
  876. var version = reader.byte();
  877. switch (version) {
  878. case 1:
  879. this.constructor_v1(reader);
  880. break;
  881. case 3:
  882. this.constructor_v3(reader);
  883. break;
  884. default:
  885. throw new hdf5.Error('Unsupported attribute message version \'' + version + '\'.');
  886. }
  887. }
  888. constructor_v1(reader) {
  889. reader.seek(1);
  890. var nameSize = reader.uint16();
  891. var datatypeSize = reader.uint16();
  892. var dataspaceSize = reader.uint16();
  893. this.name = reader.string(nameSize, 'utf-8');
  894. reader.align(8);
  895. this._datatype = new hdf5.Datatype(reader.clone());
  896. reader.seek(datatypeSize);
  897. reader.align(8);
  898. this._dataspace = new hdf5.Dataspace(reader.clone());
  899. reader.seek(dataspaceSize);
  900. reader.align(8);
  901. this._data = this._dataspace.read(this._datatype, reader);
  902. }
  903. constructor_v3(reader) {
  904. reader.byte();
  905. var nameSize = reader.uint16();
  906. var datatypeSize = reader.uint16();
  907. var dataspaceSize = reader.uint16();
  908. var encoding = reader.byte() == 1 ? 'utf-8' : 'ascii';
  909. this.name = reader.string(nameSize, encoding);
  910. this._datatype = new hdf5.Datatype(reader.clone());
  911. reader.seek(datatypeSize);
  912. this._dataspace = new hdf5.Dataspace(reader.clone());
  913. reader.seek(dataspaceSize);
  914. this._data = this._dataspace.read(this._datatype, reader);
  915. }
  916. decodeValue(globalHeap) {
  917. if (this._data) {
  918. return this._dataspace.decode(this._datatype, this._data, globalHeap);
  919. }
  920. return null;
  921. }
  922. };
  923. hdf5.ObjectHeaderContinuation = class {
  924. constructor(reader) {
  925. this.offset = reader.offset();
  926. this.length = reader.length();
  927. }
  928. };
  929. hdf5.SymbolTable = class {
  930. constructor(reader) {
  931. this._treeAddress = reader.offset();
  932. this._heapAddress = reader.offset();
  933. }
  934. };
  935. hdf5.AttributeInfo = class {
  936. constructor(reader) {
  937. var version = reader.byte();
  938. switch (version) {
  939. case 0:
  940. var flags = reader.byte();
  941. if ((flags & 1) != 0) {
  942. this.maxCreationIndex = reader.uint64();
  943. }
  944. this.fractalHeapAddress = reader.offset();
  945. this.attributeNameTreeAddress = reader.offset();
  946. if ((flags & 2) != 0) {
  947. this.attributeCreationOrderTreeAddress = reader.offset();
  948. }
  949. break;
  950. default:
  951. throw new hdf5.Error('Unsupported attribute info message version \'' + version + '\'.');
  952. }
  953. }
  954. };
  955. hdf5.Tree = class {
  956. constructor(reader) {
  957. if (!reader.match('TREE')) {
  958. throw new hdf5.Error("Not a valid 'TREE' block.");
  959. }
  960. var type = reader.byte();
  961. var level = reader.byte();
  962. var entriesUsed = reader.uint16();
  963. reader.offset();
  964. reader.offset();
  965. this.nodes = [];
  966. if (type == 0) {
  967. for (var i = 0; i < entriesUsed; i++) {
  968. reader.length();
  969. var childPointer = reader.offset();
  970. if (level == 0) {
  971. this.nodes.push(new hdf5.SymbolTableNode(reader.move(childPointer)));
  972. }
  973. else {
  974. var tree = new hdf5.Tree(reader.move(childPointer));
  975. tree.nodes.forEach((node) => {
  976. this.nodes.push(node);
  977. });
  978. }
  979. }
  980. }
  981. else {
  982. throw new hdf5.Error('Unsupported B-Tree node type \'' + type + '\'.');
  983. }
  984. }
  985. };
  986. hdf5.Heap = class {
  987. constructor(reader) {
  988. this._reader = reader;
  989. if (!reader.match('HEAP')) {
  990. throw new hdf5.Error("Not a valid 'HEAP' block.");
  991. }
  992. var version = reader.byte();
  993. if (version == 0) {
  994. reader.seek(3);
  995. this._dataSize = reader.length();
  996. this._offsetToHeadOfFreeList = reader.length();
  997. this._dataAddress = reader.offset();
  998. }
  999. else {
  1000. throw new hdf5.Error('Unsupported Local Heap version \'' + version + '\'.');
  1001. }
  1002. }
  1003. getString(offset) {
  1004. var reader = this._reader.move(this._dataAddress + offset);
  1005. return reader.string(-1, 'utf-8');
  1006. }
  1007. };
  1008. hdf5.GlobalHeap = class {
  1009. constructor(reader) {
  1010. this._reader = reader;
  1011. this._collections = {};
  1012. }
  1013. getCollection(address) {
  1014. var globalHeapCollection = this._collections[address];
  1015. if (!globalHeapCollection) {
  1016. globalHeapCollection = new hdf5.GlobalHeapCollection(this._reader.move(address));
  1017. this._collections[address] = globalHeapCollection;
  1018. }
  1019. return globalHeapCollection;
  1020. }
  1021. get(globalHeapID) {
  1022. var globalHeapObject = null;
  1023. var globalHeapCollection = this.getCollection(globalHeapID.address);
  1024. if (globalHeapCollection != null) {
  1025. globalHeapObject = globalHeapCollection.getObject(globalHeapID.objectIndex);
  1026. }
  1027. return globalHeapObject;
  1028. }
  1029. };
  1030. hdf5.GlobalHeapCollection = class {
  1031. constructor(reader) {
  1032. var startPosition = reader.position;
  1033. if (!reader.match('GCOL')) {
  1034. throw new hdf5.Error("Not a valid 'GCOL' block.");
  1035. }
  1036. var version = reader.byte();
  1037. if (version == 1) {
  1038. reader.seek(3);
  1039. this._objects = {};
  1040. var size = reader.length();
  1041. var endPosition = startPosition + size;
  1042. while (reader.position < endPosition) {
  1043. var index = reader.uint16();
  1044. if (index == 0) {
  1045. break;
  1046. }
  1047. var heapObject = new hdf5.GlobalHeapObject(reader);
  1048. this._objects[index] = heapObject;
  1049. reader.align(8);
  1050. }
  1051. }
  1052. else {
  1053. throw new hdf5.Error('Unsupported global heap collection version \'' + version + '\'.');
  1054. }
  1055. }
  1056. getObject(objectIndex) {
  1057. var globalHeapObject = this._objects[objectIndex];
  1058. if (globalHeapObject) {
  1059. return globalHeapObject;
  1060. }
  1061. return null;
  1062. }
  1063. };
  1064. hdf5.GlobalHeapObject = class {
  1065. constructor(reader) {
  1066. reader.uint16();
  1067. reader.seek(4);
  1068. var size = reader.length();
  1069. this.data = reader.bytes(size);
  1070. }
  1071. };
  1072. hdf5.GlobalHeapID = class {
  1073. constructor(reader) {
  1074. this.address = reader.offset();
  1075. this.objectIndex = reader.uint32();
  1076. }
  1077. };
  1078. hdf5.Error = class extends Error {
  1079. constructor(message) {
  1080. super(message);
  1081. this.name = 'HDF5 Error';
  1082. }
  1083. };
  1084. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  1085. module.exports.File = hdf5.File;
  1086. }