/* 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);