This commit is contained in:
Alakh Chandarana
2026-01-11 16:51:28 -05:00
parent 7580935639
commit 91e7812fb2
3 changed files with 85 additions and 32 deletions
+3 -2
View File
@@ -154,10 +154,11 @@ export class MatroskaInputFormat extends InputFormat {
return false;
}
const dataSize = readElementSize(headerSlice);
if (dataSize === null) {
const dataSizeResult = readElementSize(headerSlice);
if (dataSizeResult === null || dataSizeResult.size === null) {
return false; // Miss me with that shit
}
const dataSize = dataSizeResult.size;
let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize);
if (dataSlice instanceof Promise) dataSlice = await dataSlice;
+81 -27
View File
@@ -470,6 +470,11 @@ export const MIN_HEADER_SIZE = 2; // 1-byte ID and 1-byte size
export const MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; // 8-byte ID and 8-byte size
export const readVarIntSize = (slice: FileSlice) => {
// Check if we have at least one byte to read
if (slice.remainingLength < 1) {
return null;
}
const firstByte = readU8(slice);
slice.skip(-1);
@@ -484,10 +489,20 @@ export const readVarIntSize = (slice: FileSlice) => {
mask >>= 1;
}
// Check if we have enough bytes to read the full varint
if (slice.remainingLength < width) {
return null;
}
return width;
};
export const readVarInt = (slice: FileSlice) => {
// Check if we have at least one byte
if (slice.remainingLength < 1) {
return null;
}
// Read the first byte to determine the width of the variable-length integer
const firstByte = readU8(slice);
@@ -503,6 +518,13 @@ export const readVarInt = (slice: FileSlice) => {
mask >>= 1;
}
// Check if we have enough bytes remaining for the full varint
if (slice.remainingLength < width - 1) {
// Not enough bytes, rewind and return null
slice.skip(-1);
return null;
}
// First byte's value needs the marker bit cleared
let value = firstByte & (mask - 1);
@@ -567,37 +589,69 @@ export const readElementId = (slice: FileSlice) => {
return id;
};
export const readElementSize = (slice: FileSlice) => {
let size: number | null = readU8(slice);
if (size === 0xff) {
size = null;
} else {
slice.skip(-1);
size = readVarInt(slice);
// In some (livestreamed) files, this is the value of the size field. While this technically is just a very
// large number, it is intended to behave like the reserved size 0xFF, meaning the size is undefined. We
// catch the number here. Note that it cannot be perfectly represented as a double, but the comparison works
// nonetheless.
// eslint-disable-next-line no-loss-of-precision
if (size === 0x00ffffffffffffff) {
size = null;
}
}
return size;
};
export const readElementHeader = (slice: FileSlice) => {
const id = readElementId(slice);
if (id === null) {
/**
* Reads the size field of an EBML element.
*
* @returns
* - `{ size: number }` - Successfully read a definite size
* - `{ size: null }` - Successfully read an undefined size (0xFF marker, used in streaming)
* - `null` - Couldn't read (insufficient bytes or invalid data)
*/
export const readElementSize = (slice: FileSlice): { size: number | null } | null => {
// Need at least 1 byte to read the size
if (slice.remainingLength < 1) {
return null;
}
const size = readElementSize(slice);
const firstByte = readU8(slice);
return { id, size };
if (firstByte === 0xff) {
// Legitimate undefined size marker
return { size: null };
}
slice.skip(-1);
const size = readVarInt(slice);
if (size === null) {
// Couldn't read the varint (insufficient bytes or invalid)
return null;
}
// In some (livestreamed) files, this is the value of the size field. While this technically is just a very
// large number, it is intended to behave like the reserved size 0xFF, meaning the size is undefined. We
// catch the number here. Note that it cannot be perfectly represented as a double, but the comparison works
// nonetheless.
// eslint-disable-next-line no-loss-of-precision
if (size === 0x00ffffffffffffff) {
return { size: null };
}
return { size };
};
export const readElementHeader = (slice: FileSlice) => {
// We need at least MIN_HEADER_SIZE bytes to read a header
if (slice.remainingLength < MIN_HEADER_SIZE) {
return null;
}
const startPos = slice.filePos;
const id = readElementId(slice);
if (id === null) {
slice.filePos = startPos;
return null;
}
const sizeResult = readElementSize(slice);
if (sizeResult === null) {
// Couldn't read size - rewind to start
slice.filePos = startPos;
return null;
}
return { id, size: sizeResult.size };
};
export const readAsciiString = (slice: FileSlice, length: number) => {
+1 -3
View File
@@ -908,9 +908,7 @@ export class MatroskaDemuxer extends Demuxer {
}
readContiguousElements(slice: FileSlice, stopIds?: number[]) {
const startIndex = slice.filePos;
while (slice.filePos - startIndex <= slice.length - MIN_HEADER_SIZE) {
while (slice.remainingLength >= MIN_HEADER_SIZE) {
const startPos = slice.filePos;
const foundElement = this.traverseElement(slice, stopIds);