add last backwards-compatible version

This commit is contained in:
2021-12-14 00:33:46 -07:00
parent 68b10d413b
commit b0dd3f07f3
335 changed files with 4746 additions and 19627 deletions

View File

@@ -1,15 +1,21 @@
#include "foobar2000.h" // PCH
#ifdef FOOBAR2000_MODERN
#include "foobar2000-input.h"
#include <pfc/list.h>
#include <pfc/timers.h>
#endif
#include <exception>
#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) {
#include "foobar2000.h"
service_ptr input_entry::open(const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter) {
if (whatFor == input_decoder::class_guid) {
input_decoder::ptr obj;
open(obj, hint, path, aborter);
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;
}
#ifdef FOOBAR2000_DESKTOP
if ( whatFor == input_stream_info_reader::class_guid ) {
input_entry_v2::ptr v2;
@@ -26,62 +32,7 @@ service_ptr input_entry::open(const GUID & whatFor, file::ptr hint, const char *
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();
service_enum_t<album_art_extractor> e;
album_art_extractor_v2::ptr p;
while( e.next(p) ) {
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();
service_enum_t<album_art_editor> e;
album_art_editor_v2::ptr p;
while( e.next(p) ) {
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();
uBugCheck();
}
bool input_entry::g_find_service_by_path(service_ptr_t<input_entry> & p_out,const char * p_path)
@@ -155,41 +106,24 @@ static void prepare_for_open(service_ptr_t<input_entry> & p_service,service_ptr_
#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 ) {
service_enum_t<input_entry> e;
service_ptr_t<input_entry> ptr;
bool ret = false;
while (e.next(ptr)) {
if ( filter(ptr) ) {
if (!(p_from_redirect && ptr->is_redirect())) {
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 ) {
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) {
service_enum_t<input_entry> e;
service_ptr_t<input_entry> ptr;
auto extension = pfc::string_extension(p_path);
bool ret = false;
while (e.next(ptr)) {
GUID guid = pfc::guid_null;
input_entry_v3::ptr ex;
if ( ex &= ptr ) guid = ex->get_guid();
if ( filter(ptr) ) {
if (!(p_from_redirect && ptr->is_redirect())) {
if (ptr->is_our_path(p_path, extension)) { p_out.add_item(ptr); ret = true; }
}
}
@@ -204,82 +138,50 @@ static GUID input_get_guid( input_entry::ptr e ) {
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) {
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, 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);
auto ret = p_list[0]->open(whatFor, p_filehint, p_path, p_abort);
if ( outGUID != nullptr ) * outGUID = input_get_guid( p_list[0] );
return ret;
} else {
std::exception_ptr errData, errUnsupported;
unsigned bad_data_count = 0;
pfc::string8 bad_data_message;
for (t_size n = 0; n < count; n++) {
try {
auto ret = p_list[n]->open(whatFor, p_filehint, p_path, logger, p_abort);
auto ret = p_list[n]->open(whatFor, p_filehint, p_path, p_abort);
if (outGUID != nullptr) * outGUID = input_get_guid(p_list[n]);
return ret;
} catch (exception_io_no_handler_for_path) {
//do nothing, skip over
} catch(exception_io_unsupported_format) {
if (!errUnsupported) errUnsupported = std::current_exception();
} catch (exception_io_data) {
if (!errData) errData = std::current_exception();
} catch (exception_io_unsupported_format) {
//do nothing, skip over
} catch (exception_io_data const & e) {
if (bad_data_count++ == 0) bad_data_message = e.what();
}
}
if (errData) std::rethrow_exception(errData);
if (errUnsupported) std::rethrow_exception(errUnsupported);
throw exception_io_unsupported_format();
if (bad_data_count > 1) throw exception_io_data();
else if (bad_data_count == 0) pfc::throw_exception_with_message<exception_io_data>(bad_data_message);
else 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) {
service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, const char * p_path, abort_callback & p_abort, bool p_from_redirect) {
#ifdef FOOBAR2000_DESKTOP
// #define rationale: not all FOOBAR2000_MODERN flavours come with input_manager implementation, but classic 1.4+ does
#if !defined(FOOBAR2000_MODERN) && FOOBAR2000_TARGET_VERSION >= 79
#if FOOBAR2000_TARGET_VERSION > 79
return input_manager_v2::get()->open_v2(whatFor, p_filehint, p_path, p_from_redirect, logger, p_abort);
#else
return input_manager::get()->open_v2(whatFor, p_filehint, p_path, p_from_redirect, logger, p_abort);
#if FOOBAR2000_TARGET_VERSION >= 79
return input_manager::get()->open(whatFor, p_filehint, p_path, p_from_redirect, p_abort);
#endif
#endif
{
input_manager::ptr m;
service_enum_t<input_manager> e;
if (e.next(m)) {
return m->open_v2(whatFor, p_filehint, p_path, p_from_redirect, logger, p_abort);
return m->open(whatFor, p_filehint, p_path, p_from_redirect, p_abort);
}
}
#endif
@@ -305,7 +207,7 @@ service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, cons
#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);
return g_open_from_list(list, whatFor, l_file, p_path, p_abort);
} catch (exception_io_unsupported_format) {
#if PFC_DEBUG
FB2K_DebugLog() << "Failed to open by content type, using fallback";
@@ -321,7 +223,7 @@ service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, cons
{
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);
return g_open_from_list(list, whatFor, l_file, p_path, p_abort);
}
}
@@ -330,17 +232,17 @@ service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, cons
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);
p_instance ^= g_open(input_decoder::class_guid, p_filehint, p_path, 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);
p_instance ^= g_open(input_info_reader::class_guid, p_filehint, p_path, 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);
p_instance ^= g_open(input_info_writer::class_guid, p_filehint, p_path, 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) {
@@ -390,61 +292,12 @@ void input_open_file_helper(service_ptr_t<file> & p_file,const char * p_path,t_i
}
}
uint32_t input_entry::g_flags_for_path( const char * path, uint32_t mask ) {
#if FOOBAR2000_TARGET_VERSION >= 80
return input_manager_v3::get()->flags_for_path(path, mask);
#else
input_manager_v3::ptr api;
if ( input_manager_v3::tryGet(api) ) {
return api->flags_for_path(path, mask);
}
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 FOOBAR2000_TARGET_VERSION >= 80
return input_manager_v3::get()->flags_for_content_type(ct, mask);
#else
input_manager_v3::ptr api;
if ( input_manager_v3::tryGet(api) ) {
return api->flags_for_content_type( ct, mask );
}
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 );
auto ext = pfc::string_extension(path);
input_entry::ptr svc;
service_enum_t<input_entry> e;
while (e.next(svc)) {
if (svc->is_our_path(path, ext) && svc->are_parallel_reads_slow()) return true;
}
this->commit( abort );
}
return false;
}