z-worker.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. // posting a message with transferables will fail on IE10
  88. try {
  89. postMessage(rmsg, transferables);
  90. } catch(ex) {
  91. postMessage(rmsg); // retry without transferables
  92. }
  93. }
  94. function onError(type, sn, e) {
  95. var msg = {
  96. type: type,
  97. sn: sn,
  98. error: formatError(e)
  99. };
  100. postMessage(msg);
  101. }
  102. function formatError(e) {
  103. return { message: e.message, stack: e.stack };
  104. }
  105. // Crc32 code copied from file zip.js
  106. function Crc32() {
  107. this.crc = -1;
  108. }
  109. Crc32.prototype.append = function append(data) {
  110. var crc = this.crc | 0, table = this.table;
  111. for (var offset = 0, len = data.length | 0; offset < len; offset++)
  112. crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
  113. this.crc = crc;
  114. };
  115. Crc32.prototype.get = function get() {
  116. return ~this.crc;
  117. };
  118. Crc32.prototype.table = (function() {
  119. var i, j, t, table = []; // Uint32Array is actually slower than []
  120. for (i = 0; i < 256; i++) {
  121. t = i;
  122. for (j = 0; j < 8; j++)
  123. if (t & 1)
  124. t = (t >>> 1) ^ 0xEDB88320;
  125. else
  126. t = t >>> 1;
  127. table[i] = t;
  128. }
  129. return table;
  130. })();
  131. // "no-op" codec
  132. function NOOP() {}
  133. global.NOOP = NOOP;
  134. NOOP.prototype.append = function append(bytes, onprogress) {
  135. return bytes;
  136. };
  137. NOOP.prototype.flush = function flush() {};
  138. })(this);