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(); }
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; }
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 }
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(); }
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; }
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(); }
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); } }