#include "foobar2000.h"

bool tag_processor_id3v2::g_get(service_ptr_t<tag_processor_id3v2> & p_out)
{
	return service_enum_t<tag_processor_id3v2>().first(p_out);
}

void tag_processor_id3v2::g_remove(const service_ptr_t<file> & p_file,t_uint64 & p_size_removed,abort_callback & p_abort) {
	g_remove_ex(tag_write_callback_dummy(),p_file,p_size_removed,p_abort);
}

void tag_processor_id3v2::g_remove_ex(tag_write_callback & p_callback,const service_ptr_t<file> & p_file,t_uint64 & p_size_removed,abort_callback & p_abort)
{
	p_file->ensure_seekable();

	t_filesize len;
	
	len = p_file->get_size(p_abort);

	if (len == filesize_invalid) throw exception_io_no_length();;
	
	p_file->seek(0,p_abort);
	
	t_uint64 offset;
	g_skip(p_file,offset,p_abort);
	
	if (offset>0 && offset<len)
	{
		len-=offset;
		service_ptr_t<file> temp;
		if (p_callback.open_temp_file(temp,p_abort)) {
			file::g_transfer_object(p_file,temp,len,p_abort);
		} else {
			if (len > 16*1024*1024) filesystem::g_open_temp(temp,p_abort);
			else filesystem::g_open_tempmem(temp,p_abort);
			file::g_transfer_object(p_file,temp,len,p_abort);
			p_file->seek(0,p_abort);
			p_file->set_eof(p_abort);
			temp->seek(0,p_abort);
			file::g_transfer_object(temp,p_file,len,p_abort);
		}
	}
	p_size_removed = offset;
}

void tag_processor_id3v2::g_skip(const service_ptr_t<file> & p_file,t_uint64 & p_size_skipped,abort_callback & p_abort)
{

	unsigned char  tmp[10];

	t_size io_bytes_done;

	p_file->seek ( 0, p_abort );

	io_bytes_done = p_file->read( tmp, sizeof(tmp),  p_abort);
	if (io_bytes_done != sizeof(tmp))  {
		p_file->seek ( 0, p_abort );
		p_size_skipped = 0;
		return;
	}

	if ( 0 != memcmp ( tmp, "ID3", 3) ) {
		p_file->seek ( 0, p_abort );
		p_size_skipped = 0;
		return;
	}

	int Unsynchronisation = tmp[5] & 0x80;
	int ExtHeaderPresent  = tmp[5] & 0x40;
	int ExperimentalFlag  = tmp[5] & 0x20;
	int FooterPresent     = tmp[5] & 0x10;

	if ( tmp[5] & 0x0F ) {
		p_file->seek ( 0, p_abort );
		p_size_skipped = 0;
		return;
	}

	if ( (tmp[6] | tmp[7] | tmp[8] | tmp[9]) & 0x80 ) {
		p_file->seek ( 0, p_abort );
		p_size_skipped = 0;
		return;
	}

	t_uint32 ret;
	ret  = tmp[6] << 21;
	ret += tmp[7] << 14;
	ret += tmp[8] <<  7;
	ret += tmp[9]      ;
	ret += 10;
	if ( FooterPresent ) ret += 10;

	p_file->seek ( ret, p_abort );

	p_size_skipped = ret;

}
