-
-
Save ademidoff/660e8ff4928ef17a08fac5cb4a851d09 to your computer and use it in GitHub Desktop.
Solution to inject/fetch a custom data to/from a PNG image
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment