nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

js-unzip.js (4891B)


      1 (function (GLOBAL) {
      2     function decodeUTF8(s){
      3         return decodeURIComponent(escape(s));
      4     }
      5 
      6     var JSUnzip = function (fileContents) {
      7         this.fileContents = new JSUnzip.BigEndianBinaryStream(fileContents);
      8     }
      9     GLOBAL.JSUnzip = JSUnzip;
     10     JSUnzip.MAGIC_NUMBER = 0x04034b50;
     11 
     12     JSUnzip.prototype = {
     13         readEntries: function () {
     14             if (!this.isZipFile()) {
     15                 throw new Error("File is not a Zip file.");
     16             }
     17 
     18             this.entries = [];
     19             var e = new JSUnzip.ZipEntry(this.fileContents);
     20             while (typeof(e.data) === "string") {
     21                 this.entries.push(e);
     22                 e = new JSUnzip.ZipEntry(this.fileContents);
     23             }
     24         },
     25 
     26         isZipFile: function () {
     27             return this.fileContents.getByteRangeAsNumber(0, 4) === JSUnzip.MAGIC_NUMBER;
     28         }
     29     }
     30 
     31     JSUnzip.ZipEntry = function (binaryStream) {
     32         this.signature          = binaryStream.getNextBytesAsNumber(4);
     33         if (this.signature !== JSUnzip.MAGIC_NUMBER) {
     34             return;
     35         }
     36 
     37         this.versionNeeded      = binaryStream.getNextBytesAsNumber(2);
     38         this.bitFlag            = binaryStream.getNextBytesAsNumber(2);
     39         this.compressionMethod  = binaryStream.getNextBytesAsNumber(2);
     40         this.timeBlob           = binaryStream.getNextBytesAsNumber(4);
     41 
     42         if (this.isEncrypted()) {
     43             throw "File contains encrypted entry. Not supported.";
     44         }
     45 
     46 
     47         this.crc32              = binaryStream.getNextBytesAsNumber(4);
     48         this.compressedSize     = binaryStream.getNextBytesAsNumber(4);
     49         this.uncompressedSize   = binaryStream.getNextBytesAsNumber(4);
     50 
     51         if (this.isUsingZip64()) {
     52             throw "File is using Zip64 (4gb+ file size). Not supported";
     53         }
     54 
     55         this.fileNameLength     = binaryStream.getNextBytesAsNumber(2);
     56         this.extraFieldLength   = binaryStream.getNextBytesAsNumber(2);
     57 
     58         this.fileName  = binaryStream.getNextBytesAsString(this.fileNameLength);
     59         this.extra     = binaryStream.getNextBytesAsString(this.extraFieldLength);
     60         this.data      = binaryStream.getNextBytesAsString(this.compressedSize);
     61 
     62         if (this.isUsingBit3TrailingDataDescriptor()) {
     63             if (typeof(console) !== "undefined") {
     64                 console.log( "File is using bit 3 trailing data descriptor. Not supported.");
     65             }
     66             binaryStream.getNextBytesAsNumber(16);  //Skip the descriptor and move to beginning of next ZipEntry
     67         }
     68 
     69         if (this.isUsingUtf8()) {
     70             this.fileName = decodeUTF8(this.fileName);
     71         }
     72 
     73     }
     74 
     75     JSUnzip.ZipEntry.prototype = {
     76         isEncrypted: function () {
     77             return (this.bitFlag & 0x01) === 0x01;
     78         },
     79 
     80         isUsingUtf8: function () {
     81             return (this.bitFlag & 0x0800) === 0x0800;
     82         },
     83 
     84         isUsingBit3TrailingDataDescriptor: function () {
     85             return (this.bitFlag & 0x0008) === 0x0008;
     86         },
     87 
     88         isUsingZip64: function () {
     89             return this.compressedSize === 0xFFFFFFFF ||
     90                 this.uncompressedSize === 0xFFFFFFFF;
     91         }
     92     }
     93 
     94     JSUnzip.BigEndianBinaryStream = function (stream) {
     95         this.stream = stream;
     96         this.resetByteIndex();
     97     }
     98 
     99     JSUnzip.BigEndianBinaryStream.prototype = {
    100         // The index of the current byte, used when we step through the byte
    101         // with getNextBytesAs*.
    102         resetByteIndex: function () {
    103             this.currentByteIndex = 0;
    104         },
    105 
    106         getByteAt: function (index) {
    107             return this.stream.charCodeAt(index);
    108         },
    109 
    110         getNextBytesAsNumber: function (steps) {
    111             var res = this.getByteRangeAsNumber(this.currentByteIndex, steps);
    112             this.currentByteIndex += steps;
    113             return res;
    114         },
    115 
    116         getNextBytesAsString: function (steps) {
    117             var res = this.getByteRangeAsString(this.currentByteIndex, steps);
    118             this.currentByteIndex += steps;
    119             return res;
    120         },
    121 
    122         // Big endian, so we're going backwards.
    123         getByteRangeAsNumber: function (index, steps) {
    124             var result = 0;
    125             var i = index + steps - 1;
    126             while (i >= index) {
    127                 result = (result << 8) + this.getByteAt(i);
    128                 i--;
    129             }
    130             return result;
    131         },
    132 
    133         getByteRangeAsString: function (index, steps) {
    134             var result = "";
    135             var max = index + steps;
    136             var i = index;
    137             while (i < max) {
    138                 var charCode = this.getByteAt(i);
    139                 result += String.fromCharCode(charCode);
    140                 // Accounting for multi-byte strings.
    141                 max -= Math.floor(charCode / 0x100);
    142                 i++;
    143             }
    144             return result;
    145         }
    146     }
    147 }(this));