// -*- tab-width:4 -*-
// see TR-B14 4-296 (p.318)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "eit.h"

char		*subtitle_cnv_str[] = {
	NULL
};
static void timecmp(int *,int *,int *,
					int, int, int);
void append_desc(EIT_CONTROL* eittop, int service_id, int event_id, EEVTDitem* eevtitem);

int parseEIThead(unsigned char *data, EIThead *h) {
	int boff = 0;

	memset(h, 0, sizeof(EIThead));

	h->table_id = getBit(data, &boff, 8);
	h->section_syntax_indicator = getBit(data, &boff, 1);
	h->reserved_future_use = getBit(data, &boff, 1);
	h->reserved1 = getBit(data, &boff, 2);
	h->section_length =getBit(data, &boff,12);
	h->service_id = getBit(data, &boff, 16);
	h->reserved2 = getBit(data, &boff, 2);
	h->version_number = getBit(data, &boff, 5);
	h->current_next_indicator = getBit(data, &boff, 1);
	h->section_number = getBit(data, &boff, 8);
	h->last_section_number = getBit(data, &boff, 8);
	h->transport_stream_id = getBit(data, &boff, 16);
	h->original_network_id = getBit(data, &boff, 16);
	h->segment_last_section_number = getBit(data, &boff, 8);
	h->last_table_id = getBit(data, &boff, 8);
  
	return 14;
}

int parseEITbody(unsigned char *data, EITbody *b)
{
	int boff = 0;
	int tnum;
	char buf[4];

	memset(b, 0, sizeof(EITbody));

	b->event_id = getBit(data, &boff, 16);

	memcpy(b->start_time, data + boff / 8, 5);
	/* b->start_time = getBit(data, &boff, 40); */
	boff += 40;
	memcpy(b->duration, data + boff / 8, 3);
	/* b->duration = getBit(data, &boff, 24); */
	boff += 24;
	b->running_status = getBit(data, &boff, 3);
	b->free_CA_mode = getBit(data, &boff, 1);
	b->descriptors_loop_length = getBit(data, &boff, 12);

	/* 日付変換 */
	tnum = (b->start_time[0] & 0xFF) << 8 | (b->start_time[1] & 0xFF);
  
	b->yy = (tnum - 15078.2) / 365.25;
	b->mm = ((tnum - 14956.1) - (int)(b->yy * 365.25)) / 30.6001;
	b->dd = (tnum - 14956) - (int)(b->yy * 365.25) - (int)(b->mm * 30.6001);

	if(b->dd == 0) {
		printf("aa");
	}

	if(b->mm == 14 || b->mm == 15) {
		b->yy += 1;
		b->mm = b->mm - 1 - (1 * 12);
	} else {
		b->mm = b->mm - 1;
	}

	b->yy += 1900;
  
	memset(buf, '\0', sizeof(buf));
	sprintf(buf, "%x", b->start_time[2]);
	b->hh = atoi(buf);
	memset(buf, '\0', sizeof(buf));
	sprintf(buf, "%x", b->start_time[3]);
	b->hm = atoi(buf);
	memset(buf, '\0', sizeof(buf));
	sprintf(buf, "%x", b->start_time[4]);
	b->ss = atoi(buf);

	if((b->duration[0] == 0xFF) && (b->duration[1] == 0xFF) && (b->duration[2] == 0xFF)){
		b->dhh = b->dhm = b->dss = 0;
	}else{
		memset(buf, '\0', sizeof(buf));
		sprintf(buf, "%x", b->duration[0]);
		b->dhh = atoi(buf);
		memset(buf, '\0', sizeof(buf));
		sprintf(buf, "%x", b->duration[1]);
		b->dhm = atoi(buf);
		memset(buf, '\0', sizeof(buf));
		sprintf(buf, "%x", b->duration[2]);
		b->dss = atoi(buf);
	}
	return 12;
}

