|
|
@ -1,10 +1,29 @@ |
|
|
|
import { Buffer } from "buffer"; |
|
|
|
import type { ImageProcessor } from "./main"; |
|
|
|
import type { EmbeddedFile, ImageProcessor } from "./main"; |
|
|
|
import { BufferWriteStream } from "./png"; |
|
|
|
|
|
|
|
const netscape = Buffer.from("!\xFF\x0BNETSCAPE2.0", 'ascii'); |
|
|
|
const magic = Buffer.from("!\xFF\x0B" + "COOMTECH0.1", 'ascii'); |
|
|
|
|
|
|
|
const read_section = (gif: Buffer, pos: number) => { |
|
|
|
const begin = pos; |
|
|
|
pos += 3 + gif[pos + 2]; |
|
|
|
let buf = Buffer.alloc(0); |
|
|
|
while (pos < gif.byteLength) { |
|
|
|
const v = gif[pos++]; |
|
|
|
buf = Buffer.concat([buf, gif.slice(pos, pos + v)]); |
|
|
|
if (v == 0) |
|
|
|
break; |
|
|
|
pos += v; |
|
|
|
} |
|
|
|
const appname = gif.slice(begin + 3, begin + 11).toString('ascii'); |
|
|
|
return { |
|
|
|
appname, |
|
|
|
data: buf, |
|
|
|
end: pos |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
const extractBuff = (gif: Buffer) => { |
|
|
|
const field = gif.readUInt8(10); |
|
|
|
const gcte = !!(field & (1 << 7)); |
|
|
@ -13,41 +32,28 @@ const extractBuff = (gif: Buffer) => { |
|
|
|
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); |
|
|
|
// eslint-disable-next-line no-constant-condition
|
|
|
|
while (true) { // skip sub blocks
|
|
|
|
const 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; |
|
|
|
} |
|
|
|
const 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 {filename: 'embedded', data: buff}; |
|
|
|
while (gif[end] == '!'.charCodeAt(0)) { |
|
|
|
let sec = read_section(gif, end); // this section contains the size to more easily preallocate a buffer size, but you don't need to care care
|
|
|
|
if (sec.appname == "COOMTECH") { |
|
|
|
const ret = Buffer.alloc(sec.data.readInt32LE(0)); |
|
|
|
let ptr = 0; |
|
|
|
do { |
|
|
|
sec = read_section(gif, sec.end); |
|
|
|
sec.data.copy(ret, ptr); |
|
|
|
ptr += sec.data.byteLength; |
|
|
|
end = sec.end; |
|
|
|
} while (sec.appname == "COOMTECH" && gif[end] == '!'.charCodeAt(0)); |
|
|
|
return { data: ret, filename: 'embedded' } as EmbeddedFile; |
|
|
|
} |
|
|
|
end = sec.end; |
|
|
|
} |
|
|
|
throw "Shouldn't happen"; |
|
|
|
// metadata ended, nothing...
|
|
|
|
}; |
|
|
|
|
|
|
|
const extract = extractBuff; |
|
|
|
|
|
|
|
const write_embedding = async (writer: WritableStreamDefaultWriter<Buffer>, inj: Buffer) => { |
|
|
|
const write_data = async (writer: WritableStreamDefaultWriter<Buffer>, inj: Buffer) => { |
|
|
|
await writer.write(magic); |
|
|
|
const byte = Buffer.from([0]); |
|
|
|
let size = inj.byteLength; |
|
|
@ -65,11 +71,26 @@ const write_embedding = async (writer: WritableStreamDefaultWriter<Buffer>, inj: |
|
|
|
await writer.write(byte); |
|
|
|
}; |
|
|
|
|
|
|
|
const write_embedding = async (writer: WritableStreamDefaultWriter<Buffer>, inj: Buffer) => { |
|
|
|
const b = Buffer.alloc(4); |
|
|
|
b.writeInt32LE(inj.byteLength, 0); |
|
|
|
await write_data(writer, b); |
|
|
|
let size = inj.byteLength; |
|
|
|
let offset = 0; |
|
|
|
while (size != 0) { |
|
|
|
const ws = size >= (3 << 13) ? (3 << 13) : size; |
|
|
|
await write_data(writer, inj.slice(offset, offset + ws)); |
|
|
|
offset += ws; |
|
|
|
size -= ws; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const inject = async (container: File, inj: File) => { |
|
|
|
const [writestream, extract] = BufferWriteStream(); |
|
|
|
const writer = writestream.getWriter(); |
|
|
|
|
|
|
|
const contbuff = Buffer.from(await container.arrayBuffer()); |
|
|
|
debugger; |
|
|
|
|
|
|
|
const field = contbuff.readUInt8(10); |
|
|
|
const gcte = !!(field & (1 << 0x7)); |
|
|
|