115 lines
2.8 KiB
TypeScript
115 lines
2.8 KiB
TypeScript
import { createEbmlTag } from 'src/factory';
|
|
import { decodeEbmlTagHeader } from '../decode-utils';
|
|
import { EbmlElementType, EbmlTagPosition, isEbmlMasterTagId } from './enums';
|
|
import type { EbmlMasterTagIdType } from './enums';
|
|
import {
|
|
type CreateEbmlTagOptions,
|
|
type DecodeContentOptions,
|
|
EbmlTagTrait,
|
|
} from './tag-trait';
|
|
|
|
export interface CreateEbmlMasterTagOptions
|
|
extends Omit<CreateEbmlTagOptions, 'position' | 'type' | 'id'> {
|
|
id: EbmlMasterTagIdType;
|
|
}
|
|
|
|
export class EbmlMasterTag extends EbmlTagTrait {
|
|
private _children: EbmlTagTrait[] = [];
|
|
|
|
constructor(options: CreateEbmlMasterTagOptions) {
|
|
super({
|
|
...options,
|
|
id: options.id,
|
|
type: EbmlElementType.Master,
|
|
});
|
|
}
|
|
|
|
override get byteLengthQueuingSize(): number {
|
|
if (this.position === EbmlTagPosition.Start) {
|
|
return this.headerLength;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
get children(): EbmlTagTrait[] {
|
|
return this._children;
|
|
}
|
|
|
|
set children(value: EbmlTagTrait[]) {
|
|
this._children = value;
|
|
}
|
|
|
|
*encodeContent(): Generator<Uint8Array, void, unknown> {
|
|
for (const child of this.children) {
|
|
yield* child.encode();
|
|
}
|
|
}
|
|
|
|
async *decodeContentImpl(options: DecodeContentOptions) {
|
|
const controller = options.dataViewController;
|
|
const collectChild = options.collectChild;
|
|
while (true) {
|
|
const offset = controller.getOffset();
|
|
|
|
if (offset >= this.endOffset) {
|
|
break;
|
|
}
|
|
|
|
const peeked = await controller.peek(offset);
|
|
|
|
if (!peeked) {
|
|
break;
|
|
}
|
|
|
|
const vints = await decodeEbmlTagHeader(controller);
|
|
|
|
const { tagId, tagVint, sizeVint } = vints;
|
|
|
|
const headerLength = tagVint.length + sizeVint.length;
|
|
const contentLength = sizeVint.value;
|
|
|
|
const isMaster = isEbmlMasterTagId(tagId);
|
|
|
|
if (isMaster) {
|
|
const tag: EbmlTagTrait = createEbmlTag(tagId, {
|
|
headerLength,
|
|
contentLength,
|
|
startOffset: offset,
|
|
position: EbmlTagPosition.Start,
|
|
parent: this,
|
|
});
|
|
yield tag;
|
|
}
|
|
|
|
await controller.seek(offset + headerLength);
|
|
|
|
const tag: EbmlTagTrait = createEbmlTag(tagId, {
|
|
headerLength,
|
|
contentLength,
|
|
startOffset: offset,
|
|
position: isMaster ? EbmlTagPosition.End : EbmlTagPosition.Content,
|
|
parent: this,
|
|
});
|
|
|
|
for await (const item of tag.decodeContent(options)) {
|
|
yield item;
|
|
}
|
|
|
|
tag.endOffset = controller.getOffset();
|
|
|
|
let shouldCollectChild: boolean;
|
|
if (typeof collectChild === 'function') {
|
|
shouldCollectChild = !!collectChild(tag, this);
|
|
} else {
|
|
shouldCollectChild = !!collectChild;
|
|
}
|
|
|
|
if (shouldCollectChild) {
|
|
this._children.push(tag);
|
|
}
|
|
|
|
yield tag;
|
|
}
|
|
}
|
|
}
|