Skip to content

Instantly share code, notes, and snippets.

@lahmatiy
Last active April 16, 2018 13:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lahmatiy/0332b6dc3319190f9493831492dbf036 to your computer and use it in GitHub Desktop.
Save lahmatiy/0332b6dc3319190f9493831492dbf036 to your computer and use it in GitHub Desktop.
Solution to inject/fetch a custom data to/from a PNG image
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