"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.streamToBuffer = exports.ZeroStream = exports.blockDecompressor = exports.blockGenerator = exports.withOpenImage = void 0;
const adc = require("apple-data-compression");
const fs_1 = require("fs");
const stream_1 = require("stream");
const bz2 = require("unbzip2-stream");
const zlib = require("zlib");
const constants_1 = require("./constants");
const image_1 = require("./image");
async function withOpenImage(filePath, fn) {
    const handle = await fs_1.promises.open(filePath, 'r');
    try {
        const image = new image_1.Image({
            size: (await handle.stat()).size,
            createReadStream: async (start = 0, end = Infinity) => {
                return (0, fs_1.createReadStream)('', { fd: handle.fd, autoClose: false, start, end });
            },
        });
        await image.ready;
        return await fn(image);
    }
    finally {
        await handle.close();
    }
}
exports.withOpenImage = withOpenImage;
function* blockGenerator(image, exclude = []) {
    for (const entry of image.resourceFork.blkx) {
        for (const block of entry.map.blocks) {
            if (!exclude.includes(block.type)) {
                yield { entry, block };
            }
        }
    }
}
exports.blockGenerator = blockGenerator;
function blockDecompressor(type, inputStream) {
    if (type === constants_1.BLOCK.RAW) {
        return inputStream;
    }
    else if (type === constants_1.BLOCK.UDZO) {
        return inputStream.pipe(zlib.createInflate());
    }
    else if (type === constants_1.BLOCK.UDBZ) {
        return inputStream.pipe(bz2());
    }
    else if (type === constants_1.BLOCK.UDCO) {
        return inputStream.pipe(new adc.Decompressor());
    }
    else if (type === constants_1.BLOCK.LZFSE) {
        throw new Error('Unsupported compression method: LZFSE');
    }
    throw new Error(`Unknown compression method for type "0x${type.toString(16)}"`);
}
exports.blockDecompressor = blockDecompressor;
class ZeroStream extends stream_1.Readable {
    constructor(length = Infinity, blank) {
        super();
        this.length = length;
        this.blank = blank !== null && blank !== void 0 ? blank : Buffer.alloc(64 * 1024);
    }
    _read() {
        if (this.length >= this.blank.length) {
            this.push(this.blank);
            this.length -= this.blank.length;
        }
        else if (this.length > 0) {
            this.push(this.blank.slice(0, this.length));
            this.length = 0;
        }
        else {
            this.push(null);
        }
    }
}
exports.ZeroStream = ZeroStream;
function streamToBuffer(stream) {
    const chunks = [];
    return new Promise((resolve, reject) => {
        stream.on('data', (buf) => {
            chunks.push(buf);
        });
        stream.on('end', () => {
            resolve(Buffer.concat(chunks));
        });
        stream.on('error', reject);
    });
}
exports.streamToBuffer = streamToBuffer;
//# sourceMappingURL=utils.js.map