"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeSfntOtf = writeSfntOtf;
exports.writeSfntOtfFromTableSlices = writeSfntOtfFromTableSlices;
const bin_util_1 = require("@ot-builder/bin-util");
const primitive_1 = require("@ot-builder/primitive");
const collector_1 = require("./collector");
function offsetTableSize(numTable) {
    const headerSize = primitive_1.UInt32.size + primitive_1.UInt16.size * 4;
    const recordSize = primitive_1.Tag.size + primitive_1.UInt32.size * 3;
    return headerSize + numTable * recordSize;
}
// Reference
//  - https://docs.microsoft.com/en-us/typography/opentype/spec/otff#calculating-checksums
function fixHeadChecksum(bw, headOffset) {
    bw.seek(bw.length);
    while (bw.length % 4)
        bw.uint8(0);
    bw.seek(headOffset + 8);
    bw.uint32(0);
    const fontChecksum = (0, collector_1.calculateChecksum)(bw.toBuffer());
    bw.seek(headOffset + 8);
    bw.uint32(primitive_1.UInt32.from(0xb1b0afba - fontChecksum));
}
function writeSfntOtf(sfnt) {
    const ds = { version: sfnt.version, tables: new Map() };
    for (const [tag, table] of sfnt.tables)
        ds.tables.set(tag, (0, collector_1.BufferToSlice)(table));
    return writeSfntOtfFromTableSlices(ds);
}
function writeSfntOtfFromTableSlices(sfnt) {
    const store = new Map();
    const numTable = sfnt.tables.size;
    const searchRange = Math.pow(2, Math.floor(Math.log(numTable) / Math.LN2)) * 16;
    const entrySelector = Math.floor(Math.log(numTable) / Math.LN2);
    const rangeShift = numTable * 16 - searchRange;
    const headerSize = offsetTableSize(numTable);
    const records = [];
    for (const [tag, table] of sfnt.tables) {
        records.push((0, collector_1.collectTableData)(tag, table, store));
    }
    records.sort((a, b) => (a.tag < b.tag ? -1 : a.tag > b.tag ? 1 : 0));
    (0, collector_1.allocateBlobOffsets)(store);
    const bw = new bin_util_1.BufferWriter();
    bw.uint32(sfnt.version);
    bw.uint16(numTable);
    bw.uint16(searchRange);
    bw.uint16(entrySelector);
    bw.uint16(rangeShift);
    let headOffset = 0;
    for (const record of records) {
        if (record.tag === "head")
            headOffset = headerSize + record.blob.offset;
        bw.bytes(bin_util_1.Frag.pack(new bin_util_1.Frag().push(primitive_1.Tag, record.tag)));
        bw.uint32(record.blob.checksum);
        bw.uint32(headerSize + record.blob.offset + record.start);
        bw.uint32(record.length);
    }
    for (const blob of store.values()) {
        bw.seek(headerSize + blob.offset);
        bw.bytes(blob.content);
    }
    fixHeadChecksum(bw, headOffset);
    return bw.toBuffer();
}
//# sourceMappingURL=write.js.map