Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/SDK/input.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/SDK/input.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,459 @@ +#include "foobar2000-sdk-pch.h" +#include <exception> +#include "input.h" +#include "input_impl.h" +#include "album_art.h" +#include "file_info_impl.h" + +service_ptr input_entry::open(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter) { + +#ifdef FOOBAR2000_DESKTOP + if ( whatFor == input_stream_info_reader::class_guid ) { + input_entry_v2::ptr v2; + if ( v2 &= this ) { + GUID g = v2->get_guid(); + for (auto p : input_stream_info_reader_entry::enumerate()) { + if (p->get_guid() == g) { + return p->open(path, hint, aborter); + } + } + } + throw exception_io_unsupported_format(); + } +#endif + if ( whatFor == album_art_extractor_instance::class_guid ) { + input_entry_v2::ptr v2; + if (v2 &= this) { + GUID g = v2->get_guid(); + for (auto p : album_art_extractor::enumerate()) { + if (p->get_guid() == g) { + return p->open(hint, path, aborter); + } + } + } + throw exception_io_unsupported_format(); + } + if ( whatFor == album_art_editor_instance::class_guid ) { + input_entry_v2::ptr v2; + if (v2 &= this) { + GUID g = v2->get_guid(); + for (auto p : album_art_editor::enumerate()) { + if (p->get_guid() == g) { + return p->open(hint, path, aborter); + } + } + } + throw exception_io_unsupported_format(); + } + + input_entry_v3::ptr v3; + + if (v3 &= this) { + return v3->open_v3( whatFor, hint, path, logger, aborter ); + } else { + if (whatFor == input_decoder::class_guid) { + input_decoder::ptr obj; + open(obj, hint, path, aborter); + if ( logger.is_valid() ) { + input_decoder_v2::ptr v2; + if (v2 &= obj) v2->set_logger(logger); + } + return obj; + } + if (whatFor == input_info_reader::class_guid) { + input_info_reader::ptr obj; + open(obj, hint, path, aborter); + return obj; + } + if (whatFor == input_info_writer::class_guid) { + input_info_writer::ptr obj; + open(obj, hint, path, aborter); + return obj; + } + } + + throw pfc::exception_not_implemented(); +} + +bool input_entry::g_find_service_by_path(service_ptr_t<input_entry> & p_out,const char * p_path) +{ + auto ext = pfc::string_extension(p_path); + return g_find_service_by_path(p_out, p_path, ext ); +} + +bool input_entry::g_find_service_by_path(service_ptr_t<input_entry> & p_out,const char * p_path, const char * p_ext) +{ + for (auto ptr : enumerate()) { + if (ptr->is_our_path(p_path,p_ext)) { + p_out = ptr; + return true; + } + } + return false; +} + +bool input_entry::g_find_service_by_content_type(service_ptr_t<input_entry> & p_out,const char * p_content_type) +{ + for (auto ptr : enumerate()) { + if (ptr->is_our_content_type(p_content_type)) { + p_out = ptr; + return true; + } + } + return false; +} + + +#if 0 +static void prepare_for_open(service_ptr_t<input_entry> & p_service,service_ptr_t<file> & p_file,const char * p_path,filesystem::t_open_mode p_open_mode,abort_callback & p_abort,bool p_from_redirect) +{ + if (p_file.is_empty()) + { + service_ptr_t<filesystem> fs; + if (filesystem::g_get_interface(fs,p_path)) { + if (fs->supports_content_types()) { + fs->open(p_file,p_path,p_open_mode,p_abort); + } + } + } + + if (p_file.is_valid()) + { + pfc::string8 content_type; + if (p_file->get_content_type(content_type)) + { + if (input_entry::g_find_service_by_content_type(p_service,content_type)) + return; + } + } + + if (input_entry::g_find_service_by_path(p_service,p_path)) + { + if (p_from_redirect && p_service->is_redirect()) throw exception_io_unsupported_format(); + return; + } + + throw exception_io_unsupported_format(); +} +#endif + +bool input_entry::g_find_inputs_by_content_type(pfc::list_base_t<service_ptr_t<input_entry> > & p_out, const char * p_content_type, bool p_from_redirect) { + auto filter = [=] (input_entry::ptr p) { + return !(p_from_redirect && p->is_redirect()); + }; + return g_find_inputs_by_content_type_ex(p_out, p_content_type, filter ); +} + +bool input_entry::g_find_inputs_by_path(pfc::list_base_t<service_ptr_t<input_entry> > & p_out, const char * p_path, bool p_from_redirect) { + auto filter = [=] (input_entry::ptr p) { + return !(p_from_redirect && p->is_redirect()); + }; + return g_find_inputs_by_path_ex(p_out, p_path, filter); +} + +bool input_entry::g_find_inputs_by_content_type_ex(pfc::list_base_t<service_ptr_t<input_entry> > & p_out, const char * p_content_type, input_filter_t filter ) { + bool ret = false; + for (auto ptr : enumerate()) { + if (filter(ptr)) { + if (ptr->is_our_content_type(p_content_type)) { p_out.add_item(ptr); ret = true; } + } + } + return ret; +} + +bool input_entry::g_find_inputs_by_path_ex(pfc::list_base_t<service_ptr_t<input_entry> > & p_out, const char * p_path, input_filter_t filter ) { + auto extension = pfc::string_extension(p_path); + bool ret = false; + for( auto ptr : enumerate()) { + GUID guid = pfc::guid_null; + input_entry_v3::ptr ex; + if ( ex &= ptr ) guid = ex->get_guid(); + if ( filter(ptr) ) { + if (ptr->is_our_path(p_path, extension)) { p_out.add_item(ptr); ret = true; } + } + } + return ret; +} + +static GUID input_get_guid( input_entry::ptr e ) { +#ifdef FOOBAR2000_DESKTOP + input_entry_v2::ptr p; + if ( p &= e ) return p->get_guid(); +#endif + return pfc::guid_null; +} + +service_ptr input_entry::g_open_from_list(input_entry_list_t const & p_list, const GUID & whatFor, service_ptr_t<file> p_filehint, const char * p_path, event_logger::ptr logger, abort_callback & p_abort, GUID * outGUID) { + const t_size count = p_list.get_count(); + if ( count == 0 ) { + // sanity + throw exception_io_unsupported_format(); + } else if (count == 1) { + auto ret = p_list[0]->open(whatFor, p_filehint, p_path, logger, p_abort); + if ( outGUID != nullptr ) * outGUID = input_get_guid( p_list[0] ); + return ret; + } else { + std::exception_ptr errData, errUnsupported; + for (t_size n = 0; n < count; n++) { + try { + auto ret = p_list[n]->open(whatFor, p_filehint, p_path, logger, p_abort); + if (outGUID != nullptr) * outGUID = input_get_guid(p_list[n]); + return ret; + } catch (exception_io_no_handler_for_path const &) { + //do nothing, skip over + } catch(exception_io_unsupported_format const &) { + if (!errUnsupported) errUnsupported = std::current_exception(); + } catch (exception_io_data const &) { + if (!errData) errData = std::current_exception(); + } + } + if (errData) std::rethrow_exception(errData); + if (errUnsupported) std::rethrow_exception(errUnsupported); + throw exception_io_unsupported_format(); + } +} + +#ifdef FOOBAR2000_DESKTOP +service_ptr input_manager::open_v2(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry) { + // We're wrapping open_v2() on top of old open(). + // Assert on GUIDs that old open() is known to recognize. + PFC_ASSERT(whatFor == input_decoder::class_guid || whatFor == input_info_reader::class_guid || whatFor == input_info_writer::class_guid || whatFor == input_stream_selector::class_guid); + + { + input_manager_v2::ptr v2; + if ( v2 &= this ) { + return v2->open_v2( whatFor, hint, path, fromRedirect, logger, aborter, outUsedEntry ); + } + } + + auto ret = open( whatFor, hint, path, fromRedirect, aborter, outUsedEntry ); + +#ifdef FB2K_HAVE_EVENT_LOGGER + if ( logger.is_valid() ) { + input_decoder_v2::ptr dec; + if (dec &= ret) { + dec->set_logger(logger); + } + } +#endif + return ret; +} +#endif + +service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, const char * p_path, event_logger::ptr logger, abort_callback & p_abort, bool p_from_redirect) { + +#ifdef FOOBAR2000_DESKTOP + return input_manager_v2::get()->open_v2(whatFor, p_filehint, p_path, p_from_redirect, logger, p_abort); +#else // FOOBAR2000_DESKTOP or not + const bool needWriteAcecss = !!(whatFor == input_info_writer::class_guid); + + service_ptr_t<file> l_file = p_filehint; + if (l_file.is_empty()) { + service_ptr_t<filesystem> fs; + if (filesystem::g_get_interface(fs, p_path)) { + if (fs->supports_content_types()) { + fs->open(l_file, p_path, needWriteAcecss ? filesystem::open_mode_write_existing : filesystem::open_mode_read, p_abort); + } + } + } + + if (l_file.is_valid()) { + pfc::string8 content_type; + if (l_file->get_content_type(content_type)) { + pfc::list_t< input_entry::ptr > list; +#if PFC_DEBUG + FB2K_DebugLog() << "attempting input open by content type: " << content_type; +#endif + if (g_find_inputs_by_content_type(list, content_type, p_from_redirect)) { + try { + return g_open_from_list(list, whatFor, l_file, p_path, logger, p_abort); + } catch (exception_io_unsupported_format const &) { +#if PFC_DEBUG + FB2K_DebugLog() << "Failed to open by content type, using fallback"; +#endif + } + } + } + } + +#if PFC_DEBUG + FB2K_DebugLog() << "attempting input open by path: " << p_path; +#endif + { + pfc::list_t< input_entry::ptr > list; + if (g_find_inputs_by_path(list, p_path, p_from_redirect)) { + return g_open_from_list(list, whatFor, l_file, p_path, logger, p_abort); + } + } + + throw exception_io_unsupported_format(); +#endif // not FOOBAR2000_DESKTOP +} + +void input_entry::g_open_for_decoding(service_ptr_t<input_decoder> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) { + TRACK_CALL_TEXT("input_entry::g_open_for_decoding"); + p_instance ^= g_open(input_decoder::class_guid, p_filehint, p_path, nullptr, p_abort, p_from_redirect); +} + +void input_entry::g_open_for_info_read(service_ptr_t<input_info_reader> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) { + TRACK_CALL_TEXT("input_entry::g_open_for_info_read"); + p_instance ^= g_open(input_info_reader::class_guid, p_filehint, p_path, nullptr, p_abort, p_from_redirect); +} + +void input_entry::g_open_for_info_write(service_ptr_t<input_info_writer> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) { + TRACK_CALL_TEXT("input_entry::g_open_for_info_write"); + p_instance ^= g_open(input_info_writer::class_guid, p_filehint, p_path, nullptr, p_abort, p_from_redirect); +} + +void input_entry::g_open_for_info_write_timeout(service_ptr_t<input_info_writer> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,double p_timeout,bool p_from_redirect) { + pfc::lores_timer timer; + timer.start(); + for(;;) { + try { + g_open_for_info_write(p_instance,p_filehint,p_path,p_abort,p_from_redirect); + break; + } catch(exception_io_sharing_violation const &) { + if (timer.query() > p_timeout) throw; + p_abort.sleep(0.01); + } + } +} + +bool input_entry::g_is_supported_path(const char * p_path) +{ + auto ext = pfc::string_extension (p_path); + for( auto ptr : enumerate() ) { + if (ptr->is_our_path(p_path,ext)) return true; + } + return false; +} + + + +void input_open_file_helper(service_ptr_t<file> & p_file,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) +{ + if (p_file.is_empty()) { + switch(p_reason) { + default: + uBugCheck(); + case input_open_info_read: + case input_open_decode: + filesystem::g_open(p_file,p_path,filesystem::open_mode_read,p_abort); + break; + case input_open_info_write: + filesystem::g_open(p_file,p_path,filesystem::open_mode_write_existing,p_abort); + break; + } + } else { + p_file->reopen(p_abort); + } +} + +uint32_t input_entry::g_flags_for_path( const char * path, uint32_t mask ) { +#if defined(FOOBAR2000_DESKTOP) && FOOBAR2000_TARGET_VERSION >= 80 + return input_manager_v3::get()->flags_for_path(path, mask); +#else +#ifdef FOOBAR2000_DESKTOP + input_manager_v3::ptr api; + if ( input_manager_v3::tryGet(api) ) { + return api->flags_for_path(path, mask); + } +#endif + uint32_t ret = 0; + service_enum_t<input_entry> e; input_entry::ptr p; + auto ext = pfc::string_extension(path); + while(e.next(p)) { + uint32_t f = p->get_flags() & mask; + if ( f != 0 && p->is_our_path( path, ext ) ) ret |= f;; + } + return ret; +#endif +} +uint32_t input_entry::g_flags_for_content_type( const char * ct, uint32_t mask ) { +#if defined(FOOBAR2000_DESKTOP) && FOOBAR2000_TARGET_VERSION >= 80 + return input_manager_v3::get()->flags_for_content_type(ct, mask); +#else +#ifdef FOOBAR2000_DESKTOP + input_manager_v3::ptr api; + if ( input_manager_v3::tryGet(api) ) { + return api->flags_for_content_type( ct, mask ); + } +#endif + uint32_t ret = 0; + service_enum_t<input_entry> e; input_entry::ptr p; + while(e.next(p)) { + uint32_t f = p->get_flags() & mask; + if ( f != 0 && p->is_our_content_type(ct) ) ret |= f; + } + return ret; +#endif +} + +bool input_entry::g_are_parallel_reads_slow(const char * path) { + return g_flags_for_path(path, flag_parallel_reads_slow) != 0; +} + +void input_entry_v3::open_for_decoding(service_ptr_t<input_decoder> & p_instance, service_ptr_t<file> p_filehint, const char * p_path, abort_callback & p_abort) { + p_instance ^= open_v3( input_decoder::class_guid, p_filehint, p_path, nullptr, p_abort ); +} +void input_entry_v3::open_for_info_read(service_ptr_t<input_info_reader> & p_instance, service_ptr_t<file> p_filehint, const char * p_path, abort_callback & p_abort) { + p_instance ^= open_v3(input_info_reader::class_guid, p_filehint, p_path, nullptr, p_abort); +} +void input_entry_v3::open_for_info_write(service_ptr_t<input_info_writer> & p_instance, service_ptr_t<file> p_filehint, const char * p_path, abort_callback & p_abort) { + p_instance ^= open_v3(input_info_writer::class_guid, p_filehint, p_path, nullptr, p_abort); +} + +void input_info_writer::remove_tags_fallback(abort_callback & abort) { + uint32_t total = this->get_subsong_count(); + file_info_impl blank; + for( uint32_t walk = 0; walk < total; ++ walk ) { + this->set_info( this->get_subsong(walk), blank, abort ); + } + this->commit( abort ); +} + +t_filestats input_info_reader_v2::get_file_stats(abort_callback& a) { + return this->get_stats2(stats2_size | stats2_timestamp, a).to_legacy(); +} + +t_filestats2 input_info_reader::get_stats2_(const char* fallbackPath, uint32_t f, abort_callback& a) { + t_filestats2 ret; + input_info_reader_v2::ptr v2; + if (v2 &= this) { + ret = v2->get_stats2(f, a); + } else if ((f & ~stats2_legacy) == 0) { + t_filestats subset = this->get_file_stats(a); + ret.m_size = subset.m_size; + ret.m_timestamp = subset.m_timestamp; + } else { + try { + auto fs = filesystem::tryGet(fallbackPath); + if (fs.is_valid()) ret = fs->get_stats2_(fallbackPath, f, a); + } catch (exception_io const &) {} + } + return ret; +} + +GUID input_entry::get_guid_() { + auto ret = pfc::guid_null; + input_entry_v2::ptr v2; + if ( v2 &= this ) ret = v2->get_guid(); + return ret; +} + +const char* input_entry::get_name_() { + const char * ret = "<legacy object>"; + input_entry_v2::ptr v2; + if ( v2 &= this ) ret = v2->get_name(); + return ret; +} + +input_entry::ptr input_entry::g_find_by_guid(const GUID& guid) { + for (auto ptr : enumerate()) { + input_entry_v2::ptr v2; + if (v2 &= ptr) { + if ( guid == v2->get_guid() ) return v2; + } + } + return nullptr; +} \ No newline at end of file
