示例#1
0
	void run(threaded_process_status & p_status,abort_callback & p_abort) {
		try {
			const t_uint32 decode_flags = input_flag_no_seeking | input_flag_no_looping; // tell the decoders that we won't seek and that we don't want looping on formats that support looping.
			input_helper input;
			audio_hash.set_count(m_items.get_size());
			for(t_size walk = 0; walk < m_items.get_size(); ++walk) {

				p_abort.check(); // in case the input we're working with fails at doing this
				p_status.set_progress(walk, m_items.get_size());
				p_status.set_progress_secondary(0);
				p_status.set_item_path( m_items[walk]->get_path() );
				input.open(NULL, m_items[walk], decode_flags, p_abort);
				
				double length;
				{ // fetch the track length for proper dual progress display;
					file_info_impl info;
					// input.open should have preloaded relevant info, no need to query the input itself again.
					// Regular get_info() may not retrieve freshly loaded info yet at this point (it will start giving the new info when relevant info change callbacks are dispatched); we need to use get_info_async.
					if (m_items[walk]->get_info_async(info)) length = info.get_length();
					else length = 0;
				}

				memset( &ctx, 0, sizeof( sha1_context ) );
				sha1_starts( &ctx );
				audio_chunk_impl_temporary l_chunk;
				
				double decoded = 0;
				while(input.run(l_chunk, p_abort)) { // main decode loop
				    sha1_update(&ctx,(unsigned char*)l_chunk.get_data(),l_chunk.get_data_length());
					//m_peak = l_chunk.get_peak(m_peak);
					if (length > 0) { // don't bother for unknown length tracks
						decoded += l_chunk.get_duration();
						if (decoded > length) decoded = length;
						p_status.set_progress_secondary_float(decoded / length);
					}
					p_abort.check(); // in case the input we're working with fails at doing this
				}
				unsigned char sha1sum[20] ={0};
				sha1_finish(&ctx,sha1sum);
				pfc::string_formatter msg;
			    for(int i = 0; i < 20; i++ )
				{
				 
				  msg <<pfc::format_hex(sha1sum[i]);
				  audio_hash[walk] =msg;
				}
				



			}
		} catch(std::exception const & e) {
			m_failMsg = e.what();
		}
	}
	void writeOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, const void * in,DWORD inBytes, abort_callback & abort) {
		abort.check();
		if (inBytes == 0) return;
		OVERLAPPED ol = {};
		fillOverlapped(ol, myEvent, position);
		ResetEvent(myEvent);
		DWORD bytesWritten;
		SetLastError(NO_ERROR);
		if (WriteFile( handle, in, inBytes, &bytesWritten, &ol)) {
			// succeeded already?
			if (bytesWritten != inBytes) throw exception_io();
			return;
		}
		
		{
			const DWORD code = GetLastError();
			if (code != ERROR_IO_PENDING) exception_io_from_win32(code);
		}
		const HANDLE handles[] = {myEvent, abort.get_abort_event()};
		SetLastError(NO_ERROR);
		DWORD state = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
		if (state == WAIT_OBJECT_0) {
			try {
				WIN32_IO_OP( GetOverlappedResult(handle,&ol,&bytesWritten,TRUE) );
			} catch(...) {
				CancelIo(handle);
				throw;
			}
			if (bytesWritten != inBytes) throw exception_io();
			return;
		}
		CancelIo(handle);
		throw exception_aborted();
	}
