/*
			(c) Copyright 1998-2000 - Tord Jansson
			======================================

		This file is part of the BladeEnc MP3 Encoder, based on
		ISO's reference code for MPEG Layer 3 compression, and might
		contain smaller or larger sections that are directly taken
		from ISO's reference code.

		All changes to the ISO reference code herein are either
		copyrighted by Tord Jansson (tord.jansson@swipnet.se)
		or sublicensed to Tord Jansson by a third party.

	BladeEnc is free software; you can redistribute this file
	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.



	------------    Changes    ------------

	2000-12-04  Andre Piotrowski

	-	reformatted, slightly optimized
	-	bug fix: original dist10 bug - would never work with non-square huffman tables
*/

#include <stdlib.h>

#include "system.h"
#include "common.h"
#include "huffman.h"





/* array of all huffcodtable headers    */
/* 0..31 Huffman code table 0..31       */
/* 32,33 count1-tables                  */

struct huffcodetab		ht[HTN];





/* read the huffman encode table */
int						read_huffcodetab (void)
{
	char					command[40], huffdata[40];
	unsigned int			t, i, j, x, y;
	unsigned int			xl, yl, bits, len;
	HUFFBITS				code;

	char					*line;
	unsigned int			line_no  = 0;
	unsigned int			table_no = 0;
	struct huffcodetab		*h       = ht;


#define		read_next_line_and_skip_over_comments \
			do { \
				line = aHuffcode[line_no++]; \
			} while (line[0] == '#'  ||  line[0] < ' ')


	read_next_line_and_skip_over_comments;

 	while (1)
	{
		sscanf (line, "%s %s %u %u %u", command, h->tablename, &xl, &yl, &h->linbits);
		if (strcmp (command, ".end") == 0)
		{
			return table_no;
		}
		else if (strcmp (command, ".table") != 0)
		{
			fprintf (stderr, "huffman table %u data corrupted\n", table_no);
			return -1;
		}

		sscanf (h->tablename, "%u", &t);
		if (t != table_no)
		{
			fprintf (stderr, "wrong table number %u\n", table_no);
			return -2;
		}

		h->xlen = xl;
		h->ylen = yl;

		h->linmax = (1 << h->linbits) - 1;

		read_next_line_and_skip_over_comments;

		sscanf (line, "%s %u", command, &t);
		if (strcmp (command, ".reference") == 0)
		{
			h->ref   = t;

			h->table = ht[t].table;
			h->hlen  = ht[t].hlen;

			if (xl != ht[t].xlen  ||  yl != ht[t].ylen)
			{
				fprintf (stderr, "wrong table %u reference\n", table_no);
				return -3;
			};

			read_next_line_and_skip_over_comments;
		}
		else
		{
			h->ref   = -1;

#ifdef NO_ZERO_CALLOC
			h->table = (HUFFBITS *) calloc (xl * yl + 1, sizeof(HUFFBITS));
#else
			h->table = (HUFFBITS *) calloc (xl * yl    , sizeof(HUFFBITS));
#endif

			if (h->table == NULL)
			{
				fprintf (stderr, "unsufficient heap error\n");
				return -4;
			}

#ifdef NO_ZERO_CALLOC
			h->hlen = (unsigned char *) calloc(xl * yl + 1, sizeof(unsigned char));
#else
			h->hlen = (unsigned char *) calloc(xl * yl    , sizeof(unsigned char));
#endif
			if (h->hlen == NULL)
			{
				fprintf (stderr, "unsufficient heap error\n");
				return -4;

			}

			for (i = 0;  i < xl;  i++)
			{
				for (j = 0;  j < yl;  j++)
				{
					if (xl > 1)
						sscanf (line, "%u %u %u %s", &x, &y, &len, huffdata);
					else
						sscanf (line, "%u %u %s", &x, &len, huffdata);

					code = 0;
					bits = 0;

					while (huffdata[bits])
					{
						code <<= 1;
						if (huffdata[bits] == '1')
						{
							code++;
						}
						else if (huffdata[bits] != '0')
						{
							fprintf (stderr, "huffman-table %u bit error\n", table_no);
							return -5;
						}
						bits++;
					}

					if (bits != len)
					{
						fprintf (stderr, "warning: wrong codelen in table %u, pos [%2u][%2u]\n", table_no, i, j);
					}

					/* original dist10 error: 'xl' instead of 'yl' would not work in case of non-square tables */
					h->table[i * yl + j] = code;
					h-> hlen[i * yl + j] = (unsigned char) len;

					read_next_line_and_skip_over_comments;
				}
			}
		}

		table_no++;
		h++;
	}
}



