source: frontend/node_modules/loader-utils/lib/hash/wasm-hash.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 2 weeks ago

Fix frontend appearance

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6'use strict';
7
8// 65536 is the size of a wasm memory page
9// 64 is the maximum chunk size for every possible wasm hash implementation
10// 4 is the maximum number of bytes per char for string encoding (max is utf-8)
11// ~3 makes sure that it's always a block of 4 chars, so avoid partially encoded bytes for base64
12const MAX_SHORT_STRING = Math.floor((65536 - 64) / 4) & ~3;
13
14class WasmHash {
15 /**
16 * @param {WebAssembly.Instance} instance wasm instance
17 * @param {WebAssembly.Instance[]} instancesPool pool of instances
18 * @param {number} chunkSize size of data chunks passed to wasm
19 * @param {number} digestSize size of digest returned by wasm
20 */
21 constructor(instance, instancesPool, chunkSize, digestSize) {
22 const exports = /** @type {any} */ (instance.exports);
23
24 exports.init();
25
26 this.exports = exports;
27 this.mem = Buffer.from(exports.memory.buffer, 0, 65536);
28 this.buffered = 0;
29 this.instancesPool = instancesPool;
30 this.chunkSize = chunkSize;
31 this.digestSize = digestSize;
32 }
33
34 reset() {
35 this.buffered = 0;
36 this.exports.init();
37 }
38
39 /**
40 * @param {Buffer | string} data data
41 * @param {BufferEncoding=} encoding encoding
42 * @returns {this} itself
43 */
44 update(data, encoding) {
45 if (typeof data === 'string') {
46 while (data.length > MAX_SHORT_STRING) {
47 this._updateWithShortString(data.slice(0, MAX_SHORT_STRING), encoding);
48 data = data.slice(MAX_SHORT_STRING);
49 }
50
51 this._updateWithShortString(data, encoding);
52
53 return this;
54 }
55
56 this._updateWithBuffer(data);
57
58 return this;
59 }
60
61 /**
62 * @param {string} data data
63 * @param {BufferEncoding=} encoding encoding
64 * @returns {void}
65 */
66 _updateWithShortString(data, encoding) {
67 const { exports, buffered, mem, chunkSize } = this;
68
69 let endPos;
70
71 if (data.length < 70) {
72 if (!encoding || encoding === 'utf-8' || encoding === 'utf8') {
73 endPos = buffered;
74 for (let i = 0; i < data.length; i++) {
75 const cc = data.charCodeAt(i);
76
77 if (cc < 0x80) {
78 mem[endPos++] = cc;
79 } else if (cc < 0x800) {
80 mem[endPos] = (cc >> 6) | 0xc0;
81 mem[endPos + 1] = (cc & 0x3f) | 0x80;
82 endPos += 2;
83 } else {
84 // bail-out for weird chars
85 endPos += mem.write(data.slice(i), endPos, encoding);
86 break;
87 }
88 }
89 } else if (encoding === 'latin1') {
90 endPos = buffered;
91
92 for (let i = 0; i < data.length; i++) {
93 const cc = data.charCodeAt(i);
94
95 mem[endPos++] = cc;
96 }
97 } else {
98 endPos = buffered + mem.write(data, buffered, encoding);
99 }
100 } else {
101 endPos = buffered + mem.write(data, buffered, encoding);
102 }
103
104 if (endPos < chunkSize) {
105 this.buffered = endPos;
106 } else {
107 const l = endPos & ~(this.chunkSize - 1);
108
109 exports.update(l);
110
111 const newBuffered = endPos - l;
112
113 this.buffered = newBuffered;
114
115 if (newBuffered > 0) {
116 mem.copyWithin(0, l, endPos);
117 }
118 }
119 }
120
121 /**
122 * @param {Buffer} data data
123 * @returns {void}
124 */
125 _updateWithBuffer(data) {
126 const { exports, buffered, mem } = this;
127 const length = data.length;
128
129 if (buffered + length < this.chunkSize) {
130 data.copy(mem, buffered, 0, length);
131
132 this.buffered += length;
133 } else {
134 const l = (buffered + length) & ~(this.chunkSize - 1);
135
136 if (l > 65536) {
137 let i = 65536 - buffered;
138
139 data.copy(mem, buffered, 0, i);
140 exports.update(65536);
141
142 const stop = l - buffered - 65536;
143
144 while (i < stop) {
145 data.copy(mem, 0, i, i + 65536);
146 exports.update(65536);
147 i += 65536;
148 }
149
150 data.copy(mem, 0, i, l - buffered);
151
152 exports.update(l - buffered - i);
153 } else {
154 data.copy(mem, buffered, 0, l - buffered);
155
156 exports.update(l);
157 }
158
159 const newBuffered = length + buffered - l;
160
161 this.buffered = newBuffered;
162
163 if (newBuffered > 0) {
164 data.copy(mem, 0, length - newBuffered, length);
165 }
166 }
167 }
168
169 digest(type) {
170 const { exports, buffered, mem, digestSize } = this;
171
172 exports.final(buffered);
173
174 this.instancesPool.push(this);
175
176 const hex = mem.toString('latin1', 0, digestSize);
177
178 if (type === 'hex') {
179 return hex;
180 }
181
182 if (type === 'binary' || !type) {
183 return Buffer.from(hex, 'hex');
184 }
185
186 return Buffer.from(hex, 'hex').toString(type);
187 }
188}
189
190const create = (wasmModule, instancesPool, chunkSize, digestSize) => {
191 if (instancesPool.length > 0) {
192 const old = instancesPool.pop();
193
194 old.reset();
195
196 return old;
197 } else {
198 return new WasmHash(
199 new WebAssembly.Instance(wasmModule),
200 instancesPool,
201 chunkSize,
202 digestSize
203 );
204 }
205};
206
207module.exports = create;
208module.exports.MAX_SHORT_STRING = MAX_SHORT_STRING;
Note: See TracBrowser for help on using the repository browser.