示例#3
0
bool input_helper::open_path(file::ptr p_filehint,const char * path,abort_callback & p_abort,bool p_from_redirect,bool p_skip_hints) {
	p_abort.check();

	if (!need_file_reopen(path)) return false;
	m_input.release();

	service_ptr_t<file> l_file = p_filehint;
	process_fullbuffer(l_file,path,m_fullbuffer,p_abort);

	TRACK_CODE("input_entry::g_open_for_decoding",
		input_entry::g_open_for_decoding(m_input,l_file,path,p_abort,p_from_redirect)
		);

	
	if (!p_skip_hints) {
		try {
			static_api_ptr_t<metadb_io>()->hint_reader(m_input.get_ptr(),path,p_abort);
		} catch(exception_io_data) {
			//Don't fail to decode when this barfs, might be barfing when reading info from another subsong than the one we're trying to decode etc.
			m_input.release();
			if (l_file.is_valid()) l_file->reopen(p_abort);
			TRACK_CODE("input_entry::g_open_for_decoding",
				input_entry::g_open_for_decoding(m_input,l_file,path,p_abort,p_from_redirect)
				);
		}
	}

	m_path = path;
	return true;
}
示例#4
0
void input_helper::open(service_ptr_t<file> p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect,bool p_skip_hints) {
	p_abort.check();

	if (m_input.is_empty() || metadb::path_compare(p_location.get_path(),m_path) != 0)
	{
		m_input.release();

		service_ptr_t<file> l_file = p_filehint;
		process_fullbuffer(l_file,p_location.get_path(),m_fullbuffer,p_abort);

		TRACK_CODE("input_entry::g_open_for_decoding",
			input_entry::g_open_for_decoding(m_input,l_file,p_location.get_path(),p_abort,p_from_redirect)
			);

		
		if (!p_skip_hints) {
			try {
				static_api_ptr_t<metadb_io>()->hint_reader(m_input.get_ptr(),p_location.get_path(),p_abort);
			} catch(exception_io_data) {
				//don't fail to decode when this barfs
				m_input.release();
				if (l_file.is_valid()) l_file->reopen(p_abort);
				TRACK_CODE("input_entry::g_open_for_decoding",
					input_entry::g_open_for_decoding(m_input,l_file,p_location.get_path(),p_abort,p_from_redirect)
					);
			}
		}

		m_path = p_location.get_path();
	}

	TRACK_CODE("input_decoder::initialize",m_input->initialize(p_location.get_subsong_index(),p_flags,p_abort));
}
	HANDLE createFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile, abort_callback & abort) {
		abort.check();
		
		return CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);

		// CancelSynchronousIo() doesn't f*****g work. Useless.
#if 0
		pCancelSynchronousIo_t pCancelSynchronousIo = (pCancelSynchronousIo_t) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelSynchronousIo");
		if (pCancelSynchronousIo == NULL) {
#ifdef _DEBUG
			uDebugLog() << "Async CreateFile unavailable - using regular";
#endif
			return CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
		} else {
#ifdef _DEBUG
			uDebugLog() << "Starting async CreateFile...";
			pfc::hires_timer t; t.start();
#endif
			createFileData_t data = {lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile, NULL, 0};
			HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, createFileProc, &data, 0, NULL);
			HANDLE waitHandles[2] = {hThread, abort.get_abort_event()};
			switch(WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE)) {
			case WAIT_OBJECT_0: // succeeded
				break;
			case WAIT_OBJECT_0 + 1: // abort
#ifdef _DEBUG
				uDebugLog() << "Aborting async CreateFile...";
#endif
				pCancelSynchronousIo(hThread);
				WaitForSingleObject(hThread, INFINITE);
				break;
			default:
				uBugCheck();
			}
			CloseHandle(hThread);
			SetLastError(data.dwErrorCode);
#ifdef _DEBUG
			uDebugLog() << "Async CreateFile completed in " << pfc::format_time_ex(t.query(), 6) << ", status: " << (uint32_t) data.dwErrorCode;
#endif
			if (abort.is_aborting()) {
				if (data.hResult != INVALID_HANDLE_VALUE) CloseHandle(data.hResult);
				throw exception_aborted();
			}
			return data.hResult;
		}
#endif
	}
