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