1 /* 2 Copyright 2008-2024 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Alfred Wassermann, 8 Peter Wilfahrt 9 10 This file is part of JSXGraph and JSXCompressor. 11 12 JSXGraph is free software dual licensed under the GNU LGPL or MIT License. 13 JSXCompressor is free software dual licensed under the GNU LGPL or Apache License. 14 15 You can redistribute it and/or modify it under the terms of the 16 17 * GNU Lesser General Public License as published by 18 the Free Software Foundation, either version 3 of the License, or 19 (at your option) any later version 20 OR 21 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 22 OR 23 * Apache License Version 2.0 24 25 JSXGraph is distributed in the hope that it will be useful, 26 but WITHOUT ANY WARRANTY; without even the implied warranty of 27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 GNU Lesser General Public License for more details. 29 30 You should have received a copy of the GNU Lesser General Public License, Apache 31 License, and the MIT License along with JSXGraph. If not, see 32 <https://www.gnu.org/licenses/>, <https://www.apache.org/licenses/LICENSE-2.0.html>, 33 and <https://opensource.org/licenses/MIT/>. 34 */ 35 36 /*global JXG: true, define: true*/ 37 /*jslint nomen: true, plusplus: true, bitwise: true*/ 38 39 /** 40 * @fileoverview Utilities for uncompressing and base64 decoding 41 */ 42 43 import JXG from "../jxg.js"; 44 45 // Zip routine constants 46 47 var bitReverse = [ 48 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 49 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 50 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 51 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 52 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 53 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 54 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 55 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 56 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 57 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 58 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 59 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 60 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 61 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 62 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 63 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 64 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 65 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 66 0x3f, 0xbf, 0x7f, 0xff 67 ], 68 cplens = [ 69 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 70 115, 131, 163, 195, 227, 258, 0, 0 71 ], 72 cplext = [ 73 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 74 99, 99 75 ] /* 99==invalid */, 76 cpdist = [ 77 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, 0x0011, 0x0019, 0x0021, 78 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 79 0x0801, 0x0c01, 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001 80 ], 81 cpdext = [ 82 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 83 12, 13, 13 84 ], 85 border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], 86 NAMEMAX = 256; 87 88 // Util namespace 89 JXG.Util = JXG.Util || {}; 90 91 /** 92 * @class Unzip class 93 * Class for gunzipping, unzipping and base64 decoding of files. 94 * It is used for reading GEONExT, Geogebra and Intergeo files. 95 * 96 * Only Huffman codes are decoded in gunzip. 97 * The code is based on the source code for gunzip.c by Pasi Ojala 98 * @see http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c 99 * @see http://www.cs.tut.fi/~albert 100 */ 101 JXG.Util.Unzip = function (barray) { 102 var gpflags, 103 // SIZE, 104 fileout, 105 flens, 106 fmax, 107 outputArr = [], 108 files = 0, 109 unzipped = [], 110 buf32k = new Array(32768), 111 bIdx = 0, 112 modeZIP = false, 113 barraylen = barray.length, 114 bytepos = 0, 115 bb = 1, 116 // bits = 0, 117 literalTree = new Array(288), 118 distanceTree = new Array(32), 119 treepos = 0, 120 Places = null, 121 // crc, 122 // output = "", 123 // debug = false, 124 // bitpos = 0, 125 // Places2 = null, 126 // impDistanceTree = new Array(64), 127 // impLengthTree = new Array(64), 128 len = 0, 129 fpos = new Array(17), 130 nameBuf = []; 131 132 fpos[0] = 0; 133 134 function readByte() { 135 // bits += 8; 136 137 if (bytepos < barraylen) { 138 return barray[bytepos++]; 139 } 140 141 return -1; 142 } 143 144 function byteAlign() { 145 bb = 1; 146 } 147 148 function readBit() { 149 var carry; 150 151 // Prevent problems on iOS7 with >> 152 try { 153 // bits++; 154 carry = bb & 1; 155 bb >>= 1; 156 157 if (bb === 0) { 158 bb = readByte(); 159 carry = bb & 1; 160 bb = (bb >> 1) | 0x80; 161 } 162 } catch (e) { 163 console.log("Probably problems on iOS7 with >>"); 164 throw e; 165 } 166 167 return carry; 168 } 169 170 function readBits(a) { 171 var res = 0, 172 i = a; 173 174 // Prevent problems on iOS7 with >> 175 try { 176 while (i--) { 177 res = (res << 1) | readBit(); 178 } 179 180 if (a) { 181 res = bitReverse[res] >> (8 - a); 182 } 183 } catch (e) { 184 console.log("Probably problems on iOS7 with >>"); 185 throw e; 186 } 187 return res; 188 } 189 190 function flushBuffer() { 191 bIdx = 0; 192 } 193 194 function addBuffer(a) { 195 // SIZE++; 196 buf32k[bIdx++] = a; 197 outputArr.push(String.fromCharCode(a)); 198 199 if (bIdx === 0x8000) { 200 bIdx = 0; 201 } 202 } 203 204 function HufNode() { 205 this.b0 = 0; 206 this.b1 = 0; 207 this.jump = null; 208 this.jumppos = -1; 209 } 210 211 function isPat() { 212 var endless = true; 213 while (endless) { 214 if (fpos[len] >= fmax) { 215 return -1; 216 } 217 218 if (flens[fpos[len]] === len) { 219 return fpos[len]++; 220 } 221 222 fpos[len]++; 223 } 224 } 225 226 function rec() { 227 var curplace = Places[treepos], 228 tmp; 229 230 if (len === 17) { 231 return -1; 232 } 233 treepos++; 234 len++; 235 236 tmp = isPat(); 237 238 if (tmp >= 0) { 239 /* leaf cell for 0-bit */ 240 curplace.b0 = tmp; 241 } else { 242 /* Not a Leaf cell */ 243 curplace.b0 = 0x8000; 244 245 if (rec()) { 246 return -1; 247 } 248 } 249 250 tmp = isPat(); 251 252 if (tmp >= 0) { 253 /* leaf cell for 1-bit */ 254 curplace.b1 = tmp; 255 /* Just for the display routine */ 256 curplace.jump = null; 257 } else { 258 /* Not a Leaf cell */ 259 curplace.b1 = 0x8000; 260 curplace.jump = Places[treepos]; 261 curplace.jumppos = treepos; 262 if (rec()) { 263 return -1; 264 } 265 } 266 len--; 267 268 return 0; 269 } 270 271 function createTree(currentTree, numval, lengths, show) { 272 var i; 273 274 Places = currentTree; 275 treepos = 0; 276 flens = lengths; 277 fmax = numval; 278 279 for (i = 0; i < 17; i++) { 280 fpos[i] = 0; 281 } 282 len = 0; 283 284 if (rec()) { 285 return -1; 286 } 287 288 return 0; 289 } 290 291 function decodeValue(currentTree) { 292 var len, 293 i, b, 294 endless = true, 295 xtreepos = 0, 296 X = currentTree[xtreepos]; 297 298 /* decode one symbol of the data */ 299 while (endless) { 300 b = readBit(); 301 302 if (b) { 303 if (!(X.b1 & 0x8000)) { 304 /* If leaf node, return data */ 305 return X.b1; 306 } 307 308 X = X.jump; 309 len = currentTree.length; 310 311 for (i = 0; i < len; i++) { 312 if (currentTree[i] === X) { 313 xtreepos = i; 314 break; 315 } 316 } 317 } else { 318 if (!(X.b0 & 0x8000)) { 319 /* If leaf node, return data */ 320 return X.b0; 321 } 322 xtreepos++; 323 X = currentTree[xtreepos]; 324 } 325 } 326 } 327 328 function deflateLoop() { 329 var last, c, type, i, j, l, ll, ll2, 330 len, blockLen, dist, cSum, n,// z, 331 literalCodes, distCodes, lenCodes, 332 endless = true; 333 334 do { 335 last = readBit(); 336 type = readBits(2); 337 338 if (type === 0) { 339 // Stored 340 byteAlign(); 341 blockLen = readByte(); 342 blockLen |= readByte() << 8; 343 344 cSum = readByte(); 345 cSum |= readByte() << 8; 346 347 if ((blockLen ^ ~cSum) & 0xffff) { 348 JXG.debug("BlockLen checksum mismatch\n"); 349 } 350 351 while (blockLen--) { 352 c = readByte(); 353 addBuffer(c); 354 } 355 } else if (type === 1) { 356 /* Fixed Huffman tables -- fixed decode routine */ 357 while (endless) { 358 /* 359 256 0000000 0 360 : : : 361 279 0010111 23 362 0 00110000 48 363 : : : 364 143 10111111 191 365 280 11000000 192 366 : : : 367 287 11000111 199 368 144 110010000 400 369 : : : 370 255 111111111 511 371 372 Note the bit order! 373 */ 374 375 j = bitReverse[readBits(7)] >> 1; 376 377 if (j > 23) { 378 j = (j << 1) | readBit(); /* 48..255 */ 379 380 if (j > 199) { 381 /* 200..255 */ 382 j -= 128; /* 72..127 */ 383 j = (j << 1) | readBit(); /* 144..255 << */ 384 } else { 385 /* 48..199 */ 386 j -= 48; /* 0..151 */ 387 if (j > 143) { 388 j = j + 136; /* 280..287 << */ 389 /* 0..143 << */ 390 } 391 } 392 } else { 393 /* 0..23 */ 394 j += 256; /* 256..279 << */ 395 } 396 397 if (j < 256) { 398 addBuffer(j); 399 } else if (j === 256) { 400 /* EOF */ 401 break; 402 } else { 403 j -= 256 + 1; /* bytes + EOF */ 404 len = readBits(cplext[j]) + cplens[j]; 405 j = bitReverse[readBits(5)] >> 3; 406 407 if (cpdext[j] > 8) { 408 dist = readBits(8); 409 dist |= readBits(cpdext[j] - 8) << 8; 410 } else { 411 dist = readBits(cpdext[j]); 412 } 413 414 dist += cpdist[j]; 415 416 for (j = 0; j < len; j++) { 417 c = buf32k[(bIdx - dist) & 0x7fff]; 418 addBuffer(c); 419 } 420 } 421 } // while 422 } else if (type === 2) { 423 // "static" just to preserve stack 424 ll = new Array(288 + 32); 425 426 // Dynamic Huffman tables 427 literalCodes = 257 + readBits(5); 428 distCodes = 1 + readBits(5); 429 lenCodes = 4 + readBits(4); 430 431 for (j = 0; j < 19; j++) { 432 ll[j] = 0; 433 } 434 435 // Get the decode tree code lengths 436 437 for (j = 0; j < lenCodes; j++) { 438 ll[border[j]] = readBits(3); 439 } 440 len = distanceTree.length; 441 442 for (i = 0; i < len; i++) { 443 distanceTree[i] = new HufNode(); 444 } 445 446 if (createTree(distanceTree, 19, ll, 0)) { 447 flushBuffer(); 448 return 1; 449 } 450 451 //read in literal and distance code lengths 452 n = literalCodes + distCodes; 453 i = 0; 454 // z = -1; 455 456 while (i < n) { 457 // z++; 458 j = decodeValue(distanceTree); 459 460 // length of code in bits (0..15) 461 if (j < 16) { 462 ll[i++] = j; 463 // repeat last length 3 to 6 times 464 } else if (j === 16) { 465 j = 3 + readBits(2); 466 467 if (i + j > n) { 468 flushBuffer(); 469 return 1; 470 } 471 l = i ? ll[i - 1] : 0; 472 473 while (j--) { 474 ll[i++] = l; 475 } 476 } else { 477 // 3 to 10 zero length codes 478 if (j === 17) { 479 j = 3 + readBits(3); 480 // j == 18: 11 to 138 zero length codes 481 } else { 482 j = 11 + readBits(7); 483 } 484 485 if (i + j > n) { 486 flushBuffer(); 487 return 1; 488 } 489 490 while (j--) { 491 ll[i++] = 0; 492 } 493 } 494 } 495 496 // Can overwrite tree decode tree as it is not used anymore 497 len = literalTree.length; 498 for (i = 0; i < len; i++) { 499 literalTree[i] = new HufNode(); 500 } 501 502 if (createTree(literalTree, literalCodes, ll, 0)) { 503 flushBuffer(); 504 return 1; 505 } 506 507 len = literalTree.length; 508 509 for (i = 0; i < len; i++) { 510 distanceTree[i] = new HufNode(); 511 } 512 513 ll2 = []; 514 515 for (i = literalCodes; i < ll.length; i++) { 516 ll2[i - literalCodes] = ll[i]; 517 } 518 519 if (createTree(distanceTree, distCodes, ll2, 0)) { 520 flushBuffer(); 521 return 1; 522 } 523 524 while (endless) { 525 j = decodeValue(literalTree); 526 527 // In C64: if carry set 528 if (j >= 256) { 529 j -= 256; 530 if (j === 0) { 531 // EOF 532 break; 533 } 534 535 j -= 1; 536 len = readBits(cplext[j]) + cplens[j]; 537 j = decodeValue(distanceTree); 538 539 if (cpdext[j] > 8) { 540 dist = readBits(8); 541 dist |= readBits(cpdext[j] - 8) << 8; 542 } else { 543 dist = readBits(cpdext[j]); 544 } 545 546 dist += cpdist[j]; 547 548 while (len--) { 549 c = buf32k[(bIdx - dist) & 0x7fff]; 550 addBuffer(c); 551 } 552 } else { 553 addBuffer(j); 554 } 555 } 556 } 557 } while (!last); 558 559 flushBuffer(); 560 byteAlign(); 561 562 return 0; 563 } 564 565 /** 566 * nextFile: 567 * Extract the next file from the compressed archive. 568 * Calls skipdir() to proceed recursively. 569 * 570 * @return {Boolean} false if the end of files' data section has baseElement 571 * reached. Then, then all recursive functions are stopped immediately. 572 * 573 */ 574 function nextFile() { 575 /* eslint-disable no-unused-vars */ 576 var i, 577 c, 578 extralen, 579 filelen, 580 size, 581 compSize, 582 crc, 583 method, 584 tmp = []; 585 586 // Prevent problems on iOS7 with >> 587 try { 588 outputArr = []; 589 modeZIP = false; 590 tmp[0] = readByte(); 591 tmp[1] = readByte(); 592 593 //GZIP 594 if (tmp[0] === 0x78 && tmp[1] === 0xda) { 595 deflateLoop(); 596 unzipped[files] = [outputArr.join(""), "geonext.gxt"]; 597 files++; 598 } 599 600 //GZIP 601 if (tmp[0] === 0x1f && tmp[1] === 0x8b) { 602 skipdir(); 603 unzipped[files] = [outputArr.join(""), "file"]; 604 files++; 605 } 606 607 //ZIP 608 if (tmp[0] === 0x50 && tmp[1] === 0x4b) { 609 modeZIP = true; 610 tmp[2] = readByte(); 611 tmp[3] = readByte(); 612 613 if (tmp[2] === 0x03 && tmp[3] === 0x04) { 614 //MODE_ZIP 615 tmp[0] = readByte(); 616 tmp[1] = readByte(); 617 618 gpflags = readByte(); 619 gpflags |= readByte() << 8; 620 621 method = readByte(); 622 method |= readByte() << 8; 623 624 readByte(); 625 readByte(); 626 readByte(); 627 readByte(); 628 629 crc = readByte(); 630 crc |= readByte() << 8; 631 crc |= readByte() << 16; 632 crc |= readByte() << 24; 633 634 compSize = readByte(); 635 compSize |= readByte() << 8; 636 compSize |= readByte() << 16; 637 compSize |= readByte() << 24; 638 639 size = readByte(); 640 size |= readByte() << 8; 641 size |= readByte() << 16; 642 size |= readByte() << 24; 643 644 filelen = readByte(); 645 filelen |= readByte() << 8; 646 647 extralen = readByte(); 648 extralen |= readByte() << 8; 649 650 i = 0; 651 nameBuf = []; 652 653 while (filelen--) { 654 c = readByte(); 655 if ((c === "/") | (c === ":")) { 656 i = 0; 657 } else if (i < NAMEMAX - 1) { 658 nameBuf[i++] = String.fromCharCode(c); 659 } 660 } 661 662 if (!fileout) { 663 fileout = nameBuf; 664 } 665 666 i = 0; 667 while (i < extralen) { 668 c = readByte(); 669 i++; 670 } 671 672 // SIZE = 0; 673 if (method === 8) { 674 deflateLoop(); 675 unzipped[files] = new Array(2); 676 unzipped[files][0] = outputArr.join(""); 677 unzipped[files][1] = nameBuf.join(""); 678 files++; 679 } 680 681 if (skipdir()) { 682 // We are beyond the files' data in the zip archive. 683 // Let's get out immediately... 684 return false; 685 } 686 } 687 return true; 688 } 689 } catch (e) { 690 console.log("Probably problems on iOS7 with >>"); 691 throw e; 692 } 693 return false; 694 /* eslint-enable no-unused-vars */ 695 } 696 697 /** 698 * Test if the end of the files' data part of the archive has baseElement 699 * reached. If not, uncompressing is resumed. 700 * 701 * @return {Boolean} true if the end of the files' data sections have 702 * been reached. 703 * 704 * @private 705 */ 706 function skipdir() { 707 /* eslint-disable no-unused-vars */ 708 var crc, compSize, size, os, i, c, 709 tmp = []; 710 711 if (gpflags & 8) { 712 tmp[0] = readByte(); 713 tmp[1] = readByte(); 714 tmp[2] = readByte(); 715 tmp[3] = readByte(); 716 717 // signature for data descriptor record: 0x08074b50 718 // 12 bytes: 719 // crc 4 bytes 720 // compressed size 4 bytes 721 // uncompressed size 4 bytes 722 if (tmp[0] === 0x50 && tmp[1] === 0x4b && tmp[2] === 0x07 && tmp[3] === 0x08) { 723 crc = readByte(); 724 crc |= readByte() << 8; 725 crc |= readByte() << 16; 726 crc |= readByte() << 24; 727 } else { 728 crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24); 729 } 730 731 compSize = readByte(); 732 compSize |= readByte() << 8; 733 compSize |= readByte() << 16; 734 compSize |= readByte() << 24; 735 736 size = readByte(); 737 size |= readByte() << 8; 738 size |= readByte() << 16; 739 size |= readByte() << 24; 740 } 741 742 if (modeZIP) { 743 if (nextFile()) { 744 // A file has been decompressed, we have to proceed 745 return false; 746 } 747 } 748 749 tmp[0] = readByte(); 750 if (tmp[0] !== 8) { 751 // It seems, we are beyond the files' data in the zip archive. 752 // We'll skip the rest.. 753 return true; 754 } 755 756 // There is another file in the zip file. We proceed... 757 gpflags = readByte(); 758 759 readByte(); 760 readByte(); 761 readByte(); 762 readByte(); 763 764 readByte(); 765 os = readByte(); 766 767 if (gpflags & 4) { 768 tmp[0] = readByte(); 769 tmp[2] = readByte(); 770 len = tmp[0] + 256 * tmp[1]; 771 for (i = 0; i < len; i++) { 772 readByte(); 773 } 774 } 775 776 if (gpflags & 8) { 777 i = 0; 778 nameBuf = []; 779 780 c = readByte(); 781 while (c) { 782 if (c === "7" || c === ":") { 783 i = 0; 784 } 785 786 if (i < NAMEMAX - 1) { 787 nameBuf[i++] = c; 788 } 789 790 c = readByte(); 791 } 792 } 793 794 if (gpflags & 16) { 795 c = readByte(); 796 while (c) { 797 c = readByte(); 798 } 799 } 800 801 if (gpflags & 2) { 802 readByte(); 803 readByte(); 804 } 805 806 deflateLoop(); 807 808 crc = readByte(); 809 crc |= readByte() << 8; 810 crc |= readByte() << 16; 811 crc |= readByte() << 24; 812 813 size = readByte(); 814 size |= readByte() << 8; 815 size |= readByte() << 16; 816 size |= readByte() << 24; 817 818 if (modeZIP) { 819 if (nextFile()) { 820 // A file has been decompressed, we have to proceed 821 return false; 822 } 823 } 824 825 // We are here in non-ZIP-files only, 826 // In that case the eturn value doesn't matter 827 return false; 828 /* eslint-enable no-unused-vars */ 829 830 } 831 832 JXG.Util.Unzip.prototype.unzipFile = function (name) { 833 var i; 834 835 this.unzip(); 836 837 for (i = 0; i < unzipped.length; i++) { 838 if (unzipped[i][1] === name) { 839 return unzipped[i][0]; 840 } 841 } 842 843 return ""; 844 }; 845 846 JXG.Util.Unzip.prototype.unzip = function () { 847 nextFile(); 848 return unzipped; 849 }; 850 }; 851 852 export default JXG.Util; 853