int parseSEVTdesc(unsigned char *data, SEVTdesc *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(SEVTdesc));

	desc->descriptor_tag = getBit(data, &boff, 8);
	if((desc->descriptor_tag & 0xFF) != 0x4D) {
		return -1;
	}
	desc->descriptor_length = getBit(data, &boff, 8);
	memcpy(desc->ISO_639_language_code, data + boff / 8, 3);
	/* desc->ISO_639_language_code = getBit(data, &boff, 24); */
	boff += 24;
	desc->event_name_length = getBit(data, &boff, 8);
	getStr(desc->event_name, data, &boff, desc->event_name_length);
	desc->text_length = getBit(data, &boff, 8);
	getStr(desc->text, data, &boff, desc->text_length);

	return desc->descriptor_length + 2;
}

int parseContentDesc(unsigned char *data, ContentDesc *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(ContentDesc));

	desc->descriptor_tag = getBit(data, &boff, 8);
	if((desc->descriptor_tag & 0xFF) != 0x54) {
		return -1;
	}
	desc->descriptor_length = getBit(data, &boff, 8);
	//memcpy(desc->content, data+(boff/8), desc->descriptor_length);
	// FIXME: 1つ目のコンテント記述子のみパース
	desc->content_nibble_level_1 = getBit(data, &boff, 4);
	desc->content_nibble_level_2 = getBit(data, &boff, 4);
	desc->user_nibble_1 = getBit(data, &boff, 4);
	desc->user_nibble_2 = getBit(data, &boff, 4);
	return desc->descriptor_length + 2;
}

int parseSeriesDesc(unsigned char *data, SeriesDesc *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(SeriesDesc));

	desc->descriptor_tag = getBit(data, &boff, 8);
	if((desc->descriptor_tag & 0xFF) != 0xD5) {
		return -1;
	}
	desc->descriptor_length = getBit(data, &boff, 8);
	desc->series_id = getBit(data, &boff, 16);
	desc->repeat_label = getBit(data, &boff, 4);
	desc->program_pattern = getBit(data, &boff, 3);
	desc->expire_date_valid_flag = getBit(data, &boff, 1);

	desc->expire_date = getBit(data, &boff, 16);
	//memcpy(desc->expire_date, data + boff / 8, 2);
	//boff += 16;

	desc->episode_number = getBit(data, &boff, 12);
	desc->last_episode_number = getBit(data, &boff, 12);

	getStr(desc->series_name_char, data, &boff, desc->descriptor_length - 8);
	return desc->descriptor_length + 2;
}

int parseComponentDesc(unsigned char *data, ComponentDesc *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(ComponentDesc));

	desc->descriptor_tag = getBit(data, &boff, 8);
	if((desc->descriptor_tag & 0xFF) != 0x50) {
		return -1;
	}
	desc->descriptor_length = getBit(data, &boff, 8);
	desc->reserved_future_use = getBit(data, &boff, 4);
	desc->stream_content = getBit(data, &boff, 4);
	desc->component_type = getBit(data, &boff, 8);
	desc->component_tag = getBit(data, &boff, 8);
	memcpy(desc->ISO_639_language_code, data + boff / 8, 3);
	boff += 24;
	getStr(desc->text_char, data, &boff, desc->descriptor_length - 6);
	return desc->descriptor_length + 2;
}

int parseAudioComponentDesc(unsigned char *data, AudioComponentDesc *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(AudioComponentDesc));

	desc->descriptor_tag = getBit(data, &boff, 8);
	if((desc->descriptor_tag & 0xFF) != 0xC4) {
		return -1;
	}
	desc->descriptor_length = getBit(data, &boff, 8);
	desc->reserved_future_use_1 = getBit(data, &boff, 4);
	desc->stream_content = getBit(data, &boff, 4);
	desc->component_type = getBit(data, &boff, 8);
	desc->component_tag = getBit(data, &boff, 8);
	desc->stream_type = getBit(data, &boff, 8);
	desc->simulcast_group_tag = getBit(data, &boff, 8);
	desc->ES_multi_lingual_flag = getBit(data, &boff, 1);
	desc->main_component_flag = getBit(data, &boff, 1);
	desc->quality_indicator = getBit(data, &boff, 2);
	desc->sampling_rate = getBit(data, &boff, 3);
	desc->reserved_future_use_2 = getBit(data, &boff, 1);
	memcpy(desc->ISO_639_language_code_1, data + boff / 8, 3);
	boff += 24;
	memcpy(desc->ISO_639_language_code_2, data + boff / 8, 3);
	boff += 24;
	getStr(desc->text_char, data, &boff, desc->descriptor_length - desc->ES_multi_lingual_flag ? 12 : 9);
	return desc->descriptor_length + 2;
}

