/*****************************************************************************
 * ts_arib.c : TS demux ARIB specific handling
 *****************************************************************************
 * Copyright (C) 2017 - VideoLAN Authors
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_demux.h>

#include "timestamps.h"
#include "ts_pid.h"
#include "ts.h"

#include "ts_arib.h"

/*
 * ARIB TR-B21
 * Logo PNG is 8 bit indexed dans the palette is missing,
 * provided as a CLUT. We need to reinject the CLUT as a
 * split palette + transparency (as PNG only allows split alpha table)
*/

/* ARIB TR-B14-1 Appendix 1 */
static const unsigned char CLUT_to_chunks[] = {
    /* size + PLTE */
    0x00, 0x00, 0x01, 0x80, 0x50, 0x4c, 0x54, 0x45,
    /* DATA ARIB TR-B14-1 Appendix 1 */
    0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, /* 0-7 */
    0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,

    0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, /* 8-15 */
    0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,

    0x00, 0x00, 0x55, 0x00, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x55, 0xaa, /* 16-23 */
    0x00, 0x55, 0xff, 0x00, 0xaa, 0x55, 0x00, 0xaa, 0xff, 0x00, 0xff, 0x55,

    0x00, 0xff, 0xaa, 0x55, 0x00, 0x00, 0x55, 0x00, 0x55, 0x55, 0x00, 0xaa, /* 24-31 */
    0x55, 0x00, 0xff, 0x55, 0x55, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xaa,

    0x55, 0x55, 0xff, 0x55, 0xaa, 0x00, 0x55, 0xaa, 0x00, 0x55, 0xaa, 0x55, /* 32-39 */
    0x55, 0xaa, 0xaa, 0x55, 0xaa, 0xff, 0x55, 0xff, 0x00, 0x55, 0xff, 0x55,

    0x55, 0xff, 0xff, 0xaa, 0x00, 0x55, 0xaa, 0x00, 0xff, 0xaa, 0x55, 0x00, /* 40-47 */
    0xaa, 0x55, 0x55, 0xaa, 0x55, 0xaa, 0xaa, 0x55, 0xff, 0xaa, 0xaa, 0x55,

    0xaa, 0xaa, 0xff, 0xaa, 0xff, 0x00, 0xaa, 0xff, 0x55, 0xaa, 0xff, 0xaa, /* 48-55 */
    0xaa, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0x00, 0xaa, 0xff, 0x55, 0x00,

    0xff, 0x55, 0x55, 0xff, 0x55, 0xaa, 0xff, 0x55, 0xff, 0xff, 0xaa, 0x00, /* 56-63 */
    0xff, 0xaa, 0x55, 0xff, 0xaa, 0xaa, 0xff, 0xaa, 0xff, 0xff, 0xff, 0x55,

    0xff, 0xff, 0xaa, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, /* 64-71 */
    0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff,

    0xff, 0xff, 0xff, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0xaa, 0x00, /* 72-79 */
    0x00, 0x00, 0xaa, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,

    0x00, 0x00, 0x55, 0x00, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x55, 0xaa, /* 80-87 */
    0x00, 0x55, 0xff, 0x00, 0xaa, 0x55, 0x00, 0xaa, 0xff, 0x00, 0xff, 0x55,

    0x00, 0xff, 0xaa, 0x55, 0x00, 0x00, 0x55, 0x00, 0x55, 0x55, 0x00, 0xaa, /* 88-95 */
    0x55, 0x00, 0xff, 0x55, 0x55, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xaa,

    0x55, 0x55, 0xff, 0x55, 0xaa, 0x00, 0x55, 0xaa, 0x55, 0x55, 0xaa, 0xaa, /* 96-103 */
    0x55, 0xaa, 0xff, 0x55, 0xff, 0x00, 0x55, 0xff, 0x55, 0x55, 0xff, 0xaa,

    0x55, 0xff, 0xff, 0xaa, 0x00, 0x55, 0xaa, 0x00, 0xff, 0xaa, 0x55, 0x00, /* 104-111 */
    0xaa, 0x55, 0x55, 0xaa, 0x55, 0xaa, 0xaa, 0x55, 0xff, 0xaa, 0xaa, 0x55,

    0xaa, 0xaa, 0xff, 0xaa, 0xff, 0x00, 0xaa, 0xff, 0x55, 0xaa, 0xff, 0xaa, /* 112-119 */
    0xaa, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0x00, 0xaa, 0xff, 0x55, 0x00,

    0xff, 0x55, 0x55, 0xff, 0x55, 0xaa, 0xff, 0x55, 0xff, 0xff, 0xaa, 0x00, /* 120-127 */
    0xff, 0xaa, 0x55, 0xff, 0xaa, 0xaa, 0xff, 0xaa, 0xff, 0xff, 0xff, 0x55,

    /* CRC32 (all data including type, without length and crc) . pngcheck output being the lazy way */
    0x4f, 0xed, 0xfc, 0x8d,

    /* Second Chunk */

    /* size + tRNS */
    0x00, 0x00, 0x00, 0x80, 0x74, 0x52, 0x4e, 0x53,

    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0-63 */
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff,

    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, /* 64-127 */
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80,

    /* CRC32 */
    0xfa, 0xe9, 0x51, 0x40,
};
static const unsigned int CLUT_to_chunks_len = sizeof(CLUT_to_chunks);

