zip.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. var zip = {};
  2. var gzip = {};
  3. var zlib = {};
  4. zip.Archive = class {
  5. static open(data, format) {
  6. const stream = data instanceof Uint8Array ? new zip.BinaryReader(data) : data;
  7. if (stream && stream.length > 2) {
  8. const buffer = stream.peek(Math.min(512, stream.length));
  9. if (buffer.length >= 512) {
  10. // Reject tar with Zip content
  11. const sum = buffer.map((value, index) => (index >= 148 && index < 156) ? 32 : value).reduce((a, b) => a + b, 0);
  12. const checksum = parseInt(Array.from(buffer.slice(148, 156)).map((c) => String.fromCharCode(c)).join('').split('\0').shift(), 8);
  13. if (!isNaN(checksum) && sum === checksum) {
  14. return null;
  15. }
  16. }
  17. if ((!format || format === 'zlib') && buffer[0] === 0x78) { // zlib
  18. const check = (buffer[0] << 8) + buffer[1];
  19. if (check % 31 === 0) {
  20. return new zlib.Archive(stream);
  21. }
  22. }
  23. if ((!format || format == 'gzip') && buffer.length > 18 && buffer[0] === 0x1f && buffer[1] === 0x8b) { // gzip
  24. return new gzip.Archive(stream);
  25. }
  26. if (!format || format == 'zip') {
  27. const signature = buffer[0] === 0x50 && buffer[1] === 0x4B;
  28. const position = stream.position;
  29. const seek = (content) => {
  30. let position = stream.length;
  31. do {
  32. position = Math.max(0, position - 66000);
  33. stream.seek(position);
  34. const length = Math.min(stream.length - position, 66000 + 4);
  35. const buffer = stream.read(length);
  36. for (let i = buffer.length - 4; i >= 0; i--) {
  37. if (content[0] === buffer[i] && content[1] === buffer[i + 1] && content[2] === buffer[i + 2] && content[3] === buffer[i + 3]) {
  38. stream.seek(position + i + 4);
  39. return true;
  40. }
  41. }
  42. if (!signature) {
  43. break;
  44. }
  45. }
  46. while (position > 0);
  47. return false;
  48. };
  49. if (!seek([ 0x50, 0x4B, 0x05, 0x06 ])) {
  50. stream.seek(position);
  51. if (!signature) {
  52. return null;
  53. }
  54. throw new zip.Error('End of Zip central directory not found.');
  55. }
  56. const reader = new zip.BinaryReader(stream.read(16));
  57. reader.skip(12);
  58. let offset = reader.uint32(); // central directory offset
  59. if (offset === 0xffffffff || offset > stream.length) {
  60. if (!seek([ 0x50, 0x4B, 0x06, 0x06 ])) {
  61. stream.seek(position);
  62. throw new zip.Error('End of Zip64 central directory not found.');
  63. }
  64. const reader = new zip.BinaryReader(stream.read(52));
  65. reader.skip(44);
  66. offset = reader.uint64();
  67. if (offset === undefined) {
  68. stream.seek(position);
  69. throw new zip.Error('Zip 64-bit central directory offset not supported.');
  70. }
  71. }
  72. if (offset > stream.length) {
  73. stream.seek(position);
  74. throw new zip.Error('Invalid Zip central directory offset.');
  75. }
  76. stream.seek(offset);
  77. const archive = new zip.Archive(stream);
  78. stream.seek(position);
  79. return archive;
  80. }
  81. }
  82. return null;
  83. }
  84. constructor(stream) {
  85. this._entries = new Map();
  86. const headers = [];
  87. const signature = [ 0x50, 0x4B, 0x01, 0x02 ];
  88. while (stream.position + 4 < stream.length && stream.read(4).every((value, index) => value === signature[index])) {
  89. const header = {};
  90. const reader = new zip.BinaryReader(stream.read(42));
  91. reader.uint16(); // version made by
  92. reader.skip(2); // version needed to extract
  93. const flags = reader.uint16();
  94. if ((flags & 1) == 1) {
  95. throw new zip.Error('Encrypted Zip entries not supported.');
  96. }
  97. header.encoding = flags & 0x800 ? 'utf-8' : 'ascii';
  98. header.compressionMethod = reader.uint16();
  99. header.date = reader.uint32(); // date
  100. header.crc32 = reader.uint32(); // crc32
  101. header.compressedSize = reader.uint32();
  102. header.size = reader.uint32();
  103. header.nameLength = reader.uint16(); // file name length
  104. const extraDataLength = reader.uint16();
  105. const commentLength = reader.uint16();
  106. header.disk = reader.uint16(); // disk number start
  107. reader.uint16(); // internal file attributes
  108. reader.uint32(); // external file attributes
  109. header.localHeaderOffset = reader.uint32();
  110. const nameBuffer = stream.read(header.nameLength);
  111. const decoder = new TextDecoder(header.encoding);
  112. header.name = decoder.decode(nameBuffer);
  113. const extraData = stream.read(extraDataLength);
  114. if (extraData.length > 0) {
  115. const reader = new zip.BinaryReader(extraData);
  116. while (reader.position < reader.length) {
  117. const type = reader.uint16();
  118. const length = reader.uint16();
  119. switch (type) {
  120. case 0x0001:
  121. if (header.size === 0xffffffff) {
  122. header.size = reader.uint64();
  123. if (header.size === undefined) {
  124. throw new zip.Error('Zip 64-bit size not supported.');
  125. }
  126. }
  127. if (header.compressedSize === 0xffffffff) {
  128. header.compressedSize = reader.uint64();
  129. if (header.compressedSize === undefined) {
  130. throw new zip.Error('Zip 64-bit compressed size not supported.');
  131. }
  132. }
  133. if (header.localHeaderOffset === 0xffffffff) {
  134. header.localHeaderOffset = reader.uint64();
  135. if (header.localHeaderOffset === undefined) {
  136. throw new zip.Error('Zip 64-bit offset not supported.');
  137. }
  138. }
  139. if (header.disk === 0xffff) {
  140. header.disk = reader.uint32();
  141. }
  142. break;
  143. default:
  144. reader.skip(length);
  145. break;
  146. }
  147. }
  148. }
  149. stream.read(commentLength); // comment
  150. headers.push(header);
  151. }
  152. for (const header of headers) {
  153. if (header.size === 0 && header.name.endsWith('/')) {
  154. continue;
  155. }
  156. const entry = new zip.Entry(stream, header);
  157. this._entries.set(entry.name, entry.stream);
  158. }
  159. }
  160. get entries() {
  161. return this._entries;
  162. }
  163. };
  164. zip.Entry = class {
  165. constructor(stream, header) {
  166. this._name = header.name;
  167. stream.seek(header.localHeaderOffset);
  168. const signature = [ 0x50, 0x4B, 0x03, 0x04 ];
  169. if (stream.position + 4 > stream.length || !stream.read(4).every((value, index) => value === signature[index])) {
  170. this._stream = new zip.ErrorStream(header.size, 'Invalid Zip local file header signature.');
  171. }
  172. else {
  173. const reader = new zip.BinaryReader(stream.read(26));
  174. reader.skip(22);
  175. header.nameLength = reader.uint16();
  176. const extraDataLength = reader.uint16();
  177. header.nameBuffer = stream.read(header.nameLength);
  178. stream.skip(extraDataLength);
  179. const decoder = new TextDecoder(header.encoding);
  180. this._name = decoder.decode(header.nameBuffer);
  181. this._stream = stream.stream(header.compressedSize);
  182. switch (header.compressionMethod) {
  183. case 0: { // stored
  184. if (header.size !== header.compressedSize) {
  185. this._stream = new zip.ErrorStream(header.size, 'Invalid compression size.');
  186. }
  187. break;
  188. }
  189. case 8: { // deflate
  190. this._stream = new zip.InflaterStream(this._stream, header.size);
  191. break;
  192. }
  193. default: {
  194. this._stream = new new zip.ErrorStream(header.size, 'Invalid compression method.');
  195. }
  196. }
  197. }
  198. }
  199. get name() {
  200. return this._name;
  201. }
  202. get stream() {
  203. return this._stream;
  204. }
  205. };
  206. zip.Inflater = class {
  207. inflateRaw(data, length) {
  208. let buffer = null;
  209. if (typeof process === 'object' && typeof process.versions == 'object' && typeof process.versions.node !== 'undefined') {
  210. buffer = require('zlib').inflateRawSync(data);
  211. }
  212. else {
  213. const reader = new zip.BitReader(data);
  214. const writer = length === undefined ? new zip.BlockWriter() : new zip.BufferWriter(length);
  215. if (!zip.Inflater._staticLengthTree) {
  216. zip.Inflater._codeLengths = new Uint8Array(19);
  217. zip.Inflater._codeOrder = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
  218. zip.Inflater._lengthBase = [ 24, 32, 40, 48, 56, 64, 72, 80, 89, 105, 121, 137, 154, 186, 218, 250, 283, 347, 411, 475, 540, 668, 796, 924, 1053, 1309, 1565, 1821, 2064, 7992, 7992, 7992 ];
  219. zip.Inflater._distanceBase = [ 16, 32, 48, 64, 81, 113, 146, 210, 275, 403, 532, 788, 1045, 1557, 2070, 3094, 4119, 6167, 8216, 12312, 16409, 24601, 32794, 49178, 65563, 98331, 131100, 196636, 262173, 393245, 1048560, 1048560 ];
  220. }
  221. let type;
  222. do {
  223. type = reader.bits(3);
  224. switch (type >>> 1) {
  225. case 0: { // uncompressed block
  226. this._copyUncompressedBlock(reader, writer);
  227. break;
  228. }
  229. case 1: { // block with fixed huffman trees
  230. if (!zip.Inflater._staticLengthTree) {
  231. zip.Inflater._staticLengthTree = zip.HuffmanTree.create(new Uint8Array([].concat.apply([], [[144, 8], [112, 9], [24, 7], [8, 8]].map((x) => [...Array(x[0])].map(() => x[1])))));
  232. zip.Inflater._staticDistanceTree = zip.HuffmanTree.create(new Uint8Array([...Array(32)].map(() => 5)));
  233. }
  234. this._lengthTree = zip.Inflater._staticLengthTree;
  235. this._distanceTree = zip.Inflater._staticDistanceTree;
  236. this._inflateBlock(reader, writer);
  237. break;
  238. }
  239. case 2: { // block with dynamic huffman trees
  240. this._decodeTrees(reader);
  241. this._inflateBlock(reader, writer);
  242. break;
  243. }
  244. default: {
  245. throw new zip.Error('Unsupported block type.');
  246. }
  247. }
  248. } while ((type & 1) == 0);
  249. if (length !== undefined && length !== writer.length) {
  250. throw new zip.Error('Invalid uncompressed size.');
  251. }
  252. buffer = writer.toBuffer();
  253. }
  254. if (length !== undefined && length !== buffer.length) {
  255. throw new zip.Error('Invalid uncompressed size.');
  256. }
  257. return buffer;
  258. }
  259. _copyUncompressedBlock(reader, writer) {
  260. const length = reader.uint16();
  261. const inverseLength = reader.uint16();
  262. if (length !== (~inverseLength & 0xffff)) {
  263. throw new zip.Error('Invalid uncompressed block length.');
  264. }
  265. writer.write(reader.read(length));
  266. }
  267. _decodeTrees(reader) {
  268. const hlit = reader.bits(5) + 257;
  269. const hdist = reader.bits(5) + 1;
  270. const hclen = reader.bits(4) + 4;
  271. const codeLengths = zip.Inflater._codeLengths;
  272. for (let i = 0; i < codeLengths.length; i++) {
  273. codeLengths[i] = 0;
  274. }
  275. const codeOrder = zip.Inflater._codeOrder;
  276. for (let i = 0; i < hclen; i++) {
  277. codeLengths[codeOrder[i]] = reader.bits(3);
  278. }
  279. const codeTree = zip.HuffmanTree.create(codeLengths);
  280. const codeMask = codeTree.length - 1;
  281. const lengths = new Uint8Array(hlit + hdist);
  282. let value = 0;
  283. let length = 0;
  284. for (let i = 0; i < hlit + hdist;) {
  285. const code = codeTree[reader.bits16() & codeMask];
  286. reader.position += code & 0x0f;
  287. const literal = code >>> 4;
  288. switch (literal) {
  289. case 16: length = reader.bits(2) + 3; break;
  290. case 17: length = reader.bits(3) + 3; value = 0; break;
  291. case 18: length = reader.bits(7) + 11; value = 0; break;
  292. default: length = 1; value = literal; break;
  293. }
  294. for (; length > 0; length--) {
  295. lengths[i++] = value;
  296. }
  297. }
  298. this._lengthTree = zip.HuffmanTree.create(lengths.subarray(0, hlit));
  299. this._distanceTree = zip.HuffmanTree.create(lengths.subarray(hlit, hlit + hdist));
  300. }
  301. _inflateBlock(reader, writer) {
  302. const lengthTree = this._lengthTree;
  303. const distanceTree = this._distanceTree;
  304. const lengthMask = lengthTree.length - 1;
  305. const distanceMask = distanceTree.length - 1;
  306. const buffer = writer.buffer;
  307. const threshold = writer.threshold !== undefined ? writer.threshold : writer.length;
  308. let position = writer.position;
  309. for (;;) {
  310. if (position > threshold) {
  311. position = writer.push(position);
  312. }
  313. const code = lengthTree[reader.bits16() & lengthMask];
  314. reader.position += code & 0x0f;
  315. const literal = code >>> 4;
  316. if (literal < 256) {
  317. buffer[position++] = literal;
  318. }
  319. else if (literal === 256) {
  320. writer.push(position);
  321. return;
  322. }
  323. else {
  324. let length = literal - 254;
  325. if (literal > 264) {
  326. const lengthBase = zip.Inflater._lengthBase[literal - 257];
  327. length = (lengthBase >>> 3) + reader.bits(lengthBase & 0x07);
  328. }
  329. const code = distanceTree[reader.bits16() & distanceMask];
  330. reader.position += code & 0x0f;
  331. const distanceBase = zip.Inflater._distanceBase[code >>> 4];
  332. const bits = distanceBase & 0x0f;
  333. const distance = (distanceBase >>> 4) + (reader.bits16() & ((1 << bits) - 1));
  334. reader.position += bits;
  335. let offset = position - distance;
  336. for (let i = 0; i < length; i++) {
  337. buffer[position++] = buffer[offset++];
  338. }
  339. }
  340. }
  341. }
  342. };
  343. zip.HuffmanTree = class {
  344. static create(tree) {
  345. let bits = tree[0];
  346. for (let i = 1; i < tree.length; ++i) {
  347. if (tree[i] > bits) {
  348. bits = tree[i];
  349. }
  350. }
  351. // Algorithm from https://github.com/photopea/UZIP.js
  352. let rev15 = zip.HuffmanTree._rev15;
  353. if (!rev15) {
  354. const length = 1 << 15;
  355. rev15 = new Uint16Array(length);
  356. for (let i = 0; i < length; i++) {
  357. let x = i;
  358. x = (((x & 0xaaaaaaaa) >>> 1) | ((x & 0x55555555) << 1));
  359. x = (((x & 0xcccccccc) >>> 2) | ((x & 0x33333333) << 2));
  360. x = (((x & 0xf0f0f0f0) >>> 4) | ((x & 0x0f0f0f0f) << 4));
  361. x = (((x & 0xff00ff00) >>> 8) | ((x & 0x00ff00ff) << 8));
  362. rev15[i] = (((x >>> 16) | (x << 16))) >>> 17;
  363. }
  364. zip.HuffmanTree._rev15 = rev15;
  365. zip.HuffmanTree._bitLengthCounts = new Uint16Array(16);
  366. zip.HuffmanTree._nextCodes = new Uint16Array(16);
  367. }
  368. const length = tree.length;
  369. const bitLengthCounts = zip.HuffmanTree._bitLengthCounts;
  370. for (let i = 0; i < 16; i++) {
  371. bitLengthCounts[i] = 0;
  372. }
  373. for (let i = 0; i < length; i++) {
  374. bitLengthCounts[tree[i]]++;
  375. }
  376. const nextCodes = zip.HuffmanTree._nextCodes;
  377. let code = 0;
  378. bitLengthCounts[0] = 0;
  379. for (let i = 0; i < bits; i++) {
  380. code = (code + bitLengthCounts[i]) << 1;
  381. nextCodes[i + 1] = code;
  382. }
  383. const codes = new Uint16Array(length);
  384. for (let i = 0; i < length; i++) {
  385. const index = tree[i];
  386. if (index !== 0) {
  387. codes[i] = nextCodes[index];
  388. nextCodes[index]++;
  389. }
  390. }
  391. const shift = 15 - bits;
  392. const table = new Uint16Array(1 << bits);
  393. for (let i = 0; i < length; i++) {
  394. const c = tree[i];
  395. if (c !== 0) {
  396. const value = (i << 4) | c;
  397. const rest = bits - c;
  398. let index = codes[i] << rest;
  399. const max = index + (1 << rest);
  400. for (; index != max; index++) {
  401. table[rev15[index] >>> shift] = value;
  402. }
  403. }
  404. }
  405. return table;
  406. }
  407. };
  408. zip.BitReader = class {
  409. constructor(buffer) {
  410. this.buffer = buffer;
  411. this.position = 0;
  412. }
  413. bits(count) {
  414. const offset = (this.position / 8) >> 0;
  415. const shift = (this.position & 7);
  416. this.position += count;
  417. return ((this.buffer[offset] | (this.buffer[offset + 1] << 8)) >>> shift) & ((1 << count) - 1);
  418. }
  419. bits16() {
  420. const offset = (this.position / 8) >> 0;
  421. return ((this.buffer[offset] | (this.buffer[offset + 1] << 8) | (this.buffer[offset + 2] << 16)) >>> (this.position & 7));
  422. }
  423. read(length) {
  424. this.position = (this.position + 7) & ~7; // align
  425. const offset = (this.position / 8) >> 0;
  426. this.position += length * 8;
  427. return this.buffer.subarray(offset, offset + length);
  428. }
  429. uint16() {
  430. this.position = (this.position + 7) & ~7; // align
  431. const offset = (this.position / 8) >> 0;
  432. this.position += 16;
  433. return this.buffer[offset] | (this.buffer[offset + 1] << 8);
  434. }
  435. };
  436. zip.BlockWriter = class {
  437. constructor() {
  438. this.blocks = [];
  439. this.buffer = new Uint8Array(65536);
  440. this.position = 0;
  441. this.length = 0;
  442. this.threshold = 0xf400;
  443. }
  444. push(position) {
  445. this.blocks.push(new Uint8Array(this.buffer.subarray(this.position, position)));
  446. this.length += position - this.position;
  447. this.position = position;
  448. return this._reset();
  449. }
  450. write(buffer) {
  451. this.blocks.push(buffer);
  452. const length = buffer.length;
  453. this.length += length;
  454. if (length > 32768) {
  455. this.buffer.set(buffer.subarray(length - 32768, length), 0);
  456. this.position = 32768;
  457. }
  458. else {
  459. this._reset();
  460. this.buffer.set(buffer, this.position);
  461. this.position += length;
  462. }
  463. }
  464. toBuffer() {
  465. const buffer = new Uint8Array(this.length);
  466. let offset = 0;
  467. for (const block of this.blocks) {
  468. buffer.set(block, offset);
  469. offset += block.length;
  470. }
  471. return buffer;
  472. }
  473. _reset() {
  474. if (this.position > 32768) {
  475. this.buffer.set(this.buffer.subarray(this.position - 32768, this.position), 0);
  476. this.position = 32768;
  477. }
  478. return this.position;
  479. }
  480. };
  481. zip.BufferWriter = class {
  482. constructor(length) {
  483. this.buffer = new Uint8Array(length);
  484. this.length = length;
  485. this.position = 0;
  486. }
  487. push(position) {
  488. this.position = position;
  489. if (this.position > this.length) {
  490. throw new zip.Error('Invalid size.');
  491. }
  492. return this.position;
  493. }
  494. write(buffer) {
  495. this.buffer.set(buffer, this.position);
  496. this.position += buffer.length;
  497. if (this.position > this.length) {
  498. throw new zip.Error('Invalid size.');
  499. }
  500. return this.position;
  501. }
  502. toBuffer() {
  503. return this.buffer;
  504. }
  505. };
  506. zip.InflaterStream = class {
  507. constructor(stream, length) {
  508. this._stream = stream;
  509. this._offset = this._stream.position;
  510. this._position = 0;
  511. this._length = length;
  512. }
  513. get position() {
  514. return this._position;
  515. }
  516. get length() {
  517. if (this._length === undefined) {
  518. this._inflate();
  519. }
  520. return this._length;
  521. }
  522. seek(position) {
  523. if (this._buffer === undefined) {
  524. this._inflate();
  525. }
  526. this._position = position >= 0 ? position : this._length + position;
  527. }
  528. skip(offset) {
  529. if (this._buffer === undefined) {
  530. this._inflate();
  531. }
  532. this._position += offset;
  533. }
  534. peek(length) {
  535. const position = this._position;
  536. length = length !== undefined ? length : this.length - position;
  537. this.skip(length);
  538. const end = this._position;
  539. this.seek(position);
  540. if (position === 0 && length === this.length) {
  541. return this._buffer;
  542. }
  543. return this._buffer.subarray(position, end);
  544. }
  545. read(length) {
  546. const position = this._position;
  547. length = length !== undefined ? length : this.length - position;
  548. this.skip(length);
  549. if (position === 0 && length === this.length) {
  550. return this._buffer;
  551. }
  552. return this._buffer.subarray(position, this._position);
  553. }
  554. stream(length) {
  555. const buffer = this.read(length);
  556. return new zip.BinaryReader(buffer);
  557. }
  558. byte() {
  559. const position = this._position;
  560. this.skip(1);
  561. return this._buffer[position];
  562. }
  563. _inflate() {
  564. if (this._buffer === undefined) {
  565. const position = this._stream.position;
  566. this._stream.seek(this._offset);
  567. const buffer = this._stream.peek();
  568. this._buffer = new zip.Inflater().inflateRaw(buffer, this._length);
  569. this._length = this._buffer.length;
  570. this._stream.seek(position);
  571. delete this._stream;
  572. }
  573. }
  574. };
  575. zip.ErrorStream = class {
  576. constructor(size, message) {
  577. this._message = message;
  578. this._position = 0;
  579. this._length = size;
  580. }
  581. get position() {
  582. return this._position;
  583. }
  584. get length() {
  585. return this._length;
  586. }
  587. seek(position) {
  588. this._position = position >= 0 ? position : this._length + position;
  589. }
  590. skip(offset) {
  591. this._position += offset;
  592. }
  593. peek(/* length */) {
  594. this._throw();
  595. }
  596. read(/* length */) {
  597. this._throw();
  598. }
  599. stream(/* length */) {
  600. this._throw();
  601. }
  602. byte() {
  603. this._throw();
  604. }
  605. _throw() {
  606. throw new zip.Error(this._message);
  607. }
  608. };
  609. zip.BinaryReader = class {
  610. constructor(buffer) {
  611. this._buffer = buffer;
  612. this._length = buffer.length;
  613. this._position = 0;
  614. this._view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  615. }
  616. get position() {
  617. return this._position;
  618. }
  619. get length() {
  620. return this._length;
  621. }
  622. create(buffer) {
  623. return new zip.BinaryReader(buffer);
  624. }
  625. stream(length) {
  626. return this.create(this.read(length));
  627. }
  628. seek(position) {
  629. this._position = position >= 0 ? position : this._length + position;
  630. }
  631. skip(offset) {
  632. this._position += offset;
  633. }
  634. peek(length) {
  635. if (this._position === 0 && length === undefined) {
  636. return this._buffer;
  637. }
  638. const position = this._position;
  639. this.skip(length !== undefined ? length : this._length - this._position);
  640. const end = this._position;
  641. this.seek(position);
  642. return this._buffer.subarray(position, end);
  643. }
  644. read(length) {
  645. if (this._position === 0 && length === undefined) {
  646. this._position = this._length;
  647. return this._buffer;
  648. }
  649. const position = this._position;
  650. this.skip(length !== undefined ? length : this._length - this._position);
  651. return this._buffer.subarray(position, this._position);
  652. }
  653. byte() {
  654. const position = this._position;
  655. this.skip(1);
  656. return this._buffer[position];
  657. }
  658. uint16() {
  659. const position = this._position;
  660. this.skip(2);
  661. return this._view.getUint16(position, true);
  662. }
  663. uint32() {
  664. const position = this._position;
  665. this.skip(4);
  666. return this._view.getUint32(position, true);
  667. }
  668. uint64() {
  669. const lo = this.uint32();
  670. const hi = this.uint32();
  671. if (hi > 0xffff) {
  672. return undefined;
  673. }
  674. return hi * 4294967296 + lo;
  675. }
  676. };
  677. zlib.Archive = class {
  678. constructor(stream) {
  679. const position = stream.position;
  680. stream.read(2);
  681. this._entries = new Map([ [ '', new zip.InflaterStream(stream) ] ]);
  682. stream.seek(position);
  683. }
  684. get entries() {
  685. return this._entries;
  686. }
  687. };
  688. zip.Error = class extends Error {
  689. constructor(message) {
  690. super(message);
  691. this.name = 'Zip Error';
  692. }
  693. };
  694. gzip.Archive = class {
  695. constructor(stream) {
  696. const position = stream.position;
  697. const signature = [ 0x1f, 0x8b ];
  698. if (stream.position + 2 > stream.length ||
  699. !stream.read(2).every((value, index) => value === signature[index])) {
  700. throw new gzip.Error('Invalid gzip signature.');
  701. }
  702. const string = () => {
  703. let content = '';
  704. while (stream.position < stream.length) {
  705. const value = stream.byte();
  706. if (value === 0x00) {
  707. break;
  708. }
  709. content += String.fromCharCode(value);
  710. }
  711. return content;
  712. };
  713. const reader = new zip.BinaryReader(stream.read(8));
  714. const compressionMethod = reader.byte();
  715. if (compressionMethod != 8) {
  716. throw new gzip.Error("Invalid compression method '" + compressionMethod.toString() + "'.");
  717. }
  718. const flags = reader.byte();
  719. reader.uint32(); // MTIME
  720. reader.byte(); // XFL
  721. reader.byte(); // OS
  722. if ((flags & 4) != 0) { // FEXTRA
  723. const xlen = stream.byte() | (stream.byte() << 8);
  724. stream.skip(xlen);
  725. }
  726. const name = (flags & 8) != 0 ? string() : ''; // FNAME
  727. if ((flags & 16) != 0) { // FCOMMENT
  728. string();
  729. }
  730. if ((flags & 1) != 0) { // FHCRC
  731. stream.skip(2);
  732. }
  733. this._entries = new Map([ [ name, new gzip.InflaterStream(stream) ] ]);
  734. stream.seek(position);
  735. }
  736. get entries() {
  737. return this._entries;
  738. }
  739. };
  740. gzip.InflaterStream = class {
  741. constructor(stream) {
  742. this._stream = stream.stream(stream.length - stream.position - 8);
  743. const reader = new zip.BinaryReader(stream.read(8));
  744. reader.uint32(); // CRC32
  745. this._length = reader.uint32(); // ISIZE
  746. this._position = 0;
  747. }
  748. get position() {
  749. return this._position;
  750. }
  751. get length() {
  752. return this._length;
  753. }
  754. seek(position) {
  755. if (this._buffer === undefined) {
  756. this._inflate();
  757. }
  758. this._position = position >= 0 ? position : this._length + position;
  759. }
  760. skip(offset) {
  761. if (this._buffer === undefined) {
  762. this._inflate();
  763. }
  764. this._position += offset;
  765. }
  766. stream(length) {
  767. return new zip.BinaryReader(this.read(length));
  768. }
  769. peek(length) {
  770. const position = this._position;
  771. length = length !== undefined ? length : this._length - this._position;
  772. this.skip(length);
  773. const end = this._position;
  774. this.seek(position);
  775. if (position === 0 && length === this._length) {
  776. return this._buffer;
  777. }
  778. return this._buffer.subarray(position, end);
  779. }
  780. read(length) {
  781. const position = this._position;
  782. length = length !== undefined ? length : this._length - this._position;
  783. this.skip(length);
  784. if (position === 0 && length === this._length) {
  785. return this._buffer;
  786. }
  787. return this._buffer.subarray(position, this._position);
  788. }
  789. byte() {
  790. const position = this._position;
  791. this.skip(1);
  792. return this._buffer[position];
  793. }
  794. _inflate() {
  795. if (this._buffer === undefined) {
  796. const buffer = this._stream.peek();
  797. this._buffer = new zip.Inflater().inflateRaw(buffer, this._length);
  798. delete this._stream;
  799. }
  800. }
  801. };
  802. gzip.Error = class extends Error {
  803. constructor(message) {
  804. super(message);
  805. this.name = 'Gzip Error';
  806. }
  807. };
  808. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  809. module.exports.Archive = zip.Archive;
  810. module.exports.Inflater = zip.Inflater;
  811. }