char* parseComponentDescType(int componentDescType) {
	static char str[MAXSECLEN];
	memset(str, '\0', sizeof(str));
	char *strpart;

	switch (componentDescType & 0xF0) {
	case 0x00 :
		strpart = "映像480i ";
		break;
	case 0x90 :
		strpart = "映像2160p ";
		break;
	case 0xA0 :
		strpart = "映像480p ";
		break;
	case 0xB0 :
		strpart = "映像1080i ";
		break;
	case 0xC0 :
		strpart = "映像720p ";
		break;
	case 0xD0 :
		strpart = "映像240p ";
		break;
	case 0xE0 :
		strpart = "映像1080p ";
		break;
	default :
		strpart = "映像不明 ";
		break;
	}
	strcat(str, strpart);

	switch (componentDescType & 0x0F) {
	case 0x01 :
		strpart = "アスペクト比4:3";
		break;
	case 0x02 :
		strpart = "アスペクト比16:9 パンベクトルあり";
		break;
	case 0x03 :
		strpart = "アスペクト比16:9 パンベクトルなし";
		break;
	case 0x04 :
		strpart = "アスペクト比 > 16:9";
		break;
	default :
		strpart = "アスペクト比不明";
		break;
	}
	strcat(str, strpart);

	return str;
}

char* parseAudioComponentDescType(int AudiocomponentDescType) {
	static char str[MAXSECLEN];
	memset(str, '\0', sizeof(str));
	char *strpart;

	switch (AudiocomponentDescType) {
	case 0x01 :
		strpart = "音声1/0モード(シングルモノ)";
		break;
	case 0x02 :
		strpart = "音声1/0+1/0モード(デュアルモノ)";
		break;
	case 0x03 :
		strpart = "音声2/0モード(ステレオ)";
		break;
	case 0x04 :
		strpart = "音声2/1モード";
		break;
	case 0x05 :
		strpart = "音声3/0モード";
		break;
	case 0x06 :
		strpart = "音声2/2モード";
		break;
	case 0x07 :
		strpart = "音声3/1モード";
		break;
	case 0x08 :
		strpart = "音声3/2モード";
		break;
	case 0x09 :
		strpart = "音声3/2+LFEモード(3/2.1モード)";
		break;
	case 0x0A :
		strpart = "音声3/3.1モード";
		break;
	case 0x0B :
		strpart = "音声2/0/0-2/0/2-0.1モード";
		break;
	case 0x0C :
		strpart = "音声5/2.1モード";
		break;
	case 0x0D :
		strpart = "音声3/2/2.1モード";
		break;
	case 0x0E :
		strpart = "音声2/0/0-3/0/2-0.1モード";
		break;
	case 0x0F :
		strpart = "音声0/2/0-3/0/2-0.1モード";
		break;
	case 0x10 :
		strpart = "音声2/0/0-3/2/3-0.2モード";
		break;
	case 0x11 :
		strpart = "音声3/3/3-5/2/3-3/0/0.2モード";
		break;
	case 0x40 :
		strpart = "音声視覚障害者用解説";
		break;
	case 0x41 :
		strpart = "音声聴覚障害者用";
		break;
	default :
		strpart = "音声不明";
		break;
	}
	strcat(str, strpart);

	return str;
}

