yahoo/pngjs-image

View on GitHub
lib/png/custom/jsOn.js

Summary

Maintainability
B
6 hrs
Test Coverage
// Copyright 2015 Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

// jsOn - JSON Data

var Compressor = require('../processor/compressor');
var BufferedStream = require('../utils/bufferedStream');

/**
 * @class jsOn
 * @module PNG
 * @submodule PNGChunks
 */
module.exports = {

    /**
     * Gets the sequence
     *
     * @method getSequence
     * @return {int}
     */
    getSequence: function () {
        return 600;
    },


    /**
     * Gets the keyword of the JSON data
     *
     * @method getKeyword
     * @return {string}
     */
    getKeyword: function () {
        return this._keyword || '';
    },

    /**
     * Sets the keyword of the JSON data
     *
     * @method setKeyword
     * @param {string} type
     */
    setKeyword: function (type) {
        this._keyword = type;
    },

    /**
     * Gets the data content
     *
     * @method getContent
     * @return {object}
     */
    getContent: function () {
        return this._content || {};
    },

    /**
     * Sets the data content
     *
     * @method setContent
     * @param {object} data
     */
    setContent: function (data) {
        this._content = data;
    },


    /**
     * Parsing of chunk data
     *
     * Phase 1
     *
     * @method parse
     * @param {BufferedStream} stream Data stream
     * @param {int} length Length of chunk data
     * @param {boolean} strict Should parsing be strict?
     * @param {object} options Decoding options
     */
    parse: function (stream, length, strict, options) {

        var i, len, foundIndex = null, buffer, string,
            compressor,
            data,
            compressionMethod;

        // See where the null-character is
        buffer = stream.peekBuffer(length);
        for (i = 0, len = buffer.length; i < len; i++) {
            if (buffer.readUInt8(i) === 0) {
                foundIndex = i;
                break;
            }
        }

        // Found a null-character?
        if (foundIndex === null) {
            throw new Error('Cannot find separator in ' + this.getType() + ' chunk.');
        }

        // Convert keyword from latin1
        buffer = stream.readBuffer(foundIndex);
        string = buffer.toString('utf8');
        this.setKeyword(string);

        // Skip null
        stream.skip(1);

        // Load compression method
        compressionMethod = stream.readUInt8();
        if (compressionMethod !== 0) {
            throw new Error('Unknown compression method for chunk ' + this.getType() + '.');
        }

        // Read the data
        data = stream.readBuffer(length - foundIndex - 2);

        // Decompress
        compressor = new Compressor(options);
        data = compressor.decode(data);

        // Convert buffer into string
        this.setContent(JSON.parse(data.toString('utf8')));
    },

    /**
     * Gathers chunk-data from decoded chunks
     *
     * Phase 5
     *
     * @static
     * @method decodeData
     * @param {object} data Data-object that will be used to export values
     * @param {boolean} strict Should parsing be strict?
     * @param {object} options Decoding options
     */
    decodeData: function (data, strict, options) {

        var chunks = this.getChunksByType(this.getType());

        if (!chunks) {
            return ;
        }

        data.JSON = [];
        chunks.forEach(function (chunk) {

            data.JSON.push({
                keyword: chunk.getKeyword(),
                content: chunk.getContent()
            });
        });
    },


    /**
     * Returns a list of chunks to be added to the data-stream
     *
     * Phase 1
     *
     * @static
     * @method encodeData
     * @param {Buffer} image Image data
     * @param {object} options Encoding options
     * @return {Chunk[]} List of chunks to encode
     */
    encodeData: function (image, options) {

        if (options.JSON) {

            var result = [],
                type = this.getType(),
                chunks = this.getChunks();

            options.JSON.forEach(function (entry) {

                var chunk = this.createChunk(type, chunks);

                chunk.setKeyword(entry.keyword);
                chunk.setContent(entry.content);

                result.push(chunk);

            }.bind(this));

            return result;
        } else {
            return [];
        }
    },

    /**
     * Composing of chunk data
     *
     * Phase 4
     *
     * @method compose
     * @param {BufferedStream} stream Data stream
     * @param {object} options Encoding options
     */
    compose: function (stream, options) {

        var compressor,
            dataStr,
            data,
            string,
            buffer;

        dataStr = JSON.stringify(this.getContent() || {});

        // Compress the data
        compressor = new Compressor(options);
        data = compressor.encode(new Buffer(dataStr, 'utf8'));

        // Write title to stream
        string = this.getKeyword();
        buffer = new Buffer(string, 'utf8');
        stream.writeBuffer(buffer);

        // Write null-character
        stream.writeUInt8(0);

        // Write compression method - only 0 supported
        stream.writeUInt8(0);

        // Write the rest of the data
        stream.writeBuffer(data);
    }
};