mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-02 21:33:52 +02:00
Add strict slice range validation, fix RF64 reading error (fixes #146)
This commit is contained in:
@@ -14,12 +14,21 @@
|
|||||||
source: new Mediabunny.BlobSource(file),
|
source: new Mediabunny.BlobSource(file),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const audioTrack = await input.getPrimaryAudioTrack();
|
||||||
|
|
||||||
|
const sink = new Mediabunny.EncodedPacketSink(audioTrack);
|
||||||
|
for await (const packet of sink.packets()) {
|
||||||
|
console.log(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
const videoTrack = await input.getPrimaryVideoTrack();
|
const videoTrack = await input.getPrimaryVideoTrack();
|
||||||
const sink = new Mediabunny.VideoSampleSink(videoTrack);
|
const sink = new Mediabunny.VideoSampleSink(videoTrack);
|
||||||
|
|
||||||
const sample = await sink.getSample(0);
|
const sample = await sink.getSample(0);
|
||||||
|
|
||||||
console.log(sample);
|
console.log(sample);
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
||||||
|
|||||||
+2
-2
@@ -155,7 +155,7 @@ export const writeBits = (bytes: Uint8Array, start: number, end: number, value:
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const toUint8Array = (source: AllowSharedBufferSource): Uint8Array => {
|
export const toUint8Array = (source: AllowSharedBufferSource): Uint8Array => {
|
||||||
if (source instanceof Uint8Array) {
|
if (source.constructor === Uint8Array) { // We want a true Uint8Array, not something that extends it like Buffer
|
||||||
return source;
|
return source;
|
||||||
} else if (source instanceof ArrayBuffer) {
|
} else if (source instanceof ArrayBuffer) {
|
||||||
return new Uint8Array(source);
|
return new Uint8Array(source);
|
||||||
@@ -165,7 +165,7 @@ export const toUint8Array = (source: AllowSharedBufferSource): Uint8Array => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const toDataView = (source: AllowSharedBufferSource) => {
|
export const toDataView = (source: AllowSharedBufferSource) => {
|
||||||
if (source instanceof DataView) {
|
if (source.constructor === DataView) {
|
||||||
return source;
|
return source;
|
||||||
} else if (source instanceof ArrayBuffer) {
|
} else if (source instanceof ArrayBuffer) {
|
||||||
return new DataView(source);
|
return new DataView(source);
|
||||||
|
|||||||
+38
-4
@@ -149,16 +149,32 @@ export class FileSlice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkIsInRange = (slice: FileSlice, bytesToRead: number) => {
|
||||||
|
if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) {
|
||||||
|
throw new RangeError(
|
||||||
|
`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is`
|
||||||
|
+ ` [${slice.start}, ${slice.end}).`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const readBytes = (slice: FileSlice, length: number) => {
|
export const readBytes = (slice: FileSlice, length: number) => {
|
||||||
|
checkIsInRange(slice, length);
|
||||||
|
|
||||||
const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length);
|
const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length);
|
||||||
slice.bufferPos += length;
|
slice.bufferPos += length;
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const readU8 = (slice: FileSlice) => slice.view.getUint8(slice.bufferPos++);
|
export const readU8 = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 1);
|
||||||
|
return slice.view.getUint8(slice.bufferPos++);
|
||||||
|
};
|
||||||
|
|
||||||
export const readU16 = (slice: FileSlice, littleEndian: boolean) => {
|
export const readU16 = (slice: FileSlice, littleEndian: boolean) => {
|
||||||
|
checkIsInRange(slice, 2);
|
||||||
|
|
||||||
const value = slice.view.getUint16(slice.bufferPos, littleEndian);
|
const value = slice.view.getUint16(slice.bufferPos, littleEndian);
|
||||||
slice.bufferPos += 2;
|
slice.bufferPos += 2;
|
||||||
|
|
||||||
@@ -166,6 +182,8 @@ export const readU16 = (slice: FileSlice, littleEndian: boolean) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readU16Be = (slice: FileSlice) => {
|
export const readU16Be = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 2);
|
||||||
|
|
||||||
const value = slice.view.getUint16(slice.bufferPos, false);
|
const value = slice.view.getUint16(slice.bufferPos, false);
|
||||||
slice.bufferPos += 2;
|
slice.bufferPos += 2;
|
||||||
|
|
||||||
@@ -173,6 +191,8 @@ export const readU16Be = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readU24Be = (slice: FileSlice) => {
|
export const readU24Be = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 3);
|
||||||
|
|
||||||
const value = getUint24(slice.view, slice.bufferPos, false);
|
const value = getUint24(slice.view, slice.bufferPos, false);
|
||||||
slice.bufferPos += 3;
|
slice.bufferPos += 3;
|
||||||
|
|
||||||
@@ -180,6 +200,8 @@ export const readU24Be = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readI16Be = (slice: FileSlice) => {
|
export const readI16Be = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 2);
|
||||||
|
|
||||||
const value = slice.view.getInt16(slice.bufferPos, false);
|
const value = slice.view.getInt16(slice.bufferPos, false);
|
||||||
slice.bufferPos += 2;
|
slice.bufferPos += 2;
|
||||||
|
|
||||||
@@ -187,6 +209,8 @@ export const readI16Be = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readU32 = (slice: FileSlice, littleEndian: boolean) => {
|
export const readU32 = (slice: FileSlice, littleEndian: boolean) => {
|
||||||
|
checkIsInRange(slice, 4);
|
||||||
|
|
||||||
const value = slice.view.getUint32(slice.bufferPos, littleEndian);
|
const value = slice.view.getUint32(slice.bufferPos, littleEndian);
|
||||||
slice.bufferPos += 4;
|
slice.bufferPos += 4;
|
||||||
|
|
||||||
@@ -194,6 +218,8 @@ export const readU32 = (slice: FileSlice, littleEndian: boolean) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readU32Be = (slice: FileSlice) => {
|
export const readU32Be = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 4);
|
||||||
|
|
||||||
const value = slice.view.getUint32(slice.bufferPos, false);
|
const value = slice.view.getUint32(slice.bufferPos, false);
|
||||||
slice.bufferPos += 4;
|
slice.bufferPos += 4;
|
||||||
|
|
||||||
@@ -201,6 +227,8 @@ export const readU32Be = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readU32Le = (slice: FileSlice) => {
|
export const readU32Le = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 4);
|
||||||
|
|
||||||
const value = slice.view.getUint32(slice.bufferPos, true);
|
const value = slice.view.getUint32(slice.bufferPos, true);
|
||||||
slice.bufferPos += 4;
|
slice.bufferPos += 4;
|
||||||
|
|
||||||
@@ -208,6 +236,8 @@ export const readU32Le = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readI32Be = (slice: FileSlice) => {
|
export const readI32Be = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 4);
|
||||||
|
|
||||||
const value = slice.view.getInt32(slice.bufferPos, false);
|
const value = slice.view.getInt32(slice.bufferPos, false);
|
||||||
slice.bufferPos += 4;
|
slice.bufferPos += 4;
|
||||||
|
|
||||||
@@ -215,6 +245,8 @@ export const readI32Be = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readI32Le = (slice: FileSlice) => {
|
export const readI32Le = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 4);
|
||||||
|
|
||||||
const value = slice.view.getInt32(slice.bufferPos, true);
|
const value = slice.view.getInt32(slice.bufferPos, true);
|
||||||
slice.bufferPos += 4;
|
slice.bufferPos += 4;
|
||||||
|
|
||||||
@@ -255,6 +287,8 @@ export const readI64Le = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readF32Be = (slice: FileSlice) => {
|
export const readF32Be = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 4);
|
||||||
|
|
||||||
const value = slice.view.getFloat32(slice.bufferPos, false);
|
const value = slice.view.getFloat32(slice.bufferPos, false);
|
||||||
slice.bufferPos += 4;
|
slice.bufferPos += 4;
|
||||||
|
|
||||||
@@ -262,6 +296,8 @@ export const readF32Be = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readF64Be = (slice: FileSlice) => {
|
export const readF64Be = (slice: FileSlice) => {
|
||||||
|
checkIsInRange(slice, 8);
|
||||||
|
|
||||||
const value = slice.view.getFloat64(slice.bufferPos, false);
|
const value = slice.view.getFloat64(slice.bufferPos, false);
|
||||||
slice.bufferPos += 8;
|
slice.bufferPos += 8;
|
||||||
|
|
||||||
@@ -269,9 +305,7 @@ export const readF64Be = (slice: FileSlice) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const readAscii = (slice: FileSlice, length: number) => {
|
export const readAscii = (slice: FileSlice, length: number) => {
|
||||||
if (slice.bufferPos + length > slice.bytes.length) {
|
checkIsInRange(slice, length);
|
||||||
throw new RangeError('Reading past end of slice.');
|
|
||||||
}
|
|
||||||
|
|
||||||
let str = '';
|
let str = '';
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -764,6 +764,8 @@ export class StreamSource extends Source {
|
|||||||
if (data instanceof Promise) data = await data;
|
if (data instanceof Promise) data = await data;
|
||||||
|
|
||||||
if (data instanceof Uint8Array) {
|
if (data instanceof Uint8Array) {
|
||||||
|
data = toUint8Array(data); // Normalize things like Node.js Buffer to Uint8Array
|
||||||
|
|
||||||
if (data.length !== originalTargetPos - worker.currentPos) {
|
if (data.length !== originalTargetPos - worker.currentPos) {
|
||||||
// Yes, we're that strict
|
// Yes, we're that strict
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -798,8 +800,10 @@ export class StreamSource extends Source {
|
|||||||
throw new TypeError('ReadableStream returned by options.read must yield Uint8Array chunks.');
|
throw new TypeError('ReadableStream returned by options.read must yield Uint8Array chunks.');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onread?.(worker.currentPos, worker.currentPos + value.length);
|
const data = toUint8Array(value); // Normalize things like Node.js Buffer to Uint8Array
|
||||||
this._orchestrator.supplyWorkerData(worker, value);
|
|
||||||
|
this.onread?.(worker.currentPos, worker.currentPos + data.length);
|
||||||
|
this._orchestrator.supplyWorkerData(worker, data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new TypeError('options.read must return or resolve to a Uint8Array or a ReadableStream.');
|
throw new TypeError('options.read must return or resolve to a Uint8Array or a ReadableStream.');
|
||||||
|
|||||||
@@ -102,8 +102,12 @@ export class WaveDemuxer extends Demuxer {
|
|||||||
} else if (chunkId === 'ds64') {
|
} else if (chunkId === 'ds64') {
|
||||||
// File and data chunk sizes are defined in here instead
|
// File and data chunk sizes are defined in here instead
|
||||||
|
|
||||||
const riffChunkSize = readU64(slice, littleEndian);
|
let ds64Slice = this.reader.requestSlice(startPos, chunkSize);
|
||||||
dataChunkSize = readU64(slice, littleEndian);
|
if (ds64Slice instanceof Promise) ds64Slice = await ds64Slice;
|
||||||
|
if (!ds64Slice) break;
|
||||||
|
|
||||||
|
const riffChunkSize = readU64(ds64Slice, littleEndian);
|
||||||
|
dataChunkSize = readU64(ds64Slice, littleEndian);
|
||||||
|
|
||||||
totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity);
|
totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity);
|
||||||
} else if (chunkId === 'LIST') {
|
} else if (chunkId === 'LIST') {
|
||||||
|
|||||||
Reference in New Issue
Block a user