mirror of
https://git.coom.tech/fuckjannies/lolipiss.git
synced 2024-06-27 13:12:34 +00:00
199 lines
4.6 KiB
Plaintext
199 lines
4.6 KiB
Plaintext
|
|
||
|
function readVint(buff: ArrayBuffer, start = 0) {
|
||
|
const buffer = new Uint8Array(buff);
|
||
|
const length = 8 - Math.floor(Math.log2(buffer[start]));
|
||
|
if (length > 8) {
|
||
|
throw new Error(`Unrepresentable length`);
|
||
|
}
|
||
|
|
||
|
if (start + length > buffer.length) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let value = buffer[start] & ((1 << (8 - length)) - 1);
|
||
|
for (let i = 1; i < length; i += 1) {
|
||
|
if (i === 7) {
|
||
|
if (value >= 2 ** 8 && buffer[start + 7] > 0) {
|
||
|
return { length, value: -1 };
|
||
|
}
|
||
|
}
|
||
|
value *= 2 ** 8;
|
||
|
value += buffer[start + i];
|
||
|
}
|
||
|
|
||
|
return { length, value };
|
||
|
}
|
||
|
|
||
|
enum DecoderState {
|
||
|
Tag, Size, Content
|
||
|
}
|
||
|
|
||
|
const schema = new Map([
|
||
|
[
|
||
|
0x1a45dfa3,
|
||
|
{
|
||
|
name: 'EBML',
|
||
|
type: 'm',
|
||
|
},
|
||
|
], [
|
||
|
0x1654ae6b,
|
||
|
{
|
||
|
name: 'Tracks',
|
||
|
type: 'm',
|
||
|
},
|
||
|
], [
|
||
|
0x4485,
|
||
|
{
|
||
|
name: 'TagBinary',
|
||
|
type: 'b',
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
0x4487,
|
||
|
{
|
||
|
name: 'TagString',
|
||
|
type: '8',
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
0x63c0,
|
||
|
{
|
||
|
name: 'Targets',
|
||
|
type: 'm',
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
0x7373,
|
||
|
{
|
||
|
name: 'Tag',
|
||
|
type: 'm',
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
0x1254c367,
|
||
|
{
|
||
|
name: 'Tags',
|
||
|
type: 'm',
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
0x45a3,
|
||
|
{
|
||
|
name: 'TagName',
|
||
|
type: '8',
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
0x67c8,
|
||
|
{
|
||
|
name: 'SimpleTag',
|
||
|
type: 'm',
|
||
|
},
|
||
|
]]);
|
||
|
|
||
|
type Tag = [id: number, type: string, name: string, ln: number, pos: number, size?: number]
|
||
|
|
||
|
export const decodeEBML = (arr: ArrayBuffer): {
|
||
|
tag: Tag;
|
||
|
isEnd?: true | undefined;
|
||
|
data?: ArrayBuffer | undefined;
|
||
|
}[] => {
|
||
|
let ptr = 0;
|
||
|
const buffer = new Uint8Array(arr);
|
||
|
const dw = new DataView(arr);
|
||
|
let total = 0;
|
||
|
let stack: Tag[] = [];
|
||
|
let ret: { tag: Tag, isEnd?: true, data?: ArrayBuffer }[] = [];
|
||
|
let state: number = DecoderState.Tag;
|
||
|
|
||
|
const readTag = () => {
|
||
|
if (ptr >= arr.byteLength)
|
||
|
return;
|
||
|
const vint = readVint(arr, ptr);
|
||
|
if (!vint)
|
||
|
return;
|
||
|
let v = 0;
|
||
|
switch (vint.length) {
|
||
|
case 1:
|
||
|
v = dw.getInt8(ptr);
|
||
|
break;
|
||
|
case 2:
|
||
|
v = dw.getInt16(ptr);
|
||
|
break;
|
||
|
case 3:
|
||
|
v = dw.getInt32(ptr) & 0xFFFFFF;
|
||
|
break;
|
||
|
case 4:
|
||
|
v = dw.getInt32(ptr);
|
||
|
break;
|
||
|
default:
|
||
|
throw "Unexpected v size";
|
||
|
}
|
||
|
const elem = schema.get(v);
|
||
|
const start = total;
|
||
|
total += vint.length;
|
||
|
const tag = [v, elem?.type, elem?.name, vint.length, start] as Tag;
|
||
|
stack.push(tag);
|
||
|
state = DecoderState.Size;
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
const readSize = () => {
|
||
|
const lasttag = stack.slice(-1)[0];
|
||
|
if (ptr >= arr.byteLength)
|
||
|
return;
|
||
|
const size = readVint(arr, ptr);
|
||
|
if (!size)
|
||
|
return;
|
||
|
ptr += size.length;
|
||
|
total += size.length;
|
||
|
lasttag[5] = size?.value;
|
||
|
if (lasttag[5] == -1)
|
||
|
lasttag[3] = -1;
|
||
|
else
|
||
|
lasttag[3] += size.length + size.value;
|
||
|
state = DecoderState.Content;
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
const readContent = () => {
|
||
|
const lasttag = stack.slice(-1)[0];
|
||
|
if (lasttag[1] == "m") {
|
||
|
state = DecoderState.Tag;
|
||
|
return true;
|
||
|
}
|
||
|
if (arr.byteLength < ptr + lasttag[5]!)
|
||
|
return;
|
||
|
const data = arr.slice(ptr, ptr + lasttag[5]!);
|
||
|
total += data.byteLength;
|
||
|
arr = arr.slice(ptr + lasttag[5]!);
|
||
|
ptr = 0;
|
||
|
state = DecoderState.Tag;
|
||
|
ret.push({ tag: lasttag, data });
|
||
|
stack.pop();
|
||
|
while (stack.length > 0) {
|
||
|
const top = stack.pop();
|
||
|
if (!top)
|
||
|
break;
|
||
|
if (total < top[4] + top[3]) {
|
||
|
stack.push(top);
|
||
|
break;
|
||
|
}
|
||
|
ret.push({ tag: lasttag, data, isEnd: true });
|
||
|
}
|
||
|
};
|
||
|
|
||
|
while (ptr < buffer.length) {
|
||
|
if (state == DecoderState.Tag) {
|
||
|
if (!readTag())
|
||
|
break;
|
||
|
} else if (state == DecoderState.Size) {
|
||
|
if (!readSize())
|
||
|
break;
|
||
|
} else if (state == DecoderState.Content) {
|
||
|
if (!readContent())
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
}
|