Allow all Matroska AttachedFiles to be read & written via metadata tags

This commit is contained in:
Vanilagy
2025-09-19 20:12:29 +02:00
parent e28c34cb7a
commit a3f4f7f4f7
8 changed files with 220 additions and 21 deletions
+54 -4
View File
@@ -16,6 +16,7 @@ export interface EBMLElement {
size?: number;
data:
| number
| bigint
| string
| Uint8Array
| EBMLFloat32
@@ -198,6 +199,26 @@ export const measureUnsignedInt = (value: number) => {
}
};
export const measureUnsignedBigInt = (value: bigint) => {
if (value < (1n << 8n)) {
return 1;
} else if (value < (1n << 16n)) {
return 2;
} else if (value < (1n << 24n)) {
return 3;
} else if (value < (1n << 32n)) {
return 4;
} else if (value < (1n << 40n)) {
return 5;
} else if (value < (1n << 48n)) {
return 6;
} else if (value < (1n << 56n)) {
return 7;
} else {
return 8;
}
};
export const measureSignedInt = (value: number) => {
if (value >= -(1 << 6) && value < (1 << 6)) {
return 1;
@@ -276,16 +297,16 @@ export class EBMLWriter {
// eslint-disable-next-line no-fallthrough
case 5:
this.helperView.setUint8(pos++, (value / 2 ** 32) | 0);
// eslint-disable-next-line no-fallthrough
// eslint-disable-next-line no-fallthrough
case 4:
this.helperView.setUint8(pos++, value >> 24);
// eslint-disable-next-line no-fallthrough
// eslint-disable-next-line no-fallthrough
case 3:
this.helperView.setUint8(pos++, value >> 16);
// eslint-disable-next-line no-fallthrough
// eslint-disable-next-line no-fallthrough
case 2:
this.helperView.setUint8(pos++, value >> 8);
// eslint-disable-next-line no-fallthrough
// eslint-disable-next-line no-fallthrough
case 1:
this.helperView.setUint8(pos++, value);
break;
@@ -296,6 +317,16 @@ export class EBMLWriter {
this.writer.write(this.helper.subarray(0, pos));
}
writeUnsignedBigInt(value: bigint, width = measureUnsignedBigInt(value)) {
let pos = 0;
for (let i = width - 1; i >= 0; i--) {
this.helperView.setUint8(pos++, Number((value >> BigInt(i * 8)) & 0xffn));
}
this.writer.write(this.helper.subarray(0, pos));
}
writeSignedInt(value: number, width = measureSignedInt(value)) {
if (value < 0) {
// Two's complement stuff
@@ -398,6 +429,10 @@ export class EBMLWriter {
const size = data.size ?? measureUnsignedInt(data.data);
this.writeVarInt(size);
this.writeUnsignedInt(data.data, size);
} else if (typeof data.data === 'bigint') {
const size = data.size ?? measureUnsignedBigInt(data.data);
this.writeVarInt(size);
this.writeUnsignedBigInt(data.data, size);
} else if (typeof data.data === 'string') {
this.writeVarInt(data.data.length);
this.writeAsciiString(data.data);
@@ -491,6 +526,21 @@ export const readUnsignedInt = (slice: FileSlice, width: number) => {
return value;
};
export const readUnsignedBigInt = (slice: FileSlice, width: number) => {
if (width < 1) {
throw new Error('Bad unsigned int size ' + width);
}
let value = 0n;
for (let i = 0; i < width; i++) {
value <<= 8n;
value += BigInt(readU8(slice));
}
return value;
};
export const readSignedInt = (slice: FileSlice, width: number) => {
let value = readUnsignedInt(slice, width);