/*************************************************************************
 *    Copyright (C) 2008 Christian Kuka <ckuka@madkooky.de>
 *
 *    This file is part of libpqstego.
 *
 *    Libpqstego is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    Libpqstego is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 *************************************************************************/

#ifndef _PQ_H
#define	_PQ_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <stdlib.h>
#include <stdint.h>

#define ALLOC(t) (t*) malloc(sizeof(t))
#define ALLOCN(t, n) (t*) malloc(sizeof(t) * n)

#define SAFE_DELETE(p) \
    if (p) { \
        free(p); \
        (p) = NULL; \
    }

#define FAIL(e) pq_errno = e;  \
  return EXIT_FAILURE;

    #define PQ_E_UNKNOWN "Unknown error."

    enum PQ_ERROR_CODE {
        PQ_E_INSUFFHEADERCAP = 300,
        PQ_E_INSUFFBODYCAP,
        PQ_E_MSGTOOLONG,
        PQ_E_MALLOC,
        PQ_E_LTPROCESS,
        PQ_E_GAUSS,

        PQ_E_LAST
    };
    extern const char *PQ_ERROR_MSGS[];
    extern enum PQ_ERROR_CODE pq_errno;

    inline const uint8_t *pq_strerror(const enum PQ_ERROR_CODE errno) {
        return (errno >= 300 && errno < PQ_E_LAST) ? PQ_ERROR_MSGS[errno - 300] : PQ_E_UNKNOWN;
    }
    /**
     * Data structure for a jpeg quantization table with 8x8 integers.
     *
     */
    typedef struct {
        uint16_t values[64];
    } pq_quant_t;

    /**
     * Data structure for a single 8x8 Block of JPEG coefficients
     *
     */
    typedef struct {
        int16_t values[64];
    } pq_block_t;

    /**
     * Data structure for a jpeg component consisting of a quantisation table
     * and a number of blocks
     *
     */
    typedef struct {
        pq_quant_t *quant;
        pq_block_t *block;
        uint32_t blocks;
    } pq_component_t;

    /**
     * Data structure for a jpeg image with with a number
     * of jpeg_matrices and a x- and y-size.
     */
    typedef struct {
        /** Number of components (1 = gray scale, 3 = color) */
        uint8_t components;

        /** Components tables */
        pq_component_t *component;

        /** Width of the image in blocks (X-axis). */
        uint32_t size_x;

        /** Height of the image in blocks (Y-axis). */
        uint32_t size_y;

    } pq_data_t;

    typedef struct {
        uint8_t* password;
        uint32_t pwlen;
        uint32_t quality;
        uint32_t header_size;
    } pq_parameter_t;

    static const uint16_t _pq_luminance_quant_tbl[64] = {
        16, 11, 10, 16, 24, 40, 51, 61,
        12, 12, 14, 19, 26, 58, 60, 55,
        14, 13, 16, 24, 40, 57, 69, 56,
        14, 17, 22, 29, 51, 87, 80, 62,
        18, 22, 37, 56, 68, 109, 103, 77,
        24, 35, 55, 64, 81, 104, 113, 92,
        49, 64, 78, 87, 103, 121, 120, 101,
        72, 92, 95, 98, 112, 100, 103, 99
    };
    static const uint16_t _pq_chrominance_quant_tbl[64] = {
        17, 18, 24, 47, 99, 99, 99, 99,
        18, 21, 26, 66, 99, 99, 99, 99,
        24, 26, 56, 99, 99, 99, 99, 99,
        47, 66, 99, 99, 99, 99, 99, 99,
        99, 99, 99, 99, 99, 99, 99, 99,
        99, 99, 99, 99, 99, 99, 99, 99,
        99, 99, 99, 99, 99, 99, 99, 99,
        99, 99, 99, 99, 99, 99, 99, 99
    };

    uint32_t pq_embed(const pq_data_t *src_data, pq_data_t *stego_data, uint8_t *message, uint32_t msglen, const pq_parameter_t *param);

    uint32_t pq_extract(const pq_data_t *stego_data, uint8_t **message, uint32_t *msglen, const pq_parameter_t *param);

    int32_t pq_get_message_length(const pq_data_t *stego_data, const pq_parameter_t *para);

    int32_t pq_check_capacity(const pq_data_t *src_data, const pq_parameter_t *param, uint32_t *capacity);



#ifdef	__cplusplus
}
#endif

#endif	/* _PQ_H */

