124 lines
3.2 KiB
TypeScript
124 lines
3.2 KiB
TypeScript
import { type CreateEbmlDataTagOptions, EbmlDataTag } from './tag-data';
|
|
import { EbmlBlockLacing } from './enums';
|
|
import {
|
|
dataViewSlice,
|
|
dataViewSliceToBuf,
|
|
readSigned,
|
|
readVint,
|
|
writeSigned,
|
|
writeVint,
|
|
} from '../tools';
|
|
import {
|
|
type EbmlBlockTagIdType,
|
|
type EbmlSimpleBlockTagIdType,
|
|
EbmlTagIdEnum,
|
|
} from './enums';
|
|
import { EbmlElementType } from './enums';
|
|
import type { FileDataViewController } from '../adapters';
|
|
|
|
export interface CreateEbmlBlockTagOptions
|
|
extends Omit<CreateEbmlDataTagOptions, 'id' | 'type'> {
|
|
id?: EbmlBlockTagIdType | EbmlSimpleBlockTagIdType;
|
|
}
|
|
|
|
export class EbmlBlockTag extends EbmlDataTag {
|
|
payload = new Uint8Array(0);
|
|
track: number | bigint = 0;
|
|
value = 0;
|
|
|
|
invisible: boolean | undefined;
|
|
lacing: EbmlBlockLacing | undefined;
|
|
|
|
constructor(options: CreateEbmlBlockTagOptions) {
|
|
super({
|
|
...options,
|
|
id: options.id ?? EbmlTagIdEnum.Block,
|
|
type: EbmlElementType.Binary,
|
|
});
|
|
}
|
|
|
|
protected writeTrackBuffer(): Uint8Array {
|
|
return writeVint(this.track);
|
|
}
|
|
|
|
protected writeValueBuffer(): Uint8Array {
|
|
return writeSigned(this.value, 2);
|
|
}
|
|
|
|
protected writeFlagsBuffer(): Uint8Array {
|
|
let flags = 0x00;
|
|
if (this.invisible) {
|
|
flags |= 0x10;
|
|
}
|
|
|
|
switch (this.lacing) {
|
|
case EbmlBlockLacing.None:
|
|
break;
|
|
case EbmlBlockLacing.Xiph:
|
|
flags |= 0x04;
|
|
break;
|
|
case EbmlBlockLacing.EBML:
|
|
flags |= 0x08;
|
|
break;
|
|
case EbmlBlockLacing.FixedSize:
|
|
flags |= 0x0c;
|
|
break;
|
|
default:
|
|
}
|
|
|
|
return new Uint8Array([flags % 256]);
|
|
}
|
|
|
|
*encodeContent(): Generator<Uint8Array, void, unknown> {
|
|
yield this.writeTrackBuffer();
|
|
yield this.writeValueBuffer();
|
|
yield this.writeFlagsBuffer();
|
|
yield this.payload;
|
|
}
|
|
|
|
// biome-ignore lint/correctness/useYield: <explanation>
|
|
async *decodeContentImpl(controller: FileDataViewController) {
|
|
const offset = controller.getOffset();
|
|
const view = await controller.read(offset, this.contentLength, true);
|
|
const track = readVint(view)!;
|
|
this.track = track.value;
|
|
this.value = Number(
|
|
readSigned(dataViewSlice(view, track.length, track.length + 2))
|
|
);
|
|
const flags: number = view.getUint8(track.length + 2);
|
|
this.invisible = Boolean(flags & 0x10);
|
|
switch (flags & 0x0c) {
|
|
case 0x00:
|
|
this.lacing = EbmlBlockLacing.None;
|
|
break;
|
|
|
|
case 0x04:
|
|
this.lacing = EbmlBlockLacing.Xiph;
|
|
break;
|
|
|
|
case 0x08:
|
|
this.lacing = EbmlBlockLacing.EBML;
|
|
break;
|
|
|
|
case 0x0c:
|
|
this.lacing = EbmlBlockLacing.FixedSize;
|
|
break;
|
|
default:
|
|
}
|
|
this.payload = dataViewSliceToBuf(view, track.length + 3, undefined);
|
|
await controller.seek(offset + view.byteLength);
|
|
}
|
|
|
|
override toDebugRecord() {
|
|
const s = super.toDebugRecord();
|
|
return {
|
|
...s,
|
|
payload: this.payload,
|
|
track: this.track,
|
|
value: this.value,
|
|
invisible: this.invisible,
|
|
lacing: EbmlBlockLacing[this.lacing!] || this.lacing,
|
|
};
|
|
}
|
|
}
|