coomdev
2 years ago
6 changed files with 712 additions and 521 deletions
File diff suppressed because it is too large
@ -0,0 +1,97 @@ |
|||||
|
import { Buffer } from "buffer"; |
||||
|
import { BufferWriteStream, concatAB } from "./png"; |
||||
|
|
||||
|
const netscape = Buffer.from("!\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00"); |
||||
|
const magic = Buffer.from("!\xFF\x0B" + "COOMTECH0.1", 'ascii'); |
||||
|
|
||||
|
const extractBuff = (gif: Buffer) => { |
||||
|
let field = gif.readUInt8(10); |
||||
|
let gcte = !!(field & (1 << 7)); |
||||
|
let end = 13; |
||||
|
if (gcte) { |
||||
|
end += 3 * (1 << ((field & 7) + 1)); |
||||
|
} |
||||
|
// skip beeg blocks
|
||||
|
while (gif.readUInt8(end) == '!'.charCodeAt(0)) { |
||||
|
if (magic.compare(gif, end, end + magic.byteLength) != 0) { |
||||
|
end += 3 + gif.readUInt8(end + 2); |
||||
|
while (1) { // skip sub blocks
|
||||
|
let v = gif.readUInt8(end++); |
||||
|
if (!v) |
||||
|
break; |
||||
|
end += v; |
||||
|
} |
||||
|
} else { |
||||
|
let count = end + magic.byteLength; |
||||
|
let t = 0; |
||||
|
let v = 0; |
||||
|
while ((v = gif.readUInt8(count)) != 0) { |
||||
|
t += v; |
||||
|
count += v + 1; |
||||
|
} |
||||
|
let buff = Buffer.alloc(t); |
||||
|
count = end + magic.byteLength; |
||||
|
t = 0; |
||||
|
while ((v = gif.readUInt8(count)) != 0) { |
||||
|
gif.copy(buff, t, count + 1, count + 1 + v) |
||||
|
t += v; |
||||
|
count += v + 1; |
||||
|
} |
||||
|
return buff; |
||||
|
} |
||||
|
} |
||||
|
// metadata ended, nothing...
|
||||
|
}; |
||||
|
|
||||
|
export const extract = async (reader: ReadableStreamDefaultReader<Uint8Array>): Promise<{ filename: string; data: Buffer } | undefined> => { |
||||
|
let total = Buffer.from(''); |
||||
|
let chunk: ReadableStreamDefaultReadResult<Uint8Array>; |
||||
|
// todo: early reject
|
||||
|
do { |
||||
|
chunk = await reader.read(); |
||||
|
if (chunk.value) |
||||
|
total = concatAB(total, Buffer.from(chunk.value)); |
||||
|
} while (!chunk.done); |
||||
|
const data = extractBuff(total); |
||||
|
if (!data) |
||||
|
return; |
||||
|
return { filename: 'embedded', data }; |
||||
|
}; |
||||
|
|
||||
|
const write_embedding = async (writer: WritableStreamDefaultWriter<Buffer>, inj: Buffer) => { |
||||
|
await writer.write(magic); |
||||
|
const byte = Buffer.from([0]); |
||||
|
let size = inj.byteLength; |
||||
|
let ws; |
||||
|
let offset = 0; |
||||
|
while (size != 0) { |
||||
|
ws = size >= 255 ? 255 : size; |
||||
|
byte.writeUInt8(ws, 0); |
||||
|
await writer.write(byte); |
||||
|
await writer.write(inj.slice(offset, offset + ws)); |
||||
|
size -= ws; |
||||
|
offset += ws; |
||||
|
} |
||||
|
byte.writeUInt8(0, 0); |
||||
|
await writer.write(byte); |
||||
|
}; |
||||
|
|
||||
|
export const inject = async (container: File, inj: File) => { |
||||
|
const [writestream, extract] = BufferWriteStream(); |
||||
|
const writer = writestream.getWriter(); |
||||
|
|
||||
|
let contbuff = Buffer.from(await container.arrayBuffer()); |
||||
|
|
||||
|
let field = contbuff.readUInt8(10); |
||||
|
let gcte = !!(field & (1 << 0x7)) |
||||
|
let endo = 13; |
||||
|
if (gcte) |
||||
|
endo += 3 * (1 << ((field & 7) + 1)); |
||||
|
|
||||
|
if (netscape.compare(contbuff, endo, endo + netscape.byteLength) == 0) |
||||
|
endo += netscape.byteLength; |
||||
|
await writer.write(contbuff.slice(0, endo)); |
||||
|
await write_embedding(writer, Buffer.from(await inj.arrayBuffer())); |
||||
|
await writer.write(contbuff.slice(endo)); |
||||
|
return extract(); |
||||
|
}; |
Loading…
Reference in new issue