/* GemRB - Infinity Engine Emulator
 * Copyright (C) 2009 The GemRB Project
 *
 * This program 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 2
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *
 */

//code derived from FFMPEG
//using code from get_bits.h, bitstream.c

#include "common.h"

#define INIT_VLC_LE         2
#define INIT_VLC_USE_NEW_STATIC 4 

class VLC
{
public:
	int bits = 0;
	int16_t (*table)[2] = nullptr; ///< code, bits
	int table_size = 0;
	int table_allocated = 0;
public:
	int init_vlc(int nb_bits, int nb_codes,
		const void *bits, int bits_wrap, int bits_size,
		const void *codes, int codes_wrap, int codes_size,
		int flags);
private:
	int alloc_table(int size);
	int build_table(int table_nb_bits, int nb_codes,
		const void *bits, int bits_wrap, int bits_size,
		const void *codes, int codes_wrap, int codes_size,
		uint32_t code_prefix, int n_prefix, int flags);

};

#if defined(__arm__)
#define GET_DATA(v, table, i, wrap, size) \
{\
	const uint8_t *ptr = (const uint8_t *)table + i * wrap;\
	v = 0;\
	switch(size) {\
	default:\
		v |= *((const uint8_t *)ptr+3) << 24;\
		v |= *((const uint8_t *)ptr+2) << 16;\
	case 2:\
		v |= *((const uint8_t *)ptr+1) << 8;\
	case 1:\
		v |= *(const uint8_t *)ptr;\
	}\
}
#else
#define GET_DATA(v, table, i, wrap, size) \
{\
	const uint8_t *ptr = reinterpret_cast<const uint8_t *>(table) + i * wrap;\
	switch(size) {\
	case 1:\
		v = *reinterpret_cast<const uint8_t *>(ptr);\
		break;\
	case 2:\
		v = *reinterpret_cast<const uint16_t *>(ptr);\
		break;\
	default:\
		v = *reinterpret_cast<const uint32_t *>(ptr);\
		break;\
	}\
}
#endif

#define AV_RL32(x)                           \
	((((const uint8_t*)(x))[3] << 24) |  \
	(((const uint8_t*)(x))[2] << 16) |   \
	(((const uint8_t*)(x))[1] <<  8) |   \
	((const uint8_t*)(x))[0]) 

class GetBitContext
{
public:
	const uint8_t* buffer = nullptr;
	const uint8_t* buffer_end = nullptr;
	int index = 0;
	int size_in_bits = 0;
public:
	void debug(const char *prefix) const;
	float get_float();
	void skip_bits(int x) { index+=x; }
	int get_bits_count() const { return index; }
	void get_bits_align32();
	unsigned int get_bits(int x);
	unsigned int peek_bits(int x) const;
	unsigned int get_bits_long(int n);
	void init_get_bits(const uint8_t *b, int bit_size);
	void read_tree(Tree *tree);
private:
	void merge(uint8_t *dst, const uint8_t *src, int size);
};
