ebml-stream
Version:
Ebml parser and encoder
97 lines (96 loc) • 3.79 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const stream_1 = require("stream");
const tools_1 = require("./tools");
const EbmlElementType_1 = require("./models/enums/EbmlElementType");
const EbmlTagPosition_1 = require("./models/enums/EbmlTagPosition");
const EbmlTagFactory_1 = require("./models/EbmlTagFactory");
class EbmlStreamDecoderOptions {
constructor() {
this.bufferTagIds = [];
}
}
exports.EbmlStreamDecoderOptions = EbmlStreamDecoderOptions;
class EbmlStreamDecoder extends stream_1.Transform {
constructor(options = {}) {
super(Object.assign({}, options, { readableObjectMode: true }));
this._currentBufferOffset = 0;
this._tagStack = [];
this._buffer = Buffer.alloc(0);
this._bufferTagIds = [];
this._bufferTagIds = options.bufferTagIds || [];
}
get buffer() {
return this._buffer;
}
_transform(chunk, enc, done) {
this._buffer = Buffer.concat([this._buffer, Buffer.from(chunk)]);
while (this.parseTags())
;
done();
}
parseTags() {
const currentTag = this.readTagHeader(this._buffer);
if (!currentTag) {
return false;
}
if (currentTag.type === EbmlElementType_1.EbmlElementType.Master && !this._bufferTagIds.some(i => i === currentTag.id)) {
this._tagStack.push(currentTag);
this.emitTag(currentTag, EbmlTagPosition_1.EbmlTagPosition.Start);
this.advanceBuffer(currentTag.tagHeaderLength);
return true;
}
else {
if (this._buffer.length < currentTag.tagHeaderLength + currentTag.size) {
return false;
}
const data = this._buffer.slice(currentTag.tagHeaderLength, currentTag.tagHeaderLength + currentTag.size);
this.emitTag(currentTag, EbmlTagPosition_1.EbmlTagPosition.Content, data);
this.advanceBuffer(currentTag.tagHeaderLength + currentTag.size);
while (this._tagStack.length > 0) {
const nextTag = this._tagStack[this._tagStack.length - 1];
if (this._currentBufferOffset < (nextTag.absoluteStart + nextTag.tagHeaderLength + nextTag.size)) {
break;
}
this.emitTag(nextTag, EbmlTagPosition_1.EbmlTagPosition.End);
this._tagStack.pop();
}
}
return true;
}
advanceBuffer(length) {
this._currentBufferOffset += length;
this._buffer = this._buffer.slice(length);
}
readTagHeader(buffer, offset = 0) {
if (buffer.length == 0) {
return null;
}
const tag = tools_1.Tools.readVint(buffer, offset);
if (tag == null) {
return null;
}
const size = tools_1.Tools.readVint(buffer, offset + tag.length);
if (size == null) {
return null;
}
const tagIdHex = tools_1.Tools.readHexString(buffer, offset, offset + tag.length);
const tagId = Number.parseInt(tagIdHex, 16);
let tagObject = EbmlTagFactory_1.EbmlTagFactory.create(tagId);
tagObject.size = size.value;
return Object.assign(tagObject, {
absoluteStart: this._currentBufferOffset + offset,
tagHeaderLength: tag.length + size.length
});
}
emitTag(tag, position, data) {
let emittedTag = EbmlTagFactory_1.EbmlTagFactory.create(tag.id);
emittedTag.size = tag.size;
emittedTag.position = position;
if (position === EbmlTagPosition_1.EbmlTagPosition.Content) {
emittedTag.parseContent(data);
}
this.push(emittedTag);
}
}
exports.EbmlStreamDecoder = EbmlStreamDecoder;