int parseEEVTDhead(unsigned char *data, EEVTDhead *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(EEVTDhead));

	desc->descriptor_tag = getBit(data, &boff, 8);
	if((desc->descriptor_tag & 0xFF) != 0x4E) {
		return -1;
	}
	desc->descriptor_length = getBit(data, &boff, 8);
	desc->descriptor_number = getBit(data, &boff, 4);
	desc->last_descriptor_number = getBit(data, &boff, 4);
	memcpy(desc->ISO_639_language_code, data + boff / 8, 3);
	/* desc->ISO_639_language_code = getBit(data, &boff, 24); */
	boff += 24;

	desc->length_of_items = getBit(data, &boff, 8);

	return 7;
}

int parseEEVTDitem(unsigned char *data, EEVTDitem *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(EEVTDitem));

	desc->item_description_length = getBit(data, &boff, 8);
	memset(desc->item_description, 0, MAXSECLEN);
	getStr(desc->item_description, data, &boff, desc->item_description_length);

	desc->item_length = getBit(data, &boff, 8);
	memset(desc->item, 0, MAXSECLEN);
	memcpy(desc->item, data + (boff / 8), desc->item_length);
	/* getStr(desc->item, data, &boff, desc->item_length); */

	return desc->item_description_length + desc->item_length + 2;
}

int parseEEVTDtail(unsigned char *data, EEVTDtail *desc) {
	int boff = 0;
  
	memset(desc, 0, sizeof(EEVTDtail));

	desc->text_length = getBit(data, &boff, 8);
	memset(desc->text, 0, MAXSECLEN);
	getStr(desc->text, data, &boff, desc->text_length);

	return desc->text_length + 1;
}

