      1 /*
      2     Copyright 2008-2013
      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, skipdir,
    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         function nextFile() {
    580             var i, c, extralen, filelen, size, compSize, crc, method,
    581                 tmp = [];
    582
    583             // Prevent problems on iOS7 with >>
    584             try {
    585                 outputArr = [];
    586                 modeZIP = false;
    587                 tmp[0] = readByte();
    588                 tmp[1] = readByte();
    589
    590                 //GZIP
    591                 if (tmp[0] === 0x78 && tmp[1] === 0xda) {
    592                     deflateLoop();
    593                     unzipped[files] = [outputArr.join(''), 'geonext.gxt'];
    594                     files++;
    595                 }
    596
    597                 //GZIP
    598                 if (tmp[0] === 0x1f && tmp[1] === 0x8b) {
    599                     skipdir();
    600                     unzipped[files] = [outputArr.join(''), 'file'];
    601                     files++;
    602                 }
    603
    604                 //ZIP
    605                 if (tmp[0] === 0x50 && tmp[1] === 0x4b) {
    606                     modeZIP = true;
    607                     tmp[2] = readByte();
    608                     tmp[3] = readByte();
    609
    610                     if (tmp[2] === 0x03 && tmp[3] === 0x04) {
    611                         //MODE_ZIP
    612                         tmp[0] = readByte();
    613                         tmp[1] = readByte();
    614
    615                         gpflags = readByte();
    616                         gpflags |= (readByte() << 8);
    617
    618                         method = readByte();
    619                         method |= (readByte() << 8);
    620
    621                         readByte();
    622                         readByte();
    623                         readByte();
    624                         readByte();
    625
    626                         crc = readByte();
    627                         crc |= (readByte() << 8);
    628                         crc |= (readByte() << 16);
    629                         crc |= (readByte() << 24);
    630
    631                         compSize = readByte();
    632                         compSize |= (readByte() << 8);
    633                         compSize |= (readByte() << 16);
    634                         compSize |= (readByte() << 24);
    635
    636                         size = readByte();
    637                         size |= (readByte() << 8);
    638                         size |= (readByte() << 16);
    639                         size |= (readByte() << 24);
    640
    641                         filelen = readByte();
    642                         filelen |= (readByte() << 8);
    643
    644                         extralen = readByte();
    645                         extralen |= (readByte() << 8);
    646
    647                         i = 0;
    648                         nameBuf = [];
    649
    650                         while (filelen--) {
    651                             c = readByte();
    652                             if (c === '/' | c === ':') {
    653                                 i = 0;
    654                             } else if (i < NAMEMAX - 1) {
    655                                 nameBuf[i++] = String.fromCharCode(c);
    656                             }
    657                         }
    658
    659                         if (!fileout) {
    660                             fileout = nameBuf;
    661                         }
    662
    663                         i = 0;
    664                         while (i < extralen) {
    665                             c = readByte();
    666                             i++;
    667                         }
    668
    669                         SIZE = 0;
    670
    671                         if (method === 8) {
    672                             deflateLoop();
    673                             unzipped[files] = new Array(2);
    674                             unzipped[files][0] = outputArr.join('');
    675                             unzipped[files][1] = nameBuf.join('');
    676                             files++;
    677                         }
    678
    679                         skipdir();
    680                     }
    681                 }
    682             } catch (e) {
    683                 throw e;
    684             }
    685         }
    686
    687         skipdir = function () {
    688             var crc, compSize, size, os, i, c,
    689                 tmp = [];
    690
    691             if ((gpflags & 8)) {
    692                 tmp[0] = readByte();
    693                 tmp[1] = readByte();
    694                 tmp[2] = readByte();
    695                 tmp[3] = readByte();
    696
    697                 if (tmp[0] === 0x50 &&
    698                         tmp[1] === 0x4b &&
    699                         tmp[2] === 0x07 &&
    700                         tmp[3] === 0x08) {
    701                     crc = readByte();
    702                     crc |= (readByte() << 8);
    703                     crc |= (readByte() << 16);
    704                     crc |= (readByte() << 24);
    705                 } else {
    706                     crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24);
    707                 }
    708
    709                 compSize = readByte();
    710                 compSize |= (readByte() << 8);
    711                 compSize |= (readByte() << 16);
    712                 compSize |= (readByte() << 24);
    713
    714                 size = readByte();
    715                 size |= (readByte() << 8);
    716                 size |= (readByte() << 16);
    717                 size |= (readByte() << 24);
    718             }
    719
    720             if (modeZIP) {
    721                 nextFile();
    722             }
    723
    724             tmp[0] = readByte();
    725             if (tmp[0] !== 8) {
    726                 return;
    727             }
    728
    729             gpflags = readByte();
    730
    731             readByte();
    732             readByte();
    733             readByte();
    734             readByte();
    735
    736             readByte();
    737             os = readByte();
    738
    739             if ((gpflags & 4)) {
    740                 tmp[0] = readByte();
    741                 tmp[2] = readByte();
    742                 len = tmp[0] + 256 * tmp[1];
    743                 for (i = 0; i < len; i++) {
    744                     readByte();
    745                 }
    746             }
    747
    748             if ((gpflags & 8)) {
    749                 i = 0;
    750                 nameBuf = [];
    751
    752                 c = readByte();
    753                 while (c) {
    754                     if (c === '7' || c === ':') {
    755                         i = 0;
    756                     }
    757
    758                     if (i < NAMEMAX - 1) {
    759                         nameBuf[i++] = c;
    760                     }
    761
    762                     c = readByte();
    763                 }
    764             }
    765
    766             if ((gpflags & 16)) {
    767                 c = readByte();
    768                 while (c) {
    769                     c = readByte();
    770                 }
    771             }
    772
    773             if ((gpflags & 2)) {
    774                 readByte();
    775                 readByte();
    776             }
    777
    778             deflateLoop();
    779
    780             crc = readByte();
    781             crc |= (readByte() << 8);
    782             crc |= (readByte() << 16);
    783             crc |= (readByte() << 24);
    784
    785             size = readByte();
    786             size |= (readByte() << 8);
    787             size |= (readByte() << 16);
    788             size |= (readByte() << 24);
    789
    790             if (modeZIP) {
    791                 nextFile();
    792             }
    793         };
    794
    795         JXG.Util.Unzip.prototype.unzipFile = function (name) {
    796             var i;
    797
    798             this.unzip();
    799
    800             for (i = 0; i < unzipped.length; i++) {
    801                 if (unzipped[i][1] === name) {
    802                     return unzipped[i][0];
    803                 }
    804             }
    805
    806             return '';
    807         };
    808
    809         JXG.Util.Unzip.prototype.unzip = function () {
    810             nextFile();
    811             return unzipped;
    812         };
    813     };
    814
    815     return JXG.Util;
    816 });
    817