text: /*
      Copyright 2008,2009
          Matthias Ehmann,
          Michael Gerhaeuser,
          Carsten Miller,
          Bianca Valentin,
          Alfred Wassermann,
          Peter Wilfahrt
  
      This file is part of JSXGraph.
  
      JSXGraph is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      JSXGraph is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.
  
      You should have received a copy of the GNU Lesser General Public License
      along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
  */
  
  /**
   * @fileoverview Utilities for uncompressing and base64 decoding
   */
  
  /**
    * @class Util class
    * Class for gunzipping, unzipping and base64 decoding of files.
    * It is used for reading GEONExT, Geogebra and Intergeo files.
    *
    * Only Huffman codes are decoded in gunzip.
    * The code is based on the source code for gunzip.c by Pasi Ojala 
    * @see <a href="http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c">http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c</a>
    * @see <a href="http://www.cs.tut.fi/~albert">http://www.cs.tut.fi/~albert</a>
    */
  var util = require('util');
  var Zlib = exports.Zlib = {};
        
  /**
   * Unzip zip files
   */
  Zlib.Unzip = function (barray){
      var outputArr = [],
          output = "",
          debug = false,
          gpflags,
          files = 0,
          unzipped = [],
          crc,
          buf32k = new Array(32768),
          bIdx = 0,
          modeZIP=false,
  
          CRC, SIZE,
      
          bitReverse = [
          0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
          0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
          0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
          0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
          0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
          0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
          0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
          0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
          0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
          0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
          0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
          0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
          0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
          0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
          0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
          0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
          0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
          0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
          0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
          0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
          0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
          0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
          0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
          0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
          0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
          0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
          0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
          0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
          0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
          0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
          0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
          0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
      ],
      
      cplens = [
          3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
          35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
      ],
  
      cplext = [
          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, 99, 99
      ], /* 99==invalid */
  
      cpdist = [
          0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d,
          0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1,
          0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01,
          0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
      ],
  
      cpdext = [
          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, 12, 13, 13
      ],
      
      border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
      
      bA = barray,
  
      bytepos=0,
      bitpos=0,
      bb = 1,
      bits=0,
      
      NAMEMAX = 256,
      
      nameBuf = [],
      
      fileout;
      
      function readByte(){
          bits+=8;
          if (bytepos<bA.length){
              //if (debug)
              //    document.write(bytepos+": "+bA[bytepos]+"<br>");
              // util.debug(bA[bytepos++].toString(16))
              // return String.fromCharCode(bA[bytepos++]);
              return bA[bytepos++];
          } else
              return -1;
      };
  
      function byteAlign(){
          bb = 1;
      };
      
      function readBit(){
          var carry;
          bits++;
          carry = (bb & 1);
          bb >>= 1;
          if (bb==0){
              bb = readByte();
              carry = (bb & 1);
              bb = (bb>>1) | 0x80;
          }
          return carry;
      };
  
      function readBits(a) {
          var res = 0,
              i = a;
      
          while(i--) {
              res = (res<<1) | readBit();
          }
          if(a) {
              res = bitReverse[res]>>(8-a);
          }
          return res;
      };
          
      function flushBuffer(){
          //document.write('FLUSHBUFFER:'+buf32k);
          bIdx = 0;
      };
      function addBuffer(a){
          SIZE++;
          //CRC=updcrc(a,crc);
          buf32k[bIdx++] = a;
          outputArr.push(String.fromCharCode(a));
          //output+=String.fromCharCode(a);
          if(bIdx==0x8000){
              //document.write('ADDBUFFER:'+buf32k);
              bIdx=0;
          }
      };
      
      function HufNode() {
          this.b0=0;
          this.b1=0;
          this.jump = null;
          this.jumppos = -1;
      };
  
      var LITERALS = 288;
      
      var literalTree = new Array(LITERALS);
      var distanceTree = new Array(32);
      var treepos=0;
      var Places = null;
      var Places2 = null;
      
      var impDistanceTree = new Array(64);
      var impLengthTree = new Array(64);
      
      var len = 0;
      var fpos = new Array(17);
      fpos[0]=0;
      var flens;
      var fmax;
      
      function IsPat() {
          while (1) {
              if (fpos[len] >= fmax)
                  return -1;
              if (flens[fpos[len]] == len)
                  return fpos[len]++;
              fpos[len]++;
          }
      };
  
      function Rec() {
          var curplace = Places[treepos];
          var tmp;
          if (debug)
            util.debug("len: " + len + " treepos: " + treepos)
          if(len==17) { //war 17
              return -1;
          }
          treepos++;
          len++;
      	
          tmp = IsPat();
          if (debug)
            util.debug("IsPat " + tmp)
          if(tmp >= 0) {
              curplace.b0 = tmp;    /* leaf cell for 0-bit */
              if (debug)
                util.debug("b0 " + curplace.b0)
          } else {
          /* Not a Leaf cell */
          curplace.b0 = 0x8000;
          if (debug)
            util.debug("b0 " + curplace.b0)
          if(Rec())
              return -1;
          }
          tmp = IsPat();
          if(tmp >= 0) {
              curplace.b1 = tmp;    /* leaf cell for 1-bit */
              if (debug)
                util.debug("b1 " + curplace.b1);
              curplace.jump = null;    /* Just for the display routine */
          } else {
              /* Not a Leaf cell */
              curplace.b1 = 0x8000;
              if (debug)
                util.debug("b1 " + curplace.b1);
              curplace.jump = Places[treepos];
              curplace.jumppos = treepos;
              if(Rec())
                  return -1;
          }
          len--;
          return 0;
      };
  
      function CreateTree(currentTree, numval, lengths, show) {
          var i;
          /* Create the Huffman decode tree/table */
          //document.write("<br>createtree<br>");
          if (debug)
            util.debug("currentTree " + currentTree + " numval " + numval + " lengths " + lengths + " show " + show);
          Places = currentTree;
          treepos=0;
          flens = lengths;
          fmax  = numval;
          for (i=0;i<17;i++)
              fpos[i] = 0;
          len = 0;
          if(Rec()) {
              //fprintf(stderr, "invalid huffman tree\n");
              if (debug)
                util.debug("invalid huffman tree");
              return -1;
          }
          if (debug){
            util.debug("Tree: " + Places.length);
          	for (var a=0;a<32;a++){
          	  util.debug("Places[" + a + "].b0=" + Places[a].b0);
          	  util.debug("Places[" + a + "].b1=" + Places[a].b1);
          	}
          }
      
          /*if(show) {
              var tmp;
              for(tmp=currentTree;tmp<Places;tmp++) {
                  fprintf(stdout, "0x%03x  0x%03x (0x%04x)",tmp-currentTree, tmp->jump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0);
                  if(!(tmp.b0 & 0x8000)) {
                      //fprintf(stdout, "  0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�');
                  }
                  if(!(tmp.b1 & 0x8000)) {
                      if((tmp.b0 & 0x8000))
                          fprintf(stdout, "           ");
                      fprintf(stdout, "  0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�');
                  }
                  fprintf(stdout, "\n");
              }
          }*/
          return 0;
      };
      
      function DecodeValue(currentTree) {
          var len, i,
              xtreepos=0,
              X = currentTree[xtreepos],
              b;
  
          /* decode one symbol of the data */
          while(1) {
              b=readBit();
              if (debug)
                util.debug("b=" + b);
              if(b) {
                  if(!(X.b1 & 0x8000)){
                  	if (debug)
                  	  util.debug("ret1");
                      return X.b1;    /* If leaf node, return data */
                  }
                  X = X.jump;
                  len = currentTree.length;
                  for (i=0;i<len;i++){
                      if (currentTree[i]===X){
                          xtreepos=i;
                          break;
                      }
                  }
                  //xtreepos++;
              } else {
                  if(!(X.b0 & 0x8000)){
                  	if (debug)
                  	  util.debug("ret2");
                      return X.b0;    /* If leaf node, return data */
                  }
                  //X++; //??????????????????
                  xtreepos++;
                  X = currentTree[xtreepos];
              }
          }
          if (debug)
            util.debug("ret3");
          return -1;
      };
      
      function DeflateLoop() {
      var last, c, type, i, len;
  
      do {
          /*if((last = readBit())){
              fprintf(errfp, "Last Block: ");
          } else {
              fprintf(errfp, "Not Last Block: ");
          }*/
          last = readBit();
          type = readBits(2);
          
          switch(type) {
              case 0:
              	if (debug)
              	    util.debug("Stored");
                  break;
              case 1:
              	if (debug)
                    util.debug("Fixed Huffman codes");
                  break;
              case 2:
              	if (debug)
              	    util.debug("Dynamic Huffman codes");
                  break;
              case 3:
              	if (debug)
                    util.debug("Reserved block type!!");
                  break;
              default:
              	if (debug)
                    util.debug("Unexpected value " + type);
                  break;
          }
          
          if(type==0) {
              var blockLen, cSum;
  
              // Stored 
              byteAlign();
              blockLen = readByte();
              blockLen |= (readByte()<<8);
  
              cSum = readByte();
              cSum |= (readByte()<<8);
  
              if(((blockLen ^ ~cSum) & 0xffff)) {
                util.debug("BlockLen checksum mismatch");
              }
              while(blockLen--) {
                  c = readByte();
                  addBuffer(c);
              }
          } else if(type==1) {
              var j;
  
              /* Fixed Huffman tables -- fixed decode routine */
              while(1) {
              /*
                  256    0000000        0
                  :   :     :
                  279    0010111        23
                  0   00110000    48
                  :    :      :
                  143    10111111    191
                  280 11000000    192
                  :    :      :
                  287 11000111    199
                  144    110010000    400
                  :    :       :
                  255    111111111    511
      
                  Note the bit order!
                  */
  
              j = (bitReverse[readBits(7)]>>1);
              if(j > 23) {
                  j = (j<<1) | readBit();    /* 48..255 */
  
                  if(j > 199) {    /* 200..255 */
                      j -= 128;    /*  72..127 */
                      j = (j<<1) | readBit();        /* 144..255 << */
                  } else {        /*  48..199 */
                      j -= 48;    /*   0..151 */
                      if(j > 143) {
                          j = j+136;    /* 280..287 << */
                          /*   0..143 << */
                      }
                  }
              } else {    /*   0..23 */
                  j += 256;    /* 256..279 << */
              }
              if(j < 256) {
                  addBuffer(j);
                  //document.write("out:"+String.fromCharCode(j));
                  /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/
              } else if(j == 256) {
                  /* EOF */
                  break;
              } else {
                  var len, dist;
  
                  j -= 256 + 1;    /* bytes + EOF */
                  len = readBits(cplext[j]) + cplens[j];
  
                  j = bitReverse[readBits(5)]>>3;
                  if(cpdext[j] > 8) {
                      dist = readBits(8);
                      dist |= (readBits(cpdext[j]-8)<<8);
                  } else {
                      dist = readBits(cpdext[j]);
                  }
                  dist += cpdist[j];
  
                  /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/
                  for(j=0;j<len;j++) {
                      var c = buf32k[(bIdx - dist) & 0x7fff];
                      addBuffer(c);
                  }
              }
              } // while
          } else if(type==2) {
              var j, n, literalCodes, distCodes, lenCodes;
              var ll = new Array(288+32);    // "static" just to preserve stack
      
              // Dynamic Huffman tables 
      
              literalCodes = 257 + readBits(5);
              distCodes = 1 + readBits(5);
              lenCodes = 4 + readBits(4);
              //document.write("<br>param: "+literalCodes+" "+distCodes+" "+lenCodes+"<br>");
              for(j=0; j<19; j++) {
                  ll[j] = 0;
              }
      
              // Get the decode tree code lengths
      
              //document.write("<br>");
              for(j=0; j<lenCodes; j++) {
                  ll[border[j]] = readBits(3);
                  //document.write(ll[border[j]]+" ");
              }
              //fprintf(errfp, "\n");
              //document.write('<br>ll:'+ll);
              len = distanceTree.length;
              for (i=0; i<len; i++)
                  distanceTree[i]=new HufNode();
              if(CreateTree(distanceTree, 19, ll, 0)) {
                  flushBuffer();
                  return 1;
              }
              if (debug){
                util.debug("distanceTree");
              	for(var a=0;a<distanceTree.length;a++){
                    util.debug("" + distanceTree[a].b0 + " " + distanceTree[a].b1 + " " + distanceTree[a].jump + " " + distanceTree[a].jumppos);
                  	/*if (distanceTree[a].jumppos!=-1)
                      	document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1);
                  	*/
              	}
              }
              //document.write('<BR>tree created');
      
              //read in literal and distance code lengths
              n = literalCodes + distCodes;
              i = 0;
              var z=-1;
              if (debug)
                util.debug("n=" + n + " bits: " + bits);
              while(i < n) {
                  z++;
                  j = DecodeValue(distanceTree);
                  if (debug)
                    util.debug("" + z + " i:" + i + " decode: " + j + "    bits" + bits);
                  if(j<16) {    // length of code in bits (0..15)
                         ll[i++] = j;
                  } else if(j==16) {    // repeat last length 3 to 6 times 
                         var l;
                      j = 3 + readBits(2);
                      if(i+j > n) {
                          flushBuffer();
                          return 1;
                      }
                      l = i ? ll[i-1] : 0;
                      while(j--) {
                          ll[i++] = l;
                      }
                  } else {
                      if(j==17) {        // 3 to 10 zero length codes
                          j = 3 + readBits(3);
                      } else {        // j == 18: 11 to 138 zero length codes 
                          j = 11 + readBits(7);
                      }
                      if(i+j > n) {
                          flushBuffer();
                          return 1;
                      }
                      while(j--) {
                          ll[i++] = 0;
                      }
                  }
              }
              /*for(j=0; j<literalCodes+distCodes; j++) {
                  //fprintf(errfp, "%d ", ll[j]);
                  if ((j&7)==7)
                      fprintf(errfp, "\n");
              }
              fprintf(errfp, "\n");*/
              // Can overwrite tree decode tree as it is not used anymore
              len = literalTree.length;
              for (i=0; i<len; i++)
                  literalTree[i]=new HufNode();
              if(CreateTree(literalTree, literalCodes, ll, 0)) {
                  flushBuffer();
                  return 1;
              }
              len = literalTree.length;
              for (i=0; i<len; i++)
                  distanceTree[i]=new HufNode();
              var ll2 = new Array();
              for (i=literalCodes; i <ll.length; i++){
                  ll2[i-literalCodes]=ll[i];
              }    
              if(CreateTree(distanceTree, distCodes, ll2, 0)) {
                  flushBuffer();
                  return 1;
              }
              if (debug)
                util.debug("literalTree");
              while(1) {
                  j = DecodeValue(literalTree);
                  if(j >= 256) {        // In C64: if carry set
                      var len, dist;
                      j -= 256;
                      if(j == 0) {
                          // EOF
                          break;
                      }
                      j--;
                      len = readBits(cplext[j]) + cplens[j];
      
                      j = DecodeValue(distanceTree);
                      if(cpdext[j] > 8) {
                          dist = readBits(8);
                          dist |= (readBits(cpdext[j]-8)<<8);
                      } else {
                          dist = readBits(cpdext[j]);
                      }
                      dist += cpdist[j];
                      while(len--) {
                          var c = buf32k[(bIdx - dist) & 0x7fff];
                          addBuffer(c);
                      }
                  } else {
                      addBuffer(j);
                  }
              }
          }
      } while(!last);
      flushBuffer();
  
      byteAlign();
      return 0;
  };
  
  Zlib.Unzip.prototype.unzipFile = function(name) {
      var i;
  	this.unzip();
  	//alert(unzipped[0][1]);
  	for (i=0;i<unzipped.length;i++){
  		if(unzipped[i][1]==name) {
  			return unzipped[i][0];
  		}
  	}
  	
    };
      
      
  Zlib.Unzip.prototype.unzip = function() {
  	//convertToByteArray(input);
  	if (debug)
  	  util.debug(bA);
  	/*for (i=0;i<bA.length*8;i++){
  		document.write(readBit());
  		if ((i+1)%8==0)
  			document.write(" ");
  	}*/
  	/*for (i=0;i<bA.length;i++){
  		document.write(readByte()+" ");
  		if ((i+1)%8==0)
  			document.write(" ");
  	}
  	for (i=0;i<bA.length;i++){
  		document.write(bA[i]+" ");
  		if ((i+1)%16==0)
  			document.write("<br>");
  	}	
  	*/
  	//alert(bA);
  	nextFile();
  	return unzipped;
    };
      
   function nextFile(){
   	if (debug)
   	  util.debug("NEXTFILE");
   	outputArr = [];
   	var tmp = [];
   	modeZIP = false;
  	tmp[0] = readByte();
  	tmp[1] = readByte();
  	
  	if (debug)
  	  util.debug("type: " + tmp[0] + " " + tmp[1]);
  	if (tmp[0] == parseInt("78",16) && (tmp[1] == parseInt("156",10) || tmp[1] == parseInt("1", 10))){ //GZIP
  		if (debug)
  		  util.debug("GEONExT-GZIP");
  		DeflateLoop();
  		if (debug)
  	    util.debug(outputArr.join(''));
      // unzipped[files] = new Array(2);
      	unzipped[files] = outputArr.join('');
      	files++;
  	}
  	if (tmp[0] == parseInt("1f",16) && tmp[1] == parseInt("8b",16)){ //GZIP
  		if (debug)
        util.debug("GZIP");
  		//DeflateLoop();
  		skipdir();
  		if (debug)
        util.debug(outputArr.join(''));
  		unzipped[files] = new Array(2);
      	unzipped[files][0] = outputArr.join('');
      	unzipped[files][1] = "file";
      	files++;
  	}
  	if (tmp[0] == parseInt("50",16) && tmp[1] == parseInt("4b",16)){ //ZIP
  		modeZIP = true;
  		tmp[2] = readByte();
  		tmp[3] = readByte();
  		if (tmp[2] == parseInt("3",16) && tmp[3] == parseInt("4",16)){
  			//MODE_ZIP
  			tmp[0] = readByte();
  			tmp[1] = readByte();
  			if (debug)
          util.debug("ZIP-Version: "+tmp[1]+" "+tmp[0]/10+"."+tmp[0]%10);
  			
  			gpflags = readByte();
  			gpflags |= (readByte()<<8);
  			if (debug)
          util.debug("gpflags: "+gpflags);
  			
  			var method = readByte();
  			method |= (readByte()<<8);
  			if (debug)
          util.debug("method: "+method);
  			
  			readByte();
  			readByte();
  			readByte();
  			readByte();
  			
  			var crc = readByte();
  			crc |= (readByte()<<8);
  			crc |= (readByte()<<16);
  			crc |= (readByte()<<24);
  			
  			var compSize = readByte();
  			compSize |= (readByte()<<8);
  			compSize |= (readByte()<<16);
  			compSize |= (readByte()<<24);
  			
  			var size = readByte();
  			size |= (readByte()<<8);
  			size |= (readByte()<<16);
  			size |= (readByte()<<24);
  			
  			if (debug)
  			  util.debug("local CRC: "+crc+"\nlocal Size: "+size+"\nlocal CompSize: "+compSize);
  			
  			var filelen = readByte();
  			filelen |= (readByte()<<8);
  			
  			var extralen = readByte();
  			extralen |= (readByte()<<8);
  			
  			if (debug)
  			  util.debug("filelen "+filelen);
  			i = 0;
  			nameBuf = [];
  			while (filelen--){ 
  				var c = readByte();
  				if (c == "/" | c ==":"){
  					i = 0;
  				} else if (i < NAMEMAX-1)
  					nameBuf[i++] = String.fromCharCode(c);
  			}
  			if (debug)
  			  util.debug("nameBuf: "+nameBuf);
  			
  			//nameBuf[i] = "\0";
  			if (!fileout)
  				fileout = nameBuf;
  			
  			var i = 0;
  			while (i < extralen){
  				c = readByte();
  				i++;
  			}
  				
  			CRC = 0xffffffff;
  			SIZE = 0;
  			
  			if (size = 0 && fileOut.charAt(fileout.length-1)=="/"){
  				//skipdir
  				if (debug)
  				  util.debug("skipdir");
  			}
  			if (method == 8){
  				DeflateLoop();
  				if (debug)
  				  util.debug(outputArr.join(''));
  				unzipped[files] = new Array(2);
  				unzipped[files][0] = outputArr.join('');
      			unzipped[files][1] = nameBuf.join('');
      			files++;
  				//return outputArr.join('');
  			}
  			skipdir();
  		}
  	}
   };
  	
  function skipdir(){
      var crc, 
          tmp = [],
          compSize, size, os, i, c;
      
  	if ((gpflags & 8)) {
  		tmp[0] = readByte();
  		tmp[1] = readByte();
  		tmp[2] = readByte();
  		tmp[3] = readByte();
  		
  		if (tmp[0] == parseInt("50",16) && 
              tmp[1] == parseInt("4b",16) && 
              tmp[2] == parseInt("07",16) && 
              tmp[3] == parseInt("08",16))
          {
              crc = readByte();
              crc |= (readByte()<<8);
              crc |= (readByte()<<16);
              crc |= (readByte()<<24);
  		} else {
  			crc = tmp[0] | (tmp[1]<<8) | (tmp[2]<<16) | (tmp[3]<<24);
  		}
  		
  		compSize = readByte();
  		compSize |= (readByte()<<8);
  		compSize |= (readByte()<<16);
  		compSize |= (readByte()<<24);
  		
  		size = readByte();
  		size |= (readByte()<<8);
  		size |= (readByte()<<16);
  		size |= (readByte()<<24);
  		
  		if (debug)
  		  util.debug("CRC:");
  	}
  
  	if (modeZIP)
  		nextFile();
  	
  	tmp[0] = readByte();
  	if (tmp[0] != 8) {
  		if (debug)
  		  util.debug("Unknown compression method!");
          return 0;	
  	}
  	
  	gpflags = readByte();
  	if (debug){
  		if ((gpflags & ~(parseInt("1f",16))))
  		  util.debug("Unknown flags set!");
  	}
  	
  	readByte();
  	readByte();
  	readByte();
  	readByte();
  	
  	readByte();
  	os = readByte();
  	
  	if ((gpflags & 4)){
  		tmp[0] = readByte();
  		tmp[2] = readByte();
  		len = tmp[0] + 256*tmp[1];
  		if (debug)
  		  util.debug("Extra field size: "+len);
  		for (i=0;i<len;i++)
  			readByte();
  	}
  	
  	if ((gpflags & 8)){
  		i=0;
  		nameBuf=[];
  		while (c=readByte()){
  			if(c == "7" || c == ":")
  				i=0;
  			if (i<NAMEMAX-1)
  				nameBuf[i++] = c;
  		}
  		//nameBuf[i] = "\0";
  		if (debug)
  		  util.debug("original file name: "+nameBuf);
  	}
  		
  	if ((gpflags & 16)){
  		while (c=readByte()){
  			//FILE COMMENT
  		}
  	}
  	
  	if ((gpflags & 2)){
  		readByte();
  		readByte();
  	}
  	
  	DeflateLoop();
  	
  	crc = readByte();
  	crc |= (readByte()<<8);
  	crc |= (readByte()<<16);
  	crc |= (readByte()<<24);
  	
  	size = readByte();
  	size |= (readByte()<<8);
  	size |= (readByte()<<16);
  	size |= (readByte()<<24);
  	
  	if (modeZIP)
  		nextFile();
  	
  };
  
  };
  
  /**
  *  Base64 encoding / decoding
  *  @see <a href="http://www.webtoolkit.info/">http://www.webtoolkit.info/</A>
  */
  Zlib.Base64 = {
  
      // private property
      _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  
      // public method for encoding
      encode : function (input) {
          var output = [],
              chr1, chr2, chr3, enc1, enc2, enc3, enc4,
              i = 0;
  
          input = Zlib.Base64._utf8_encode(input);
  
          while (i < input.length) {
  
              chr1 = input.charCodeAt(i++);
              chr2 = input.charCodeAt(i++);
              chr3 = input.charCodeAt(i++);
  
              enc1 = chr1 >> 2;
              enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
              enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
              enc4 = chr3 & 63;
  
              if (isNaN(chr2)) {
                  enc3 = enc4 = 64;
              } else if (isNaN(chr3)) {
                  enc4 = 64;
              }
  
              output.push([this._keyStr.charAt(enc1),
                           this._keyStr.charAt(enc2),
                           this._keyStr.charAt(enc3),
                           this._keyStr.charAt(enc4)].join(''));
          }
  
          return output.join('');
      },
  
      // public method for decoding
      decode : function (input, utf8) {
          var output = [],
              chr1, chr2, chr3,
              enc1, enc2, enc3, enc4,
              i = 0;
  
          input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  
          while (i < input.length) {
  
              enc1 = this._keyStr.indexOf(input.charAt(i++));
              enc2 = this._keyStr.indexOf(input.charAt(i++));
              enc3 = this._keyStr.indexOf(input.charAt(i++));
              enc4 = this._keyStr.indexOf(input.charAt(i++));
  
              chr1 = (enc1 << 2) | (enc2 >> 4);
              chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
              chr3 = ((enc3 & 3) << 6) | enc4;
  
              output.push(String.fromCharCode(chr1));
  
              if (enc3 != 64) {
                  output.push(String.fromCharCode(chr2));
              }
              if (enc4 != 64) {
                  output.push(String.fromCharCode(chr3));
              }
          }
          
          output = output.join(''); 
          
          if (utf8) {
              output = Zlib.Base64._utf8_decode(output);
          }
          return output;
  
      },
  
      // private method for UTF-8 encoding
      _utf8_encode : function (string) {
          string = string.replace(/\r\n/g,"\n");
          var utftext = "";
  
          for (var n = 0; n < string.length; n++) {
  
              var c = string.charCodeAt(n);
  
              if (c < 128) {
                  utftext += String.fromCharCode(c);
              }
              else if((c > 127) && (c < 2048)) {
                  utftext += String.fromCharCode((c >> 6) | 192);
                  utftext += String.fromCharCode((c & 63) | 128);
              }
              else {
                  utftext += String.fromCharCode((c >> 12) | 224);
                  utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                  utftext += String.fromCharCode((c & 63) | 128);
              }
  
          }
  
          return utftext;
      },
  
      // private method for UTF-8 decoding
      _utf8_decode : function (utftext) {
          var string = [],
              i = 0,
              c = 0, c2 = 0, c3 = 0;
  
          while ( i < utftext.length ) {
              c = utftext.charCodeAt(i);
              if (c < 128) {
                  string.push(String.fromCharCode(c));
                  i++;
              }
              else if((c > 191) && (c < 224)) {
                  c2 = utftext.charCodeAt(i+1);
                  string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
                  i += 2;
              }
              else {
                  c2 = utftext.charCodeAt(i+1);
                  c3 = utftext.charCodeAt(i+2);
                  string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
                  i += 3;
              }
          }
          return string.join('');
      },
      
      _destrip: function (stripped, wrap){
          var lines = [], lineno, i,
              destripped = [];
          
          if (wrap==null) 
              wrap = 76;
              
          stripped.replace(/ /g, "");
          lineno = stripped.length / wrap;
          for (i = 0; i < lineno; i++)
              lines[i]=stripped.substr(i * wrap, wrap);
          if (lineno != stripped.length / wrap)
              lines[lines.length]=stripped.substr(lineno * wrap, stripped.length-(lineno * wrap));
              
          for (i = 0; i < lines.length; i++)
              destripped.push(lines[i]);
          return destripped.join('\n');
      },
      
      decodeAsArray: function (input){
          var dec = this.decode(input),
              ar = [], i;
          for (i=0;i<dec.length;i++){
              ar[i]=dec.charCodeAt(i);
          }
          return ar;
      },
      
      decodeGEONExT : function (input) {
          return decodeAsArray(destrip(input),false);
      }
  };
  
  /**
   * @private
   */
  Zlib.asciiCharCodeAt = function(str,i){
  	var c = str.charCodeAt(i);
  	if (c>255){
      	switch (c) {
  			case 8364: c=128;
  	    	break;
  	    	case 8218: c=130;
  	    	break;
  	    	case 402: c=131;
  	    	break;
  	    	case 8222: c=132;
  	    	break;
  	    	case 8230: c=133;
  	    	break;
  	    	case 8224: c=134;
  	    	break;
  	    	case 8225: c=135;
  	    	break;
  	    	case 710: c=136;
  	    	break;
  	    	case 8240: c=137;
  	    	break;
  	    	case 352: c=138;
  	    	break;
  	    	case 8249: c=139;
  	    	break;
  	    	case 338: c=140;
  	    	break;
  	    	case 381: c=142;
  	    	break;
  	    	case 8216: c=145;
  	    	break;
  	    	case 8217: c=146;
  	    	break;
  	    	case 8220: c=147;
  	    	break;
  	    	case 8221: c=148;
  	    	break;
  	    	case 8226: c=149;
  	    	break;
  	    	case 8211: c=150;
  	    	break;
  	    	case 8212: c=151;
  	    	break;
  	    	case 732: c=152;
  	    	break;
  	    	case 8482: c=153;
  	    	break;
  	    	case 353: c=154;
  	    	break;
  	    	case 8250: c=155;
  	    	break;
  	    	case 339: c=156;
  	    	break;
  	    	case 382: c=158;
  	    	break;
  	    	case 376: c=159;
  	    	break;
  	    	default:
  	    	break;
  	    }
  	}
  	return c;
  };
  
  /**
   * Decoding string into utf-8
   * @param {String} string to decode
   * @return {String} utf8 decoded string
   */
  Zlib.utf8Decode = function(utftext) {
    var string = [];
    var i = 0;
    var c = 0, c1 = 0, c2 = 0;
  
    while ( i < utftext.length ) {
      c = utftext.charCodeAt(i);
  
      if (c < 128) {
        string.push(String.fromCharCode(c));
        i++;
      } else if((c > 191) && (c < 224)) {
        c2 = utftext.charCodeAt(i+1);
        string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
        i += 2;
      } else {
        c2 = utftext.charCodeAt(i+1);
        c3 = utftext.charCodeAt(i+2);
        string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
        i += 3;
      }
    };
    return string.join('');
  };