zip.js 33 KB

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