int checkEEVTDitem(EEVTDitem *save, EEVTDitem *new, int descriptor_number) {

	EEVTDitem swap;
	int boff = 0;

	if(new == NULL) {
		if(save->item_length != 0) {
			swap = *save;
			memset(save->item, 0, MAXSECLEN);
			getStr(save->item, (unsigned char*)swap.item, &boff, swap.item_length);
			return 1;
		} else {
			return 0;
		}
	}

	if(new->item_description_length == 0) {
		/* 続き 保存 */
		memcpy(save->item + save->item_length, new->item, new->item_length);
		save->item_length += new->item_length;
		return 0;
	} else {
		/* ブレーク。saveを印刷対象にする。saveをクリア? */
		if(save->item_length != 0) {
			/* 退避済みがあり */
			swap = *save;
			memset(save->item, 0, MAXSECLEN);
			getStr(save->item, (unsigned char*)swap.item, &boff, swap.item_length);

			// swap save new -> swap save new
			//         b   c -> ( c)    c   b
			swap = *new;
			*new = *save;
			*save = swap;
			save->descriptor_number = descriptor_number;
			return 1;
		} else {
			*save = *new;
			save->descriptor_number = descriptor_number;
			return 0;
		}
	}
}
EIT_CONTROL	*searcheit(EIT_CONTROL *top, int servid, int eventid)
{
	EIT_CONTROL	*cur ;
	cur = top ;

	while(cur != NULL){
		if((cur->event_id == eventid) && (cur->servid == servid)){
			return cur ;
		}

		cur = cur->next ;
	}
	return NULL ;
}
char	*strstr_eucjp(const char *str, const char *search)
{
	char *pos ;
	pos = (char *)str ;

	while (*pos != '\0') {
		if (*pos == *search) {
			if (strncmp(pos, search, strlen(search)) == 0) {
				return pos ;
			}
		}
		if ((unsigned char)*pos == 0x8Fu) {
			pos += 3 ;
		} else if ((unsigned char)*pos >= 0x80u) {
			pos += 2 ;
		} else {
			pos += 1 ;
		}
	}

	return NULL ;
}
void	conv_title_subtitle(EIT_CONTROL *eitptr)
{
	int		lp = 0 ;
//	size_t	addsize ;
	char	*ptr ;
	char	*ptr2 ;
	char	*newsubtitle ;

	for(lp = 0 ; subtitle_cnv_str[lp] != NULL ; lp++){
		ptr = strstr(eitptr->title, subtitle_cnv_str[lp]);
		if(ptr == NULL){
			continue ;
		}
		// タイトルがなくならないように
		if(ptr == eitptr->title){
			continue ;
		}
		/*
		ptr2 = ptr ;
		for( ; (unsigned char)*ptr2 == 0x20u ; ptr2++ );
		for( ; (unsigned char)*ptr2 == 0xA1u && (unsigned char)*(ptr2+1) == 0xA1u ; ptr2 += 2);
		for( ; (unsigned char)*ptr2 == 0x20u ; ptr2++ );
		newsubtitle = calloc(1, ((strlen(ptr2) + 2) + (strlen(eitptr->subtitle) + 1)));
		memcpy(newsubtitle, ptr2, strlen(ptr2));
//		*(newsubtitle+strlen(ptr)) = ' ';
		strcat(newsubtitle, "▽");
		*/
		newsubtitle = calloc(1, ((strlen(ptr) + 1) + (strlen(eitptr->subtitle) + 1)));
		memcpy(newsubtitle, ptr, strlen(ptr));
		newsubtitle[strlen(ptr)] = ' ';

		*ptr = '\0';
		strcat(newsubtitle, eitptr->subtitle);
		free(eitptr->subtitle);
		eitptr->subtitle = newsubtitle ;
		return ;
	}
}
void	enqueue(EIT_CONTROL *top, EIT_CONTROL *eitptr)
{
	EIT_CONTROL	*cur ;
	cur = top ;
	int		rc ;

	if(top->next == NULL){
		top->next = eitptr ;
		eitptr->prev = top ;
		return ;
	}
	cur = top->next ;
	while(cur != NULL){
		rc = memcmp(&cur->yy, &eitptr->yy, (sizeof(int) * 3));
		if(rc == 0){
			rc = memcmp(&cur->hh, &eitptr->hh, (sizeof(int) * 3));
			if(rc == 0){
				free(eitptr->title);
				free(eitptr->subtitle);
				free(eitptr);
				return ;
			}
			if(rc > 0){
				if(cur->prev != 0){
					cur->prev->next = eitptr ;
					eitptr->prev = cur->prev ;
				}
				cur->prev = eitptr ;
				eitptr->next = cur ;
				conv_title_subtitle(eitptr);
				return ;
			}
		}
		if(rc > 0){
			if(cur->prev != 0){
				cur->prev->next = eitptr ;
				eitptr->prev = cur->prev ;
			}
			cur->prev = eitptr ;
			eitptr->next = cur ;
			conv_title_subtitle(eitptr);
			return ;
		}
		if(cur->next == NULL){
			cur->next = eitptr ;
			eitptr->prev = cur ;
			conv_title_subtitle(eitptr);
			return ;
		}
		cur = cur->next ;
	}
	return ;

}

