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

@@ -22,21 +22,3 @@ bool abort_callback::waitForEvent( pfc::eventHandle_t evtHandle, double timeOut
default: uBugCheck();
}
}
bool abort_callback::waitForEvent(pfc::event& evt, double timeOut) {
return waitForEvent(evt.get_handle(), timeOut);
}
void abort_callback::waitForEvent(pfc::eventHandle_t evtHandle) {
bool status = waitForEvent(evtHandle, -1); (void)status;
PFC_ASSERT(status); // should never return false
}
void abort_callback::waitForEvent(pfc::event& evt) {
bool status = waitForEvent(evt, -1); (void)status;
PFC_ASSERT(status); // should never return false
}
namespace fb2k {
abort_callback_dummy noAbort;
}

View File

@@ -40,17 +40,8 @@ public:
//! Sleeps p_timeout_seconds or less when aborted, returns true when execution should continue, false when not.
bool sleep_ex(double p_timeout_seconds) const;
//! Waits for an event. Returns true if event is now signaled, false if the specified period has elapsed and the event did not become signaled. \n
//! Throws exception_aborted if aborted.
bool waitForEvent( pfc::eventHandle_t evtHandle, double timeOut );
//! Waits for an event. Returns true if event is now signaled, false if the specified period has elapsed and the event did not become signaled. \n
//! Throws exception_aborted if aborted.
bool waitForEvent(pfc::event& evt, double timeOut);
//! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first.
void waitForEvent(pfc::eventHandle_t evtHandle);
//! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first.
void waitForEvent(pfc::event& evt);
bool waitForEvent( pfc::eventHandle_t evtHandle, double timeOut );
bool waitForEvent( pfc::event & evt, double timeOut ) {return waitForEvent( evt.get_handle(), timeOut ); }
protected:
abort_callback() {}
~abort_callback() {}
@@ -73,8 +64,8 @@ public:
abort_callback_event get_abort_event() const {return m_event.get_handle();}
private:
abort_callback_impl(const abort_callback_impl &) = delete;
const abort_callback_impl & operator=(const abort_callback_impl&) = delete;
abort_callback_impl(const abort_callback_impl &);
const abort_callback_impl & operator=(const abort_callback_impl&);
volatile bool m_aborting;
pfc::event m_event;
@@ -110,10 +101,4 @@ using namespace foobar2000_io;
PP::aborter aborter_pfcv2( aborterRef ); \
PP::aborterScope l_aborterScope( aborter_pfcv2 );
namespace fb2k {
// A shared abort_callback_dummy instance
extern abort_callback_dummy noAbort;
}
#endif //_foobar2000_sdk_abort_callback_h_

View File

