decode.js 1.5 KB
const { Transform } = require('stream');

/**
 * Decodes a Base64 data stream, coming in as a string or Buffer of UTF-8 text, into binary Buffers.
 * @extends Transform
 */
module.exports = class Base64Decode extends Transform {
    /**
     * Create a Base64Decode
     */
    constructor() {
        super({ decodeStrings: false });
        // Any extra chars from the last chunk
        this.extra = '';
    }

    /**
     * Decodes a Base64 data stream, coming in as a string or Buffer of UTF-8 text, into binary Buffers.
     * @param {Buffer|string} chunk
     * @param encoding
     * @param cb
     * @private
     */
    _transform(chunk, encoding, cb) {
        // Convert chunk to a string
        chunk = '' + chunk;

        // Add previous extra and remove any newline characters
        chunk = this.extra + chunk.replace(/(\r\n|\n|\r)/gm, '');

        // 4 characters represent 3 bytes, so we can only decode in groups of 4 chars
        const remaining = chunk.length % 4;

        // Store the extra chars for later
        this.extra = chunk.slice(chunk.length - remaining);
        chunk = chunk.slice(0, chunk.length - remaining);

        // Create the new buffer and push
        const buf = Buffer.from(chunk, 'base64');
        this.push(buf);
        cb();
    }

    /**
     * Emits 1, 2, or 3 extra characters of base64 data.
     * @param cb
     * @private
     */
    _flush(cb) {
        if (this.extra.length) {
            this.push(Buffer.from(this.extra, 'base64'));
        }

        cb();
    }
};