hdf5.js 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457
  1. /* jshint esversion: 6 */
  2. // Experimental HDF5 JavaScript reader
  3. var hdf5 = hdf5 || {};
  4. var zip = zip || require('./zip');
  5. hdf5.File = class {
  6. constructor(buffer) {
  7. // https://support.hdfgroup.org/HDF5/doc/H5.format.html
  8. const reader = new hdf5.Reader(buffer, 0);
  9. this._globalHeap = new hdf5.GlobalHeap(reader);
  10. if (!reader.match('\x89HDF\r\n\x1A\n')) {
  11. throw new hdf5.Error('Not a valid HDF5 file.');
  12. }
  13. const version = reader.byte();
  14. switch (version) {
  15. case 0:
  16. case 1: {
  17. this._freeSpaceStorageVersion = reader.byte();
  18. this._rootGroupEntryVersion = reader.byte();
  19. reader.skip(1);
  20. this._sharedHeaderMessageVersionFormat = reader.byte();
  21. reader.initialize();
  22. reader.skip(1);
  23. this._groupLeafNodeK = reader.uint16(); // 0x04?
  24. this._groupInternalNodeK = reader.uint16(); // 0x10?
  25. reader.skip(4);
  26. if (version > 0) {
  27. this._indexedStorageInternalNodeK = reader.uint16();
  28. this.seek(2); // Reserved
  29. }
  30. this._baseAddress = reader.offset();
  31. reader.offset(); // Address of File Free space Info
  32. this._endOfFileAddress = reader.offset();
  33. reader.offset(); // Driver Information Block Address
  34. if (this._baseAddress != 0) {
  35. throw new hdf5.Error('Base address is not zero.');
  36. }
  37. const rootGroupEntry = new hdf5.SymbolTableEntry(reader);
  38. this._rootGroup = new hdf5.Group(reader, rootGroupEntry, null, this._globalHeap, '', '');
  39. break;
  40. }
  41. case 2:
  42. case 3: {
  43. reader.initialize();
  44. reader.byte();
  45. this._baseAddress = reader.offset();
  46. this._superBlockExtensionAddress = reader.offset();
  47. this._endOfFileAddress = reader.offset();
  48. const rootGroupObjectHeader = new hdf5.DataObjectHeader(reader.at(reader.offset()));
  49. this._rootGroup = new hdf5.Group(reader, null, rootGroupObjectHeader, this._globalHeap, '', '');
  50. break;
  51. }
  52. default:
  53. throw new hdf5.Error('Unsupported Superblock version ' + version + '.');
  54. }
  55. }
  56. get rootGroup() {
  57. return this._rootGroup;
  58. }
  59. };
  60. hdf5.Group = class {
  61. constructor(reader, entry, objectHeader, globalHeap, parentPath, name) {
  62. this._reader = reader;
  63. this._entry = entry;
  64. this._dataObjectHeader = objectHeader;
  65. this._globalHeap = globalHeap;
  66. this._name = name;
  67. this._path = parentPath == '/' ? (parentPath + name) : (parentPath + '/' + name);
  68. }
  69. get name() {
  70. return this._name;
  71. }
  72. get path() {
  73. return this._path;
  74. }
  75. group(path) {
  76. this._decodeGroups();
  77. const index = path.indexOf('/');
  78. if (index != -1) {
  79. const childPath = path.substring(index + 1);
  80. const subPath = path.substring(0, index);
  81. const subGroup = this.group(subPath);
  82. if (subGroup != null) {
  83. return subGroup.group(childPath);
  84. }
  85. }
  86. else {
  87. const group = this._groupMap[path];
  88. if (group) {
  89. return group;
  90. }
  91. }
  92. return null;
  93. }
  94. get groups() {
  95. this._decodeGroups();
  96. return this._groups;
  97. }
  98. attribute(name) {
  99. this._decodeDataObject();
  100. return this._attributes[name];
  101. }
  102. get attributes() {
  103. this._decodeDataObject();
  104. return this._attributes;
  105. }
  106. get value() {
  107. this._decodeDataObject();
  108. return this._value;
  109. }
  110. _decodeDataObject() {
  111. if (!this._dataObjectHeader) {
  112. this._dataObjectHeader = new hdf5.DataObjectHeader(this._reader.at(this._entry.objectHeaderAddress));
  113. }
  114. if (!this._attributes) {
  115. this._attributes = {};
  116. for (const attribute of this._dataObjectHeader.attributes) {
  117. const name = attribute.name;
  118. const value = attribute.decodeValue(this._globalHeap);
  119. this._attributes[name] = value;
  120. }
  121. this._value = null;
  122. const datatype = this._dataObjectHeader.datatype;
  123. const dataspace = this._dataObjectHeader.dataspace;
  124. const dataLayout = this._dataObjectHeader.dataLayout;
  125. const filterPipeline = this._dataObjectHeader.filterPipeline;
  126. if (datatype && dataspace && dataLayout) {
  127. this._value = new hdf5.Variable(this._reader, this._globalHeap, datatype, dataspace, dataLayout, filterPipeline);
  128. }
  129. }
  130. }
  131. _decodeGroups() {
  132. if (!this._groups) {
  133. this._groupMap = {};
  134. this._groups = [];
  135. if (this._entry) {
  136. if (this._entry.treeAddress || this._entry.heapAddress) {
  137. const heap = new hdf5.Heap(this._reader.at(this._entry.heapAddress));
  138. const tree = new hdf5.Tree(this._reader.at(this._entry.treeAddress));
  139. for (const node of tree.nodes) {
  140. for (const entry of node.entries) {
  141. const name = heap.getString(entry.linkNameOffset);
  142. const group = new hdf5.Group(this._reader, entry, null, this._globalHeap, this._path, name);
  143. this._groups.push(group);
  144. this._groupMap[name] = group;
  145. }
  146. }
  147. }
  148. }
  149. else {
  150. this._decodeDataObject();
  151. for (const link of this._dataObjectHeader.links) {
  152. if (Object.prototype.hasOwnProperty.call(link, 'objectHeaderAddress')) {
  153. const name = link.name;
  154. const objectHeader = new hdf5.DataObjectHeader(this._reader.at(link.objectHeaderAddress));
  155. const linkGroup = new hdf5.Group(this._reader, null, objectHeader, this._globalHeap, this._path, name);
  156. this._groups.push(linkGroup);
  157. this._groupMap[name] = linkGroup;
  158. }
  159. }
  160. }
  161. }
  162. }
  163. };
  164. hdf5.Variable = class {
  165. constructor(reader, globalHeap, datatype, dataspace, dataLayout, filterPipeline) {
  166. this._reader = reader;
  167. this._globalHeap = globalHeap;
  168. this._datatype = datatype;
  169. this._dataspace = dataspace;
  170. this._dataLayout = dataLayout;
  171. this._filterPipeline = filterPipeline;
  172. }
  173. get type () {
  174. return this._datatype.type;
  175. }
  176. get littleEndian() {
  177. return this._datatype.littleEndian;
  178. }
  179. get shape() {
  180. return this._dataspace.shape;
  181. }
  182. get value() {
  183. const data = this.data;
  184. if (data) {
  185. const reader = new hdf5.Reader(data);
  186. const array = this._dataspace.read(this._datatype, reader);
  187. return this._dataspace.decode(this._datatype, array, array, this._globalHeap);
  188. }
  189. return null;
  190. }
  191. get data() {
  192. switch (this._dataLayout.layoutClass) {
  193. case 1: // Contiguous
  194. if (this._dataLayout.address) {
  195. return this._reader.at(this._dataLayout.address).bytes(this._dataLayout.size);
  196. }
  197. break;
  198. case 2: { // Chunked
  199. const tree = new hdf5.Tree(this._reader.at(this._dataLayout.address), this._dataLayout.dimensionality);
  200. if (this._dataLayout.dimensionality == 2 && this._dataspace.shape.length == 1) {
  201. let size = this._dataLayout.datasetElementSize;
  202. for (let i = 0; i < this._dataspace.shape.length; i++) {
  203. size *= this._dataspace.shape[i];
  204. }
  205. const data = new Uint8Array(size);
  206. for (const node of tree.nodes) {
  207. if (node.fields.length !== 2 || node.fields[1] !== 0) {
  208. return null;
  209. }
  210. if (node.filterMask !== 0) {
  211. return null;
  212. }
  213. const start = node.fields[0] * this._dataLayout.datasetElementSize;
  214. let chunk = node.data;
  215. if (this._filterPipeline) {
  216. for (const filter of this._filterPipeline.filters) {
  217. chunk = filter.decode(chunk);
  218. }
  219. }
  220. for (let i = 0; i < chunk.length; i++) {
  221. data[start + i] = chunk[i];
  222. }
  223. }
  224. return data;
  225. }
  226. break;
  227. }
  228. default: {
  229. throw new hdf5.Error("Unknown data layout class '" + this.layoutClass + "'.");
  230. }
  231. }
  232. return null;
  233. }
  234. };
  235. hdf5.Reader = class {
  236. constructor(buffer) {
  237. if (buffer) {
  238. this._buffer = buffer;
  239. this._dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  240. this._position = 0;
  241. this._offset = 0;
  242. }
  243. }
  244. initialize() {
  245. this._offsetSize = this.byte();
  246. this._lengthSize = this.byte();
  247. }
  248. skip(offset) {
  249. this._offset += offset;
  250. if (this._position + this._offset > this._buffer.length) {
  251. throw new hdf5.Error('Expected ' + (this._position + this._offset - this._buffer.length) + ' more bytes. The file might be corrupted. Unexpected end of file.');
  252. }
  253. }
  254. int8() {
  255. const offset = this._offset;
  256. this.skip(1);
  257. return this._dataView.getInt8(this._position + offset);
  258. }
  259. byte() {
  260. const offset = this._offset;
  261. this.skip(1);
  262. return this._dataView.getUint8(this._position + offset);
  263. }
  264. bytes(length) {
  265. const offset = this._offset;
  266. this.skip(length);
  267. return this._buffer.subarray(this._position + offset, this._position + this._offset);
  268. }
  269. int16() {
  270. const offset = this._position + this._offset;
  271. this.skip(2);
  272. return this._dataView.getInt16(offset, true);
  273. }
  274. uint16() {
  275. const offset = this._position + this._offset;
  276. this.skip(2);
  277. return this._dataView.getUint16(offset, true);
  278. }
  279. int32() {
  280. const offset = this._position + this._offset;
  281. this.skip(4);
  282. return this._dataView.getInt32(offset, true);
  283. }
  284. uint32() {
  285. const offset = this._position + this._offset;
  286. this.skip(4);
  287. return this._dataView.getUint32(offset, true);
  288. }
  289. int64() {
  290. const offset = this._position + this._offset;
  291. this.skip(8);
  292. return this._dataView.getInt64(offset, true).toNumber();
  293. }
  294. uint64() {
  295. const offset = this._position + this._offset;
  296. this.skip(8);
  297. return this._dataView.getUint64(offset, true).toNumber();
  298. }
  299. uint(type) {
  300. switch (type) {
  301. case 0: return this.byte();
  302. case 1: return this.uint16();
  303. case 2: return this.uint32();
  304. case 3: return this.uint64();
  305. }
  306. }
  307. float16() {
  308. const offset = this._offset;
  309. this.skip(2);
  310. const value = this._dataView.getUint16(this._position + offset, true);
  311. // decode float16 value
  312. const s = (value & 0x8000) >> 15;
  313. const e = (value & 0x7C00) >> 10;
  314. const f = value & 0x03FF;
  315. if(e == 0) {
  316. return (s ? -1 : 1) * Math.pow(2, -14) * (f / Math.pow(2, 10));
  317. }
  318. else if (e == 0x1F) {
  319. return f ? NaN : ((s ? -1 : 1) * Infinity);
  320. }
  321. return (s ? -1 : 1) * Math.pow(2, e-15) * (1 + (f / Math.pow(2, 10)));
  322. }
  323. float32() {
  324. const offset = this._position + this._offset;
  325. this.skip(4);
  326. return this._dataView.getFloat32(offset, true);
  327. }
  328. float64() {
  329. const offset = this._position + this._offset;
  330. this.skip(8);
  331. return this._dataView.getFloat64(offset, true);
  332. }
  333. string(size, encoding) {
  334. if (!size || size == -1) {
  335. let position = this._position + this._offset;
  336. while (this._buffer[position] != 0) {
  337. position++;
  338. }
  339. size = position - this._position - this._offset + 1;
  340. }
  341. const data = this.bytes(size);
  342. return hdf5.Reader.decode(data, encoding);
  343. }
  344. static decode(data, encoding) {
  345. let text = '';
  346. if (encoding == 'utf-8') {
  347. if (!hdf5.Reader._utf8Decoder) {
  348. hdf5.Reader._utf8Decoder = new TextDecoder('utf-8');
  349. }
  350. text = hdf5.Reader._utf8Decoder.decode(data);
  351. }
  352. else {
  353. if (!hdf5.Reader._asciiDecoder) {
  354. hdf5.Reader._asciiDecoder = new TextDecoder('ascii');
  355. }
  356. text = hdf5.Reader._asciiDecoder.decode(data);
  357. }
  358. return text.replace(/\0/g, '');
  359. }
  360. offset() {
  361. switch (this._offsetSize) {
  362. case 8: {
  363. const position = this._position + this._offset;
  364. this.skip(8);
  365. const value = this._dataView.getUint64(position, true);
  366. if (value.low === -1 && value.high === -1) {
  367. return undefined;
  368. }
  369. return value.toNumber();
  370. }
  371. case 4: {
  372. const value = this.uint32();
  373. if (value === 0xffffffff) {
  374. return undefined;
  375. }
  376. return value;
  377. }
  378. }
  379. throw new hdf5.Error('Unsupported offset size \'' + this._offsetSize + '\'.');
  380. }
  381. length() {
  382. switch (this._lengthSize) {
  383. case 8: {
  384. const position = this._position + this._offset;
  385. this.skip(8);
  386. const value = this._dataView.getUint64(position, true);
  387. if (value.low === -1 && value.high === -1) {
  388. return undefined;
  389. }
  390. return value.toNumber();
  391. }
  392. case 4: {
  393. const value = this.uint32();
  394. if (value === 0xffffffff) {
  395. return undefined;
  396. }
  397. return value;
  398. }
  399. }
  400. throw new hdf5.Error('Unsupported length size \'' + this._lengthSize + '\'.');
  401. }
  402. at(position) {
  403. const reader = new hdf5.Reader(null);
  404. reader._buffer = this._buffer;
  405. reader._dataView = this._dataView;
  406. reader._position = position;
  407. reader._offset = 0;
  408. reader._offsetSize = this._offsetSize;
  409. reader._lengthSize = this._lengthSize;
  410. return reader;
  411. }
  412. clone() {
  413. const reader = new hdf5.Reader(this._buffer, this._position);
  414. reader._buffer = this._buffer;
  415. reader._dataView = this._dataView;
  416. reader._position = this._position;
  417. reader._offset = this._offset;
  418. reader._offsetSize = this._offsetSize;
  419. reader._lengthSize = this._lengthSize;
  420. return reader;
  421. }
  422. align(mod) {
  423. if (this._offset % mod != 0) {
  424. this._offset = (Math.floor(this._offset / mod) + 1) * mod;
  425. }
  426. }
  427. match(text) {
  428. if (this._position + this._offset + text.length > this._buffer.length) {
  429. return false;
  430. }
  431. const offset = this._offset;
  432. const buffer = this.bytes(text.length);
  433. for (let i = 0; i < text.length; i++) {
  434. if (text.charCodeAt(i) != buffer[i]) {
  435. this._offset = offset;
  436. return false;
  437. }
  438. }
  439. return true;
  440. }
  441. get position() {
  442. return this._position + this._offset;
  443. }
  444. get size() {
  445. return this._buffer.length;
  446. }
  447. };
  448. hdf5.SymbolTableNode = class {
  449. constructor(reader) {
  450. if (!reader.match('SNOD')) {
  451. throw new hdf5.Error("Not a valid 'SNOD' block.");
  452. }
  453. const version = reader.byte();
  454. if (version == 1) {
  455. reader.skip(1);
  456. const entriesUsed = reader.uint16();
  457. this.entries = [];
  458. for (let i = 0; i < entriesUsed; i++) {
  459. this.entries.push(new hdf5.SymbolTableEntry(reader));
  460. }
  461. }
  462. else {
  463. throw new hdf5.Error('Unsupported symbol table node version \'' + version + '\'.');
  464. }
  465. }
  466. };
  467. hdf5.SymbolTableEntry = class {
  468. constructor(reader) {
  469. this.linkNameOffset = reader.offset();
  470. this.objectHeaderAddress = reader.offset();
  471. const cacheType = reader.uint32();
  472. reader.skip(4); // Reserved
  473. switch (cacheType) {
  474. case 0:
  475. break;
  476. case 1: {
  477. const scratchReader = reader.clone();
  478. this.treeAddress = scratchReader.offset();
  479. this.heapAddress = scratchReader.offset();
  480. break;
  481. }
  482. default:
  483. throw new hdf5.Error('Unsupported cache type \'' + cacheType + '\'.');
  484. }
  485. reader.skip(16); // Scratch-pad space
  486. }
  487. };
  488. hdf5.DataObjectHeader = class {
  489. constructor(reader) {
  490. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#ObjectHeader
  491. this.attributes = [];
  492. this.links = [];
  493. this.continuations = [];
  494. const version = reader.match('OHDR') ? reader.byte() : reader.byte();
  495. switch (version) {
  496. case 1: {
  497. reader.skip(1);
  498. const messageCount = reader.uint16();
  499. reader.uint32();
  500. const objectHeaderSize = reader.uint32();
  501. reader.align(8);
  502. let end = reader.position + objectHeaderSize;
  503. for (let i = 0; i < messageCount; i++) {
  504. const messageType = reader.uint16();
  505. const messageSize = reader.uint16();
  506. const messageFlags = reader.byte();
  507. reader.skip(3);
  508. reader.align(8);
  509. const next = this._readMessage(reader, messageType, messageSize, messageFlags);
  510. if ((!next || reader.position >= end) && this.continuations.length > 0) {
  511. const continuation = this.continuations.shift();
  512. reader = reader.at(continuation.offset);
  513. end = continuation.offset + continuation.length;
  514. }
  515. else {
  516. reader.align(8);
  517. }
  518. }
  519. break;
  520. }
  521. case 2: {
  522. const flags = reader.byte();
  523. if ((flags & 0x20) != 0) {
  524. reader.uint32();
  525. reader.uint32();
  526. reader.uint32();
  527. reader.uint32();
  528. }
  529. if ((flags & 0x10) != 0) {
  530. reader.uint16();
  531. reader.uint16();
  532. }
  533. const size = reader.uint(flags & 0x03);
  534. let next = true;
  535. let end = reader.position + size;
  536. while (next && reader.position < end) {
  537. const messageType = reader.byte();
  538. const messageSize = reader.uint16();
  539. const messageFlags = reader.byte();
  540. if (reader.position < end) {
  541. if ((flags & 0x04) != 0) {
  542. reader.uint16();
  543. }
  544. next = this._readMessage(reader, messageType, messageSize, messageFlags);
  545. }
  546. if ((!next || reader.position >= end) && this.continuations.length > 0) {
  547. const continuation = this.continuations.shift();
  548. reader = reader.at(continuation.offset);
  549. end = continuation.offset + continuation.length;
  550. if (!reader.match('OCHK')) {
  551. throw new hdf5.Error("Invalid continuation block signature.");
  552. }
  553. next = true;
  554. }
  555. }
  556. break;
  557. }
  558. default: {
  559. throw new hdf5.Error('Unsupported data object header version \'' + version + '\'.');
  560. }
  561. }
  562. }
  563. _readMessage(reader, type, size, flags) {
  564. switch(type) {
  565. case 0x0000: // NIL
  566. return false;
  567. case 0x0001: // Dataspace
  568. this.dataspace = (size != 4 || flags != 1) ? new hdf5.Dataspace(reader.clone()) : null;
  569. break;
  570. case 0x0002: // Link Info
  571. this.linkInfo = new hdf5.LinkInfo(reader.clone());
  572. break;
  573. case 0x0003: // Datatype
  574. this.datatype = new hdf5.Datatype(reader.clone());
  575. break;
  576. case 0x0004:
  577. case 0x0005: // Fill Value
  578. this.fillValue = new hdf5.FillValue(reader.clone(), type);
  579. break;
  580. case 0x0006: // Link
  581. this.links.push(new hdf5.Link(reader.clone()));
  582. break;
  583. case 0x0008: // Data Layout
  584. this.dataLayout = new hdf5.DataLayout(reader.clone());
  585. break;
  586. case 0x000A: // Group Info
  587. this.groupInfo = new hdf5.GroupInfo(reader.clone());
  588. break;
  589. case 0x000B: // Filter Pipeline
  590. this.filterPipeline = new hdf5.FilterPipeline(reader.clone());
  591. break;
  592. case 0x000C: // Attribute
  593. this.attributes.push(new hdf5.Attribute(reader.clone()));
  594. break;
  595. case 0x000D: // Object Comment Message
  596. this.comment = reader.string(-1, 'ascii');
  597. break;
  598. case 0x0010: // Object Header Continuation
  599. this.continuations.push(new hdf5.ObjectHeaderContinuation(reader.clone()));
  600. break;
  601. case 0x0011: // Symbol Table
  602. this.symbolTable = new hdf5.SymbolTable(reader.clone());
  603. break;
  604. case 0x000E: // Object Modification Time (Old)
  605. case 0x0012: // Object Modification Time
  606. this.objectModificationTime = new hdf5.ObjectModificationTime(reader.clone(), type);
  607. break;
  608. case 0x0015: // Attribute Info
  609. this.attributeInfo = new hdf5.AttributeInfo(reader.clone());
  610. break;
  611. default:
  612. throw new hdf5.Error('Unsupported message type \'' + type + '\'.');
  613. }
  614. reader.skip(size);
  615. return true;
  616. }
  617. };
  618. hdf5.Message = class {
  619. constructor(type, data, flags) {
  620. this._type = type;
  621. this._data = data;
  622. this._flags = flags;
  623. }
  624. };
  625. hdf5.Dataspace = class {
  626. constructor(reader) {
  627. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#DataspaceMessage
  628. this._sizes = [];
  629. const version = reader.byte();
  630. switch (version) {
  631. case 1:
  632. this._dimensions = reader.byte();
  633. this._flags = reader.byte();
  634. reader.skip(1);
  635. reader.skip(4);
  636. for (let i = 0; i < this._dimensions; i++) {
  637. this._sizes.push(reader.length());
  638. }
  639. if ((this._flags & 0x01) != 0) {
  640. this._maxSizes = [];
  641. for (let j = 0; j < this._dimensions; j++) {
  642. this._maxSizes.push(reader.length());
  643. if (this._maxSizes[j] != this._sizes[j]) {
  644. throw new hdf5.Error('Max size is not supported.');
  645. }
  646. }
  647. }
  648. if ((this._flags & 0x02) != 0) {
  649. throw new hdf5.Error('Permutation indices not supported.');
  650. }
  651. break;
  652. case 2:
  653. this._dimensions = reader.byte();
  654. this._flags = reader.byte();
  655. this._type = reader.byte(); // 0 scalar, 1 simple, 2 null
  656. for (let k = 0; k < this._dimensions; k++) {
  657. this._sizes.push(reader.length());
  658. }
  659. if ((this._flags & 0x01) != 0) {
  660. this._maxSizes = [];
  661. for (let l = 0; l < this._dimensions; l++) {
  662. this._maxSizes.push(reader.length());
  663. }
  664. }
  665. break;
  666. default:
  667. throw new hdf5.Error("Unsupported dataspace message version '" + version + "'.");
  668. }
  669. }
  670. get shape() {
  671. return this._sizes;
  672. }
  673. read(datatype, reader) {
  674. if (this._dimensions == 0) {
  675. return datatype.read(reader);
  676. }
  677. return this._readArray(datatype, reader, this._sizes, 0);
  678. }
  679. _readArray(datatype, reader, shape, dimension) {
  680. const array = [];
  681. const size = shape[dimension];
  682. if (dimension == shape.length - 1) {
  683. for (let i = 0; i < size; i++) {
  684. array.push(datatype.read(reader));
  685. }
  686. }
  687. else {
  688. for (let j = 0; j < size; j++) {
  689. array.push(this._readArray(datatype, reader, shape, dimension + 1));
  690. }
  691. }
  692. return array;
  693. }
  694. decode(datatype, data, globalHeap) {
  695. if (this._dimensions == 0) {
  696. return datatype.decode(data, globalHeap);
  697. }
  698. return this._decodeArray(datatype, data, globalHeap, this._sizes, 0);
  699. }
  700. _decodeArray(datatype, data, globalHeap, shape, dimension) {
  701. const size = shape[dimension];
  702. if (dimension == shape.length - 1) {
  703. for (let i = 0; i < size; i++) {
  704. data[i] = datatype.decode(data[i], globalHeap);
  705. }
  706. }
  707. else {
  708. for (let j = 0; j < size; j++) {
  709. data[j] = this._decodeArray(datatype, data[j], shape, dimension + 1);
  710. }
  711. }
  712. return data;
  713. }
  714. };
  715. hdf5.LinkInfo = class {
  716. constructor(reader) {
  717. const version = reader.byte();
  718. switch (version) {
  719. case 0: {
  720. const flags = reader.byte();
  721. if ((flags & 1) != 0) {
  722. this.maxCreationIndex = reader.uint64();
  723. }
  724. this.fractalHeapAddress = reader.offset();
  725. this.nameIndexTreeAddress = reader.offset();
  726. if ((flags & 2) != 0) {
  727. this.creationOrderIndexTreeAddress = reader.offset();
  728. }
  729. break;
  730. }
  731. default:
  732. throw new hdf5.Error("Unsupported link info message version '" + version + "'.");
  733. }
  734. }
  735. };
  736. hdf5.Datatype = class {
  737. constructor(reader) {
  738. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#DatatypeMessage
  739. const format = reader.byte();
  740. const version = format >> 4;
  741. this._class = format & 0xf;
  742. switch (version) {
  743. case 1:
  744. case 2: {
  745. this._flags = reader.byte() | reader.byte() << 8 | reader.byte() << 16;
  746. this._size = reader.uint32();
  747. switch (this._class) {
  748. case 0: {
  749. this._bitOffset = reader.uint16();
  750. this._bitPrecision = reader.uint16();
  751. break;
  752. }
  753. case 8: {
  754. this._base = new hdf5.Datatype(reader);
  755. this._names = [];
  756. this._values = [];
  757. const count = this._flags & 0xffff;
  758. for (let i = 0; i < count; i++) {
  759. const name = reader.clone().string(-1, 'ascii');
  760. this._names.push(name);
  761. reader.skip(Math.round((name.length + 1) / 8) * 8);
  762. }
  763. for (let i = 0; i < count; i++) {
  764. this._values.push(this._base.read(reader));
  765. }
  766. break;
  767. }
  768. }
  769. break;
  770. }
  771. default:
  772. throw new hdf5.Error('Unsupported datatype version \'' + version + '\'.');
  773. }
  774. }
  775. get type() {
  776. switch (this._class) {
  777. case 0: // fixed-point
  778. if ((this._flags & 0xfff6) === 0) {
  779. if ((this._flags && 0x08) !== 0) {
  780. switch (this._size) {
  781. case 1: return 'int8';
  782. case 2: return 'int16';
  783. case 4: return 'int32';
  784. case 8: return 'int64';
  785. }
  786. }
  787. else {
  788. switch (this._size) {
  789. case 1: return 'uint8';
  790. case 2: return 'uint16';
  791. case 4: return 'uint32';
  792. case 8: return 'uint64';
  793. }
  794. }
  795. }
  796. break;
  797. case 1: // floating-point
  798. if (this._size == 2 && this._flags == 0x0f20) {
  799. return 'float16';
  800. }
  801. else if (this._size == 4 && this._flags == 0x1f20) {
  802. return 'float32';
  803. }
  804. else if (this._size == 8 && this._flags == 0x3f20) {
  805. return 'float64';
  806. }
  807. break;
  808. case 3: // string
  809. return 'string';
  810. case 5: // opaque
  811. return 'uint8[]';
  812. case 8: // enumerated
  813. if (this._base.type === 'int8' &&
  814. this._names.length === 2 && this._names[0] === 'FALSE' && this._names[1] === 'TRUE' &&
  815. this._values.length === 2 && this._values[0] === 0 && this._values[1] === 1) {
  816. return 'boolean';
  817. }
  818. break;
  819. case 9: // variable-length
  820. if ((this._flags & 0x0f) == 1) { // type
  821. return 'char[]';
  822. }
  823. break;
  824. }
  825. throw new hdf5.Error('Unsupported datatype class \'' + this._class + '\'.');
  826. }
  827. get littleEndian() {
  828. switch (this._class) {
  829. case 0: // fixed-point
  830. case 1: // floating-point
  831. return (this.flags & 0x01) == 0;
  832. }
  833. return true;
  834. }
  835. read(reader) {
  836. switch (this._class) {
  837. case 0: // fixed-point
  838. if (this._size == 1) {
  839. return ((this._flags & 0x8) != 0) ? reader.int8() : reader.byte();
  840. }
  841. else if (this._size == 2) {
  842. return ((this._flags & 0x8) != 0) ? reader.int16() : reader.uint16();
  843. }
  844. else if (this._size == 4) {
  845. return ((this._flags & 0x8) != 0) ? reader.int32() : reader.uint32();
  846. }
  847. else if (this._size == 8) {
  848. return ((this._flags & 0x8) != 0) ? reader.int64() : reader.uint64();
  849. }
  850. throw new hdf5.Error('Unsupported fixed-point datatype.');
  851. case 1: // floating-point
  852. if (this._size == 2 && this._flags == 0x0f20) {
  853. return reader.float16();
  854. }
  855. else if (this._size == 4 && this._flags == 0x1f20) {
  856. return reader.float32();
  857. }
  858. else if (this._size == 8 && this._flags == 0x3f20) {
  859. return reader.float64();
  860. }
  861. throw new hdf5.Error('Unsupported floating-point datatype.');
  862. case 3: // string
  863. switch ((this._flags >> 8) & 0x0f) { // character set
  864. case 0:
  865. return hdf5.Reader.decode(reader.bytes(this._size), 'ascii');
  866. case 1:
  867. return hdf5.Reader.decode(reader.bytes(this._size), 'utf-8');
  868. }
  869. throw new hdf5.Error('Unsupported character encoding.');
  870. case 5: // opaque
  871. return reader.bytes(this._size);
  872. case 9: // variable-length
  873. return {
  874. length: reader.uint32(),
  875. globalHeapID: new hdf5.GlobalHeapID(reader)
  876. };
  877. }
  878. throw new hdf5.Error('Unsupported datatype class \'' + this._class + '\'.');
  879. }
  880. decode(data, globalHeap) {
  881. switch (this._class) {
  882. case 0: // fixed-point
  883. return data;
  884. case 1: // floating-point
  885. return data;
  886. case 3: // string
  887. return data;
  888. case 5: // opaque
  889. return data;
  890. case 9: { // variable-length
  891. const globalHeapObject = globalHeap.get(data.globalHeapID);
  892. if (globalHeapObject != null) {
  893. const characterSet = (this._flags >> 8) & 0x0f;
  894. switch (characterSet) {
  895. case 0:
  896. return hdf5.Reader.decode(globalHeapObject.data, 'ascii');
  897. case 1:
  898. return hdf5.Reader.decode(globalHeapObject.data, 'utf-8');
  899. }
  900. throw new hdf5.Error('Unsupported character encoding.');
  901. }
  902. break;
  903. }
  904. default:
  905. throw new hdf5.Error('Unsupported datatype class \'' + this._class + '\'.');
  906. }
  907. return null;
  908. }
  909. };
  910. hdf5.FillValue = class {
  911. constructor(reader, type) {
  912. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#FillValueMessage
  913. switch (type) {
  914. case 0x0004: {
  915. const size = reader.uint32();
  916. this.data = reader.bytes(size);
  917. break;
  918. }
  919. case 0x0005:
  920. default: {
  921. const version = reader.byte();
  922. switch (version) {
  923. case 1:
  924. case 2: {
  925. reader.byte();
  926. reader.byte();
  927. const valueDefined = reader.byte();
  928. if (version === 1 || valueDefined === 1) {
  929. const size = reader.uint32();
  930. this.data = reader.bytes(size);
  931. }
  932. break;
  933. }
  934. default:
  935. throw new hdf5.Error('Unsupported fill value version \'' + version + '\'.');
  936. }
  937. break;
  938. }
  939. }
  940. }
  941. };
  942. hdf5.Link = class {
  943. constructor(reader) {
  944. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#FillValueMessage
  945. const version = reader.byte();
  946. switch (version) {
  947. case 1: {
  948. const flags = reader.byte();
  949. this.type = (flags & 0x08) != 0 ? reader.byte() : 0;
  950. if ((flags & 0x04) != 0) {
  951. this.creationOrder = reader.uint32();
  952. }
  953. const encoding = ((flags & 0x10) != 0 && reader.byte() == 1) ? 'utf-8' : 'ascii';
  954. this.name = reader.string(reader.uint(flags & 0x03), encoding);
  955. switch (this.type) {
  956. case 0: // hard link
  957. this.objectHeaderAddress = reader.offset();
  958. break;
  959. case 1: // soft link
  960. break;
  961. }
  962. break;
  963. }
  964. default:
  965. throw new hdf5.Error('Unsupported link message version \'' + version + '\'.');
  966. }
  967. }
  968. };
  969. hdf5.DataLayout = class {
  970. constructor(reader) {
  971. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#LayoutMessage
  972. const version = reader.byte();
  973. switch (version) {
  974. case 1:
  975. case 2: {
  976. this.dimensionality = reader.byte();
  977. this.layoutClass = reader.byte();
  978. reader.skip(5);
  979. switch (this.layoutClass) {
  980. case 1:
  981. this.address = reader.offset();
  982. this.dimensionSizes = [];
  983. for (let i = 0; i < this.dimensionality - 1; i++) {
  984. this.dimensionSizes.push(reader.int32());
  985. }
  986. break;
  987. case 2: // Chunked
  988. this.address = reader.offset();
  989. this.dimensionSizes = [];
  990. for (let i = 0; i < this.dimensionality - 1; i++) {
  991. this.dimensionSizes.push(reader.int32());
  992. }
  993. this.datasetElementSize = reader.int32();
  994. break;
  995. default:
  996. throw new hdf5.Error('Unsupported data layout class \'' + this.layoutClass + '\'.');
  997. }
  998. break;
  999. }
  1000. case 3: {
  1001. this.layoutClass = reader.byte();
  1002. switch (this.layoutClass) {
  1003. case 1: // Contiguous
  1004. this.address = reader.offset();
  1005. this.size = reader.length();
  1006. break;
  1007. case 2: // Chunked
  1008. this.dimensionality = reader.byte();
  1009. this.address = reader.offset();
  1010. this.dimensionSizes = [];
  1011. for (let i = 0; i < this.dimensionality - 1; i++) {
  1012. this.dimensionSizes.push(reader.int32());
  1013. }
  1014. this.datasetElementSize = reader.int32();
  1015. break;
  1016. case 0: // Compact
  1017. default:
  1018. throw new hdf5.Error('Unsupported data layout class \'' + this.layoutClass + '\'.');
  1019. }
  1020. break;
  1021. }
  1022. default:
  1023. throw new hdf5.Error('Unsupported data layout version \'' + version + '\'.');
  1024. }
  1025. }
  1026. };
  1027. hdf5.GroupInfo = class {
  1028. constructor(reader) {
  1029. const version = reader.byte();
  1030. switch (version) {
  1031. case 0: {
  1032. const flags = reader.byte();
  1033. if ((flags & 0x01) != 0) {
  1034. this.maxCompactLinks = reader.uint16();
  1035. this.minDenseLinks = reader.uint16();
  1036. }
  1037. if ((flags & 0x02) != 0) {
  1038. this.estimatedEntriesNumber = reader.uint16();
  1039. this.estimatedLinkNameLengthEntires = reader.uint16();
  1040. }
  1041. break;
  1042. }
  1043. default:
  1044. throw new hdf5.Error('Unsupported group info version \'' + version + '\'.');
  1045. }
  1046. }
  1047. };
  1048. hdf5.FilterPipeline = class {
  1049. constructor(reader) {
  1050. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#FilterMessage
  1051. const version = reader.byte();
  1052. switch (version) {
  1053. case 1: {
  1054. this.filters = [];
  1055. const numberOfFilters = reader.byte();
  1056. reader.skip(2);
  1057. reader.skip(4);
  1058. for (let i = 0; i < numberOfFilters; i++) {
  1059. this.filters.push(new hdf5.Filter(reader));
  1060. reader.align(8);
  1061. }
  1062. break;
  1063. }
  1064. default:
  1065. throw new hdf5.Error('Unsupported filter pipeline message version \'' + version + '\'.');
  1066. }
  1067. }
  1068. };
  1069. hdf5.Filter = class {
  1070. constructor(reader) {
  1071. this.id = reader.int16();
  1072. const nameLength = reader.int16();
  1073. this.flags = reader.int16();
  1074. const clientDataSize = reader.int16();
  1075. this.name = reader.string(nameLength, 'ascii');
  1076. this.clientData = reader.bytes(clientDataSize * 4);
  1077. }
  1078. decode(data) {
  1079. switch (this.id) {
  1080. case 1: { // gzip
  1081. const rawData = data.subarray(2, data.length); // skip zlib header
  1082. return new zip.Inflater().inflateRaw(rawData);
  1083. }
  1084. default:
  1085. throw hdf5.Error("Unsupported filter '" + this.name + "'.");
  1086. }
  1087. }
  1088. };
  1089. hdf5.Attribute = class {
  1090. constructor(reader) {
  1091. const version = reader.byte();
  1092. switch (version) {
  1093. case 1: {
  1094. reader.skip(1);
  1095. const nameSize = reader.uint16();
  1096. const datatypeSize = reader.uint16();
  1097. const dataspaceSize = reader.uint16();
  1098. this.name = reader.string(nameSize, 'utf-8');
  1099. reader.align(8);
  1100. this._datatype = new hdf5.Datatype(reader.clone());
  1101. reader.skip(datatypeSize);
  1102. reader.align(8);
  1103. this._dataspace = new hdf5.Dataspace(reader.clone());
  1104. reader.skip(dataspaceSize);
  1105. reader.align(8);
  1106. this._data = this._dataspace.read(this._datatype, reader);
  1107. break;
  1108. }
  1109. case 3: {
  1110. reader.byte();
  1111. const nameSize = reader.uint16();
  1112. const datatypeSize = reader.uint16();
  1113. const dataspaceSize = reader.uint16();
  1114. const encoding = reader.byte() == 1 ? 'utf-8' : 'ascii';
  1115. this.name = reader.string(nameSize, encoding);
  1116. this._datatype = new hdf5.Datatype(reader.clone());
  1117. reader.skip(datatypeSize);
  1118. this._dataspace = new hdf5.Dataspace(reader.clone());
  1119. reader.skip(dataspaceSize);
  1120. this._data = this._dataspace.read(this._datatype, reader);
  1121. break;
  1122. }
  1123. default:
  1124. throw new hdf5.Error('Unsupported attribute message version \'' + version + '\'.');
  1125. }
  1126. }
  1127. decodeValue(globalHeap) {
  1128. if (this._data) {
  1129. return this._dataspace.decode(this._datatype, this._data, globalHeap);
  1130. }
  1131. return null;
  1132. }
  1133. };
  1134. hdf5.ObjectHeaderContinuation = class {
  1135. constructor(reader) {
  1136. this.offset = reader.offset();
  1137. this.length = reader.length();
  1138. }
  1139. };
  1140. hdf5.SymbolTable = class {
  1141. constructor(reader) {
  1142. this._treeAddress = reader.offset();
  1143. this._heapAddress = reader.offset();
  1144. }
  1145. };
  1146. hdf5.ObjectModificationTime = class {
  1147. constructor(reader, type) {
  1148. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#ModificationTimeMessage
  1149. switch (type) {
  1150. case 0x000E: {
  1151. this.year = reader.uint32();
  1152. this.month = reader.uint16();
  1153. this.day = reader.uint16();
  1154. this.hour = reader.uint16();
  1155. this.minute = reader.uint16();
  1156. this.second = reader.uint16();
  1157. reader.skip(2);
  1158. break;
  1159. }
  1160. case 0x0012: {
  1161. const version = reader.byte();
  1162. reader.skip(3);
  1163. switch (version) {
  1164. case 1:
  1165. this.timestamp = reader.uint32();
  1166. break;
  1167. default:
  1168. throw new hdf5.Error('Unsupported object modification time message version \'' + version + '\'.');
  1169. }
  1170. break;
  1171. }
  1172. }
  1173. }
  1174. };
  1175. hdf5.AttributeInfo = class {
  1176. constructor(reader) {
  1177. const version = reader.byte();
  1178. switch (version) {
  1179. case 0: {
  1180. const flags = reader.byte();
  1181. if ((flags & 1) != 0) {
  1182. this.maxCreationIndex = reader.uint64();
  1183. }
  1184. this.fractalHeapAddress = reader.offset();
  1185. this.attributeNameTreeAddress = reader.offset();
  1186. if ((flags & 2) != 0) {
  1187. this.attributeCreationOrderTreeAddress = reader.offset();
  1188. }
  1189. break;
  1190. }
  1191. default:
  1192. throw new hdf5.Error('Unsupported attribute info message version \'' + version + '\'.');
  1193. }
  1194. }
  1195. };
  1196. hdf5.Tree = class {
  1197. constructor(reader, dimensionality) {
  1198. // https://support.hdfgroup.org/HDF5/doc/H5.format.html#V1Btrees
  1199. if (!reader.match('TREE')) {
  1200. throw new hdf5.Error("Not a valid 'TREE' block.");
  1201. }
  1202. this.type = reader.byte();
  1203. this.level = reader.byte();
  1204. const entriesUsed = reader.uint16();
  1205. reader.offset(); // address of left sibling
  1206. reader.offset(); // address of right sibling
  1207. this.nodes = [];
  1208. switch (this.type) {
  1209. case 0: // Group nodes
  1210. for (let i = 0; i < entriesUsed; i++) {
  1211. reader.length();
  1212. const childPointer = reader.offset();
  1213. if (this.level == 0) {
  1214. this.nodes.push(new hdf5.SymbolTableNode(reader.at(childPointer)));
  1215. }
  1216. else {
  1217. const tree = new hdf5.Tree(reader.at(childPointer));
  1218. this.nodes = this.nodes.concat(tree.nodes);
  1219. }
  1220. }
  1221. break;
  1222. case 1: // Raw data chunk nodes
  1223. for (let i = 0; i < entriesUsed; i++) {
  1224. const size = reader.int32();
  1225. const filterMask = reader.int32();
  1226. const fields = [];
  1227. for (let j = 0; j < dimensionality; j++) {
  1228. fields.push(reader.uint64());
  1229. }
  1230. const childPointer = reader.offset();
  1231. if (this.level == 0) {
  1232. const data = reader.at(childPointer).bytes(size);
  1233. this.nodes.push({ data: data, fields: fields, filterMask: filterMask });
  1234. }
  1235. else {
  1236. const tree = new hdf5.Tree(reader.at(childPointer), dimensionality);
  1237. this.nodes = this.nodes.concat(tree.nodes);
  1238. }
  1239. }
  1240. break;
  1241. default:
  1242. throw new hdf5.Error('Unsupported B-Tree node type \'' + this.type + '\'.');
  1243. }
  1244. }
  1245. };
  1246. hdf5.Heap = class {
  1247. constructor(reader) {
  1248. this._reader = reader;
  1249. if (!reader.match('HEAP')) {
  1250. throw new hdf5.Error("Not a valid 'HEAP' block.");
  1251. }
  1252. const version = reader.byte();
  1253. switch (version) {
  1254. case 0: {
  1255. reader.skip(3);
  1256. this._dataSize = reader.length();
  1257. this._offsetToHeadOfFreeList = reader.length();
  1258. this._dataAddress = reader.offset();
  1259. break;
  1260. }
  1261. default: {
  1262. throw new hdf5.Error('Unsupported Local Heap version \'' + version + '\'.');
  1263. }
  1264. }
  1265. }
  1266. getString(offset) {
  1267. const reader = this._reader.at(this._dataAddress + offset);
  1268. return reader.string(-1, 'utf-8');
  1269. }
  1270. };
  1271. hdf5.GlobalHeap = class {
  1272. constructor(reader) {
  1273. this._reader = reader;
  1274. this._collections = new Map();
  1275. }
  1276. get(globalHeapID) {
  1277. const address = globalHeapID.address;
  1278. if (!this._collections.has(address)) {
  1279. this._collections.set(address, new hdf5.GlobalHeapCollection(this._reader.at(address)));
  1280. }
  1281. return this._collections.get(globalHeapID.address).getObject(globalHeapID.objectIndex);
  1282. }
  1283. };
  1284. hdf5.GlobalHeapCollection = class {
  1285. constructor(reader) {
  1286. const startPosition = reader.position;
  1287. if (!reader.match('GCOL')) {
  1288. throw new hdf5.Error("Not a valid 'GCOL' block.");
  1289. }
  1290. const version = reader.byte();
  1291. switch (version) {
  1292. case 1: {
  1293. reader.skip(3);
  1294. this._objects = new Map();
  1295. const size = reader.length();
  1296. const endPosition = startPosition + size;
  1297. while (reader.position < endPosition) {
  1298. const index = reader.uint16();
  1299. if (index == 0) {
  1300. break;
  1301. }
  1302. this._objects.set(index, new hdf5.GlobalHeapObject(reader));
  1303. reader.align(8);
  1304. }
  1305. break;
  1306. }
  1307. default: {
  1308. throw new hdf5.Error('Unsupported global heap collection version \'' + version + '\'.');
  1309. }
  1310. }
  1311. }
  1312. getObject(objectIndex) {
  1313. if (this._objects.has(objectIndex)) {
  1314. return this._objects.get(objectIndex);
  1315. }
  1316. return null;
  1317. }
  1318. };
  1319. hdf5.GlobalHeapObject = class {
  1320. constructor(reader) {
  1321. reader.uint16();
  1322. reader.skip(4);
  1323. this.data = reader.bytes(reader.length());
  1324. }
  1325. };
  1326. hdf5.GlobalHeapID = class {
  1327. constructor(reader) {
  1328. this.address = reader.offset();
  1329. this.objectIndex = reader.uint32();
  1330. }
  1331. };
  1332. hdf5.Error = class extends Error {
  1333. constructor(message) {
  1334. super(message);
  1335. this.name = 'HDF5 Error';
  1336. }
  1337. };
  1338. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  1339. module.exports.File = hdf5.File;
  1340. }