text: #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_multiskip(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;
  }
  
  t_size tag_processor_id3v2::g_multiskip(const service_ptr_t<file> & p_file,t_filesize & p_size_skipped,abort_callback & p_abort) {
  	t_filesize offset = 0;
  	t_size count = 0;
  	for(;;) {
  		t_filesize delta;
  		g_skip_at(p_file, offset, delta, p_abort);
  		if (delta == 0) break;
  		offset += delta;
  		++count;
  	}
  	p_size_skipped = offset;
  	return count;
  }
  void tag_processor_id3v2::g_skip(const service_ptr_t<file> & p_file,t_uint64 & p_size_skipped,abort_callback & p_abort) {
  	g_skip_at(p_file, 0, p_size_skipped, p_abort);
  }
  
  void tag_processor_id3v2::g_skip_at(const service_ptr_t<file> & p_file,t_filesize p_base, t_filesize & p_size_skipped,abort_callback & p_abort) {
  
  	unsigned char  tmp[10];
  
  	p_file->seek ( p_base, p_abort );
  
  	if (p_file->read( tmp, sizeof(tmp),  p_abort) != sizeof(tmp))  {
  		p_file->seek ( p_base, p_abort );
  		p_size_skipped = 0;
  		return;
  	}
  
  	if ( 
  		0 != memcmp ( tmp, "ID3", 3) ||
  		( tmp[5] & 0x0F ) != 0 || 
  		((tmp[6] | tmp[7] | tmp[8] | tmp[9]) & 0x80) != 0 
  		) {
  		p_file->seek ( p_base, p_abort );
  		p_size_skipped = 0;
  		return;
  	}
  
  	int FooterPresent     = tmp[5] & 0x10;
  
  	t_uint32 ret;
  	ret  = tmp[6] << 21;
  	ret += tmp[7] << 14;
  	ret += tmp[8] <<  7;
  	ret += tmp[9]      ;
  	ret += 10;
  	if ( FooterPresent ) ret += 10;
  
  	try {
  		p_file->seek ( p_base + ret, p_abort );
  	} catch(exception_io_seek_out_of_range) {
  		p_file->seek( p_base, p_abort );
  		p_size_skipped = 0;
  		return;
  	}
  
  	p_size_skipped = ret;
  
  }
  