bool ts_arib_inject_png_palette( const uint8_t *p_in, size_t i_in, uint8_t **pp_out, size_t *pi_out )
{
    const uint8_t *p_data = p_in;
    const uint8_t *p_idat = NULL;
    size_t i_data = i_in - 8;
    p_data += 8;
    i_data -= 8;

    while( i_data > 11 )
    {
        uint32_t i_len = GetDWBE( p_data );
        if( i_len > 0x7FFFFFFFU || i_len > i_data - 12 )
            break;

        uint32_t i_chunk = VLC_FOURCC(p_data[4], p_data[5], p_data[6], p_data[7]);
        if( i_chunk == VLC_FOURCC('I', 'D', 'A', 'T') )
        {
            p_idat = p_data;
            break;
        }

        p_data += i_len + 12;
        i_data -= i_len + 12;
    }

    if( !p_idat )
        return false;

    {
        uint8_t *p_out = *pp_out = malloc( i_in + CLUT_to_chunks_len );
        if( !p_out )
            return false;
        *pi_out = i_in + CLUT_to_chunks_len;

        const size_t i_head = p_data - p_in;
        memcpy( p_out, p_in, i_head );
        memcpy( &p_out[i_head], CLUT_to_chunks, CLUT_to_chunks_len );
        memcpy( &p_out[i_head + CLUT_to_chunks_len], p_data, i_in - i_head );
    }

    return true;
}


void ts_arib_logo_dr_Delete( ts_arib_logo_dr_t *p_dr )
{
    free( p_dr->p_logo_char );
    free( p_dr );
}

ts_arib_logo_dr_t * ts_arib_logo_dr_Decode( const uint8_t *p_data, size_t i_data )
{
    if( i_data < 2 )
        return NULL;

    ts_arib_logo_dr_t *p_dr = calloc( 1, sizeof(*p_dr) );
    if( unlikely( p_dr == NULL ) )
        return NULL;

    p_dr->i_logo_version = p_data[0];
    switch( p_data[0] )
    {
        case 1:
            if( i_data != 7 )
                break;
            p_dr->i_logo_id = ((p_data[1] & 0x01) << 8) | p_data[2];
            p_dr->i_logo_version = ((p_data[3] & 0x0F) << 8) | p_data[4];
            p_dr->i_download_data_id = (p_data[5] << 8) | p_data[6];
            return p_dr;
        case 2:
            if( i_data != 3 )
                break;
            p_dr->i_logo_id = ((p_data[1] & 0x01) << 8) | p_data[2];
            return p_dr;
        case 3:
            if( i_data <= 2 )
                break;

            p_dr->p_logo_char = malloc( i_data - 1 );
            if( unlikely( p_dr->p_logo_char == NULL ) )
                break;

            p_dr->i_logo_char = i_data - 1;
            memcpy( p_dr->p_logo_char, &p_data[1], p_dr->i_logo_char );
            return p_dr;
        default:
            break;
    }

    ts_arib_logo_dr_Delete( p_dr );
    return NULL;
}
