zip.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  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. do {
  38. position = Math.max(0, position - 66000);
  39. stream.seek(position);
  40. const length = Math.min(stream.length - position, 66000 + size);
  41. const buffer = stream.read(length);
  42. for (let i = buffer.length - size; i >= 0; i--) {
  43. if (signature[0] === buffer[i] && signature[1] === buffer[i + 1] &&
  44. signature[2] === buffer[i + 2] && signature[3] === buffer[i + 3]) {
  45. stream.seek(position + i);
  46. return new zip.BinaryReader(buffer.subarray(i, i + size));
  47. }
  48. }
  49. if (!search) {
  50. break;
  51. }
  52. }
  53. while (position > 0);
  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('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('Zip 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();
  109. header.offset = reader.uint64();
  110. if (header.offset === undefined) {
  111. stream.seek(location);
  112. throw new zip.Error('Zip 64-bit central directory offset not supported.');
  113. }
  114. }
  115. position -= header.size;
  116. if (position < 0 || position > stream.length) {
  117. stream.seek(location);
  118. throw new zip.Error('Invalid Zip central directory size.');
  119. }
  120. if (position < header.offset) {
  121. stream.seek(location);
  122. throw new zip.Error('Invalid Zip central directory offset.');
  123. }
  124. stream.seek(position);
  125. position -= header.offset;
  126. const archive = new zip.Archive(stream, position);
  127. stream.seek(location);
  128. return archive;
  129. }
  130. }
  131. return null;
  132. }
  133. constructor(stream, offset) {
  134. offset = offset || 0;
  135. this._entries = new Map();
  136. const headers = [];
  137. const signature = Array.from('PK\x01\x02', (c) => c.charCodeAt(0));
  138. while (stream.position + 4 < stream.length && stream.read(4).every((value, index) => value === signature[index])) {
  139. const header = {};
  140. const reader = new zip.BinaryReader(stream.read(42));
  141. reader.uint16(); // version made by
  142. reader.skip(2); // version needed to extract
  143. const flags = reader.uint16();
  144. if ((flags & 1) == 1) {
  145. throw new zip.Error('Encrypted Zip entries not supported.');
  146. }
  147. header.encoding = flags & 0x800 ? 'utf-8' : 'ascii';
  148. header.compressionMethod = reader.uint16();
  149. header.date = reader.uint32(); // date
  150. header.crc32 = reader.uint32(); // crc32
  151. header.compressedSize = reader.uint32();
  152. header.size = reader.uint32();
  153. header.nameLength = reader.uint16(); // file name length
  154. const extraDataLength = reader.uint16();
  155. const commentLength = reader.uint16();
  156. header.disk = reader.uint16(); // disk number start
  157. reader.uint16(); // internal file attributes
  158. reader.uint32(); // external file attributes
  159. header.localHeaderOffset = reader.uint32();
  160. const nameBuffer = stream.read(header.nameLength);
  161. const decoder = new TextDecoder(header.encoding);
  162. header.name = decoder.decode(nameBuffer);
  163. const extraData = stream.read(extraDataLength);
  164. if (extraData.length > 0) {
  165. const reader = new zip.BinaryReader(extraData);
  166. while (reader.position < reader.length) {
  167. const type = reader.uint16();
  168. const length = reader.uint16();
  169. switch (type) {
  170. case 0x0001:
  171. if (header.size === 0xffffffff) {
  172. header.size = reader.uint64();
  173. if (header.size === undefined) {
  174. throw new zip.Error('Zip 64-bit size not supported.');
  175. }
  176. }
  177. if (header.compressedSize === 0xffffffff) {
  178. header.compressedSize = reader.uint64();
  179. if (header.compressedSize === undefined) {
  180. throw new zip.Error('Zip 64-bit compressed size not supported.');
  181. }
  182. }
  183. if (header.localHeaderOffset === 0xffffffff) {
  184. header.localHeaderOffset = reader.uint64();
  185. if (header.localHeaderOffset === undefined) {
  186. throw new zip.Error('Zip 64-bit offset not supported.');
  187. }
  188. }
  189. if (header.disk === 0xffff) {
  190. header.disk = reader.uint32();
  191. }
  192. break;
  193. default:
  194. reader.skip(length);
  195. break;
  196. }
  197. }
  198. }
  199. stream.read(commentLength); // comment
  200. headers.push(header);
  201. }
  202. for (const header of headers) {
  203. if (header.size === 0 && header.name.endsWith('/')) {
  204. continue;
  205. }
  206. const entry = new zip.Entry(stream, header, offset);
  207. this._entries.set(entry.name, entry.stream);
  208. }
  209. }
  210. get entries() {
  211. return this._entries;
  212. }
  213. };
  214. zip.Entry = class {
  215. constructor(stream, header, offset) {
  216. offset = offset || 0;
  217. this._name = header.name;
  218. stream.seek(offset + header.localHeaderOffset);
  219. const signature = Array.from('PK\x03\x04', (c) => c.charCodeAt(0));
  220. if (stream.position + 4 > stream.length || !stream.read(4).every((value, index) => value === signature[index])) {
  221. this._stream = new zip.ErrorStream(header.size, 'Invalid Zip local file header signature.');
  222. } else {
  223. const reader = new zip.BinaryReader(stream.read(26));
  224. reader.skip(22);
  225. header.nameLength = reader.uint16();
  226. const extraDataLength = reader.uint16();
  227. header.nameBuffer = stream.read(header.nameLength);
  228. stream.skip(extraDataLength);
  229. const decoder = new TextDecoder(header.encoding);
  230. this._name = decoder.decode(header.nameBuffer);
  231. this._stream = stream.stream(header.compressedSize);
  232. switch (header.compressionMethod) {
  233. case 0: { // stored
  234. if (header.size !== header.compressedSize) {
  235. this._stream = new zip.ErrorStream(header.size, 'Invalid compression size.');
  236. }
  237. break;
  238. }
  239. case 8: { // deflate
  240. this._stream = new zip.InflaterStream(this._stream, header.size);
  241. break;
  242. }
  243. default: {
  244. this._stream = new new zip.ErrorStream(header.size, 'Invalid compression method.');
  245. }
  246. }
  247. }
  248. }
  249. get name() {
  250. return this._name;
  251. }
  252. get stream() {
  253. return this._stream;
  254. }
  255. };
  256. zip.Inflater = class {
  257. inflateRaw(data, length) {
  258. let buffer = null;
  259. if (zip.zlib) {
  260. buffer = zip.zlib.inflateRawSync(data);
  261. } else {
  262. const reader = new zip.BitReader(data);
  263. const writer = length === undefined ? new zip.BlockWriter() : new zip.BufferWriter(length);
  264. if (!zip.Inflater._staticLengthTree) {
  265. zip.Inflater._codeLengths = new Uint8Array(19);
  266. zip.Inflater._codeOrder = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
  267. 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 ];
  268. 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 ];
  269. }
  270. let type;
  271. do {
  272. type = reader.bits(3);
  273. switch (type >>> 1) {
  274. case 0: { // uncompressed block
  275. this._copyUncompressedBlock(reader, writer);
  276. break;
  277. }
  278. case 1: { // block with fixed huffman trees
  279. if (!zip.Inflater._staticLengthTree) {
  280. 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])))));
  281. zip.Inflater._staticDistanceTree = zip.HuffmanTree.create(new Uint8Array([...Array(32)].map(() => 5)));
  282. }
  283. this._lengthTree = zip.Inflater._staticLengthTree;
  284. this._distanceTree = zip.Inflater._staticDistanceTree;
  285. this._inflateBlock(reader, writer);
  286. break;
  287. }
  288. case 2: { // block with dynamic huffman trees
  289. this._decodeTrees(reader);
  290. this._inflateBlock(reader, writer);
  291. break;
  292. }
  293. default: {
  294. throw new zip.Error('Unsupported block type.');
  295. }
  296. }
  297. } while ((type & 1) == 0);
  298. if (length !== undefined && length !== writer.length) {
  299. throw new zip.Error('Invalid uncompressed size.');
  300. }
  301. buffer = writer.toBuffer();
  302. }
  303. if (length !== undefined && length !== buffer.length) {
  304. throw new zip.Error('Invalid uncompressed size.');
  305. }
  306. return buffer;
  307. }
  308. _copyUncompressedBlock(reader, writer) {
  309. const length = reader.uint16();
  310. const inverseLength = reader.uint16();
  311. if (length !== (~inverseLength & 0xffff)) {
  312. throw new zip.Error('Invalid uncompressed block length.');
  313. }
  314. writer.write(reader.read(length));
  315. }
  316. _decodeTrees(reader) {
  317. const hlit = reader.bits(5) + 257;
  318. const hdist = reader.bits(5) + 1;
  319. const hclen = reader.bits(4) + 4;
  320. const codeLengths = zip.Inflater._codeLengths;
  321. for (let i = 0; i < codeLengths.length; i++) {
  322. codeLengths[i] = 0;
  323. }
  324. const codeOrder = zip.Inflater._codeOrder;
  325. for (let i = 0; i < hclen; i++) {
  326. codeLengths[codeOrder[i]] = reader.bits(3);
  327. }
  328. const codeTree = zip.HuffmanTree.create(codeLengths);
  329. const codeMask = codeTree.length - 1;
  330. const lengths = new Uint8Array(hlit + hdist);
  331. let value = 0;
  332. let length = 0;
  333. for (let i = 0; i < hlit + hdist;) {
  334. const code = codeTree[reader.bits16() & codeMask];
  335. reader.position += code & 0x0f;
  336. const literal = code >>> 4;
  337. switch (literal) {
  338. case 16: length = reader.bits(2) + 3; break;
  339. case 17: length = reader.bits(3) + 3; value = 0; break;
  340. case 18: length = reader.bits(7) + 11; value = 0; break;
  341. default: length = 1; value = literal; break;
  342. }
  343. for (; length > 0; length--) {
  344. lengths[i++] = value;
  345. }
  346. }
  347. this._lengthTree = zip.HuffmanTree.create(lengths.subarray(0, hlit));
  348. this._distanceTree = zip.HuffmanTree.create(lengths.subarray(hlit, hlit + hdist));
  349. }
  350. _inflateBlock(reader, writer) {
  351. const lengthTree = this._lengthTree;
  352. const distanceTree = this._distanceTree;
  353. const lengthMask = lengthTree.length - 1;
  354. const distanceMask = distanceTree.length - 1;
  355. const buffer = writer.buffer;
  356. const threshold = writer.threshold !== undefined ? writer.threshold : writer.length;
  357. let position = writer.position;
  358. for (;;) {
  359. if (position > threshold) {
  360. position = writer.push(position);
  361. }
  362. const code = lengthTree[reader.bits16() & lengthMask];
  363. reader.position += code & 0x0f;
  364. const literal = code >>> 4;
  365. if (literal < 256) {
  366. buffer[position++] = literal;
  367. } else if (literal === 256) {
  368. writer.push(position);
  369. return;
  370. } else {
  371. let length = literal - 254;
  372. if (literal > 264) {
  373. const lengthBase = zip.Inflater._lengthBase[literal - 257];
  374. length = (lengthBase >>> 3) + reader.bits(lengthBase & 0x07);
  375. }
  376. const code = distanceTree[reader.bits16() & distanceMask];
  377. reader.position += code & 0x0f;
  378. const distanceBase = zip.Inflater._distanceBase[code >>> 4];
  379. const bits = distanceBase & 0x0f;
  380. const distance = (distanceBase >>> 4) + (reader.bits16() & ((1 << bits) - 1));
  381. reader.position += bits;
  382. let offset = position - distance;
  383. for (let i = 0; i < length; i++) {
  384. buffer[position++] = buffer[offset++];
  385. }
  386. }
  387. }
  388. }
  389. };
  390. zip.HuffmanTree = class {
  391. static create(tree) {
  392. const bits = Math.max.apply(null, tree);
  393. // Algorithm from https://github.com/photopea/UZIP.js
  394. let rev15 = zip.HuffmanTree._rev15;
  395. if (!rev15) {
  396. const length = 1 << 15;
  397. rev15 = new Uint16Array(length);
  398. for (let i = 0; i < length; i++) {
  399. let x = i;
  400. x = (((x & 0xaaaaaaaa) >>> 1) | ((x & 0x55555555) << 1));
  401. x = (((x & 0xcccccccc) >>> 2) | ((x & 0x33333333) << 2));
  402. x = (((x & 0xf0f0f0f0) >>> 4) | ((x & 0x0f0f0f0f) << 4));
  403. x = (((x & 0xff00ff00) >>> 8) | ((x & 0x00ff00ff) << 8));
  404. rev15[i] = (((x >>> 16) | (x << 16))) >>> 17;
  405. }
  406. zip.HuffmanTree._rev15 = rev15;
  407. zip.HuffmanTree._bitLengthCounts = new Uint16Array(16);
  408. zip.HuffmanTree._nextCodes = new Uint16Array(16);
  409. }
  410. const length = tree.length;
  411. const bitLengthCounts = zip.HuffmanTree._bitLengthCounts;
  412. for (let i = 0; i < 16; i++) {
  413. bitLengthCounts[i] = 0;
  414. }
  415. for (let i = 0; i < length; i++) {
  416. bitLengthCounts[tree[i]]++;
  417. }
  418. const nextCodes = zip.HuffmanTree._nextCodes;
  419. let code = 0;
  420. bitLengthCounts[0] = 0;
  421. for (let i = 0; i < bits; i++) {
  422. code = (code + bitLengthCounts[i]) << 1;
  423. nextCodes[i + 1] = code;
  424. }
  425. const codes = new Uint16Array(length);
  426. for (let i = 0; i < length; i++) {
  427. const index = tree[i];
  428. if (index !== 0) {
  429. codes[i] = nextCodes[index];
  430. nextCodes[index]++;
  431. }
  432. }
  433. const shift = 15 - bits;
  434. const table = new Uint16Array(1 << bits);
  435. for (let i = 0; i < length; i++) {
  436. const c = tree[i];
  437. if (c !== 0) {
  438. const value = (i << 4) | c;
  439. const rest = bits - c;
  440. let index = codes[i] << rest;
  441. const max = index + (1 << rest);
  442. for (; index != max; index++) {
  443. table[rev15[index] >>> shift] = value;
  444. }
  445. }
  446. }
  447. return table;
  448. }
  449. };
  450. zip.BitReader = class {
  451. constructor(buffer) {
  452. this.buffer = buffer;
  453. this.position = 0;
  454. }
  455. bits(count) {
  456. const offset = Math.floor(this.position / 8);
  457. const shift = (this.position & 7);
  458. this.position += count;
  459. return ((this.buffer[offset] | (this.buffer[offset + 1] << 8)) >>> shift) & ((1 << count) - 1);
  460. }
  461. bits16() {
  462. const offset = Math.floor(this.position / 8);
  463. return ((this.buffer[offset] | (this.buffer[offset + 1] << 8) | (this.buffer[offset + 2] << 16)) >>> (this.position & 7));
  464. }
  465. read(length) {
  466. const remainder = this.position & 7;
  467. if (remainder !== 0) {
  468. this.position += (8 - remainder);
  469. }
  470. const offset = Math.floor(this.position / 8);
  471. this.position += length * 8;
  472. return this.buffer.subarray(offset, offset + length);
  473. }
  474. uint16() {
  475. const remainder = this.position & 7;
  476. if (remainder !== 0) {
  477. this.position += (8 - remainder);
  478. }
  479. const offset = Math.floor(this.position / 8);
  480. this.position += 16;
  481. return this.buffer[offset] | (this.buffer[offset + 1] << 8);
  482. }
  483. };
  484. zip.BlockWriter = class {
  485. constructor() {
  486. this.blocks = [];
  487. this.buffer = new Uint8Array(65536);
  488. this.position = 0;
  489. this.length = 0;
  490. this.threshold = 0xf400;
  491. }
  492. push(position) {
  493. this.blocks.push(new Uint8Array(this.buffer.subarray(this.position, position)));
  494. this.length += position - this.position;
  495. this.position = position;
  496. return this._reset();
  497. }
  498. write(buffer) {
  499. this.blocks.push(buffer);
  500. const length = buffer.length;
  501. this.length += length;
  502. if (length > 32768) {
  503. this.buffer.set(buffer.subarray(length - 32768, length), 0);
  504. this.position = 32768;
  505. } else {
  506. this._reset();
  507. this.buffer.set(buffer, this.position);
  508. this.position += length;
  509. }
  510. }
  511. toBuffer() {
  512. const buffer = new Uint8Array(this.length);
  513. let offset = 0;
  514. for (const block of this.blocks) {
  515. buffer.set(block, offset);
  516. offset += block.length;
  517. }
  518. return buffer;
  519. }
  520. _reset() {
  521. if (this.position > 32768) {
  522. this.buffer.set(this.buffer.subarray(this.position - 32768, this.position), 0);
  523. this.position = 32768;
  524. }
  525. return this.position;
  526. }
  527. };
  528. zip.BufferWriter = class {
  529. constructor(length) {
  530. this.buffer = new Uint8Array(length);
  531. this.length = length;
  532. this.position = 0;
  533. }
  534. push(position) {
  535. this.position = position;
  536. if (this.position > this.length) {
  537. throw new zip.Error('Invalid size.');
  538. }
  539. return this.position;
  540. }
  541. write(buffer) {
  542. this.buffer.set(buffer, this.position);
  543. this.position += buffer.length;
  544. if (this.position > this.length) {
  545. throw new zip.Error('Invalid size.');
  546. }
  547. return this.position;
  548. }
  549. toBuffer() {
  550. return this.buffer;
  551. }
  552. };
  553. zip.InflaterStream = class {
  554. constructor(stream, length) {
  555. this._stream = stream;
  556. this._offset = this._stream.position;
  557. this._position = 0;
  558. this._length = length;
  559. }
  560. get position() {
  561. return this._position;
  562. }
  563. get length() {
  564. if (this._length === undefined) {
  565. this._inflate();
  566. }
  567. return this._length;
  568. }
  569. seek(position) {
  570. if (this._buffer === undefined) {
  571. this._inflate();
  572. }
  573. this._position = position >= 0 ? position : this._length + position;
  574. }
  575. skip(offset) {
  576. if (this._buffer === undefined) {
  577. this._inflate();
  578. }
  579. this._position += offset;
  580. }
  581. peek(length) {
  582. const position = this._position;
  583. length = length !== undefined ? length : this.length - position;
  584. this.skip(length);
  585. const end = this._position;
  586. this.seek(position);
  587. if (position === 0 && length === this.length) {
  588. return this._buffer;
  589. }
  590. return this._buffer.subarray(position, end);
  591. }
  592. read(length) {
  593. const position = this._position;
  594. length = length !== undefined ? length : this.length - position;
  595. this.skip(length);
  596. if (position === 0 && length === this.length) {
  597. return this._buffer;
  598. }
  599. return this._buffer.subarray(position, this._position);
  600. }
  601. stream(length) {
  602. const buffer = this.read(length);
  603. return new zip.BinaryReader(buffer);
  604. }
  605. byte() {
  606. const position = this._position;
  607. this.skip(1);
  608. return this._buffer[position];
  609. }
  610. _inflate() {
  611. if (this._buffer === undefined) {
  612. const position = this._stream.position;
  613. this._stream.seek(this._offset);
  614. const buffer = this._stream.peek();
  615. this._buffer = new zip.Inflater().inflateRaw(buffer, this._length);
  616. this._length = this._buffer.length;
  617. this._stream.seek(position);
  618. delete this._stream;
  619. }
  620. }
  621. };
  622. zip.ErrorStream = class {
  623. constructor(size, message) {
  624. this._message = message;
  625. this._position = 0;
  626. this._length = size;
  627. }
  628. get position() {
  629. return this._position;
  630. }
  631. get length() {
  632. return this._length;
  633. }
  634. seek(position) {
  635. this._position = position >= 0 ? position : this._length + position;
  636. }
  637. skip(offset) {
  638. this._position += offset;
  639. }
  640. peek(/* length */) {
  641. this._throw();
  642. }
  643. read(/* length */) {
  644. this._throw();
  645. }
  646. stream(/* length */) {
  647. this._throw();
  648. }
  649. byte() {
  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 ? length : this._length - this._position);
  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 ? length : this._length - this._position);
  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 lo = this.uint32();
  717. const hi = this.uint32();
  718. if (hi > 0xffff) {
  719. return undefined;
  720. }
  721. return hi * 4294967296 + lo;
  722. }
  723. };
  724. zlib.Archive = class {
  725. constructor(stream) {
  726. const position = stream.position;
  727. stream.read(2);
  728. this._entries = new Map([ [ '', new zip.InflaterStream(stream) ] ]);
  729. stream.seek(position);
  730. }
  731. get entries() {
  732. return this._entries;
  733. }
  734. };
  735. zip.Error = class extends Error {
  736. constructor(message) {
  737. super(message);
  738. this.name = 'Zip Error';
  739. }
  740. };
  741. gzip.Archive = class {
  742. constructor(stream) {
  743. const position = stream.position;
  744. const signature = [ 0x1f, 0x8b ];
  745. if (stream.position + 2 > stream.length ||
  746. !stream.read(2).every((value, index) => value === signature[index])) {
  747. throw new gzip.Error('Invalid gzip signature.');
  748. }
  749. const string = () => {
  750. let content = '';
  751. while (stream.position < stream.length) {
  752. const value = stream.byte();
  753. if (value === 0x00) {
  754. break;
  755. }
  756. content += String.fromCharCode(value);
  757. }
  758. return content;
  759. };
  760. const reader = new zip.BinaryReader(stream.read(8));
  761. const compressionMethod = reader.byte();
  762. if (compressionMethod != 8) {
  763. stream.seek(position);
  764. throw new gzip.Error(`Invalid compression method '${compressionMethod}'.`);
  765. }
  766. const flags = reader.byte();
  767. reader.uint32(); // MTIME
  768. reader.byte(); // XFL
  769. reader.byte(); // OS
  770. if ((flags & 4) != 0) { // FEXTRA
  771. const xlen = stream.byte() | (stream.byte() << 8);
  772. stream.skip(xlen);
  773. }
  774. const name = (flags & 8) != 0 ? string() : ''; // FNAME
  775. if ((flags & 16) != 0) { // FCOMMENT
  776. string();
  777. }
  778. if ((flags & 1) != 0) { // FHCRC
  779. stream.skip(2);
  780. }
  781. this._entries = new Map([ [ 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 ? length : this._length - this._position;
  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 ? length : this._length - this._position;
  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. byte() {
  838. const position = this._position;
  839. this.skip(1);
  840. return this._buffer[position];
  841. }
  842. _inflate() {
  843. if (this._buffer === undefined) {
  844. const buffer = this._stream.peek();
  845. this._buffer = new zip.Inflater().inflateRaw(buffer, this._length);
  846. delete this._stream;
  847. }
  848. }
  849. };
  850. gzip.Error = class extends Error {
  851. constructor(message) {
  852. super(message);
  853. this.name = 'Gzip Error';
  854. }
  855. };
  856. export const Archive = zip.Archive;