# Source: streaming/utils/EBMLParser.js

    import FactoryMaker from '../../core/FactoryMaker';

    /**
     * Creates an instance of an EBMLParser class which implements a large subset
     * of the functionality required to parse Matroska EBML
     *
     * @param {Object} config object with data member which is the buffer to parse
     * @ignore
     */
    function EBMLParser(config) {

        config = config || {};
        let instance;

        let data = new DataView(config.data);
        let pos = 0;

        function getPos() {
            return pos;
        }

        function setPos(value) {
            pos = value;
        }

        /**
         * Consumes an EBML tag from the data stream.
         *
         * @param {Object} tag to parse, A tag is an object with at least a {number} tag and
         * {boolean} required flag.
         * @param {boolean} test whether or not the function should throw if a required
         * tag is not found
         * @return {boolean} whether or not the tag was found
         * @throws will throw an exception if a required tag is not found and test
         * param is false or undefined, or if the stream is malformed.
         * @memberof EBMLParser
         */
        function consumeTag(tag, test) {
            let found = true;
            let bytesConsumed = 0;
            let p1,
                p2;

            if (test === undefined) {
                test = false;
            }

            if (tag.tag > 0xFFFFFF) {
                if (data.getUint32(pos) !== tag.tag) {
                    found = false;
                }
                bytesConsumed = 4;
            } else if (tag.tag > 0xFFFF) {
                // 3 bytes
                p1 = data.getUint16(pos);
                p2 = data.getUint8(pos + 2);

                // shift p1 over a byte and add p2
                if (p1 * 256 + p2 !== tag.tag) {
                    found = false;
                }
                bytesConsumed = 3;
            } else if (tag.tag > 0xFF) {
                if (data.getUint16(pos) !== tag.tag) {
                    found = false;
                }
                bytesConsumed = 2;
            } else {
                if (data.getUint8(pos) !== tag.tag) {
                    found = false;
                }
                bytesConsumed = 1;
            }

            if (!found && tag.required && !test) {
                throw new Error('required tag not found');
            }

            if (found) {
                pos += bytesConsumed;
            }

            return found;
        }

        /**
         * Consumes an EBML tag from the data stream.   If the tag is found then this
         * function will also remove the size field which follows the tag from the
         * data stream.
         *
         * @param {Object} tag to parse, A tag is an object with at least a {number} tag and
         * {boolean} required flag.
         * @param {boolean} test whether or not the function should throw if a required
         * tag is not found
         * @return {boolean} whether or not the tag was found
         * @throws will throw an exception if a required tag is not found and test
         * param is false or undefined, or if the stream is malformedata.
         * @memberof EBMLParser
         */
        function consumeTagAndSize(tag, test) {
            let found = consumeTag(tag, test);

            if (found) {
                getMatroskaCodedNum();
            }

            return found;
        }

        /**
         * Consumes an EBML tag from the data stream.   If the tag is found then this
         * function will also remove the size field which follows the tag from the
         * data stream.  It will use the value of the size field to parse a binary
         * field, using a parser defined in the tag itself
         *
         * @param {Object} tag to parse, A tag is an object with at least a {number} tag,
         * {boolean} required flag, and a parse function which takes a size parameter
         * @return {boolean} whether or not the tag was found
         * @throws will throw an exception if a required tag is not found,
         * or if the stream is malformed
         * @memberof EBMLParser
         */
        function parseTag(tag) {
            let size;

            consumeTag(tag);
            size = getMatroskaCodedNum();
            return instance[tag.parse](size);
        }

        /**
         * Consumes an EBML tag from the data stream.   If the tag is found then this
         * function will also remove the size field which follows the tag from the
         * data stream.  It will use the value of the size field to skip over the
         * entire section of EBML encapsulated by the tag.
         *
         * @param {Object} tag to parse, A tag is an object with at least a {number} tag, and
         * {boolean} required flag
         * @param {boolean} test a flag to indicate if an exception should be thrown
         * if a required tag is not found
         * @return {boolean} whether or not the tag was found
         * @throws will throw an exception if a required tag is not found and test is
         * false or undefined or if the stream is malformed
         * @memberof EBMLParser
         */
        function skipOverElement(tag, test) {
            let found = consumeTag(tag, test);
            let headerSize;

            if (found) {
                headerSize = getMatroskaCodedNum();
                pos += headerSize;
            }

            return found;
        }

        /**
         * Returns and consumes a number encoded according to the Matroska EBML
         * specification from the bitstream.
         *
         * @param {boolean} retainMSB whether or not to retain the Most Significant Bit (the
         * first 1). this is usually true when reading Tag IDs.
         * @return {number} the decoded number
         * @throws will throw an exception if the bit stream is malformed or there is
         * not enough data
         * @memberof EBMLParser
         */
        function getMatroskaCodedNum(retainMSB) {
            let bytesUsed = 1;
            let mask = 0x80;
            let maxBytes = 8;
            let extraBytes = -1;
            let num = 0;
            let ch = data.getUint8(pos);
            let i = 0;

            for (i = 0; i < maxBytes; i += 1) {
                if ((ch & mask) === mask) {
                    num = (retainMSB === undefined) ? ch & ~mask : ch;
                    extraBytes = i;
                    break;
                }
                mask >>= 1;
            }

            for (i = 0; i < extraBytes; i += 1, bytesUsed += 1) {
                num = (num << 8) | (0xff & data.getUint8(pos + bytesUsed));
            }

            pos += bytesUsed;

            return num;
        }

        /**
         * Returns and consumes a float from the bitstream.
         *
         * @param {number} size 4 or 8 byte floats are supported
         * @return {number} the decoded number
         * @throws will throw an exception if the bit stream is malformed or there is
         * not enough data
         * @memberof EBMLParser
         */
        function getMatroskaFloat(size) {
            let outFloat;

            switch (size) {
                case 4:
                    outFloat = data.getFloat32(pos);
                    pos += 4;
                    break;
                case 8:
                    outFloat = data.getFloat64(pos);
                    pos += 8;
                    break;
            }
            return outFloat;
        }

        /**
         * Consumes and returns an unsigned int from the bitstream.
         *
         * @param {number} size 1 to 8 bytes
         * @return {number} the decoded number
         * @throws will throw an exception if the bit stream is malformed, there is
         * not enough data, or if the value exceeds the maximum safe integer value
         * @memberof EBMLParser
         */
        function getMatroskaUint(size) {
            if (size > 4) {
                return getMatroskaUintLarge(size);
            }

            let val = 0;

            for (let i = 0; i < size; i += 1) {
                val <<= 8;
                val |= data.getUint8(pos + i) & 0xff;
            }

            pos += size;
            return val >>> 0;
        }

        /**
         * Consumes and returns an unsigned int from the bitstream.
         *
         * @param {number} size 1 to 8 bytes
         * @return {number} the decoded number
         * @throws will throw an exception if the bit stream is malformed, there is
         * not enough data, or if the value exceeds the maximum safe integer value
         */
        function getMatroskaUintLarge(size) {
            const limit = Math.floor(Number.MAX_SAFE_INTEGER / 256);
            let val = 0;

            for (let i = 0; i < size; i += 1) {
                if (val > limit) {
                    throw new Error('Value exceeds safe integer limit');
                }
                val *= 256;
                const n = data.getUint8(pos + i);
                if (val > Number.MAX_SAFE_INTEGER - n) {
                    throw new Error('Value exceeds safe integer limit');
                }
                val += n;
            }

            pos += size;
            return val;
        }

        /**
         * Tests whether there is more data in the bitstream for parsing
         *
         * @return {boolean} whether there is more data to parse
         * @memberof EBMLParser
         */
        function moreData() {
            return pos < data.byteLength;
        }

        instance = {
            getPos: getPos,
            setPos: setPos,
            consumeTag: consumeTag,
            consumeTagAndSize: consumeTagAndSize,
            parseTag: parseTag,
            skipOverElement: skipOverElement,
            getMatroskaCodedNum: getMatroskaCodedNum,
            getMatroskaFloat: getMatroskaFloat,
            getMatroskaUint: getMatroskaUint,
            moreData: moreData
        };

        return instance;
    }

    EBMLParser.__dashjs_factory_name = 'EBMLParser';
    export default FactoryMaker.getClassFactory(EBMLParser);

#### Search results