z-worker.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /* jshint worker:true */
  2. (function main(global) {
  3. "use strict";
  4. if (global.zWorkerInitialized)
  5. throw new Error('z-worker.js should be run only once');
  6. global.zWorkerInitialized = true;
  7. addEventListener("message", function(event) {
  8. var message = event.data, type = message.type, sn = message.sn;
  9. var handler = handlers[type];
  10. if (handler) {
  11. try {
  12. handler(message);
  13. } catch (e) {
  14. onError(type, sn, e);
  15. }
  16. }
  17. //for debug
  18. //postMessage({type: 'echo', originalType: type, sn: sn});
  19. });
  20. var handlers = {
  21. importScripts: doImportScripts,
  22. newTask: newTask,
  23. append: processData,
  24. flush: processData,
  25. };
  26. // deflater/inflater tasks indexed by serial numbers
  27. var tasks = {};
  28. function doImportScripts(msg) {
  29. if (msg.scripts && msg.scripts.length > 0)
  30. importScripts.apply(undefined, msg.scripts);
  31. postMessage({type: 'importScripts'});
  32. }
  33. function newTask(msg) {
  34. var CodecClass = global[msg.codecClass];
  35. var sn = msg.sn;
  36. if (tasks[sn])
  37. throw Error('duplicated sn');
  38. tasks[sn] = {
  39. codec: new CodecClass(msg.options),
  40. crcInput: msg.crcType === 'input',
  41. crcOutput: msg.crcType === 'output',
  42. crc: new Crc32(),
  43. };
  44. postMessage({type: 'newTask', sn: sn});
  45. }
  46. // performance may not be supported
  47. var now = global.performance ? global.performance.now.bind(global.performance) : Date.now;
  48. function processData(msg) {
  49. var sn = msg.sn, type = msg.type, input = msg.data;
  50. var task = tasks[sn];
  51. // allow creating codec on first append
  52. if (!task && msg.codecClass) {
  53. newTask(msg);
  54. task = tasks[sn];
  55. }
  56. var isAppend = type === 'append';
  57. var start = now();
  58. var output;
  59. if (isAppend) {
  60. try {
  61. output = task.codec.append(input, function onprogress(loaded) {
  62. postMessage({type: 'progress', sn: sn, loaded: loaded});
  63. });
  64. } catch (e) {
  65. delete tasks[sn];
  66. throw e;
  67. }
  68. } else {
  69. delete tasks[sn];
  70. output = task.codec.flush();
  71. }
  72. var codecTime = now() - start;
  73. start = now();
  74. if (input && task.crcInput)
  75. task.crc.append(input);
  76. if (output && task.crcOutput)
  77. task.crc.append(output);
  78. var crcTime = now() - start;
  79. var rmsg = {type: type, sn: sn, codecTime: codecTime, crcTime: crcTime};
  80. var transferables = [];
  81. if (output) {
  82. rmsg.data = output;
  83. transferables.push(output.buffer);
  84. }
  85. if (!isAppend && (task.crcInput || task.crcOutput))
  86. rmsg.crc = task.crc.get();
  87. postMessage(rmsg, transferables);
  88. }
  89. function onError(type, sn, e) {
  90. var msg = {
  91. type: type,
  92. sn: sn,
  93. error: formatError(e)
  94. };
  95. postMessage(msg);
  96. }
  97. function formatError(e) {
  98. return { message: e.message, stack: e.stack };
  99. }
  100. // Crc32 code copied from file zip.js
  101. function Crc32() {
  102. this.crc = -1;
  103. }
  104. Crc32.prototype.append = function append(data) {
  105. var crc = this.crc | 0, table = this.table;
  106. for (var offset = 0, len = data.length | 0; offset < len; offset++)
  107. crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
  108. this.crc = crc;
  109. };
  110. Crc32.prototype.get = function get() {
  111. return ~this.crc;
  112. };
  113. Crc32.prototype.table = (function() {
  114. var i, j, t, table = []; // Uint32Array is actually slower than []
  115. for (i = 0; i < 256; i++) {
  116. t = i;
  117. for (j = 0; j < 8; j++)
  118. if (t & 1)
  119. t = (t >>> 1) ^ 0xEDB88320;
  120. else
  121. t = t >>> 1;
  122. table[i] = t;
  123. }
  124. return table;
  125. })();
  126. // "no-op" codec
  127. function NOOP() {}
  128. global.NOOP = NOOP;
  129. NOOP.prototype.append = function append(bytes, onprogress) {
  130. return bytes;
  131. };
  132. NOOP.prototype.flush = function flush() {};
  133. })(this);