示例#6
0
static void index_tracks_helper(const char * p_path,const service_ptr_t<file> & p_reader,const t_filestats & p_stats,playlist_loader_callback::t_entry_type p_type,playlist_loader_callback::ptr p_callback, abort_callback & p_abort,bool & p_got_input)
{
	TRACK_CALL_TEXT("index_tracks_helper");
	if (p_reader.is_empty() && filesystem::g_is_remote_safe(p_path))
	{
		TRACK_CALL_TEXT("remote");
		metadb_handle_ptr handle;
		p_callback->handle_create(handle,make_playable_location(p_path,0));
		p_got_input = true;
		p_callback->on_entry(handle,p_type,p_stats,true);
	} else {
		TRACK_CALL_TEXT("hintable");
		service_ptr_t<input_info_reader> instance;
		input_entry::g_open_for_info_read(instance,p_reader,p_path,p_abort);

		t_filestats stats = instance->get_file_stats(p_abort);

		t_uint32 subsong,subsong_count = instance->get_subsong_count();
		bool bInfoGetError = false;
		for(subsong=0;subsong<subsong_count;subsong++)
		{
			TRACK_CALL_TEXT("subsong-loop");
			p_abort.check();
			metadb_handle_ptr handle;
			t_uint32 index = instance->get_subsong(subsong);
			p_callback->handle_create(handle,make_playable_location(p_path,index));

			p_got_input = true;
			if (! bInfoGetError && p_callback->want_info(handle,p_type,stats,true) )
			{
				file_info_impl info;
				try {
					TRACK_CODE("get_info",instance->get_info(index,info,p_abort));
				} catch(std::exception const & e) {
					bInfoGetError = true;
				}
				p_callback->on_entry_info(handle,p_type,stats,info,true);
			}
			else
			{
				p_callback->on_entry(handle,p_type,stats,true);
			}
		}
	}
}
	DWORD readOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, void * out, DWORD outBytes, abort_callback & abort) {
		abort.check();
		if (outBytes == 0) return 0;
		OVERLAPPED ol = {};
		fillOverlapped(ol, myEvent, position);
		ResetEvent(myEvent);
		DWORD bytesDone;
		SetLastError(NO_ERROR);
		if (ReadFile( handle, out, outBytes, &bytesDone, &ol)) {
			// succeeded already?
			return bytesDone;
		}

		{
			const DWORD code = GetLastError();
			switch(code) {
			case ERROR_HANDLE_EOF:
			case ERROR_BROKEN_PIPE:
				return 0;
			case ERROR_IO_PENDING:
				break; // continue
			default:
				exception_io_from_win32(code);
			};
		}

		const HANDLE handles[] = {myEvent, abort.get_abort_event()};
		SetLastError(NO_ERROR);
		DWORD state = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
		if (state == WAIT_OBJECT_0) {
			SetLastError(NO_ERROR);
			if (!GetOverlappedResult(handle,&ol,&bytesDone,TRUE)) {
				const DWORD code = GetLastError();
				if (code == ERROR_HANDLE_EOF || code == ERROR_BROKEN_PIPE) bytesDone = 0;
				else {
					CancelIo(handle);
					exception_io_from_win32(code);
				}
			}
			return bytesDone;
		}
		CancelIo(handle);
		throw exception_aborted();
	}
示例#8
0
	void open_path_helper(input_decoder::ptr & p_input, file::ptr p_file, const char * path,abort_callback & p_abort,bool p_from_redirect,bool p_skip_hints) {
		p_abort.check();
		p_input.release();

		TRACK_CODE("input_entry::g_open_for_decoding",
			input_entry::g_open_for_decoding(p_input,p_file,path,p_abort,p_from_redirect)
			);

		
		if (!p_skip_hints) {
			try {
				static_api_ptr_t<metadb_io>()->hint_reader(p_input.get_ptr(),path,p_abort);
			} catch(exception_io_data) {
				//Don't fail to decode when this barfs, might be barfing when reading info from another subsong than the one we're trying to decode etc.
				p_input.release();
				if (p_file.is_valid()) p_file->reopen(p_abort);
				TRACK_CODE("input_entry::g_open_for_decoding",
					input_entry::g_open_for_decoding(p_input,p_file,path,p_abort,p_from_redirect)
					);
			}
		}
	}
