1 /*
  2     Copyright 2008-2023
  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";
 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         crc,
104         SIZE,
105         fileout,
106         flens,
107         fmax,
108         outputArr = [],
109         output = "",
110         debug = false,
111         files = 0,
112         unzipped = [],
113         buf32k = new Array(32768),
114         bIdx = 0,
115         modeZIP = false,
116         barraylen = barray.length,
117         bytepos = 0,
118         bitpos = 0,
119         bb = 1,
120         bits = 0,
121         literalTree = new Array(288),
122         distanceTree = new Array(32),
123         treepos = 0,
124         Places = null,
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         var i,
576             c,
577             extralen,
578             filelen,
579             size,
580             compSize,
581             crc,
582             method,
583             tmp = [];
584 
585         // Prevent problems on iOS7 with >>
586         try {
587             outputArr = [];
588             modeZIP = false;
589             tmp[0] = readByte();
590             tmp[1] = readByte();
591 
592             //GZIP
593             if (tmp[0] === 0x78 && tmp[1] === 0xda) {
594                 deflateLoop();
595                 unzipped[files] = [outputArr.join(""), "geonext.gxt"];
596                 files++;
597             }
598 
599             //GZIP
600             if (tmp[0] === 0x1f && tmp[1] === 0x8b) {
601                 skipdir();
602                 unzipped[files] = [outputArr.join(""), "file"];
603                 files++;
604             }
605 
606             //ZIP
607             if (tmp[0] === 0x50 && tmp[1] === 0x4b) {
608                 modeZIP = true;
609                 tmp[2] = readByte();
610                 tmp[3] = readByte();
611 
612                 if (tmp[2] === 0x03 && tmp[3] === 0x04) {
613                     //MODE_ZIP
614                     tmp[0] = readByte();
615                     tmp[1] = readByte();
616 
617                     gpflags = readByte();
618                     gpflags |= readByte() << 8;
619 
620                     method = readByte();
621                     method |= readByte() << 8;
622 
623                     readByte();
624                     readByte();
625                     readByte();
626                     readByte();
627 
628                     crc = readByte();
629                     crc |= readByte() << 8;
630                     crc |= readByte() << 16;
631                     crc |= readByte() << 24;
632 
633                     compSize = readByte();
634                     compSize |= readByte() << 8;
635                     compSize |= readByte() << 16;
636                     compSize |= readByte() << 24;
637 
638                     size = readByte();
639                     size |= readByte() << 8;
640                     size |= readByte() << 16;
641                     size |= readByte() << 24;
642 
643                     filelen = readByte();
644                     filelen |= readByte() << 8;
645 
646                     extralen = readByte();
647                     extralen |= readByte() << 8;
648 
649                     i = 0;
650                     nameBuf = [];
651 
652                     while (filelen--) {
653                         c = readByte();
654                         if ((c === "/") | (c === ":")) {
655                             i = 0;
656                         } else if (i < NAMEMAX - 1) {
657                             nameBuf[i++] = String.fromCharCode(c);
658                         }
659                     }
660 
661                     if (!fileout) {
662                         fileout = nameBuf;
663                     }
664 
665                     i = 0;
666                     while (i < extralen) {
667                         c = readByte();
668                         i++;
669                     }
670 
671                     SIZE = 0;
672                     if (method === 8) {
673                         deflateLoop();
674                         unzipped[files] = new Array(2);
675                         unzipped[files][0] = outputArr.join("");
676                         unzipped[files][1] = nameBuf.join("");
677                         files++;
678                     }
679 
680                     if (skipdir()) {
681                         // We are beyond the files' data in the zip archive.
682                         // Let's get out immediately...
683                         return false;
684                     }
685                 }
686                 return true;
687             }
688         } catch (e) {
689             console.log("Probably problems on iOS7 with >>");
690             throw e;
691         }
692         return false;
693     }
694 
695     /**
696      * Test if the end of the files' data part of the archive has baseElement
697      * reached. If not, uncompressing is resumed.
698      *
699      * @return {Boolean}  true if the end of the files' data sections have
700      * been reached.
701      *
702      * @private
703      */
704     function skipdir() {
705         var crc, compSize, size, os, i, c,
706             tmp = [];
707 
708         if (gpflags & 8) {
709             tmp[0] = readByte();
710             tmp[1] = readByte();
711             tmp[2] = readByte();
712             tmp[3] = readByte();
713 
714             // signature for data descriptor record: 0x08074b50
715             // 12 bytes:
716             //  crc 4 bytes
717             //  compressed size 4 bytes
718             // uncompressed size 4 bytes
719             if (tmp[0] === 0x50 && tmp[1] === 0x4b && tmp[2] === 0x07 && tmp[3] === 0x08) {
720                 crc = readByte();
721                 crc |= readByte() << 8;
722                 crc |= readByte() << 16;
723                 crc |= readByte() << 24;
724             } else {
725                 crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24);
726             }
727 
728             compSize = readByte();
729             compSize |= readByte() << 8;
730             compSize |= readByte() << 16;
731             compSize |= readByte() << 24;
732 
733             size = readByte();
734             size |= readByte() << 8;
735             size |= readByte() << 16;
736             size |= readByte() << 24;
737         }
738 
739         if (modeZIP) {
740             if (nextFile()) {
741                 // A file has been decompressed, we have to proceed
742                 return false;
743             }
744         }
745 
746         tmp[0] = readByte();
747         if (tmp[0] !== 8) {
748             // It seems, we are beyond the files' data in the zip archive.
749             // We'll skip the rest..
750             return true;
751         }
752 
753         // There is another file in the zip file. We proceed...
754         gpflags = readByte();
755 
756         readByte();
757         readByte();
758         readByte();
759         readByte();
760 
761         readByte();
762         os = readByte();
763 
764         if (gpflags & 4) {
765             tmp[0] = readByte();
766             tmp[2] = readByte();
767             len = tmp[0] + 256 * tmp[1];
768             for (i = 0; i < len; i++) {
769                 readByte();
770             }
771         }
772 
773         if (gpflags & 8) {
774             i = 0;
775             nameBuf = [];
776 
777             c = readByte();
778             while (c) {
779                 if (c === "7" || c === ":") {
780                     i = 0;
781                 }
782 
783                 if (i < NAMEMAX - 1) {
784                     nameBuf[i++] = c;
785                 }
786 
787                 c = readByte();
788             }
789         }
790 
791         if (gpflags & 16) {
792             c = readByte();
793             while (c) {
794                 c = readByte();
795             }
796         }
797 
798         if (gpflags & 2) {
799             readByte();
800             readByte();
801         }
802 
803         deflateLoop();
804 
805         crc = readByte();
806         crc |= readByte() << 8;
807         crc |= readByte() << 16;
808         crc |= readByte() << 24;
809 
810         size = readByte();
811         size |= readByte() << 8;
812         size |= readByte() << 16;
813         size |= readByte() << 24;
814 
815         if (modeZIP) {
816             if (nextFile()) {
817                 // A file has been decompressed, we have to proceed
818                 return false;
819             }
820         }
821 
822         // We are here in non-ZIP-files only,
823         // In that case the eturn value doesn't matter
824         return false;
825     }
826 
827     JXG.Util.Unzip.prototype.unzipFile = function (name) {
828         var i;
829 
830         this.unzip();
831 
832         for (i = 0; i < unzipped.length; i++) {
833             if (unzipped[i][1] === name) {
834                 return unzipped[i][0];
835             }
836         }
837 
838         return "";
839     };
840 
841     JXG.Util.Unzip.prototype.unzip = function () {
842         nextFile();
843         return unzipped;
844     };
845 };
846 
847 export default JXG.Util;
848