|
|
@@ -0,0 +1,94 @@ |
|
|
const pngSignature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]); |
|
|
const hashKey = 'react-snapshot-hash'; |
|
|
const crcTable = []; |
|
|
const initialCrc = 0xffffffff; |
|
|
|
|
|
for (let n = 0; n < 256; n++) { |
|
|
let c = n; |
|
|
|
|
|
for (let k = 0; k < 8; k++) { |
|
|
if (c & 1) { |
|
|
c = 0xedb88320 ^ (c >>> 1); |
|
|
} else { |
|
|
c = c >>> 1; |
|
|
} |
|
|
} |
|
|
|
|
|
crcTable[n] = c; |
|
|
} |
|
|
|
|
|
function updateCrc(crc, data, length) { |
|
|
let c = crc; |
|
|
|
|
|
for (let n = 0; n < length; n++) { |
|
|
c = crcTable[(c ^ data[n]) & 0xff] ^ (c >>> 8); |
|
|
} |
|
|
|
|
|
return c; |
|
|
} |
|
|
|
|
|
function crc(data, length) { |
|
|
return (updateCrc(initialCrc, data, length) ^ initialCrc) >>> 0; |
|
|
} |
|
|
|
|
|
function fetchRequestHash(data) { |
|
|
const view = new DataView(data.buffer); |
|
|
|
|
|
if (pngSignature.compare(data, 0, pngSignature.length) !== 0) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
// fast png scan |
|
|
for (let offset = pngSignature.length; offset < data.length;) { |
|
|
const len = view.getUint32(offset); |
|
|
const type = data.toString('ascii', offset + 4, offset + 8); |
|
|
|
|
|
// search for text chunk with `hashKey` as a key |
|
|
if (type === 'tEXt') { |
|
|
const keyEnd = data.indexOf(0, offset + 8); |
|
|
|
|
|
if (keyEnd !== -1) { |
|
|
const key = data.toString('ascii', offset + 8, keyEnd); |
|
|
|
|
|
if (key === hashKey) { |
|
|
return data.toString('utf8', keyEnd + 1, offset + 8 + len); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
offset += len + 12; // len + type + crc |
|
|
} |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
function buildRequestHashChunk(hash) { |
|
|
const data = Buffer.from([ |
|
|
'tEXt', // type |
|
|
hashKey, // key |
|
|
'\0', // key terminator |
|
|
hash // data |
|
|
].join('')); |
|
|
const res = Buffer.alloc(4 + data.length + 4); |
|
|
const view = new DataView(res.buffer); |
|
|
|
|
|
view.setUint32(0, data.length - 4); |
|
|
view.setUint32(4 + data.length, crc(data, data.length)); |
|
|
data.copy(res, 4); |
|
|
|
|
|
return res; |
|
|
} |
|
|
|
|
|
function injectRequestHash(buffer, hash) { |
|
|
return Buffer.concat([ |
|
|
buffer.slice(0, buffer.length - 12), |
|
|
buildRequestHashChunk(hash), |
|
|
buffer.slice(buffer.length - 12) |
|
|
]); |
|
|
} |
|
|
|
|
|
module.exports = { |
|
|
crc, |
|
|
fetchRequestHash, |
|
|
injectRequestHash |
|
|
}; |