t_size stream_reader_buffered::read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
	if (p_bytes <= m_bufferRemaining) {
		memcpy( p_buffer, m_bufferPtr, p_bytes );
		m_bufferRemaining -= p_bytes;
		m_bufferPtr += p_bytes;
		return p_bytes;
	}
	
	p_abort.check();
	char * output = (char*) p_buffer;
	t_size output_ptr = 0;

	while(output_ptr < p_bytes) {
		{
			t_size delta = pfc::min_t(p_bytes - output_ptr, m_bufferRemaining);
			if (delta > 0)
			{
				memcpy(output + output_ptr, m_bufferPtr, delta);
				output_ptr += delta;
				m_bufferPtr += delta;
				m_bufferRemaining -= delta;
			}
		}

		if (m_bufferRemaining == 0)
		{
			t_size bytes_read;
			bytes_read = m_base->read(m_buffer.get_ptr(), m_buffer.get_size(), p_abort);
			m_bufferPtr = m_buffer.get_ptr();
			m_bufferRemaining = bytes_read;

			if (m_bufferRemaining == 0) break;
		}
		
	}		

	return output_ptr;
}
示例#10
0
		void load_database_t::load_cache(HWND wnd, ipod_device_ptr_ref_t p_ipod, bool b_CheckIfFilesChanged, threaded_process_v2_t & p_status, abort_callback & p_abort)
		{
			pfc::string8 base;
			p_ipod->get_root_path(base);

			metadb_handle_list handlestoread(m_handles);

			pfc::string8 cachePath = base;
			cachePath << "metadata_cache.fpl";

			//We want to hint from main thread to avoid annoyances
			static_api_ptr_t<main_thread_callback_manager> p_main_thread;
			p_status.update_text("Loading metadata cache");
			service_ptr_t<t_main_thread_load_cache_v2_t> p_cache_loader = new service_impl_t<t_main_thread_load_cache_v2_t>
				(base);

			p_cache_loader->callback_run();
			//p_main_thread->add_callback(p_cache_loader);
			if (!p_cache_loader->m_signal.wait_for(-1))
				throw pfc::exception("Cache read timeout!");
			if (!p_cache_loader->m_ret)
				throw pfc::exception(pfc::string8() << "Error reading metadata cache: " << p_cache_loader->m_error);

			p_status.update_text("Checking files for changes");
			//pfc::hires_timer timer2;
			//timer2.start();
			t_size n = handlestoread.get_count(), count = n;
			for (; n; n--)
			{
				if (p_ipod->mobile || !b_CheckIfFilesChanged)
				{
					if (handlestoread[n - 1]->is_info_loaded_async())
						handlestoread.remove_by_idx(n - 1);
					m_tracks[n - 1]->m_runtime_filestats.m_timestamp = filetimestamp_invalid;
					if (m_tracks[n - 1]->original_timestamp_valid)
						m_tracks[n - 1]->m_runtime_filestats.m_timestamp = m_tracks[n - 1]->original_timestamp;
					else if (m_tracks[n - 1]->lastmodifiedtime)
						m_tracks[n - 1]->m_runtime_filestats.m_timestamp = filetime_time_from_appletime(m_tracks[n - 1]->lastmodifiedtime);
					m_tracks[n - 1]->m_runtime_filestats.m_size = m_tracks[n - 1]->size;
				}
				else
				{
					if (true)
					{
						if (n % 20 == 0)
							p_abort.check();
						t_filestats stats = handlestoread[n - 1]->get_filestats();
						const char * path = handlestoread[n - 1]->get_path();
						if (!stricmp_utf8_max(path, "file://", 7))
						{
							path += 7;
							win32::handle_ptr_t p_file =
								CreateFile(pfc::stringcvt::string_os_from_utf8(path), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
							if (p_file.is_valid())
							{
								t_filestats newstats = filestats_invalid;
								GetFileSizeEx(p_file, (PLARGE_INTEGER)&newstats.m_size);
								GetFileTime(p_file, NULL, NULL, (LPFILETIME)&newstats.m_timestamp);
								m_tracks[n - 1]->m_runtime_filestats = newstats;
								if (handlestoread[n - 1]->is_info_loaded_async())
								{
									t_uint64 hour = 60 * 60;
									hour *= 10000000;
									if (stats.m_size == newstats.m_size && (stats.m_timestamp == newstats.m_timestamp || _abs64(newstats.m_timestamp - stats.m_timestamp) == hour) && newstats.m_size != filesize_invalid && newstats.m_timestamp != filetimestamp_invalid)
										handlestoread.remove_by_idx(n - 1);
								}
							}
						}
					}
				}
				p_status.update_progress_subpart_helper(count - n + 1, count);
			}
			//console::formatter() << "info checked in: " << pfc::format_time_ex(timer2.query(),6);

			if (handlestoread.get_count())
			{
				p_status.update_text("Loading file info");
				//static_api_ptr_t<main_thread_callback_manager> p_main_thread;

				service_ptr_t<t_main_thread_scan_file_info> p_info_loader = new service_impl_t<t_main_thread_scan_file_info>
					(handlestoread, metadb_io::load_info_force, wnd);
				p_main_thread->add_callback(p_info_loader);
				if (!p_info_loader->m_signal.wait_for(-1))
					throw pfc::exception("File info reading timeout!");
				if (p_info_loader->m_ret == metadb_io::load_info_aborted)
					throw pfc::exception("File info read was aborted");
			}

			p_abort.check();

		}
示例#11
0
static void process_path_internal(const char * p_path,const service_ptr_t<file> & p_reader,playlist_loader_callback::ptr callback, abort_callback & abort,playlist_loader_callback::t_entry_type type,const t_filestats & p_stats)
{
	//p_path must be canonical

	abort.check();

	callback->on_progress(p_path);

	
	{
		if (p_reader.is_empty() && type != playlist_loader_callback::entry_directory_enumerated) {
			directory_callback_impl2 directory_results(true);
			try {
				filesystem::g_list_directory(p_path,directory_results,abort);
				for(t_size n=0;n<directory_results.get_count();n++) {
					process_path_internal(directory_results.get_item(n),0,callback,abort,playlist_loader_callback::entry_directory_enumerated,directory_results.get_item_stats(n));
				}
				return;
			} catch(exception_aborted) {throw;}
			catch(...) {
				//do nothing, fall thru
				//fixme - catch only filesystem exceptions?
			}
		}

		bool found = false;


		{
			archive_callback_impl archive_results(callback, abort);
			service_enum_t<filesystem> e;
			service_ptr_t<filesystem> f;
			while(e.next(f)) {
				abort.check();
				service_ptr_t<archive> arch;
				if (f->service_query_t(arch)) {
					if (p_reader.is_valid()) p_reader->reopen(abort);

					try {
						TRACK_CODE("archive::archive_list",arch->archive_list(p_path,p_reader,archive_results,true));
						return;
					} catch(exception_aborted) {throw;} 
					catch(...) {}
				}
			} 
		}
	}

	

	{
		service_ptr_t<link_resolver> ptr;
		if (link_resolver::g_find(ptr,p_path))
		{
			if (p_reader.is_valid()) p_reader->reopen(abort);

			pfc::string8 temp;
			try {
				TRACK_CODE("link_resolver::resolve",ptr->resolve(p_reader,p_path,temp,abort));

				track_indexer__g_get_tracks_wrap(temp,0,filestats_invalid,playlist_loader_callback::entry_from_playlist,callback, abort);
				return;//success
			} catch(exception_aborted) {throw;}
			catch(...) {}
		}
	}

	if (callback->is_path_wanted(p_path,type)) {
		track_indexer__g_get_tracks_wrap(p_path,p_reader,p_stats,type,callback, abort);
	}
}