void dumpEIT(unsigned char *ptr, int serv_id, int original_network_id, int transport_stream_id, EIT_CONTROL *eittop)
{

	EIThead  eith;
	EITbody  eitb;
	SEVTdesc sevtd;

	EEVTDhead eevthead;
	EEVTDitem eevtitem;
	EEVTDtail eevttail;

	EEVTDitem save_eevtitem;

	EIT_CONTROL	*cur ;
	EIT_CONTROL	*curtmp ;

	int len = 0;
	int loop_len = 0;
	int loop_blen = 0;
	int loop_elen = 0;

	int ehh, emm, ess;

	/* EIT */
	len = parseEIThead(ptr, &eith); 

	ptr += len;
	loop_len = eith.section_length - (len - 3 + 4); // 3は共通ヘッダ長 4はCRC
	while(loop_len > 0) {
		/* 連続する拡張イベントは、漢字コードが泣き別れして
		   分割されるようだ。連続かどうかは、item_description_lengthが
		   設定されているかどうかで判断できるようだ。 */
		memset(&save_eevtitem, 0, sizeof(EEVTDitem));

		len = parseEITbody(ptr, &eitb);
		ptr += len;
		loop_len -= len;

		/* printf("evtid:%d\n", eitb.event_id); */

		loop_blen = eitb.descriptors_loop_length;
		loop_len -= loop_blen;

		while(loop_blen > 0) {

			/*yukikaze-test*/
			//printf("desc_tag");
			//int itt=getBit(*ptr,0,8);
			//printf("%x",itt);

			len = parseSEVTdesc(ptr, &sevtd);
			if(len > 0) {

				/*
				  if(eith.service_id == 19304 && 
				  eitb.event_id == 46564) {
				  printf("aa");
				  }
				*/

				ehh = eitb.hh;
				emm = eitb.hm;
				ess = eitb.ss;
				if(eith.service_id != serv_id){
					ptr += len;
					loop_blen -= len;
					continue ;
				}

				timecmp(&ehh, &emm, &ess,
						eitb.dhh, eitb.dhm, eitb.dss);
				cur = searcheit(eittop, eith.service_id, eitb.event_id);
				if(cur == NULL){
					curtmp = NULL;
					cur = calloc(1, sizeof(EIT_CONTROL));
				}
				else {
					curtmp = cur;
				}
				cur->event_id = eitb.event_id ;
				cur->servid = eith.service_id ;
				cur->title = calloc(1, (strlen(sevtd.event_name) + 1));

				memcpy(cur->title, sevtd.event_name, strlen(sevtd.event_name));
				cur->subtitle = calloc(1, (strlen(sevtd.text) + 1));
				memcpy(cur->subtitle, sevtd.text, strlen(sevtd.text));
				cur->yy = eitb.yy;
				cur->mm = eitb.mm;
				cur->dd = eitb.dd;
				cur->hh = eitb.hh;
				cur->hm = eitb.hm;
				cur->ss = eitb.ss;
				cur->ehh = eitb.dhh;
				cur->emm = eitb.dhm;
				cur->ess = eitb.dss ;
				cur->table_id = eith.table_id ;
				if ( !curtmp ) enqueue(eittop, cur);
			} else {
				len = parseEEVTDhead(ptr, &eevthead);

				/*
				if(eith.service_id == 19304 && 
				eitb.event_id == 46564) {
				printf("aa");
				}
				*/

				if(len > 0) {
					ptr += len;
					loop_blen -= len;

					loop_elen = eevthead.length_of_items;
					loop_len -= loop_elen;
					while(loop_elen > 0) {
						len = parseEEVTDitem(ptr, &eevtitem);

						ptr += len;
						loop_elen -= len;
						loop_blen -= len;

						if(checkEEVTDitem(&save_eevtitem, &eevtitem, 
							eevthead.descriptor_number)) {

							{
								if (eevtitem.descriptor_number>0){
									//printf("descriptor_num %d\n",eevtitem.descriptor_number);
								}
								/* long format */
								//printf("descriptor_num %d\n",eevtitem.descriptor_number);
#if 0
								printf("EEVT,%d,%d,%d,%s,%s\n",
									eith.service_id,
									eitb.event_id,
									eevtitem.descriptor_number, // 退避項目
									eevtitem.item_description,
									eevtitem.item);
#endif
							}
							append_desc(eittop, eith.service_id, eitb.event_id, &eevtitem);

						}
					}

					len = parseEEVTDtail(ptr, &eevttail);
#if 0
					{ /* long format */
						printf("EEVTt,%d,%d,%d,%s\n", 
								eith.service_id,
								eitb.event_id,
								eevthead.descriptor_number,
								eevttail.text);
					}
#endif
				} else {
					ContentDesc			contentDesc;
					SeriesDesc			seriesDesc;
					ComponentDesc		componentDesc;
					AudioComponentDesc	audioComponentDesc;

					if((eith.original_network_id == original_network_id) && (eith.transport_stream_id == transport_stream_id)){
						cur = searcheit(eittop, eith.service_id, eitb.event_id);
					}
					else {
						cur = NULL;
					}

					switch (*ptr) {
					case 0x54 :
						len = parseContentDesc(ptr, &contentDesc);
						if (len > 0) {
							if(cur != NULL){
								cur->content_type = (unsigned char)contentDesc.content_nibble_level_1;
							}
						}
						break;
					case 0xD5 :
						len = parseSeriesDesc(ptr, &seriesDesc);
						if (len > 0) {
							#if 0
								printf("Series,%d,%d,series=%d,repeat=%01x,pattern=%d,expire_valid=%d,expire=%04x,epinum=%d,lastepinum=%d,%s\n",
									eith.service_id,
									eitb.event_id,
									seriesDesc.series_id,
									seriesDesc.repeat_label,
									seriesDesc.program_pattern,
									seriesDesc.expire_date_valid_flag,
									seriesDesc.expire_date,
									seriesDesc.episode_number,
									seriesDesc.last_episode_number,
									seriesDesc.series_name_char);
							#endif
						}
						break;
					case 0x50 :
						len = parseComponentDesc(ptr, &componentDesc);
						if (len > 0) {
							if(cur != NULL){
								cur->video_type = componentDesc.component_type;
							}
							#if 0
							printf("Component,%d %d %s\n",
								componentDesc.stream_content, 
								componentDesc.component_type, 
								parseComponentDescType(componentDesc.component_type));
							#endif
						}
						break;
					case 0xC4 :
						len = parseAudioComponentDesc(ptr, &audioComponentDesc);
						if (len > 0) {
							if(cur != NULL){
								cur->audio_type = audioComponentDesc.component_type;
								cur->multi_type = audioComponentDesc.ES_multi_lingual_flag;
							}
							#if 0
							printf("AudioComponent,%d %d %d %s\n",
								audioComponentDesc.component_type, 
								audioComponentDesc.ES_multi_lingual_flag, 
								audioComponentDesc.sampling_rate, 
								parseAudioComponentDescType(audioComponentDesc.component_type)
								);
							#endif
						}
						break;
					default :
						len = parseOTHERdesc(ptr);
					}
				}
			}
			ptr += len;
			loop_blen -= len;
		}
		/* 最後のブレークチェック */

		if(checkEEVTDitem(&save_eevtitem, NULL, 0)) {
#if 0
			{ /* long format */
				fprintf(stdout, "EEVT,%d,%d,%d,%s,%s\n", 
						eith.service_id,
						eitb.event_id,
						save_eevtitem.descriptor_number,
						save_eevtitem.item_description,
						save_eevtitem.item);
			}
#endif
			append_desc(eittop, eith.service_id, eitb.event_id, &save_eevtitem);
		}
	}

	return;
}