@@ -1,13 +1,5 @@
#include "foobar2000.h"
bool advconfig_entry::is_branch() {
advconfig_branch::ptr branch;
return branch &= this;
}
bool advconfig_entry::g_find(service_ptr_t<advconfig_entry>& out, const GUID & id) {
service_enum_t<advconfig_entry> e; service_ptr_t<advconfig_entry> ptr; while(e.next(ptr)) { if (ptr->get_guid() == id) {out = ptr; return true;} } return false;
}
t_uint32 advconfig_entry::get_preferences_flags_() {
{

View File

@@ -11,10 +11,11 @@ public:
virtual void reset() = 0;
virtual double get_sort_priority() = 0;
bool is_branch();
t_uint32 get_preferences_flags_();
static bool g_find(service_ptr_t<advconfig_entry>& out, const GUID & id);
static bool g_find(service_ptr_t<advconfig_entry>& out, const GUID & id) {
service_enum_t<advconfig_entry> e; service_ptr_t<advconfig_entry> ptr; while(e.next(ptr)) { if (ptr->get_guid() == id) {out = ptr; return true;} } return false;
}
template<typename outptr> static bool g_find_t(outptr & out, const GUID & id) {
service_ptr_t<advconfig_entry> temp;
@@ -23,7 +24,7 @@ public:
}
static const GUID guid_root;
static const GUID guid_branch_tagging,guid_branch_decoding,guid_branch_tools,guid_branch_playback,guid_branch_display,guid_branch_debug, guid_branch_tagging_general;
static const GUID guid_branch_tagging,guid_branch_decoding,guid_branch_tools,guid_branch_playback,guid_branch_display,guid_branch_debug;
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(advconfig_entry);
};
@@ -249,8 +250,8 @@ public:
advconfig_integer_factory_(const char * p_name,const GUID & p_guid,const GUID & p_parent,double p_priority,t_uint64 p_initialstate,t_uint64 p_min,t_uint64 p_max, t_uint32 p_prefFlags = 0)
: service_factory_single_t<advconfig_entry_integer_impl_<int_t_> >(p_name,p_guid,p_parent,p_priority,p_initialstate,p_min,p_max,p_prefFlags) {}
int_t get() const {return this->get_static_instance().get_state_int();}
void set(int_t val) {this->get_static_instance().set_state_int(val);}
int_t get() const {return get_static_instance().get_state_int();}
void set(int_t val) {get_static_instance().set_state_int(val);}
operator int_t() const {return get();}
int_t operator=(int_t val) {set(val); return val;}

View File

@@ -1,17 +1,5 @@
#include "foobar2000.h"
GUID album_art_extractor::get_guid() {
album_art_extractor_v2::ptr v2;
if ( v2 &= this ) return v2->get_guid();
return pfc::guid_null;
}
GUID album_art_editor::get_guid() {
album_art_editor_v2::ptr v2;
if ( v2 &= this ) return v2->get_guid();
return pfc::guid_null;
}
bool album_art_extractor_instance::query(const GUID & what, album_art_data::ptr & out, abort_callback & abort) {
try { out = query(what, abort); return true; } catch (exception_album_art_not_found) { return false; }
}
@@ -20,23 +8,9 @@ bool album_art_extractor_instance::have_entry(const GUID & what, abort_callback
try { query(what, abort); return true; } catch(exception_album_art_not_found) { return false; }
}
void album_art_editor_instance::remove_all_() {
album_art_editor_instance_v2::ptr v2;
if ( v2 &= this ) {
v2->remove_all();
} else {
for( size_t walk = 0; walk < album_art_ids::num_types(); ++ walk ) {
try {
this->remove( album_art_ids::query_type( walk ) );
} catch(exception_io_data) {}
catch(exception_album_art_not_found) {}
}
}
}
bool album_art_editor::g_get_interface(service_ptr_t<album_art_editor> & out,const char * path) {
service_enum_t<album_art_editor> e; ptr ptr;
auto ext = pfc::string_extension(path);
pfc::string_extension ext(path);
while(e.next(ptr)) {
if (ptr->is_our_path(path,ext)) { out = ptr; return true; }
}
@@ -48,18 +22,6 @@ bool album_art_editor::g_is_supported_path(const char * path) {
}
album_art_editor_instance_ptr album_art_editor::g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) {
#ifdef FOOBAR2000_DESKTOP
{
input_manager_v2::ptr m;
if (fb2k::std_api_try_get(m)) {
album_art_editor_instance::ptr ret;
ret ^= m->open_v2(album_art_editor_instance::class_guid, p_filehint, p_path, false, nullptr, p_abort);
return ret;
}
}
#endif
album_art_editor::ptr obj;
if (!g_get_interface(obj, p_path)) throw exception_album_art_unsupported_format();
return obj->open(p_filehint, p_path, p_abort);
@@ -68,7 +30,7 @@ album_art_editor_instance_ptr album_art_editor::g_open(file_ptr p_filehint,const
bool album_art_extractor::g_get_interface(service_ptr_t<album_art_extractor> & out,const char * path) {
service_enum_t<album_art_extractor> e; ptr ptr;
auto ext = pfc::string_extension(path);
pfc::string_extension ext(path);
while(e.next(ptr)) {
if (ptr->is_our_path(path,ext)) { out = ptr; return true; }
}
@@ -79,17 +41,6 @@ bool album_art_extractor::g_is_supported_path(const char * path) {
ptr ptr; return g_get_interface(ptr,path);
}
album_art_extractor_instance_ptr album_art_extractor::g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) {
#ifdef FOOBAR2000_DESKTOP
{
input_manager_v2::ptr m;
if (fb2k::std_api_try_get(m)) {
album_art_extractor_instance::ptr ret;
ret ^= m->open_v2(album_art_extractor_instance::class_guid, p_filehint, p_path, false, nullptr, p_abort);
return ret;
}
}
#endif
album_art_extractor::ptr obj;
if (!g_get_interface(obj, p_path)) throw exception_album_art_unsupported_format();
return obj->open(p_filehint, p_path, p_abort);
@@ -120,66 +71,4 @@ now_playing_album_art_notify * now_playing_album_art_notify_manager::add(std::fu
obj->f = f;
add(obj);
return obj;
}
namespace {
struct aa_t {
GUID type; const char * name;
};
static const GUID guids[] = {
album_art_ids::cover_front,
album_art_ids::cover_back,
album_art_ids::artist,
album_art_ids::disc,
album_art_ids::icon,
};
static const char * const names[] = {
"front cover",
"back cover",
"artist",
"disc",
"icon"
};
static const char * const names2[] = {
"Front Cover",
"Back Cover",
"Artist",
"Disc",
"Icon"
};
}
size_t album_art_ids::num_types() {
PFC_STATIC_ASSERT( PFC_TABSIZE( guids ) == PFC_TABSIZE( names ) );
PFC_STATIC_ASSERT( PFC_TABSIZE( guids ) == PFC_TABSIZE( names2 ) );
return PFC_TABSIZE( guids );
}
GUID album_art_ids::query_type(size_t idx) {
PFC_ASSERT( idx < PFC_TABSIZE( guids ) );
return guids[idx];
}
const char * album_art_ids::query_name(size_t idx) {
PFC_ASSERT( idx < PFC_TABSIZE( names ) );
return names[idx];
}
const char * album_art_ids::name_of(const GUID & id) {
for( size_t w = 0; w < num_types(); ++w ) {
if ( query_type(w) == id ) return query_name(w);
}
return nullptr;
}
const char * album_art_ids::query_capitalized_name( size_t idx ) {
PFC_ASSERT( idx < PFC_TABSIZE( names2 ) );
return names2[idx];
}
const char * album_art_ids::capitalized_name_of( const GUID & id) {
for( size_t w = 0; w < num_types(); ++w ) {
if ( query_type(w) == id ) return query_capitalized_name(w);
}
return nullptr;
}
}

View File

@@ -25,9 +25,6 @@ public:
};
typedef service_ptr_t<album_art_data> album_art_data_ptr;
namespace fb2k {
typedef album_art_data_ptr memBlockRef;
}
//! Namespace containing identifiers of album art types.
namespace album_art_ids {
@@ -42,14 +39,6 @@ namespace album_art_ids {
//! Artist picture.
static const GUID artist = { 0x9a654042, 0xacd1, 0x43f7, { 0xbf, 0xcf, 0xd3, 0xec, 0xf, 0xfe, 0x40, 0xfa } };
size_t num_types();
GUID query_type( size_t );
// returns lowercase name
const char * query_name( size_t );
const char * name_of( const GUID & );
// returns Capitalized name
const char * query_capitalized_name( size_t );
const char * capitalized_name_of( const GUID & );
};
PFC_DECLARE_EXCEPTION(exception_album_art_not_found,exception_io_not_found,"Attached picture not found");
@@ -80,9 +69,6 @@ public:
//! Finalizes file tag update operation.
virtual void commit(abort_callback & p_abort) = 0;
//! Helper; see album_art_editor_instance_v2::remove_all();
void remove_all_();
};
class NOVTABLE album_art_editor_instance_v2 : public album_art_editor_instance {
@@ -98,7 +84,6 @@ typedef service_ptr_t<album_art_editor_instance> album_art_editor_instance_ptr;
//! Entrypoint class for accessing album art extraction functionality. Register your own implementation to allow album art extraction from your media file format. \n
//! If you want to extract album art from a media file, it's recommended that you use album_art_manager API instead of calling album_art_extractor directly.
class NOVTABLE album_art_extractor : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_extractor);
public:
//! Returns whether the specified file is one of formats supported by our album_art_extractor implementation.
//! @param p_path Path to file being queried.
@@ -115,21 +100,11 @@ public:
static album_art_extractor_instance_ptr g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort);
static album_art_extractor_instance_ptr g_open_allowempty(file_ptr p_filehint,const char * p_path,abort_callback & p_abort);
//! Returns GUID of the corresponding input class. Null GUID if none.
GUID get_guid();
};
//! \since 1.5
class NOVTABLE album_art_extractor_v2 : public album_art_extractor {
FB2K_MAKE_SERVICE_INTERFACE(album_art_extractor_v2 , album_art_extractor);
public:
//! Returns GUID of the corresponding input class. Null GUID if none.
virtual GUID get_guid() = 0;
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_extractor);
};
//! Entrypoint class for accessing album art editing functionality. Register your own implementation to allow album art editing on your media file format.
class NOVTABLE album_art_editor : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_editor);
public:
//! Returns whether the specified file is one of formats supported by our album_art_editor implementation.
//! @param p_path Path to file being queried.
@@ -148,20 +123,11 @@ public:
static album_art_editor_instance_ptr g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort);
//! Returns GUID of the corresponding input class. Null GUID if none.
GUID get_guid();
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_editor);
};
//! \since 1.5
class NOVTABLE album_art_editor_v2 : public album_art_editor {
FB2K_MAKE_SERVICE_INTERFACE( album_art_editor_v2, album_art_editor )
public:
//! Returns GUID of the corresponding input class. Null GUID if none.
virtual GUID get_guid() = 0;
};
//! \since 0.9.5
//! Helper API for extracting album art from APEv2 tags.
//! Helper API for extracting album art from APEv2 tags - introduced in 0.9.5.
class NOVTABLE tag_processor_album_art_utils : public service_base {
FB2K_MAKE_SERVICE_COREAPI(tag_processor_album_art_utils)
public:

View File

@@ -1,4 +1,3 @@
#pragma once
//! Implements album_art_data.
class album_art_data_impl : public album_art_data {
public:
@@ -51,37 +50,32 @@ private:
};
//! Helper implementation of album_art_extractor - reads album art from arbitrary file formats that comply with APEv2 tagging specification.
class album_art_extractor_impl_stdtags : public album_art_extractor_v2 {
class album_art_extractor_impl_stdtags : public album_art_extractor {
public:
//! @param exts Semicolon-separated list of file format extensions to support.
album_art_extractor_impl_stdtags(const char * exts, const GUID & guid) : m_guid(guid) {
album_art_extractor_impl_stdtags(const char * exts) {
pfc::splitStringSimple_toList(m_extensions,';',exts);
}
bool is_our_path(const char * p_path,const char * p_extension) override {
bool is_our_path(const char * p_path,const char * p_extension) {
return m_extensions.have_item(p_extension);
}
album_art_extractor_instance_ptr open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) override {
album_art_extractor_instance_ptr open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) {
PFC_ASSERT( is_our_path(p_path, pfc::string_extension(p_path) ) );
file_ptr l_file ( p_filehint );
if (l_file.is_empty()) filesystem::g_open_read(l_file, p_path, p_abort);
return tag_processor_album_art_utils::get()->open( l_file, p_abort );
}
GUID get_guid() override {
return m_guid;
}
private:
pfc::avltree_t<pfc::string,pfc::string::comparatorCaseInsensitiveASCII> m_extensions;
const GUID m_guid;
};
//! Helper implementation of album_art_editor - edits album art from arbitrary file formats that comply with APEv2 tagging specification.
class album_art_editor_impl_stdtags : public album_art_editor_v2 {
class album_art_editor_impl_stdtags : public album_art_editor {
public:
//! @param exts Semicolon-separated list of file format extensions to support.
album_art_editor_impl_stdtags(const char * exts, const GUID & guid) : m_guid(guid) {
album_art_editor_impl_stdtags(const char * exts) {
pfc::splitStringSimple_toList(m_extensions,';',exts);
}
@@ -95,12 +89,8 @@ public:
if (l_file.is_empty()) filesystem::g_open(l_file, p_path, filesystem::open_mode_write_existing, p_abort);
return tag_processor_album_art_utils::get()->edit( l_file, p_abort );
}
GUID get_guid() override {
return m_guid;
}
private:
pfc::avltree_t<pfc::string,pfc::string::comparatorCaseInsensitiveASCII> m_extensions;
const GUID m_guid;
};

View File

@@ -1,85 +0,0 @@
#pragma once
namespace foobar2000_io {
class archive;
class NOVTABLE archive_callback : public abort_callback {
public:
virtual bool on_entry(archive * owner,const char * url,const t_filestats & p_stats,const service_ptr_t<file> & p_reader) = 0;
};
//! Interface for archive reader services. When implementing, derive from archive_impl rather than from deriving from archive directly.
class NOVTABLE archive : public filesystem {
FB2K_MAKE_SERVICE_INTERFACE(archive,filesystem);
public:
//! Lists archive contents. \n
//! May be called with any path, not only path accepted by is_our_archive.
virtual void archive_list(const char * p_path,const service_ptr_t<file> & p_reader,archive_callback & p_callback,bool p_want_readers) = 0;
//! Optional method to weed out unsupported formats prior to calling archive_list. \n
//! Use this to suppress calls to archive_list() to avoid spurious exceptions being thrown. \n
//! Implemented via archive_v2.
bool is_our_archive( const char * path );
};
//! \since 1.5
//! New 1.5 series API, though allowed to implement/call in earlier versions. \n
//! Suppresses spurious C++ exceptions on all files not recognized as archives by this instance.
class NOVTABLE archive_v2 : public archive {
FB2K_MAKE_SERVICE_INTERFACE(archive_v2, archive)
public:
//! Optional method to weed out unsupported formats prior to calling archive_list. \n
//! Use this to suppress calls to archive_list() to avoid spurious exceptions being thrown.
virtual bool is_our_archive( const char * path ) = 0;
};
//! \since 1.6
//! New 1.6 series API, though allowed to implement/call in earlier versions.
class NOVTABLE archive_v3 : public archive_v2 {
FB2K_MAKE_SERVICE_INTERFACE(archive_v3, archive_v2)
public:
//! Determine supported archive file types. \n
//! Returns a list of extensions, colon delimited, e.g.: "zip,rar,7z"
virtual void list_extensions(pfc::string_base & out) = 0;
};
//! Root class for archive implementations. Derive from this instead of from archive directly.
class NOVTABLE archive_impl : public archive_v3 {
private:
//do not override these
bool get_canonical_path(const char * path,pfc::string_base & out);
bool is_our_path(const char * path);
bool get_display_path(const char * path,pfc::string_base & out);
void remove(const char * path,abort_callback & p_abort);
void move(const char * src,const char * dst,abort_callback & p_abort);
bool is_remote(const char * src);
bool relative_path_create(const char * file_path,const char * playlist_path,pfc::string_base & out);
bool relative_path_parse(const char * relative_path,const char * playlist_path,pfc::string_base & out);
void open(service_ptr_t<file> & p_out,const char * path, t_open_mode mode,abort_callback & p_abort);
void create_directory(const char * path,abort_callback &);
void list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort);
void get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort);
void list_extensions(pfc::string_base & out) override { out = get_archive_type(); }
protected:
//override these
virtual const char * get_archive_type()=0;//eg. "zip", must be lowercase
virtual t_filestats get_stats_in_archive(const char * p_archive,const char * p_file,abort_callback & p_abort) = 0;
virtual void open_archive(service_ptr_t<file> & p_out,const char * archive,const char * file, abort_callback & p_abort) = 0;//opens for reading
public:
//override these
virtual void archive_list(const char * path,const service_ptr_t<file> & p_reader,archive_callback & p_out,bool p_want_readers)= 0 ;
virtual bool is_our_archive( const char * path ) = 0;
static bool g_is_unpack_path(const char * path);
static bool g_parse_unpack_path(const char * path,pfc::string_base & archive,pfc::string_base & file);
static bool g_parse_unpack_path_ex(const char * path,pfc::string_base & archive,pfc::string_base & file, pfc::string_base & type);
static void g_make_unpack_path(pfc::string_base & path,const char * archive,const char * file,const char * type);
void make_unpack_path(pfc::string_base & path,const char * archive,const char * file);
};
template<typename T>
class archive_factory_t : public service_factory_single_t<T> {};
}

View File

@@ -101,7 +101,7 @@ template<bool byteSwap, bool isSigned> static void _import32any(const void * in,
for(size_t walk = 0; walk < count; ++walk) {
uint32_t v = *inPtr++;
if (byteSwap) v = pfc::byteswap_t(v);
if (!isSigned) v ^= 0x80000000u; // to signed
if (!isSigned) v ^= 0x80000000; // to signed
*out++ = (audio_sample) (int32_t) v * factor;
}
}
@@ -325,14 +325,8 @@ void audio_chunk::set_data_floatingpoint_ex(const void * ptr,t_size size,unsigne
set_channels(nch,p_channel_config);
}
pfc::string8 audio_chunk::formatChunkSpec() const {
pfc::string8 msg;
msg << get_sample_rate() << " Hz, " << get_channels() << ":0x" << pfc::format_hex(get_channel_config(), 2) << " channels, " << get_sample_count() << " samples";
return msg;
}
void audio_chunk::debugChunkSpec() const {
FB2K_DebugLog() << "Chunk: " << this->formatChunkSpec();
FB2K_DebugLog() << "Chunk: " << get_sample_rate() << " Hz, " << get_channels() << ":0x" << pfc::format_hex(get_channel_config(),2) << " channels, " << get_sample_count() << " samples";
}
#if PFC_DEBUG
@@ -347,7 +341,7 @@ void audio_chunk::assert_valid(const char * ctx) const {
bool audio_chunk::is_valid() const
{
unsigned nch = get_channels();
if (nch == 0 || nch > 32) return false;
if (nch==0 || nch>256) return false;
if (!g_is_valid_sample_rate(get_srate())) return false;
t_size samples = get_sample_count();
if (samples==0 || samples >= 0x80000000ul / (sizeof(audio_sample) * nch) ) return false;
@@ -596,19 +590,13 @@ bool audio_chunk::spec_t::equals( const spec_t & v1, const spec_t & v2 ) {
return v1.sampleRate == v2.sampleRate && v1.chanCount == v2.chanCount && v1.chanMask == v2.chanMask;
}
pfc::string8 audio_chunk::spec_t::toString(const char * delim) const {
pfc::string8 audio_chunk::spec_t::toString() const {
pfc::string_formatter temp;
if ( sampleRate > 0 ) temp << sampleRate << "Hz";
if (chanCount > 0) {
if ( temp.length() > 0 ) temp << delim;
temp << chanCount << "ch";
}
temp << sampleRate << "Hz " << chanCount << "ch";
if ( chanMask != audio_chunk::channel_config_mono && chanMask != audio_chunk::channel_config_stereo ) {
pfc::string8 strMask;
audio_chunk::g_formatChannelMaskDesc( chanMask, strMask );
if ( temp.length() > 0) temp << delim;
temp << strMask;
temp << " " << strMask;
}
return temp;
}
@@ -689,14 +677,3 @@ WAVEFORMATEXTENSIBLE audio_chunk::spec_t::toWFXEXWithBPS(uint32_t bps) const {
return wfxe;
}
#endif // _WIN32
void audio_chunk::append(const audio_chunk& other) {
if (other.get_spec() != this->get_spec()) {
throw pfc::exception_invalid_params();
}
this->grow_data_size(get_used_size() + other.get_used_size());
audio_sample* p = this->get_data() + get_used_size();
memcpy(p, other.get_data(), other.get_used_size() * sizeof(audio_sample));
set_sample_count(get_sample_count() + other.get_sample_count());
}

View File

@@ -45,9 +45,6 @@ public:
channel_config_5point1_side = channel_front_left | channel_front_right | channel_front_center | channel_lfe | channel_side_left | channel_side_right,
channel_config_7point1 = channel_config_5point1 | channel_side_left | channel_side_right,
channels_back_left_right = channel_back_left | channel_back_right,
channels_side_left_right = channel_side_left | channel_side_right,
defined_channel_count = 18,
};
@@ -139,7 +136,6 @@ public:
bool is_valid() const;
void debugChunkSpec() const;
pfc::string8 formatChunkSpec() const;
#if PFC_DEBUG
void assert_valid(const char * ctx) const;
#else
@@ -162,7 +158,7 @@ public:
inline void reset() {
set_sample_count(0);
set_srate(0);
set_channels(0,0);
set_channels(0);
set_data_size(0);
}
@@ -289,7 +285,7 @@ public:
WAVEFORMATEXTENSIBLE toWFXEXWithBPS(uint32_t bps) const;
#endif
pfc::string8 toString( const char * delim = " " ) const;
pfc::string8 toString() const;
};
static spec_t makeSpec(uint32_t rate, uint32_t channels);
static spec_t makeSpec(uint32_t rate, uint32_t channels, uint32_t chanMask);
@@ -297,8 +293,6 @@ public:
spec_t get_spec() const;
void set_spec(const spec_t &);
void append(const audio_chunk& other);
protected:
audio_chunk() {}
~audio_chunk() {}
@@ -353,17 +347,17 @@ public:
audio_sample * get_data() {throw pfc::exception_not_implemented();}
const audio_sample * get_data() const {return m_data;}
t_size get_data_size() const {return m_samples * m_channels;}
void set_data_size(t_size) {throw pfc::exception_not_implemented();}
void set_data_size(t_size p_new_size) {throw pfc::exception_not_implemented();}
unsigned get_srate() const {return m_sample_rate;}
void set_srate(unsigned) {throw pfc::exception_not_implemented();}
void set_srate(unsigned val) {throw pfc::exception_not_implemented();}
unsigned get_channels() const {return m_channels;}
unsigned get_channel_config() const {return m_channel_config;}
void set_channels(unsigned,unsigned) {throw pfc::exception_not_implemented();}
void set_channels(unsigned p_count,unsigned p_config) {throw pfc::exception_not_implemented();}
t_size get_sample_count() const {return m_samples;}
void set_sample_count(t_size) {throw pfc::exception_not_implemented();}
void set_sample_count(t_size val) {throw pfc::exception_not_implemented();}
private:
t_size m_samples;

View File

@@ -88,27 +88,32 @@ static const unsigned g_audio_channel_config_table[] =
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_lfe,
audio_chunk::channel_config_5point1,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_lfe | audio_chunk::channel_front_center_right | audio_chunk::channel_front_center_left,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_front_center | audio_chunk::channel_lfe | audio_chunk::channel_front_center_right | audio_chunk::channel_front_center_left,
};
static const unsigned g_audio_channel_config_table_xiph[] =
{
0,
audio_chunk::channel_config_7point1,
0,
audio_chunk::channel_config_7point1 | audio_chunk::channel_front_center_right | audio_chunk::channel_front_center_left,
audio_chunk::channel_config_mono,
audio_chunk::channel_config_stereo,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_front_center,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_front_center,
audio_chunk::channel_config_5point1,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_front_center | audio_chunk::channel_lfe | audio_chunk::channel_back_center | audio_chunk::channel_side_left | audio_chunk::channel_side_right,
audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_front_center | audio_chunk::channel_lfe | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_side_left | audio_chunk::channel_side_right,
};
unsigned audio_chunk::g_guess_channel_config(unsigned count)
{
if (count == 0) return 0;
if (count > 32) throw exception_io_data();
unsigned ret = 0;
if (count < PFC_TABSIZE(g_audio_channel_config_table)) ret = g_audio_channel_config_table[count];
if (ret == 0) {
ret = (1 << count) - 1;
}
PFC_ASSERT(g_count_channels(ret) == count);
return ret;
if (count >= PFC_TABSIZE(g_audio_channel_config_table)) return 0;
return g_audio_channel_config_table[count];
}
unsigned audio_chunk::g_guess_channel_config_xiph(unsigned count) {
return g_guess_channel_config(count);
if (count == 0 || count >= PFC_TABSIZE(g_audio_channel_config_table_xiph)) throw exception_io_data();
return g_audio_channel_config_table_xiph[count];
}
unsigned audio_chunk::g_channel_index_from_flag(unsigned p_config,unsigned p_flag) {

View File

@@ -1,5 +1,3 @@
#pragma once
//! This class handles conversion of audio data (audio_chunk) to various linear PCM types, with optional dithering.
class NOVTABLE audio_postprocessor : public service_base

View File

@@ -28,10 +28,7 @@ public:
template<typename t_array> void get_configuration(t_array & p_out) {
PFC_STATIC_ASSERT( sizeof(p_out[0]) == 1 );
typedef pfc::array_t<t_uint8,pfc::alloc_fast_aggressive> t_temp; t_temp temp;
{
stream_writer_buffer_append_ref_t<t_temp> writer(temp);
get_configuration(&writer,fb2k::noAbort);
}
get_configuration(&stream_writer_buffer_append_ref_t<t_temp>(temp),abort_callback_dummy());
p_out = temp;
}
};

View File

@@ -67,7 +67,7 @@ private:
t_inttype m_val;
protected:
void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) {p_stream->write_lendian_t(m_val,p_abort);}
void set_data_raw(stream_reader * p_stream,t_size,abort_callback & p_abort) {
void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) {
t_inttype temp;
p_stream->read_lendian_t(temp,p_abort);//alter member data only on success, this will throw an exception when something isn't right
m_val = temp;
@@ -88,11 +88,9 @@ public:
typedef cfg_int_t<t_int32> cfg_int;
typedef cfg_int_t<t_uint32> cfg_uint;
//! Since relevant byteswapping functions also understand GUIDs, this can be used to declare a cfg_guid.
//! Since relevant byteswapping functions also understand GUIDs, this can be abused to declare a cfg_guid.
typedef cfg_int_t<GUID> cfg_guid;
typedef cfg_int_t<bool> cfg_bool;
typedef cfg_int_t<float> cfg_float;
typedef cfg_int_t<double> cfg_double;
//! String config variable. Stored in the stream with int32 header containing size in bytes, followed by non-null-terminated UTF-8 data.\n
//! Note that cfg_var class and its derivatives may be only instantiated statically (as static objects or members of other static objects), NEVER dynamically (operator new, local variables, members of objects instantiated as such).
@@ -120,7 +118,7 @@ protected:
get(temp);
p_stream->write_object(temp.get_ptr(), temp.length(),p_abort);
}
void set_data_raw(stream_reader * p_stream,t_size,abort_callback & p_abort) {
void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) {
pfc::string8_fastalloc temp;
p_stream->read_string_raw(temp,p_abort);
set(temp);

View File

@@ -1,5 +1,3 @@
#pragma once
#include <functional>
//! Generic service for receiving notifications about async operation completion. Used by various other services.
@@ -22,7 +20,7 @@ public:
//! Implementation helper.
class completion_notify_dummy : public completion_notify {
public:
void on_completion(unsigned) {}
void on_completion(unsigned p_code) {}
};
//! Implementation helper.
@@ -70,7 +68,7 @@ public:
~completion_notify_receiver();
void orphan_all_tasks();
virtual void on_task_completion(unsigned p_id,unsigned p_status) {(void)p_id;(void)p_status;}
virtual void on_task_completion(unsigned p_id,unsigned p_status) {}
private:
static void orphanfunc(unsigned,completion_notify_orphanable_nnptr p_item) {p_item->orphan();}
pfc::map_t<unsigned,completion_notify_orphanable_nnptr> m_tasks;

View File

@@ -14,7 +14,8 @@ bool component_installation_validator::have_other_file(const char * fn) {
path << fn;
try {
try {
bool v = filesystem::g_exists(path, fb2k::noAbort);
abort_callback_dummy aborter;
bool v = filesystem::g_exists(path, aborter);
PFC_ASSERT( v );
return v;
} catch(std::exception const & e) {

View File

@@ -146,20 +146,23 @@ namespace {
t_size config_object::get_data_raw(void * p_out,t_size p_bytes) {
t_size ret = 0;
stream_writer_fixedbuffer stream(p_out,p_bytes,ret);
get_data(&stream,fb2k::noAbort);
abort_callback_dummy aborter;
get_data(&stream,aborter);
return ret;
}
t_size config_object::get_data_raw_length() {
t_size ret = 0;
stream_writer_get_length stream(ret);
get_data(&stream,fb2k::noAbort);
abort_callback_dummy aborter;
get_data(&stream,aborter);
return ret;
}
void config_object::set_data_raw(const void * p_data,t_size p_bytes, bool p_notify) {
stream_reader_memblock_ref stream(p_data,p_bytes);
set_data(&stream,fb2k::noAbort,p_notify);
abort_callback_dummy aborter;
set_data(&stream,aborter,p_notify);
}
void config_object::set_data_string(const char * p_data,t_size p_length) {
@@ -168,7 +171,8 @@ void config_object::set_data_string(const char * p_data,t_size p_length) {
void config_object::get_data_string(pfc::string_base & p_out) {
stream_writer_string stream(p_out);
get_data(&stream,fb2k::noAbort);
abort_callback_dummy aborter;
get_data(&stream,aborter);
}

View File

@@ -1,5 +1,3 @@
#pragma once
//! Reserved for future use.
typedef void * t_glyph;
@@ -123,7 +121,6 @@ public:
//! Return DEFAULT_ON to show this item in the context menu by default - useful for most cases. \n
//! Return DEFAULT_OFF to hide this item in the context menu by default - useful for rarely used utility commands. \n
//! Return FORCE_OFF to hide this item by default and prevent the user from making it visible (very rarely used). \n
//! foobar2000 v1.6 and newer: FORCE_OFF items are meant for being shown only in the keyboard shortcut list, not anywhere else. \n
//! Values returned by this method should be constant for this context menu item and not change later. Do not use this to conditionally hide the item - return false from get_display_data() instead.
virtual t_enabled_state get_enabled_state(unsigned p_index) = 0;
//! Executes the menu item command without going thru the instantiate_item path. For items with dynamically-generated sub-items, p_node is identifies of the sub-item command to execute.

View File

@@ -27,7 +27,7 @@ namespace core_api {
const char * get_profile_path();
//! Returns a path to <file name> in fb2k profile folder.
inline pfc::string8 pathInProfile(const char * fileName) { pfc::string8 p( core_api::get_profile_path() ); p.add_filename( fileName ); return p; }
inline pfc::string8 pathInProfile(const char * fileName) { pfc::string8 p( core_api::get_profile_path() ); p.add_filename( fileName ); return std::move(p); }
//! Returns whether foobar2000 has been installed in "portable" mode.
bool is_portable_mode_enabled();

View File

@@ -85,9 +85,6 @@ void dsp_chunk_list::remove_bad_chunks()
audio_chunk * chunk = get_item(idx);
if (!chunk->is_valid())
{
#if PFC_DEBUG
FB2K_console_formatter() << "Removing bad chunk: " << chunk->formatChunkSpec();
#endif
chunk->reset();
remove_by_idx(idx);
blah = true;
@@ -285,42 +282,6 @@ dsp_chain_config_impl::~dsp_chain_config_impl()
m_data.delete_all();
}
pfc::string8 dsp_preset::get_owner_name() const {
pfc::string8 ret;
dsp_entry::ptr obj;
if (dsp_entry::g_get_interface(obj, this->get_owner())) {
obj->get_name(ret);
}
return ret;
}
pfc::string8 dsp_preset::get_owner_name_debug() const {
pfc::string8 ret;
dsp_entry::ptr obj;
if (dsp_entry::g_get_interface(obj, this->get_owner())) {
obj->get_name(ret);
} else {
ret = "[unknown]";
}
return ret;
}
pfc::string8 dsp_preset::debug() const {
pfc::string8 ret;
ret << this->get_owner_name_debug() << " :: " << pfc::print_guid(this->get_owner()) << " :: " << pfc::format_hexdump(this->get_data(), this->get_data_size());
return ret;
}
pfc::string8 dsp_chain_config::debug() const {
const size_t count = get_count();
pfc::string8 ret;
ret << "dsp_chain_config: " << count << " items";
for (size_t walk = 0; walk < count; ++walk) {
ret << "\n" << get_item(walk).debug();
}
return ret;
}
void dsp_preset::contents_to_stream(stream_writer * p_stream,abort_callback & p_abort) const {
t_uint32 size = pfc::downcast_guarded<t_uint32>(get_data_size());
p_stream->write_lendian_t(get_owner(),p_abort);
@@ -470,24 +431,6 @@ bool dsp_chain_config::equals(dsp_chain_config const & v1, dsp_chain_config cons
}
return true;
}
bool dsp_chain_config::equals_debug(dsp_chain_config const& v1, dsp_chain_config const& v2) {
FB2K_DebugLog() << "Comparing DSP chains";
const t_size count = v1.get_count();
if (count != v2.get_count()) {
FB2K_DebugLog() << "Count mismatch, " << count << " vs " << v2.get_count();
return false;
}
for (t_size walk = 0; walk < count; ++walk) {
if (v1.get_item(walk) != v2.get_item(walk)) {
FB2K_DebugLog() << "Item " << (walk+1) << " mismatch";
FB2K_DebugLog() << "Item 1: " << v1.get_item(walk).debug();
FB2K_DebugLog() << "Item 2: " << v2.get_item(walk).debug();
return false;
}
}
FB2K_DebugLog() << "DSP chains are identical";
return true;
}
void dsp_chain_config::get_name_list(pfc::string_base & p_out) const
{
const t_size count = get_count();
@@ -537,20 +480,4 @@ bool dsp_entry_v2::show_config_popup(dsp_preset & p_data,HWND p_parent) {
return true;
}
void resampler_manager::make_chain_(dsp_chain_config& outChain, unsigned rateFrom, unsigned rateTo, float qualityScale) {
resampler_manager_v2::ptr v2;
if (v2 &= this) {
v2->make_chain(outChain, rateFrom, rateTo, qualityScale);
} else {
outChain.remove_all();
auto obj = this->get_resampler(rateFrom, rateTo);
if (obj.is_valid()) {
dsp_preset_impl p;
if (obj->create_preset(p, rateTo, qualityScale)) {
outChain.add_item(p);
}
}
}
}
#endif // FOOBAR2000_HAVE_DSP

View File

@@ -76,7 +76,8 @@ public:
virtual void run_v2(dsp_chunk_list * p_chunk_list,const metadb_handle_ptr & p_cur_file,int p_flags,abort_callback & p_abort) = 0;
private:
void run(dsp_chunk_list * p_chunk_list,const metadb_handle_ptr & p_cur_file,int p_flags) {
run_v2(p_chunk_list,p_cur_file,p_flags,fb2k::noAbort);
abort_callback_dummy dummy;
run_v2(p_chunk_list,p_cur_file,p_flags,dummy);
}
FB2K_MAKE_SERVICE_INTERFACE(dsp_v2,dsp);
@@ -205,10 +206,6 @@ public:
bool operator!=(const dsp_preset & p_other) const {
return !(*this == p_other);
}
pfc::string8 get_owner_name() const;
pfc::string8 get_owner_name_debug() const;
pfc::string8 debug() const;
protected:
dsp_preset() {}
~dsp_preset() {}
@@ -451,9 +448,6 @@ public:
void get_name_list(pfc::string_base & p_out) const;
static bool equals(dsp_chain_config const & v1, dsp_chain_config const & v2);
static bool equals_debug(dsp_chain_config const& v1, dsp_chain_config const& v2);
pfc::string8 debug() const;
bool operator==(const dsp_chain_config & other) const {return equals(*this, other);}
bool operator!=(const dsp_chain_config & other) const {return !equals(*this, other);}
@@ -525,7 +519,7 @@ private:
//! Helper.
class dsp_preset_parser : public stream_reader_formatter<> {
public:
dsp_preset_parser(const dsp_preset & in) : m_data(in), _m_stream(in.get_data(),in.get_data_size()), stream_reader_formatter(_m_stream,fb2k::noAbort) {}
dsp_preset_parser(const dsp_preset & in) : m_data(in), _m_stream(in.get_data(),in.get_data_size()), stream_reader_formatter(_m_stream,_m_abort) {}
void reset() {_m_stream.reset();}
t_size get_remaining() const {return _m_stream.get_remaining();}
@@ -537,13 +531,14 @@ public:
GUID get_owner() const {return m_data.get_owner();}
private:
const dsp_preset & m_data;
abort_callback_dummy _m_abort;
stream_reader_memblock_ref _m_stream;
};
//! Helper.
class dsp_preset_builder : public stream_writer_formatter<> {
public:
dsp_preset_builder() : stream_writer_formatter(_m_stream,fb2k::noAbort) {}
dsp_preset_builder() : stream_writer_formatter(_m_stream,_m_abort) {}
void finish(const GUID & id, dsp_preset & out) {
out.set_owner(id);
out.set_data(_m_stream.m_buffer.get_ptr(), _m_stream.m_buffer.get_size());
@@ -552,6 +547,7 @@ public:
_m_stream.m_buffer.set_size(0);
}
private:
abort_callback_dummy _m_abort;
stream_writer_buffer_simple _m_stream;
};

View File

@@ -64,7 +64,7 @@ double dsp_manager::run(dsp_chunk_list * p_list,const metadb_handle_ptr & p_cur_
}
// Recycle existing DSPs in a special case when user has apparently only altered settings of one of DSPs.
//HACK: recycle existing DSPs in a special case when user has apparently only altered settings of one of DSPs.
if (newchain.get_count() == m_chain.get_count()) {
t_size data_mismatch_count = 0;
t_size owner_mismatch_count = 0;

View File

@@ -5,7 +5,7 @@
//! Helper class for running audio data through a DSP chain.
class dsp_manager {
public:
dsp_manager() {}
dsp_manager() : m_config_changed(false) {}
//! Alters the DSP chain configuration. Should be called before the first run() to set the configuration but can be also called anytime later between run() calls.
void set_config( const dsp_chain_config & p_data );
@@ -32,7 +32,7 @@ private:
t_dsp_chain m_chain;
dsp_chain_config_impl m_config;
bool m_config_changed = false;
bool m_config_changed;
void dsp_run(t_dsp_chain::const_iterator p_iter,dsp_chunk_list * list,const metadb_handle_ptr & cur_file,unsigned flags,double & latency,abort_callback&);

View File

@@ -1,12 +1,3 @@
#pragma once
#if defined(FOOBAR2000_DESKTOP) || PFC_DEBUG
// RATIONALE
// Mobile target doesn't really care about event logging, logger interface exists there only for source compat
// We can use macros to suppress all PFC_string_formatter bloat for targets that do not care about any of this
#define FB2K_HAVE_EVENT_LOGGER
#endif
class NOVTABLE event_logger : public service_base {
FB2K_MAKE_SERVICE_INTERFACE(event_logger, service_base);
public:
@@ -35,16 +26,8 @@ public:
static event_logger_recorder::ptr create();
};
#ifdef FB2K_HAVE_EVENT_LOGGER
#define FB2K_LOG_STATUS(X,Y) (X)->log_status(Y)
#define FB2K_LOG_WARNING(X,Y) (X)->log_warning(Y)
#define FB2K_LOG_ERROR(X,Y) (X)->log_error(Y)
#else
#define FB2K_LOG_STATUS(X,Y) ((void)0)
#define FB2K_LOG_WARNING(X,Y) ((void)0)
#define FB2K_LOG_ERROR(X,Y) ((void)0)
#endif
#define FB2K_HAVE_EVENT_LOGGER

View File

@@ -11,3 +11,5 @@ PFC_DECLARE_EXCEPTION(exception_osfailure, exception_messagebox, "Internal error
PFC_DECLARE_EXCEPTION(exception_out_of_resources, exception_messagebox, "Not enough system resources available.");
PFC_DECLARE_EXCEPTION(exception_configdamaged, exception_messagebox, "Internal error - configuration files are unreadable.");
PFC_DECLARE_EXCEPTION(exception_profileaccess, exception_messagebox, "Internal error - cannot access configuration folder.");

View File

@@ -3,7 +3,7 @@ namespace {
#define FILE_CACHED_DEBUG_LOG 0
class file_cached_impl_v2 : public service_multi_inherit< file_cached, file_lowLevelIO > {
class file_cached_impl_v2 : public file_cached {
public:
enum {minBlockSize = 4096};
enum {maxSkipSize = 128*1024};
@@ -20,15 +20,6 @@ public:
m_can_seek = m_base->can_seek();
_reinit(p_abort);
}
size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override {
abort.check();
file_lowLevelIO::ptr ll;
if ( ll &= m_base ) {
flush_buffer();
return ll->lowLevelIO(guid, arg1, arg2, arg2size, abort );
}
return 0;
}
private:
void _reinit(abort_callback & p_abort) {
m_position = 0;
@@ -222,7 +213,7 @@ private:
size_t m_readSize;
};
class file_cached_impl : public service_multi_inherit< file_cached, file_lowLevelIO > {
class file_cached_impl : public file_cached {
public:
file_cached_impl(t_size blocksize) {
m_buffer.set_size(blocksize);
@@ -249,15 +240,7 @@ private:
flush_buffer();
}
public:
size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override {
abort.check();
file_lowLevelIO::ptr ll;
if ( ll &= m_base ) {
flush_buffer();
return ll->lowLevelIO(guid, arg1, arg2, arg2size, abort);
}
return 0;
}
t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
t_uint8 * outptr = (t_uint8*)p_buffer;
t_size done = 0;

View File

@@ -5,9 +5,6 @@
#define _atoi64 atoll
#endif
const float replaygain_info::peak_invalid = -1;
const float replaygain_info::gain_invalid = -1000;
t_size file_info::meta_find_ex(const char * p_name,t_size p_name_length) const
{
t_size n, m = meta_get_count();
@@ -414,19 +411,6 @@ void file_info::info_calculate_bitrate(t_filesize p_filesize,double p_length)
if ( b > 0 ) info_set_bitrate(b);
}
bool file_info::is_encoding_overkill() const {
auto bs = info_get_int("bitspersample");
auto extra = info_get("bitspersample_extra");
if ( bs <= 24 ) return false; // fixedpoint up to 24bit, OK
if ( bs > 32 ) return true; // fixed or float beyond 32bit, overkill
if ( extra != nullptr ) {
if (strcmp(extra, "fixed-point") == 0) return true; // int32, overkill
}
return false;
}
bool file_info::is_encoding_lossy() const {
const char * encoding = info_get("encoding");
if (encoding != NULL) {
@@ -766,4 +750,4 @@ audio_chunk::spec_t file_info::audio_chunk_spec() const
rv.chanMask = audio_chunk::g_guess_channel_config( rv.chanCount );
}
return rv;
}
}

View File

@@ -7,7 +7,7 @@ struct replaygain_info
enum {text_buffer_size = 16 };
typedef char t_text_buffer[text_buffer_size];
static const float peak_invalid, gain_invalid;
enum { peak_invalid = -1, gain_invalid = -1000 };
static bool g_format_gain(float p_value,char p_buffer[text_buffer_size]);
static bool g_format_peak(float p_value,char p_buffer[text_buffer_size]);
@@ -18,15 +18,14 @@ struct replaygain_info
inline bool format_album_peak(char p_buffer[text_buffer_size]) const {return g_format_peak(m_album_peak,p_buffer);}
inline bool format_track_peak(char p_buffer[text_buffer_size]) const {return g_format_peak(m_track_peak,p_buffer);}
static float g_parse_gain_text(const char * p_text, t_size p_text_len = SIZE_MAX);
void set_album_gain_text(const char * p_text,t_size p_text_len = SIZE_MAX);
void set_track_gain_text(const char * p_text,t_size p_text_len = SIZE_MAX);
void set_album_peak_text(const char * p_text,t_size p_text_len = SIZE_MAX);
void set_track_peak_text(const char * p_text,t_size p_text_len = SIZE_MAX);
void set_album_gain_text(const char * p_text,t_size p_text_len = pfc_infinite);
void set_track_gain_text(const char * p_text,t_size p_text_len = pfc_infinite);
void set_album_peak_text(const char * p_text,t_size p_text_len = pfc_infinite);
void set_track_peak_text(const char * p_text,t_size p_text_len = pfc_infinite);
static bool g_is_meta_replaygain(const char * p_name,t_size p_name_len = SIZE_MAX);
static bool g_is_meta_replaygain(const char * p_name,t_size p_name_len = pfc_infinite);
bool set_from_meta_ex(const char * p_name,t_size p_name_len,const char * p_value,t_size p_value_len);
inline bool set_from_meta(const char * p_name,const char * p_value) {return set_from_meta_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline bool set_from_meta(const char * p_name,const char * p_value) {return set_from_meta_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
inline bool is_album_gain_present() const {return m_album_gain != gain_invalid;}
inline bool is_track_gain_present() const {return m_track_gain != gain_invalid;}
@@ -158,29 +157,29 @@ public:
bool info_remove_ex(const char * p_name,t_size p_name_length);
const char * info_get_ex(const char * p_name,t_size p_name_length) const;
inline t_size meta_find(const char * p_name) const {return meta_find_ex(p_name,SIZE_MAX);}
inline bool meta_exists(const char * p_name) const {return meta_exists_ex(p_name,SIZE_MAX);}
inline void meta_remove_field(const char * p_name) {meta_remove_field_ex(p_name,SIZE_MAX);}
inline t_size meta_set(const char * p_name,const char * p_value) {return meta_set_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline void meta_insert_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_insert_value_ex(p_index,p_value_index,p_value,SIZE_MAX);}
inline void meta_add_value(t_size p_index,const char * p_value) {meta_add_value_ex(p_index,p_value,SIZE_MAX);}
inline const char* meta_get(const char * p_name,t_size p_index) const {return meta_get_ex(p_name,SIZE_MAX,p_index);}
inline t_size meta_get_count_by_name(const char * p_name) const {return meta_get_count_by_name_ex(p_name,SIZE_MAX);}
inline t_size meta_add(const char * p_name,const char * p_value) {return meta_add_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline void meta_modify_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_modify_value_ex(p_index,p_value_index,p_value,SIZE_MAX);}
inline t_size meta_find(const char * p_name) const {return meta_find_ex(p_name,pfc_infinite);}
inline bool meta_exists(const char * p_name) const {return meta_exists_ex(p_name,pfc_infinite);}
inline void meta_remove_field(const char * p_name) {meta_remove_field_ex(p_name,pfc_infinite);}
inline t_size meta_set(const char * p_name,const char * p_value) {return meta_set_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
inline void meta_insert_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_insert_value_ex(p_index,p_value_index,p_value,pfc_infinite);}
inline void meta_add_value(t_size p_index,const char * p_value) {meta_add_value_ex(p_index,p_value,pfc_infinite);}
inline const char* meta_get(const char * p_name,t_size p_index) const {return meta_get_ex(p_name,pfc_infinite,p_index);}
inline t_size meta_get_count_by_name(const char * p_name) const {return meta_get_count_by_name_ex(p_name,pfc_infinite);}
inline t_size meta_add(const char * p_name,const char * p_value) {return meta_add_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
inline void meta_modify_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_modify_value_ex(p_index,p_value_index,p_value,pfc_infinite);}
inline t_size info_set(const char * p_name,const char * p_value) {return info_set_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline t_size info_find(const char * p_name) const {return info_find_ex(p_name,SIZE_MAX);}
inline bool info_exists(const char * p_name) const {return info_exists_ex(p_name,SIZE_MAX);}
inline bool info_remove(const char * p_name) {return info_remove_ex(p_name,SIZE_MAX);}
inline const char * info_get(const char * p_name) const {return info_get_ex(p_name,SIZE_MAX);}
inline t_size info_set(const char * p_name,const char * p_value) {return info_set_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
inline t_size info_find(const char * p_name) const {return info_find_ex(p_name,pfc_infinite);}
inline bool info_exists(const char * p_name) const {return info_exists_ex(p_name,pfc_infinite);}
inline bool info_remove(const char * p_name) {return info_remove_ex(p_name,pfc_infinite);}
inline const char * info_get(const char * p_name) const {return info_get_ex(p_name,pfc_infinite);}
bool info_set_replaygain_ex(const char * p_name,t_size p_name_len,const char * p_value,t_size p_value_len);
inline bool info_set_replaygain(const char * p_name,const char * p_value) {return info_set_replaygain_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline bool info_set_replaygain(const char * p_name,const char * p_value) {return info_set_replaygain_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
void info_set_replaygain_auto_ex(const char * p_name,t_size p_name_len,const char * p_value,t_size p_value_len);
inline void info_set_replaygain_auto(const char * p_name,const char * p_value) {info_set_replaygain_auto_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline void info_set_replaygain_auto(const char * p_name,const char * p_value) {info_set_replaygain_auto_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
@@ -188,12 +187,12 @@ public:
void copy_info_single(const file_info & p_source,t_size p_index);
void copy_meta_single_by_name_ex(const file_info & p_source,const char * p_name,t_size p_name_length);
void copy_info_single_by_name_ex(const file_info & p_source,const char * p_name,t_size p_name_length);
inline void copy_meta_single_by_name(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_ex(p_source,p_name,SIZE_MAX);}
inline void copy_info_single_by_name(const file_info & p_source,const char * p_name) {copy_info_single_by_name_ex(p_source,p_name,SIZE_MAX);}
inline void copy_meta_single_by_name(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_ex(p_source,p_name,pfc_infinite);}
inline void copy_info_single_by_name(const file_info & p_source,const char * p_name) {copy_info_single_by_name_ex(p_source,p_name,pfc_infinite);}
void reset();
void reset_replaygain();
void copy_meta_single_rename_ex(const file_info & p_source,t_size p_index,const char * p_new_name,t_size p_new_name_length);
inline void copy_meta_single_rename(const file_info & p_source,t_size p_index,const char * p_new_name) {copy_meta_single_rename_ex(p_source,p_index,p_new_name,SIZE_MAX);}
inline void copy_meta_single_rename(const file_info & p_source,t_size p_index,const char * p_new_name) {copy_meta_single_rename_ex(p_source,p_index,p_new_name,pfc_infinite);}
void overwrite_info(const file_info & p_source);
void overwrite_meta(const file_info & p_source);
@@ -216,7 +215,6 @@ public:
uint32_t info_get_wfx_chanMask() const;
bool is_encoding_lossy() const;
bool is_encoding_overkill() const;
void info_calculate_bitrate(t_filesize p_filesize,double p_length);
@@ -243,16 +241,16 @@ public:
//! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally.
t_size __meta_add_unsafe_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) {return meta_set_nocheck_ex(p_name,p_name_length,p_value,p_value_length);}
//! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally.
t_size __meta_add_unsafe(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
t_size __meta_add_unsafe(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
//! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally.
t_size __info_add_unsafe_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) {return info_set_nocheck_ex(p_name,p_name_length,p_value,p_value_length);}
//! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally.
t_size __info_add_unsafe(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
t_size __info_add_unsafe(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
void _copy_meta_single_nocheck(const file_info & p_source,t_size p_index) {copy_meta_single_nocheck(p_source, p_index);}
static bool g_is_valid_field_name(const char * p_name,t_size p_length = SIZE_MAX);
static bool g_is_valid_field_name(const char * p_name,t_size p_length = pfc_infinite);
//typedef pfc::comparator_stricmp_ascii field_name_comparator;
typedef pfc::string::comparatorCaseInsensitiveASCII field_name_comparator;
@@ -277,11 +275,11 @@ protected:
void copy_info_single_nocheck(const file_info & p_source,t_size p_index);
void copy_meta_single_by_name_nocheck_ex(const file_info & p_source,const char * p_name,t_size p_name_length);
void copy_info_single_by_name_nocheck_ex(const file_info & p_source,const char * p_name,t_size p_name_length);
inline void copy_meta_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_nocheck_ex(p_source,p_name,SIZE_MAX);}
inline void copy_info_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_info_single_by_name_nocheck_ex(p_source,p_name,SIZE_MAX);}
inline void copy_meta_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_nocheck_ex(p_source,p_name,pfc_infinite);}
inline void copy_info_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_info_single_by_name_nocheck_ex(p_source,p_name,pfc_infinite);}
virtual t_size meta_set_nocheck_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) = 0;
virtual t_size info_set_nocheck_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) = 0;
inline t_size meta_set_nocheck(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline t_size info_set_nocheck(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);}
inline t_size meta_set_nocheck(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
inline t_size info_set_nocheck(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);}
};

View File

@@ -1,46 +0,0 @@
#pragma once
#include "tracks.h"
//! Implementing this class gives you direct control over which part of file_info gets altered during a tag update uperation. To be used with metadb_io_v2::update_info_async().
class NOVTABLE file_info_filter : public service_base {
FB2K_MAKE_SERVICE_INTERFACE(file_info_filter, service_base);
public:
//! Alters specified file_info entry; called as a part of tag update process. Specified file_info has been read from a file, and will be written back.\n
//! WARNING: This will be typically called from another thread than main app thread (precisely, from thread created by tag updater). You should copy all relevant data to members of your file_info_filter instance in constructor and reference only member data in apply_filter() implementation.
//! @returns True when you have altered file_info and changes need to be written back to the file; false if no changes have been made.
virtual bool apply_filter(trackRef p_location, t_filestats p_stats, file_info & p_info) = 0;
typedef std::function< bool (trackRef, t_filestats, file_info & ) > func_t;
static file_info_filter::ptr create( func_t f );
};
//! Extended file_info_filter allowing the caller to do their own manipulation of the file before and after the metadata update takes place. \n
//! Respected by foobar2000 v1.5 and up; if metadb_io_v4 is supported, then file_info_filter_v2 is understood.
class NOVTABLE file_info_filter_v2 : public file_info_filter {
FB2K_MAKE_SERVICE_INTERFACE(file_info_filter_v2, file_info_filter);
public:
enum filterStatus_t {
filterNoUpdate = 0,
filterProceed,
filterAlreadyUpdated
};
//! Called after just before rewriting metadata. The file is not yet opened for writing, but a file_lock has already been granted (so don't call it on your own). \n
//! You can use this method to perform album art updates (via album_art_editor API) alongside metadata updates. \n
//! Return value can be used to stop fb2k from proceeding with metadata update on this file. \n
//! If your own operations on this file fail, just pass the exceptions to the caller and they will be reported just as other tag update errors.
//! @param fileIfAlreadyOpened Reference to an already opened file object, if already opened by the caller. May be null.
virtual filterStatus_t before_tag_update(const char * location, file::ptr fileIfAlreadyOpened, abort_callback & aborter) = 0;
//! Called after metadata has been updated. \n
//! If you wish to alter the file on your own, use before_tag_update() for this instead. \n
//! If your own operations on this file fail, just pass the exceptions to the caller and they will be reported just as other tag update errors. \n
//! The passed reader object can be used to read the properties of the updated file back. In most cases it will be the writer that was used to update the tags. Do not call tag writing methods on it from this function.
virtual void after_tag_update(const char * location, service_ptr_t<class input_info_reader> reader, abort_callback & aborter) = 0;
virtual void after_all_tag_updates(abort_callback & aborter) = 0;
//! Allows you to do your own error logging.
//! @returns True if the error has been noted by your code and does not need to be shown to the user.
virtual bool filter_error(const char * location, const char * msg) = 0;
};

View File

@@ -1,33 +0,0 @@
#pragma once
//! Generic implementation of file_info_filter_impl.
class file_info_filter_impl : public file_info_filter {
public:
file_info_filter_impl(const pfc::list_base_const_t<metadb_handle_ptr> & p_list, const pfc::list_base_const_t<const file_info*> & p_new_info) {
FB2K_DYNAMIC_ASSERT(p_list.get_count() == p_new_info.get_count());
pfc::array_t<t_size> order;
order.set_size(p_list.get_count());
order_helper::g_fill(order.get_ptr(), order.get_size());
p_list.sort_get_permutation_t(pfc::compare_t<metadb_handle_ptr, metadb_handle_ptr>, order.get_ptr());
m_handles.set_count(order.get_size());
m_infos.set_size(order.get_size());
for (t_size n = 0; n < order.get_size(); n++) {
m_handles[n] = p_list[order[n]];
m_infos[n] = *p_new_info[order[n]];
}
}
bool apply_filter(metadb_handle_ptr p_location, t_filestats p_stats, file_info & p_info) {
t_size index;
if (m_handles.bsearch_t(pfc::compare_t<metadb_handle_ptr, metadb_handle_ptr>, p_location, index)) {
p_info = m_infos[index];
return true;
}
else {
return false;
}
}
private:
metadb_handle_list m_handles;
pfc::array_t<file_info_impl> m_infos;
};

View File

@@ -30,23 +30,6 @@ public:
typedef service_ptr_t<file_lock> file_lock_ptr;
//! \since 1.5
//! Modern version of file locking. \n
//! A read lock can be interrupted by a write lock request, from the thread that requested writing. \n
class NOVTABLE file_lock_interrupt : public service_base {
FB2K_MAKE_SERVICE_INTERFACE(file_lock_interrupt, service_base);
public:
//! Please note that interrupt() is called outside any sync scopes and may be called after lock reference has been released. \n
//! It is implementer's responsibility to safeguard against such. \n
//! The interrupt() function must *never* fail, unless aborted by calling context - which means that whoever asked for write access is aborting whatever they're doing. \n
//! This function may block for as long as it takes to release the owned resources, but must be able to abort cleanly if doing so. \n
//! If the function was aborted, it may be called again on the same object. \n
//! If the function succeeded, it will not be called again on the same object; the object will be released immediately after.
virtual void interrupt( abort_callback & aborter ) = 0;
static file_lock_interrupt::ptr create( std::function< void (abort_callback&)> );
};
//! Entry point class for obtaining file_lock objects.
class NOVTABLE file_lock_manager : public service_base {
public:
@@ -68,10 +51,3 @@ public:
FB2K_MAKE_SERVICE_COREAPI(file_lock_manager);
};
// \since 1.5
class NOVTABLE file_lock_manager_v2 : public file_lock_manager {
FB2K_MAKE_SERVICE_COREAPI_EXTENSION( file_lock_manager_v2, file_lock_manager );
public:
virtual fb2k::objRef acquire_read_v2(const char * p_path, file_lock_interrupt::ptr interruptHandler, abort_callback & p_abort) = 0;
};

View File

@@ -210,7 +210,7 @@ void filesystem::g_move(const char * src,const char * dst,abort_callback & p_abo
void filesystem::g_link(const char * p_src,const char * p_dst,abort_callback & p_abort) {
if (!foobar2000_io::_extract_native_path_ptr(p_src) || !foobar2000_io::_extract_native_path_ptr(p_dst)) throw exception_io_no_handler_for_path();
WIN32_IO_OP( CreateHardLink( pfc::stringcvt::string_os_from_utf8( pfc::winPrefixPath( p_dst ) ), pfc::stringcvt::string_os_from_utf8( pfc::winPrefixPath( p_src ) ), NULL) );
WIN32_IO_OP( CreateHardLink( pfc::stringcvt::string_os_from_utf8( p_dst ), pfc::stringcvt::string_os_from_utf8( p_src ), NULL) );
}
void filesystem::g_link_timeout(const char * p_src,const char * p_dst,double p_timeout,abort_callback & p_abort) {
@@ -300,11 +300,7 @@ bool filesystem::g_relative_path_parse(const char * relative_path,const char * p
return false;
}
bool archive::is_our_archive( const char * path ) {
archive_v2::ptr v2;
if ( v2 &= this ) return v2->is_our_archive( path );
return true; // accept all files
}
bool archive_impl::get_canonical_path(const char * path,pfc::string_base & out)
{
@@ -551,7 +547,8 @@ namespace {
file::g_transfer_object(r_src,r_dst,size,p_abort);
} catch(...) {
r_dst.release();
try {m_fs->remove(dst,fb2k::noAbort);} catch(...) {}
abort_callback_dummy dummy;
try {m_fs->remove(dst,dummy);} catch(...) {}
throw;
}
}
@@ -612,14 +609,11 @@ void filesystem::g_copy(const char * src,const char * dst,abort_callback & p_abo
file::g_transfer_object(r_src,r_dst,size,p_abort);
} catch(...) {
r_dst.release();
try {g_remove(dst,fb2k::noAbort);} catch(...) {}
abort_callback_dummy dummy;
try {g_remove(dst,dummy);} catch(...) {}
throw;
}
}
try {
file::g_copy_timestamps(r_src, r_dst, p_abort);
} catch (exception_io) {}
}
void stream_reader::read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
@@ -679,7 +673,8 @@ void filesystem::g_open_tempmem(service_ptr_t<file> & p_out,abort_callback & p_a
}
file::ptr filesystem::g_open_tempmem() {
file::ptr f; g_open_tempmem(f, fb2k::noAbort); return f;
abort_callback_dummy aborter;
file::ptr f; g_open_tempmem(f, aborter); return f;
}
void archive_impl::list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort) {
@@ -715,21 +710,6 @@ bool file::is_eof(abort_callback & p_abort) {
}
t_filetimestamp foobar2000_io::import_DOS_time(uint32_t v) {
#ifdef _WIN32
FILETIME ft = {};
if (DosDateTimeToFileTime(HIWORD(v), LOWORD(v), &ft)) {
FILETIME ft2 = {};
if (LocalFileTimeToFileTime(&ft, &ft2)) {
return ((uint64_t)ft2.dwHighDateTime << 32) | (uint64_t)ft2.dwLowDateTime;
}
}
#endif
// FIX ME
return filetimestamp_invalid;
}
t_filetimestamp foobar2000_io::filetimestamp_from_system_timer()
{
return pfc::fileTimeNow();
@@ -803,18 +783,7 @@ namespace {
class exception_io_win32_ex : public exception_io_win32 {
public:
static pfc::string8 format(DWORD code) {
pfc::string8 ret;
ret << "I/O error (win32 ";
if (code & 0x80000000) {
ret << "0x" << pfc::format_hex(code, 8);
} else {
ret << "#" << (uint32_t)code;
}
ret << ")";
return ret;
}
exception_io_win32_ex(DWORD p_code) : m_msg(format(p_code)) {}
exception_io_win32_ex(DWORD p_code) : m_msg(pfc::string_formatter() << "I/O error (win32 #" << (t_uint32)p_code << ")") {}
exception_io_win32_ex(const exception_io_win32_ex & p_other) {*this = p_other;}
const char * what() const throw() {return m_msg;}
private:
@@ -832,7 +801,7 @@ PFC_NORETURN void foobar2000_io::win32_file_write_failure(DWORD p_code, const ch
PFC_NORETURN void foobar2000_io::exception_io_from_win32(DWORD p_code) {
#if PFC_DEBUG
PFC_DEBUGLOG << "exception_io_from_win32: " << p_code;
pfc::debugLog() << "exception_io_from_win32: " << p_code;
#endif
//pfc::string_fixed_t<32> debugMsg; debugMsg << "Win32 I/O error #" << (t_uint32)p_code;
//TRACK_CALL_TEXT(debugMsg);
@@ -890,7 +859,6 @@ PFC_NORETURN void foobar2000_io::exception_io_from_win32(DWORD p_code) {
case ERROR_BAD_NETPATH:
// known to be inflicted by momentary net connectivity issues - NOT the same as exception_io_not_found
throw exception_io("Network path not found");
#if FB2K_SUPPORT_TRANSACTED_FILESYSTEM
case ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED:
case ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE:
case ERROR_RM_NOT_ACTIVE:
@@ -901,16 +869,9 @@ PFC_NORETURN void foobar2000_io::exception_io_from_win32(DWORD p_code) {
throw exception_io_transactional_conflict();
case ERROR_TRANSACTION_ALREADY_ABORTED:
throw exception_io_transaction_aborted();
case ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION:
throw exception_io("Transacted updates of encrypted content are not supported");
#endif // FB2K_SUPPORT_TRANSACTED_FILESYSTEM
case ERROR_UNEXP_NET_ERR:
// QNAP threw this when messing with very long file paths and concurrent conversion, probably SMB daemon crashed
throw exception_io("Unexpected network error");
case ERROR_NOT_SAME_DEVICE:
throw exception_io("Source and destination must be on the same device");
case 0x80310000:
throw exception_io("Drive locked by BitLocker");
throw exception_io("Unexpected netwrok error");
default:
throw exception_io_win32_ex(p_code);
}
@@ -1049,17 +1010,6 @@ bool foobar2000_io::extract_native_path_ex(const char * p_fspath, pfc::string_ba
return true;
}
bool foobar2000_io::extract_native_path_archive_aware(const char * in, pfc::string_base & out) {
if (foobar2000_io::extract_native_path(in, out)) return true;
if (archive_impl::g_is_unpack_path(in)) {
pfc::string8 arc, dummy;
if (archive_impl::g_parse_unpack_path(in, arc, dummy)) {
return foobar2000_io::extract_native_path(arc, out);
}
}
return false;
}
pfc::string stream_reader::read_string(abort_callback & p_abort) {
t_uint32 len;
read_lendian_t(len,p_abort);
@@ -1169,8 +1119,7 @@ bool foobar2000_io::matchContentType(const char * fullString, const char * ourTy
const char * foobar2000_io::contentTypeFromExtension( const char * ext ) {
if ( pfc::stringEqualsI_ascii( ext, "mp3" ) ) return "audio/mpeg";
if ( pfc::stringEqualsI_ascii( ext, "flac" ) ) return "audio/flac";
if ( pfc::stringEqualsI_ascii( ext, "mp4" ) ) return "application/mp4"; // We don't know if it's audio-only or other.
if ( pfc::stringEqualsI_ascii( ext, "m4a" ) ) return "audio/mp4";
if ( pfc::stringEqualsI_ascii( ext, "mp4" ) || pfc::stringEqualsI_ascii( ext, "m4a" ) ) return "audio/mp4";
if ( pfc::stringEqualsI_ascii( ext, "mpc" ) ) return "audio/musepack";
if ( pfc::stringEqualsI_ascii( ext, "ogg" ) ) return "audio/ogg";
if ( pfc::stringEqualsI_ascii( ext, "opus" ) ) return "audio/opus";
@@ -1183,7 +1132,6 @@ const char * foobar2000_io::contentTypeFromExtension( const char * ext ) {
const char * foobar2000_io::extensionFromContentType( const char * contentType ) {
if (matchContentType_MP3( contentType )) return "mp3";
if (matchContentType_FLAC( contentType )) return "flac";
if (matchContentType_MP4audio( contentType)) return "m4a";
if (matchContentType_MP4( contentType)) return "mp4";
if (matchContentType_Musepack( contentType )) return "mpc";
if (matchContentType_Ogg( contentType )) return "ogg";
@@ -1199,12 +1147,6 @@ bool foobar2000_io::matchContentType_MP3( const char * type) {
return matchContentType(type,"audio/mp3") || matchContentType(type,"audio/mpeg") || matchContentType(type,"audio/mpg") || matchContentType(type,"audio/x-mp3") || matchContentType(type,"audio/x-mpeg") || matchContentType(type,"audio/x-mpg");
}
bool foobar2000_io::matchContentType_MP4( const char * type ) {
return matchContentType(type, "audio/mp4") || matchContentType(type, "audio/x-mp4")
|| matchContentType(type, "video/mp4") || matchContentType(type, "video/x-mp4")
|| matchContentType(type, "application/mp4") || matchContentType(type, "application/x-mp4");
}
bool foobar2000_io::matchContentType_MP4audio( const char * type ) {
return matchContentType(type, "audio/mp4") || matchContentType(type, "audio/x-mp4");
}
bool foobar2000_io::matchContentType_Ogg( const char * type) {
@@ -1414,7 +1356,6 @@ void filesystem::rewrite_file(const char * path, abort_callback & abort, double
{
auto f = this->openWriteNew( temp, abort, opTimeout );
worker(f);
f->flushFileBuffers_( abort );
}
retryOnSharingViolation(opTimeout, abort, [&] {
@@ -1423,7 +1364,8 @@ void filesystem::rewrite_file(const char * path, abort_callback & abort, double
} catch(...) {
try {
retryOnSharingViolation(opTimeout, abort, [&] { this->remove(temp, fb2k::noAbort); } );
abort_callback_dummy noAbort;
retryOnSharingViolation(opTimeout, abort, [&] { this->remove(temp, noAbort); } );
} catch(...) {}
throw;
}
@@ -1528,72 +1470,7 @@ bool filesystem::commit_if_transacted(abort_callback &abort) {
return rv;
}
t_filestats filesystem::get_stats(const char * path, abort_callback & abort) {
t_filestats s; bool dummy;
this->get_stats(path, s, dummy, abort);
return s;
}
bool file_dynamicinfo_v2::get_dynamic_info(class file_info & p_out) {
t_filesize dummy = 0;
return this->get_dynamic_info_v2(p_out, dummy);
}
void file::flushFileBuffers_(abort_callback&a) {
file_lowLevelIO::ptr f;
if ( f &= this ) f->flushFileBuffers(a);
}
size_t file::lowLevelIO_(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) {
size_t retval = 0;
file_lowLevelIO::ptr f;
if (f &= this) retval = f->lowLevelIO(guid, arg1, arg2, arg2size, abort);
return retval;
}
bool file_lowLevelIO::flushFileBuffers(abort_callback & abort) {
return this->lowLevelIO( guid_flushFileBuffers, 0, nullptr, 0, abort) != 0;
}
bool file_lowLevelIO::getFileTimes(filetimes_t & out, abort_callback & a) {
return this->lowLevelIO(guid_getFileTimes, 0, &out, sizeof(out), a) != 0;
}
bool file_lowLevelIO::setFileTimes(filetimes_t const & in, abort_callback & a) {
return this->lowLevelIO(guid_setFileTimes, 0, (void*)&in, sizeof(in), a) != 0;
}
bool file::g_copy_creation_time(service_ptr_t<file> from, service_ptr_t<file> to, abort_callback& a) {
file_lowLevelIO::ptr llFrom, llTo;
bool rv = false;
if (llTo &= to) {
if (llFrom &= from) {
file_lowLevelIO::filetimes_t filetimes;
if (llFrom->getFileTimes(filetimes, a)) {
if (filetimes.creation != filetimestamp_invalid) {
file_lowLevelIO::filetimes_t ft2;
ft2.creation = filetimes.creation;
rv = llTo->setFileTimes(ft2, a);
}
}
}
}
return rv;
}
bool file::g_copy_timestamps(file::ptr from, file::ptr to, abort_callback& a) {
file_lowLevelIO::ptr llFrom, llTo;
if ( llTo &= to ) {
if (llFrom &= from) {
file_lowLevelIO::filetimes_t filetimes = {};
if (llFrom->getFileTimes(filetimes, a)) {
return llTo->setFileTimes(filetimes, a);
}
}
file_lowLevelIO::filetimes_t filetimes = {};
filetimes.lastWrite = from->get_timestamp(a);
if ( filetimes.lastWrite != filetimestamp_invalid ) {
return llTo->setFileTimes(filetimes, a);
}
}
return false;
}

View File

@@ -23,8 +23,7 @@ namespace foobar2000_io
PFC_DECLARE_EXCEPTION(exception_io, pfc::exception,"I/O error");
//! Object not found.
PFC_DECLARE_EXCEPTION(exception_io_not_found, exception_io,"Object not found");
//! Access denied. \n
//! Special Windows note: this MAY be thrown instead of exception_io_sharing_violation by operations that rename/move files due to Win32 MoveFile() bugs.
//! Access denied.
PFC_DECLARE_EXCEPTION(exception_io_denied, exception_io,"Access denied");
//! Access denied.
PFC_DECLARE_EXCEPTION(exception_io_denied_readonly, exception_io_denied,"File is read-only");
@@ -269,12 +268,12 @@ namespace foobar2000_io
//! Optional, called by owner thread before sleeping.
//! @param p_abort abort_callback object signaling user aborting the operation.
virtual void on_idle(abort_callback & p_abort) {(void)p_abort;}
virtual void on_idle(abort_callback & p_abort) {}
//! Retrieves last modification time of the file.
//! @param p_abort abort_callback object signaling user aborting the operation.
//! @returns Last modification time o fthe file; filetimestamp_invalid if N/A.
virtual t_filetimestamp get_timestamp(abort_callback & p_abort) {(void)p_abort;return filetimestamp_invalid;}
virtual t_filetimestamp get_timestamp(abort_callback & p_abort) {return filetimestamp_invalid;}
//! Resets non-seekable stream, or seeks to zero on seekable file.
//! @param p_abort abort_callback object signaling user aborting the operation.
@@ -318,19 +317,12 @@ namespace foobar2000_io
static void g_transfer_object(stream_reader * src,stream_writer * dst,t_filesize bytes,abort_callback & p_abort);
//! Helper; transfers entire file content from one file to another, erasing previous content.
static void g_transfer_file(const service_ptr_t<file> & p_from,const service_ptr_t<file> & p_to,abort_callback & p_abort);
//! Helper; transfers file modification times from one file to another, if supported by underlying objects. Returns true on success, false if the operation doesn't appear to be supported.
static bool g_copy_timestamps(service_ptr_t<file> from, service_ptr_t<file> to, abort_callback& abort);
static bool g_copy_creation_time(service_ptr_t<file> from, service_ptr_t<file> to, abort_callback& abort);
//! Helper; improved performance over g_transfer on streams (avoids disk fragmentation when transferring large blocks).
static t_filesize g_transfer(service_ptr_t<file> p_src,service_ptr_t<file> p_dst,t_filesize p_bytes,abort_callback & p_abort);
//! Helper; improved performance over g_transfer_file on streams (avoids disk fragmentation when transferring large blocks).
static void g_transfer_object(service_ptr_t<file> p_src,service_ptr_t<file> p_dst,t_filesize p_bytes,abort_callback & p_abort);
//! file_lowLevelIO wrapper
void flushFileBuffers_(abort_callback &);
//! file_lowLevelIO wrapper
size_t lowLevelIO_(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort);
t_filesize skip(t_filesize p_bytes,abort_callback & p_abort);
t_filesize skip_seek(t_filesize p_bytes,abort_callback & p_abort);
@@ -376,46 +368,6 @@ namespace foobar2000_io
static void g_decodeInitCache(file::ptr & theFile, abort_callback & abort, size_t blockSize);
};
//! \since 1.5
//! Additional service implemented by standard file object providing access to low level OS specific APIs.
class file_lowLevelIO : public service_base {
FB2K_MAKE_SERVICE_INTERFACE(file_lowLevelIO, service_base );
public:
//! @returns 0 if the command was not recognized, a command-defined non zero value otherwise.
virtual size_t lowLevelIO( const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort ) = 0;
//! Win32 FlushFileBuffers() wrapper. \n
//! Throws exception_io_denied on a file opened for reading. \n
//! No arguments are defined. \n
//! Returns 1 if handled, 0 if unsupported.
static const GUID guid_flushFileBuffers;
//! Retrieves file creation / last access / last write times. \n
//! Parameters: arg2 points to a filetimes_t struct to receive the data; arg2size must be set to sizeof(filetimes_t). \n
//! If the filesystem does not support a specific portion of the information, relevant struct member will be set to filetimestamp_invalid. \n
//! Returns 1 if handled, 0 if unsupported.
static const GUID guid_getFileTimes;
//! Sets file creation / last access / last write times. \n
//! Parameters: arg2 points to a filetimes_t struct holding the new data; arg2size must be set to sizeof(filetimes_t). \n
//! Individual members of the filetimes_t struct can be set to filetimestamp_invalid, if not all of the values are to be altered on the file. \n
//! Returns 1 if handled, 0 if unsupported.
static const GUID guid_setFileTimes;
//! Struct to be used with guid_getFileTimes / guid_setFileTimes.
struct filetimes_t {
t_filetimestamp creation = filetimestamp_invalid;
t_filetimestamp lastAccess = filetimestamp_invalid;
t_filetimestamp lastWrite = filetimestamp_invalid;
};
//! Helper
bool flushFileBuffers(abort_callback &);
//! Helper
bool getFileTimes( filetimes_t & out, abort_callback &);
//! Helper
bool setFileTimes( filetimes_t const & in, abort_callback &);
};
//! Implementation helper - contains dummy implementations of methods that modify the file
template<typename t_base> class file_readonly_t : public t_base {
public:
@@ -426,13 +378,13 @@ namespace foobar2000_io
class file_streamstub : public file_readonly {
public:
t_size read(void *,t_size,abort_callback &) {return 0;}
t_filesize get_size(abort_callback &) {return filesize_invalid;}
t_filesize get_position(abort_callback &) {return 0;}
bool get_content_type(pfc::string_base &) {return false;}
t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {return 0;}
t_filesize get_size(abort_callback & p_abort) {return filesize_invalid;}
t_filesize get_position(abort_callback & p_abort) {return 0;}
bool get_content_type(pfc::string_base & p_out) {return false;}
bool is_remote() {return true;}
void reopen(abort_callback&) {}
void seek(t_filesize,abort_callback &) {throw exception_io_object_not_seekable();}
void seek(t_filesize p_position,abort_callback & p_abort) {throw exception_io_object_not_seekable();}
bool can_seek() {return false;}
};
@@ -470,16 +422,12 @@ namespace foobar2000_io
virtual void open(service_ptr_t<file> & p_out,const char * p_path, t_open_mode p_mode,abort_callback & p_abort)=0;
virtual void remove(const char * p_path,abort_callback & p_abort)=0;
//! Moves/renames a file. Will fail if the destination file already exists. \n
//! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
virtual void move(const char * p_src,const char * p_dst,abort_callback & p_abort)=0;
//! Queries whether a file at specified path belonging to this filesystem is a remote object or not.
//! Queries whether a file at specified path belonging to this filesystem is a remove object or not.
virtual bool is_remote(const char * p_src) = 0;
//! Retrieves stats of a file at specified path.
virtual void get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort) = 0;
//! Helper
t_filestats get_stats( const char * path, abort_callback & abort );
virtual bool relative_path_create(const char * file_path,const char * playlist_path,pfc::string_base & out) {return false;}
virtual bool relative_path_parse(const char * relative_path,const char * playlist_path,pfc::string_base & out) {return false;}
@@ -522,7 +470,6 @@ namespace foobar2000_io
//! Attempts to remove file at specified path; if the operation fails with a sharing violation error, keeps retrying (with short sleep period between retries) for specified amount of time.
static void g_remove_timeout(const char * p_path,double p_timeout,abort_callback & p_abort);
//! Moves file from one path to another.
//! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
static void g_move(const char * p_src,const char * p_dst,abort_callback & p_abort);
//! Attempts to move file from one path to another; if the operation fails with a sharing violation error, keeps retrying (with short sleep period between retries) for specified amount of time.
static void g_move_timeout(const char * p_src,const char * p_dst,double p_timeout,abort_callback & p_abort);
@@ -559,12 +506,10 @@ namespace foobar2000_io
// Presumes both source and destination belong to this filesystem.
void copy_directory(const char * p_src, const char * p_dst, abort_callback & p_abort);
//! Moves/renames a file, overwriting the destination atomically if exists. \n
//! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
//! Move file overwriting an existing one. Regular move() will fail if the file exists.
void move_overwrite( const char * src, const char * dst, abort_callback & abort);
//! Moves/renames a file, overwriting the destination atomically if exists. \n
//! Meant to retain destination attributes if feasible. Otherwise identical to move_overwrite(). \n
//! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
//! Same as move_overwrite(). \n
//! This used to call win32 ReplaceFile() but that was pulled due to extreme stupidity of ReplaceFile() implementation.
void replace_file(const char * src, const char * dst, abort_callback & abort);
//! Create a directory, without throwing an exception if it already exists.
//! @param didCreate bool flag indicating whether a new directory was created or not. \n
@@ -598,12 +543,6 @@ namespace foobar2000_io
//! See also: filesystem_transacted. \n
//! In order to perform transacted operations, you must obtain a transacted filesystem explicitly, or get one passed down from a higher level context (example: in config_io_callback_v3).
void rewrite_file( const char * path, abort_callback & abort, double opTimeout, std::function<void (file::ptr) > worker );
//! Full directory rewrite helper that automatically does the right thing to ensure atomic update. \n
//! If this is a transacted filesystem, a simple in-place rewrite is performed. \n
//! If this is not a transacted filesystem, your content first goes to a temporary folder, which then replaces the original. \n
//! It is encouraged to perform flushFileBuffers on all files accessed from within. \n
//! See also: filesystem_transacted. \n
//! In order to perform transacted operations, you must obtain a transacted filesystem explicitly, or get one passed down from a higher level context (example: in config_io_callback_v3).
void rewrite_directory(const char * path, abort_callback & abort, double opTimeout, std::function<void(const char *) > worker);
protected:
static bool get_parent_helper(const char * path, char separator, pfc::string_base & out);
@@ -628,16 +567,8 @@ namespace foobar2000_io
class filesystem_v2 : public filesystem {
FB2K_MAKE_SERVICE_INTERFACE( filesystem_v2, filesystem )
public:
//! Moves/renames a file, overwriting the destination atomically if exists. \n
//! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
virtual void move_overwrite(const char * src, const char * dst, abort_callback & abort) = 0;
//! Moves/renames a file, overwriting the destination atomically if exists. \n
//! Meant to retain destination attributes if feasible. Otherwise identical to move_overwrite(). \n
//! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
virtual void replace_file(const char * src, const char * dst, abort_callback & abort);
//! Create a directory, without throwing an exception if it already exists.
//! @param didCreate bool flag indicating whether a new directory was created or not. \n
//! This should be a retval, but because it's messy to obtain this information with certain APIs, the caller can opt out of receiving this information,.
virtual void make_directory(const char * path, abort_callback & abort, bool * didCreate = nullptr) = 0;
virtual bool directory_exists(const char * path, abort_callback & abort) = 0;
virtual bool file_exists(const char * path, abort_callback & abort) = 0;
@@ -678,9 +609,61 @@ namespace foobar2000_io
void sort() {m_data.sort_t(sortfunc);}
};
class archive;
class NOVTABLE archive_callback : public abort_callback {
public:
virtual bool on_entry(archive * owner,const char * url,const t_filestats & p_stats,const service_ptr_t<file> & p_reader) = 0;
};
//! Interface for archive reader services. When implementing, derive from archive_impl rather than from deriving from archive directly.
class NOVTABLE archive : public filesystem {
public:
virtual void archive_list(const char * p_path,const service_ptr_t<file> & p_reader,archive_callback & p_callback,bool p_want_readers) = 0;
FB2K_MAKE_SERVICE_INTERFACE(archive,filesystem);
};
//! Root class for archive implementations. Derive from this instead of from archive directly.
class NOVTABLE archive_impl : public archive {
private:
//do not override these
bool get_canonical_path(const char * path,pfc::string_base & out);
bool is_our_path(const char * path);
bool get_display_path(const char * path,pfc::string_base & out);
void remove(const char * path,abort_callback & p_abort);
void move(const char * src,const char * dst,abort_callback & p_abort);
bool is_remote(const char * src);
bool relative_path_create(const char * file_path,const char * playlist_path,pfc::string_base & out);
bool relative_path_parse(const char * relative_path,const char * playlist_path,pfc::string_base & out);
void open(service_ptr_t<file> & p_out,const char * path, t_open_mode mode,abort_callback & p_abort);
void create_directory(const char * path,abort_callback &);
void list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort);
void get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort);
protected:
//override these
virtual const char * get_archive_type()=0;//eg. "zip", must be lowercase
virtual t_filestats get_stats_in_archive(const char * p_archive,const char * p_file,abort_callback & p_abort) = 0;
virtual void open_archive(service_ptr_t<file> & p_out,const char * archive,const char * file, abort_callback & p_abort)=0;//opens for reading
public:
//override these
virtual void archive_list(const char * path,const service_ptr_t<file> & p_reader,archive_callback & p_out,bool p_want_readers)=0;
static bool g_is_unpack_path(const char * path);
static bool g_parse_unpack_path(const char * path,pfc::string_base & archive,pfc::string_base & file);
static bool g_parse_unpack_path_ex(const char * path,pfc::string_base & archive,pfc::string_base & file, pfc::string_base & type);
static void g_make_unpack_path(pfc::string_base & path,const char * archive,const char * file,const char * type);
void make_unpack_path(pfc::string_base & path,const char * archive,const char * file);
};
template<typename T>
class archive_factory_t : public service_factory_single_t<T> {};
t_filetimestamp filetimestamp_from_system_timer();
t_filetimestamp import_DOS_time(uint32_t);
#ifdef _WIN32
inline t_filetimestamp import_filetimestamp(FILETIME ft) {
@@ -776,8 +759,6 @@ namespace foobar2000_io
bool is_native_filesystem( const char * p_fspath );
bool extract_native_path_ex(const char * p_fspath, pfc::string_base & p_native);//prepends \\?\ where needed
bool extract_native_path_archive_aware( const char * fspatch, pfc::string_base & out );
template<typename T>
pfc::string getPathDisplay(const T& source) {
const char * c = pfc::stringToPtr(source);
@@ -802,7 +783,6 @@ namespace foobar2000_io
void substituteProtocol(pfc::string_base & out, const char * fullString, const char * protocolName);
bool matchContentType_MP3( const char * fullString);
bool matchContentType_MP4audio( const char * fullString);
bool matchContentType_MP4( const char * fullString);
bool matchContentType_Ogg( const char * fullString);
bool matchContentType_Opus( const char * fullString);
@@ -814,22 +794,6 @@ namespace foobar2000_io
const char * contentTypeFromExtension( const char * ext );
void purgeOldFiles(const char * directory, t_filetimestamp period, abort_callback & abort);
//! \since 1.6
class read_ahead_tools : public service_base {
FB2K_MAKE_SERVICE_COREAPI(read_ahead_tools);
public:
//! Turn any file object into asynchronous read-ahead-buffered file.
//! @param f File object to wrap. Do not call this object's method after a successful call to add_read_ahead; new file object takes over the ownership of it.
//! @param size Requested read-ahead bytes. Pass 0 to use user settings for local/remote playback.
virtual file::ptr add_read_ahead(file::ptr f, size_t size, abort_callback & aborter) = 0;
//! A helper method to use prior to opening decoders. \n
//! May open the file if needed or leave it blank for the decoder to open.
//! @param f File object to open if needed (buffering mandated by user settings). May be valid or null prior to call. May be valid or null (no buffering) after call.
//! @param path Path to open. May be null if f is not null. At least one of f and path must be valid prior to call.
virtual void open_file_helper(file::ptr & f, const char * path, abort_callback & aborter) = 0;
};
}
using namespace foobar2000_io;

View File

@@ -244,6 +244,8 @@ namespace foobar2000_io {
}
DWORD winVolumeFlags( const char * fb2kPath ) {
PFC_ASSERT( matchProtocol( fb2kPath, "file" ) );
PFC_ASSERT(matchProtocol(fb2kPath, "file"));
pfc::string8 native;
if (!filesystem::g_get_native_path(fb2kPath, native)) throw pfc::exception_invalid_params();

View File

@@ -470,20 +470,21 @@ FB2K_STREAM_READER_OVERLOAD(bool) {
template<bool BE = false>
class stream_writer_formatter_simple : public stream_writer_formatter<BE> {
public:
stream_writer_formatter_simple() : stream_writer_formatter<BE>(_m_stream,fb2k::noAbort), m_buffer(_m_stream.m_buffer) {}
stream_writer_formatter_simple() : stream_writer_formatter<BE>(_m_stream,_m_abort), m_buffer(_m_stream.m_buffer) {}
typedef stream_writer_buffer_simple::t_buffer t_buffer;
t_buffer & m_buffer;
private:
stream_writer_buffer_simple _m_stream;
abort_callback_dummy _m_abort;
};
template<bool BE = false>
class stream_reader_formatter_simple_ref : public stream_reader_formatter<BE> {
public:
stream_reader_formatter_simple_ref(const void * source, t_size sourceSize) : stream_reader_formatter<BE>(_m_stream,fb2k::noAbort), _m_stream(source,sourceSize) {}
template<typename TSource> stream_reader_formatter_simple_ref(const TSource& source) : stream_reader_formatter<BE>(_m_stream,fb2k::noAbort), _m_stream(source) {}
stream_reader_formatter_simple_ref() : stream_reader_formatter<BE>(_m_stream,fb2k::noAbort) {}
stream_reader_formatter_simple_ref(const void * source, t_size sourceSize) : stream_reader_formatter<BE>(_m_stream,_m_abort), _m_stream(source,sourceSize) {}
template<typename TSource> stream_reader_formatter_simple_ref(const TSource& source) : stream_reader_formatter<BE>(_m_stream,_m_abort), _m_stream(source) {}
stream_reader_formatter_simple_ref() : stream_reader_formatter<BE>(_m_stream,_m_abort) {}
void set_data(const void * source, t_size sourceSize) {_m_stream.set_data(source,sourceSize);}
template<typename TSource> void set_data(const TSource & source) {_m_stream.set_data(source);}
@@ -494,6 +495,7 @@ public:
const void * get_ptr_() const {return _m_stream.get_ptr_();}
private:
stream_reader_memblock_ref _m_stream;
abort_callback_dummy _m_abort;
};
template<bool BE = false>

View File

@@ -38,7 +38,5 @@ public:
virtual bool is_our_path( const char * path ) = 0;
};
// Since 1.5, transacted filesystem is no longer supported
// as it adds extra complexity without actually solving any problems.
// Even Microsoft recommends not to use this API.
#define FB2K_SUPPORT_TRANSACTED_FILESYSTEM 0
// Defined but not actually provided for MS Store target - because it plainly doesn't work there
#define FB2K_SUPPORT_TRANSACTED_FILESYSTEM (!FB2K_TARGET_MICROSOFT_STORE)

View File

@@ -1,15 +1,23 @@
#pragma once
#ifndef UNICODE
#error Only UNICODE environment supported.
#endif
#define FOOBAR2000_DESKTOP
#define FOOBAR2000_DESKTOP_WINDOWS
#define FOOBAR2000_DESKTOP_WINDOWS_OR_BOOM
// Set target versions to Windows XP as that's what foobar2000 supports, unless overridden before #including us
#if !defined(_WIN32_WINNT) && !defined(WINVER)
#define _WIN32_WINNT 0x501
#define WINVER 0x501
#endif
#define FOOBAR2000_HAVE_FILE_FORMAT_SANITIZER
#define FOOBAR2000_HAVE_CHAPTERIZER
#define FOOBAR2000_HAVE_ALBUM_ART
#define FOOBAR2000_DECLARE_FILE_TYPES
#define FOOBAR2000_HAVE_DSP
#define FOOBAR2000_HAVE_CONSOLE
#define FOOBAR2000_INTERACTIVE
#define FOOBAR2000_WINAPI_CLASSIC
#define FOOBAR2000_HAVE_METADB

View File

@@ -7,13 +7,12 @@
// #define FOOBAR2000_TARGET_VERSION 75 // 0.9.6
// #define FOOBAR2000_TARGET_VERSION 76 // 1.0
// #define FOOBAR2000_TARGET_VERSION 77 // 1.1, 1.2
// #define FOOBAR2000_TARGET_VERSION 78 // 1.3
#define FOOBAR2000_TARGET_VERSION 79 // 1.4
// #define FOOBAR2000_TARGET_VERSION 80 // 1.5, 1.6
// #define FOOBAR2000_TARGET_VERSION 77 // 1.1
#define FOOBAR2000_TARGET_VERSION 78 // 1.3
// #define FOOBAR2000_TARGET_VERSION 79 // 1.4
// Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018
#define FOOBAR2000_SDK_VERSION 20210223
#define FOOBAR2000_SDK_VERSION 20190617
#include "foobar2000-pfc.h"
@@ -34,8 +33,8 @@ typedef const char * pcchar;
#include "core_api.h"
#include "service.h"
#include "service_impl.h"
#include "service_factory.h"
#include "service_by_guid.h"
#include "service_compat.h"
#include "completion_notify.h"
#include "abort_callback.h"
@@ -44,7 +43,6 @@ typedef const char * pcchar;
#include "coreversion.h"
#include "filesystem.h"
#include "filesystem_transacted.h"
#include "archive.h"
#include "audio_chunk.h"
#include "cfg_var.h"
#include "mem_block_container.h"
@@ -55,7 +53,6 @@ typedef const char * pcchar;
#include "hasher_md5.h"
#include "metadb_handle.h"
#include "metadb.h"
#include "file_info_filter.h"
#include "console.h"
#include "dsp.h"
#include "dsp_manager.h"
@@ -124,7 +121,5 @@ typedef const char * pcchar;
#include "commonObjects.h"
#include "file_lock_manager.h"
#include "imageLoaderLite.h"
#include "imageViewer.h"
#endif //_FOOBAR2000_H_

View File

@@ -13,6 +13,7 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{E8091321-D79D-4575-86EF-064EA1A4A20D}</ProjectGuid>
<RootNamespace>foobar2000_SDK</RootNamespace>
<WindowsTargetPlatformVersion>7.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -20,13 +21,13 @@
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v141_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v141_xp</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -44,6 +45,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>foobar2000.h</PrecompiledHeaderFile>
@@ -53,6 +55,7 @@
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -65,6 +68,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FloatingPointModel>Fast</FloatingPointModel>
@@ -75,12 +79,11 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<AdditionalOptions>/d2notypeopt %(AdditionalOptions)</AdditionalOptions>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers>true</OmitFramePointers>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -96,7 +99,6 @@
<ClInclude Include="album_art.h" />
<ClInclude Include="album_art_helpers.h" />
<ClInclude Include="app_close_blocker.h" />
<ClInclude Include="archive.h" />
<ClInclude Include="audio_chunk.h" />
<ClInclude Include="audio_chunk_impl.h" />
<ClInclude Include="audio_postprocessor.h" />
@@ -124,8 +126,6 @@
<ClInclude Include="filesystem_transacted.h" />
<ClInclude Include="file_format_sanitizer.h" />
<ClInclude Include="file_info.h" />
<ClInclude Include="file_info_filter.h" />
<ClInclude Include="file_info_filter_impl.h" />
<ClInclude Include="file_info_impl.h" />
<ClInclude Include="file_lock_manager.h" />
<ClInclude Include="file_operation_callback.h" />
@@ -140,8 +140,6 @@
<ClInclude Include="hasher_md5.h" />
<ClInclude Include="http_client.h" />
<ClInclude Include="icon_remap.h" />
<ClInclude Include="imageLoaderLite.h" />
<ClInclude Include="imageViewer.h" />
<ClInclude Include="info_lookup_handler.h" />
<ClInclude Include="initquit.h" />
<ClInclude Include="input.h" />
@@ -175,18 +173,16 @@
<ClInclude Include="search_tools.h" />
<ClInclude Include="service.h" />
<ClInclude Include="service_by_guid.h" />
<ClInclude Include="service_compat.h" />
<ClInclude Include="service_factory.h" />
<ClInclude Include="service_impl.h" />
<ClInclude Include="system_time_keeper.h" />
<ClInclude Include="tag_processor.h" />
<ClInclude Include="threaded_process.h" />
<ClInclude Include="titleformat.h" />
<ClInclude Include="tracks.h" />
<ClInclude Include="track_property.h" />
<ClInclude Include="ui.h" />
<ClInclude Include="ui_edit_context.h" />
<ClInclude Include="ui_element.h" />
<ClInclude Include="ui_element_typable_window_manager.h" />
<ClInclude Include="unpack.h" />
<ClInclude Include="vis.h" />
</ItemGroup>
@@ -280,7 +276,6 @@
</ClCompile>
<ClCompile Include="titleformat.cpp">
</ClCompile>
<ClCompile Include="track_property.cpp" />
<ClCompile Include="ui.cpp">
</ClCompile>
<ClCompile Include="ui_element.cpp" />

View File

@@ -269,6 +269,9 @@
<ClInclude Include="service_by_guid.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="service_factory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="foobar2000-pfc.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -281,30 +284,6 @@
<ClInclude Include="file_lock_manager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="archive.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ui_element_typable_window_manager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="service_compat.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="tracks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="file_info_filter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="file_info_filter_impl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="imageLoaderLite.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="imageViewer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="abort_callback.cpp">
@@ -481,8 +460,5 @@
<ClCompile Include="foosort.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="track_property.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -55,8 +55,6 @@ FOOGUIDDECL const GUID resampler_entry::class_guid = { 0x3feed4fc, 0xa400, 0x4a3
#ifdef FOOBAR2000_DESKTOP
FOOGUIDDECL const GUID resampler_manager::class_guid = { 0x9a7e5f01, 0x975b, 0x4373,{ 0xb8, 0x55, 0x3e, 0xf4, 0x16, 0x17, 0x43, 0x3 } };
FOOGUIDDECL const GUID resampler_manager_v2::class_guid = { 0xfe4d7f2e, 0xb705, 0x48fa, { 0x89, 0xce, 0xd7, 0x34, 0xa6, 0x3b, 0x9f, 0x15 } };
FOOGUIDDECL const GUID resampler_manager_v3::class_guid = { 0x262bfb95, 0x7f3c, 0x45c2, { 0xb0, 0x64, 0x9b, 0x6a, 0xd8, 0x3d, 0x34, 0xdd } };
#endif
#endif // FOOBAR2000_HAVE_DSP
@@ -99,10 +97,6 @@ FOOGUIDDECL const GUID packet_decoder_streamparse::class_guid =
FOOGUIDDECL const GUID packet_decoder_entry::class_guid =
{ 0x53006a71, 0xc03c, 0x4c38, { 0x82, 0x2f, 0x9a, 0x34, 0xa5, 0x65, 0x50, 0x95 } };
// {C20940DC-8632-414A-BCF5-415DB77CF9BA}
FOOGUIDDECL const GUID packet_decoder_entry_v2::class_guid =
{ 0xc20940dc, 0x8632, 0x414a, { 0xbc, 0xf5, 0x41, 0x5d, 0xb7, 0x7c, 0xf9, 0xba } };
// {D3BD5F53-A6D6-4346-991F-CF14DFAD2B3A}
FOOGUIDDECL const GUID contextmenu_manager::class_guid =
{ 0xd3bd5f53, 0xa6d6, 0x4346, { 0x99, 0x1f, 0xcf, 0x14, 0xdf, 0xad, 0x2b, 0x3a } };
@@ -119,11 +113,6 @@ FOOGUIDDECL const GUID input_file_type_v2::class_guid =
FOOGUIDDECL const GUID ui_control::class_guid =
{ 0x2dc57ff7, 0x476d, 0x42f5, { 0xa0, 0x5a, 0x60, 0x49, 0x98, 0x96, 0x13, 0x4a } };
#if FOOBAR2000_TARGET_VERSION >= 80
FOOGUIDDECL const GUID ui_control_v2::class_guid = { 0x6fc5d5c3, 0x13aa, 0x4f7f, { 0x97, 0x8d, 0x89, 0x6b, 0x9b, 0x90, 0x4a, 0x5 } };
#endif // FOOBAR2000_TARGET_VERSION >= 80
// {392B88DE-50FC-43b0-9F03-2D79B071CAF6}
FOOGUIDDECL const GUID ui_status_text_override::class_guid =
{ 0x392b88de, 0x50fc, 0x43b0, { 0x9f, 0x3, 0x2d, 0x79, 0xb0, 0x71, 0xca, 0xf6 } };
@@ -176,14 +165,6 @@ FOOGUIDDECL const GUID unpacker::class_guid =
FOOGUIDDECL const GUID archive::class_guid =
{ 0xec707440, 0xfa3e, 0x4d12, { 0x98, 0x76, 0xfc, 0x36, 0x9f, 0x4, 0xd4, 0xa4 } };
// {69897890-90CB-4F7D-9969-1A9DCC5D9DDB}
FOOGUIDDECL const GUID archive_v2::class_guid =
{ 0x69897890, 0x90cb, 0x4f7d, { 0x99, 0x69, 0x1a, 0x9d, 0xcc, 0x5d, 0x9d, 0xdb } };
// {8D3F8B2D-A866-4F1F-9A4F-FF23929ED6DA}
FOOGUIDDECL const GUID archive_v3::class_guid =
{ 0x8d3f8b2d, 0xa866, 0x4f1f, { 0x9a, 0x4f, 0xff, 0x23, 0x92, 0x9e, 0xd6, 0xda } };
// {B2F9FC40-3E55-4b23-A2C9-22BAAD8795B1}
FOOGUIDDECL const GUID file::class_guid =
{ 0xb2f9fc40, 0x3e55, 0x4b23, { 0xa2, 0xc9, 0x22, 0xba, 0xad, 0x87, 0x95, 0xb1 } };
@@ -270,11 +251,6 @@ FOOGUIDDECL const GUID packet_decoder::owner_MP4_ALAC =
FOOGUIDDECL const GUID packet_decoder::owner_MP4_AC3 =
{ 0x62263199, 0x48c2, 0x4777, { 0xb3, 0x3a, 0x87, 0xed, 0x16, 0x1a, 0x16, 0x30 } };
// {AE6325BE-6C65-4B8F-B60D-5C803763BFB5}
FOOGUIDDECL const GUID packet_decoder::owner_MP4_EAC3 =
{ 0xae6325be, 0x6c65, 0x4b8f, { 0xb6, 0xd, 0x5c, 0x80, 0x37, 0x63, 0xbf, 0xb5 } };
// {40017871-50A9-48b6-BF60-BD181A227F9B}
FOOGUIDDECL const GUID packet_decoder::owner_MP4_AMR =
{ 0x40017871, 0x50a9, 0x48b6, { 0xbf, 0x60, 0xbd, 0x18, 0x1a, 0x22, 0x7f, 0x9b } };
@@ -347,14 +323,6 @@ FOOGUIDDECL const GUID packet_decoder::property_eventlogger =
FOOGUIDDECL const GUID packet_decoder::property_mp3_delayless =
{ 0x7ad5e747, 0xcbf3, 0x487d, { 0x88, 0x4f, 0xd9, 0x3c, 0xf8, 0xb8, 0x6e, 0xb0 } };
// {CC2741CF-B57F-43A7-83C9-01C8628E6FDC}
FOOGUIDDECL const GUID packet_decoder::property_query_delay_samples =
{ 0xcc2741cf, 0xb57f, 0x43a7, { 0x83, 0xc9, 0x1, 0xc8, 0x62, 0x8e, 0x6f, 0xdc } };
// {69DD756A-1396-4D69-A08D-82B34B033141}
FOOGUIDDECL const GUID packet_decoder::property_query_mp4_use_elst =
{ 0x69dd756a, 0x1396, 0x4d69, { 0xa0, 0x8d, 0x82, 0xb3, 0x4b, 0x3, 0x31, 0x41 } };
// {6F441057-1D18-4a58-9AC4-8F409CDA7DFD}
FOOGUIDDECL const GUID standard_commands::guid_context_file_properties =
{ 0x6f441057, 0x1d18, 0x4a58, { 0x9a, 0xc4, 0x8f, 0x40, 0x9c, 0xda, 0x7d, 0xfd } };
@@ -633,8 +601,8 @@ FOOGUIDDECL const GUID standard_commands::guid_main_playlist_redo =
{ 0x7a9d9450, 0xa8bf, 0x4a88, { 0xb4, 0x4f, 0xdc, 0xd8, 0x3a, 0x49, 0xdd, 0x7a } };
// {02D89A8A-5F7D-41c3-A215-6731D8621036}
FOOGUIDDECL const GUID standard_commands::guid_main_show_console =
{ 0x5b652d25, 0xce44, 0x4737, { 0x99, 0xbb, 0xa3, 0xcf, 0x2a, 0xeb, 0x35, 0xcc } };
FOOGUIDDECL const GUID standard_commands::guid_main_show_console =
{ 0x2d89a8a, 0x5f7d, 0x41c3, { 0xa2, 0x15, 0x67, 0x31, 0xd8, 0x62, 0x10, 0x36 } };
// {E6970E91-33BE-4288-AC01-4B02F07B5D38}
FOOGUIDDECL const GUID standard_commands::guid_main_play_cd =
@@ -819,9 +787,6 @@ FOOGUIDDECL const GUID preferences_page::guid_tag_writing=
FOOGUIDDECL const GUID preferences_page::guid_media_library=
{ 0x2d269fa9, 0x6f78, 0x4cec, { 0x9f, 0x1f, 0xa, 0x17, 0x6e, 0xfc, 0xe7, 0x7a } };
FOOGUIDDECL const GUID preferences_page::guid_output = { 0xa9038870, 0xdc08, 0x431d, { 0x8c, 0x91, 0x3b, 0x4e, 0x41, 0xd2, 0x43, 0x6d } };
FOOGUIDDECL const GUID preferences_page::guid_advanced = { 0x56eb56ab, 0xedfe, 0x4853, { 0x90, 0xf7, 0xc6, 0xb8, 0x34, 0xfa, 0x2f, 0x6b } };
FOOGUIDDECL const GUID preferences_page::guid_components = { 0xe966267, 0x7dfb, 0x433b, { 0xa0, 0x7c, 0x3f, 0x8c, 0xdd, 0x31, 0xa2, 0x58 } };
// {B8C5CEEA-A5F4-4278-AA2D-798E4403001F}
FOOGUIDDECL const GUID library_viewer::class_guid=
{ 0xb8c5ceea, 0xa5f4, 0x4278, { 0xaa, 0x2d, 0x79, 0x8e, 0x44, 0x3, 0x0, 0x1f } };
@@ -836,9 +801,6 @@ FOOGUIDDECL const GUID input_decoder_v3::class_guid = { 0x953c71ed, 0xd3a2, 0x43
FOOGUIDDECL const GUID input_decoder_v4::class_guid = { 0x7bbf10b5, 0x2064, 0x4da2,{ 0x8a, 0x72, 0xeb, 0x4c, 0xe9, 0xb3, 0xa0, 0xb4 } };
FOOGUIDDECL const GUID input_params::seeking_expensive = { 0x10973582, 0x1aae, 0x4169, { 0xb9, 0x76, 0xb5, 0xbe, 0xf9, 0x4b, 0x7a, 0x71 } };
FOOGUIDDECL const GUID input_params::set_preferred_sample_rate = { 0x7dc7f926, 0x9b9f, 0x4a73, { 0xa2, 0x37, 0x83, 0xe9, 0x93, 0x38, 0x41, 0x75 } };
FOOGUIDDECL const GUID input_params::query_position = { 0xa9d79933, 0x5438, 0x480f, { 0x85, 0xf3, 0xb6, 0xb8, 0xee, 0x1e, 0xfa, 0xe9 } };
FOOGUIDDECL const GUID input_params::continue_stream = { 0x673050df, 0x11f6, 0x4039, { 0x8b, 0x4, 0x6c, 0x31, 0x98, 0x91, 0x4b, 0x89 } };
// {8E9BB1D4-A52B-4df6-A929-1AAE4075388A}
FOOGUIDDECL const GUID input_info_reader::class_guid =
@@ -856,23 +818,13 @@ FOOGUIDDECL const GUID input_entry::class_guid =
FOOGUIDDECL const GUID input_entry_v2::class_guid =
{ 0x7037df35, 0xd246, 0x4cdd,{ 0xb2, 0x24, 0x8, 0xcf, 0x44, 0x4c, 0xe4, 0xce } };
FOOGUIDDECL const GUID input_entry_v3::class_guid = { 0x7099fac8, 0x10ee, 0x4906, { 0xa3, 0x13, 0xb9, 0x8c, 0x69, 0x74, 0xe7, 0xb9 } };
#ifdef FOOBAR2000_DESKTOP
FOOGUIDDECL const GUID input_manager::class_guid = { 0x291fccfd, 0xe7de, 0x4e08,{ 0x8d, 0xef, 0x6b, 0xe5, 0xf8, 0x23, 0xc4, 0x9a } };
FOOGUIDDECL const GUID input_manager_v2::class_guid = { 0x81b36d9e, 0x4fb6, 0x4788, { 0xa1, 0x2c, 0x40, 0xc0, 0x64, 0x82, 0xe5, 0xc6 } };
FOOGUIDDECL const GUID input_manager_v3::class_guid = { 0xc1c414be, 0x74f, 0x41f0, { 0xb8, 0x7f, 0x29, 0x2e, 0xad, 0x50, 0xc0, 0x76 } };
FOOGUIDDECL const GUID input_stream_selector::class_guid = { 0x2a511979, 0x2e57, 0x438a,{ 0x9a, 0x6e, 0x37, 0x3c, 0x25, 0x2, 0xd7, 0x63 } };
FOOGUIDDECL const GUID input_stream_info_reader::class_guid = { 0x934f1361, 0x9c18, 0x497a,{ 0xb6, 0xef, 0xc0, 0x4e, 0xa1, 0x66, 0x3e, 0xab } };
FOOGUIDDECL const GUID input_stream_info_reader_entry::class_guid = { 0xb53b66f2, 0x7cd3, 0x4ce2,{ 0xbf, 0x63, 0x7b, 0xcf, 0xcf, 0xa1, 0xb2, 0x8f } };
FOOGUIDDECL const GUID input_stream_manipulator::class_guid = { 0xc258aa65, 0x961a, 0x4e8e,{ 0x83, 0x98, 0xcc, 0x88, 0xd2, 0xba, 0xe0, 0x5d } };
FOOGUIDDECL const GUID input_stream_manipulator_callback::class_guid = { 0x88ce44b6, 0x8721, 0x440f,{ 0x9e, 0xab, 0xbd, 0xc6, 0x63, 0xed, 0xe1, 0x73 } };
FOOGUIDDECL const GUID input_info_filter::class_guid = { 0xd64af9aa, 0x1c0d, 0x4dd9, { 0xa3, 0x49, 0x2, 0xa3, 0x77, 0xbd, 0x7a, 0xf2 } };
FOOGUIDDECL const GUID input_info_filter_v2::class_guid = { 0x7a2023cb, 0xfb7c, 0x4f04, { 0xa5, 0x45, 0x7f, 0xbd, 0x52, 0x92, 0x31, 0x92 } };
FOOGUIDDECL const GUID input_stream_info_filter::class_guid = { 0xfd056bba, 0xc6a1, 0x40b5, { 0xa6, 0x17, 0x37, 0xb9, 0x71, 0x34, 0xb4, 0xc6 } };
FOOGUIDDECL const GUID input_playback_shim::class_guid = { 0xaf8aea76, 0x144f, 0x4770, { 0x8d, 0x84, 0x7, 0x27, 0x22, 0x8f, 0x29, 0x8 } };
FOOGUIDDECL const GUID preferences_page::guid_input_info_filter = { 0xf9de8ee1, 0x9a5b, 0x4bbd, { 0xb4, 0x62, 0xef, 0x7b, 0x3a, 0xa5, 0x0, 0x24 } };
#endif
// {3296219B-EBA5-4c32-A193-C9BB174801DA}
@@ -1094,8 +1046,6 @@ FOOGUIDDECL const GUID advconfig_entry::guid_branch_tools = { 0x35365484, 0xcc58
FOOGUIDDECL const GUID advconfig_entry::guid_branch_playback = { 0xc48d430d, 0x112, 0x4922, { 0x97, 0x23, 0x28, 0x38, 0xc7, 0xd9, 0x7d, 0xd7 } };
FOOGUIDDECL const GUID advconfig_entry::guid_branch_display = { 0x6c4bc1c8, 0xbaf4, 0x40c3, { 0x9d, 0xb1, 0x9, 0x50, 0x7f, 0xc, 0xc, 0xb9 } };
FOOGUIDDECL const GUID advconfig_entry::guid_branch_debug = { 0xc375447d, 0x58e6, 0x4fd5, { 0xbd, 0xd8, 0x99, 0xfa, 0xef, 0x7b, 0x30, 0x9f } };
FOOGUIDDECL const GUID advconfig_entry::guid_branch_tagging_general = { 0x1a7757de, 0x55bd, 0x4c25, { 0xb2, 0xf9, 0xc6, 0x3a, 0x85, 0x0, 0xba, 0xed } };
@@ -1106,7 +1056,6 @@ FOOGUIDDECL const GUID preferences_branch_v2::class_guid = { 0x167ebeb9, 0x8334,
FOOGUIDDECL const GUID advconfig_entry_enum::class_guid = { 0xb1451540, 0x98ec, 0x4d36, { 0x9f, 0x19, 0xe3, 0x10, 0xfb, 0xa7, 0xab, 0x5a } };
FOOGUIDDECL const GUID info_lookup_handler::class_guid = { 0x4fcfdab7, 0x55b5, 0x47d6, { 0xb1, 0x9d, 0xa4, 0xdc, 0x9f, 0xd7, 0x69, 0x4c } };
@@ -1117,9 +1066,6 @@ FOOGUIDDECL const GUID completion_notify::class_guid = { 0xdf26d586, 0xf7ec, 0x4
FOOGUIDDECL const GUID metadb_io_v2::class_guid = { 0x265c4ece, 0xffb2, 0x4299, { 0x91, 0xb5, 0x6c, 0xa6, 0x60, 0x3d, 0xa1, 0x53 } };
FOOGUIDDECL const GUID file_info_filter::class_guid = { 0x45d0b800, 0xde83, 0x4a77, { 0xad, 0x34, 0x3f, 0x84, 0x2d, 0x40, 0xe7, 0x95 } };
FOOGUIDDECL const GUID file_info_filter_v2::class_guid = { 0x9bb4da92, 0xd334, 0x4f18, { 0x91, 0xc1, 0x91, 0x9f, 0xb2, 0xf4, 0x4f, 0x30 } };
FOOGUIDDECL const GUID metadb_hint_list::class_guid = { 0x719dc072, 0x8d4d, 0x4aa6, { 0xa6, 0xf3, 0x90, 0x73, 0x7, 0xe5, 0xbc, 0xee } };
@@ -1241,8 +1187,6 @@ FOOGUIDDECL const GUID library_file_move_manager::class_guid = { 0xc4cd4818, 0xe
FOOGUIDDECL const GUID library_file_move_notify::class_guid = { 0xd8ae7613, 0x7577, 0x4192, { 0x8f, 0xa4, 0x2d, 0x8f, 0x7e, 0xc6, 0x6, 0x38 } };
FOOGUIDDECL const GUID library_meta_autocomplete::class_guid = { 0x4b976e34, 0xf05a, 0x4da4, { 0xad, 0x65, 0x71, 0x9c, 0xdf, 0xd, 0xed, 0xae } };
FOOGUIDDECL const GUID library_meta_autocomplete_v2::class_guid = { 0xd60d585e, 0xb42e, 0x4a6e, { 0x8f, 0x24, 0x27, 0x50, 0x71, 0x1a, 0x87, 0x30 } };
FOOGUIDDECL const GUID input_protocol_type::class_guid = { 0x6a03c4ee, 0xf87b, 0x49d7, { 0x81, 0xdb, 0x66, 0xb, 0xe8, 0xc1, 0x0, 0x7e } };
@@ -1263,7 +1207,6 @@ FOOGUIDDECL const GUID album_art_fallback::class_guid = { 0x45481581, 0x40b3, 0x
FOOGUIDDECL const GUID preferences_page_callback::class_guid = { 0x3d26e08e, 0x861c, 0x4599, { 0x9c, 0x89, 0xaa, 0xa7, 0x19, 0xaf, 0x50, 0x70 } };
FOOGUIDDECL const GUID preferences_page_instance::class_guid = { 0x6893a996, 0xa816, 0x49fe, { 0x82, 0xce, 0xc, 0xb8, 0x4, 0xa4, 0xcf, 0xec } };
FOOGUIDDECL const GUID preferences_page_v3::class_guid = { 0xd6d0f741, 0x9f17, 0x4df8, { 0x9d, 0x5c, 0x87, 0xf2, 0x8b, 0x1f, 0xe, 0x64 } };
FOOGUIDDECL const GUID preferences_page_v4::class_guid = { 0x76227dab, 0xc740, 0x4d49, { 0xa2, 0xe2, 0x50, 0x80, 0x13, 0xe, 0xf6, 0xba } };
FOOGUIDDECL const GUID advconfig_entry_string_v2::class_guid = { 0x2ec9b1fa, 0xe1e4, 0x42f0, { 0x87, 0x97, 0x4a, 0x63, 0x16, 0x94, 0x86, 0xbc } };
FOOGUIDDECL const GUID advconfig_entry_checkbox_v2::class_guid = { 0xe29b37d0, 0xa957, 0x4a85, { 0x82, 0x40, 0x1e, 0x96, 0xc7, 0x29, 0xb6, 0x69 } };
@@ -1298,7 +1241,6 @@ FOOGUIDDECL const GUID playback_stream_capture::class_guid = { 0x9423439e, 0x8cd
FOOGUIDDECL const GUID http_request::class_guid = { 0x48580056, 0x2c5f, 0x45a8, { 0xb8, 0x6e, 0x5, 0x83, 0x55, 0x3e, 0xaa, 0x4f } };
FOOGUIDDECL const GUID http_request_post::class_guid = { 0xe254b804, 0xeac5, 0x4be0, { 0x99, 0x4d, 0x53, 0x1c, 0x17, 0xea, 0xfd, 0x37 } };
FOOGUIDDECL const GUID http_request_post_v2::class_guid = { 0x95309335, 0xd301, 0x4946, { 0x99, 0x27, 0x2d, 0xb7, 0x9b, 0x22, 0x46, 0x9c } };
FOOGUIDDECL const GUID http_client::class_guid = { 0x3b5ffe0c, 0xd75a, 0x491e, { 0xbb, 0x6f, 0x10, 0x3f, 0x73, 0x1e, 0x81, 0x84 } };
FOOGUIDDECL const GUID http_reply::class_guid = { 0x7f02bf78, 0x5c98, 0x4d6d, { 0x83, 0x6b, 0xb7, 0x77, 0xa4, 0xa3, 0x3e, 0xe5 } };
@@ -1331,14 +1273,9 @@ FOOGUIDDECL const GUID track_property_provider_v3::class_guid = { 0xdbbce29c, 0x
FOOGUIDDECL const GUID output::class_guid = { 0xb9632c4f, 0x596e, 0x43ee, { 0xb2, 0x14, 0x71, 0x4, 0x48, 0x4b, 0x65, 0xf1 } };
FOOGUIDDECL const GUID output_entry::class_guid = { 0xe7480b4f, 0x4941, 0x4dd2, { 0xad, 0xbf, 0x96, 0x6c, 0x76, 0x63, 0x43, 0x92 } };
FOOGUIDDECL const GUID output_entry_v2::class_guid = { 0xaacc17f3, 0xb7cc, 0x48c2, { 0x95, 0x6e, 0x52, 0xba, 0x72, 0x89, 0x42, 0xe5 } };
FOOGUIDDECL const GUID output_entry_v3::class_guid = { 0xfa18060e, 0xfc84, 0x4f53, { 0xa8, 0xe3, 0x60, 0xc5, 0xf5, 0x22, 0x50, 0x7a } };
FOOGUIDDECL const GUID volume_control::class_guid = { 0x39f9fc0c, 0x4dc9, 0x4a7a, { 0xb9, 0xad, 0x75, 0x8b, 0x78, 0x57, 0x78, 0xad } };
FOOGUIDDECL const GUID output_v2::class_guid = { 0x4f679e4b, 0x79e0, 0x4fc9, { 0x90, 0x27, 0x55, 0x49, 0x85, 0x72, 0x26, 0xbf } };
FOOGUIDDECL const GUID output_v3::class_guid = { 0x3b764d8e, 0x6c1c, 0x40bd, { 0x9a, 0x7e, 0xac, 0x3, 0x2a, 0x3e, 0x25, 0xf1 } };
FOOGUIDDECL const GUID output_v4::class_guid = { 0x2c7a21a, 0xcc12, 0x48f3, { 0x89, 0x2e, 0xa7, 0x98, 0xb0, 0xc8, 0xaa, 0x49 } };
FOOGUIDDECL const GUID output_v5::class_guid = { 0x735e6e3f, 0x95d8, 0x45ca, { 0xad, 0x1a, 0xca, 0x88, 0x1f, 0x1d, 0x5c, 0xfa } };
FOOGUIDDECL const GUID output_manager::class_guid = { 0x6cc5827e, 0x2c89, 0x42ff, { 0x83, 0x51, 0x76, 0xa9, 0x2e, 0x2f, 0x34, 0x50 } };
FOOGUIDDECL const GUID output_manager_v2::class_guid = { 0xcc8aa352, 0x7af1, 0x41d2, { 0x94, 0x7e, 0xa2, 0x65, 0x17, 0x5b, 0x68, 0x96 } };
@@ -1357,6 +1294,7 @@ FOOGUIDDECL const GUID ui_element_replace_dialog_notify::class_guid = { 0x95f925
FOOGUIDDECL const GUID ui_element_popup_host::class_guid = { 0xfcc381e9, 0xe527, 0x4887,{ 0xae, 0x63, 0x27, 0xc0, 0x3f, 0x4, 0xd, 0x1 } };
FOOGUIDDECL const GUID ui_element_popup_host_callback::class_guid = { 0x2993a043, 0x2e70, 0x4d8f,{ 0x81, 0xb, 0x41, 0x3, 0x37, 0x73, 0x97, 0xcd } };
FOOGUIDDECL const GUID ui_element_config::class_guid = { 0xd34bba46, 0x1bad, 0x4547,{ 0xba, 0xb4, 0x17, 0xe2, 0x44, 0xd5, 0xeb, 0x94 } };
FOOGUIDDECL const GUID ui_element_typable_window_manager::class_guid = { 0xbaa99ee2, 0xf770, 0x4981,{ 0x9e, 0x50, 0xf3, 0x4c, 0x5c, 0x6d, 0x98, 0x81 } };
FOOGUIDDECL const GUID ui_element_instance_callback_v3::class_guid = { 0x6d15c0c6, 0x90b6, 0x4c7e,{ 0xbf, 0x39, 0xe9, 0x39, 0xf2, 0xdf, 0x9b, 0x91 } };
FOOGUIDDECL const GUID ui_element_popup_host_v2::class_guid = { 0x8caac11e, 0x52b6, 0x47f7,{ 0x97, 0xc9, 0x2c, 0x87, 0xdb, 0xdb, 0x2e, 0x5b } };
@@ -1382,32 +1320,5 @@ FOOGUIDDECL const GUID playlist_incoming_item_filter_v4::class_guid = { 0x9bd438
FOOGUIDDECL const GUID file_lock::class_guid = { 0xb2f0b2f8, 0x1ccf, 0x438e, { 0xb9, 0x75, 0x9f, 0x5b, 0x75, 0x5a, 0xa3, 0x2e } };
FOOGUIDDECL const GUID file_lock_manager::class_guid = { 0xa808fe53, 0xd36, 0x42fb, { 0xac, 0x2, 0x6a, 0xc8, 0x9c, 0xcb, 0x24, 0xbe } };
FOOGUIDDECL const GUID file_lock_manager_v2::class_guid = { 0x30c07c6a, 0xde51, 0x4094, { 0x82, 0xe6, 0xf1, 0x57, 0xd1, 0xb2, 0x3a, 0xe8 } };
FOOGUIDDECL const GUID file_lock_interrupt::class_guid = { 0x73ebabc8, 0xfe66, 0x4dae, { 0x95, 0x90, 0x3d, 0xa3, 0x9f, 0x17, 0x19, 0x15 } };
FOOGUIDDECL const GUID track_property_provider_v4::class_guid = { 0x707abb57, 0x35f7, 0x41c3, { 0xac, 0x43, 0xc9, 0xb6, 0xc, 0xc6, 0xa9, 0xae } };
FOOGUIDDECL const GUID album_art_extractor_v2::class_guid = { 0x3aa31001, 0xaf5b, 0x497a, { 0xbd, 0xdc, 0xa9, 0x3f, 0x23, 0xb2, 0x1b, 0xc2 } };
FOOGUIDDECL const GUID album_art_editor_v2::class_guid = { 0xf16827d3, 0xca20, 0x44fe, { 0x94, 0xe0, 0x56, 0xd7, 0x2d, 0x35, 0x81, 0x6 } };
FOOGUIDDECL const GUID replaygain_scanner_config::class_guid = { 0x210970e1, 0xa478, 0x4d76, { 0xa5, 0x7c, 0x95, 0x9, 0xae, 0x82, 0xae, 0x41 } };
#if FOOBAR2000_TARGET_VERSION >= 80
FOOGUIDDECL const GUID metadb_io_v4::class_guid = { 0x6ec07034, 0xd5c2, 0x4fb5, { 0xb7, 0x59, 0x7d, 0x12, 0x4f, 0xa7, 0x27, 0xf4 } };
FOOGUIDDECL const GUID popup_message_v3::class_guid = { 0xef3c83fd, 0x1144, 0x4edb, { 0xb8, 0x43, 0xcf, 0xba, 0xc6, 0xe5, 0xe1, 0x8b } };
#endif // FOOBAR2000_TARGET_VERSION >= 80
FOOGUIDDECL const GUID file_lowLevelIO::class_guid = { 0xbcacb272, 0x8e6c, 0x4d23, { 0x91, 0x9a, 0xe, 0xaa, 0x55, 0x2e, 0xc9, 0x70 } };
FOOGUIDDECL const GUID file_lowLevelIO::guid_flushFileBuffers = { 0xace5356b, 0x8c72, 0x408a, { 0x8e, 0x32, 0x78, 0x1e, 0x7d, 0x7f, 0xe9, 0x97 } };
FOOGUIDDECL const GUID file_lowLevelIO::guid_getFileTimes = { 0xb5a3cd80, 0x23ae, 0x4c51, { 0x83, 0x3b, 0xa5, 0x98, 0x6b, 0xe1, 0xec, 0x59 } };
FOOGUIDDECL const GUID file_lowLevelIO::guid_setFileTimes = { 0x46501e0d, 0x644d, 0x4d00, { 0xaf, 0x8c, 0xc5, 0xc1, 0xb, 0x34, 0xae, 0x37 } };
FOOGUIDDECL const GUID async_task_manager::class_guid = { 0xea055f49, 0x7c6d, 0x4695, { 0x8c, 0xf, 0xeb, 0xbd, 0x92, 0xdb, 0xa7, 0xa7 } };
FOOGUIDDECL const GUID read_ahead_tools::class_guid = { 0x709671bf, 0x449a, 0x4dc8, { 0x9f, 0xcf, 0x84, 0xb3, 0xbc, 0xec, 0x98, 0x4d } };
FOOGUIDDECL const GUID fb2k::imageLoaderLite::class_guid = { 0xbe06ead9, 0x1c9, 0x42e0, { 0x9f, 0x9f, 0x12, 0xb2, 0xde, 0x95, 0xca, 0x96 } };
FOOGUIDDECL const GUID fb2k::imageViewer::class_guid = { 0xdbdaaa24, 0x2f90, 0x426c, { 0x86, 0x3, 0x1c, 0x5a, 0xe5, 0xf9, 0x82, 0x21 } };

View File

@@ -14,13 +14,6 @@ struct hasher_md5_result {
static hasher_md5_result null() {hasher_md5_result h = {}; return h;}
};
FB2K_STREAM_READER_OVERLOAD(hasher_md5_result) {
stream.read_raw(&value, sizeof(value)); return stream;
}
FB2K_STREAM_WRITER_OVERLOAD(hasher_md5_result) {
stream.write_raw(&value, sizeof(value)); return stream;
}
inline bool operator==(const hasher_md5_result & p_item1,const hasher_md5_result & p_item2) {return memcmp(&p_item1,&p_item2,sizeof(hasher_md5_result)) == 0;}
inline bool operator!=(const hasher_md5_result & p_item1,const hasher_md5_result & p_item2) {return memcmp(&p_item1,&p_item2,sizeof(hasher_md5_result)) != 0;}
@@ -81,7 +74,7 @@ private:
template<bool isBigEndian = false>
class stream_formatter_hasher_md5 : public stream_writer_formatter<isBigEndian> {
public:
stream_formatter_hasher_md5() : stream_writer_formatter<isBigEndian>(_m_stream,fb2k::noAbort) {}
stream_formatter_hasher_md5() : stream_writer_formatter<isBigEndian>(_m_stream,_m_abort) {}
hasher_md5_result result() const {
return _m_stream.result();
@@ -90,5 +83,6 @@ public:
return hasher_md5::guid_from_result(result());
}
private:
abort_callback_dummy _m_abort;
stream_writer_hasher_md5 _m_stream;
};

View File

@@ -41,13 +41,6 @@ public:
void add_post_data(const char * name, const char * value) { add_post_data(name, value, strlen(value), "", ""); }
};
//! \since 1.5
class NOVTABLE http_request_post_v2 : public http_request_post {
FB2K_MAKE_SERVICE_INTERFACE(http_request_post_v2, http_request_post);
public:
virtual void set_post_data(const void* blob, size_t bytes, const char* contentType) = 0;
};
class NOVTABLE http_client : public service_base {
FB2K_MAKE_SERVICE_COREAPI(http_client)
public:

View File

@@ -1,52 +0,0 @@
#pragma once
#ifdef _WIN32
namespace Gdiplus {
class Image;
}
#endif
namespace fb2k {
#ifdef _WIN32
typedef Gdiplus::Image * nativeImage_t;
#else
typedef void * nativeImage_t;
#endif
struct imageInfo_t {
uint32_t width, height, bitDepth;
bool haveAlpha;
const char * formatName;
const char * mime;
};
//! \since 1.6
//! Interface to common image loader routines that turn a bytestream into a image that can be drawn in a window. \n
//! Windows: Using imageLoaderLite methods initializes gdiplus if necessary, leaving gdiplus initialized for the rest of app lifetime. \n
//! If your component supports running on foobar2000 older than 1.6, use tryGet() to gracefully fall back to your own image loader: \n
//! auto api = fb2k::imageLoaderLite::tryGet(); if (api.is_valid()) { do stuff with api; } else { use fallbacks; }
class imageLoaderLite : public service_base {
FB2K_MAKE_SERVICE_COREAPI(imageLoaderLite);
public:
//! Throws excpetions on failure, returns valid image otherwise.\n
//! Caller takes ownership of the returned object. \n
//! @param outInfo Optional struct to receive information about the loaded image.
virtual nativeImage_t load(const void * data, size_t bytes, imageInfo_t * outInfo = nullptr, abort_callback & aborter = fb2k::noAbort) = 0;
//! Parses the image data just enough to hand over basic info about what's inside. \n
//! Much faster than load(). \n
//! Supports all formats recognized by load().
virtual imageInfo_t getInfo(const void * data, size_t bytes, abort_callback & aborter = fb2k::noAbort) = 0;
//! Helper - made virtual so it can be possibly specialized in the future
virtual nativeImage_t load(album_art_data_ptr data, imageInfo_t * outInfo = nullptr, abort_callback & aborter = fb2k::noAbort) {
return load(data->get_ptr(), data->get_size(), outInfo, aborter);
}
//! Helper - made virtual so it can be possibly specialized in the future
virtual imageInfo_t getInfo(album_art_data_ptr data, abort_callback & aborter = fb2k::noAbort) {
return getInfo(data->get_ptr(), data->get_size(), aborter);
}
};
}
#define FB2K_GETOPENFILENAME_PICTUREFILES "Picture files|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.webp"
#define FB2K_GETOPENFILENAME_PICTUREFILES_ALL FB2K_GETOPENFILENAME_PICTUREFILES "|All files|*.*"

View File

@@ -1,15 +0,0 @@
#pragma once
namespace fb2k {
//! \since 1.6.2
class imageViewer : public service_base {
FB2K_MAKE_SERVICE_COREAPI(imageViewer);
public:
//! Spawns an image viewer window, showing the specified picture already loaded into application memory.
virtual void show(HWND parent, fb2k::memBlockRef data) = 0;
//! Spawns an image viewer window, showing album art from the specified list of items.
//! @param aaType Type of picture to load, front cover, back cover or other.
//! @param pageno Reserved for future use, set to 0.
virtual void load_and_show(HWND parent, metadb_handle_list_cref items, const GUID & aaType, unsigned pageno = 0) = 0;
};
}

View File

@@ -24,7 +24,6 @@ namespace init_stages {
before_config_read = 10,
after_config_read = 20,
before_library_init = 30,
// Since foobar2000 v2.0, after_library_init is fired OUT OF ORDER with the rest, after ASYNCHRONOUS library init has completed.
after_library_init = 40,
before_ui_init = 50,
after_ui_init = 60,

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

View File

@@ -1,8 +1,3 @@
#pragma once
#include <functional>
#include "event_logger.h"
#include "audio_chunk.h"
PFC_DECLARE_EXCEPTION(exception_tagging_unsupported, exception_io_data, "Tagging of this file format is not supported")
enum {
@@ -107,8 +102,8 @@ public:
//! Returned raw data should be possible to cut into individual samples; size in bytes should be divisible by audio_chunk's sample count for splitting in case partial output is needed (with cuesheets etc).
virtual bool run_raw(audio_chunk & out, mem_block_container & outRaw, abort_callback & abort) = 0;
//! OBSOLETE since 1.5 \n
//! Specify logger when opening to reliably get info generated during input open operation.
//! OPTIONAL, the call is ignored if this implementation doesn't support status logging. \n
//! Mainly used to generate logs when ripping CDs etc.
virtual void set_logger(event_logger::ptr ptr) = 0;
};
@@ -139,21 +134,6 @@ public:
//! Tells the decoder to output at this sample rate if the decoder's sample rate is adjustable. \n
//! Sample rate signaled in arg1.
static const GUID set_preferred_sample_rate;
//! Retrieves logical decode position from the decoder. Implemented only in some rare cases where logical position does not match duration of returned data so far.
//! arg2 points to double position in seconds.
//! Return 1 if position was written to arg2, 0 if n/a.
static const GUID query_position;
struct continue_stream_t {
file::ptr reader;
const char * path;
};
//! Tells the decoder to continue decoding from another URL, without flushing etc. Mainly used by HLS streams.
//! arg2: continue_stream_t
//! Return 1 to acknowledge, 0 if unsupported.
//! A call to decode_initialize() will follow if you return 1; perform actual file open from there.
static const GUID continue_stream;
};
//! Class providing interface for writing metadata and replaygain info to files. Also see: file_info. \n
@@ -172,9 +152,6 @@ public:
//! @param p_abort abort_callback object signaling user aborting the operation. WARNING: abort_callback object is provided for consistency; if writing tags actually gets aborted, user will be likely left with corrupted file. Anything calling this should make sure that aborting is either impossible, or gives appropriate warning to the user first.
virtual void commit(abort_callback & p_abort) = 0;
//! Helper for writers not implementing input_info_writer_v2::remove_tags().
void remove_tags_fallback(abort_callback & abort);
FB2K_MAKE_SERVICE_INTERFACE(input_info_writer,input_info_reader);
};
@@ -245,25 +222,20 @@ public:
static void 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 = false);
static void 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 = false);
static bool g_is_supported_path(const char * p_path);
typedef std::function<bool ( input_entry::ptr ) > input_filter_t;
static bool 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);
static bool g_find_inputs_by_path(pfc::list_base_t<service_ptr_t<input_entry> > & p_out, const char * p_path, bool p_from_redirect );
static bool 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 );
static bool 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 );
static service_ptr g_open(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter, bool fromRedirect = false);
static bool g_find_inputs_by_path(pfc::list_base_t<service_ptr_t<input_entry> > & p_out, const char * p_path, bool p_from_redirect);
static service_ptr g_open(const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter, bool fromRedirect = false);
void open(service_ptr_t<input_decoder> & p_instance,service_ptr_t<file> const & p_filehint,const char * p_path,abort_callback & p_abort) {open_for_decoding(p_instance,p_filehint,p_path,p_abort);}
void open(service_ptr_t<input_info_reader> & p_instance,service_ptr_t<file> const & p_filehint,const char * p_path,abort_callback & p_abort) {open_for_info_read(p_instance,p_filehint,p_path,p_abort);}
void open(service_ptr_t<input_info_writer> & p_instance,service_ptr_t<file> const & p_filehint,const char * p_path,abort_callback & p_abort) {open_for_info_write(p_instance,p_filehint,p_path,p_abort);}
service_ptr open(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter);
service_ptr open(const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter);
typedef pfc::list_base_const_t< input_entry::ptr > input_entry_list_t;
static service_ptr g_open_from_list(input_entry_list_t const & list, const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter, GUID * outGUID = nullptr);
static service_ptr g_open_from_list(input_entry_list_t const & list, const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter, GUID * outGUID = nullptr);
static bool g_are_parallel_reads_slow( const char * path );
static uint32_t g_flags_for_path( const char * pathFor, uint32_t mask = UINT32_MAX );
static uint32_t g_flags_for_content_type( const char * ct, uint32_t mask = UINT32_MAX );
};
//! \since 1.4
@@ -272,7 +244,8 @@ public:
class input_entry_v2 : public input_entry {
FB2K_MAKE_SERVICE_INTERFACE(input_entry_v2, input_entry);
public:
//! @returns GUID used to identify us among other decoders in the decoder priority table.
#ifdef FOOBAR2000_DESKTOP // none of this is used in fb2k mobile
//! @returns GUID used to identify us among other deciders in the decoder priority table.
virtual GUID get_guid() = 0;
//! @returns Name to present to the user in the decoder priority table.
virtual const char * get_name() = 0;
@@ -280,22 +253,7 @@ public:
virtual GUID get_preferences_guid() = 0;
//! @returns true if the decoder should be put at the end of the list when it's first sighted, false otherwise (will be put at the beginning of the list).
virtual bool is_low_merit() = 0;
};
//! \since 1.5
class input_entry_v3 : public input_entry_v2 {
FB2K_MAKE_SERVICE_INTERFACE(input_entry_v3, input_entry_v2);
public:
//! New unified open() function for all supported interfaces. Supports any future interfaces via alternate GUIDs, as well as allows the event logger to be set prior to the open() call.
//! @param whatFor The class GUID of the service we want. \n
//! Currently allowed are: input_decoder::class_guid, input_info_reader::class_guid, input_info_writer::class_guid. \n
//! This method must throw pfc::exception_not_implemented for any GUIDs it does not recognize.
virtual service_ptr open_v3( const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter ) = 0;
void open_for_decoding(service_ptr_t<input_decoder> & p_instance, service_ptr_t<file> p_filehint, const char * p_path, abort_callback & p_abort) ;
void 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);
void 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);
#endif
};
#ifdef FOOBAR2000_DESKTOP
@@ -306,40 +264,6 @@ class input_manager : public service_base {
FB2K_MAKE_SERVICE_COREAPI(input_manager);
public:
virtual service_ptr open(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, abort_callback & aborter, GUID * outUsedEntry = nullptr) = 0;
//! input_manager_v2 wrapper.
service_ptr open_v2(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry = nullptr);
};
//! \since 1.5
//! Extension of input_manager. \n
//! Extended open_v2() supports album_art_extractor and album_art_editor. It reliably throws pfc::exception_not_implemented() for unsupported GUIDs (old version would bugcheck). \n
//! It also allows event_logger to be specified in advance so open() implementation can already use it.
class input_manager_v2 : public input_manager {
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(input_manager_v2, input_manager)
public:
virtual service_ptr open_v2(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry = nullptr) = 0;
};
//! \since 1.5
class input_manager_v3 : public input_manager_v2 {
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(input_manager_v3, input_manager_v2);
public:
//! Retrieves list of enabled inputs, in user-specified order. \n
//! This is rarely needed. If you need this function, consider redesigning your code to call input_manager open methods instead.
virtual void get_enabled_inputs( pfc::list_base_t<input_entry::ptr> & out ) = 0;
//! Returns input_entry get_flags() values for this path, as returned by enabled inputs.
virtual uint32_t flags_for_path( const char * pathFor, uint32_t mask = UINT32_MAX ) = 0;
//! Returns input_entry get_flags() values for this content type, as returned by enabled inputs.
virtual uint32_t flags_for_content_type( const char * ct, uint32_t mask = UINT32_MAX ) = 0;
enum {
flagFromRedirect = 1 << 0,
flagSuppressFilters = 1 << 1,
};
virtual service_ptr open_v3(const GUID & whatFor, file::ptr hint, const char * path, uint32_t flags, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry = nullptr) = 0;
};
//! \since 1.4
@@ -385,8 +309,6 @@ public:
};
//! \since 1.4
//! Callback for input_stream_manipulator \n
//! Used for applying ReplayGain to encoded audio streams.
class input_stream_manipulator_callback : public service_base {
FB2K_MAKE_SERVICE_INTERFACE(input_stream_manipulator_callback, service_base);
public:
@@ -402,8 +324,6 @@ public:
};
//! \since 1.4
//! Manipulate audio stream payload in files. \n
//! Used for applying ReplayGain to encoded audio streams.
class input_stream_manipulator : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(input_stream_manipulator);
public:
@@ -425,121 +345,4 @@ public:
//! Return GUID of the matching input_entry.
virtual GUID get_guid() = 0;
};
//! \since 1.5
//! An input_info_filter lets you hook into all performed tag read & write operations. \n
//! Your tag manipulations will be transparent to all fb2k components, as if the tags were read/written by relevant inputs. \n
//! Your input_info_filter needs to be enabled in Preferences in order to become active. Newly added ones are inactive by default.
class input_info_filter : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT( input_info_filter );
public:
//! Tags are being read from a file.
virtual void filter_info_read( const playable_location & loc,file_info & info,abort_callback & abort ) = 0;
//! Tags are being written to a file. \n
//! Return true to continue, false to suppress writing of tags.
virtual bool filter_info_write( const playable_location & loc, file_info & info, abort_callback & abort ) = 0;
//! Tags are being removed from a file.
virtual void on_info_remove( const char * path, abort_callback & abort ) = 0;
//! Return GUID of your filter.
virtual GUID get_guid() = 0;
//! Return preferences page or advconfig branch GUID of your filter.
virtual GUID get_preferences_guid() = 0;
//! Return user-friendly name of your filter to be shown in preferences.
virtual const char * get_name() = 0;
//! Optional backwards compatibility method. \n
//! If you also provide input services for old foobar2000 versions which don't recognize input_info_filter, report their GUIDs here so they can be ignored. \n
//! @param outGUIDs empty on entry, contains GUIDs of ignored inputs (if any) on return.
virtual void get_suppressed_inputs( pfc::list_base_t<GUID> & outGUIDs ) {outGUIDs.remove_all();}
//! write_fallback() supported or not? \n
//! Used if your filter can store tags for untaggable files.
virtual bool supports_fallback() = 0;
//! Optional; called when user attempted to tag an untaggable/readonly file. \n
//! Used if your filter can store tags for untaggable files.
virtual bool write_fallback( const playable_location & loc, file_info const & info, abort_callback & abort ) = 0;
//! Optional; called when user attempted to remove tags from an untaggable/readonly file.\ n
//! Used if your filter can store tags for untaggable files.
virtual void remove_tags_fallback( const char * path, abort_callback & abort ) = 0;
};
//! \since 1.5
class input_stream_info_filter : public service_base {
FB2K_MAKE_SERVICE_INTERFACE( input_stream_info_filter, service_base );
public:
virtual void filter_dynamic_info( file_info & info ) = 0;
virtual void filter_dynamic_info_track( file_info & info ) = 0;
};
class album_art_data;
//! \since 1.5
//! Extended input_info_filter.
class input_info_filter_v2 : public input_info_filter {
FB2K_MAKE_SERVICE_INTERFACE( input_info_filter_v2, input_info_filter );
public:
//! Creates an object which then can work with dynamic track titles etc of a decoded track. \n
//! Returning null to filter the info is allowed.
virtual input_stream_info_filter::ptr open_stream(playable_location const & loc, abort_callback & abort) = 0;
typedef service_ptr_t<album_art_data> aaptr_t;
//! Album art is being read from the file. \n
//! info may be null if file had no such picture. \n
//! Return passed info, altered info or null.
virtual aaptr_t filter_album_art_read( const char * path, const GUID & type, aaptr_t info, abort_callback & aborter ) = 0;
//! Album art is being written to the file. \n
//! Return passed info, altered info or null to suppress writing.
virtual aaptr_t filter_album_art_write( const char * path, const GUID & type, aaptr_t info, abort_callback & aborter ) = 0;
//! Specific album art is being removed from the file. \n
//! Return true to go on, false to suppress file update.
virtual bool filter_album_art_remove( const char * path, const GUID & type, abort_callback & aborter ) = 0;
//! All album art is being removed from the file. \n
//! Return true to go on, false to suppress file update.
virtual bool filter_album_art_remove_all( const char * path, abort_callback & aborter ) = 0;
//! Valid with supports_fallback() = true \n
//! Album art is being written to an untaggable file.
virtual void write_album_art_fallback( const char * path, const GUID & type, aaptr_t info, abort_callback & aborter ) = 0;
//! Valid with supports_fallback() = true \n
//! Specific album art is being removed from an untaggable file.
virtual void remove_album_art_fallback( const char * path, const GUID & type, abort_callback & aborter ) = 0;
//! Valid with supports_fallback() = true \n
//! All album art is being removed from an untaggable file.
virtual void remove_all_album_art_fallback( const char * path, abort_callback & aborter ) = 0;
};
class dsp_preset;
//! \since 1.5
//! An input_playback_shim adds additional functionality to a DSP, allowing full control of the decoder. \n
//! Currently, input_playback_shim can only exist alongside a DSP, must have the same GUID as a DSP. \n
//! It will only be used in supported scenarios when the user has put your DSP in the chain. \n
//! Your DSP will be deactivated in such case when your input_playback_shim is active. \n
//! input_playback_shim is specifically intended to be instantiated for playback. Do not call this service from your component. \n/
//! Implement this service ONLY IF NECESSARY. Very few tasks really need it, primarily DSPs that manipulate logical playback time & seeking.
class input_playback_shim : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT( input_playback_shim );
public:
//! Same GUID as your DSP.
virtual GUID get_guid() = 0;
//! Preferences page / advconfig branch GUID of your shim, pfc::guid_null if none. \n
//! This is currently unused / reserved for future use.
virtual GUID get_preferences_guid() = 0;
//! Same as your DSP. \n
//! This is currently unused / reserved for future use.
virtual const char * get_name() = 0;
//! Instantiates your shim on top of existing input_decoder. \n
//! If you don't want to do anything with this specific decoder, just return the passed decoder.
virtual input_decoder::ptr shim( input_decoder::ptr dec, const char * path, dsp_preset const & preset, abort_callback & aborter ) = 0;
//! Optional backwards compatibility method. \n
//! If you also provide input services for old versions of foobar2000 which don't recognize input_playback_shim, report their GUIDs here so they can be ignored. \n
//! @param outGUIDs empty on entry, contains GUIDs of ignored inputs (if any) on return.
virtual void get_suppressed_inputs( pfc::list_base_t<GUID> & outGUIDs ) {outGUIDs.remove_all();}
};
#endif // #ifdef FOOBAR2000_DESKTOP
typedef input_info_writer_v2 input_info_writer_vhighest;
typedef input_decoder_v4 input_decoder_vhighest;
typedef input_info_reader input_info_reader_vhighest;
#endif

View File

@@ -66,10 +66,9 @@ void input_file_type::make_extension_support_fingerprint(pfc::string_base & str)
}
str = out;
}
void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include_playlists, bool b_include_archives)
void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include_playlists)
{
t_fnList extensionsAll, extensionsPl, extensionsArc;
t_fnList extensionsAll, extensionsPl;;
if (b_include_playlists) {
service_enum_t<playlist_loader> e; service_ptr_t<playlist_loader> ptr;
@@ -81,19 +80,6 @@ void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include
}
}
}
if (b_include_archives) {
service_enum_t<filesystem> e;
archive_v3::ptr p;
pfc::string_formatter temp;
while (e.next(p)) {
p->list_extensions(temp);
pfc::chain_list_v2_t<pfc::string8> lst;
pfc::splitStringByChar(lst, temp, ',');
for (auto iter = lst.first(); iter.is_valid(); ++iter) {
extensionsArc += PFC_string_formatter() << "*." << *iter;
}
}
}
typedef pfc::map_t<pfc::string8,t_fnList,pfc::string::comparatorCaseInsensitive> t_masks;
t_masks masks;
@@ -117,11 +103,8 @@ void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include
}
pfc::string_formatter outBuf;
outBuf << "All files|*.*|";
formatMaskList(outBuf, extensionsAll, "All supported media types");
formatMaskList(outBuf, extensionsAll, "All supported types");
formatMaskList(outBuf, extensionsPl, "Playlists");
formatMaskList(outBuf, extensionsArc, "Archives");
for(auto walk = masks.cfirst(); walk.is_valid(); ++walk) {
formatMaskList(outBuf,walk->m_value,walk->m_key);
}

View File

@@ -8,7 +8,7 @@ public:
virtual bool is_associatable(unsigned idx) = 0;
#if FOOBAR2000_TARGET_VERSION >= 76
static void build_openfile_mask(pfc::string_base & out,bool b_include_playlists=true, bool b_include_archives = false);
static void build_openfile_mask(pfc::string_base & out,bool b_include_playlists=true);
static void make_extension_support_fingerprint(pfc::string_base & str);
static void make_filetype_support_fingerprint(pfc::string_base & str);
#endif

View File

@@ -1,8 +1,3 @@
#pragma once
#include "input.h"
#include "mem_block_container.h"
enum t_input_open_reason {
input_open_info_read,
input_open_decode,
@@ -78,8 +73,7 @@ public:
//! See: input_decoder_v2::run_raw(). Relevant only when implementing input_decoder_v2. Valid after decode_initialize().
bool decode_run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort);
//! OLD way: may be called at any time from input_decoder_v2 \n
//! NEW way (1.5): called prior to open().
//! See: input_decoder::set_logger(). Relevant only when implementing input_decoder_v2. Valid after any open().
void set_logger(event_logger::ptr ptr);
protected:
input_impl() {}
@@ -98,11 +92,6 @@ public:
static GUID g_get_preferences_guid() {return pfc::guid_null;}
static bool g_is_low_merit() { return false; }
bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) { return false; }
bool decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) { return false; }
void decode_on_idle(abort_callback & p_abort) { }
//! These typedefs indicate which interfaces your class actually supports. You can override them to support non default input API interfaces without specifying input_factory parameters.
typedef input_decoder_v4 interface_decoder_t;
typedef input_info_reader interface_info_reader_t;
@@ -165,9 +154,8 @@ template<typename I, typename interface_t>
class input_impl_interface_wrapper_t : public interface_t
{
public:
template<typename ... args_t>
void open( args_t && ... args) {
m_instance.open(std::forward<args_t>(args) ... );
void open(service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) {
m_instance.open(p_filehint,p_path,p_reason,p_abort);
}
// input_info_reader methods
@@ -307,10 +295,9 @@ class input_wrapper_singletrack_t : public input_forward_static_methods<I>
public:
input_wrapper_singletrack_t() {}
template<typename ... args_t>
void open( args_t && ... args) {
m_instance.open(std::forward<args_t>(args) ... );
}
void open(service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) {
m_instance.open(p_filehint,p_path,p_reason,p_abort);
}
void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort) {
if (p_subsong != 0) throw exception_io_bad_subsong_index();
@@ -373,40 +360,32 @@ private:
//! Helper; standard input_entry implementation. Do not instantiate this directly, use input_factory_t or one of other input_*_factory_t helpers instead.
template<typename I,unsigned t_flags, typename t_decoder = typename I::interface_decoder_t, typename t_inforeader = typename I::interface_info_reader_t, typename t_infowriter = typename I::interface_info_writer_t>
class input_entry_impl_t : public input_entry_v3
class input_entry_impl_t : public input_entry_v2
{
private:
template<typename T, typename out>
void instantiate_t(service_ptr_t<out> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort)
{
service_ptr_t< service_impl_t<input_impl_interface_wrapper_t<I,T> > > temp;
temp = new service_impl_t<input_impl_interface_wrapper_t<I,T> >();
temp->open(p_filehint,p_path,p_reason,p_abort);
p_instance = temp.get_ptr();
}
public:
bool is_our_content_type(const char * p_type) {return I::g_is_our_content_type(p_type);}
bool is_our_path(const char * p_full_path,const char * p_extension) {return I::g_is_our_path(p_full_path,p_extension);}
void open_for_decoding(service_ptr_t<input_decoder> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort) {
instantiate_t<t_decoder>(p_instance,p_filehint,p_path,input_open_decode,p_abort);
}
template<typename interface_t, typename outInterace_t, typename ... args_t>
void open_ex(service_ptr_t<outInterace_t> & p_instance,args_t && ... args)
{
auto temp = fb2k::service_new<input_impl_interface_wrapper_t<I,interface_t> >();
temp->open(std::forward<args_t>(args) ... );
p_instance = temp.get_ptr();
}
void 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) {
instantiate_t<t_inforeader>(p_instance,p_filehint,p_path,input_open_info_read,p_abort);
}
service_ptr open_v3(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter) {
if ( whatFor == input_decoder::class_guid ) {
auto obj = fb2k::service_new< input_impl_interface_wrapper_t<I,t_decoder> > ();
if ( logger.is_valid() ) obj->set_logger(logger);
obj->open( hint, path, input_open_decode, aborter );
return obj;
}
if ( whatFor == input_info_reader::class_guid ) {
auto obj = fb2k::service_new < input_impl_interface_wrapper_t<I, t_inforeader> >();
if (logger.is_valid()) obj->set_logger(logger);
obj->open(hint, path, input_open_info_read, aborter);
return obj;
}
if ( whatFor == input_info_writer::class_guid ) {
auto obj = fb2k::service_new < input_impl_interface_wrapper_t<I, t_infowriter> >();
if (logger.is_valid()) obj->set_logger(logger);
obj->open(hint, path, input_open_info_write, aborter);
return obj;
}
throw pfc::exception_not_implemented();
void 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) {
instantiate_t<t_infowriter>(p_instance,p_filehint,p_path,input_open_info_write,p_abort);
}
void get_extended_data(service_ptr_t<file> p_filehint,const playable_location & p_location,const GUID & p_guid,mem_block_container & p_out,abort_callback & p_abort) {

View File

@@ -195,12 +195,3 @@ class NOVTABLE library_meta_autocomplete : public service_base {
public:
virtual bool get_value_list(const char * metaName, pfc::com_ptr_t<IUnknown> & out) = 0;
};
//! \since 1.6.1
//! Caching & asynchronous version. \n
//! Keep a reference to your library_meta_autocomplete_v2 object in your dialog class to cache the looked up values & speed up the operation.
class NOVTABLE library_meta_autocomplete_v2 : public service_base {
FB2K_MAKE_SERVICE_COREAPI(library_meta_autocomplete_v2)
public:
virtual bool get_value_list_async(const char* metaName, pfc::com_ptr_t<IUnknown>& out) = 0;
};

View File

@@ -1,27 +1,6 @@
#pragma once
#include <functional>
// ======================================================================================================
// Most of main_thread_callback.h declares API internals and obsolete helpers.
// In modern code, simply use fb2k::inMainThread() declared below and disregard the rest.
// ======================================================================================================
namespace fb2k {
//! Queue a call in main thread. Returns immediately. \n
//! You can call this from any thread, including main thread - to execute some code outside the current call stack / global fb2k callbacks / etc.
void inMainThread(std::function<void() > f);
//! Call f synchronously if called from main thread, queue call if called from another.
void inMainThread2(std::function<void() > f);
}
// ======================================================================================================
// API declarations
// ======================================================================================================
//! Callback object class for main_thread_callback_manager service. \n
//! You do not need to implement this directly - simply use fb2k::inMainThread() with a lambda.
//! Callback object class for main_thread_callback_manager service.
class NOVTABLE main_thread_callback : public service_base {
public:
//! Gets called from main app thread. See main_thread_callback_manager description for more info.
@@ -34,8 +13,7 @@ public:
/*!
Allows you to queue a callback object to be called from main app thread. This is commonly used to trigger main-thread-only API calls from worker threads.\n
This can be also used from main app thread, to avoid race conditions when trying to use APIs that dispatch global callbacks from inside some other global callback, or using message loops / modal dialogs inside global callbacks. \n
There is no need to use this API directly - use fb2k::inMainThread() with a lambda.
This can be also used from main app thread, to avoid race conditions when trying to use APIs that dispatch global callbacks from inside some other global callback, or using message loops / modal dialogs inside global callbacks.
*/
class NOVTABLE main_thread_callback_manager : public service_base {
public:
@@ -46,11 +24,6 @@ public:
};
// ======================================================================================================
// Obsolete helpers - they still work, but it's easier to just use fb2k::inMainThread().
// ======================================================================================================
//! Helper, equivalent to main_thread_callback_manager::get()->add_callback(ptr)
void main_thread_callback_add(main_thread_callback::ptr ptr);
template<typename t_class> static void main_thread_callback_spawn() {
@@ -107,8 +80,7 @@ static void callInMainThreadSvc(myservice_t * host, param_t const & param) {
//! Have this as a member of your class, then use m_mthelper.add( this, somearg ) ; to defer a call to this->inMainThread(somearg). \n
//! If your class becomes invalid before inMainThread is executed, the pending callback is discarded. \n
//! You can optionally call shutdown() to invalidate all pending callbacks early (in a destructor of your class - without waiting for callInMainThreadHelper destructor to do the job. \n
//! In order to let callInMainThreadHelper access your private methods, declare friend class callInMainThread. \n
//! Note that callInMainThreadHelper is expected to be created and destroyed in main thread.
//! In order to let callInMainThreadHelper access your private methods, declare friend class callInMainThread.
class callInMainThreadHelper {
public:
@@ -185,3 +157,11 @@ private:
killswitch_t m_ks;
};
// Modern helper
namespace fb2k {
// Queue call in main thread
void inMainThread( std::function<void () > f );
// Call f synchronously if called from main thread, queue call if called from another
void inMainThread2( std::function<void () > f );
}

View File

@@ -2,8 +2,6 @@
#ifdef WIN32
#include "ui_element_typable_window_manager.h"
static void fix_ampersand(const char * src,pfc::string_base & out)
{
out.reset();
@@ -351,8 +349,8 @@ bool keyboard_shortcut_manager::on_keydown_restricted_auto_context(const pfc::li
static bool filterTypableWindowMessage(const MSG * msg, t_uint32 modifiers) {
if (keyboard_shortcut_manager::is_typing_key_combo((t_uint32)msg->wParam, modifiers)) {
const DWORD mask = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
auto status = ::SendMessage(msg->hwnd, WM_GETDLGCODE,0, 0);
if ( (status & mask) == mask ) return false;
auto status = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
if ((status & mask) == mask) return false;
ui_element_typable_window_manager::ptr api;
if (ui_element_typable_window_manager::tryGet(api)) {

View File

@@ -1,5 +1,5 @@
#include "foobar2000.h"
#include "file_info_filter_impl.h"
void metadb::handle_create_replace_path_canonical(metadb_handle_ptr & p_out,const metadb_handle_ptr & p_source,const char * p_new_path) {
handle_create(p_out,make_playable_location(p_new_path,p_source->get_subsong_index()));
@@ -93,20 +93,3 @@ void metadb_io_v2::on_files_rechaptered( metadb_handle_list_cref newHandles ) {
load_info_async( newHandles, metadb_io::load_info_force, core_api::get_main_window(), metadb_io_v3::op_flag_delay_ui, notify );
}
metadb_hint_list::ptr metadb_hint_list::create() {
return metadb_io_v2::get()->create_hint_list();
}
metadb_hint_list_v2::ptr metadb_hint_list_v2::create() {
metadb_hint_list_v2::ptr ret;
ret ^= metadb_hint_list::create();
return ret;
}
metadb_hint_list_v3::ptr metadb_hint_list_v3::create() {
metadb_hint_list_v3::ptr ret;
ret ^= metadb_hint_list::create();
return ret;
}

View File

@@ -1,9 +1,3 @@
#pragma once
class file_info_filter; // forward decl; file_info_filter moved to file_info_filter.h
//! API for tag read/write operations. Legal to call from main thread only, except for hint_multi_async() / hint_async() / hint_reader().\n
//! Implemented only by core, do not reimplement.\n
//! Use static_api_ptr_t template to access metadb_io methods.\n
@@ -68,72 +62,49 @@ public:
FB2K_MAKE_SERVICE_COREAPI(metadb_io);
};
//! Advanced interface for passing infos read from files to metadb backend. Use metadb_io_v2::create_hint_list() to instantiate. \n
//! Thread safety: all methods other than on_done() are intended for worker threads. Instantiate and use the object in a worker thread, call on_done() in main thread to finalize. \n
//! Typical usage pattern: create a hint list (in any thread), hand infos to it from files that you work with (in a worker thread), call on_done() in main thread. \n
//! Implementing this class gives you direct control over which part of file_info gets altered during a tag update uperation. To be used with metadb_io_v2::update_info_async().
class NOVTABLE file_info_filter : public service_base {
public:
//! Alters specified file_info entry; called as a part of tag update process. Specified file_info has been read from a file, and will be written back.\n
//! WARNING: This will be typically called from another thread than main app thread (precisely, from thread created by tag updater). You should copy all relevant data to members of your file_info_filter instance in constructor and reference only member data in apply_filter() implementation.
//! @returns True when you have altered file_info and changes need to be written back to the file; false if no changes have been made.
virtual bool apply_filter(metadb_handle_ptr p_location,t_filestats p_stats,file_info & p_info) = 0;
FB2K_MAKE_SERVICE_INTERFACE(file_info_filter,service_base);
};
//! Advanced interface for passing infos read from files to metadb backend. Use metadb_io_v2::create_hint_list() to instantiate.
class NOVTABLE metadb_hint_list : public service_base {
FB2K_MAKE_SERVICE_INTERFACE(metadb_hint_list,service_base);
public:
//! Helper.
static metadb_hint_list::ptr create();
//! Adds a hint to the list.
//! @param p_location Location of the item the hint applies to.
//! @param p_info file_info object describing the item.
//! @param p_stats Information about the file containing item the hint applies to.
//! @param p_freshflag Set to true if the info has been directly read from the file, false if it comes from another source such as a playlist file.
virtual void add_hint(metadb_handle_ptr const & p_location,const file_info & p_info,const t_filestats & p_stats,bool p_freshflag) = 0;
//! Reads info from specified info reader instance and adds hints. May throw an exception in case info read has failed. \n
//! If the file has multiple subsongs, info from all the subsongs will be read and pssed to add_hint(). \n
//! Note that an input_info_writer is a subclass of input_info_reader - so any input_info_reader OR input_info_writer is a valid argument for add_hint_reader(). \n
//! This method is often called with your input_info_writer instance after committing tag updates, to notify metadb about altered tags.
//! Reads info from specified info reader instance and adds hints. May throw an exception in case info read has failed.
virtual void add_hint_reader(const char * p_path,service_ptr_t<input_info_reader> const & p_reader,abort_callback & p_abort) = 0;
//! Call this when you're done working with this metadb_hint_list instance, to apply hints and dispatch callbacks. \n
//! If you don't call this, all added hints will be ignored. \n
//! As a general rule, you should add as many infos as possible - such as all the tracks involved in some operation that you perform - then call on_done() once. \n
//! on_done() is expensive because it not only updates the metadb, but tells all components about the changes made - refreshes playlists/autoplaylists, library viewers, etc. \n
//! Calling on_done() repeatedly is inefficient and should be avoided.
//! Call this when you're done working with this metadb_hint_list instance, to apply hints and dispatch callbacks. If you don't call this, all added hints will be ignored.
virtual void on_done() = 0;
};
//! \since 1.0
//! To obtain metadb_hint_list_v2, use service_query on a metadb_hint_list object. \n
//! Simplified: metadb_hint_list_v2::ptr v2; v2 ^= myHintList; ( causes bugcheck if old fb2k / no interface ).
class NOVTABLE metadb_hint_list_v2 : public metadb_hint_list {
FB2K_MAKE_SERVICE_INTERFACE(metadb_hint_list_v2, metadb_hint_list);
public:
//! Helper.
static metadb_hint_list_v2::ptr create();
//! Hint with browse info. \n
//! See: metadb_handle::get_browse_info() for browse info rationale.
//! @param p_location Location for which we're providing browse info.
//! @param p_info Browse info for this location.
//! @param browseTS timestamp of the browse info - such as last-modified time of the playlist file providing browse info.
virtual void add_hint_browse(metadb_handle_ptr const & p_location,const file_info & p_info, t_filetimestamp browseTS) = 0;
};
//! \since 1.3
//! To obtain metadb_hint_list_v3, use service_query on a metadb_hint_list object. \n
//! Simplified: metadb_hint_list_v3::ptr v3; v3 ^= myHintList; ( causes bugcheck if old fb2k / no interface ).
class NOVTABLE metadb_hint_list_v3 : public metadb_hint_list_v2 {
FB2K_MAKE_SERVICE_INTERFACE(metadb_hint_list_v3, metadb_hint_list_v2);
public:
//! Helper.
static metadb_hint_list_v3::ptr create();
//! Hint primary info with a metadb_info_container.
virtual void add_hint_v3(metadb_handle_ptr const & p_location, metadb_info_container::ptr info,bool p_freshflag) = 0;
//! Hint browse info with a metadb_info_container.
virtual void add_hint_browse_v3(metadb_handle_ptr const & p_location,metadb_info_container::ptr info) = 0;
//! Add a forced hint.\n
//! A normal hint may or may not cause metadb update - metadb is not updated if the file has not changed according to last modified time. \n
//! A forced hint always updates metadb regardless of timestamps.
virtual void add_hint_forced(metadb_handle_ptr const & p_location, const file_info & p_info,const t_filestats & p_stats,bool p_freshflag) = 0;
//! Add a forced hint, with metadb_info_container. \n
//! Forced hint rationale - see add_hint_forced().
virtual void add_hint_forced_v3(metadb_handle_ptr const & p_location, metadb_info_container::ptr info,bool p_freshflag) = 0;
//! Adds a forced hint, with an input_info_reader. \n
//! Forced hint rationale - see add_hint_forced(). \n
//! Info reader use rationale - see add_hint_reader().
virtual void add_hint_forced_reader(const char * p_path,service_ptr_t<input_info_reader> const & p_reader,abort_callback & p_abort) = 0;
};
@@ -178,8 +149,7 @@ public:
//! @param p_notify Called when the task is completed. Status code is one of t_update_info values. Can be null if caller doesn't care.
virtual void remove_info_async(metadb_handle_list_cref p_list,HWND p_parent_window,t_uint32 p_op_flags,completion_notify_ptr p_notify) = 0;
//! Creates a metadb_hint_list object. \n
//! Contrary to other metadb_io methods, this can be safely called in a worker thread. You only need to call the hint list's on_done() method in main thread to finalize.
//! Creates a metadb_hint_list object.
virtual metadb_hint_list::ptr create_hint_list() = 0;
//! Updates tags of the specified tracks. Helper; uses update_info_async internally.
@@ -192,8 +162,6 @@ public:
//! Helper to be called after a file has been rechaptered. \n
//! Forcibly reloads info then tells playlist_manager to update all affected playlists.
void on_file_rechaptered( const char * path, metadb_handle_list_cref newItems );
//! Helper to be called after a file has been rechaptered. \n
//! Forcibly reloads info then tells playlist_manager to update all affected playlists.
void on_files_rechaptered( metadb_handle_list_cref newHandles );
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v2,metadb_io);
@@ -206,7 +174,7 @@ public:
virtual void on_changed_sorted(metadb_handle_list_cref p_items_sorted, bool p_fromhook) = 0;
};
//! \since 0.9.5
//! New (0.9.5)
class NOVTABLE metadb_io_v3 : public metadb_io_v2 {
public:
virtual void register_callback(metadb_io_callback_dynamic * p_callback) = 0;
@@ -215,29 +183,6 @@ public:
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v3,metadb_io_v2);
};
class threaded_process_callback;
#if FOOBAR2000_TARGET_VERSION >= 80
//! \since 1.5
class NOVTABLE metadb_io_v4 : public metadb_io_v3 {
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v4, metadb_io_v3);
public:
//! Creates an update-info task, that can be either fed to threaded_process API, or invoked by yourself respecting threaded_process semantics. \n
//! May return null pointer if the operation has been refused (by user settings or such). \n
//! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup.
virtual service_ptr_t<threaded_process_callback> spawn_update_info( metadb_handle_list_cref items, service_ptr_t<file_info_filter> p_filter, uint32_t opFlags, completion_notify_ptr reply ) = 0;
//! Creates an remove-info task, that can be either fed to threaded_process API, or invoked by yourself respecting threaded_process semantics. \n
//! May return null pointer if the operation has been refused (by user settings or such). \n
//! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup.
virtual service_ptr_t<threaded_process_callback> spawn_remove_info( metadb_handle_list_cref items, uint32_t opFlags, completion_notify_ptr reply) = 0;
//! Creates an load-info task, that can be either fed to threaded_process API, or invoked by yourself respecting threaded_process semantics. \n
//! May return null pointer if the operation has been refused (for an example no loading is needed for these items). \n
//! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup.
virtual service_ptr_t<threaded_process_callback> spawn_load_info( metadb_handle_list_cref items, t_load_info_type opType, uint32_t opFlags, completion_notify_ptr reply) = 0;
};
#endif
//! metadb_io_callback_dynamic implementation helper.
class metadb_io_callback_dynamic_impl_base : public metadb_io_callback_dynamic {
public:
@@ -297,8 +242,8 @@ public:
//! @returns True on success; false on failure (no known playable locations).
static bool g_get_random_handle(metadb_handle_ptr & p_out);
enum {case_sensitive = playable_location::case_sensitive};
typedef playable_location::path_comparator path_comparator;
enum {case_sensitive = true};
typedef pfc::comparator_strcmp path_comparator;
inline static int path_compare_ex(const char * p1,t_size len1,const char * p2,t_size len2) {return case_sensitive ? pfc::strcmp_ex(p1,len1,p2,len2) : stricmp_utf8_ex(p1,len1,p2,len2);}
inline static int path_compare_nc(const char * p1, size_t len1, const char * p2, size_t len2) {return case_sensitive ? pfc::strcmp_nc(p1,len1,p2,len2) : stricmp_utf8_ex(p1,len1,p2,len2);}
@@ -349,6 +294,38 @@ public:
//! Helper implementation of file_info_filter_impl.
class file_info_filter_impl : public file_info_filter {
public:
file_info_filter_impl(const pfc::list_base_const_t<metadb_handle_ptr> & p_list,const pfc::list_base_const_t<const file_info*> & p_new_info) {
FB2K_DYNAMIC_ASSERT(p_list.get_count() == p_new_info.get_count());
pfc::array_t<t_size> order;
order.set_size(p_list.get_count());
order_helper::g_fill(order.get_ptr(),order.get_size());
p_list.sort_get_permutation_t(pfc::compare_t<metadb_handle_ptr,metadb_handle_ptr>,order.get_ptr());
m_handles.set_count(order.get_size());
m_infos.set_size(order.get_size());
for(t_size n = 0; n < order.get_size(); n++) {
m_handles[n] = p_list[order[n]];
m_infos[n] = *p_new_info[order[n]];
}
}
bool apply_filter(metadb_handle_ptr p_location,t_filestats p_stats,file_info & p_info) {
t_size index;
if (m_handles.bsearch_t(pfc::compare_t<metadb_handle_ptr,metadb_handle_ptr>,p_location,index)) {
p_info = m_infos[index];
return true;
} else {
return false;
}
}
private:
metadb_handle_list m_handles;
pfc::array_t<file_info_impl> m_infos;
};
//! \since 1.1
//! metadb_index_manager hash, currently a 64bit int, typically made from halving MD5 hash.
typedef t_uint64 metadb_index_hash;

View File

@@ -99,30 +99,3 @@ metadb_info_container::ptr metadb_handle::get_full_info_ref( abort_callback & ab
reader->get_info( this->get_subsong_index(), obj->m_info, aborter );
return obj;
}
namespace fb2k {
pfc::string_formatter formatTrackList( metadb_handle_list_cref lst ) {
pfc::string_formatter ret;
auto cnt = lst.get_count();
if ( cnt == 0 ) ret << "[Empty track list]\n";
else {
if (cnt == 1) ret << "[Track list: 1 track]\n";
else ret << "[Track list: " << cnt << " tracks]\n";
for( size_t walk = 0; walk < cnt; ++ walk ) {
ret << " " << lst[walk]->get_location() << "\n";
}
ret << "[Track list end]";
}
return ret;
}
pfc::string_formatter formatTrackTitle(metadb_handle_ptr item, const char * script ) {
pfc::string_formatter ret;
item->format_title_legacy(NULL,ret,script,NULL);
return ret;
}
pfc::string_formatter formatTrackTitle(metadb_handle_ptr item,service_ptr_t<class titleformat_object> script) {
pfc::string_formatter ret;
item->format_title(NULL,ret,script,NULL);
return ret;
}
}

View File

@@ -1,5 +1,3 @@
#pragma once
class titleformat_hook;
class titleformat_text_filter;
class titleformat_object;
@@ -17,6 +15,7 @@ public:
//! To obtain a metadb_handle to specific location, use metadb::handle_create(). To obtain a list of metadb_handle objects corresponding to specific path (directory, playlist, multitrack file, etc), use relevant playlist_incoming_item_filter methods (recommended), or call playlist_loader methods directly.\n
//! A metadb_handle is also the most efficient way of passing playable object locations around because it provides fast access to both location and infos, and is reference counted so duplicating it is as fast as possible.\n
//! To retrieve a path of a file from a metadb_handle, use metadb_handle::get_path() function. Note that metadb_handle is NOT just file path, some formats support multiple subsongs per physical file, which are signaled using subsong indexes.
class NOVTABLE metadb_handle : public service_base
{
public:
@@ -40,11 +39,9 @@ public:
//! Returns last seen file stats, filestats_invalid if unknown.
virtual t_filestats get_filestats() const = 0;
//! Obsolete, use get_info_ref() family of methods instead. \n
//! Queries whether cached info about item referenced by this metadb_handle object is already available. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden.\n
//! Note that state of cached info changes only inside main thread, so you can safely assume that it doesn't change while some block of your code inside main thread is being executed.
virtual bool is_info_loaded() const = 0;
//! Obsolete, use get_info_ref() instead. \n
//! Queries cached info about item referenced by this metadb_handle object. Returns true on success, false when info is not yet known. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden. \n
//! Note that state of cached info changes only inside main thread, so you can safely assume that it doesn't change while some block of your code inside main thread is being executed.
virtual bool get_info(file_info & p_info) const = 0;
@@ -52,11 +49,9 @@ public:
//! OBSOLETE, DO NOT CALL
__declspec(deprecated) virtual bool get_info_locked(const file_info * & p_info) const = 0;
//! Obsolete, use get_info_ref() family of methods instead. \n
//! Queries whether cached info about item referenced by this metadb_handle object is already available.\n
//! This is intended for use in special cases when you need to immediately retrieve info sent by metadb_io hint from another thread; state of returned data can be altered by any thread, as opposed to non-async methods.
virtual bool is_info_loaded_async() const = 0;
//! Obsolete, use get_info_ref() family of methods instead. \n
virtual bool is_info_loaded_async() const = 0;
//! Queries cached info about item referenced by this metadb_handle object. Returns true on success, false when info is not yet known. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden.\n
//! This is intended for use in special cases when you need to immediately retrieve info sent by metadb_io hint from another thread; state of returned data can be altered by any thread, as opposed to non-async methods.
virtual bool get_info_async(file_info & p_info) const = 0;
@@ -73,40 +68,34 @@ public:
__declspec(deprecated) virtual void format_title_from_external_info_nonlocking(const file_info & p_info,titleformat_hook * p_hook,pfc::string_base & p_out,const service_ptr_t<titleformat_object> & p_script,titleformat_text_filter * p_filter) = 0;
#if FOOBAR2000_TARGET_VERSION >= 76
//! \since 1.0
//! Returns browse info for this track. \n
//! Browse info comes from an external source - such as internet playlist metadata - not from the media file itself, and is maintained separately. \n
//! When title formatting calls are invoked on for a track having browse info present, data for title formatting is sourced from both primary and browse info. \n
//! Example: internet radio stream provides no metadata but its playlist XML has title (radio station name), %title% resolves to the radio station name from the playlist.
//! New in 1.0
virtual bool get_browse_info(file_info & info, t_filetimestamp & ts) const = 0;
//! \since 1.0
//! OBSOLETE, DO NOT CALL
__declspec(deprecated) virtual bool get_browse_info_locked(const file_info * & p_info, t_filetimestamp & ts) const = 0;
#endif
#if FOOBAR2000_TARGET_VERSION >= 78
//! \since 1.3
//! Retrieve a reference to the primary info. \n
//! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n
//! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes.
//! Returns true and sets outInfo to a reference to this item's primary info on success, returns false on failure (no info known at this time).
virtual bool get_info_ref(metadb_info_container::ptr & outInfo) const = 0;
//! \since 1.3
//! Retrieve a reference to the async info (pending info update). If async info isn't set, a reference to the primary info is returned.\n
//! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n
//! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes.
//! Returns true and sets outInfo to a reference to this item's async or primary info on success, returns false on failure (no info known at this time).
virtual bool get_async_info_ref(metadb_info_container::ptr & outInfo) const = 0;
//! \since 1.3
//! Retrieve references to the item's primary and browse infos. If no info is set, NULL pointers are returned. For most local files, browse info is not available and you get a NULL for it.\n
//! Since browse info is usually used along with the primary info (as a fallback for missing metas), you can get the two with one call for better performance. \n
//! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n
//! See also: get_browse_info(), for browse info rationale.
//! Since browse info is usually used along with the primary info (as a fallback for missing metas), you can get the two with one call for better performance.
//! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes.
virtual void get_browse_info_ref(metadb_info_container::ptr & outInfo, metadb_info_container::ptr & outBrowse) const = 0;
//! Simplified method, always returns non-null, dummy info if nothing to return.
//! Simplified method, always returns non-null, dummy info if nothing to return
virtual metadb_info_container::ptr get_info_ref() const = 0;
//! Simplified method, always returns non-null, dummy info if nothing to return.
//! Simplified method, always returns non-null, dummy info if nothing to return
virtual metadb_info_container::ptr get_async_info_ref() const = 0;
//! \since 1.3
@@ -116,11 +105,10 @@ public:
#endif
//! \since 1.3
//! Helper using get_browse_info_ref(). \n
//! Retrieves primary info + browse info merged together. \n
//! Returns true on success, false if neither info is available. \n
//! If neither info is avaialble, output data structure is emptied. \n
//! See also: get_browse_info() for browse info rationale.
//! Helper using get_browse_info_ref()
//! Retrieves primary info + browse info merged together.
//! Returns true on success, false if neither info is available.
//! If neither info is avaialble, output data structure is emptied.
bool get_browse_info_merged(file_info & infoMerged) const;
@@ -143,9 +131,6 @@ public:
t_filetimestamp get_filetimestamp();
t_filesize get_filesize();
//! Internal method, do not use
inline const char * _get_path() const { return get_path(); }
FB2K_MAKE_SERVICE_INTERFACE(metadb_handle,service_base);
};
@@ -253,10 +238,17 @@ inline pfc::string_base & operator<<(pfc::string_base & p_fmt,const metadb_handl
}
class string_format_title {
public:
string_format_title(metadb_handle_ptr p_item,const char * p_script) {
p_item->format_title_legacy(NULL,m_data,p_script,NULL);
}
string_format_title(metadb_handle_ptr p_item,service_ptr_t<class titleformat_object> p_script) {
p_item->format_title(NULL,m_data,p_script,NULL);
}
namespace fb2k {
pfc::string_formatter formatTrackList( metadb_handle_list_cref );
pfc::string_formatter formatTrackTitle(metadb_handle_ptr item, const char * script = "%title%" );
pfc::string_formatter formatTrackTitle(metadb_handle_ptr item,service_ptr_t<class titleformat_object> script);
}
const char * get_ptr() const {return m_data.get_ptr();}
operator const char * () const {return m_data.get_ptr();}
private:
pfc::string8_fastalloc m_data;
};

View File

@@ -89,7 +89,8 @@ namespace {
void metadb_handle_list_helper::sort_by_format_get_order(metadb_handle_list_cref p_list,t_size* order,const service_ptr_t<titleformat_object> & p_script,titleformat_hook * p_hook,int p_direction)
{
sort_by_format_get_order_v2(p_list, order, p_script, p_hook, p_direction, fb2k::noAbort );
abort_callback_dummy noAbort;
sort_by_format_get_order_v2(p_list, order, p_script, p_hook, p_direction, noAbort );
}
void metadb_handle_list_helper::sort_by_relative_path(metadb_handle_list_ref p_list)

View File

@@ -44,11 +44,12 @@ public:
set_entry_count(total);
t_size done = 0;
pfc::string8 name; metadb_handle_list content;
abort_callback_dummy abort;
for(t_size walk = 0; walk < pltotal; ++walk) if (mask[walk]) {
pfc::dynamic_assert( done < total );
api->playlist_get_name(walk,name); api->playlist_get_all_items(walk,content);
set_entry_name(done,name); set_entry_content(done,content);
stream_writer_buffer_simple sideData; api->playlist_get_sideinfo(walk, &sideData, fb2k::noAbort);
stream_writer_buffer_simple sideData; api->playlist_get_sideinfo(walk, &sideData, abort);
set_side_data(done,sideData.m_buffer.get_ptr(), sideData.m_buffer.get_size());
++done;
}

View File

@@ -1,13 +1,9 @@
#include "foobar2000.h"
#include "output.h"
#include "audio_chunk_impl.h"
#include "dsp.h"
#include "resampler.h"
pfc::string8 output_entry::get_device_name( const GUID & deviceID ) {
pfc::string8 temp;
if (!get_device_name(deviceID, temp)) temp = "[unknown device]";
return temp;
return std::move(temp);
}
namespace {
@@ -50,25 +46,8 @@ output_entry::ptr output_entry::g_find( const GUID & outputID ) {
}
bool output::is_progressing_() {
output_v4::ptr v4;
if ( v4 &= this ) return v4->is_progressing();
return true;
}
size_t output::update_v2_() {
output_v4::ptr v4;
if ( v4 &= this ) return v4->update_v2();
bool bReady = false;
this->update(bReady);
return bReady ? SIZE_MAX : 0;
}
pfc::eventHandle_t output::get_trigger_event_() {
output_v4::ptr v4;
if ( v4 &= this ) return v4->get_trigger_event();
return pfc::eventInvalid;
}
void output_impl::flush() {
m_incoming_ptr = 0;
@@ -80,11 +59,7 @@ void output_impl::flush_changing_track() {
m_incoming.set_size(0);
on_flush_changing_track();
}
void output_impl::update(bool & p_ready) {
p_ready = update_v2() > 0;
}
size_t output_impl::update_v2() {
on_update();
if (m_incoming_spec != m_active_spec && m_incoming_ptr < m_incoming.get_size()) {
if (get_latency_samples() == 0) {
@@ -93,8 +68,7 @@ size_t output_impl::update_v2() {
} else {
force_play();
}
}
size_t retCanWriteSamples = 0;
}
if (m_incoming_spec == m_active_spec && m_incoming_ptr < m_incoming.get_size()) {
t_size cw = can_write_samples() * m_incoming_spec.m_channels;
t_size delta = pfc::min_t(m_incoming.get_size() - m_incoming_ptr,cw);
@@ -102,13 +76,9 @@ size_t output_impl::update_v2() {
write(audio_chunk_temp_impl(m_incoming.get_ptr()+m_incoming_ptr,delta / m_incoming_spec.m_channels,m_incoming_spec.m_sample_rate,m_incoming_spec.m_channels,m_incoming_spec.m_channel_config));
m_incoming_ptr += delta;
}
retCanWriteSamples = (cw - delta) / m_incoming_spec.m_channels;
} else if ( m_incoming_ptr == m_incoming.get_size() ) {
retCanWriteSamples = SIZE_MAX;
}
return retCanWriteSamples;
}
p_ready = (m_incoming_ptr == m_incoming.get_size());
}
double output_impl::get_latency() {
double ret = 0;
if (m_incoming_spec.is_valid()) {
@@ -117,7 +87,7 @@ double output_impl::get_latency() {
if (m_active_spec.is_valid()) {
ret += audio_math::samples_to_time( get_latency_samples() , m_active_spec.m_sample_rate );
}
return ret;
return ret;
}
void output_impl::process_samples(const audio_chunk & p_chunk) {
pfc::dynamic_assert(m_incoming_ptr == m_incoming.get_size());
@@ -131,50 +101,18 @@ void output_impl::process_samples(const audio_chunk & p_chunk) {
}
void output_v3::get_injected_dsps( dsp_chain_config & dsps ) {
#ifdef FOOBAR2000_HAVE_DSP
dsps.remove_all();
#if 0 // DEPRECATED
unsigned rate = this->get_forced_sample_rate();
if (rate != 0) {
#if PFC_DEBUG
FB2K_console_formatter() << "output_v3::get_injected_dsps() : requesting resampling to " << rate << " Hz";
#endif
dsp_preset_impl temp;
if (resampler_entry::g_create_preset( temp, 0, rate, 0 )) {
dsps.insert_item( temp, dsps.get_count() );
} else {
#if PFC_DEBUG
FB2K_console_formatter() << "output_v3::get_injected_dsps() : resampler could not be created";
#endif
}
}
#endif
#endif // FOOBAR2000_HAVE_DSP
}
size_t output_v4::update_v2() {
bool bReady = false;
update(bReady);
return bReady ? SIZE_MAX : 0;
}
uint32_t output_entry::get_config_flags_compat() {
uint32_t ret = get_config_flags();
if ((ret & (flag_low_latency | flag_high_latency)) == 0) {
// output predating flag_high_latency + flag_low_latency
// if it's old foo_out_upnp, report high latency, otherwise low latency.
static const GUID guid_foo_out_upnp = { 0x9900b4f6, 0x8431, 0x4b0a, { 0x95, 0x56, 0xa7, 0xfc, 0xb9, 0x5b, 0x74, 0x3 } };
if (this->get_guid() == guid_foo_out_upnp) ret |= flag_high_latency;
else ret |= flag_low_latency;
}
return ret;
}
bool output_entry::is_high_latency() {
return (this->get_config_flags_compat() & flag_high_latency) != 0;
}
bool output_entry::is_low_latency() {
return (this->get_config_flags_compat() & flag_low_latency) != 0;
}
// {EEEB07DE-C2C8-44c2-985C-C85856D96DA1}
const GUID output_id_null =

View File

@@ -4,9 +4,6 @@
PFC_DECLARE_EXCEPTION(exception_output_device_not_found, pfc::exception, "Audio device not found")
PFC_DECLARE_EXCEPTION(exception_output_module_not_found, exception_output_device_not_found, "Output module not found")
PFC_DECLARE_EXCEPTION(exception_output_invalidated, pfc::exception, "Audio device invalidated")
PFC_DECLARE_EXCEPTION(exception_output_device_in_use, pfc::exception, "Audio device in use")
PFC_DECLARE_EXCEPTION(exception_output_unsupported_stream_format, pfc::exception, "Unsupported audio stream format")
// =======================================================
@@ -20,15 +17,17 @@ PFC_DECLARE_EXCEPTION(exception_output_unsupported_stream_format, pfc::exception
//! Structure describing PCM audio data format, with basic helper functions.
struct t_pcmspec
{
unsigned m_sample_rate = 0;
unsigned m_bits_per_sample = 0;
unsigned m_channels = 0,m_channel_config = 0;
bool m_float = false;
inline t_pcmspec() {reset();}
inline t_pcmspec(const t_pcmspec & p_source) {*this = p_source;}
unsigned m_sample_rate;
unsigned m_bits_per_sample;
unsigned m_channels,m_channel_config;
bool m_float;
inline unsigned align() const {return (m_bits_per_sample / 8) * m_channels;}
uint64_t time_to_bytes(double p_time) const {return audio_math::time_to_samples(p_time,m_sample_rate) * (m_bits_per_sample / 8) * m_channels;}
double bytes_to_time(uint64_t p_bytes) const {return (double) (p_bytes / ((m_bits_per_sample / 8) * m_channels)) / (double) m_sample_rate;}
t_size time_to_bytes(double p_time) const {return (t_size)audio_math::time_to_samples(p_time,m_sample_rate) * (m_bits_per_sample / 8) * m_channels;}
double bytes_to_time(t_size p_bytes) const {return (double) (p_bytes / ((m_bits_per_sample / 8) * m_channels)) / (double) m_sample_rate;}
inline bool operator==(/*const t_pcmspec & p_spec1,*/const t_pcmspec & p_spec2) const
{
@@ -44,7 +43,7 @@ struct t_pcmspec
return !(*this == p_spec2);
}
inline void reset() { *this = t_pcmspec(); }
inline void reset() {m_sample_rate = 0; m_bits_per_sample = 0; m_channels = 0; m_channel_config = 0; m_float = false;}
inline bool is_valid() const
{
return m_sample_rate >= 1000 && m_sample_rate <= 1000000 &&
@@ -114,72 +113,27 @@ public:
//! Sets playback volume.
//! @p_val Volume level in dB. Value of 0 indicates full ("100%") volume, negative values indciate different attenuation levels.
virtual void volume_set(double p_val) = 0;
//! Helper, see output_v4::is_progressing().
bool is_progressing_();
//! Helper, see output_v4::update_v2()
size_t update_v2_();
//! Helper, see output_v4::get_event_trigger()
pfc::eventHandle_t get_trigger_event_();
//! Helper for output_entry implementation.
static uint32_t g_extra_flags() { return 0; }
};
class NOVTABLE output_v2 : public output {
FB2K_MAKE_SERVICE_INTERFACE(output_v2, output);
public:
//! Obsolete, do not use.
virtual bool want_track_marks() {return false;}
//! Obsolete, do not use.
virtual void on_track_mark() {}
//! Obsolete, do not use.
virtual void enable_fading(bool state) {}
//! Called when flushing due to manual track change rather than seek-within-track
virtual void flush_changing_track() {flush();}
};
class dsp_chain_config;
//! \since 1.4
class NOVTABLE output_v3 : public output_v2 {
FB2K_MAKE_SERVICE_INTERFACE(output_v3, output_v2);
public:
//! Does this output require a specific sample rate? If yes, return the value, otherwise return zero. \n
//! Returning a nonzero will cause a resampler DSP to be injected.
virtual unsigned get_forced_sample_rate() { return 0; }
//! Allows the output to inject specific DSPs at the end of the used chain. \n
//! Default implementation queries get_forced_sample_rate() and injects a resampler.
virtual void get_injected_dsps( dsp_chain_config & );
};
//! \since 1.6
class NOVTABLE output_v4 : public output_v3 {
FB2K_MAKE_SERVICE_INTERFACE(output_v4, output_v3);
public:
//! Returns an event handle that becomes signaled once the output wants an update() call and possibly process_samples(). \n
//! Optional; may return pfc::eventInvalid if not available at this time or not supported. \n
//! If implemented, calling update() should clear the event each time.
virtual pfc::eventHandle_t get_trigger_event() {return pfc::eventInvalid;}
//! Returns whether the audio stream is currently being played or not. \n
//! Typically, for a short period of time, initially send data is not played until a sufficient amount is queued to initiate playback without glitches. \n
//! For old outputs that do not implement this, the value can be assumed to be true.
virtual bool is_progressing() {return true;}
//! Improved version of update(); returns 0 if the output isn't ready to receive any new data, otherwise an advisory number of samples - at the current stream format - that the output expects to take now. \n
//! If the caller changes the stream format, the value is irrelevant. \n
//! The output may return SIZE_MAX to indicate that it can take data but does not currently have any hints to tell how much.
virtual size_t update_v2();
};
//! \since 1.6
class output_v5 : public output_v4 {
FB2K_MAKE_SERVICE_INTERFACE(output_v5, output_v4);
public:
virtual unsigned get_forced_channel_mask() { return 0; }
};
class NOVTABLE output_entry : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(output_entry);
public:
@@ -192,34 +146,20 @@ public:
//! For internal use by backend. Retrieves human-readable name of this output_entry implementation.
virtual const char * get_name() = 0;
//! Obsolete, do not use.
//! Pops up advanced settings dialog. This method is optional and not supported if get_config_flag() return value does not have flag_needs_advanced_config set.
//! @param p_parent Parent window for the dialog.
//! @param p_menupoint Point in screen coordinates - can be used to display a simple popup menu with options to be checked instead of a full dialog.
virtual void advanced_settings_popup(HWND p_parent,POINT p_menupoint) = 0;
enum {
flag_needs_bitdepth_config = 1 << 0,
flag_needs_dither_config = 1 << 1,
//! Obsolete, do not use.
flag_needs_advanced_config = 1 << 2,
flag_needs_device_list_prefixes = 1 << 3,
//! Supports playing multiple simultaneous audio streams thru one device?
flag_supports_multiple_streams = 1 << 4,
//! High latency operation (such as remote network playback), mutually exclusive with flag_low_latency
flag_high_latency = 1 << 5,
//! Low latency operation (local playback), mutually exclusive with flag_high_latency
flag_low_latency = 1 << 6,
//! When set, the output will be used in special compatibility mode: guaranteed regular update() calls, injected padding (silence) at the end of stream.
flag_needs_shims = 1 << 7,
};
virtual t_uint32 get_config_flags() = 0;
uint32_t get_config_flags_compat();
bool is_high_latency();
bool is_low_latency();
pfc::string8 get_device_name( const GUID & deviceID);
bool get_device_name( const GUID & deviceID, pfc::string_base & out );
@@ -245,11 +185,7 @@ public:
if (T::g_advanced_settings_query()) flags |= output_entry::flag_needs_advanced_config;
if (T::g_needs_bitdepth_config()) flags |= output_entry::flag_needs_bitdepth_config;
if (T::g_needs_dither_config()) flags |= output_entry::flag_needs_dither_config;
if (T::g_needs_device_list_prefixes()) flags |= output_entry::flag_needs_device_list_prefixes;
if (T::g_supports_multiple_streams()) flags |= output_entry::flag_supports_multiple_streams;
if (T::g_is_high_latency()) flags |= output_entry::flag_high_latency;
else flags |= output_entry::flag_low_latency;
flags |= T::g_extra_flags();
if (T::g_needs_device_list_prefixes()) flags |= output_entry::flag_needs_device_list_prefixes ;
return flags;
}
};
@@ -259,7 +195,7 @@ public:
template<class T>
class output_factory_t : public service_factory_single_t<output_entry_impl_t<T> > {};
class output_impl : public output_v5 {
class output_impl : public output_v3 {
protected:
output_impl() : m_incoming_ptr(0) {}
virtual void on_update() = 0;
@@ -280,7 +216,6 @@ private:
void flush();
void flush_changing_track();
void update(bool & p_ready);
size_t update_v2();
double get_latency();
void process_samples(const audio_chunk & p_chunk);
@@ -292,8 +227,8 @@ private:
class NOVTABLE volume_callback {
public:
virtual void on_volume_scale(float v) = 0;
virtual void on_volume_arbitrary(int v) = 0;
virtual void on_volume_scale(float v) = 0;
virtual void on_volume_arbitrary(int v) = 0;
};
class NOVTABLE volume_control : public service_base {
@@ -328,31 +263,6 @@ public:
virtual bool hasVisualisation() = 0;
};
//! \since 1.5
class NOVTABLE output_devices_notify {
public:
virtual void output_devices_changed() = 0;
protected:
output_devices_notify() {}
private:
output_devices_notify(const output_devices_notify &) = delete;
void operator=(const output_devices_notify &) = delete;
};
//! \since 1.5
class NOVTABLE output_entry_v3 : public output_entry_v2 {
FB2K_MAKE_SERVICE_INTERFACE(output_entry_v3, output_entry_v2)
public:
//! Main thread only!
virtual void add_notify(output_devices_notify *) = 0;
//! Main thread only!
virtual void remove_notify(output_devices_notify *) = 0;
//! Main thread only!
virtual void set_pinned_device(const GUID & guid) = 0;
};
#pragma pack(push, 1)
//! \since 1.3.5
struct outputCoreConfig_t {

View File

@@ -1,35 +1,16 @@
#include "foobar2000.h"
#include <exception>
void packet_decoder::g_open(service_ptr_t<packet_decoder> & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort)
{
std::exception_ptr rethrow;
bool havePartial = false, tryingPartial = false;
for ( ;; ) {
service_enum_t<packet_decoder_entry> e;
service_ptr_t<packet_decoder_entry> ptr;
while (e.next(ptr)) {
p_abort.check();
if (ptr->is_our_setup(p_owner, p_param1, p_param2, p_param2size)) {
if (!tryingPartial && ptr->is_supported_partially_(p_owner, p_param1, p_param2, p_param2size)) {
havePartial = true;
} else {
try {
ptr->open(p_out, p_decode, p_owner, p_param1, p_param2, p_param2size, p_abort);
return;
} catch (exception_io_data) {
rethrow = std::current_exception();
}
}
}
service_enum_t<packet_decoder_entry> e;
service_ptr_t<packet_decoder_entry> ptr;
while(e.next(ptr)) {
p_abort.check();
if (ptr->is_our_setup(p_owner,p_param1,p_param2,p_param2size)) {
ptr->open(p_out,p_decode,p_owner,p_param1,p_param2,p_param2size,p_abort);
return;
}
if (!havePartial || tryingPartial) break;
tryingPartial = true;
}
if (rethrow) std::rethrow_exception(rethrow);
throw exception_io_data();
}
@@ -53,11 +34,3 @@ void packet_decoder::setAllowDelayed( bool bAllow ) {
this->set_stream_property( property_allow_delayed_output, bAllow ? 1 : 0, NULL, 0);
}
bool packet_decoder_entry::is_supported_partially_(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) {
bool ret = false;
packet_decoder_entry_v2::ptr v2;
if (v2 &= this) {
ret = v2->is_supported_partially(p_owner, p_param1, p_param2, p_param2size);
}
return ret;
}

View File

@@ -13,10 +13,6 @@ protected:
void open(const GUID & p_owner,bool p_decode,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) {throw exception_io_data();}
public:
//! Prototype of function that must be implemented by packet_decoder implementation but is not accessible through packet_decoder interface itself.
//! Returns true if this is not the preferred decoder for this format, another one should be used if found.
static bool g_is_supported_partially(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) { return false; }
//! Forwards additional information about stream being decoded. \n
//! Calling: this must be called immediately after packet_decoder object is created, before any other methods are called.\n
@@ -38,7 +34,6 @@ public:
//! Decodes a block of audio data.\n
//! It may return empty chunk even when successful (caused by encoder+decoder delay for an example), caller must check for it and handle it appropriately.
//! Called with 0 bytes at the end of stream - if the decoder introduces a delay between input/output, any buffered data should be passed back then.
virtual void decode(const void * p_buffer,t_size p_bytes,audio_chunk & p_chunk,abort_callback & p_abort)=0;
//! Returns whether this packet decoder supports analyze_first_frame() function.
@@ -49,7 +44,7 @@ public:
//! Static helper, creates a packet_decoder instance and initializes it with specific decoder setup data.
static void g_open(service_ptr_t<packet_decoder> & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort);
static const GUID owner_MP4,owner_matroska,owner_MP3,owner_MP2,owner_MP1,owner_MP4_ALAC,owner_ADTS,owner_ADIF, owner_Ogg, owner_MP4_AMR, owner_MP4_AMR_WB, owner_MP4_AC3, owner_MP4_EAC3;
static const GUID owner_MP4,owner_matroska,owner_MP3,owner_MP2,owner_MP1,owner_MP4_ALAC,owner_ADTS,owner_ADIF, owner_Ogg, owner_MP4_AMR, owner_MP4_AMR_WB, owner_MP4_AC3;
struct matroska_setup
{
@@ -87,21 +82,12 @@ public:
//property_mp4_esds : p_param2 = MP4 ESDS chunk content as needed by some decoders
static const GUID property_mp4_esds;
// DEPRECATED
//property_allow_delayed_output : p_param1 = bool flag indicating whether the decoder than delay outputting audio data at will; essential for Apple AQ decoder
static const GUID property_allow_delayed_output;
// property_mp3_delayless : return non-zero if this codec drops MP3 delay by itself
static const GUID property_mp3_delayless;
// property_query_delay_samples :
// Return non-zero if this codec has a decoder delay that the caller should deal with.
// Param1 signals sample rate used by input - should always match decoder's sample rate - return zero if it does not match.
static const GUID property_query_delay_samples;
// property_query_mp4_use_elst :
// Return non-zero if MP4 elst should be used with this codec.
static const GUID property_query_mp4_use_elst;
size_t initPadding();
void setEventLogger(event_logger::ptr logger);
void setCheckingIntegrity(bool checkingIntegrity);
@@ -119,40 +105,29 @@ public:
FB2K_MAKE_SERVICE_INTERFACE(packet_decoder_streamparse,packet_decoder);
};
class NOVTABLE packet_decoder_entry : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(packet_decoder_entry);
class NOVTABLE packet_decoder_entry : public service_base
{
public:
virtual bool is_our_setup(const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) = 0;
virtual void open(service_ptr_t<packet_decoder> & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) = 0;
//! Returns true if this is not the preferred decoder for this format, another one should be used if found.
bool is_supported_partially_(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size);
};
class NOVTABLE packet_decoder_entry_v2 : public packet_decoder_entry {
FB2K_MAKE_SERVICE_INTERFACE(packet_decoder_entry_v2, packet_decoder_entry);
public:
//! Returns true if this is not the preferred decoder for this format, another one should be used if found.
virtual bool is_supported_partially(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) = 0;
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(packet_decoder_entry);
};
template<class T>
class packet_decoder_entry_impl_t : public packet_decoder_entry_v2
class packet_decoder_entry_impl_t : public packet_decoder_entry
{
public:
bool is_our_setup(const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) override {
bool is_our_setup(const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) {
return T::g_is_our_setup(p_owner,p_param1,p_param2,p_param2size);
}
void open(service_ptr_t<packet_decoder> & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) override {
void open(service_ptr_t<packet_decoder> & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) {
PFC_ASSERT(is_our_setup(p_owner,p_param1,p_param2,p_param2size));
service_ptr_t<T> instance = new service_impl_t<T>();
instance->open(p_owner,p_decode,p_param1,p_param2,p_param2size,p_abort);
p_out = instance.get_ptr();
}
bool is_supported_partially(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) override {
return T::g_is_supported_partially(p_owner, p_param1, p_param2, p_param2size);
}
};
template<typename T>

View File

@@ -5,26 +5,26 @@ Use play_callback_manager to register your dynamically created instances. Static
class NOVTABLE play_callback {
public:
//! Playback process is being initialized. on_playback_new_track() should be called soon after this when first file is successfully opened for decoding.
virtual void on_playback_starting(play_control::t_track_command p_command,bool p_paused) = 0;
virtual void FB2KAPI on_playback_starting(play_control::t_track_command p_command,bool p_paused) = 0;
//! Playback advanced to new track.
virtual void on_playback_new_track(metadb_handle_ptr p_track) = 0;
virtual void FB2KAPI on_playback_new_track(metadb_handle_ptr p_track) = 0;
//! Playback stopped.
virtual void on_playback_stop(play_control::t_stop_reason p_reason) = 0;
virtual void FB2KAPI on_playback_stop(play_control::t_stop_reason p_reason) = 0;
//! User has seeked to specific time.
virtual void on_playback_seek(double p_time) = 0;
virtual void FB2KAPI on_playback_seek(double p_time) = 0;
//! Called on pause/unpause.
virtual void on_playback_pause(bool p_state) = 0;
virtual void FB2KAPI on_playback_pause(bool p_state) = 0;
//! Called when currently played file gets edited.
virtual void on_playback_edited(metadb_handle_ptr p_track) = 0;
virtual void FB2KAPI on_playback_edited(metadb_handle_ptr p_track) = 0;
//! Dynamic info (VBR bitrate etc) change.
virtual void on_playback_dynamic_info(const file_info & p_info) = 0;
virtual void FB2KAPI on_playback_dynamic_info(const file_info & p_info) = 0;
//! Per-track dynamic info (stream track titles etc) change. Happens less often than on_playback_dynamic_info().
virtual void on_playback_dynamic_info_track(const file_info & p_info) = 0;
virtual void FB2KAPI on_playback_dynamic_info_track(const file_info & p_info) = 0;
//! Called every second, for time display
virtual void on_playback_time(double p_time) = 0;
virtual void FB2KAPI on_playback_time(double p_time) = 0;
//! User changed volume settings. Possibly called when not playing.
//! @param p_new_val new volume level in dB; 0 for full volume.
virtual void on_volume_change(float p_new_val) = 0;
virtual void FB2KAPI on_volume_change(float p_new_val) = 0;
enum {
flag_on_playback_starting = 1 << 0,
@@ -51,23 +51,25 @@ protected:
//! Standard API (always present); manages registrations of dynamic play_callbacks. \n
//! Usage: use play_callback_manager::get() to obtain on instance. \n
//! Do not reimplement.
class NOVTABLE play_callback_manager : public service_base {
FB2K_MAKE_SERVICE_COREAPI(play_callback_manager);
class NOVTABLE play_callback_manager : public service_base
{
public:
//! Registers a play_callback object.
//! @param p_callback Interface to register.
//! @param p_flags Indicates which notifications are requested.
//! @param p_forward_status_on_register Set to true to have the callback immediately receive current playback status as notifications if playback is active (eg. to receive info about playback process that started before our callback was registered).
virtual void register_callback(play_callback * p_callback,unsigned p_flags,bool p_forward_status_on_register) = 0;
virtual void FB2KAPI register_callback(play_callback * p_callback,unsigned p_flags,bool p_forward_status_on_register) = 0;
//! Unregisters a play_callback object.
//! @p_callback Previously registered interface to unregister.
virtual void unregister_callback(play_callback * p_callback) = 0;
virtual void FB2KAPI unregister_callback(play_callback * p_callback) = 0;
FB2K_MAKE_SERVICE_COREAPI(play_callback_manager);
};
//! Implementation helper.
class play_callback_impl_base : public play_callback {
public:
play_callback_impl_base(unsigned p_flags = UINT_MAX) {
play_callback_impl_base(unsigned p_flags = ~0) {
play_callback_manager::get()->register_callback(this,p_flags,false);
}
~play_callback_impl_base() {
@@ -94,10 +96,11 @@ public:
//! Static (autoregistered) version of play_callback. Use play_callback_static_factory_t to register.
class play_callback_static : public service_base, public play_callback {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(play_callback_static);
public:
//! Controls which methods your callback wants called; returned value should not change in run time, you should expect it to be queried only once (on startup). See play_callback::flag_* constants.
virtual unsigned get_flags() = 0;
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(play_callback_static);
};
template<typename T>
@@ -107,9 +110,10 @@ class play_callback_static_factory_t : public service_factory_single_t<T> {};
//! Gets notified about tracks being played. Notification occurs when at least 60s of the track has been played, or the track has reached its end after at least 1/3 of it has been played through.
//! Use playback_statistics_collector_factory_t to register.
class NOVTABLE playback_statistics_collector : public service_base {
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(playback_statistics_collector);
public:
virtual void on_item_played(metadb_handle_ptr p_item) = 0;
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(playback_statistics_collector);
};
template<typename T>

View File

@@ -36,9 +36,6 @@ public:
bool is_valid() const;
enum {case_sensitive = true};
typedef pfc::comparator_strcmp path_comparator;
class comparator {
public:
static int compare(const playable_location & v1, const playable_location & v2) {return g_compare(v1,v2);}

View File

@@ -1,7 +1,4 @@
#pragma once
//! \since 1.0
//! Implemented by components - register with playback_stream_capture methods.
class NOVTABLE playback_stream_capture_callback {
public:
//! Delivers a real-time chunk of audio data. \n
@@ -14,12 +11,13 @@ protected:
};
//! \since 1.0
//! Implemented by core.
class NOVTABLE playback_stream_capture : public service_base {
FB2K_MAKE_SERVICE_COREAPI(playback_stream_capture)
public:
//! Possible to call only from the main thread.
virtual void add_callback(playback_stream_capture_callback * ) = 0;
//! Possible to call only from the main thread.
virtual void remove_callback(playback_stream_capture_callback * ) = 0;
FB2K_MAKE_SERVICE_COREAPI(playback_stream_capture)
};

View File

@@ -90,14 +90,12 @@ void playlist_manager::playlist_get_all_items(t_size p_playlist,pfc::list_base_t
void playlist_manager::playlist_get_selected_items(t_size p_playlist,pfc::list_base_t<metadb_handle_ptr> & out)
{
enum_items_callback_retrieve_selected_items cb(out);
playlist_enum_items(p_playlist,cb,pfc::bit_array_true());
playlist_enum_items(p_playlist,enum_items_callback_retrieve_selected_items(out),pfc::bit_array_true());
}
void playlist_manager::playlist_get_selection_mask(t_size p_playlist,bit_array_var & out)
{
enum_items_callback_retrieve_selection_mask cb(out);
playlist_enum_items(p_playlist,cb,pfc::bit_array_true());
playlist_enum_items(p_playlist,enum_items_callback_retrieve_selection_mask(out),pfc::bit_array_true());
}
bool playlist_manager::playlist_is_item_selected(t_size p_playlist,t_size p_item)
@@ -134,9 +132,8 @@ bool playlist_manager::playlist_move_selection(t_size p_playlist,int p_delta) {
pfc::array_t<t_size> order; order.set_size(count);
pfc::array_t<bool> selection; selection.set_size(count);
pfc::bit_array_var_table mask(selection.get_ptr(),selection.get_size());
playlist_get_selection_mask(p_playlist, mask);
g_make_selection_move_permutation(order.get_ptr(),count,mask,p_delta);
playlist_get_selection_mask(p_playlist, pfc::bit_array_var_table(selection.get_ptr(),selection.get_size()));
g_make_selection_move_permutation(order.get_ptr(),count, pfc::bit_array_table(selection.get_ptr(),selection.get_size()),p_delta);
return playlist_reorder_items(p_playlist,order.get_ptr(),count);
}
@@ -552,8 +549,7 @@ bool playlist_manager::highlight_playing_item()
void playlist_manager::playlist_get_items(t_size p_playlist,pfc::list_base_t<metadb_handle_ptr> & out,const bit_array & p_mask)
{
enum_items_callback_retrieve_all_items cb(out);
playlist_enum_items(p_playlist,cb,p_mask);
playlist_enum_items(p_playlist,enum_items_callback_retrieve_all_items(out),p_mask);
}
void playlist_manager::activeplaylist_get_items(pfc::list_base_t<metadb_handle_ptr> & out,const bit_array & p_mask)

View File

@@ -441,8 +441,7 @@ public:
//! \param p_data array that contains the data that will be associated with the property
template<typename t_array> void playlist_set_property(t_size p_playlist,const GUID & p_property,const t_array & p_data) {
PFC_STATIC_ASSERT( sizeof(p_data[0]) == 1 );
stream_reader_memblock_ref reader(p_data);
playlist_set_property(p_playlist,p_property,&reader,p_data.get_size(),fb2k::noAbort);
playlist_set_property(p_playlist,p_property,&stream_reader_memblock_ref(p_data),p_data.get_size(),abort_callback_dummy());
}
//! Read a persistent playlist property.
//! \param p_playlist Index of the playlist
@@ -453,10 +452,7 @@ public:
PFC_STATIC_ASSERT( sizeof(p_data[0]) == 1 );
typedef pfc::array_t<t_uint8,pfc::alloc_fast_aggressive> t_temp;
t_temp temp;
{
stream_writer_buffer_append_ref_t<t_temp> reader(temp);
if (!playlist_get_property(p_playlist,p_property,&reader,fb2k::noAbort)) return false;
}
if (!playlist_get_property(p_playlist,p_property,&stream_writer_buffer_append_ref_t<t_temp>(temp),abort_callback_dummy())) return false;
p_data = temp;
return true;
}

View File

@@ -155,7 +155,7 @@ static void track_indexer__g_get_tracks_wrap(const char * p_path,const service_p
fail = true;
} catch(std::exception const & e) {
fail = true;
FB2K_console_formatter() << "could not enumerate tracks (" << e << ") on:\n" << file_path_display(p_path);
console::formatter() << "could not enumerate tracks (" << e << ") on:\n" << file_path_display(p_path);
}
if (fail) {
if (!got_input && !p_abort.is_aborting()) {
@@ -276,7 +276,7 @@ static void process_path_internal(const char * p_path,const service_ptr_t<file>
while(e.next(f)) {
abort.check();
service_ptr_t<archive> arch;
if (f->service_query_t(arch) && arch->is_our_archive(p_path)) {
if (f->service_query_t(arch)) {
if (p_reader.is_valid()) p_reader->reopen(abort);
try {

View File

@@ -22,16 +22,6 @@ void popup_message::g_complain(const char * p_whatFailed, const char * msg) {
g_complain( PFC_string_formatter() << p_whatFailed << ": " << msg );
}
#if FOOBAR2000_TARGET_VERSION >= 80
void popup_message_v3::show_query( const char * title, const char * msg, unsigned buttons, completion_notify::ptr reply) {
query_t q;
q.title = title; q.msg = msg; q.buttons = buttons; q.reply = reply;
this->show_query( q );
}
#endif
#ifdef FOOBAR2000_DESKTOP_WINDOWS
void popup_message_v2::g_show(HWND parent, const char * msg, const char * title) {
service_enum_t< popup_message_v2 > e;
service_ptr_t< popup_message_v2 > m;
@@ -47,91 +37,3 @@ void popup_message_v2::g_complain(HWND parent, const char * whatFailed, const ch
void popup_message_v2::g_complain(HWND parent, const char * whatFailed, const std::exception & e) {
g_complain(parent, whatFailed, e.what());
}
#endif // FOOBAR2000_DESKTOP_WINDOWS
#ifdef FOOBAR2000_MODERN
void fb2k::showToast( const char * msg ) {
fb2k::popup_toast::arg_t arg;
fb2k::popup_toast::get()->show_toast(msg, arg);
}
void fb2k::showToastLongDuration( const char * msg ) {
fb2k::popup_toast::arg_t arg;
arg.longDuration = true;
fb2k::popup_toast::get()->show_toast(msg, arg);
}
void popup_message::g_showToast(const char * msg) {
fb2k::showToast( msg );
}
void popup_message::g_showToastLongDuration(const char * msg) {
fb2k::showToastLongDuration( msg );
}
#endif // FOOBAR2000_MODERN
#if defined(FOOBAR2000_DESKTOP_WINDOWS) && FOOBAR2000_TARGET_VERSION >= 80
int popup_message_v3::messageBox(HWND parent, const char* msg, const char* title, UINT flags) {
query_t q = {};
q.title = title;
q.msg = msg;
q.wndParent = parent;
switch (flags & 0xF) {
default:
case MB_OK:
q.buttons = buttonOK;
q.defButton = buttonOK;
break;
case MB_OKCANCEL:
q.buttons = buttonOK | buttonCancel;
q.defButton = (flags & MB_DEFBUTTON2) ? buttonCancel : buttonOK;
break;
case MB_ABORTRETRYIGNORE:
q.buttons = buttonAbort | buttonRetry | buttonIgnore;
if (flags & MB_DEFBUTTON3) q.defButton = buttonIgnore;
else if (flags & MB_DEFBUTTON2) q.defButton = buttonRetry;
else q.defButton = buttonAbort;
break;
case MB_YESNOCANCEL:
q.buttons = buttonYes | buttonNo | buttonCancel;
if (flags & MB_DEFBUTTON3) q.defButton = buttonCancel;
else if (flags & MB_DEFBUTTON2) q.defButton = buttonNo;
else q.defButton = buttonYes;
break;
case MB_YESNO:
q.buttons = buttonYes | buttonNo;
q.defButton = (flags & MB_DEFBUTTON2) ? buttonNo : buttonYes;
break;
case MB_RETRYCANCEL:
q.buttons = buttonRetry | buttonCancel;
q.defButton = (flags & MB_DEFBUTTON2) ? buttonCancel : buttonRetry;
break;
}
switch (flags & 0xF0) {
case MB_ICONHAND:
q.icon = iconWarning;
break;
case MB_ICONQUESTION:
q.icon = iconQuestion;
break;
case MB_ICONEXCLAMATION:
q.icon = iconError;
break;
case MB_ICONASTERISK:
q.icon = iconInformation;
break;
}
uint32_t status = this->show_query_modal(q);
if (status & buttonOK) return IDOK;
if (status & buttonCancel) return IDCANCEL;
if (status & buttonYes) return IDYES;
if (status & buttonNo) return IDNO;
if (status & buttonRetry) return IDRETRY;
if (status & buttonAbort) return IDABORT;
if (status & buttonIgnore) return IDIGNORE;
return -1;
}
#endif

View File

@@ -1,8 +1,3 @@
#pragma once
#include <climits> // UINT_MAX
#include "completion_notify.h"
//! This interface allows you to show generic nonmodal noninteractive dialog with a text message. This should be used instead of MessageBox where possible.\n
//! Usage: use popup_message::g_show / popup_message::g_show_ex static helpers, or popup_message::get() to obtain an instance.\n
@@ -23,12 +18,12 @@ public:
//! @param p_msg Message to show (UTF-8 encoded string).
//! @param p_title Title of dialog to show (UTF-8 encoded string).
//! @param p_icon Icon of the dialog - can be set to icon_information, icon_error or icon_query.
inline void show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {show_ex(p_msg,UINT_MAX,p_title,UINT_MAX,p_icon);}
inline void show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {show_ex(p_msg,~0,p_title,~0,p_icon);}
//! Static helper function instantiating the service and activating the message dialog. See show_ex() for description of parameters.
static void g_show_ex(const char * p_msg,unsigned p_msg_length,const char * p_title,unsigned p_title_length,t_icon p_icon = icon_information);
//! Static helper function instantiating the service and activating the message dialog. See show() for description of parameters.
static inline void g_show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {g_show_ex(p_msg,UINT_MAX,p_title,UINT_MAX,p_icon);}
static inline void g_show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {g_show_ex(p_msg,~0,p_title,~0,p_icon);}
//! Shows generic box with a failure message
static void g_complain(const char * what);
@@ -37,20 +32,14 @@ public:
//! <whatfailed>: <msg>
static void g_complain(const char * p_whatFailed, const char * msg);
#ifdef FOOBAR2000_MODERN
static void g_showToast(const char * msg);
static void g_showToastLongDuration(const char * msg);
#endif
FB2K_MAKE_SERVICE_COREAPI(popup_message);
FB2K_MAKE_SERVICE_COREAPI(popup_message);
};
#define EXCEPTION_TO_POPUP_MESSAGE(CODE,LABEL) try { CODE; } catch(std::exception const & e) {popup_message::g_complain(LABEL,e);}
#ifdef FOOBAR2000_DESKTOP_WINDOWS
//! \since 1.1
class NOVTABLE popup_message_v2 : public service_base {
FB2K_MAKE_SERVICE_COREAPI(popup_message_v2);
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(popup_message_v2);
public:
virtual void show(HWND parent, const char * msg, t_size msg_length, const char * title, t_size title_length) = 0;
void show(HWND parent, const char * msg, const char * title) {show(parent, msg, ~0, title, ~0);}
@@ -59,83 +48,3 @@ public:
static void g_complain(HWND parent, const char * whatFailed, const char * msg);
static void g_complain(HWND parent, const char * whatFailed, const std::exception & e);
};
#endif
#ifdef FOOBAR2000_MODERN
namespace fb2k {
class popup_toast : public service_base {
FB2K_MAKE_SERVICE_COREAPI( popup_toast );
public:
struct arg_t {
bool longDuration = false;
};
virtual void show_toast(const char * msg, arg_t const & arg) = 0;
};
void showToast( const char * msg );
void showToastLongDuration( const char * msg );
class toastFormatter : public pfc::string_formatter {
public:
~toastFormatter() {
if ( this->length() > 0 ) showToast( c_str() );
}
};
}
#define FB2K_Toast() ::fb2k::toastFormatter()._formatter()
#endif
#if FOOBAR2000_TARGET_VERSION >= 80
//! \since 1.5
class NOVTABLE popup_message_v3 : public service_base {
FB2K_MAKE_SERVICE_COREAPI(popup_message_v3);
public:
//! show_query button codes. \n
//! Combine one or more of these to create a button mask to pass to show_query().
enum {
buttonOK = 1 << 0,
buttonCancel = 1 << 1,
buttonYes = 1 << 2,
buttonNo = 1 << 3,
buttonRetry = 1 << 4,
buttonAbort = 1 << 5,
buttonIgnore = 1 << 6,
flagDoNotAskAgain = 1 << 16,
iconNone = 0,
iconInformation,
iconQuestion,
iconWarning,
iconError,
};
struct query_t {
const char * title = nullptr;
const char * msg = nullptr;
uint32_t buttons = 0;
uint32_t defButton = 0;
uint32_t icon = iconNone;
completion_notify::ptr reply;
#ifdef _WIN32
HWND wndParent = NULL;
#endif
const char * msgDoNotAskAgain = nullptr;
};
//! Shows an interactive query presenting the user with multiple actions to choose from.
virtual void show_query(query_t const &) = 0;
//! Modal version of show_query. Reply part of the argument can be empty; the status code will be returned.
virtual uint32_t show_query_modal(query_t const &) = 0;
#ifdef FOOBAR2000_DESKTOP_WINDOWS
// Minimalist MessageBox() reimplementation wrapper
int messageBox(HWND, const char*, const char*, UINT);
#endif
//! Old method wrapper
void show_query( const char * title, const char * msg, unsigned buttons, completion_notify::ptr reply);
};
#endif // FOOBAR2000_TARGET_VERSION >= 80

View File

@@ -1,5 +1,3 @@
#pragma once
//! Implementing this service will generate a page in preferences dialog. Use preferences_page_factory_t template to register. \n
//! In 1.0 and newer you should always derive from preferences_page_v3 rather than from preferences_page directly.
class NOVTABLE preferences_page : public service_base {
@@ -21,9 +19,7 @@ public:
static void get_help_url_helper(pfc::string_base & out, const char * category, const GUID & id, const char * name);
static const GUID guid_root, guid_hidden, guid_tools,guid_core,guid_display,guid_playback,guid_visualisations,guid_input,guid_tag_writing,guid_media_library, guid_tagging, guid_output, guid_advanced, guid_components;
//! \since 1.5
static const GUID guid_input_info_filter;
static const GUID guid_root, guid_hidden, guid_tools,guid_core,guid_display,guid_playback,guid_visualisations,guid_input,guid_tag_writing,guid_media_library, guid_tagging;
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(preferences_page);
};
@@ -137,14 +133,7 @@ class preferences_page_v3 : public preferences_page_v2 {
public:
virtual preferences_page_instance::ptr instantiate(HWND parent, preferences_page_callback::ptr callback) = 0;
private:
HWND create(HWND) {throw pfc::exception_not_implemented();} //stub
HWND create(HWND p_parent) {throw pfc::exception_not_implemented();} //stub
bool reset_query() {return false;} //stub - the new apply-friendly reset should be used instead.
void reset() {} //stub
};
//! \since 1.5
class NOVTABLE preferences_page_v4 : public preferences_page_v3 {
FB2K_MAKE_SERVICE_INTERFACE(preferences_page_v4, preferences_page_v3);
public:
virtual bool is_hidden() = 0;
};

View File

@@ -7,8 +7,6 @@ public:
virtual void set_progress(float value) = 0;
//! Toggles paused state.
virtual void set_pause(bool isPaused) = 0;
static bool serviceRequiresMainThreadDestructor() { return true; }
};
//! Entrypoint interface for instantiating progress_meter_instance objects.

View File

@@ -115,21 +115,22 @@ float replaygain_info::anyGain(bool bPreferAlbum) const {
}
}
float replaygain_info::g_parse_gain_text(const char * p_text, t_size p_text_len) {
void replaygain_info::set_album_gain_text(const char * p_text,t_size p_text_len)
{
RG_FPU();
if (p_text != 0 && p_text_len > 0 && *p_text != 0)
return (float)pfc::string_to_float(p_text, p_text_len);
m_album_gain = (float)pfc::string_to_float(p_text,p_text_len);
else
return gain_invalid;
}
void replaygain_info::set_album_gain_text(const char * p_text,t_size p_text_len) {
m_album_gain = g_parse_gain_text(p_text, p_text_len);
remove_album_gain();
}
void replaygain_info::set_track_gain_text(const char * p_text,t_size p_text_len)
{
m_track_gain = g_parse_gain_text(p_text, p_text_len);
RG_FPU();
if (p_text != 0 && p_text_len > 0 && *p_text != 0)
m_track_gain = (float)pfc::string_to_float(p_text,p_text_len);
else
remove_track_gain();
}
void replaygain_info::set_album_peak_text(const char * p_text,t_size p_text_len)

View File

@@ -73,14 +73,6 @@ public:
virtual replaygain_scanner::ptr instantiate(uint32_t flags) = 0;
};
//! Internal service introduced in 1.5. No guarantees about compatibility. May be changed or removed at any time.
class replaygain_scanner_config : public service_base {
FB2K_MAKE_SERVICE_COREAPI(replaygain_scanner_config);
public:
virtual void get_album_pattern( pfc::string_base & out ) = 0;
virtual uint64_t get_read_size_bytes() = 0;
};
#ifdef FOOBAR2000_DESKTOP
//! \since 1.4
//! A class for applying gain to compressed audio packets such as MP3 or AAC. \n

View File

@@ -2,11 +2,6 @@
#ifdef FOOBAR2000_HAVE_DSP
//! A resampler DSP entry. \n
//! It is STRICTLY REQUIRED that the output is: \n
//! (A) In the requested sample rate (specified when creating the preset), \n
//! (B) .. or untouched if the conversion cannot be performed / there's no conversion to be performed (input rate == output rate). \n
//! Not every resampler supports every possible sample rate conversion ratio. Bundled PPHS resampler (always installed since foobar2000 v1.6) does accept every possible conversion.
class NOVTABLE resampler_entry : public dsp_entry
{
public:
@@ -40,36 +35,9 @@ class resampler_factory_t : public service_factory_single_t<resampler_entry_impl
class resampler_manager : public service_base {
FB2K_MAKE_SERVICE_COREAPI(resampler_manager);
public:
//! Locate the preferred resampler that is capable of performing conversion from the source to destination rate. \n
//! If input sample rate is not known in advance or may change in mid-conversion, it's recommended to use make_chain() instead to full obey user settings.
virtual resampler_entry::ptr get_resampler( unsigned rateFrom, unsigned rateTo ) = 0;
//! Compatibility wrapper, see resampler_manager_v2::make_chain().
void make_chain_(dsp_chain_config& outChain, unsigned rateFrom, unsigned rateTo, float qualityScale);
};
class dsp_chain_config;
//! \since 1.6
class resampler_manager_v2 : public resampler_manager {
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(resampler_manager_v2, resampler_manager);
public:
//! Make a chain of resamplers. \n
//! Pass the intended sample rates for rateFrom & rateTo. Pass 0 rateFrom if it is not known in advance or may change in mid-conversion.
//! With rateFrom known in advance, the chain should hold only one DSP. \n
//! If rateFrom is not known in advance, multiple DSPs may be returned - a preferred one that accepts common conversion ratios but not all of them, and a fallback one that handles every scenario if the first one failed. \n
//! For an example, by default, SSRC (higher quality) is used, but PPHS (more compatible) is added to clean up odd sample rates that SSRC failed to process. \n
//! Note that it is required that resamplers pass untouched data if no resampling is performed, so additional DSPs have no effect on the audio coming thru, as just one resampler will actually do anything.
virtual void make_chain( dsp_chain_config & outChain, unsigned rateFrom, unsigned rateTo, float qualityScale) = 0;
};
//! \since 1.6.1
class resampler_manager_v3 : public resampler_manager_v2 {
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(resampler_manager_v3, resampler_manager_v2);
public:
//! Extended make_chain that also manipulates channel layout.
virtual void make_chain_v3(dsp_chain_config& outChain, unsigned rateFromm, unsigned rateTo, float qualityScale, unsigned chmask) = 0;
};
#endif
#endif // FOOBAR2000_HAVE_DSP

View File

@@ -24,12 +24,23 @@ t_size service_factory_base::enum_get_count(service_class_ref p_class)
service_factory_base * service_factory_base::__internal__list = NULL;
namespace {
class main_thread_callback_release_object : public main_thread_callback {
public:
main_thread_callback_release_object(service_ptr obj) : m_object(obj) {}
void callback_run() {
try { m_object.release(); } catch(...) {}
}
private:
service_ptr m_object;
};
}
namespace service_impl_helper {
void release_object_delayed(service_base * ptr) {
ptr->service_add_ref();
fb2k::inMainThread( [ptr] {
try { ptr->service_release(); } catch(...) {}
} );
void release_object_delayed(service_ptr obj) {
main_thread_callback_manager::get()->add_callback(new service_impl_t<main_thread_callback_release_object>(obj));
}
};
@@ -38,11 +49,6 @@ void _standard_api_create_internal(service_ptr & out, const GUID & classID) {
service_class_ref c = service_factory_base::enum_find_class(classID);
switch(service_factory_base::enum_get_count(c)) {
case 0:
#if PFC_DEBUG
if ( core_api::are_services_available() ) {
FB2K_DebugLog() << "Service not found of type: " << pfc::print_guid(classID);
}
#endif
throw exception_service_not_found();
case 1:
PFC_ASSERT_SUCCESS( service_factory_base::enum_create(out, c, 0) );

View File

@@ -18,6 +18,16 @@ PFC_DECLARE_EXCEPTION(exception_service_duplicated,pfc::exception,"Service dupli
#define DECLARE_GUID(NAME,A,S,D,F,G,H,J,K,L,Z,X) FOOGUIDDECL const GUID NAME = {A,S,D,{F,G,H,J,K,L,Z,X}};
#define DECLARE_CLASS_GUID(NAME,A,S,D,F,G,H,J,K,L,Z,X) FOOGUIDDECL const GUID NAME::class_guid = {A,S,D,{F,G,H,J,K,L,Z,X}};
//! Special hack to ensure errors when someone tries to ->service_add_ref()/->service_release() on a service_ptr_t
template<typename T> class service_obscure_refcounting : public T {
private:
int service_add_ref() throw();
int service_release() throw();
};
//! Converts a service interface pointer to a pointer that obscures service counter functionality.
template<typename T> static inline service_obscure_refcounting<T>* service_obscure_refcounting_cast(T * p_source) throw() {return static_cast<service_obscure_refcounting<T>*>(p_source);}
//Must be templated instead of taking service_base* because of multiple inheritance issues.
template<typename T> static void service_release_safe(T * p_ptr) throw() {
if (p_ptr != NULL) PFC_ASSERT_NO_EXCEPTION( p_ptr->service_release() );
@@ -34,7 +44,6 @@ template<typename T>
class service_ptr_base_t {
public:
inline T* get_ptr() const throw() {return m_ptr;}
typedef T obj_t;
protected:
T * m_ptr;
};
@@ -42,10 +51,6 @@ protected:
// forward declaration
template<typename T> class service_nnptr_t;
template<typename T> struct forced_cast_t {
T* ptr;
};
//! Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes.
template<typename T>
class service_ptr_t : public service_ptr_base_t<T> {
@@ -101,7 +106,6 @@ public:
return *this;
}
inline void reset() throw() { release(); }
inline void release() throw() {
service_release_safe(this->m_ptr);
@@ -109,15 +113,7 @@ public:
}
inline T* operator->() const throw() {
#if PFC_DEBUG
if (this->m_ptr == NULL) {
FB2K_DebugLog() << "service_ptr operator-> on a null pointer, type: " << T::debugServiceName();
uBugCheck();
}
#endif
return this->m_ptr;
}
inline service_obscure_refcounting<T>* operator->() const throw() {PFC_ASSERT(this->m_ptr != NULL);return service_obscure_refcounting_cast(this->m_ptr);}
inline T* get_ptr() const throw() {return this->m_ptr;}
@@ -170,8 +166,8 @@ public:
//! Forced cast operator - obtains a valid service pointer to the expected class or crashes the app if such pointer cannot be obtained.
template<typename otherPtr_t>
void operator ^= ( otherPtr_t other ) {
if (other.is_empty()) release();
else forcedCastFrom(other);
if (other.is_empty()) release(); // allow null ptr, get upset only on type mismatch
else if (!other->cast(*this)) uBugCheck();
}
template<typename otherObj_t>
void operator ^= ( otherObj_t * other ) {
@@ -179,15 +175,10 @@ public:
else forcedCastFrom( other );
}
bool testForInterface(const GUID & guid) const {
if (this->m_ptr == nullptr) return false;
service_ptr_t<service_base> dummy;
return this->m_ptr->service_query(dummy, guid);
}
//! Conditional cast operator - attempts to obtain a vaild service pointer to the expected class; returns true on success, false on failure.
template<typename otherPtr_t>
bool operator &= ( otherPtr_t other ) {
if (other.is_empty()) return false;
PFC_ASSERT( other.is_valid() );
return other->cast(*this);
}
template<typename otherObj_t>
@@ -196,28 +187,6 @@ public:
return other->cast( *this );
}
template<typename otherPtr_t>
void operator=(forced_cast_t<otherPtr_t> other) {
if (other.ptr == NULL) release();
else forcedCastFrom(other.ptr);
}
//! Alternate forcedCast syntax, for contexts where operator^= fails to compile. \n
//! Usage: target = source.forcedCast();
forced_cast_t<T> forcedCast() const {
forced_cast_t<T> r = { this->m_ptr };
return r;
}
template<typename source_t>
void forcedCastFrom(source_t const & other) {
if (!other->cast(*this)) {
#if PFC_DEBUG
FB2K_DebugLog() << "Forced cast failure: " << pfc::print_guid(T::class_guid);
#endif
uBugCheck();
}
}
};
//! Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes. \n
@@ -262,7 +231,7 @@ public:
template<typename t_source> inline t_self & operator=(service_ptr_t<t_source> && p_source) throw() {this->m_ptr->service_release(); this->m_ptr = p_source.detach();}
inline T* operator->() const throw() {PFC_ASSERT(this->m_ptr != NULL);return this->m_ptr;}
inline service_obscure_refcounting<T>* operator->() const throw() {PFC_ASSERT(this->m_ptr != NULL);return service_obscure_refcounting_cast(this->m_ptr);}
inline T* get_ptr() const throw() {return this->m_ptr;}
@@ -295,11 +264,6 @@ public:
static bool _as_base_ptr_check() {
return static_cast<service_base*>((T*)NULL) == reinterpret_cast<service_base*>((T*)NULL);
}
forced_cast_t<T> forcedCast() const {
forced_cast_t<T> r = { this->m_ptr };
return r;
}
};
namespace pfc {
@@ -313,6 +277,11 @@ namespace pfc {
}
template<typename T, template<typename> class t_alloc = pfc::alloc_fast>
class service_list_t : public pfc::list_t<service_ptr_t<T>, t_alloc >
{
};
//! For internal use, see FB2K_MAKE_SERVICE_INTERFACE
#define FB2K_MAKE_SERVICE_INTERFACE_EX(THISCLASS,PARENTCLASS,IS_CORE_API) \
public: \
@@ -325,7 +294,6 @@ namespace pfc {
typedef service_nnptr_t<t_interface> nnptr; \
typedef ptr ref; \
typedef nnptr nnref; \
static const char * debugServiceName() { return #THISCLASS; } \
enum { _is_core_api = IS_CORE_API }; \
protected: \
THISCLASS() {} \
@@ -345,7 +313,6 @@ namespace pfc {
#define FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT_EX(THISCLASS, IS_CORE_API) \
public: \
typedef THISCLASS t_interface_entrypoint; \
static service_enum_t<THISCLASS> enumerate() { return service_enum_t<THISCLASS>(); } \
FB2K_MAKE_SERVICE_INTERFACE_EX(THISCLASS,service_base, IS_CORE_API)
//! Helper macro for use when defining a service class. Generates standard features of a service, without ability to register using service_factory / enumerate using service_enum_t. \n
@@ -364,17 +331,11 @@ namespace pfc {
#define FB2K_MAKE_SERVICE_COREAPI(THISCLASS) \
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT_EX( THISCLASS, true ) \
public: \
static ptr get() { return fb2k::std_api_get<THISCLASS>(); } \
static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } \
static ptr tryGet() { ptr ret; tryGet(ret); return ret; }
public: static ptr get() { return fb2k::std_api_get<THISCLASS>(); } static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); }
#define FB2K_MAKE_SERVICE_COREAPI_EXTENSION(THISCLASS, BASECLASS) \
FB2K_MAKE_SERVICE_INTERFACE_EX( THISCLASS, BASECLASS, true ) \
public: \
static ptr get() { return fb2k::std_api_get<THISCLASS>(); } \
static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } \
static ptr tryGet() { ptr ret; tryGet(ret); return ret; }
public: static ptr get() { return fb2k::std_api_get<THISCLASS>(); } static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); }
@@ -398,6 +359,7 @@ class service_base;
typedef service_ptr_t<service_base> service_ptr;
typedef service_nnptr_t<service_base> service_nnptr;
//! Base class for all service classes.\n
//! Provides interfaces for reference counter and querying for different interfaces supported by the object.\n
class NOVTABLE service_base
@@ -433,14 +395,8 @@ public:
typedef service_base t_interface;
enum { _is_core_api = false };
static const char * debugServiceName() {return "service_base"; }
static bool serviceRequiresMainThreadDestructor() { return false; }
#ifdef FOOBAR2000_MODERN
static bool shouldRegisterService() { return true; }
#endif
service_base * as_service_base() { return this; }
protected:
service_base() {}
@@ -466,6 +422,7 @@ private:
const service_base & operator=(const service_base&) = delete;
};
template<typename T>
inline void _validate_service_class_helper() {
_validate_service_class_helper<typename T::t_interface_parent>();
@@ -475,48 +432,6 @@ template<>
inline void _validate_service_class_helper<service_base>() {}
#include "service_impl.h"
class NOVTABLE service_factory_base {
protected:
inline service_factory_base(const GUID & p_guid, service_factory_base * & factoryList = __internal__list) : m_guid(p_guid) { PFC_ASSERT(!core_api::are_services_available()); __internal__next = factoryList; factoryList = this; }
public:
inline const GUID & get_class_guid() const {return m_guid;}
static service_class_ref enum_find_class(const GUID & p_guid);
static bool enum_create(service_ptr_t<service_base> & p_out,service_class_ref p_class,t_size p_index);
static t_size enum_get_count(service_class_ref p_class);
inline static bool is_service_present(const GUID & g) {return enum_get_count(enum_find_class(g))>0;}
//! Throws std::bad_alloc or another exception on failure.
virtual void instance_create(service_ptr_t<service_base> & p_out) = 0;
#ifdef FOOBAR2000_MODERN
virtual bool should_register() { return true; }
#endif
//! FOR INTERNAL USE ONLY
static service_factory_base *__internal__list;
//! FOR INTERNAL USE ONLY
service_factory_base * __internal__next;
private:
const GUID & m_guid;
};
template<typename B>
class service_factory_traits {
public:
static service_factory_base * & factory_list() {return service_factory_base::__internal__list;}
};
template<typename B>
class service_factory_base_t : public service_factory_base {
public:
service_factory_base_t() : service_factory_base(B::class_guid, service_factory_traits<B>::factory_list()) {
pfc::assert_same_type<B,typename B::t_interface_entrypoint>();
}
};
template<typename T> static void _validate_service_ptr(service_ptr_t<T> const & ptr) {
PFC_ASSERT( ptr.is_valid() );
service_ptr_t<T> test;
@@ -597,12 +512,7 @@ template<typename T> inline void standard_api_create_t(service_ptr_t<T> & p_out)
} else {
service_ptr_t<typename T::t_interface_entrypoint> temp;
standard_api_create_t(temp);
if (!temp->service_query_t(p_out)) {
#if PFC_DEBUG
FB2K_DebugLog() << "Service extension not found: " << T::debugServiceName() << " (" << pfc::print_guid(T::class_guid) << ") of base type: " << T::t_interface_entrypoint::debugServiceName() << " (" << pfc::print_guid(T::t_interface_entrypoint::class_guid) << ")";
#endif
throw exception_service_extension_not_found();
}
if (!temp->service_query_t(p_out)) throw exception_service_extension_not_found();
}
}
@@ -644,7 +554,7 @@ public:
static_api_ptr_t() {
standard_api_create_t(m_ptr);
}
t_interface* operator->() const {return m_ptr;}
service_obscure_refcounting<t_interface>* operator->() const {return service_obscure_refcounting_cast(m_ptr);}
t_interface * get_ptr() const {return m_ptr;}
~static_api_ptr_t() {m_ptr->service_release();}
@@ -656,6 +566,26 @@ private:
t_interface * m_ptr;
};
//! Helper; simulates array with instance of each available implementation of given service class.
template<typename T> class service_instance_array_t {
public:
typedef service_ptr_t<T> t_ptr;
service_instance_array_t() {
service_class_helper_t<T> helper;
const t_size count = helper.get_count();
m_data.set_size(count);
for(t_size n=0;n<count;n++) m_data[n] = helper.create(n);
}
t_size get_size() const {return m_data.get_size();}
const t_ptr & operator[](t_size p_index) const {return m_data[p_index];}
//nonconst version to allow sorting/bsearching; do not abuse
t_ptr & operator[](t_size p_index) {return m_data[p_index];}
private:
pfc::array_t<t_ptr> m_data;
};
template<typename t_interface>
class service_enum_t {
public:
@@ -684,27 +614,6 @@ public:
}
}
service_ptr_t<t_interface> get() const {
PFC_ASSERT(!finished());
return m_helper.create(m_index);
}
void operator++() {
PFC_ASSERT(!finished());
++m_index;
}
void operator++(int) {
PFC_ASSERT(!finished());
++m_index;
}
bool finished() const {
return m_index >= m_helper.get_count();
}
service_ptr_t<t_interface> operator*() const {
return get();
}
private:
bool _next(service_ptr_t<t_interface> & p_out) {
return m_helper.create(p_out,m_index++);
@@ -713,9 +622,6 @@ private:
service_class_helper_t<t_interface> m_helper;
};
//! New fb2k service enumeration syntax
//! for(auto e = FB2K_ENUMERATE(someclass); !e.finished(); ++e) { auto srv = *e; srv->do_stuff(); }
#define FB2K_ENUMERATE(what_t) service_enum_t<what_t>()
namespace fb2k {
//! Modern get-std-api helper. \n
@@ -747,99 +653,3 @@ namespace fb2k {
}
}
}
template<typename T>
class service_factory_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
public:
void instance_create(service_ptr_t<service_base> & p_out) override {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>( new service_impl_t<T> )));
}
#ifdef FOOBAR2000_MODERN
bool should_register() override { return T::shouldRegisterService(); }
#endif
};
template<typename T>
class service_factory_single_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
service_impl_single_t<T> g_instance;
public:
template<typename ... arg_t> service_factory_single_t(arg_t && ... arg) : g_instance(std::forward<arg_t>(arg) ...) {}
void instance_create(service_ptr_t<service_base> & p_out) override {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>(&g_instance)));
}
#ifdef FOOBAR2000_MODERN
bool should_register() override { return g_instance.shouldRegisterService(); }
#endif
inline T& get_static_instance() { return g_instance; }
inline const T& get_static_instance() const { return g_instance; }
};
//! Alternate service_factory_single, shared instance created on first access and never deallocated. \n
//! Addresses the problem of dangling references to our object getting invoked or plainly de-refcounted during late shutdown.
template<typename T>
class service_factory_single_v2_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
public:
T * get() {
static T * g_instance = new service_impl_single_t<T>;
return g_instance;
}
void instance_create(service_ptr_t<service_base> & p_out) override {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(get()));
}
#ifdef FOOBAR2000_MODERN
bool should_register() override { return T::shouldRegisterService(); }
#endif
};
template<typename T>
class service_factory_single_ref_t : public service_factory_base_t<typename T::t_interface_entrypoint>
{
private:
T & instance;
public:
service_factory_single_ref_t(T& param) : instance(param) {}
void instance_create(service_ptr_t<service_base> & p_out) override {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>(&instance)));
}
#ifdef FOOBAR2000_MODERN
bool should_register() override { return instance.shouldRegisterService(); }
#endif
inline T& get_static_instance() { return instance; }
};
template<typename T>
class service_factory_single_transparent_t : public service_factory_base_t<typename T::t_interface_entrypoint>, public service_impl_single_t<T>
{
public:
template<typename ... arg_t> service_factory_single_transparent_t(arg_t && ... arg) : service_impl_single_t<T>( std::forward<arg_t>(arg) ...) {}
void instance_create(service_ptr_t<service_base> & p_out) override {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>(this)));
}
#ifdef FOOBAR2000_MODERN
bool should_register() override { return this->shouldRegisterService(); }
#endif
inline T& get_static_instance() {return *(T*)this;}
inline const T& get_static_instance() const {return *(const T*)this;}
};
#ifdef _MSC_VER
#define FB2K_SERVICE_FACTORY_ATTR
#else
#define FB2K_SERVICE_FACTORY_ATTR __attribute__ (( __used__ ))
#endif
#define FB2K_SERVICE_FACTORY( TYPE ) static ::service_factory_single_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR;
#define FB2K_SERVICE_FACTORY_DYNAMIC( TYPE ) static ::service_factory_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR;
#define FB2K_FOR_EACH_SERVICE(type, call) {service_enum_t<typename type::t_interface_entrypoint> e; service_ptr_t<type> ptr; while(e.next(ptr)) {ptr->call;} }

View File

@@ -1,16 +1,11 @@
#pragma once
#ifdef FOOBAR2000_MODERN
#include <pfc/map.h>
#endif
template<typename what>
static bool service_by_guid_fallback(service_ptr_t<what> & out, const GUID & id) {
service_enum_t<what> e;
service_ptr_t<what> ptr;
while(e.next(ptr)) {
if (ptr->get_guid() == id) {out = ptr; return true;}
while (e.next(ptr)) {
if (ptr->get_guid() == id) { out = ptr; return true; }
}
return false;
}
@@ -18,9 +13,9 @@ static bool service_by_guid_fallback(service_ptr_t<what> & out, const GUID & id)
template<typename what>
class service_by_guid_data {
public:
service_by_guid_data() : m_inited(), m_servClass() {}
service_by_guid_data() : m_servClass(), m_inited() {}
bool ready() const {return m_inited;}
bool ready() const { return m_inited; }
// Caller must ensure initialize call before create() as well as thread safety of initialize() calls. The rest of this class is thread safe (only reads member data).
void initialize() {
@@ -28,7 +23,7 @@ public:
pfc::assert_same_type< what, typename what::t_interface_entrypoint >();
m_servClass = service_factory_base::enum_find_class(what::class_guid);
const t_size servCount = service_factory_base::enum_get_count(m_servClass);
for(t_size walk = 0; walk < servCount; ++walk) {
for (t_size walk = 0; walk < servCount; ++walk) {
service_ptr_t<what> temp;
if (_service_instantiate_helper(temp, m_servClass, walk)) {
m_order.set(temp->get_guid(), walk);
@@ -40,16 +35,16 @@ public:
bool create(service_ptr_t<what> & out, const GUID & theID) const {
PFC_ASSERT(m_inited);
t_size index;
if (!m_order.query(theID,index)) return false;
if (!m_order.query(theID, index)) return false;
return _service_instantiate_helper(out, m_servClass, index);
}
service_ptr_t<what> create(const GUID & theID) const {
service_ptr_t<what> temp; if (!crete(temp,theID)) throw exception_service_not_found(); return temp;
service_ptr_t<what> temp; if (!crete(temp, theID)) throw exception_service_not_found(); return temp;
}
private:
volatile bool m_inited;
pfc::map_t<GUID,t_size> m_order;
pfc::map_t<GUID, t_size> m_order;
service_class_ref m_servClass;
};
@@ -75,25 +70,21 @@ static bool service_by_guid(service_ptr_t<what> & out, const GUID & theID) {
} else if (core_api::is_main_thread()) {
data.initialize();
} else {
#if PFC_DEBUG
#ifdef _DEBUG
FB2K_DebugLog() << "Warning: service_by_guid() used in non-main thread without initialization, using fallback";
#endif
return service_by_guid_fallback(out,theID);
return service_by_guid_fallback(out, theID);
}
return data.create(out,theID);
return data.create(out, theID);
}
template<typename what>
static service_ptr_t<what> service_by_guid(const GUID & theID) {
service_ptr_t<what> temp;
if (!service_by_guid(temp, theID)) {
#if PFC_DEBUG
FB2K_DebugLog() << "service_by_guid failure: " << what::debugServiceName() << " : " << pfc::print_guid( theID );
#endif
throw exception_service_not_found();
}
if (!service_by_guid(temp, theID)) throw exception_service_not_found();
return temp;
}
#define FB2K_FOR_EACH_SERVICE(type, call) {service_enum_t<typename type::t_interface_entrypoint> e; service_ptr_t<type> ptr; while(e.next(ptr)) {ptr->call;} }

View File

@@ -1,38 +0,0 @@
#pragma once
// Obsolete features
//! Special hack to ensure errors when someone tries to ->service_add_ref()/->service_release() on a service_ptr_t
template<typename T> class service_obscure_refcounting : public T {
private:
int service_add_ref() throw();
int service_release() throw();
};
//! Converts a service interface pointer to a pointer that obscures service counter functionality.
template<typename T> static inline service_obscure_refcounting<T>* service_obscure_refcounting_cast(T * p_source) throw() {return static_cast<service_obscure_refcounting<T>*>(p_source);}
template<typename T, template<typename> class t_alloc = pfc::alloc_fast>
class service_list_t : public pfc::list_t<service_ptr_t<T>, t_alloc >
{
};
//! Helper; simulates array with instance of each available implementation of given service class.
template<typename T> class service_instance_array_t {
public:
typedef service_ptr_t<T> t_ptr;
service_instance_array_t() {
service_class_helper_t<T> helper;
const t_size count = helper.get_count();
m_data.set_size(count);
for(t_size n=0;n<count;n++) m_data[n] = helper.create(n);
}
t_size get_size() const {return m_data.get_size();}
const t_ptr & operator[](t_size p_index) const {return m_data[p_index];}
//nonconst version to allow sorting/bsearching; do not abuse
t_ptr & operator[](t_size p_index) {return m_data[p_index];}
private:
pfc::array_t<t_ptr> m_data;
};

View File

@@ -0,0 +1,117 @@
#pragma once
class NOVTABLE service_factory_base {
public:
inline const GUID & get_class_guid() const { return m_guid; }
static service_class_ref enum_find_class(const GUID & p_guid);
static bool enum_create(service_ptr_t<service_base> & p_out, service_class_ref p_class, t_size p_index);
static t_size enum_get_count(service_class_ref p_class);
inline static bool is_service_present(const GUID & g) { return enum_get_count(enum_find_class(g))>0; }
//! Throws std::bad_alloc or another exception on failure.
virtual void instance_create(service_ptr_t<service_base> & p_out) = 0;
//! FOR INTERNAL USE ONLY
static service_factory_base *__internal__list;
//! FOR INTERNAL USE ONLY
service_factory_base * __internal__next;
private:
const GUID & m_guid;
protected:
inline service_factory_base(const GUID & p_guid, service_factory_base * & factoryList = __internal__list) : m_guid(p_guid) { PFC_ASSERT(!core_api::are_services_available()); __internal__next = factoryList; factoryList = this; }
inline ~service_factory_base() { PFC_ASSERT(!core_api::are_services_available()); }
};
template<typename B>
class service_factory_traits {
public:
static service_factory_base * & factory_list() { return service_factory_base::__internal__list; }
};
template<typename B>
class service_factory_base_t : public service_factory_base {
public:
service_factory_base_t() : service_factory_base(B::class_guid, service_factory_traits<B>::factory_list()) {
pfc::assert_same_type<B, typename B::t_interface_entrypoint>();
}
};
template<typename T>
class service_factory_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
public:
void instance_create(service_ptr_t<service_base> & p_out) {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>(new service_impl_t<T>)));
}
};
template<typename T>
class service_factory_single_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
service_impl_single_t<T> g_instance;
public:
template<typename ... arg_t> service_factory_single_t(arg_t && ... arg) : g_instance(std::forward<arg_t>(arg) ...) {}
void instance_create(service_ptr_t<service_base> & p_out) {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>(&g_instance)));
}
inline T& get_static_instance() { return g_instance; }
inline const T& get_static_instance() const { return g_instance; }
};
//! Alternate service_factory_single, shared instance created on first access and never deallocated. \n
//! Addresses the problem of dangling references to our object getting invoked or plainly de-refcounted during late shutdown.
template<typename T>
class service_factory_single_v2_t : public service_factory_base_t<typename T::t_interface_entrypoint> {
public:
T * get() {
static T * g_instance = new service_impl_single_t<T>;
return g_instance;
}
void instance_create(service_ptr_t<service_base> & p_out) {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(get()));
}
};
template<typename T>
class service_factory_single_ref_t : public service_factory_base_t<typename T::t_interface_entrypoint>
{
private:
T & instance;
public:
service_factory_single_ref_t(T& param) : instance(param) {}
void instance_create(service_ptr_t<service_base> & p_out) {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>(&instance)));
}
inline T& get_static_instance() { return instance; }
};
template<typename T>
class service_factory_single_transparent_t : public service_factory_base_t<typename T::t_interface_entrypoint>, public service_impl_single_t<T>
{
public:
template<typename ... arg_t> service_factory_single_transparent_t(arg_t && ... arg) : service_impl_single_t<T>(std::forward<arg_t>(arg) ...) {}
void instance_create(service_ptr_t<service_base> & p_out) {
p_out = pfc::implicit_cast<service_base*>(pfc::implicit_cast<typename T::t_interface_entrypoint*>(pfc::implicit_cast<T*>(this)));
}
inline T& get_static_instance() { return *(T*)this; }
};
#ifdef _MSC_VER
#define FB2K_SERVICE_FACTORY_ATTR
#else
#define FB2K_SERVICE_FACTORY_ATTR __attribute__ (( __used__ ))
#endif
#define FB2K_SERVICE_FACTORY( TYPE ) static ::service_factory_single_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR;
#define FB2K_SERVICE_FACTORY_DYNAMIC( TYPE ) static ::service_factory_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR;

View File

@@ -8,10 +8,9 @@
#include <utility>
namespace service_impl_helper {
//! Helper function to defer destruction of a service object. \n
//! Enqueues a main_thread_callback to release the object at a later time, escaping the current scope. \n
//! Important: this takes a raw service_base* - not an autoptr - to ensure that the last reference can be released in main thread. \n
void release_object_delayed(service_base* obj);
//! Helper function to defer destruction of a service object.
//! Enqueues a main_thread_callback to release the object at a later time, escaping the current scope.
void release_object_delayed(service_ptr obj);
};
//! Multi inheritance helper. \n
@@ -28,7 +27,6 @@ public:
}
service_base * as_service_base() { return class1_t::as_service_base(); }
static const char * debugServiceName() { return "multi inherited service"; }
// Obscure service_base methods from both so calling myclass->service_query() works like it should
virtual int service_release() throw() = 0;
@@ -66,7 +64,6 @@ public:
if (!this->serviceRequiresMainThreadDestructor() || core_api::is_main_thread()) {
PFC_ASSERT_NO_EXCEPTION( delete this );
} else {
// Pass to release_object_delayed() with zero ref count - a temporary single reference will be created there
service_impl_helper::release_object_delayed(this->as_service_base());
}
}

View File

@@ -124,7 +124,7 @@ void tag_processor::read_trailing(const service_ptr_t<file> & p_file,file_info &
tag_processor_trailing::get()->read(p_file,p_info,p_abort);
}
void tag_processor::read_trailing_ex(const service_ptr_t<file> & p_file,file_info & p_info,t_filesize & p_tagoffset,abort_callback & p_abort) {
void tag_processor::read_trailing_ex(const service_ptr_t<file> & p_file,file_info & p_info,t_uint64 & p_tagoffset,abort_callback & p_abort) {
tag_processor_trailing::get()->read_ex(p_file,p_info,p_tagoffset,p_abort);
}
@@ -165,7 +165,7 @@ void tag_processor::read_id3v2_trailing(const service_ptr_t<file> & p_file,file_
}
}
void tag_processor::skip_id3v2(const service_ptr_t<file> & p_file,t_filesize & p_size_skipped,abort_callback & p_abort) {
void tag_processor::skip_id3v2(const service_ptr_t<file> & p_file,t_uint64 & p_size_skipped,abort_callback & p_abort) {
tag_processor_id3v2::g_skip(p_file,p_size_skipped,p_abort);
}

View File

@@ -37,7 +37,6 @@ public:
static t_size g_multiskip(const service_ptr_t<file> & p_file,t_filesize & p_size_skipped,abort_callback & p_abort);
static void g_remove(const service_ptr_t<file> & p_file,t_filesize & p_size_removed,abort_callback & p_abort);
static void g_remove_ex(tag_write_callback & p_callback,const service_ptr_t<file> & p_file,t_filesize & p_size_removed,abort_callback & p_abort);
static uint32_t g_tagsize(const void* pHeader10bytes);
FB2K_MAKE_SERVICE_COREAPI(tag_processor_id3v2);
};

View File

@@ -2,8 +2,7 @@
bool tag_processor_id3v2::g_get(service_ptr_t<tag_processor_id3v2> & p_out)
{
p_out = get();
return true;
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) {
@@ -58,25 +57,6 @@ t_size tag_processor_id3v2::g_multiskip(const service_ptr_t<file> & p_file,t_fil
p_size_skipped = offset;
return count;
}
uint32_t tag_processor_id3v2::g_tagsize(const void* pHeader10bytes) {
const uint8_t* tmp = (const uint8_t*)pHeader10bytes;
if ( 0 != memcmp(tmp, "ID3", 3) || (tmp[5] & 0x0F) != 0 || ((tmp[6] | tmp[7] | tmp[8] | tmp[9]) & 0x80) != 0 ) {
return 0;
}
int FooterPresent = tmp[5] & 0x10;
uint32_t ret;
ret = tmp[6] << 21;
ret += tmp[7] << 14;
ret += tmp[8] << 7;
ret += tmp[9];
ret += 10;
if (FooterPresent) ret += 10;
return ret;
}
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);
}
@@ -93,13 +73,26 @@ void tag_processor_id3v2::g_skip_at(const service_ptr_t<file> & p_file,t_filesiz
return;
}
uint32_t ret = g_tagsize(tmp);
if (ret == 0) {
p_file->seek(p_base, p_abort);
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) {
@@ -109,4 +102,5 @@ void tag_processor_id3v2::g_skip_at(const service_ptr_t<file> & p_file,t_filesiz
}
p_size_skipped = ret;
}

View File

@@ -107,12 +107,12 @@ service_ptr_t<threaded_process_callback_lambda> threaded_process_callback_lambda
service_ptr_t<threaded_process_callback_lambda> threaded_process_callback_lambda::create(run_t f) {
auto obj = create();
obj->m_run = f;
return obj;
return std::move(obj);
}
service_ptr_t<threaded_process_callback_lambda> threaded_process_callback_lambda::create(on_init_t f1, run_t f2, on_done_t f3) {
auto obj = create();
obj->m_on_init = f1;
obj->m_run = f2;
obj->m_on_done = f3;
return obj;
return std::move(obj);
}

View File

@@ -2,28 +2,28 @@
#include <functional>
//! Callback class passed to your threaded_process client code; allows you to give various visual feedback to the user.
class threaded_process_status {
class NOVTABLE threaded_process_status {
public:
enum {progress_min = 0, progress_max = 5000};
//! Sets the primary progress bar state; scale from progress_min to progress_max.
virtual void set_progress(t_size p_state) {}
virtual void set_progress(t_size p_state) = 0;
//! Sets the secondary progress bar state; scale from progress_min to progress_max.
virtual void set_progress_secondary(t_size p_state) {}
virtual void set_progress_secondary(t_size p_state) = 0;
//! Sets the currently progressed item label. When working with files, you should use set_file_path() instead.
virtual void set_item(const char * p_item,t_size p_item_len = ~0) {}
virtual void set_item(const char * p_item,t_size p_item_len = ~0) = 0;
//! Sets the currently progressed item label; treats the label as a file path.
virtual void set_item_path(const char * p_item,t_size p_item_len = ~0) {}
virtual void set_item_path(const char * p_item,t_size p_item_len = ~0) = 0;
//! Sets the title of the dialog. You normally don't need this function unless you want to override the title you set when initializing the threaded_process.
virtual void set_title(const char * p_title,t_size p_title_len = ~0) {}
virtual void set_title(const char * p_title,t_size p_title_len = ~0) = 0;
//! Should not be used.
virtual void force_update() {}
virtual void force_update() = 0;
//! Returns whether the process is paused.
virtual bool is_paused() {return false;}
virtual bool is_paused() = 0;
//! Checks if process is paused and sleeps if needed; returns false when process should be aborted, true on success. \n
//! You should use poll_pause() instead of calling this directly.
virtual bool process_pause() {return true;}
virtual bool process_pause() = 0;
//! Automatically sleeps if the process is paused.
void poll_pause() {if (!process_pause()) throw exception_aborted();}
@@ -39,12 +39,9 @@ public:
//! Helper; gracefully reports multiple items being concurrently worked on.
void set_items( metadb_handle_list_cref items );
void set_items( pfc::list_base_const_t<const char*> const & paths );
};
//! Fb2k mobile compatibility
class threaded_process_context {
public:
static HWND g_default() { return core_api::get_main_window(); }
protected:
threaded_process_status() {}
~threaded_process_status() {}
};
//! Callback class for the threaded_process API. You must implement this to create your own threaded_process client.

View File

@@ -55,8 +55,7 @@ void titleformat_compiler::remove_forbidden_chars(titleformat_text_out * p_out,c
void titleformat_compiler::remove_forbidden_chars_string_append(pfc::string_receiver & p_out,const char * p_source,t_size p_source_len,const char * p_reserved_chars)
{
titleformat_text_out_impl_string tfout(p_out);
remove_forbidden_chars(&tfout,pfc::guid_null,p_source,p_source_len,p_reserved_chars);
remove_forbidden_chars(&titleformat_text_out_impl_string(p_out),pfc::guid_null,p_source,p_source_len,p_reserved_chars);
}
void titleformat_compiler::remove_forbidden_chars_string(pfc::string_base & p_out,const char * p_source,t_size p_source_len,const char * p_reserved_chars)
@@ -76,21 +75,24 @@ void titleformat_object::run_hook(const playable_location & p_location,const fil
{
if (p_hook)
{
titleformat_hook_impl_file_info hook1(p_location, p_source);
titleformat_hook_impl_splitter hook2(p_hook, &hook1);
run(&hook2,p_out,p_filter);
run(
&titleformat_hook_impl_splitter(
p_hook,
&titleformat_hook_impl_file_info(p_location,p_source)
),
p_out,p_filter);
}
else
{
titleformat_hook_impl_file_info hook(p_location, p_source);
run(&hook,p_out,p_filter);
run(
&titleformat_hook_impl_file_info(p_location,p_source),
p_out,p_filter);
}
}
void titleformat_object::run_simple(const playable_location & p_location,const file_info * p_source,pfc::string_base & p_out)
{
titleformat_hook_impl_file_info hook(p_location, p_source);
run(&hook,p_out,NULL);
run(&titleformat_hook_impl_file_info(p_location,p_source),p_out,NULL);
}
t_size titleformat_hook_function_params::get_param_uint(t_size index)

View File

@@ -1,70 +0,0 @@
#include "foobar2000.h"
#include "track_property.h"
namespace {
class track_property_provider_v3_info_source_impl : public track_property_provider_v3_info_source {
public:
track_property_provider_v3_info_source_impl(trackListRef items) : m_items(items) {}
trackInfoContainer::ptr get_info(size_t index) {
return trackGetInfoRef(m_items, index);
}
private:
trackListRef m_items;
};
class track_property_callback_v2_proxy : public track_property_callback_v2 {
public:
track_property_callback_v2_proxy(track_property_callback & callback) : m_callback(callback) {}
void set_property(const char * p_group, double p_sortpriority, const char * p_name, const char * p_value) { m_callback.set_property(p_group, p_sortpriority, p_name, p_value); }
bool is_group_wanted(const char*) { return true; }
private:
track_property_callback & m_callback;
};
}
void track_property_provider_v3::enumerate_properties(trackListRef p_tracks, track_property_callback & p_out) {
track_property_provider_v3_info_source_impl src(p_tracks); track_property_callback_v2_proxy cb(p_out); enumerate_properties_v3(p_tracks, src, cb);
}
void track_property_provider_v3::enumerate_properties_v2(trackListRef p_tracks, track_property_callback_v2 & p_out) {
track_property_provider_v3_info_source_impl src(p_tracks); enumerate_properties_v3(p_tracks, src, p_out);
}
void track_property_provider_v4::enumerate_properties_v3(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) {
this->enumerate_properties_v4(items, info, callback, fb2k::noAbort );
}
void track_property_provider::enumerate_properties_helper(trackListRef items, track_property_provider_v3_info_source * info, track_property_callback_v2 & callback, abort_callback & abort) {
abort.check();
track_property_provider_v2::ptr v2;
if ( ! this->cast( v2 ) ) {
// no v2
PFC_ASSERT(core_api::is_main_thread());
this->enumerate_properties( items, callback ); return;
}
track_property_provider_v3::ptr v3;
if ( ! (v3 &= v2 ) ) {
// no v3
PFC_ASSERT(core_api::is_main_thread());
v2->enumerate_properties_v2( items, callback ); return;
}
track_property_provider_v3_info_source_impl infoFallback ( items );
if ( info == nullptr ) info = & infoFallback;
track_property_provider_v4::ptr v4;
if (! ( v4 &= v3 ) ) {
// no v4
PFC_ASSERT( core_api::is_main_thread() );
v3->enumerate_properties_v3( items, *info, callback );
} else {
v4->enumerate_properties_v4( items, *info, callback, abort );
}
}

View File

@@ -1,7 +1,3 @@
#pragma once
#include "tracks.h"
//! Callback interface for track_property_provider::enumerate_properties().
class NOVTABLE track_property_callback {
public:
@@ -14,8 +10,10 @@ public:
protected:
track_property_callback() {}
~track_property_callback() {}
track_property_callback(track_property_callback const &) {};
void operator=(track_property_callback const &) {};
private:
track_property_callback(track_property_callback const &) = delete;
track_property_callback const & operator=(track_property_callback const &) = delete;
};
//! Extended version of track_property_callback
@@ -28,71 +26,59 @@ protected:
~track_property_callback_v2() {}
};
//! \since 1.3
class NOVTABLE track_property_provider_v3_info_source {
public:
virtual trackInfoContainer::ptr get_info(size_t index) = 0;
protected:
track_property_provider_v3_info_source() {}
~track_property_provider_v3_info_source() {}
track_property_provider_v3_info_source( const track_property_provider_v3_info_source & ) {};
void operator=( const track_property_provider_v3_info_source & ) {};
};
//! Service for adding custom entries in "Properties" tab of the properties dialog.
class NOVTABLE track_property_provider : public service_base {
public:
//! Enumerates properties of specified track list.
//! @param p_tracks List of tracks to enumerate properties on.
//! @param p_out Callback interface receiving enumerated properties.
virtual void enumerate_properties(trackListRef p_tracks, track_property_callback & p_out) = 0;
virtual void enumerate_properties(metadb_handle_list_cref p_tracks, track_property_callback & p_out) = 0;
//! Returns whether specified tech info filed is processed by our service and should not be displayed among unknown fields.
//! @param p_name Name of tech info field being queried.
//! @returns True if the field is among fields processed by this track_property_provider implementation and should not be displayed among unknown fields, false otherwise.
virtual bool is_our_tech_info(const char * p_name) = 0;
//! Helper; calls modern versions of this API where appropriate.
//! @param items List of tracks to enumerate properties on.
//! @param info Callback object to fetch info from. Pass null to use a generic implementation querying the metadb.
//! @param callback Callback interface receiving enumerated properties.
//! @param abort The aborter for this operation.
void enumerate_properties_helper(trackListRef items, track_property_provider_v3_info_source * info, track_property_callback_v2 & callback, abort_callback & abort);
FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(track_property_provider);
};
class NOVTABLE track_property_provider_v2 : public track_property_provider {
FB2K_MAKE_SERVICE_INTERFACE(track_property_provider_v2,track_property_provider)
public:
virtual void enumerate_properties_v2(trackListRef p_tracks, track_property_callback_v2 & p_out) = 0;
virtual void enumerate_properties_v2(metadb_handle_list_cref p_tracks, track_property_callback_v2 & p_out) = 0;
};
class NOVTABLE track_property_provider_v3_info_source {
public:
virtual metadb_info_container::ptr get_info(size_t index) = 0;
};
class track_property_provider_v3_info_source_impl : public track_property_provider_v3_info_source {
public:
track_property_provider_v3_info_source_impl(metadb_handle_list_cref items) : m_items(items) {}
metadb_info_container::ptr get_info(size_t index) {return m_items[index]->get_info_ref();}
private:
metadb_handle_list_cref m_items;
};
class track_property_callback_v2_proxy : public track_property_callback_v2 {
public:
track_property_callback_v2_proxy(track_property_callback & callback) : m_callback(callback) {}
void set_property(const char * p_group,double p_sortpriority,const char * p_name,const char * p_value) {m_callback.set_property(p_group, p_sortpriority, p_name, p_value);}
bool is_group_wanted(const char*) {return true;}
private:
track_property_callback & m_callback;
};
//! \since 1.3
class NOVTABLE track_property_provider_v3 : public track_property_provider_v2 {
FB2K_MAKE_SERVICE_INTERFACE(track_property_provider_v3,track_property_provider_v2)
public:
virtual void enumerate_properties_v3(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) = 0;
virtual void enumerate_properties_v3(metadb_handle_list_cref items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) = 0;
void enumerate_properties(trackListRef p_tracks, track_property_callback & p_out) override;
void enumerate_properties_v2(trackListRef p_tracks, track_property_callback_v2 & p_out) override;
void enumerate_properties(metadb_handle_list_cref p_tracks, track_property_callback & p_out) {track_property_provider_v3_info_source_impl src(p_tracks); track_property_callback_v2_proxy cb(p_out); enumerate_properties_v3(p_tracks, src, cb);}
void enumerate_properties_v2(metadb_handle_list_cref p_tracks, track_property_callback_v2 & p_out) {track_property_provider_v3_info_source_impl src(p_tracks); enumerate_properties_v3(p_tracks, src, p_out);}
};
template<typename T>
class track_property_provider_factory_t : public service_factory_single_t<T> {};
//! \since 1.5
//! Adds abortability on top of track_property_provider_v3 interface. \n
//! The previous revisions of this API were only legal to call from the main thread. \n
//! track_property_provider_v4 implementers should make NO ASSUMPTIONS about the thread they are in. \n
//! Implementing track_property_provider_v4 declares your class as safe to call from any thread. \n
//! If called via enumerate_properties_v4() method or off-main-thread, the implementation can assume the info source object to be thread-safe.
class NOVTABLE track_property_provider_v4 : public track_property_provider_v3 {
FB2K_MAKE_SERVICE_INTERFACE(track_property_provider_v4, track_property_provider_v3 );
public:
void enumerate_properties_v3(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) override;
virtual void enumerate_properties_v4(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback, abort_callback & abort) = 0;
};

View File

@@ -1,34 +0,0 @@
#pragma once
// Special header with fb2k mobile metadb<=>trackList interop wrappers
typedef metadb_handle_ptr trackRef;
typedef metadb_handle_list_cref trackListRef;
typedef metadb_handle_list trackListStore;
typedef metadb_info_container trackInfoContainer;
inline size_t trackCount(trackListRef l) {return l.get_size();}
inline trackRef trackListGetTrack(trackListRef l, size_t n) { return l[n]; }
// Returns blank info if no info is known, never null.
inline trackInfoContainer::ptr trackGetInfoRef(trackRef t) { return t->get_info_ref(); }
inline trackInfoContainer::ptr trackGetInfoRef(trackListRef l, size_t n) { return trackGetInfoRef(l[n]); }
// Returns null info if no info is known, contrary to trackGetInfoRef
inline trackInfoContainer::ptr trackGetInfo(trackRef t) { trackInfoContainer::ptr ret; if(!t->get_info_ref(ret)) ret = nullptr; return ret; }
inline trackInfoContainer::ptr trackGetInfo(trackListRef l, size_t n) { return trackGetInfo(l[n]); }
// Returns const char* or pfc::string8 depending on which fb2k!
inline const char * trackGetPath(trackListRef l, size_t n) { return l[n]->get_path(); }
inline const char * trackGetPath(trackRef t) { return t->get_path(); }
// Returns const playable_location& or playable_location_impl depending on which fb2k!
inline playable_location const & trackGetLocation(trackListRef l, size_t n) { return l[n]->get_location(); }
inline playable_location const & trackGetLocation(trackRef t) { return t->get_location(); }
inline double trackGetLength(trackListRef l, size_t n) { return l[n]->get_length(); }
inline double trackGetLength(trackRef t) { return t->get_length(); }
inline void trackFormatTitle(trackRef trk, titleformat_hook * hook, pfc::string_base & out, service_ptr_t<titleformat_object > script, titleformat_text_filter * filter) {
trk->format_title(hook, out, script, filter);
}

View File

@@ -88,8 +88,7 @@ public:
//! Loads main GUI icon, version with specified width/height. Returned handle needs to be freed with DestroyIcon when you are done using it.
virtual HICON load_main_icon(unsigned width,unsigned height) = 0;
//! Activates preferences dialog and navigates to specified page. See also: preference_page API. \n
//! Since foobar2000 1.5, this can be used to show advanced preferences branches or settings, just pass GUID of the advconfig_entry you wish to show.
//! Activates preferences dialog and navigates to specified page. See also: preference_page API.
virtual void show_preferences(const GUID & p_page) = 0;
//! Instantiates ui_status_text_override service, that can be used to display status messages.
@@ -98,18 +97,6 @@ public:
virtual bool override_status_text_create(service_ptr_t<ui_status_text_override> & p_out) = 0;
};
typedef ui_status_text_override ui_status_host;
#if FOOBAR2000_TARGET_VERSION >= 80
//! \since 1.5
class NOVTABLE ui_control_v2 : public ui_control {
FB2K_MAKE_SERVICE_COREAPI_EXTENSION(ui_control_v2, ui_control)
public:
virtual void register_status_host(HWND wndFor, ui_status_host::ptr obj) = 0;
virtual void unregister_status_host(HWND wndFor) = 0;
};
#endif // if FOOBAR2000_TARGET_VERSION >= 80
//! Service called from the UI when some object is dropped into the UI. Usable for modifying drag&drop behaviors such as adding custom handlers for object types other than supported media files.\n
//! Implement where needed; use ui_drop_item_callback_factory_t<> template to register, e.g. static ui_drop_item_callback_factory_t<myclass> g_myclass_factory.
class NOVTABLE ui_drop_item_callback : public service_base {

View File

@@ -1,28 +1,5 @@
#include "foobar2000.h"
namespace {
struct sysColorMapping_t {
GUID guid; int idx;
};
static const sysColorMapping_t sysColorMapping[] = {
{ ui_color_text, COLOR_WINDOWTEXT },
{ ui_color_background, COLOR_WINDOW },
{ ui_color_highlight, COLOR_HOTLIGHT },
{ui_color_selection, COLOR_HIGHLIGHT},
};
}
int ui_color_to_sys_color_index(const GUID & p_guid) {
for( unsigned i = 0; i < PFC_TABSIZE( sysColorMapping ); ++ i ) {
if ( p_guid == sysColorMapping[i].guid ) return sysColorMapping[i].idx;
}
return -1;
}
GUID ui_color_from_sys_color_index(int idx) {
for (unsigned i = 0; i < PFC_TABSIZE(sysColorMapping); ++i) {
if (idx == sysColorMapping[i].idx) return sysColorMapping[i].guid;
}
return pfc::guid_null;
}
namespace {
class ui_element_config_impl : public ui_element_config {
@@ -58,8 +35,7 @@ service_ptr_t<ui_element_config> ui_element_config::g_create(const GUID & id, st
service_ptr_t<ui_element_config> ui_element_config::g_create(stream_reader * in, t_size bytes, abort_callback & abort) {
if (bytes < sizeof(GUID)) throw exception_io_data_truncation();
GUID id;
{ stream_reader_formatter<> str(*in,abort); str >> id;}
GUID id; stream_reader_formatter<>(*in,abort) >> id;
return g_create(id,in,bytes - sizeof(GUID),abort);
}
@@ -72,7 +48,7 @@ ui_element_config::ptr ui_element_config_parser::subelement(const GUID & id, t_s
service_ptr_t<ui_element_config> ui_element_config::g_create(const void * data, t_size size) {
stream_reader_memblock_ref stream(data,size);
return g_create(&stream,size,fb2k::noAbort);
return g_create(&stream,size,abort_callback_dummy());
}
bool ui_element_subclass_description(const GUID & id, pfc::string_base & p_out) {
@@ -112,13 +88,6 @@ t_ui_color ui_element_instance_callback::query_std_color(const GUID & p_what) {
#error portme
#endif
}
#ifdef _WIN32
t_ui_color ui_element_instance_callback::getSysColor(int sysColorIndex) {
GUID guid = ui_color_from_sys_color_index( sysColorIndex );
if ( guid != pfc::guid_null ) return query_std_color(guid);
return GetSysColor(sysColorIndex);
}
#endif
bool ui_element::g_find(service_ptr_t<ui_element> & out, const GUID & id) {
return service_by_guid(out, id);

View File

@@ -34,7 +34,7 @@ public:
//! Helper for reading data from ui_element_config.
class ui_element_config_parser : public stream_reader_formatter<> {
public:
ui_element_config_parser(ui_element_config::ptr in) : m_data(in), _m_stream(in->get_data(),in->get_data_size()), stream_reader_formatter(_m_stream,fb2k::noAbort) {}
ui_element_config_parser(ui_element_config::ptr in) : m_data(in), _m_stream(in->get_data(),in->get_data_size()), stream_reader_formatter(_m_stream,_m_abort) {}
void reset() {_m_stream.reset();}
t_size get_remaining() const {return _m_stream.get_remaining();}
@@ -43,13 +43,14 @@ public:
ui_element_config::ptr subelement(const GUID & id, t_size dataSize);
private:
const ui_element_config::ptr m_data;
abort_callback_dummy _m_abort;
stream_reader_memblock_ref _m_stream;
};
//! Helper creating ui_element_config from your data.
class ui_element_config_builder : public stream_writer_formatter<> {
public:
ui_element_config_builder() : stream_writer_formatter(_m_stream,fb2k::noAbort) {}
ui_element_config_builder() : stream_writer_formatter(_m_stream,_m_abort) {}
ui_element_config::ptr finish(const GUID & id) {
return ui_element_config::g_create(id,_m_stream.m_buffer);
}
@@ -57,6 +58,7 @@ public:
_m_stream.m_buffer.set_size(0);
}
private:
abort_callback_dummy _m_abort;
stream_writer_buffer_simple _m_stream;
};
@@ -96,9 +98,23 @@ static const GUID ui_font_statusbar = { 0xc7fd555b, 0xbd15, 0x4f74, { 0x93, 0xe,
static const GUID ui_font_console = { 0xb08c619d, 0xd3d1, 0x4089, { 0x93, 0xb2, 0xd5, 0xb, 0x87, 0x2d, 0x1a, 0x25 } };
//! @returns -1 when the GUID is unknown / unmappable, index that can be passed over to GetSysColor() otherwise.
int ui_color_to_sys_color_index(const GUID & p_guid);
GUID ui_color_from_sys_color_index( int idx );
static int ui_color_to_sys_color_index(const GUID & p_guid) {
if (p_guid == ui_color_text) {
return COLOR_WINDOWTEXT;
} else if (p_guid == ui_color_background) {
return COLOR_WINDOW;
} else if (p_guid == ui_color_highlight) {
return COLOR_HOTLIGHT;
} else if (p_guid == ui_color_selection) {
return COLOR_HIGHLIGHT;
} else {
return -1;
}
}
struct ui_element_min_max_info {
ui_element_min_max_info() : m_min_width(0), m_max_width(~0), m_min_height(0), m_max_height(~0) {}
@@ -138,9 +154,6 @@ public:
//! Helper - a wrapper around query_color(), if the color is not user-overridden, returns relevant system color.
t_ui_color query_std_color(const GUID & p_what);
#ifdef _WIN32
t_ui_color getSysColor( int sysColorIndex );
#endif
bool is_elem_visible_(service_ptr_t<class ui_element_instance> elem);
@@ -516,6 +529,14 @@ public:
virtual HWND highlight_element( HWND wndElem ) = 0;
};
class NOVTABLE ui_element_typable_window_manager : public service_base {
FB2K_MAKE_SERVICE_COREAPI(ui_element_typable_window_manager)
public:
virtual void add(HWND wnd) = 0;
virtual void remove(HWND wnd) = 0;
virtual bool is_registered(HWND wnd) = 0;
};
//! Dispatched through ui_element_instance::notify() when host changes color settings. Other parameters are not used and should be set to zero.
static const GUID ui_element_notify_colors_changed = { 0xeedda994, 0xe3d2, 0x441a, { 0xbe, 0x47, 0xa1, 0x63, 0x5b, 0x71, 0xab, 0x60 } };
static const GUID ui_element_notify_font_changed = { 0x7a6964a8, 0xc797, 0x4737, { 0x90, 0x55, 0x7d, 0x84, 0xe7, 0x3d, 0x63, 0x6e } };

View File

@@ -1,14 +0,0 @@
#pragma once
// API obsoleted in 1.5 and should no longer be used by anything
// Core-implemented to keep components that specifically rely on it working
class NOVTABLE ui_element_typable_window_manager : public service_base {
FB2K_MAKE_SERVICE_COREAPI(ui_element_typable_window_manager);
public:
virtual void add(HWND wnd) = 0;
virtual void remove(HWND wnd) = 0;
virtual bool is_registered(HWND wnd) = 0;
};
FOOGUIDDECL const GUID ui_element_typable_window_manager::class_guid = { 0xbaa99ee2, 0xf770, 0x4981,{ 0x9e, 0x50, 0xf3, 0x4c, 0x5c, 0x6d, 0x98, 0x81 } };

View File

@@ -29,10 +29,7 @@ namespace fb2k {
}
namespace pfc {
/*
Redirect PFC methods to shared.dll
If you're getting linker multiple-definition errors on these, change build configuration of PFC from "Debug" / "Release" to "Debug FB2K" / "Release FB2K"
*/
// Redirect PFC methods to shared.dll
BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code) {
return uFormatSystemErrorMessage(p_out, p_code);
}
@@ -40,38 +37,3 @@ namespace pfc {
uBugCheck();
}
}
// file_lock_manager.h functionality
#include "file_lock_manager.h"
namespace {
class file_lock_interrupt_impl : public file_lock_interrupt {
public:
void interrupt( abort_callback & a ) { f(a); }
std::function<void (abort_callback&)> f;
};
}
file_lock_interrupt::ptr file_lock_interrupt::create( std::function< void (abort_callback&)> f ) {
service_ptr_t<file_lock_interrupt_impl> i = new service_impl_t<file_lock_interrupt_impl>();
i->f = f;
return i;
}
// file_info_filter.h functionality
#include "file_info_filter.h"
namespace {
class file_info_filter_lambda : public file_info_filter {
public:
bool apply_filter(trackRef p_track,t_filestats p_stats,file_info & p_info) override {
return f(p_track, p_stats, p_info);
}
func_t f;
};
}
file_info_filter::ptr file_info_filter::create(func_t f) {
auto o = fb2k::service_new<file_info_filter_lambda>();
o->f = f;
return o;
}