Initial commit of zip.js lib
This commit is contained in:
parent
0e213077e7
commit
5a13dbfa4d
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,699 @@
|
||||||
|
/*
|
||||||
|
Based on https://github.com/gildas-lormeau/zip.js/blob/master/WebContent/zip.js
|
||||||
|
|
||||||
|
Copyright (c) 2013 Gildas Lormeau. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. The names of the authors may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||||
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||||
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
define(function(require) {
|
||||||
|
|
||||||
|
var ERR_BAD_FORMAT = "File format is not recognized.";
|
||||||
|
var ERR_ENCRYPTED = "File contains encrypted entry.";
|
||||||
|
var ERR_ZIP64 = "File is using Zip64 (4gb+ file size).";
|
||||||
|
var ERR_READ = "Error while reading zip file.";
|
||||||
|
var ERR_WRITE = "Error while writing zip file.";
|
||||||
|
var ERR_WRITE_DATA = "Error while writing file data.";
|
||||||
|
var ERR_READ_DATA = "Error while reading file data.";
|
||||||
|
var ERR_DUPLICATED_NAME = "File already exists.";
|
||||||
|
var CHUNK_SIZE = 512 * 1024;
|
||||||
|
|
||||||
|
var Inflater = require("zip.js/inflate");
|
||||||
|
var Deflater = require("zip.js/deflate");
|
||||||
|
|
||||||
|
var TEXT_PLAIN = "text/plain";
|
||||||
|
|
||||||
|
var MESSAGE_EVENT = "message";
|
||||||
|
|
||||||
|
var appendABViewSupported;
|
||||||
|
try {
|
||||||
|
appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
function Crc32() {
|
||||||
|
var crc = -1, that = this;
|
||||||
|
that.append = function(data) {
|
||||||
|
var offset, table = that.table;
|
||||||
|
for (offset = 0; offset < data.length; offset++)
|
||||||
|
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
|
||||||
|
};
|
||||||
|
that.get = function() {
|
||||||
|
return ~crc;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Crc32.prototype.table = (function() {
|
||||||
|
var i, j, t, table = [];
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
t = i;
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
if (t & 1)
|
||||||
|
t = (t >>> 1) ^ 0xEDB88320;
|
||||||
|
else
|
||||||
|
t = t >>> 1;
|
||||||
|
table[i] = t;
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
})();
|
||||||
|
|
||||||
|
function blobSlice(blob, index, length) {
|
||||||
|
if (blob.slice)
|
||||||
|
return blob.slice(index, index + length);
|
||||||
|
else if (blob.webkitSlice)
|
||||||
|
return blob.webkitSlice(index, index + length);
|
||||||
|
else if (blob.mozSlice)
|
||||||
|
return blob.mozSlice(index, index + length);
|
||||||
|
else if (blob.msSlice)
|
||||||
|
return blob.msSlice(index, index + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDataHelper(byteLength, bytes) {
|
||||||
|
var dataBuffer, dataArray;
|
||||||
|
dataBuffer = new ArrayBuffer(byteLength);
|
||||||
|
dataArray = new Uint8Array(dataBuffer);
|
||||||
|
if (bytes)
|
||||||
|
dataArray.set(bytes, 0);
|
||||||
|
return {
|
||||||
|
buffer : dataBuffer,
|
||||||
|
array : dataArray,
|
||||||
|
view : new DataView(dataBuffer)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readers
|
||||||
|
function Reader() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function TextReader(text) {
|
||||||
|
var that = this, blobReader;
|
||||||
|
|
||||||
|
function init(callback, onerror) {
|
||||||
|
var blob = new Blob([ text ], {
|
||||||
|
type : TEXT_PLAIN
|
||||||
|
});
|
||||||
|
blobReader = new BlobReader(blob);
|
||||||
|
blobReader.init(function() {
|
||||||
|
that.size = blobReader.size;
|
||||||
|
callback();
|
||||||
|
}, onerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readUint8Array(index, length, callback, onerror) {
|
||||||
|
blobReader.readUint8Array(index, length, callback, onerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
that.size = 0;
|
||||||
|
that.init = init;
|
||||||
|
that.readUint8Array = readUint8Array;
|
||||||
|
}
|
||||||
|
TextReader.prototype = new Reader();
|
||||||
|
TextReader.prototype.constructor = TextReader;
|
||||||
|
|
||||||
|
function Uint8Reader(u8) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function init(callback, onerror) {
|
||||||
|
that.size = u8.length;
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readUint8Array(index, length, callback, onerror) {
|
||||||
|
callback(new Uint8Array(u8.subarray(index, index + length)));
|
||||||
|
}
|
||||||
|
|
||||||
|
that.size = 0;
|
||||||
|
that.init = init;
|
||||||
|
that.readUint8Array = readUint8Array;
|
||||||
|
}
|
||||||
|
Uint8Reader.prototype = new Reader();
|
||||||
|
Uint8Reader.prototype.constructor = Uint8Reader;
|
||||||
|
|
||||||
|
function BlobReader(blob) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function init(callback) {
|
||||||
|
this.size = blob.size;
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readUint8Array(index, length, callback, onerror) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
callback(new Uint8Array(e.target.result));
|
||||||
|
};
|
||||||
|
reader.onerror = onerror;
|
||||||
|
reader.readAsArrayBuffer(blobSlice(blob, index, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
that.size = 0;
|
||||||
|
that.init = init;
|
||||||
|
that.readUint8Array = readUint8Array;
|
||||||
|
}
|
||||||
|
BlobReader.prototype = new Reader();
|
||||||
|
BlobReader.prototype.constructor = BlobReader;
|
||||||
|
|
||||||
|
// Writers
|
||||||
|
|
||||||
|
function Writer() {
|
||||||
|
}
|
||||||
|
Writer.prototype.getData = function(callback) {
|
||||||
|
callback(this.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
function TextWriter(encoding) {
|
||||||
|
var that = this, blob;
|
||||||
|
|
||||||
|
function init(callback) {
|
||||||
|
blob = new Blob([], {
|
||||||
|
type : TEXT_PLAIN
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeUint8Array(array, callback) {
|
||||||
|
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
|
||||||
|
type : TEXT_PLAIN
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getData(callback, onerror) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
callback(e.target.result);
|
||||||
|
};
|
||||||
|
reader.onerror = onerror;
|
||||||
|
reader.readAsText(blob, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
that.init = init;
|
||||||
|
that.writeUint8Array = writeUint8Array;
|
||||||
|
that.getData = getData;
|
||||||
|
}
|
||||||
|
TextWriter.prototype = new Writer();
|
||||||
|
TextWriter.prototype.constructor = TextWriter;
|
||||||
|
|
||||||
|
function Uint8Writer() {
|
||||||
|
var that = this, u8;
|
||||||
|
|
||||||
|
function init(callback) {
|
||||||
|
u8 = new Uint8Array();
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeUint8Array(array, callback) {
|
||||||
|
var both = new Uint8Array(u8.length + array.length);
|
||||||
|
both.set(u8);
|
||||||
|
both.set(array, u8.length);
|
||||||
|
u8 = both;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getData(callback) {
|
||||||
|
callback(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
that.init = init;
|
||||||
|
that.writeUint8Array = writeUint8Array;
|
||||||
|
that.getData = getData;
|
||||||
|
}
|
||||||
|
Uint8Writer.prototype = new Writer();
|
||||||
|
Uint8Writer.prototype.constructor = Uint8Writer;
|
||||||
|
|
||||||
|
function BlobWriter(contentType) {
|
||||||
|
var blob, that = this;
|
||||||
|
|
||||||
|
function init(callback) {
|
||||||
|
blob = new Blob([], {
|
||||||
|
type : contentType
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeUint8Array(array, callback) {
|
||||||
|
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
|
||||||
|
type : contentType
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getData(callback) {
|
||||||
|
callback(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
that.init = init;
|
||||||
|
that.writeUint8Array = writeUint8Array;
|
||||||
|
that.getData = getData;
|
||||||
|
}
|
||||||
|
BlobWriter.prototype = new Writer();
|
||||||
|
BlobWriter.prototype.constructor = BlobWriter;
|
||||||
|
|
||||||
|
// inflate/deflate core functions
|
||||||
|
function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
|
||||||
|
var chunkIndex = 0, index, outputSize = 0;
|
||||||
|
|
||||||
|
function step() {
|
||||||
|
var outputData;
|
||||||
|
index = chunkIndex * CHUNK_SIZE;
|
||||||
|
if (index < size)
|
||||||
|
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) {
|
||||||
|
var outputData = process.append(inputData, function() {
|
||||||
|
if (onprogress)
|
||||||
|
onprogress(offset + index, size);
|
||||||
|
});
|
||||||
|
outputSize += outputData.length;
|
||||||
|
onappend(true, inputData);
|
||||||
|
writer.writeUint8Array(outputData, function() {
|
||||||
|
onappend(false, outputData);
|
||||||
|
chunkIndex++;
|
||||||
|
setTimeout(step, 1);
|
||||||
|
}, onwriteerror);
|
||||||
|
if (onprogress)
|
||||||
|
onprogress(index, size);
|
||||||
|
}, onreaderror);
|
||||||
|
else {
|
||||||
|
outputData = process.flush();
|
||||||
|
if (outputData) {
|
||||||
|
outputSize += outputData.length;
|
||||||
|
writer.writeUint8Array(outputData, function() {
|
||||||
|
onappend(false, outputData);
|
||||||
|
onend(outputSize);
|
||||||
|
}, onwriteerror);
|
||||||
|
} else
|
||||||
|
onend(outputSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
||||||
|
var worker, crc32 = new Crc32();
|
||||||
|
|
||||||
|
function oninflateappend(sending, array) {
|
||||||
|
if (computeCrc32 && !sending)
|
||||||
|
crc32.append(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
function oninflateend(outputSize) {
|
||||||
|
onend(outputSize, crc32.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
launchProcess(new Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
|
||||||
|
return worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
|
||||||
|
var worker, crc32 = new Crc32();
|
||||||
|
|
||||||
|
function ondeflateappend(sending, array) {
|
||||||
|
if (sending)
|
||||||
|
crc32.append(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ondeflateend(outputSize) {
|
||||||
|
onend(outputSize, crc32.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
launchProcess(new Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
|
||||||
|
return worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
||||||
|
var chunkIndex = 0, crc32 = new Crc32();
|
||||||
|
|
||||||
|
function step() {
|
||||||
|
var index = chunkIndex * CHUNK_SIZE;
|
||||||
|
if (index < size)
|
||||||
|
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
|
||||||
|
if (computeCrc32)
|
||||||
|
crc32.append(array);
|
||||||
|
if (onprogress)
|
||||||
|
onprogress(index, size, array);
|
||||||
|
writer.writeUint8Array(array, function() {
|
||||||
|
chunkIndex++;
|
||||||
|
step();
|
||||||
|
}, onwriteerror);
|
||||||
|
}, onreaderror);
|
||||||
|
else
|
||||||
|
onend(size, crc32.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZipReader
|
||||||
|
|
||||||
|
function decodeASCII(str) {
|
||||||
|
var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB',
|
||||||
|
'\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9',
|
||||||
|
'\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1',
|
||||||
|
'\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6',
|
||||||
|
'\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3',
|
||||||
|
'\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE',
|
||||||
|
'\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE',
|
||||||
|
'\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
|
||||||
|
'\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ];
|
||||||
|
for (i = 0; i < str.length; i++) {
|
||||||
|
charCode = str.charCodeAt(i) & 0xFF;
|
||||||
|
if (charCode > 127)
|
||||||
|
out += extendedASCII[charCode - 128];
|
||||||
|
else
|
||||||
|
out += String.fromCharCode(charCode);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeUTF8(string) {
|
||||||
|
return decodeURIComponent(escape(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getString(bytes) {
|
||||||
|
var i, str = "";
|
||||||
|
for (i = 0; i < bytes.length; i++)
|
||||||
|
str += String.fromCharCode(bytes[i]);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDate(timeRaw) {
|
||||||
|
var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
|
||||||
|
try {
|
||||||
|
return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5,
|
||||||
|
(time & 0x001F) * 2, 0);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCommonHeader(entry, data, index, centralDirectory, onerror) {
|
||||||
|
entry.version = data.view.getUint16(index, true);
|
||||||
|
entry.bitFlag = data.view.getUint16(index + 2, true);
|
||||||
|
entry.compressionMethod = data.view.getUint16(index + 4, true);
|
||||||
|
entry.lastModDateRaw = data.view.getUint32(index + 6, true);
|
||||||
|
entry.lastModDate = getDate(entry.lastModDateRaw);
|
||||||
|
if ((entry.bitFlag & 0x01) === 0x01) {
|
||||||
|
onerror(ERR_ENCRYPTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) {
|
||||||
|
entry.crc32 = data.view.getUint32(index + 10, true);
|
||||||
|
entry.compressedSize = data.view.getUint32(index + 14, true);
|
||||||
|
entry.uncompressedSize = data.view.getUint32(index + 18, true);
|
||||||
|
}
|
||||||
|
if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) {
|
||||||
|
onerror(ERR_ZIP64);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entry.filenameLength = data.view.getUint16(index + 22, true);
|
||||||
|
entry.extraFieldLength = data.view.getUint16(index + 24, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createZipReader(reader, onerror) {
|
||||||
|
function Entry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function terminate(callback, param) {
|
||||||
|
if (callback)
|
||||||
|
callback(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testCrc32(crc32) {
|
||||||
|
var dataCrc32 = getDataHelper(4);
|
||||||
|
dataCrc32.view.setUint32(0, crc32);
|
||||||
|
return that.crc32 == dataCrc32.view.getUint32(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWriterData(uncompressedSize, crc32) {
|
||||||
|
if (checkCrc32 && !testCrc32(crc32))
|
||||||
|
onreaderror();
|
||||||
|
else
|
||||||
|
writer.getData(function(data) {
|
||||||
|
terminate(onend, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onreaderror() {
|
||||||
|
terminate(onerror, ERR_READ_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onwriteerror() {
|
||||||
|
terminate(onerror, ERR_WRITE_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.readUint8Array(that.offset, 30, function(bytes) {
|
||||||
|
var data = getDataHelper(bytes.length, bytes), dataOffset;
|
||||||
|
if (data.view.getUint32(0) != 0x504b0304) {
|
||||||
|
onerror(ERR_BAD_FORMAT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
readCommonHeader(that, data, 4, false, onerror);
|
||||||
|
dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
|
||||||
|
writer.init(function() {
|
||||||
|
copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
|
||||||
|
}, onwriteerror);
|
||||||
|
}, onreaderror);
|
||||||
|
};
|
||||||
|
|
||||||
|
function seekEOCDR(offset, entriesCallback) {
|
||||||
|
reader.readUint8Array(reader.size - offset, offset, function(bytes) {
|
||||||
|
var dataView = getDataHelper(bytes.length, bytes).view;
|
||||||
|
if (dataView.getUint32(0) != 0x504b0506) {
|
||||||
|
seekEOCDR(offset + 1, entriesCallback);
|
||||||
|
} else {
|
||||||
|
entriesCallback(dataView);
|
||||||
|
}
|
||||||
|
}, function() {
|
||||||
|
onerror(ERR_READ);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getEntries : function(callback) {
|
||||||
|
if (reader.size < 22) {
|
||||||
|
onerror(ERR_BAD_FORMAT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// look for End of central directory record
|
||||||
|
seekEOCDR(22, function(dataView) {
|
||||||
|
var datalength, fileslength;
|
||||||
|
datalength = dataView.getUint32(16, true);
|
||||||
|
fileslength = dataView.getUint16(8, true);
|
||||||
|
reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
|
||||||
|
var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes);
|
||||||
|
for (i = 0; i < fileslength; i++) {
|
||||||
|
entry = new Entry();
|
||||||
|
if (data.view.getUint32(index) != 0x504b0102) {
|
||||||
|
onerror(ERR_BAD_FORMAT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
readCommonHeader(entry, data, index + 6, true, onerror);
|
||||||
|
entry.commentLength = data.view.getUint16(index + 32, true);
|
||||||
|
entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10);
|
||||||
|
entry.offset = data.view.getUint32(index + 42, true);
|
||||||
|
filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
|
||||||
|
entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
|
||||||
|
if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
|
||||||
|
entry.directory = true;
|
||||||
|
comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46
|
||||||
|
+ entry.filenameLength + entry.extraFieldLength + entry.commentLength));
|
||||||
|
entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
|
||||||
|
entries.push(entry);
|
||||||
|
index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength;
|
||||||
|
}
|
||||||
|
callback(entries);
|
||||||
|
}, function() {
|
||||||
|
onerror(ERR_READ);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close : function(callback) {
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZipWriter
|
||||||
|
|
||||||
|
function encodeUTF8(string) {
|
||||||
|
return unescape(encodeURIComponent(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBytes(str) {
|
||||||
|
var i, array = [];
|
||||||
|
for (i = 0; i < str.length; i++)
|
||||||
|
array.push(str.charCodeAt(i));
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createZipWriter(writer, onerror, dontDeflate) {
|
||||||
|
var files = {}, filenames = [], datalength = 0;
|
||||||
|
|
||||||
|
function terminate(callback, message) {
|
||||||
|
if (callback)
|
||||||
|
callback(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onwriteerror() {
|
||||||
|
terminate(onerror, ERR_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onreaderror() {
|
||||||
|
terminate(onerror, ERR_READ_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
add : function(name, reader, onend, onprogress, options) {
|
||||||
|
var header, filename, date;
|
||||||
|
|
||||||
|
function writeHeader(callback) {
|
||||||
|
var data;
|
||||||
|
date = options.lastModDate || new Date();
|
||||||
|
header = getDataHelper(26);
|
||||||
|
files[name] = {
|
||||||
|
headerArray : header.array,
|
||||||
|
directory : options.directory,
|
||||||
|
filename : filename,
|
||||||
|
offset : datalength,
|
||||||
|
comment : getBytes(encodeUTF8(options.comment || ""))
|
||||||
|
};
|
||||||
|
header.view.setUint32(0, 0x14000808);
|
||||||
|
if (options.version)
|
||||||
|
header.view.setUint8(0, options.version);
|
||||||
|
if (!dontDeflate && options.level !== 0 && !options.directory)
|
||||||
|
header.view.setUint16(4, 0x0800);
|
||||||
|
header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true);
|
||||||
|
header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true);
|
||||||
|
header.view.setUint16(22, filename.length, true);
|
||||||
|
data = getDataHelper(30 + filename.length);
|
||||||
|
data.view.setUint32(0, 0x504b0304);
|
||||||
|
data.array.set(header.array, 4);
|
||||||
|
data.array.set(filename, 30);
|
||||||
|
datalength += data.array.length;
|
||||||
|
writer.writeUint8Array(data.array, callback, onwriteerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeFooter(compressedLength, crc32) {
|
||||||
|
var footer = getDataHelper(16);
|
||||||
|
datalength += compressedLength || 0;
|
||||||
|
footer.view.setUint32(0, 0x504b0708);
|
||||||
|
if (typeof crc32 != "undefined") {
|
||||||
|
header.view.setUint32(10, crc32, true);
|
||||||
|
footer.view.setUint32(4, crc32, true);
|
||||||
|
}
|
||||||
|
if (reader) {
|
||||||
|
footer.view.setUint32(8, compressedLength, true);
|
||||||
|
header.view.setUint32(14, compressedLength, true);
|
||||||
|
footer.view.setUint32(12, reader.size, true);
|
||||||
|
header.view.setUint32(18, reader.size, true);
|
||||||
|
}
|
||||||
|
writer.writeUint8Array(footer.array, function() {
|
||||||
|
datalength += 16;
|
||||||
|
terminate(onend);
|
||||||
|
}, onwriteerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeFile() {
|
||||||
|
options = options || {};
|
||||||
|
name = name.trim();
|
||||||
|
if (options.directory && name.charAt(name.length - 1) != "/")
|
||||||
|
name += "/";
|
||||||
|
if (files.hasOwnProperty(name)) {
|
||||||
|
onerror(ERR_DUPLICATED_NAME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
filename = getBytes(encodeUTF8(name));
|
||||||
|
filenames.push(name);
|
||||||
|
writeHeader(function() {
|
||||||
|
if (reader)
|
||||||
|
if (dontDeflate || options.level === 0)
|
||||||
|
copy(reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror);
|
||||||
|
else
|
||||||
|
writeFooter();
|
||||||
|
}, onwriteerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader)
|
||||||
|
reader.init(writeFile, onreaderror);
|
||||||
|
else
|
||||||
|
writeFile();
|
||||||
|
},
|
||||||
|
close : function(callback) {
|
||||||
|
var data, length = 0, index = 0, indexFilename, file;
|
||||||
|
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
|
||||||
|
file = files[filenames[indexFilename]];
|
||||||
|
length += 46 + file.filename.length + file.comment.length;
|
||||||
|
}
|
||||||
|
data = getDataHelper(length + 22);
|
||||||
|
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
|
||||||
|
file = files[filenames[indexFilename]];
|
||||||
|
data.view.setUint32(index, 0x504b0102);
|
||||||
|
data.view.setUint16(index + 4, 0x1400);
|
||||||
|
data.array.set(file.headerArray, index + 6);
|
||||||
|
data.view.setUint16(index + 32, file.comment.length, true);
|
||||||
|
if (file.directory)
|
||||||
|
data.view.setUint8(index + 38, 0x10);
|
||||||
|
data.view.setUint32(index + 42, file.offset, true);
|
||||||
|
data.array.set(file.filename, index + 46);
|
||||||
|
data.array.set(file.comment, index + 46 + file.filename.length);
|
||||||
|
index += 46 + file.filename.length + file.comment.length;
|
||||||
|
}
|
||||||
|
data.view.setUint32(index, 0x504b0506);
|
||||||
|
data.view.setUint16(index + 8, filenames.length, true);
|
||||||
|
data.view.setUint16(index + 10, filenames.length, true);
|
||||||
|
data.view.setUint32(index + 12, length, true);
|
||||||
|
data.view.setUint32(index + 16, datalength, true);
|
||||||
|
writer.writeUint8Array(data.array, function() {
|
||||||
|
terminate(function() {
|
||||||
|
writer.getData(callback);
|
||||||
|
});
|
||||||
|
}, onwriteerror);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
Reader : Reader,
|
||||||
|
Writer : Writer,
|
||||||
|
BlobReader : BlobReader,
|
||||||
|
Uint8Reader : Uint8Reader,
|
||||||
|
TextReader : TextReader,
|
||||||
|
BlobWriter : BlobWriter,
|
||||||
|
Uint8Writer : Uint8Writer,
|
||||||
|
TextWriter : TextWriter,
|
||||||
|
createReader : function(reader, callback, onerror) {
|
||||||
|
reader.init(function() {
|
||||||
|
callback(createZipReader(reader, onerror));
|
||||||
|
}, onerror);
|
||||||
|
},
|
||||||
|
createWriter : function(writer, callback, onerror, dontDeflate) {
|
||||||
|
writer.init(function() {
|
||||||
|
callback(createZipWriter(writer, onerror, dontDeflate));
|
||||||
|
}, onerror);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue