154 lines
3.6 KiB
JavaScript
154 lines
3.6 KiB
JavaScript
|
/* jshint worker:true */
|
||
|
(function main(global) {
|
||
|
"use strict";
|
||
|
|
||
|
if (global.zWorkerInitialized)
|
||
|
throw new Error('z-worker.js should be run only once');
|
||
|
global.zWorkerInitialized = true;
|
||
|
|
||
|
addEventListener("message", function(event) {
|
||
|
var message = event.data, type = message.type, sn = message.sn;
|
||
|
var handler = handlers[type];
|
||
|
if (handler) {
|
||
|
try {
|
||
|
handler(message);
|
||
|
} catch (e) {
|
||
|
onError(type, sn, e);
|
||
|
}
|
||
|
}
|
||
|
//for debug
|
||
|
//postMessage({type: 'echo', originalType: type, sn: sn});
|
||
|
});
|
||
|
|
||
|
var handlers = {
|
||
|
importScripts: doImportScripts,
|
||
|
newTask: newTask,
|
||
|
append: processData,
|
||
|
flush: processData,
|
||
|
};
|
||
|
|
||
|
// deflater/inflater tasks indexed by serial numbers
|
||
|
var tasks = {};
|
||
|
|
||
|
function doImportScripts(msg) {
|
||
|
if (msg.scripts && msg.scripts.length > 0)
|
||
|
importScripts.apply(undefined, msg.scripts);
|
||
|
postMessage({type: 'importScripts'});
|
||
|
}
|
||
|
|
||
|
function newTask(msg) {
|
||
|
var CodecClass = global[msg.codecClass];
|
||
|
var sn = msg.sn;
|
||
|
if (tasks[sn])
|
||
|
throw Error('duplicated sn');
|
||
|
tasks[sn] = {
|
||
|
codec: new CodecClass(msg.options),
|
||
|
crcInput: msg.crcType === 'input',
|
||
|
crcOutput: msg.crcType === 'output',
|
||
|
crc: new Crc32(),
|
||
|
};
|
||
|
postMessage({type: 'newTask', sn: sn});
|
||
|
}
|
||
|
|
||
|
// performance may not be supported
|
||
|
var now = global.performance ? global.performance.now.bind(global.performance) : Date.now;
|
||
|
|
||
|
function processData(msg) {
|
||
|
var sn = msg.sn, type = msg.type, input = msg.data;
|
||
|
var task = tasks[sn];
|
||
|
// allow creating codec on first append
|
||
|
if (!task && msg.codecClass) {
|
||
|
newTask(msg);
|
||
|
task = tasks[sn];
|
||
|
}
|
||
|
var isAppend = type === 'append';
|
||
|
var start = now();
|
||
|
var output;
|
||
|
if (isAppend) {
|
||
|
try {
|
||
|
output = task.codec.append(input, function onprogress(loaded) {
|
||
|
postMessage({type: 'progress', sn: sn, loaded: loaded});
|
||
|
});
|
||
|
} catch (e) {
|
||
|
delete tasks[sn];
|
||
|
throw e;
|
||
|
}
|
||
|
} else {
|
||
|
delete tasks[sn];
|
||
|
output = task.codec.flush();
|
||
|
}
|
||
|
var codecTime = now() - start;
|
||
|
|
||
|
start = now();
|
||
|
if (input && task.crcInput)
|
||
|
task.crc.append(input);
|
||
|
if (output && task.crcOutput)
|
||
|
task.crc.append(output);
|
||
|
var crcTime = now() - start;
|
||
|
|
||
|
var rmsg = {type: type, sn: sn, codecTime: codecTime, crcTime: crcTime};
|
||
|
var transferables = [];
|
||
|
if (output) {
|
||
|
rmsg.data = output;
|
||
|
transferables.push(output.buffer);
|
||
|
}
|
||
|
if (!isAppend && (task.crcInput || task.crcOutput))
|
||
|
rmsg.crc = task.crc.get();
|
||
|
|
||
|
// posting a message with transferables will fail on IE10
|
||
|
try {
|
||
|
postMessage(rmsg, transferables);
|
||
|
} catch(ex) {
|
||
|
postMessage(rmsg); // retry without transferables
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function onError(type, sn, e) {
|
||
|
var msg = {
|
||
|
type: type,
|
||
|
sn: sn,
|
||
|
error: formatError(e)
|
||
|
};
|
||
|
postMessage(msg);
|
||
|
}
|
||
|
|
||
|
function formatError(e) {
|
||
|
return { message: e.message, stack: e.stack };
|
||
|
}
|
||
|
|
||
|
// Crc32 code copied from file zip.js
|
||
|
function Crc32() {
|
||
|
this.crc = -1;
|
||
|
}
|
||
|
Crc32.prototype.append = function append(data) {
|
||
|
var crc = this.crc | 0, table = this.table;
|
||
|
for (var offset = 0, len = data.length | 0; offset < len; offset++)
|
||
|
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
|
||
|
this.crc = crc;
|
||
|
};
|
||
|
Crc32.prototype.get = function get() {
|
||
|
return ~this.crc;
|
||
|
};
|
||
|
Crc32.prototype.table = (function() {
|
||
|
var i, j, t, table = []; // Uint32Array is actually slower than []
|
||
|
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;
|
||
|
})();
|
||
|
|
||
|
// "no-op" codec
|
||
|
function NOOP() {}
|
||
|
global.NOOP = NOOP;
|
||
|
NOOP.prototype.append = function append(bytes, onprogress) {
|
||
|
return bytes;
|
||
|
};
|
||
|
NOOP.prototype.flush = function flush() {};
|
||
|
})(this);
|