"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CharStringIrSource = exports.CffDictIrSource = void 0;
const errors_1 = require("@ot-builder/errors");
const primitive_1 = require("@ot-builder/primitive");
const CffInterp = require("./ir");
class BinaryIrSource {
    constructor(rawView, size) {
        this.view = rawView.liftRelative(0);
        rawView.bytes(size);
        this.startCursor = this.view.cursor;
        this.endCursor = this.startCursor + size;
    }
    eof() {
        return this.view.cursor >= this.endCursor;
    }
}
function parseCffShortInt(view, leadByte) {
    if (32 <= leadByte && leadByte <= 246) {
        return CffInterp.operand(leadByte - 139);
    }
    else if (247 <= leadByte && leadByte <= 250) {
        const nextByte = view.uint8();
        return CffInterp.operand((leadByte - 247) * 256 + nextByte + 108);
    }
    else if (251 <= leadByte && leadByte <= 254) {
        const nextByte = view.uint8();
        return CffInterp.operand(-(leadByte - 251) * 256 - nextByte - 108);
    }
    else {
        throw errors_1.Errors.Unreachable();
    }
}
class CffDictIrSource extends BinaryIrSource {
    cffDictNibbles() {
        // CFF nibbles
        const nibs = [];
        for (;;) {
            const b = this.view.uint8();
            const nib0 = b >> 4, nib1 = b & 0xf;
            if (nib0 !== 0xf)
                nibs.push(nib0);
            if (nib1 !== 0xf)
                nibs.push(nib1);
            if (nib0 === 0xf || nib1 === 0xf)
                break;
        }
        let s = "";
        // prettier-ignore
        const chars = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ".", "e", "e-", "reserved", "-", "endOfNumber"];
        for (let nibIndex = 0; nibIndex < nibs.length; nibIndex++) {
            s += chars[nibs[nibIndex]];
        }
        return CffInterp.operand(parseFloat(s));
    }
    next() {
        if (this.eof())
            return null;
        const leadByte = this.view.uint8();
        if (leadByte === 28) {
            return CffInterp.operand(this.view.int16());
        }
        else if (leadByte === 29) {
            return CffInterp.operand(this.view.int32());
        }
        else if (leadByte === 30) {
            return this.cffDictNibbles();
        }
        else if (32 <= leadByte && leadByte <= 254) {
            return parseCffShortInt(this.view, leadByte);
        }
        else {
            // Operator
            if (leadByte === 12) {
                const nextByte = this.view.uint8();
                return CffInterp.operator(0x0c00 | nextByte);
            }
            else {
                return CffInterp.operator(leadByte);
            }
        }
    }
}
exports.CffDictIrSource = CffDictIrSource;
class CharStringIrSource extends BinaryIrSource {
    next() {
        if (this.eof())
            return null;
        const leadByte = this.view.uint8();
        if (this.isOperator(leadByte)) {
            return this.parseOperator(leadByte);
        }
        else if (leadByte === 28) {
            return CffInterp.operand(this.view.int16());
        }
        else if (32 <= leadByte && leadByte <= 254) {
            return parseCffShortInt(this.view, leadByte);
        }
        else if (leadByte === 255) {
            return CffInterp.operand(this.view.next(primitive_1.F16D16));
        }
        else {
            throw errors_1.Errors.Cff.UnknownToken();
        }
    }
    isOperator(leadByte) {
        return (leadByte > 0 && leadByte <= 27) || (leadByte >= 29 && leadByte <= 31);
    }
    parseOperator(leadByte) {
        let opCode;
        if (leadByte === 12) {
            const nextByte = this.view.uint8();
            opCode = (leadByte << 8) | nextByte;
        }
        else {
            opCode = leadByte;
        }
        return CffInterp.operator(opCode);
    }
    pullFlags(stemCount) {
        const maskLength = (stemCount + 7) >> 3;
        const mask = [];
        for (let byte = 0; byte < maskLength; byte++) {
            const maskByte = this.view.uint8();
            mask[(byte << 3) + 0] = (maskByte >> 7) & 1;
            mask[(byte << 3) + 1] = (maskByte >> 6) & 1;
            mask[(byte << 3) + 2] = (maskByte >> 5) & 1;
            mask[(byte << 3) + 3] = (maskByte >> 4) & 1;
            mask[(byte << 3) + 4] = (maskByte >> 3) & 1;
            mask[(byte << 3) + 5] = (maskByte >> 2) & 1;
            mask[(byte << 3) + 6] = (maskByte >> 1) & 1;
            mask[(byte << 3) + 7] = (maskByte >> 0) & 1;
        }
        return mask;
    }
}
exports.CharStringIrSource = CharStringIrSource;
//# sourceMappingURL=ir-source.js.map