void append_desc(EIT_CONTROL* eittop, int service_id, int event_id, EEVTDitem* eevtitem) {
	EIT_CONTROL *cur;
	int str_alen = 0;

	cur = searcheit(eittop, service_id, event_id);
	if (cur == NULL) {
		return;
	}

	if ( cur->desc ) {
		str_alen = strlen( cur->desc );
	}
	else {
		str_alen = 0;
	}
	//eevtitem->item_description_length = strlen(eevtitem->item_description);
	//eevtitem->item_length = strlen(eevtitem->item);
	cur->desc = realloc(cur->desc, str_alen + eevtitem->item_description_length + eevtitem->item_length + 1000);
	if ( !str_alen ) *cur->desc = '\0';

	if ( eevtitem->item_description_length && !strstr(cur->desc, eevtitem->item_description) ) {
		strcat(cur->desc + str_alen, eevtitem->item_description);
		strcat(cur->desc, "\t");
	}

	if ( eevtitem->item_length && !strstr(cur->desc, eevtitem->item) ) {
		strcat(cur->desc + str_alen, eevtitem->item);
	//printf("%s\n",eevtitem->item);
		strcat(cur->desc, "\\n");
	}
}

void timecmp(int *thh, int *tmm, int *tss,
			 int dhh, int dmm, int dss) {

	int ama;

	*tss += dss;
	ama = *tss % 60;
	*tmm += (*tss / 60);
	*tss = ama;

	*tmm += dmm;
	ama   = *tmm % 60;
	*thh += (*tmm / 60);
	*tmm  = ama;

	*thh += dhh;

}
